3
$\begingroup$

I have an RSA private key $\{d,n\}$ and a public key $\{e,n\}$, where $n$ is the modulus, and I also have the prime factors $p$ and $q$ of $n$.

I want to create a PEM file containing this information, so that I can decrypt a file encrypted with the public key using OpenSSL. How can I do this?

$\endgroup$
2
  • 3
    $\begingroup$ I'm voting to close this question as off-topic because this is a question about how to use a particular software program (OpenSSL), not cryptography $\endgroup$
    – poncho
    Commented May 8, 2015 at 12:15
  • $\begingroup$ @poncho: Technically, this question is about implementing a standard storage format for cryptographic keys. The mention of OpenSSL is really a red herring. I think it's on topic here, if perhaps marginally. (And there's certainly some overlap with Stack Overflow here; not that there's necessarily anything wrong with that.) $\endgroup$ Commented May 9, 2015 at 11:44

1 Answer 1

6
$\begingroup$

RFC 2313 specifies the RSAPrivateKey ASN1 structure as a SEQUENCE containing the INTEGERs

  • $0$;
  • $n$;
  • $e$;
  • $d$;
  • $p$;
  • $q$;
  • $d\bmod(p-1)$;
  • $d\bmod(q-1)$;
  • $q^{-1}\bmod p$.

The PEM format consists of such a structure encoded as Base64 and framed by the typical BEGIN/END RSA PRIVATE KEY header and footer lines.

Thus, you can use any ASN1 library you like to encode the private key parameters. For example, with Python's pyasn1 module, a private key file's contents can be obtained as follows:

import pyasn1.codec.der.encoder
import pyasn1.type.univ
import base64

def pempriv(n, e, d, p, q, dP, dQ, qInv):
    template = '-----BEGIN RSA PRIVATE KEY-----\n{}-----END RSA PRIVATE KEY-----\n'
    seq = pyasn1.type.univ.Sequence()
    for i,x in enumerate((0, n, e, d, p, q, dP, dQ, qInv)):
        seq.setComponentByPosition(i, pyasn1.type.univ.Integer(x))
    der = pyasn1.codec.der.encoder.encode(seq)
    return template.format(base64.encodebytes(der).decode('ascii'))

The parameters dP, dQ and qInv are most easily (as in: lines of code) computed as follows:

dP = d % (p-1)
dQ = d % (q-1)
qInv = pow(q, p-2, p)
$\endgroup$
5
  • $\begingroup$ PyAsn1Error: Attempted "__len__" operation on ASN.1 schema object $\endgroup$
    – evandrix
    Commented Jun 6, 2020 at 17:30
  • 1
    $\begingroup$ @evandrix Thanks, seems like some internals of pyasn1 changed. Fixed. $\endgroup$
    – yyyyyyy
    Commented Jun 6, 2020 at 18:58
  • $\begingroup$ python3 says: DeprecationWarning: encodestring() is a deprecated alias since 3.1, use encodebytes(). replacing it works fine as far as I can see. $\endgroup$
    – acapola
    Commented Mar 5, 2021 at 20:57
  • $\begingroup$ the code given for dP and dQ is wrong. the one given for qInv is convoluted. consider this instead expected_dP = d % (p - 1);expected_dQ = d % (q - 1); expected_qInv = pow(q, -1, p) $\endgroup$
    – acapola
    Commented Mar 5, 2021 at 22:06
  • $\begingroup$ @acapola Thanks! Fixed. $\endgroup$
    – yyyyyyy
    Commented Mar 6, 2021 at 18:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.