Cryptography In IOS (III): Sharing public keys between iOS and the rest of the world

Let me start this “Sharing public keys between iOS and the rest of the world” post by saying that I love developing for iOS. Cocoa has a great set of libraries, and Swift, even though not perfect, is a lovely language. Besides, I really like working with Xcode (when SourceKitService doesn’t crash), and I have to admit that I’ve never had that much fun while developing than for this particular platform, but…

Apple deprecated and then discontinued OpenSSL for its platforms and OS some years ago, leaving us with access to cryptography only through the Security framework. Unless, of course, you want to do some nasty hacks with custom built OpenSSL libraries. Unfortunately, the Security framework is terrible, developer-unfriendly and unintuitive to use.  That’s kind of surprising, giving the fact that iOS is (in)famous for its strong cryptographic nature. Indeed, that’s one of the main selling points that make it stand out from other platforms such as Android. There are several reasons for this:

  • The APIs are obscure and badly documented (I mean, the parts that are documented at all). There is little to no indication of how to use them in a coherent, comprehensive manner. Apple’s Security, Trust and Certificate guide is obsolete and not very clear for anything outside of the three typical uses of the framework, and the Crypto Exercise was last updated more than 6 years ago. In fact, it crashes when executed in current Xcode versions. Of course, no swift code on sight.
  • The key representation is arbitrary and inconsistent. EC keys are stored in its raw binary form, without any kind of ASN.1 treatment. Conversely, RSA keys are stored in a basic ASN.1 sequence wrapping layer.
  • The management API for the keys works well if you just want to use them inside iOS. However, it’s a real nuisance if you plan on sending them to an external server (like a backend). Its raw output is not supported by OpenSSL, and PHP won’t read it either, so basically you are out of luck unless you transform it to a standard format like PKCS#1.
  • The APIs won’t accept public keys imported from the outside world. I’m talking about simple PEM formatted RSA keys. To import public keys, you need to have a valid certificate and go through a bizarre method in order to get the reference to the public key contained inside. If you don’t have a certificate, only a public key, then it’s impossible importing that key inside iOS.

Recently, I embarked on a project to build a PasswordLess secure authentication protocol and framework. I plan on releasing it soon. One of the main requisites was being able to verify signatures and encrypt-decrypt in an asymmetric cryptography environment.

When I started to work with the iOS frontend side, I discovered that I couldn’t use the public keys from iOS outside, neither could I import my backend keys and make them work inside iOS.

After writing in the Apple developer forums, registering a bug report (that to this day remains unanswered) and contacting  the Apple engineer in charge of cryptography about the subject (who was not helpful at all), I decided to delve inside the cryptographic mess of iOS and try to understand how it deals with keys and formats.

These are my findings. However, for those of you willing to get the code, you can download it right now from my Github repository:

Importing public keys to iOS

Don’t try to import public keys contained in a DER or PEM file inside iOS. You won’t succeed.

After a lot of research, I came to the solution in a really old post in the developer forums, written by the Apple engineer I had contacted regarding the key export issue:

Cryptography In IOS (II): Sharing public keys between iOS and the rest of the world

That answer put me on the right track. I would have never thought that I needed the full certificate to perform basic cryptographic verification operations instead of just a public key (like the rest of cryptographic systems out there).

Generating The Certificate

First, we need to generate a valid certificate (probably in the backend). We can do it with some simple OpenSSL commands:

  • Generate the private key and the certificate
openssl req -newkey rsa:2048 -nodes -keyout private_key.key -x509 -days 3650 -out certificate.pem
  • Convert the certificate from PEM to DER
openssl x509 -outform der -in certificate.pem -out certificate.der
  • Check the certificate and private key
openssl x509 -text -noout -inform DER -in certificate.der
openssl rsa -check -in private_key.key

Importing The Certificate

Once we have our certificate ready, we can embed it in our iOS project and use it.  The process is somewhat bizarre, is composed of the following steps:

func importPublicKeyReferenceFromDERCertificate(certData: NSData) -> SecKeyRef? {
   // 1
   guard let certRef = SecCertificateCreateWithData(nil, certData) else { return nil }
   // 2
   var secTrust: SecTrustRef?
   let secTrustStatus = SecTrustCreateWithCertificates(certRef, nil, &secTrust) 
   if secTrustStatus != errSecSuccess { return nil }
   // 3
   var resultType: SecTrustResultType = UInt32(0) // ignore results.
   let evaluateStatus = SecTrustEvaluate(secTrust!, &resultType)
   if evaluateStatus != errSecSuccess { return nil }
   // 4
   let publicKeyRef = SecTrustCopyPublicKey(secTrust!)
   return publicKeyRef
  1. First, let’s suppose we have read our certificate in DER format from the file as a raw NSData sequence. Then, we need use SecCertificateCreateWithData to create a SecCertificate reference to the certificate.
  2. Next, we need to create a SecTrust reference from that certificate by calling SecTrustCreateWithCertificates.
  3. Then, we have to evaluate the SecTrustRef item we just created from the certificate reference. It’s unclear to me why this step is needed, but the whole process doesn’t seem to work unless the SecTrust item is properly evaluated. The results of the evaluation are retrieved in resultType. However, you can safely ignore this result.
  4. Finally, we can extract the public key reference from the SecTrust item by calling SecTrustCopyPublicKey.

If everything went as planned, we will end up with a SecKeyRef for the public key contained in the certificate. This key won’t be added to the KeyChain, so we must directly use it to any of the operations we need it for, including SecKeyEncrypt, SecKeyRawVerify, etc…

Using the Crypto Export-Import Manager

In order to import the key from the certificate using CryptoImportExportManager, you just need to call its importExportManager.importPublicKeyReferenceFromDERCertificate method:

let importExportManager = CryptoExportImportManager()
if let publicKeyRef = importExportManager.importPublicKeyReferenceFromDERCertificate(certData) {
   // use publicKeyRef to sign, decrypt, etc..
} else { ... handle error ... }

You can, of course, extract your public keys from the certificate using OpenSSL, to have a more manageable public-private key files.

Exporting iOS-generated public keys to the outside world.

Getting iOS keys to work outside of iOS has really been a nightmare for me. Actually, it took me several weeks of hard work to get it right. I hope that this article may help you, shall you find yourself in this same situation.

Some theory about key representation and formatting

As I said before, the keys generated by SecKeyGeneratePair and retrieved by means of SecItemCopyMatching are:

  • Not exportable by default to other platforms, and
  • Not consistent between different key types inside iOS

In particular, I’m not referring here to its representation in binary (DER) or base64 form (PEM). I’m talking about its DER binary structure.

About ASN.1

Generally speaking, all keys should contain a set of parameters or metadata with important information. This information includes what kind of key it is, what are its parameters, key length, type, and other relevant information that will allow a tool to properly identify, read and handle that key.

This metadata is expressed in a notation called ASN.1, concretely in the DER (Distinguished Encoding Rules) X.690 notation. This notation works by specifying a list of consecutive objects, from INTEGERS to full SEQUENCES.

Each object is identified by a starting mark and generally a length. The length in ASN.1 is codified as a single byte for values up to 128 (because of sign conversion), and for values greater than 128, it’s codified with an initial mark that’s 0x80+the number of bytes used to codify the length, followed by those bytes. For example, to codify a length of 0x1A0, you will need two bytes (0x01 + 0x1A), so the length will get encoded as 0x82 0x01 0x1A).

RSA keys

RSA keys have a module and an exponent. The modulus is shared between a pair of private-public keys, and the exponent is what differentiates them. As a result, and depending on how you wrap the modulus and exponent of a key in ASN.1 notation objects, you have different formats like PKCS#1, PKCS#7, PKCS#8, etc…

Unfortunately, Apple cryptographic tools return a basic representation of the key, just a sequence (30+length), followed by the modulus and exponent as integers (02+length+bytes) one after the other.

 0:d=0 hl=4 l= 266 cons: SEQUENCE 
 4:d=1 hl=4 l= 257 prim: INTEGER : ... (large integer number here in hex) ...
 265:d=1 hl=2 l= 3 prim: INTEGER :010001

This is a graphical representation of the data structure:

Cryptography In IOS (II): Sharing public keys between iOS and the rest of the world

If we want to make it work with OpenSSL, we need to wrap it inside a full PKCS#1 structure. From Wikipedia:

In cryptography, PKCS #1 is the first of a family of standards called Public-Key Cryptography Standards (PKCS), published by RSA Laboratories. It provides the basic definitions of and recommendations for implementing the RSA algorithm for public-key cryptography. It defines the mathematical properties of public and private keys, primitive operations for encryption and signatures, secure cryptographic schemes, and related ASN.1 syntax representations.

Building a PKCS#1 Structure

