How to decode a private key as rsa

I have a private key

-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDYBVtUvXXQZaK1
7NsTC6yLahsAAkrejbEvNdjA1AW1PPOhj3m2UM7cmI7cLODrV7UY5UpEGL7UWUQi
...
-----END PRIVATE KEY-----

and running openssl rsa -in privkey.txt -text -noout on it provides me with all the necessary info about it:

Private-Key: (2048 bit)
modulus:
    00:d8:05:5b:54:bd:75:d0:65:a2:b5:ec:db:13:0b:
    ac:8b:6a:1b:00:02:4a:de:8d:b1:2f:35:d8:c0:d4:
    ...
publicExponent: 65537 (0x10001)
privateExponent:
    14:3d:c0:41:3a:f5:78:9e:fa:b5:90:3e:e0:d4:7b:
    08:f4:85:6e:25:48:d8:52:04:df:0c:6d:1b:23:0d:
    71:33:87:b7:ef:91:33:2f:9e:df:d5:b3:01:2c:d0:
    05:cd:49:ec:a3:6e:27:88:fd:61:e4:06:b9:d4:f6:
...

But it doesn’t quite work with elixir

iex(1)> {:ok, privkey} = File.read("privkey.txt")
{:ok, "-----BEGIN PRIVATE KEY-----\nMIIE ..."}
iex(3)> [private_key_info] = :public_key.pem_decode(privkey)
[{:PrivateKeyInfo,
  <<48, 130, 4, 190, 2, 1, 0, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1,
    5, 0, 4, 130, 4, 168, 48, 130, 4, 164, 2, 1, 0, 2, 130, 1, 1, 0, 216, 5, 91,
    84, 189, 117, 208, 101, 162, 181, ...>>, :not_encrypted}]
iex(5)> key = :public_key.pem_entry_decode(private_key_info)
{:PrivateKeyInfo, :v1,
 {:PrivateKeyInfo_privateKeyAlgorithm, {1, 2, 840, 113549, 1, 1, 1},
  {:asn1_OPENTYPE, <<5, 0>>}},
 <<48, 130, 4, 164, 2, 1, 0, 2, 130, 1, 1, 0, 216, 5, 91, 84, 189, 117, 208,
   101, 162, 181, 236, 219, 19, 11, 172, 139, 106, 27, 0, 2, 74, 222, 141, 177,
   47, 53, 216, 192, 212, 5, 181, 60, 243, 161, ...>>, :asn1_NOVALUE}

I would expect to get a #RSAPrivateKey{} record.
It does work with a key starting with -----BEGIN RSA PRIVATE KEY-----.

Is there a way to specify that the private key is RSA?

What I eventually want is to sign some data with that private key. I guess I would do it like this:

iex(7)> data |> :public_key.sign(:sha256, key) |> Base.encode64()
"jCPCc7KwvFgNUiM+DLtaHqJNu7z5tElY..."

But key has to be #RSAPrivateKey{} and not #PrivateKeyInfo{}.

The PrivateKeyInfo structure is just a wrapper around the DER-encoded private key. You can take the DER binary value (<<48, 130, 4, 164, ...>>) and decode it with :public_key.der_decode(:RSAPrivateKey, der)

1 Like

I guess this private key might be slightly malformed, since :public_key.der_decode(:RSAPrivateKey, der) fails

iex(18)> {:ok, privkey} = File.read("privkey.txt")
{:ok, "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9..."}
iex(19)> [{_, der, _}] = :pubkey_pem.decode(privkey)
[{:PrivateKeyInfo,
  <<48, 130, 4, 190, 2, 1, 0, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1,
    5, 0, 4, 130, 4, 168, 48, 130, 4, 164, 2, 1, 0, 2, 130, 1, 1, 0, 216, 5, 91,
    84, 189, 117, 208, 101, 162, 181, ...>>, :not_encrypted}]
