On Cryptographic Key Formats

This thread has been locked by a moderator.
I regularly see folks having problems importing cryptographic keys, so I thought I’d write down some hints and tips on how to recognise and import the various key formats. This post describes how to recognise the format of the data you have. A companion post, Importing Cryptographic Keys, discusses how to import each type of key.

If you have questions about any of this stuff, please put them in a new thread, tagging it with Security or Apple CryptoKit.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"



On Cryptographic Key Formats


To import a key you must first work out its format and then align that format with one of the import routines in Security framework or Apple CryptoKit. This post covers the first step, figuring out the format of the key you’re working with. This is surprisingly tricky because:
  • There are a number of different key types with a number of different encodings.

  • In many cases the source of your key does not clearly document its type and encoding.

  • In some cases the documentation you do get is out-and-out wrong.

Public and private keys come in a variety of types but the ones supported by Apple are:
  • RSA

  • SECG secp256r1, aka NIST P-256

  • SECG secp384r1, aka NIST P-384

  • SECG secp521r1, aka NIST P-521

  • Curve 25519

Such keys can be encoded in a number of different ways:
These encodings can be nested, and the same key can be nested in multiple different ways. For example, an RSA key may be DER encoded and then PEM encoded, or it may be directly PEM encoded.

Once you understand the format of the key you’re trying to import, read Importing Cryptographic Keys for information on how to import that key.

PEM


PEM (short for Privacy-Enhanced Mail) is a text file format that’s easy to spot. For example:

Code Block
% cat public-key-p256.pem
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELCHzcEnURkr78BgTxRpOHveoEB0q
oStqiJY1vHw36QEb/dVABv3r2u8NhqbWYlYTR5gslSdgE9HBzS14Za/wIw==
-----END PUBLIC KEY-----


PEM is a very flexible format. It’s not uncommon for PEM files to contain metadata outside of the BEGIN and END encapsulation boundaries, or multiple credentials within the same file, each with its own encapsulation boundaries. However, the critical things to note are the:
  • Label

  • Encapsulated Data

The label identifies the type of credential represented by the PEM. The example above is a public key (PUBLIC KEY) but you might see a private key (PRIVATE KEY), a certificate (CERTIFICATE), a specific type of key (for example, RSA PUBLIC KEY), and so on.

IMPORTANT Generic keys (PUBLIC KEY and PRIVATE KEY) use a different format from typed keys (for example, RSA PUBLIC KEY and RSA PRIVATE KEY). However, it’s not uncommon for PEMs to be mislabelled, for example, be labelled PRIVATE KEY but contain an EC PRIVATE KEY. Ain’t crypto fun!?!

The encapsulated data, the Base64 encoded data between the encapsulation boundaries, represents the credential itself. You interpret this data based on the label. For example, a public key’s data is an DER-encode ASN.1 SubjectPublicKeyInfo structure (more on this below) and to interpret that you first decode the Base64 and then dump the ASN.1:

Code Block
% base64 -D > public-key-p256.der
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELCHzcEnURkr78BgTxRpOHveoEB0q
oStqiJY1vHw36QEb/dVABv3r2u8NhqbWYlYTR5gslSdgE9HBzS14Za/wIw==
^D
% dumpasn1 -p -a public-key-p256.der
SEQUENCE {
SEQUENCE {
OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
}
BIT STRING
04 2C 21 F3 70 49 D4 46 4A FB F0 18 13 C5 1A 4E
1E F7 A8 10 1D 2A A1 2B 6A 88 96 35 BC 7C 37 E9
01 1B FD D5 40 06 FD EB DA EF 0D 86 A6 D6 62 56
13 47 98 2C 95 27 60 13 D1 C1 CD 2D 78 65 AF F0
23
}


I’m using the dumpasn1 tool, available here.

Note There are easier ways to decode PEM files, most notably the openssl tool. I’m deliberately using primitive methods to illustrate how the parts fit together.

DER Encoded ASN.1


ASN.1 is a very flexible format for describing data structures. ASN.1 can be encoded in various ways but, in a cryptographic context you most commonly see DER-encoded ASN.1. Recognising DER data isn’t always easy, although there are some tricks. Consider this hex dump of the public-key.asn1 file from the previous section:

Code Block
% xxd -p public-key-p256.der
3059301306072a8648ce3d020106082a8648ce3d030107034200042c21f3
7049d4464afbf01813c51a4e1ef7a8101d2aa12b6a889635bc7c37e9011b
fdd54006fdebdaef0d86a6d662561347982c95276013d1c1cd2d7865aff0
23


The presence of the leading 0x30 is a common indicator that you’re looking at DER-encoded ASN.1 (that’s because 0x30 is the most common encoding for the ASN.1 SEQUENCE element). If you suspect that the data is DER, run dumpasn1 to confirm that:

Code Block
% dumpasn1 -p -a public-key-p256.der
SEQUENCE {
SEQUENCE {
OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
}
BIT STRING
04 2C 21 F3 70 49 D4 46 4A FB F0 18 13 C5 1A 4E
1E F7 A8 10 1D 2A A1 2B 6A 88 96 35 BC 7C 37 E9
01 1B FD D5 40 06 FD EB DA EF 0D 86 A6 D6 62 56
13 47 98 2C 95 27 60 13 D1 C1 CD 2D 78 65 AF F0
23
}


A ‘clean’ dump confirms that you’re looking at DER-encoded ASN.1. The question then becomes “What type of data is this?” If the ASN.1 came from a PEM, the PEM’s label indicates the type. If not, it’s helpful if you can match the ASN.1 against the well-known structures discussed below.

Public Key


A public key (PEM label PUBLIC KEY) is held in an ASN.1 SubjectPublicKeyInfo structure, as defined in RFC 5280. For example:

Code Block
% xxd -p public-key-p256.der
3059301306072a8648ce3d020106082a8648ce3d030107034200042c21f3
7049d4464afbf01813c51a4e1ef7a8101d2aa12b6a889635bc7c37e9011b
fdd54006fdebdaef0d86a6d662561347982c95276013d1c1cd2d7865aff0
23
%
% dumpasn1 -p -a public-key-p256.der
SEQUENCE {
SEQUENCE {
OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
}
BIT STRING
04 2C 21 F3 70 49 D4 46 4A FB F0 18 13 C5 1A 4E
1E F7 A8 10 1D 2A A1 2B 6A 88 96 35 BC 7C 37 E9
01 1B FD D5 40 06 FD EB DA EF 0D 86 A6 D6 62 56
13 47 98 2C 95 27 60 13 D1 C1 CD 2D 78 65 AF F0
23
}


The SEQUENCE starting on line 9 identifies the key algorithm. dumpasn1 helps you out here by decoding the OBJECT IDENTIFIER (OID) into a human readable form. In this case ecPublicKey indicates that we’re looking at an elliptic curve key. The remainder of this sequence holds algorithm parameters, discussed below. Finally, the BIT STRING starting on line 13 contains the public key, the format of which depends on the algorithm; see the Typed Public Key section for details.

The algorithm parameters vary by algorithm:
  • RSA keys have no parameters.

  • Common EC keys have a single parameter indicating a named elliptic curve. In the above example, prime256v1 indicates a specific curve defined by SECG.

  • You may also see an EC key with a complex set of parameters that defines the specific curve to use.

Note Security framework and Apple CryptoKit support specific named curves (more on those below). If you have a key with complex parameters, you will not be able to use it with those APIs.

Take care when reading curve names because they can contain subtle differences. For example, secp256r1 is different from secp256k1, and the latter is not supported by Apple platforms. Also, some curves have multiple common names. For example, dumpasn1 display a secp256r1 curve using the old prime256v1 name whereas in other situations you might see the newer secp256r1 name. When in doubt, check the OID against the documentation. Specifically:
  • RFC 3279 lists the OIDs for RSA keys.

  • RFC 5480 lists the OIDs for SECG keys.

  • RFC 8410 lists the OIDs for Curve 25519 keys.

For the keys supported by Apple platforms, here’s what you’ll see reported by dumpasn1:
  • RSA: rsaEncryption (1 2 840 113549 1 1 1)

  • SECG secp256r1: prime256v1 (1 2 840 10045 3 1 7)

  • SECG secp384r1: secp384r1 (1 3 132 0 34)

  • SECG secp521r1: secp521r1 (1 3 132 0 35)

  • Curve 25519: curveEd25519 (1 3 101 112)

Private Key


A private key (PEM label PRIVATE KEY) is held in a PKCS#8 structure, as defined by RFC 5208. There are two possibilities here:
  • A plaintext private key, defined by the PrivateKeyInfo structure.

  • An encrypted private key, defined by the EncryptedPrivateKeyInfo.