In order to wrap our key in a PKCS#1 structure, we need to add a “rsaEncryption” ASN.1 object. Its OID (object identifier) is 1.2.840.113549.1.1.1. Then, we need to build a structure around it to turn it into a valid PKCS#1 object:

 0:d=0 hl=4 l= 290 cons: SEQUENCE 
 4:d=1 hl=2 l= 13 cons: SEQUENCE 
 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
 17:d=2 hl=2 l= 0 prim: NULL 
 19:d=1 hl=4 l= 271 prim: BIT STRING: (bit string of the key here)

This is the visual representation of that data structure. The bit string is actually the data structure retrieved from SecItemCopyMatching previously shown.

Cryptography In IOS (II): Sharing public keys between iOS and the rest of the world

You specify an RSA key in the Security framework with the attribute kSecAttrKeyTypeRSA.

EC keys

ECC stands for “Elliptic Curve Cryptography“. From the Wikipedia:

Elliptic curve cryptography (ECC) is an approach to public-key cryptography based on the algebraic structure of elliptic curves over finite fields. One of the main benefits in comparison with non-ECC cryptography (with plain Galois fields as a basis) is the same level of security provided by keys of smaller size.

Indeed, EC keys are way smaller than its RSA counterparts for the same level of security. Probably, that’s one of the main reasons why Apple only allows these keys inside the secure enclave. You specify an EC key in the Security framework with the attribute kSecAttrKeyTypeEC.

There are many different types of EC keys, whose name depends on the mathematical curve that describes the algorithm behind them. Currently, these are the ones Apple supports:

  • kSecECCurveSecp256r1, corresponding to the ansiX9p256r1 curve. This is the only key allowed to be used for private keys contained inside the secure enclave.
  • kSecECCurveSecp384r1, corresponding to the secp384r1 curve.
  • kSecECCurveSecp521r1, corresponding to the secp521r1 curve.

Note: contrary to what’s specified in the documentation for kSecECCurveSecp256r1, the curve that needs to be specified in order for the generated key to be valid is not a prime256v1 (aka secp256r1), but a ansiX9p256r1 (OID 1.2.840.10045.3.1.7).

Building the EC Structure

Apple cryptographic tools again give us just a mere raw representation of the data. This time, as we don’t have any sequence of modulus+exponent, just the raw bits are exposed. Thus, we need to wrap it in the proper ASN.1 object structure. The length of the structure and the key itself depends on the curve chosen.

 0:d=0 hl=2 l= 89 cons: SEQUENCE 
 2:d=1 hl=2 l= 19 cons: SEQUENCE 
 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey
 13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1
 23:d=1 hl=2 l= 66 prim: BIT STRING

Here is a representation of the final wrapping of the data. In this case, the Bitstring is just the raw bits of the public key from SecKeyGeneratePair.

Cryptography In IOS (II): Sharing public keys between iOS and the rest of the world

An export mechanism that just works

CryptoImportExportManager makes it really simple to export the keys from iOS to the right format, ready to use in OpenSSL, PHP, Ruby, etc…

You just need to retrieve the public key bytes in an NSData by using SecItemCopyMatching, and then create an instance of CryptoImportExportManager and call its exportPublicKeyToDER(data, keyType, keySize) or exportPublicKeyToPEM(data, keyType, keySize) methods, depending on the output format you want. keyType can be either kSecAttrKeyTypeRSA or kSecAttrKeyTypeEC. The two key types allowed by Apple. Valid key sizes are 1024, 2048 and 4096 for RSA keys, and 256, 384 and 521 for EC keys (corresponding to the curves ansiX9p256r1, secpr384r1 and secp521r1). Example:

var pubKeyData = ... // data for the public key retrieved by SecItemCopyMatching
let keyType = kSecAttrKeyTypeEC
let keySize = 256
var exportImportManager = CryptoExportImportManager()
if let exportablePEMKey = exportImportManager.exportPublicKeyToPEM(pubKeyData, keyType: keyType, keySize: keySize) {
   // send pem string to server.
} else { ... }

Get the code

Cryptography In IOS (II): Sharing public keys between iOS and the rest of the world
CryptoImportExportManager is under the MIT license. You can get it here. It comes with a sample project to allow you to test both the importing and exporting functionality. If you find something missing or want to add anything, please don’t hesitate to leave a comment.

The project comes also with a sample PHP file that would read a key obtained from the CryptoImportExportManager. You just need to copy the PEM formatted output from the export controller, save it  in a file, and then call readkey.php:

php readkey.php public_key_file.pem

Where To Go Next

In conclusion, in this last episode of “Cryptography in iOS”, you learned how to share public keys between iOS and the rest of the world. This is essential if you want to integrate an iOS app in an Asymmetric Cryptography scenario. I also shared with you a manager to import and export public keys from your iOS application to your backend easily.

