15 March 2020

Exporting Private RSA SecKey as PKCS #1 PEM

If you have a RSA private key that you want to send somewhere, most likely you would want it in PKCS #1 PEM format to ensure compatibility with other systems.

⚠️ Exporting a private key from its SecKey reference should never be recommended for reasons that it might get compromised by an untrusted entity.

Example SecKey

Example SecKey has following characteristics:

and is created like so:

let attributes: [String: Any] = [
    kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
    kSecAttrKeySizeInBits as String: 2048,
]

var error: Unmanaged<CFError>?

guard let secKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
    // Handle error
}

For detailed tutorial around creating cryptographic keys follow the Generating New Cryptographic Keys article by Apple.

Extracting PKCS #1

You extract the PKCS #1 from a RSA SecKey using the SecKeyCopyExternalRepresentation(_:_:) function:

var error: Unmanaged<CFError>?

guard let pkcs1 = SecKeyCopyExternalRepresentation(secKey, &error) as Data? else {
    // Handle error
}

It's worth noting that the SecKey API provides external representations of RSA keys only in PKCS #1.

Creating PEM

To create a valid PEM file, first Base64 encode the PKCS #1 data delimited into 64 character long lines as specified in the Printable Encoding section of RFC 1421. Conveniently enough Data provides an API with Base64 Encoding Options for just that:

let base64EncodedPKCS1 = pkcs1.base64EncodedString(options: [.lineLength64Characters, .endLineWithLineFeed])

Lastly, provide appropriate header and footer boundaries for the encapsulated data:

let pem = [
    "-----BEGIN RSA PRIVATE KEY-----",
    base64EncodedPKCS1,
    "-----END RSA PRIVATE KEY-----"
].joined(separator: "\n")

End result should look something like this (contents between header and footer will differ of course):

-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAoTWdgxkX6bhmR4rXHEIshUb3yBlFc/pSZOWNLUGH5OSO8wNP
efv/5BhpUvNbxqOJZoPQEdWURNxnyplbInyok5aplbn1o5Rcl5Gs9YO/QitPO5P8
K92cKZePAbgR1fBgwEwk9IkMZhQx+Ph7/+oSRpLCNh1tpuxJut+4gMcSuhrCem/y
Z+VcwoHAzvt0WP6qwXWhI6pAi8aablPBodTl35Ip45h7rmvAiiws/VeuyELjncTD
08PQAaBQYzDi3X0ryP47d5BfVd8ZqSzz8dQwTMGJbbToJaU+IRqKiuNBujJ+SKD7
4ZBzwZMevpVgNX+jqbHsm95s4LeSKRhlezyG1QIDAQABAoIBAAurrn4FrIoCjAEE
56LHlaKGazzEu5b0Wc+tIKXUlyp2c3TbWf8aQ8G3FLTpIk1EnJdb1o3b+PJtRGRR
6tuZy7h3kUpiHorbnEJqzOsvQQLg0Mke4wQn9Hy8WKGGul/TGaYCPTCo1Ul0j9OW
5Z82ymDqkf3J7pzFgWbyeFB2WQA4/zM61LEF1dvHYQjAM3Exe1zUuJRu52meE84/
7cA7g7dVRiKs2tXzIsmC4parre5cBuQT1Jwu2QH7obp3ur7tEU156YwhYgaDO+ev
OAzfhugSzHSk832LZplIxjDNl44jKzic/9tBaathgfUKyegYjtufO/zBXq0ZldNn
8OPAUIECgYEA3R6RG0Io9eowxdStLuSBALOc4BYZB8BrIS7a/GNyObGBZQPBsWxa
TaICqUX4hE3EsVn8OWuxErgd2NI3Gw3Q3PdELXhmHJD+WRnW0wJ4CWAbY21cRhMY
B6SEDe+cxRYY9rAXT7kxUnMoZ4G2mtA4gulkcjQKwZubJfVZ3czh30ECgYEAuqO2
fBNVyBHZUDkgUPsJi5r3n1kwblGaeQqbp16jNUsfOzSNaFz+jRF1BbI7OZWb1RM1
vWwfTReeYOYfWaYwpxBcCG/U3XhTXJvLOukR3Wb8ZcE/kA0NyP9cKQy0g2Z373mp
kBYQycyBXAwiMYFPfmlDwowDSjrDnPPz0uMWFpUCgYEAjBHv46+OWPEoQjmOFzVi
zrn4ty7oXjOy6UtQJy8rzYY3LHErwqObtK/bNbWATvcgkSQqlYk1m2EMbywDAl1H
IKJ2CsPJE3F53aFzpylaNr4tu1csa6tuvnClwlo2Gdb8q1AzBCqRJuSSBLdzoDAk
jDEikwGKishyiKIacll1/8ECgYAqL2jGwKQJ9abV0COyyhsNN/iyRrmApecxZqlp
+iUPnawweJ9hsGtEvWZi5Dcou90eGxpxdyfYB/efVUROwhaLHFKBAa3uZQ0KiJg1
94o3LdjssvJH//tWrAlLqfh/HsELGsetrp8azaOLh56O6/hozSgop/byZzfhmO5K
g1NxxQKBgB0v2zSBUo4a4dPT+4b1wndNiPRibMRKPjyISVglm5p5yZiX9wrlqB2Y
8t2FcgFjuovWvuHOnP2/72+uT4flR73FrJ4gKArk2QJYJV52N4Z1p/fC2jFSh/0J
nIG3IPd+/S8HIDzJkK7/T06+H9ajdq+cE65g0wFQOXEaGKdsRd7U
-----END RSA PRIVATE KEY-----

Share this article on Twitter. For any questions, comments or feedback reach out to me @hungrxyz.