pythonencryptioncryptographyrsa

How to add a custom RSA key pair to a .pem file


I created a custom RSA key pair just for test purposes in python. I want to add the private key and public key to a .pem file but I didnt find anything in my research. All i found is people generating a RSA key pair from a library. I have the e, d and n variables for the public key[e, n] and private key[d, n].


Solution

  • Most major crypto libraries support this, e.g. PyCryptodome (via construct() and exportKey()) or Cryptography (as described in the Numbers and Key Serialization sections), e.g.

    PyCryptodome:

    from Crypto.PublicKey import RSA
    
    n = int("b83b...529b", 16)
    d = int("4eea...a721", 16)
    e = int("010001", 16)
    
    privateKey = RSA.construct((n, e, d))
    privateKeyPem = privateKey.exportKey(pkcs=8) # export in PKCS#8 format
    
    publicKey = RSA.construct((n, e))
    publicKeyPem = publicKey.exportKey() # export in X.509/SPKI format
    
    print(privateKeyPem.decode('utf8'))
    print(publicKeyPem.decode('utf8'))
    

    or Cryptography:

    from cryptography.hazmat.primitives.asymmetric import rsa
    from cryptography.hazmat.primitives import serialization
    
    n = int("b83b...529b", 16)
    d = int("4eea...a721", 16)
    e = int("010001", 16)
    
    (q, p) = rsa.rsa_recover_prime_factors(n, e, d)
    dmq1 = rsa.rsa_crt_dmq1(d, q)
    dmp1 = rsa.rsa_crt_dmp1(d, p)
    iqmp = rsa.rsa_crt_iqmp(p, q)
    
    publicNumbers = rsa.RSAPublicNumbers(e, n)
    privateNumbers = rsa.RSAPrivateNumbers(p, q, d, dmp1, dmq1, iqmp, publicNumbers)
    
    privateKey = privateNumbers.private_key()
    publicKey = publicNumbers.public_key()
    
    privateKeyPem = privateKey.private_bytes(
       encoding=serialization.Encoding.PEM,
       format=serialization.PrivateFormat.PKCS8,
       encryption_algorithm=serialization.NoEncryption()
    )
    
    publicKeyPem = publicKey.public_bytes(
       encoding=serialization.Encoding.PEM,
       format=serialization.PublicFormat.SubjectPublicKeyInfo
    )
    
    print(privateKeyPem.decode('utf8'))
    print(publicKeyPem.decode('utf8'))
    

    Note that the raw key is symmetric in p and q, so swapping p and q changes the PEM or DER encoded key, but not the raw key (n, e, d).