I’m going to focus on the first one.

Note RFC 5208 has been obsoleted by RFC 5958 but I’m referencing the old RFC because I find it easier to read.

When you dump a PrivateKeyInfo structure you’ll see something like this:

Code Block
% xxd -p private-key-p256.der
308187020100301306072a8648ce3d020106082a8648ce3d030107046d30
6b0201010420986a7a91cbb5f4f81636e81aaff0835a771dc66865c407a8
e84469cf6ab8a477a144034200049747e981aab8ea71a255cd9a1562858c
406006f1e418260d31e1a77f6c2b35a9a3132f232db00351d9d8003487d4
ee52847990313daa7c721f88d4bb56da91c7
%
% dumpasn1 -p -a -e private-key-p256.der
SEQUENCE {
INTEGER 0
SEQUENCE {
OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
}
OCTET STRING
30 6B 02 01 01 04 20 98 6A 7A 91 CB B5 F4 F8 16
36 E8 1A AF F0 83 5A 77 1D C6 68 65 C4 07 A8 E8
44 69 CF 6A B8 A4 77 A1 44 03 42 00 04 97 47 E9
81 AA B8 EA 71 A2 55 CD 9A 15 62 85 8C 40 60 06
F1 E4 18 26 0D 31 E1 A7 7F 6C 2B 35 A9 A3 13 2F
23 2D B0 03 51 D9 D8 00 34 87 D4 EE 52 84 79 90
31 3D AA 7C 72 1F 88 D4 BB 56 DA 91 C7
}


The INTEGER on line 10 is a version number. The SEQUENCE starting on line 11 is the key algorithm; see the discussion in the Public Key section, above. The OCTET STRING starting on line 15 is the private key, the format of which depends on the algorithm; see the Typed Private Key section for details.

IMPORTANT If you receive a PEM labelled PRIVATE KEY that doesn’t match up with this PrivateKeyInfo structure, there are two possibilities:
  • The private key may be encrypted. In that case decrypt it using the openssl tool.

  • The private key may be mislabelled. It’s depressingly common to find a typed private key labelled as PRIVATE KEY.

Typed Public Key


A typed public key has a label AAA PUBLIC KEY, where AAA denotes an algorithm. Typed public keys are relatively rare, but it’s important to understand the format because it’s this format that’s encapsulated within the SubjectPublicKeyInfo struct in the PUBLIC KEY format.

The format for the typed public key data varies by algorithm. For the algorithms supported by Apple platforms, the data in the typed public key matches the public key’s raw key bytes; see Raw Key Bytes for the details.

Typed Private Keys


A typed private key has a label AAA PRIVATE KEY, where AAA denotes an algorithm. Typed private keys are relatively rare, but it’s important to understand the format because it’s this format that’s encapsulated within the PrivateKeyInfo structure in the PRIVATE KEY format.

The format for the typed private key data varies by algorithm. For an RSA key it matches the raw key bytes of the private key; see Raw Key Bytes for the details. For other key types that’s not the case.

Curve 25519 is an easy one:

Code Block
% xxd -p curve25519-private-key.der
04209fd90805255bae86a6c3035b2de837e929ea792ea11fd466e67ed0b2
65c0a999
%
% dumpasn1 -p -a curve25519-private-key.der
OCTET STRING
9F D9 08 05 25 5B AE 86 A6 C3 03 5B 2D E8 37 E9
29 EA 79 2E A1 1F D4 66 E6 7E D0 B2 65 C0 A9 99


The raw key bytes is simply wrapped in an OCTET STRING.

In contrast, the story for SECG keys is more complex. Consider this:

Code Block
% xxd -p p256-private-key.der
308187020100301306072a8648ce3d020106082a8648ce3d030107046d30
6b0201010420986a7a91cbb5f4f81636e81aaff0835a771dc66865c407a8
e84469cf6ab8a477a144034200049747e981aab8ea71a255cd9a1562858c
406006f1e418260d31e1a77f6c2b35a9a3132f232db00351d9d8003487d4
ee52847990313daa7c721f88d4bb56da91c7
%
% dumpasn1 -p -a p256-private-key.der
SEQUENCE {
INTEGER 0
SEQUENCE {
OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
}
OCTET STRING, encapsulates {
SEQUENCE {
INTEGER 1
OCTET STRING
98 6A 7A 91 CB B5 F4 F8 16 36 E8 1A AF F0 83 5A
77 1D C6 68 65 C4 07 A8 E8 44 69 CF 6A B8 A4 77
[1] {
BIT STRING
04 97 47 E9 81 AA B8 EA 71 A2 55 CD 9A 15 62 85
8C 40 60 06 F1 E4 18 26 0D 31 E1 A7 7F 6C 2B 35
A9 A3 13 2F 23 2D B0 03 51 D9 D8 00 34 87 D4 EE
52 84 79 90 31 3D AA 7C 72 1F 88 D4 BB 56 DA 91
C7
}
}
}
}


