Skip to content

Instantly share code, notes, and snippets.

@dnaeon
Last active November 30, 2022 05:52
Show Gist options
  • Save dnaeon/0883be5c3e52e6a6da0e6d6cefeef520 to your computer and use it in GitHub Desktop.
Save dnaeon/0883be5c3e52e6a6da0e6d6cefeef520 to your computer and use it in GitHub Desktop.
Parse ASN.1 encoded RSA private key
;; Decode ASN.1 encoded private key
;;
;; RSA private key format: https://www.rfc-editor.org/rfc/rfc3447#appendix-A.1.2
;;
;; RSAPrivateKey ::= SEQUENCE {
;; version Version,
;; modulus INTEGER, -- n
;; publicExponent INTEGER, -- e
;; privateExponent INTEGER, -- d
;; prime1 INTEGER, -- p
;; prime2 INTEGER, -- q
;; exponent1 INTEGER, -- d mod (p-1)
;; exponent2 INTEGER, -- d mod (q-1)
;; coefficient INTEGER, -- (inverse of q) mod p
;; otherPrimeInfos OtherPrimeInfos OPTIONAL
;; }
;;
(ql:quickload :asn1)
(ql:quickload :trivia)
(ql:quickload :ironclad)
(ql:quickload :binascii)
(defparameter *private-key-begin* "-----BEGIN RSA PRIVATE KEY-----")
(defparameter *private-key-end* "-----END RSA PRIVATE KEY-----")
(defun extract-private-key-from-path (path)
"Extracts the private key contents from the given path"
(with-open-file (in path)
(with-output-to-string (s)
;; First line should be the beginning marker
(unless (string= *private-key-begin*
(read-line in))
(error "Invalid private key format"))
;; Read until the end marker
(loop for line = (read-line in nil nil)
until (string= line *private-key-end*)
do
(write-string line s))
s)))
(defun decode-rsa-private-key-file (path)
"Decode ASN.1 encoded RSA private key from a given PATH"
(let ((data (binascii:decode-base64 (extract-private-key-from-path path))))
(trivia:match (asn1:decode data)
((asn1:rsa-private-key :modulus n
:public-exponent e
:private-exponent d
:prime1 p
:prime2 q)
(ironclad:make-private-key :rsa :n n :e e :d d :p p :q q)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment