Hazmat RSA Key Formats (PEM, DER, and OpenSSH)
[Hazmat Home][Home]
We need ways to distribute our public keys, private keys and digital certificates in a portable format. One of the most common forms is Distinguished Encoding Rules (DER) encoding of ASN.1. Overall it is truly binary representation of the encoded data. The other common format is PEM, and which converts the binary encoding into a text readable format. With PEM we can encode cryptographic infromation in a Base64 ASCII format and with plain-text headers and footers of "-----BEGIN RSA PRIVATE KEY-----" and "-----END RSA PRIVATE KEY-----", whereas with DER we have binary format. In this page, we will read in a DER encoded hex string and determine its contents.
|
Theory
We need ways to distribute our public keys, private keys and digital certificates in a portable format. One of the most common forms is Distinguished Encoding Rules (DER) encoding of ASN.1 (Abstract Syntax Notation One). Overall it is a truly binary representation of the encoded data. The other common format is PEM, and which converts the binary encoding into a text readable format. With PEM we can encode cryptographic information in a Base64 ASCII format and with plain-text headers and footers of “ — — -BEGIN RSA PRIVATE KEY — — -” and “ — — -END RSA PRIVATE KEY — — -”, whereas with DER we have binary format.
This page will look at the DER format and has code to decode a hex string and into its contents. Overall ASN.1 is used to define abstract types and values. One of the most basic types is SEQUENCE and is an ordered collection of one or more types. In DER, SEQUENCE is identified with a tag of “30”, and followed by a byte value for the length of the object defined. The other common types are OBJECT IDENTIFIER (and which has a tag of “06”) and BIT STRING (and which has a tag of “03”).
The object identifier tag is used to define the cryptography methods used. An example identifier for ECC encryption is “1.2.840.10045.2.1”, and where 1 is OSI, 2 is member body, 840 is US (ANSI), and 10045 is “ansi-X9–62”, and “2” is key type [1]. Other common algorithms are: “1.2.840.113549.1.1.1” (X509 RSA), “1.2.840.10040.4.1” (X509 Digital Signature Standard -DSS), and “1.2.840.10046.2.1” (Diffie-Hellman — DH). The following is an example of the hex sequence for an object ID, and where we have the “06” tag, followed by an identifier for seven bytes (“07”), and then the Object ID of seven bytes (“2a8648ce3d0201”):
06 07 2a8648ce3d0201 # Object ID - 7 bytes long - 1.2.840.10045.2.1 (ECC)
We can also define the curve type in the object identifier, and where we have the form of iso(1), member-body(2), us(840), ansi-X9–62(10045), curves(3), prime(1). For example, 1.2.840.10045.3.1.7 defines ECDSA P-256. Other examples are SECP192R1 (“1.2.840.10045.3.1.1”), SECP224R1 (“1.3.132.0.33”), SECP256K1 (“1.3.132.0.10”), SECP256R1 (“1.2.840.10045.3.1.7”), SECP384R1 (“1.3.132.0.34”), SECP521R1 (“1.3.132.0.35”), and BRAINPOOLP256R1 (“1.3.36.3.3.2.8.1.1.7”). An example where we have an identifier (“06”), followed by the number of bytes identifier (“08”) and Object ID of eight bytes (“2a8648ce3d030107”):
06 08 2a8648ce3d030107 # Object ID - 8 bytes long - 1.2.840.10045.3.1.7 (ECDSA P256)For the “03” tag, we define a bitstream for keys. In the following, we have “03”, followed by the number of bytes (66 bytes) for the keys, and then the keys are defined after this (64 bytes):
03 42 # Bit stream - 0x42 (66 bytes long) 0004 # Identifies public key 2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838 # Identifies public key x co-ordinate c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e # Identifies public key y co-ordinate
An example hex string for a DER format for ECC public keys is:
3059301306072a8648ce3d020106082a8648ce3d030107034200042927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513
We can then break down with:
30 59 # Sequence length 0x59 - 91 bytes long 30 13 # Sequence length 0x13 - 21 bytes long 06 07 2a8648ce3d0201 # Object ID - 7 bytes long - 1.2.840.10045.2.1 (ECC) 06 08 2a8648ce3d030107 # Object ID - 8 bytes long - 1.2.840.10045.3.1.7 (ECDSA P256) 03 42 # Bit stream - 0x42 (66 bytes long) 0004 # Identifies public key 2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838 # Identifies public key x co-ordinate c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e # Identifies public key y co-ordinate
If we need to convert a DER into a hex format, we can just use "xxd" and "tr":
% xxd -plain 512b-rsa-example-keypair.der | tr -d '\n' 3082013b0201000241009bfc6690798442bbab13fd2b7bf8de1512e5f193e3068a7bb8b1e19e26bb9501bfe730ed648502dd1569a834b006ec3f353c1e1b2b8ffa8f001bdf07c6ac5307020301000102401b4af77b31f7e56146d6d1866943ab400eb5732688239dd9760091d4853c6f1ec051ebe6905b417fe6aa316bac59539626f1aedabe55a47540225f2717a0d291022100c8c4277cd561adbf328e1ecbe894f49f5577e5a8c970d00f8104b709b21b53e9022100c6e665be10c86db71eee8e41bce867099d8dee461bd590b9ee0dc5f9c6c9c96f0221009bb0318706da36a89c85c5b00eeee43c6345151dad0904efe0f74d1201c25b71022046d1258c84a1381f290e3aec40fc6623504b8678c3d448514ae6f0843c3900550221008d036e290ed74e1f2770b52079fb316a14b7e6559a6540cfe0e646f8b28ef4630a
In OpenSSL, we can convert from DER to PEM with:
openssl x509 -inform der -in mycert.der -out mycert.pem
and:
openssl x509 -outform der -in mycert.pem -out mycert.der
An example of a public key is:
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw51PMBm2psyIjHPU1efH Ulyh22zy3hEhlsNPH6/Cqg0HJorX1WbNKLfiU2aAt24jn4CC+y8PusrmMMCIca5x 0L4XZxm14QvKKImIOMOMblS1Te29n64HuuQ9owKLHuSMww4wiLiY/nAvjK/5/kKT HL6x7nK/Pq72eoQ/etFBkaX5nYGUD/+G+5BgAPx1mBgU5/y9+/+QZ9xbYU6zogOW Tfa6rDMSAbmJOtkk1ghnuaq4dSoHWbW+zpHMVtjtHgzDGhX9KjOmvSDQIGn4wevD p2yDLULUbsdO4ylacTkxyIc92ZHdZeP6Hh+KhNC04Z65zwXLEA3M4bucX+u6nszW xwIDAQAB -----END PUBLIC KEY-----
The following is the code:
from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives import serialization import sys import binascii size=512 if (len(sys.argv)>1): size=int(sys.argv[1]) try: private_key = rsa.generate_private_key(public_exponent=65537,key_size=size) pub = private_key.public_key() print("\n=== Private Key PEM format ===") pem = private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption()) der= private_key.private_bytes(encoding=serialization.Encoding.DER,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption()) print ("\nPrivate key (PEM):\n",pem.decode()) print ("\nPrivate key (DER):\n",binascii.b2a_hex(der).decode()) pem = pub.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo).decode("utf-8") openssh = pub.public_bytes(encoding=serialization.Encoding.OpenSSH,format=serialization.PublicFormat.OpenSSH) print("\n=== Public Key format ===") der=''.join(pem.split('\n')[1:-2]) print ("Public key (PEM):\n",pem) print ("\nPublic key (DER):\n",binascii.b2a_hex(binascii.a2b_base64(der)).decode()) print ("\nPublic key (OpenSSL):\n",openssh.decode()) except Exception as e: print(e)
A sample run for a key size of 512 bits is:
RSA key size: 512 === Private Key PEM format === Private key (PEM): -----BEGIN PRIVATE KEY----- MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAzxf3L7ftdnv2Gbcv WEhAxG1K+4K9GbkiHyANRy4Fvs73DGNlTHRAktE1rrPap7IrqnXQaQ0wUkqR6k48 mdoCfwIDAQABAkARPM5vY2DZnuHSLCQ9te3mK661FqHE1VsYuiNAzHzf79XdrrNF qjS5uK0gzOKYGsjVkFc/LwNHLHGVQSu/JNhBAiEA5vM/bQtK7mxTQ5wGLrH0R6lW EqaVzADmKm0FF7u7jp8CIQDljkv0q7c3l3qq59TK1wg6zras1yZqvQ+1Q/8W3i9g IQIgCAVCmqLdw1H3wk1U2aJMfYCgAJ3QbflKBQcsOhrG9LkCIEYWvmZED7rvi0qn YjdUlHSwLOJ1BovMkgE8c6RdzoVBAiEA0UtuFQskpXBWnEbSODMewac7Cq7zDG63 yZ8UDd6DlcM= -----END PRIVATE KEY----- Private key (DER): 30820154020100300d06092a864886f70d01010105000482013e3082013a020100024100cf17f72fb7ed767bf619b72f584840c46d4afb82bd19b9221f200d472e05becef70c63654c744092d135aeb3daa7b22baa75d0690d30524a91ea4e3c99da027f02030100010240113cce6f6360d99ee1d22c243db5ede62baeb516a1c4d55b18ba2340cc7cdfefd5ddaeb345aa34b9b8ad20cce2981ac8d590573f2f03472c7195412bbf24d841022100e6f33f6d0b4aee6c53439c062eb1f447a95612a695cc00e62a6d0517bbbb8e9f022100e58e4bf4abb737977aaae7d4cad7083aceb6acd7266abd0fb543ff16de2f602102200805429aa2ddc351f7c24d54d9a24c7d80a0009dd06df94a05072c3a1ac6f4b902204616be66440fbaef8b4aa76237549474b02ce275068bcc92013c73a45dce8541022100d14b6e150b24a570569c46d238331ec1a73b0aaef30c6eb7c99f140dde8395c3 === Public Key format === Public key (PEM): -----BEGIN PUBLIC KEY----- MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAM8X9y+37XZ79hm3L1hIQMRtSvuCvRm5 Ih8gDUcuBb7O9wxjZUx0QJLRNa6z2qeyK6p10GkNMFJKkepOPJnaAn8CAwEAAQ== -----END PUBLIC KEY----- Public key (DER): 305c300d06092a864886f70d0101010500034b003048024100cf17f72fb7ed767bf619b72f584840c46d4afb82bd19b9221f200d472e05becef70c63654c744092d135aeb3daa7b22baa75d0690d30524a91ea4e3c99da027f0203010001 Public key (OpenSSL): ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQDPF/cvt+12e/YZty9YSEDEbUr7gr0ZuSIfIA1HLgW+zvcMY2VMdECS0TWus9qnsiuqddBpDTBSSpHqTjyZ2gJ/
and for 1,024 bits:
RSA key size: 1024 === Private Key PEM format === Private key (PEM): -----BEGIN PRIVATE KEY----- MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAKJ/pn5rJP5Mdgdj Yj1GS/U7sgVmad+CtuYzsapXs1iJPfHqbYqTXxPbvj5ZVIRBy0dq3ySTeepCkNPP ieU7CSyEPsg/P5Qa5TvUjBUQVtAPUwF4UMpOXIdAuCh+9HgPl/AUmsGRZvE15Vig Z4rnevA5ouMP0rsSwRkD/z+/A4gRAgMBAAECgYAIp+oTg9uVnDcRT670+qCjMInc Fcd/+3OIsao+G6vXBICDOWyaXB1NboAkzBdfcC3G4R9/0EdHPkJ+tehviISFf88l UFBQ/TGQS+DKiPFV2NPKAqUp/cdnvTdxUFDlmtI971eiJsN5FYl5xN/PjpX1K3Bl mQ2jwkAUXLAGWyg2AQJBAMzkngZaBMeZ18zd5snM9MJmjsX+yZSJYpP7MQwJcb3E Fg/cZBD0yZD4VkHBmKFG/CA2RXE3C+kZMY2kxSI/12ECQQDLB/OOgGnjkfkUlI7M mQ06LW58HZj3Uh2EGWYM5gtA5jPOgpBdWQNq8/QLX+Icu6JzzOWr3RwRZSCtiyr2 Cl6xAkEAnRJx9oqR+XZ90icW4wNFa7Z1o2G0pTNBKBK8Qe8HjCPDifs5lyohUAqh DZ3dZV3msMcKK0W40sSmkWCMY7ovYQJBALmTwASNzbvLzk8IZuoOL2/w3N8nsozF iuMW0BeUIc8lW080Oj6IwT3+VCAdeTDoNNoB/CA2T5R6yf62iQMxgVECQQDGfe4I IYPxHwc5GkPXfZTLjDr7eSnJrzXnDHsdBuqrLHm7IdC1o428vcCE3CLaWMs7myLf /ghK/PTcdI5y92es -----END PRIVATE KEY----- Private key (DER): 30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100a27fa67e6b24fe4c760763623d464bf53bb2056669df82b6e633b1aa57b358893df1ea6d8a935f13dbbe3e59548441cb476adf249379ea4290d3cf89e53b092c843ec83f3f941ae53bd48c151056d00f53017850ca4e5c8740b8287ef4780f97f0149ac19166f135e558a0678ae77af039a2e30fd2bb12c11903ff3fbf038811020301000102818008a7ea1383db959c37114faef4faa0a33089dc15c77ffb7388b1aa3e1babd7048083396c9a5c1d4d6e8024cc175f702dc6e11f7fd047473e427eb5e86f8884857fcf25505050fd31904be0ca88f155d8d3ca02a529fdc767bd37715050e59ad23def57a226c379158979c4dfcf8e95f52b7065990da3c240145cb0065b283601024100cce49e065a04c799d7ccdde6c9ccf4c2668ec5fec994896293fb310c0971bdc4160fdc6410f4c990f85641c198a146fc20364571370be919318da4c5223fd761024100cb07f38e8069e391f914948ecc990d3a2d6e7c1d98f7521d8419660ce60b40e633ce82905d59036af3f40b5fe21cbba273cce5abdd1c116520ad8b2af60a5eb10241009d1271f68a91f9767dd22716e303456bb675a361b4a533412812bc41ef078c23c389fb39972a21500aa10d9ddd655de6b0c70a2b45b8d2c4a691608c63ba2f61024100b993c0048dcdbbcbce4f0866ea0e2f6ff0dcdf27b28cc58ae316d0179421cf255b4f343a3e88c13dfe54201d7930e834da01fc20364f947ac9feb68903318151024100c67dee082183f11f07391a43d77d94cb8c3afb7929c9af35e70c7b1d06eaab2c79bb21d0b5a38dbcbdc084dc22da58cb3b9b22dffe084afcf4dc748e72f767ac === Public Key format === Public key (PEM): -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCif6Z+ayT+THYHY2I9Rkv1O7IF ZmnfgrbmM7GqV7NYiT3x6m2Kk18T274+WVSEQctHat8kk3nqQpDTz4nlOwkshD7I Pz+UGuU71IwVEFbQD1MBeFDKTlyHQLgofvR4D5fwFJrBkWbxNeVYoGeK53rwOaLj D9K7EsEZA/8/vwOIEQIDAQAB -----END PUBLIC KEY----- Public key (DER): 30819f300d06092a864886f70d010101050003818d0030818902818100a27fa67e6b24fe4c760763623d464bf53bb2056669df82b6e633b1aa57b358893df1ea6d8a935f13dbbe3e59548441cb476adf249379ea4290d3cf89e53b092c843ec83f3f941ae53bd48c151056d00f53017850ca4e5c8740b8287ef4780f97f0149ac19166f135e558a0678ae77af039a2e30fd2bb12c11903ff3fbf0388110203010001 Public key (OpenSSL): ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCif6Z+ayT+THYHY2I9Rkv1O7IFZmnfgrbmM7GqV7NYiT3x6m2Kk18T274+WVSEQctHat8kk3nqQpDTz4nlOwkshD7IPz+UGuU71IwVEFbQD1MBeFDKTlyHQLgofvR4D5fwFJrBkWbxNeVYoGeK53rwOaLjD9K7EsEZA/8/vwOIEQ==
Note that we normally use RSA keys of 2,048 bits and above, as the state-of-the-art in factorizing the modulus is approaching 1,024 bits.