By now, you should have a good understanding of how Cryptography works in iOS. However, you might want to have a look at the previous post in the tutorial series: “Asymmetric Cryptography in iOS“.


Sergey Usov
November 1, 2015 At 8:58 pm

Great code, Ignacio, thanks!
It would be nice to have an option of saving imported public key in a keychain to use it later with AsymmetricCrypto.

    Ignacio Nieto Carvajal
    November 1, 2015 At 8:58 pm

    Thanks Sergey, nice suggestion! I will definitely add that when I have some time…

December 11, 2015 At 8:58 pm

Great blog. I’m running into problems when verifying signed content using java program. I’m able parse the public key fine using the raw key data. Any leads I can chase? Should I be using ansiX9p256r1 for verification?

    Ignacio Nieto Carvajal
    December 12, 2015 At 8:58 pm

    Hi Surya, are you experiencing problems when trying to verify the signature from iOS in Android? That’s exactly the case I want to pursue with my new password less authentication system.

March 8, 2016 At 8:58 pm

A real life-saver Ignacio thanks. This leads me on to ask the question.. is it possible to export the private key in PEM format too?



    Ignacio Nieto Carvajal
    March 8, 2016 At 8:58 pm

    Hi Geoff. Generally speaking, the private key is supposed to stay private inside the device. Why would you need to get it out? If you need some kind of KPI, it’s best to have the private/public key generated anywhere else, and then send the private keys in a secure way to the devices, and put the public key somewhere public. But generally speaking, private key is supposed to stay at the device.

April 17, 2016 At 8:58 pm

Great blog, but i have a problem. I want to share the public key with another Ios device to use asymmetric encryption. To achieve this,
I am getting the key with the “AsymmetricCryptoManager.sharedInstance.getPublicKeyData()” method. After that , I am exporting the key with the “exportImportManager.exportRSAPublicKeyToDER” method.
After that i transfer the NSData to the other device.
But the problem is , that when I want to import the data on the other device to get the Key, the “importPublicKeyReferenceFromDERCertificate” is returning nil.
Do you know how to fix that?

    Ignacio Nieto Carvajal
    April 20, 2016 At 8:58 pm

    Hi Maximilian,
    As you may imagine, all this project is aimed at exporting the iOS keys/certificates to be able to interact with non-iOS systems. If you try to import a key from the outside world (or one generated by this export project) you won’t be able to import it “as is” in iOS. You need to export the NSData directly from the Keychain, get the key bytes and import them in your other iOS device. External keys can only be imported through the certificate as I show in another section in that same project.

      August 17, 2016 At 8:58 pm

      Hello, nice blog. I have used these articles about cryptography as a reference for a little project between Mac OSX and iOS (and maybe also Android, Windows in future).

      So there’s no way to use the same import/export methods for public key transmission between Apple Apple and Apple Rest of the World ?

        Ignacio Nieto Carvajal
        August 17, 2016 At 8:58 pm

        Hi Joe,
        Thanks, I’m glad to know it helped. Unfortunately not, the Security framework from Apple has not really been thought to talk to the rest of the world or be use to integrate with OpenSSL or any other cryptographic system out there.
        Good luck in your project! :)

          August 22, 2016 At 8:58 pm

          Luck is what I need to survive Apple Keychain :)
          Now I an trying to export an OSX (or iOS) generated key data and to import it in another device using SecAddItem, but it is really bizzarre, as when I try to add a key, it returns “duplicate found” and when I try to delete any previous key I get “item does not exists”. So I wonder if it is possible to wrap public key data in a certificate and import it in another OSX (iOS) device as if it was made by OpenSSL. So I could use almost the same strategy for Apple -> Apple.
          Any suggestion is welcome

Managing contacts in Swift, AddressBook and Contacts frameworks | Digital Leaves
April 24, 2016 At 8:58 pm

[…] in swift is not as hard as dealing with cryptography on iOS, but the AddressBook framework has never been specially developer-friendly, and the strongly typed […]

June 17, 2016 At 8:58 pm

OMG, thanks a billion, your blog has literally saved my day. After two days of struggling with iOS poor document, just before I decided to jump into cryptology mess, I was lucky enough to read your blog. Thanks so much.

    Ignacio Nieto Carvajal
    June 17, 2016 At 8:58 pm

    Thanks to you. My pleasure to know it helped! Best regards.

      June 23, 2016 At 8:58 pm

      Fantastic blog, the most helpful on the net and I have been looking for this sort of assistance for 72 hours straight… I have a question, does this method allow me to use Bersteins ‘Curve 25519’

      thanks Ian

        Ignacio Nieto Carvajal
        June 23, 2016 At 8:58 pm

        Hi Ian, thanks for your words. Unfortunately, Apple currently only supports three curves:
        kSecECCurveSecp256r1, corresponding to the ansiX9p256r1 curve, kSecECCurveSecp384r1, corresponding to the secp384r1 curve.
        and kSecECCurveSecp521r1, corresponding to the secp521r1 curve.

        I haven’t tested in iOS 10 yet, but I suspect Apple didn’t add new curves.

          July 4, 2016 At 8:58 pm

          Hi Ignacio,

          Thanks for your responses, ah a great shame, apple sure seem to make it tricky for us to achieve best possible security, too many unannounced back doors on trap doors these days. Re: Dual_EC_DRBG NIST.

          If by a miracle you find 25519 on ios 10, or find a way to achieve this in the future- please do let me know. – I would be greatly indebted to you.

          All Great work, thanks for responding.


August 1, 2016 At 8:58 pm

Hi, looks like a a really useful library.

I have a couple of question though: I use 5120 bit RSA keys on iOS and need to export the public keys for encryption and signing on other platforms. I note that in your documentation you mention keys unto 4096 bits are supported.

What would I need to do add support for 5120 bit keys please?

The other question I have is: how do we go the other way? So once we’ve converted the iOS key to a portable format – how do we parse the portable format to get back a key than be used by the Sec* methods on iOS?



    Ignacio Nieto Carvajal
    August 1, 2016 At 8:58 pm

    Hi Vijay. To be honest, I’ve always sticked to the standard RSA sizes (2048, 4096…), so I’ve never tried, but apparently there’s nothing in Apple’s documentation preventing you from using that key sizes. It’s as easy as trying a SecItemAdd with that kSecAttrKeySizeInBits (and hoping that you don’t get an error back). If you are going to use the secure enclave, however, then you are limited to EC keys of exactly 256 bits in length. If you want to add support for that special length, you need to have a look at the exportRSAPublicKeyToDER method, specifically to the construction of the length header and the total size.

    Unfortunately, there’s no way of going back (sadly), at least that I’m aware of. According to Apple Security framework engineers (when you are lucky enough to receive a helpful or meaningful bit of information from them), the way of importing keys to the device keychain (or using them any other way with the Security framework in iOS) is importing the whole certificate, so if you only have the public key, you are out of luck. I wasted more than two months researching that so, if you find a way of importing just a public key into iOS, please let me know, I’d be really happy to know.


September 5, 2016 At 8:58 pm

Thanks so much for your work! You have done a great job of explaining the subject, and saved me hours of frustration. I know it’s not the scope of this blog, but if you ever figure out how to sign a document created on iOS and distributed the doc and public key to the world (including iOS, and other environments), I would definitely be interested.

Thanks again, I have enjoyed your blog.

    Ignacio Nieto Carvajal
    September 5, 2016 At 8:58 pm

    Thanks JB, my pleasure to know it helped. Actually, funny you ask because that’s something I’m working on right now.

September 15, 2016 At 8:58 pm

Hi Ignacio,

Thanks, this has been helpful. However, I’m trying to understand the null byte that’s inserted right before the bit string in the RSA public key section. What part of the encoding rules specifies this?

    Ignacio Nieto Carvajal
    September 16, 2016 At 8:58 pm


    That null corresponds to the ASN.1 “parameters” of the RSA encoding that we are specifying. In PKCS#1, even though the parameters are optional, the null value (0x05 0x00) was added as the proper way to specify that there are no parameters (null). In theory, some implementations might accept a codification in which you omit it, but the recommended implementation of PKCS#1 includes it. These rules are a little tricky, and the specification is a little too complex, so I would recommend you to read the RFC 3447 ( if you need a more in-depth understanding on how PKCS#1 works.

    Hope it helps.

Shafi Ahmed
March 23, 2017 At 8:58 pm

Thanks a lot for the quick help!
Basically I want to generate RSA keypair. Using your crypto manager I’m able to generate a public key that I send to my server. Its working perfectly right there.
Our sever encrypts some message successfully there with the same public key and sends it to my iOS app. Now I want decrypt the message with my private key. But I don’t have the private key.

However I see that crypto manager generates key pair, means private key as well. But the format of the key is not same as public key.
So how do we get the private key and in the same format as public key using the crypto manager?

Please help!
Thank you,


    Ignacio Nieto Carvajal
    March 23, 2017 At 8:58 pm

    Hi Shafi!
    The process is the following: you need to generate certificates for your server (using OpenSSL, including the generation of the private key), and then send the public certificate of the server (with the public key) to the client, the client will use my software to communicate with the server. On the other hand, the client will generate a keypair (again, you can use my tool to do that) and export the public key, and send that to your server. The server can import it properly, and you have both communication channels covered.

Shafi Ahmed
March 24, 2017 At 8:58 pm

Please ignore my last comment!

What we are trying to do is :
1) generate key par in iOS device.
2) send this public key to server. PUB1
3) signed some string (a symmetric key) using this PRIVATE key. S1.
4) send signed string S1 (generated in step 3) to the server.
5) Using PUB1, server tries to check if S1 is signed properly.
Server guy is initially having problem is step 5 as its throwing exception that the public key PUB1 is not valid. But using your tool we successfully doing this. Public key is working server side perfectly.
Now problem is how to get the private key so that our client can sign (step 3)
Our Android app (the client) doesn’t have any issues and its working this way without any issue however we want to do the same with iOS app.
Is that possible?
Can we get a valid PRIVATE key in iOS like we are getting a PUBLIC key using your tool?

Thank you

    Ignacio Nieto Carvajal
    March 24, 2017 At 8:58 pm

    Well, sure, but to be completely clear about this: you don’t need to extract the private key, right? You just need to sign a string in the iOS app with your private key from the keypair right? In that case, all you have to do is call the SecKeyRawSign method, please have a look at this post: , specifically the “Signing A Message And Verifying The Signature Scenario.” section.

Shafi Ahmed
March 25, 2017 At 8:58 pm

Ok thanks. This link certainly helped me to understand asymmetric cryptography. You are right we want to signing with the private key. We have our app written in Swift 2.2. So want to port your tool back to Swift 2.2. We have issue in porting this block of code:

// start building the ASN.1 header
let headerBuffer = headerData.withUnsafeMutableBytes {
(bytes: UnsafeMutablePointer) -> UnsafeMutablePointer in
bytes[0] = kCryptoExportImportManagerASNHeaderSequenceMark // sequence start
return bytes

Looking for how to replace this piece of code in Swift 2.2 as withUnsafeMutableBytes is not supported in 2.2. Do you have backup of your tool back to Swift 2.2?

Thanks for your prompt replies! I know you might be very busy but you saved my week long time in struggling with these issues.

    Ignacio Nieto Carvajal
    March 27, 2017 At 8:58 pm

    Hi there Shafi!
    I’m afraid I don’t. Basically, what changed in Swift 2.3 was the addition of Data as a Swift construct and its related methods (like withUnsafeBytes/withUnsafeMutableBytes). You need to replace the Data class with a good old NSData, and use the NSData methods via UnsafeMutablePointer and UnsafePointer. Use the methods bytes and mutableBytes of NSData for that. It shouldn’t be much work.

Shafi Ahmed
March 29, 2017 At 8:58 pm

Hi Ignacio,

Can you help me porting this piece of code to Swift 2.2 or or Objective-C?

// start building the ASN.1 header
let headerBuffer = headerData.withUnsafeMutableBytes {
(bytes: UnsafeMutablePointer) -> UnsafeMutablePointer in
bytes[0] = kCryptoExportImportManagerASNHeaderSequenceMark // sequence start
return bytes

Actually I tried but I’m not able to convert it successfully using NSData.

Shafi Ahmed
March 31, 2017 At 8:58 pm

Waiting for your help. I just wanted to convert this code in Swift 2.3. I tried a lot using UnsafeMutablePointer but I’m unable understand how exactly it can be converted.

var headerData = NSMutableData.init(length: 15)

let headerBuffer = headerData.withUnsafeMutableBytes {
(bytes: UnsafeMutablePointer) -> UnsafeMutablePointer in
bytes[0] = kCryptoExportImportManagerASNHeaderSequenceMark // sequence start
return bytes

Thank you

    Ignacio Nieto Carvajal
    April 4, 2017 At 8:58 pm

    Hi there! Sorry for my late reply. I’m afraid that would take me some time to get it back to the old Swift 2.2 version. I contacted you privately so maybe we can continue by email? Probably we could arrange some kind of time for developing a Swift 2.2 version if updating to Swift 2.3 is not an option for you?


Shafi Ahmed
April 5, 2017 At 8:58 pm


Sorry! My current project uses Swift 2.3 instead of 2.2. If we can port this method:

public mutating func withUnsafeMutableBytes(_ body: (UnsafeMutablePointer) throws -> ResultType) rethrows -> ResultType

or we can write similar method that can work on Swift 2.3 would be huge help for me.

Thank you,


Aun Chatchawal
April 19, 2017 At 8:58 pm

Hi, I have to do PKCS#7 Can you give me any advices ?

    Ignacio Nieto Carvajal
    April 19, 2017 At 8:58 pm

    Hi there, I’m afraid I don’t quite understand your question, can you elaborate? To build a PKCS#7, you just can use some openssl commands.

Jason Lee
April 20, 2017 At 8:58 pm

Hi Ignacio, thank you for the wonderful write-up as well as the library. I seem to be missing one piece of the puzzle however. I read Maximilian’s comment above and I’m wondering how it is that your code can generate the DER cert to be used server side but you cannot use the same data to import back into iOS? Again, I am aware that I am fundamentally misunderstanding something along the way and wondered if you could elaborate?

    Ignacio Nieto Carvajal
    April 21, 2017 At 8:58 pm

    Hi there Jason!

    Thanks to you for commenting. Yes. This is completely an Apple’s development decision. It’s how the cryptographic SDKs in iOS have been designed. I don’t know if this was an early decision to get some security through obscurity, or that interacting with the outside world was never a requisite in the minds of the engineers that designed this. They just didn’t want to talk in a common language, like the rest of the world (i.e: OpenSSL) does.
    The result is clear: you cannot just get a public key from the outside world and import it into your iOS device and start verifying some signatures. You need a whole certificate to import. This piece of wisdom comes directly from the guy in charge of that at Apple (known as “Quinn the Eskimo”), which by the way was very impolite and arrogant when asked for help. It seems I was attacking their work or their way of doing things just by asking how to import keys in iOS devices.
    In my mind, it’s obvious that modernizing and making the cryptographic API more open is not a priority in Apple’s HQ.
    Exporting is not easy, but once you know how keys are being stored and returned by the cryptographic API, it’s doable. However, the only method to import cryptographic credentials that works, as far as I know, is SecCertificateCreateWithData.
    I would love to give you a more reasonable explanation, however, but this seems like another example of the “You are doing it wrong” philosophy at Apple.
    Now, I might be wrong, and if you find a way of importing just a DER, PEM, PKCS-whatever public key into iOS, I’ll be glad to hear about it :)

Cryptography In IOS (II): Asymmetric cryptography in Swift – Digital Leaves
May 18, 2017 At 8:58 pm

[…] decrypting and verifying signatures. Next, in the third episode of the series, we will see how to import and export keys between iOS and other cryptographic systems (like […]

May 29, 2017 At 8:58 pm

Hi, Ignacio, thanks for a nice article!

Just trying to get my head around this. I am trying to generate a public/private key pair for SSH-ing into a Linux server using your nice GitHub project.

The private and public key pairs do not match up when I am trying authenticating with the server. What I want is to emulate how ssh-keygen on the desktop works.

I am a total newbie on encryption, but this is because I need an OpenSSL library which is completely different than the libraries than Apple provides for iOS? This will not work, right?

Thanks in advance!

    Ignacio Nieto Carvajal
    May 29, 2017 At 8:58 pm

    Hi there Jan,
    Thanks for commenting. I’m afraid I didn’t understand your use case. Generally speaking, if you generate a keypair in the iOS device, the private key has to stay inside the device (that’s the whole point). Then, you can export the public key using the CryptoImportExportManager, and send that key to the server. The server will store it somehow (i.e: SSH via OpenSSL will check .ssh/authorized_keys) and then you can match it against your private key in the device.
    However, I still think I didn’t quite understand you. Can you elaborate on your use case?

Anders Brink
September 13, 2017 At 8:58 pm

Hi and thanks for a good article, I’m new to the whole crypto-world and this made it sliiiiightly more understandable :)
I think I’ve managed to export the public key, but for the life of me I cannot find or figure out a way to use that key to verify, using Java8, the signature my iOS-device has created.
I’m using kSecECCurveSecp256r1 since it’s going to be stored in the vault.
If I debug my iOS code I can find and String-parse the x and y keys and using the following (excerpt)

import java.text.SimpleDateFormat;
import java.util.Base64;

String signature = “MEYCIQCbzqCDpLi9EG2K8ryig1vojasaS7MyMcA9lpzu8XVPLAIhAP7dTNzWgnA5N9G1Waj8moP5q6IwyGJQ9YO+5hv3xR47”;
String signatureData = “johan”;
String x = “1A2A44454E06A16FCDBF1D595026B70D036D702F6B81F670A74D0CFBB423232D”;
String y = “7009D173D3FE34D5D43C08FAE6B94D63DC6324418021551948B2D1C38696BC54”;

AlgorithmParameters parameters = AlgorithmParameters.getInstance(“EC”, “SunEC”);
parameters.init(new ECGenParameterSpec(“secp256r1”));
ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class);
ECPoint ecPoint = new ECPoint(new BigInteger(x), new BigInteger(y));
ECPublicKeySpec keySpec = new ECPublicKeySpec(ecPoint, ecParameters);

PublicKey publicKey = KeyFactory.getInstance(“EC”).generatePublic(keySpec);

Signature ecdsaImpl = Signature.getInstance(“SHA256withECDSA”);



If you have any good links to working java-code or anything to help me figure this out I’d much appreciate it!

    Anders Brink
    September 13, 2017 At 8:58 pm

    ahhh, premature posting…
    I meant that I can verify the signature in Java using the x and y public key I dug out from the iOS code but I haven’t managed to use the “real” exported key to do it…

    Anders Brink
    September 14, 2017 At 8:58 pm

    Well, I solved it :)

    Provider provider = new SunEC();
    Reader publicKeyReader = new StringReader(publicKeyString); // or from file etc.
    PemObject publicKeyPemReader = new PemReader(publicKeyReader).readPemObject();
    PublicKey publicKey = KeyFactory.getInstance(“EC”, provider).generatePublic(new X509EncodedKeySpec(publicKeyPemReader.getContent()));

      Anders Brink
      September 14, 2017 At 8:58 pm

      or rather

      Provider provider = new BouncyCastleProvider();

        Ignacio Nieto Carvajal
        September 15, 2017 At 8:58 pm

        Hi there Anders. Sorry for my late reply, I am in the middle of the NSSpain conference this week, so kind of busy. Glad to know you finally got it sorted out. Let me know if I can help with any other issue.