This is an ASN.1 ECPrivateKey structure, as defined by RFC 5915. The raw key bytes are split between two fields:
  • The BIT STRING starting on line 22 contains the marker (04) and the X and Y values.

  • The OCTET STRING starting on line 18 contains the K value.

See Raw Key Bytes for more information on these values.

Raw Key Bytes


It should come as no surprise that the raw key bytes are different for each algorithm.

RSA


An RSA public key is stored in an RSAPublicKey structure, as defined by RFC 8017. For example:

Code Block
% xxd -p rsa-public-key.der
3082010a0282010100cf243c324b262470131648614b62ee9c52af43319c
2498a7c16ba9790bb3a881f960f7b0303f8f49e86fedd6813be5fa888393
55d04426df0050dbb771eb683773b7dd929949695093f910c8dcdb633674
de986ada8d643e0e819b7cd5ab3bde4372103797472dc843a2711699e21a
4afddeed9f62810316903457342c345a35ebb2f06da019fed2afa56e7856
6e75a0d712849ae255155d9304348318930611b3b4f1153d77ee5970f076
299c548c8afff53157205048ade26d40930af2ecc96d4f77e8591523b767
fa3cdbc45a8a210339c4a556cea2e0dfa3ee819b62e463f75d87a53c2fbd
1bbcb8ec8fe2e8000ce37235fa903113c7b37d9c2a8b39c54b0203010001
%
% dumpasn1 -p -a rsa-public-key.der
SEQUENCE {
INTEGER
00 CF 24 3C 32 4B 26 24 70 13 16 48 61 4B 62 EE
9C 52 AF 43 31 9C 24 98 A7 C1 6B A9 79 0B B3 A8
81 F9 60 F7 B0 30 3F 8F 49 E8 6F ED D6 81 3B E5
FA 88 83 93 55 D0 44 26 DF 00 50 DB B7 71 EB 68
37 73 B7 DD 92 99 49 69 50 93 F9 10 C8 DC DB 63
36 74 DE 98 6A DA 8D 64 3E 0E 81 9B 7C D5 AB 3B
DE 43 72 10 37 97 47 2D C8 43 A2 71 16 99 E2 1A
4A FD DE ED 9F 62 81 03 16 90 34 57 34 2C 34 5A
35 EB B2 F0 6D A0 19 FE D2 AF A5 6E 78 56 6E 75
A0 D7 12 84 9A E2 55 15 5D 93 04 34 83 18 93 06
11 B3 B4 F1 15 3D 77 EE 59 70 F0 76 29 9C 54 8C
8A FF F5 31 57 20 50 48 AD E2 6D 40 93 0A F2 EC
C9 6D 4F 77 E8 59 15 23 B7 67 FA 3C DB C4 5A 8A
21 03 39 C4 A5 56 CE A2 E0 DF A3 EE 81 9B 62 E4
63 F7 5D 87 A5 3C 2F BD 1B BC B8 EC 8F E2 E8 00
0C E3 72 35 FA 90 31 13 C7 B3 7D 9C 2A 8B 39 C5
4B
INTEGER 65537
}


An RSA private key is stored in an RSAPrivateKey structure, defined by that same RFC. For example:

Code Block
% xxd -p rsa-private-key.der
308204a30201000282010100cf243c324b262470131648614b62ee9c52af
43319c2498a7c16ba9790bb3a881f960f7b0303f8f49e86fedd6813be5fa
88839355d04426df0050dbb771eb683773b7dd929949695093f910c8dcdb
633674de986ada8d643e0e819b7cd5ab3bde4372103797472dc843a27116
99e21a4afddeed9f62810316903457342c345a35ebb2f06da019fed2afa5
6e78566e75a0d712849ae255155d9304348318930611b3b4f1153d77ee59
70f076299c548c8afff53157205048ade26d40930af2ecc96d4f77e85915
23b767fa3cdbc45a8a210339c4a556cea2e0dfa3ee819b62e463f75d87a5
3c2fbd1bbcb8ec8fe2e8000ce37235fa903113c7b37d9c2a8b39c54b0203
0100010282010044b694716a946089fd0aeb3fbb2e3a5108ecb2b186466d
8d58904a4ba92213c7e9ddcccc5974fc275c3fa4f9ff2ccb816c3f996462
0df9870827ca7af4034f32f5e40c505121151a71bbb161b041e68b6e0159
363901a63b1fbcc6c3866da3127bf51e84125ebe452c8a7a513102dc0dfc
61331a2826fbcb4452d88aaa0f43ccfe436e1554f95bdd883c41e7e8529f
acd7556ba539af3e083e7143ddf8637f67b59eea494b02396ff5089a1964
48dc8f7eb236d2f92a3358d0d6f5af1443205400bbd2758d3ec7cb208c11
7d78d68409f987fd6e43a93a26961c10c05f85458821594d242f8106856c
393f3b971cae1bfc20319e37147b22d2d2179ed5844e8102818100f27c96
e84d6ff814c56996a0e143fa85106d74e2eaa848347d8681bbcc396d85fc
b51d318f543ad25090fe087e0e1ee0202f2ee8674e58609c22cc56e305c5
c55b016d0ca45c847ac88b59dd8a597388b09d7d5f86e2cdf60cb7660d94
a5e4e6f539506a6aacdf67fb9458b016a63d72392129eff5faa210a1739d
948ef0453b02818100daaf65e651382baed753222ab53dfb2f79ef96c6bd
ec1c2822e5b8405900cf9203b2a0e015d12042cc9e686bbf3e5d2d732ed7
45e2a1cc1787637b8f14727dd5da11261d3a7cbe3521296f269cdf2a16ea
2974a710b14f3e61484d2580fef9c5bf4965a7a9ee6055a8c27867609408
7ef1643e81ab17307ca40b79166b693f310281803ed463719ba6f87bc14f
039579e8d83fa42b084f478804f57cd4de469fbafd92eb10ae98c9cf8452
3c47e55aa3f6daaf2e07abbad211adba929a3da201bedc28afd4e5c191d0
db0ec969ba063a33c548d4a269fad7836ae467151a1f48b5d762b4857e3d
a4985866a3fc2322b52babde2dc95709730dd6f2423327d0775cf0430281
8100c4f14336c99c6992bb2e8e4da20de0c21ff14a7b4f9d6cba24bb7754
d412ebdc96e1ef09fffbe72ee172239e2d8c2f83f8008e34cce663942904
c9c8d0644fb920fb62b4ddf06ba813666a487eec67ce5d31da717e920048
b079d9a855e4caf270d3dbedc416fec1060ba53d8c77a4b31617ee46fedb
127a9d8e0b8dca4bed710281800c2fe643bfc8c81b39f1a574c751d2c5ee
0ce836a772197350f2f0a6a4d5248790a0cdf0c25a69a8834d645ea3c96e
e740d95adeea689259ac4ce36a7310c86c9c35441fdd96ff8cec89a65f8c
8666bbc2a42cd2a58e70b1e8b2269ed6307c5a2143cbd41de4682dea4a38
8a7c8d2f4088e9a2008fa986f9b0e92fa517ecc77b
%
% dumpasn1 -p -a rsa-private-key.der
SEQUENCE {
INTEGER 0
INTEGER
00 CF 24 3C 32 4B 26 24 70 13 16 48 61 4B 62 EE
9C 52 AF 43 31 9C 24 98 A7 C1 6B A9 79 0B B3 A8
81 F9 60 F7 B0 30 3F 8F 49 E8 6F ED D6 81 3B E5
FA 88 83 93 55 D0 44 26 DF 00 50 DB B7 71 EB 68
37 73 B7 DD 92 99 49 69 50 93 F9 10 C8 DC DB 63
36 74 DE 98 6A DA 8D 64 3E 0E 81 9B 7C D5 AB 3B
DE 43 72 10 37 97 47 2D C8 43 A2 71 16 99 E2 1A
4A FD DE ED 9F 62 81 03 16 90 34 57 34 2C 34 5A
35 EB B2 F0 6D A0 19 FE D2 AF A5 6E 78 56 6E 75
A0 D7 12 84 9A E2 55 15 5D 93 04 34 83 18 93 06
11 B3 B4 F1 15 3D 77 EE 59 70 F0 76 29 9C 54 8C
8A FF F5 31 57 20 50 48 AD E2 6D 40 93 0A F2 EC
C9 6D 4F 77 E8 59 15 23 B7 67 FA 3C DB C4 5A 8A
21 03 39 C4 A5 56 CE A2 E0 DF A3 EE 81 9B 62 E4
63 F7 5D 87 A5 3C 2F BD 1B BC B8 EC 8F E2 E8 00
0C E3 72 35 FA 90 31 13 C7 B3 7D 9C 2A 8B 39 C5
4B
INTEGER 65537
INTEGER
44 B6 94 71 6A 94 60 89 FD 0A EB 3F BB 2E 3A 51
08 EC B2 B1 86 46 6D 8D 58 90 4A 4B A9 22 13 C7
E9 DD CC CC 59 74 FC 27 5C 3F A4 F9 FF 2C CB 81
6C 3F 99 64 62 0D F9 87 08 27 CA 7A F4 03 4F 32
F5 E4 0C 50 51 21 15 1A 71 BB B1 61 B0 41 E6 8B
6E 01 59 36 39 01 A6 3B 1F BC C6 C3 86 6D A3 12
7B F5 1E 84 12 5E BE 45 2C 8A 7A 51 31 02 DC 0D
FC 61 33 1A 28 26 FB CB 44 52 D8 8A AA 0F 43 CC
FE 43 6E 15 54 F9 5B DD 88 3C 41 E7 E8 52 9F AC
D7 55 6B A5 39 AF 3E 08 3E 71 43 DD F8 63 7F 67
B5 9E EA 49 4B 02 39 6F F5 08 9A 19 64 48 DC 8F
7E B2 36 D2 F9 2A 33 58 D0 D6 F5 AF 14 43 20 54
00 BB D2 75 8D 3E C7 CB 20 8C 11 7D 78 D6 84 09
F9 87 FD 6E 43 A9 3A 26 96 1C 10 C0 5F 85 45 88
21 59 4D 24 2F 81 06 85 6C 39 3F 3B 97 1C AE 1B
FC 20 31 9E 37 14 7B 22 D2 D2 17 9E D5 84 4E 81
INTEGER
00 F2 7C 96 E8 4D 6F F8 14 C5 69 96 A0 E1 43 FA
85 10 6D 74 E2 EA A8 48 34 7D 86 81 BB CC 39 6D
85 FC B5 1D 31 8F 54 3A D2 50 90 FE 08 7E 0E 1E
E0 20 2F 2E E8 67 4E 58 60 9C 22 CC 56 E3 05 C5
C5 5B 01 6D 0C A4 5C 84 7A C8 8B 59 DD 8A 59 73
88 B0 9D 7D 5F 86 E2 CD F6 0C B7 66 0D 94 A5 E4
E6 F5 39 50 6A 6A AC DF 67 FB 94 58 B0 16 A6 3D
72 39 21 29 EF F5 FA A2 10 A1 73 9D 94 8E F0 45
3B
INTEGER
00 DA AF 65 E6 51 38 2B AE D7 53 22 2A B5 3D FB
2F 79 EF 96 C6 BD EC 1C 28 22 E5 B8 40 59 00 CF
92 03 B2 A0 E0 15 D1 20 42 CC 9E 68 6B BF 3E 5D
2D 73 2E D7 45 E2 A1 CC 17 87 63 7B 8F 14 72 7D
D5 DA 11 26 1D 3A 7C BE 35 21 29 6F 26 9C DF 2A
16 EA 29 74 A7 10 B1 4F 3E 61 48 4D 25 80 FE F9
C5 BF 49 65 A7 A9 EE 60 55 A8 C2 78 67 60 94 08
7E F1 64 3E 81 AB 17 30 7C A4 0B 79 16 6B 69 3F
31
INTEGER
3E D4 63 71 9B A6 F8 7B C1 4F 03 95 79 E8 D8 3F
A4 2B 08 4F 47 88 04 F5 7C D4 DE 46 9F BA FD 92
EB 10 AE 98 C9 CF 84 52 3C 47 E5 5A A3 F6 DA AF
2E 07 AB BA D2 11 AD BA 92 9A 3D A2 01 BE DC 28
AF D4 E5 C1 91 D0 DB 0E C9 69 BA 06 3A 33 C5 48
D4 A2 69 FA D7 83 6A E4 67 15 1A 1F 48 B5 D7 62
B4 85 7E 3D A4 98 58 66 A3 FC 23 22 B5 2B AB DE
2D C9 57 09 73 0D D6 F2 42 33 27 D0 77 5C F0 43
INTEGER
00 C4 F1 43 36 C9 9C 69 92 BB 2E 8E 4D A2 0D E0
C2 1F F1 4A 7B 4F 9D 6C BA 24 BB 77 54 D4 12 EB
DC 96 E1 EF 09 FF FB E7 2E E1 72 23 9E 2D 8C 2F
83 F8 00 8E 34 CC E6 63 94 29 04 C9 C8 D0 64 4F
B9 20 FB 62 B4 DD F0 6B A8 13 66 6A 48 7E EC 67
CE 5D 31 DA 71 7E 92 00 48 B0 79 D9 A8 55 E4 CA
F2 70 D3 DB ED C4 16 FE C1 06 0B A5 3D 8C 77 A4
B3 16 17 EE 46 FE DB 12 7A 9D 8E 0B 8D CA 4B ED
71
INTEGER
0C 2F E6 43 BF C8 C8 1B 39 F1 A5 74 C7 51 D2 C5
EE 0C E8 36 A7 72 19 73 50 F2 F0 A6 A4 D5 24 87
90 A0 CD F0 C2 5A 69 A8 83 4D 64 5E A3 C9 6E E7
40 D9 5A DE EA 68 92 59 AC 4C E3 6A 73 10 C8 6C
9C 35 44 1F DD 96 FF 8C EC 89 A6 5F 8C 86 66 BB
C2 A4 2C D2 A5 8E 70 B1 E8 B2 26 9E D6 30 7C 5A
21 43 CB D4 1D E4 68 2D EA 4A 38 8A 7C 8D 2F 40
88 E9 A2 00 8F A9 86 F9 B0 E9 2F A5 17 EC C7 7B
}