iex(20)> :public_key.der_decode(:RSAPrivateKey, der)
** (MatchError) no match of right hand side value:
    {:error, {:asn1, {{:wrong_tag, {{:expected, 2}, {:got, 16, {16, [{6, <<42, 134, 72, 134, 247, 13, 1, 1, 1>>}, {5, ""}]}}}}

    OTP-PUB-KEY.erl:20537: :"OTP-PUB-KEY".match_tags/2
    OTP-PUB-KEY.erl:20054: :"OTP-PUB-KEY".decode_integer/2
    OTP-PUB-KEY.erl:2447: :"OTP-PUB-KEY".dec_RSAPrivateKey/2
    OTP-PUB-KEY.erl:1103: :"OTP-PUB-KEY".decode/2
    public_key.erl:238: :public_key.der_decode/2
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
    (elixir) src/elixir.erl:239: :elixir.eval_forms/4
    (iex) lib/iex/evaluator.ex:219: IEx.Evaluator.handle_eval/5
    public_key.erl:242: :public_key.der_decode/2

Here’s the full key, in case you are interested

-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDYBVtUvXXQZaK1
7NsTC6yLahsAAkrejbEvNdjA1AW1PPOhj3m2UM7cmI7cLODrV7UY5UpEGL7UWUQi
JL+mQhciKPgf5tZPWLU6495/Q7W0yUmaaYCJCpEKbCSNoLIso2SzcfLk3TUgvqSk
roA+eFNLSXNqmeBFQVMW1G0ZuswU7x5SIIh9MJVgix/UHpx1sBs0/4caT1+TlmdS
KFZR/FawECOJMtBkRvu+cYhZLWTpkbFqd4z2jdJSwUIB16itSqpYUBaR1M4SDxyR
tPzZo5clkvWL+mGos66R+G5JrqwvqYERbtVNUG/j+ksGfqNwVJydATJQFCUBRw6k
UE3iQMC9AgMBAAECggEAFD3AQTr1eJ76tZA+4NR7CPSFbiVI2FIE3wxtGyMNcTOH
t++RMy+e39WzASzQBc1J7KNuJ4j9YeQGudT2rkCgGUp8dsTITQFeDelpy5lPw+Oz
2rJLDHbp1e+sfHwpEHyzmWAyfGvBKCh6QJdnRd3myXWq87tSY+WLQGbhiC5+zpvY
iDRZqivS677W+FQqyqM8rnBFBs41BjnMDyaBrFYGZCThdG4Db0wB8AiEfu9EfdQQ
pk38L/SkGaZindxbPQFXEXK1T0V0LFyuxRsZuqU9Y331kJw7NCPXEMgnw3njTQkZ
DrajMvH7m21akELCkVu8Myky1Wg363Y1k0YZzNKPEwKBgQDvZYWCnoCfH5+FoSK2
ZK2Xw/44m7Gu6MLEZxRnOGP+kcZoNAna4FG+bEjHe7AH5O9jpppmAuWPvzgbjaF8
t4S83jz/VU2sQ7j1ZyHFrWjXbzXRJyMq3AoBbpIsN0JJeJBfZgaE3Jd2V6GZGcAq
WMXNnqVl6ryjSsrsBidUKKf/mwKBgQDnAM0qU0TMdxxqyScjYIPPUghosUVvuhXG
0+5msipchC0qEHWREZ3hEf780lrczyOH8HxE68ycHD7mQgGc23qCvkA/x23CmtnI
54EUw0mtw0zqiOjQcIe4Pjr/b1cHm+TYACT4fR/IVQjs1RKQrr2/O5wTKDfGe9vp
hs6uzPlChwKBgQCNYEgDRnWxAyzi7rEgQ76cpNtKNPAu2jjDYhiTiKLM4Ovp9+lm
ABlmOm6Ul//x+YpCME54Nfe593Q8GV0n2P0jyJ7/LzJKrEfbbQdtxSXoLD39AX7s
PbwO8mySfiPAXdns7MSmy9sKwV+mmaV5nKlb7/e/g2vZhz7lOhEZy1TDRwKBgH3F
X+8lexXf3Cb/8kE+sUVVoqJtsiKMrIKerPRZGNtaU8TNRVWAw/bg93XrifEjDnNb
Ki3UPIjakByJ35rpnKBGuXCAQnBsIxtRgGQvl5P1+5DOjgO+4QYdS737fuTzqfs4
yOhKJ93I/p0DvaHsof7Wk7mSchutICTbcviVPTlNAoGBAJo1ky102BUGXA/yz1nb
G/UOnm8FklTrVTqy2/jyy/cFT+DoufZni1sf7w6+93lq3MVOlWFqxs6wY2OW4Why
2sapEWAOz2zIxIiuEcwfICFQ4DZnOE93cGZDXiRxgdDfY0f7vaDRvQ/ZChscXVNC
suv3nD8hWqVW91wLsXxJh8B8
-----END PRIVATE KEY-----
iex(7)> <<_ :: binary-size(26), der2 :: binary >> = der
<<48, 130, 4, 190, 2, 1, 0, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5,
  0, 4, 130, 4, 168, 48, 130, 4, 164, 2, 1, 0, 2, 130, 1, 1, 0, 216, 5, 91, 84,
  189, 117, 208, 101, 162, 181, 236, 219, ...>>
iex(8)> :public_key.der_decode(:RSAPrivateKey, der2)
{:RSAPrivateKey, :"two-prime", 27270115390353...

See:

1 Like

I really hope that is a testing-only private key. ^.^;
Just to note. ^.^;

Thank you @voltone @dom

It was a dev key for google storage, I removed it before posting.
btw, at first I thought it was google that generated me a malformed key, but the problem was in me, as usual

1 Like

I meant the DER binary inside the :PrivateKeyInfo record. The ‘proper’ way to get to the private key would be something like this:

require Record
Record.defrecord :private_key_info,
    Record.extract(:PrivateKeyInfo, from_lib: "public_key/include/PKCS-FRAME.hrl")

info =
  File.read!("rsa.key")
  |> :public_key.pem_decode
  |> hd()
  |> :public_key.pem_entry_decode

:public_key.der_decode(:RSAPrivateKey, private_key_info(info, :privateKey))
1 Like