Sébastien Brault
February 27, 2018 At 8:58 pm

Hi Ignacio. Thanks a lot for your work and for your code, and thanks a lot for sharing it. It has a lot of value, I was not able to find anywhere else a piece of code to that “really” works like yours. Your implementation is the only one I found which is really serious and very well documented, on a subject which is all but easy. So one more time, thank you very much.

Best regards. Sebastien.

    Ignacio Nieto Carvajal
    February 27, 2018 At 8:58 pm

    Hello there Sébastien, thanks a lot for your comment. I put a lot of effort on it, so it’s great receiving messages like yours :)

Matheus Dutra Bloebaum
March 29, 2018 At 8:58 pm

Hello Ignacio, thanks a lot for your time explaining this awesome code! I spent over a week trying to do this in my own hands and, bro.. Swift 4 and iOS libraries are way harder to handle than Java and Android libraries.. Talking about Java, I have the following scenario: Android Application in Java, iOS Application in Swift4 and my Server in Java8 with Tomcat. My communication with encoding RSA/AES and decoding AES/RSA from Android to Server and vice-versa are alright. Both PublicKeys are publics and PrivateKeys are private (in own applications).
My problem with iOS -> Java Server is the following:

– OK, I could create my Public and Private Keys in iOS using your awesome code.

– I could export my iOS PublicKey and save in my Java Server by CryptoExportImportManager, but here starts the issues.. To export a VALID key in Java Cipher, I had to: (1) use the exportRSAPublicKeyToDER() method, (2) encode to Base64, receiving another Data datatype, (3) convert to String again to (4) send via JSON to my server. (works perfectly!)

– When my iOS PublicKey is used by the Server, to Encode and send information back to iOS, I receive everything fine just like in Android, but my PrivateKey in iOS still dont’t have the same mathematical bytes as PublicKey have, once I had to do the steps 1, 2 and 3 in PublicKey and PrivateKey kept the same as created.

My problem here, I believe, is that your CryptoExportImportManager don’t have the exportRSAPRIVATEKeyToDER() method to use and do also the steps 2 and 3 to have absolutely the same math as in PublicKey. Could you please help? I tried to use my PrivateKey as parameter to exportRSAPublicKeyToDER() and repeat the other steps, but still don’t worked.. Any tips?

I will be keep trying, if got something I answer here..

Dawud Tan
August 5, 2018 At 8:58 pm

I think secp256r1 is equivalent to prime256v1, isn’t it?

Leave a Comment

sing in to post your comment or sign-up if you dont have any account.