Due to the way that these keys are encoded, the number of raw key bytes will vary from key to key. You should expect that, for a key whose size in bits is S:
  • The public key will be a little over S / 8.

  • The private key will be roughly S * 0.6.

These key formats are also known as PKCS#1.

SECG Elliptic Curve


Apple platforms support three SECG keys:
  • secp256r1, aka NIST P-256, aka P256

  • secp384r1, aka NIST P-384, aka P384

  • secp521r1, aka NIST P-521, aka P521

Note that the latter is 521 not 512!

These keys have of 4 components:
  • A marker, which is always 0x04

  • X and Y values for the public key

  • An additional K value for the private key

These values are usually formatted according to ANSI X9.63. Specifically:
  • The public key consists of 04 | X | Y.

  • The private key consists of 04 | X | Y | K.

Note In both case | indicates concatenation.

X, Y and K are all the same size, being the key size in bits divided by 8 (rounded up in the case of secp521r1). So a secp256r1 public key is 65 bytes (1 for the marker plus 32 each for X and Y) and the matching private key is 97 bytes (an extra 32 bytes for K). For example:

Code Block
% xxd -p p256-public-key.dat
049747e981aab8ea71a255cd9a1562858c406006f1e418260d31e1a77f6c
2b35a9a3132f232db00351d9d8003487d4ee52847990313daa7c721f88d4
bb56da91c7
%
% xxd -p p256-private-key.dat
049747e981aab8ea71a255cd9a1562858c406006f1e418260d31e1a77f6c
2b35a9a3132f232db00351d9d8003487d4ee52847990313daa7c721f88d4
bb56da91c7986a7a91cbb5f4f81636e81aaff0835a771dc66865c407a8e8
4469cf6ab8a477


Curve 25519


Curve 25519, defined RFC 7748, has the simplest raw key bytes format: Both the public and private key consist of 32 bytes of unstructured data. For example:

Code Block
% xxd -p curve25519-public-key.dat
910bf46f0c0dc836878fa70860fdde219d5f62650a83a7c5923d2ab74b81
76c5
%
% xxd -p curve25519-private-key.dat
9fd90805255bae86a6c3035b2de837e929ea792ea11fd466e67ed0b265c0
a999

Up vote post of eskimo
5.9k views