PythonでPEM形式のRSA鍵を生成する方法のメモ

適当なパラメータをもとに、PythonでPEM形式のRSA鍵を生成する方法のメモ。

環境

Ubuntu 14.04.3 LTS 64bit版

$ uname -a
Linux vm-ubuntu64 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:16:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.3 LTS
Release:        14.04
Codename:       trusty

PEM形式のRSA鍵を生成してみる

PEM形式のRSA鍵を生成するには、PyCryptoライブラリが使える。 pipを使ってPyCryptoをインストールするには次のようにする。

$ sudo pip install pycrypto

適当なパラメータn、e、dからPEM形式の秘密鍵を生成するコードを書くと次のようになる。 なお、n、eのみを与えた場合は公開鍵が生成される。

# generate_pem.py
from Crypto.PublicKey import RSA

n = 0x00a4ab66b810ae64ff4f43dd769ce0f473cf7f08c4e7e8717ae13954122932928c485096f11478938ac0983055b7ae089786967fa4d7550e4d01bf8af97cf3445f009f1b1e8933214691625cc9ddc4de280443a0a11a401efdcf44845e7bc66885f37ff6903ad2102e4ed1b1561d825b74b29701714cb79cad72aa009b7a86f82c222500d159939d9f581f9a7a7620f7799a43cda0a4d33c3097f6cddd8c27dc8398a22eb2903c7df5b36b9cd85bc3bce5c81d4fa6add2cd44496c67e1370efce43bae5d75b7b47fb1c8a6935444dd2af67a5df18c873cf3857bbce3614223706c02f118c219c44fdc8ed269484e233983a7f5f105e1f2304f0018f898c92ac205
e = 65537
d = 0x3abf5fad295e5e6feb8285bf2c66e12f740699454e8b51f909e31f083fa4683e1e0a8a5f45f36287ed001eb6660a73cc435aebfd0e49ad09722738d89b685aab1e18a55f368984449dd79eccf20eab475186230776cb0b83776fb55dd400cc078600d02152aae0d4f48fc119bcfb65cf736b863b3aa883002a59565021dd8729fcf9162f5a0d6eacc1985da86dbf7fd98ddf47d0869f8588834ecf86156e45dea6c0ae66d617c439d66d5607c09fcd7dbb6bfd872d37f598cd93969f0c4e4a2bbf03b98cef3d7c2624c81e0d70bcf4cd930c238dee5bf3d7b0894d004754a5baceab74e92cc3a96fde2296d0127f464e90d206d003f4538e1917f31cc604483d

key = RSA.construct(map(long, (n,e,d)))
print key.exportKey()

コードを実行してみると次のようになる。

$ python generate_pem.py
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEApKtmuBCuZP9PQ912nOD0c89/CMTn6HF64TlUEikykoxIUJbx
FHiTisCYMFW3rgiXhpZ/pNdVDk0Bv4r5fPNEXwCfGx6JMyFGkWJcyd3E3igEQ6Ch
GkAe/c9EhF57xmiF83/2kDrSEC5O0bFWHYJbdLKXAXFMt5ytcqoAm3qG+CwiJQDR
WZOdn1gfmnp2IPd5mkPNoKTTPDCX9s3djCfcg5iiLrKQPH31s2uc2FvDvOXIHU+m
rdLNRElsZ+E3DvzkO65ddbe0f7HIppNURN0q9npd8YyHPPOFe7zjYUIjcGwC8RjC
GcRP3I7SaUhOIzmDp/XxBeHyME8AGPiYySrCBQIDAQABAoIBADq/X60pXl5v64KF
vyxm4S90BplFTotR+QnjHwg/pGg+HgqKX0XzYoftAB62ZgpzzENa6/0OSa0Jcic4
2JtoWqseGKVfNomERJ3XnszyDqtHUYYjB3bLC4N3b7Vd1ADMB4YA0CFSquDU9I/B
Gbz7Zc9za4Y7OqiDACpZVlAh3Ycp/PkWL1oNbqzBmF2obb9/2Y3fR9CGn4WIg07P
hhVuRd6mwK5m1hfEOdZtVgfAn819u2v9hy039ZjNk5afDE5KK78DuYzvPXwmJMge
DXC89M2TDCON7lvz17CJTQBHVKW6zqt06SzDqW/eIpbQEn9GTpDSBtAD9FOOGRfz
HMYESD0CgYEA1u0Y/0SDl9vCmxowcT9+1OUXQV2ivP6lIUMN4nOSn+jGr1sV/ZqC
FHWnnnunOTxlm7OdM3MyPApuUhKEmg4qrIiDM/Jn5y8fJHw8EoL++EojBOjS4CFa
K3ttMjJKi9PKvzDPPL7PgXdn/p4i8P6gKMAIq/Fw6nEebFN8jTsuLSsCgYEAxCOV
FbCsSl5mnEebrDdOK+B9hQbLYoVTkgnVUlxMiunMwUqW4oKwIKxIlOv0oXjJZAxQ
JcoA8WTqqD33tSGY8VE5XiuzGvutiG22VRh7TNMf2aKaQHYtq+VjPcNYXy4BsEwW
4rMZFtbZ9bx3i0oaConYlIPLyIV4/LqFtIqBFY8CgYBmZ43zgreYkZMFx9KxAunx
kj4kXPL/Te1sDcD91sdT/ds9Dg9KSGYWTYDSGGSy9r4LE+eg7hBPX0D1RfF8Xaej
kV/CTouHMYKLJc6Rm2zU7K4G1tAzDnEiKqr6sc+nFACUXDNB5ECGlVgtjzdi0E+L
WwRGuMFuUvuF7bl4qWv1BQKBgQCS2P0mxybHa1Qxz58q2iFp0mLHtSWTNrUyErCn
QDmCi7dkRF8haa1KWRLihKKcPl2xzVI4aLw5/0989SA/ec8TZbeo3Nj069ep3FJ1
9aVjCHLBM+9/MbvSBiU+OcIxSLW089Lymhq/sc5wIFH0dF944mnID8ED+YJy3Yd7
e3NX2wKBgCoDehZI8U9Ri/HLoGnPt1xI5AMt+PmmXdMRNBV6cojUQAJ+QjjTdOAD
eVXG7w9HAq1QQUWq0wXoB23Qa71rkb3TZcrDigcAuCSfwghX7V4FAcuXJLzd+cop
Hts+sRNXTKZujJ8evbgqscMhGggSzt1k/50EQdrbX6IQ7obWz/Gb
-----END RSA PRIVATE KEY-----

$ python generate_pem.py | openssl rsa -noout -text
Private-Key: (2048 bit)
modulus:
    00:a4:ab:66:b8:10:ae:64:ff:4f:43:dd:76:9c:e0:
    f4:73:cf:7f:08:c4:e7:e8:71:7a:e1:39:54:12:29:
    32:92:8c:48:50:96:f1:14:78:93:8a:c0:98:30:55:
    b7:ae:08:97:86:96:7f:a4:d7:55:0e:4d:01:bf:8a:
    f9:7c:f3:44:5f:00:9f:1b:1e:89:33:21:46:91:62:
    5c:c9:dd:c4:de:28:04:43:a0:a1:1a:40:1e:fd:cf:
    44:84:5e:7b:c6:68:85:f3:7f:f6:90:3a:d2:10:2e:
    4e:d1:b1:56:1d:82:5b:74:b2:97:01:71:4c:b7:9c:
    ad:72:aa:00:9b:7a:86:f8:2c:22:25:00:d1:59:93:
    9d:9f:58:1f:9a:7a:76:20:f7:79:9a:43:cd:a0:a4:
    d3:3c:30:97:f6:cd:dd:8c:27:dc:83:98:a2:2e:b2:
    90:3c:7d:f5:b3:6b:9c:d8:5b:c3:bc:e5:c8:1d:4f:
    a6:ad:d2:cd:44:49:6c:67:e1:37:0e:fc:e4:3b:ae:
    5d:75:b7:b4:7f:b1:c8:a6:93:54:44:dd:2a:f6:7a:
    5d:f1:8c:87:3c:f3:85:7b:bc:e3:61:42:23:70:6c:
    02:f1:18:c2:19:c4:4f:dc:8e:d2:69:48:4e:23:39:
    83:a7:f5:f1:05:e1:f2:30:4f:00:18:f8:98:c9:2a:
    c2:05
publicExponent: 65537 (0x10001)
privateExponent:
    3a:bf:5f:ad:29:5e:5e:6f:eb:82:85:bf:2c:66:e1:
    2f:74:06:99:45:4e:8b:51:f9:09:e3:1f:08:3f:a4:
    68:3e:1e:0a:8a:5f:45:f3:62:87:ed:00:1e:b6:66:
    0a:73:cc:43:5a:eb:fd:0e:49:ad:09:72:27:38:d8:
    9b:68:5a:ab:1e:18:a5:5f:36:89:84:44:9d:d7:9e:
    cc:f2:0e:ab:47:51:86:23:07:76:cb:0b:83:77:6f:
    b5:5d:d4:00:cc:07:86:00:d0:21:52:aa:e0:d4:f4:
    8f:c1:19:bc:fb:65:cf:73:6b:86:3b:3a:a8:83:00:
    2a:59:56:50:21:dd:87:29:fc:f9:16:2f:5a:0d:6e:
    ac:c1:98:5d:a8:6d:bf:7f:d9:8d:df:47:d0:86:9f:
    85:88:83:4e:cf:86:15:6e:45:de:a6:c0:ae:66:d6:
    17:c4:39:d6:6d:56:07:c0:9f:cd:7d:bb:6b:fd:87:
    2d:37:f5:98:cd:93:96:9f:0c:4e:4a:2b:bf:03:b9:
    8c:ef:3d:7c:26:24:c8:1e:0d:70:bc:f4:cd:93:0c:
    23:8d:ee:5b:f3:d7:b0:89:4d:00:47:54:a5:ba:ce:
    ab:74:e9:2c:c3:a9:6f:de:22:96:d0:12:7f:46:4e:
    90:d2:06:d0:03:f4:53:8e:19:17:f3:1c:c6:04:48:
    3d
prime1:
    00:d6:ed:18:ff:44:83:97:db:c2:9b:1a:30:71:3f:
    7e:d4:e5:17:41:5d:a2:bc:fe:a5:21:43:0d:e2:73:
    92:9f:e8:c6:af:5b:15:fd:9a:82:14:75:a7:9e:7b:
    a7:39:3c:65:9b:b3:9d:33:73:32:3c:0a:6e:52:12:
    84:9a:0e:2a:ac:88:83:33:f2:67:e7:2f:1f:24:7c:
    3c:12:82:fe:f8:4a:23:04:e8:d2:e0:21:5a:2b:7b:
    6d:32:32:4a:8b:d3:ca:bf:30:cf:3c:be:cf:81:77:
    67:fe:9e:22:f0:fe:a0:28:c0:08:ab:f1:70:ea:71:
    1e:6c:53:7c:8d:3b:2e:2d:2b
prime2:
    00:c4:23:95:15:b0:ac:4a:5e:66:9c:47:9b:ac:37:
    4e:2b:e0:7d:85:06:cb:62:85:53:92:09:d5:52:5c:
    4c:8a:e9:cc:c1:4a:96:e2:82:b0:20:ac:48:94:eb:
    f4:a1:78:c9:64:0c:50:25:ca:00:f1:64:ea:a8:3d:
    f7:b5:21:98:f1:51:39:5e:2b:b3:1a:fb:ad:88:6d:
    b6:55:18:7b:4c:d3:1f:d9:a2:9a:40:76:2d:ab:e5:
    63:3d:c3:58:5f:2e:01:b0:4c:16:e2:b3:19:16:d6:
    d9:f5:bc:77:8b:4a:1a:0a:89:d8:94:83:cb:c8:85:
    78:fc:ba:85:b4:8a:81:15:8f
exponent1:
    66:67:8d:f3:82:b7:98:91:93:05:c7:d2:b1:02:e9:
    f1:92:3e:24:5c:f2:ff:4d:ed:6c:0d:c0:fd:d6:c7:
    53:fd:db:3d:0e:0f:4a:48:66:16:4d:80:d2:18:64:
    b2:f6:be:0b:13:e7:a0:ee:10:4f:5f:40:f5:45:f1:
    7c:5d:a7:a3:91:5f:c2:4e:8b:87:31:82:8b:25:ce:
    91:9b:6c:d4:ec:ae:06:d6:d0:33:0e:71:22:2a:aa:
    fa:b1:cf:a7:14:00:94:5c:33:41:e4:40:86:95:58:
    2d:8f:37:62:d0:4f:8b:5b:04:46:b8:c1:6e:52:fb:
    85:ed:b9:78:a9:6b:f5:05
exponent2:
    00:92:d8:fd:26:c7:26:c7:6b:54:31:cf:9f:2a:da:
    21:69:d2:62:c7:b5:25:93:36:b5:32:12:b0:a7:40:
    39:82:8b:b7:64:44:5f:21:69:ad:4a:59:12:e2:84:
    a2:9c:3e:5d:b1:cd:52:38:68:bc:39:ff:4f:7c:f5:
    20:3f:79:cf:13:65:b7:a8:dc:d8:f4:eb:d7:a9:dc:
    52:75:f5:a5:63:08:72:c1:33:ef:7f:31:bb:d2:06:
    25:3e:39:c2:31:48:b5:b4:f3:d2:f2:9a:1a:bf:b1:
    ce:70:20:51:f4:74:5f:78:e2:69:c8:0f:c1:03:f9:
    82:72:dd:87:7b:7b:73:57:db
coefficient:
    2a:03:7a:16:48:f1:4f:51:8b:f1:cb:a0:69:cf:b7:
    5c:48:e4:03:2d:f8:f9:a6:5d:d3:11:34:15:7a:72:
    88:d4:40:02:7e:42:38:d3:74:e0:03:79:55:c6:ef:
    0f:47:02:ad:50:41:45:aa:d3:05:e8:07:6d:d0:6b:
    bd:6b:91:bd:d3:65:ca:c3:8a:07:00:b8:24:9f:c2:
    08:57:ed:5e:05:01:cb:97:24:bc:dd:f9:ca:29:1e:
    db:3e:b1:13:57:4c:a6:6e:8c:9f:1e:bd:b8:2a:b1:
    c3:21:1a:08:12:ce:dd:64:ff:9d:04:41:da:db:5f:
    a2:10:ee:86:d6:cf:f1:9b

素因数分解の結果からRSA鍵を生成してみる

公開鍵nを素因数分解した結果からdを計算し、RSA鍵を生成するコードを書いた場合は次のようになる。

# generate_pem2.py
from Crypto.PublicKey import RSA
from Crypto.Util.number import inverse

e = 65537
p = 0x00d6ed18ff448397dbc29b1a30713f7ed4e517415da2bcfea521430de273929fe8c6af5b15fd9a821475a79e7ba7393c659bb39d3373323c0a6e5212849a0e2aac888333f267e72f1f247c3c1282fef84a2304e8d2e0215a2b7b6d32324a8bd3cabf30cf3cbecf817767fe9e22f0fea028c008abf170ea711e6c537c8d3b2e2d2b
q = 0x00c4239515b0ac4a5e669c479bac374e2be07d8506cb6285539209d5525c4c8ae9ccc14a96e282b020ac4894ebf4a178c9640c5025ca00f164eaa83df7b52198f151395e2bb31afbad886db655187b4cd31fd9a29a40762dabe5633dc3585f2e01b04c16e2b31916d6d9f5bc778b4a1a0a89d89483cbc88578fcba85b48a81158f

n = p*q
d = inverse(e, (p-1)*(q-1))

key = RSA.construct(map(long, (n,e,d)))
print key.exportKey()

コードを実行すると、dを与えたときと同じRSA鍵が生成されていることが確認できる。

$ python generate_pem2.py
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEApKtmuBCuZP9PQ912nOD0c89/CMTn6HF64TlUEikykoxIUJbx
FHiTisCYMFW3rgiXhpZ/pNdVDk0Bv4r5fPNEXwCfGx6JMyFGkWJcyd3E3igEQ6Ch
GkAe/c9EhF57xmiF83/2kDrSEC5O0bFWHYJbdLKXAXFMt5ytcqoAm3qG+CwiJQDR
WZOdn1gfmnp2IPd5mkPNoKTTPDCX9s3djCfcg5iiLrKQPH31s2uc2FvDvOXIHU+m
rdLNRElsZ+E3DvzkO65ddbe0f7HIppNURN0q9npd8YyHPPOFe7zjYUIjcGwC8RjC
GcRP3I7SaUhOIzmDp/XxBeHyME8AGPiYySrCBQIDAQABAoIBADq/X60pXl5v64KF
vyxm4S90BplFTotR+QnjHwg/pGg+HgqKX0XzYoftAB62ZgpzzENa6/0OSa0Jcic4
2JtoWqseGKVfNomERJ3XnszyDqtHUYYjB3bLC4N3b7Vd1ADMB4YA0CFSquDU9I/B
Gbz7Zc9za4Y7OqiDACpZVlAh3Ycp/PkWL1oNbqzBmF2obb9/2Y3fR9CGn4WIg07P
hhVuRd6mwK5m1hfEOdZtVgfAn819u2v9hy039ZjNk5afDE5KK78DuYzvPXwmJMge
DXC89M2TDCON7lvz17CJTQBHVKW6zqt06SzDqW/eIpbQEn9GTpDSBtAD9FOOGRfz
HMYESD0CgYEA1u0Y/0SDl9vCmxowcT9+1OUXQV2ivP6lIUMN4nOSn+jGr1sV/ZqC
FHWnnnunOTxlm7OdM3MyPApuUhKEmg4qrIiDM/Jn5y8fJHw8EoL++EojBOjS4CFa
K3ttMjJKi9PKvzDPPL7PgXdn/p4i8P6gKMAIq/Fw6nEebFN8jTsuLSsCgYEAxCOV
FbCsSl5mnEebrDdOK+B9hQbLYoVTkgnVUlxMiunMwUqW4oKwIKxIlOv0oXjJZAxQ
JcoA8WTqqD33tSGY8VE5XiuzGvutiG22VRh7TNMf2aKaQHYtq+VjPcNYXy4BsEwW
4rMZFtbZ9bx3i0oaConYlIPLyIV4/LqFtIqBFY8CgYBmZ43zgreYkZMFx9KxAunx
kj4kXPL/Te1sDcD91sdT/ds9Dg9KSGYWTYDSGGSy9r4LE+eg7hBPX0D1RfF8Xaej
kV/CTouHMYKLJc6Rm2zU7K4G1tAzDnEiKqr6sc+nFACUXDNB5ECGlVgtjzdi0E+L
WwRGuMFuUvuF7bl4qWv1BQKBgQCS2P0mxybHa1Qxz58q2iFp0mLHtSWTNrUyErCn
QDmCi7dkRF8haa1KWRLihKKcPl2xzVI4aLw5/0989SA/ec8TZbeo3Nj069ep3FJ1
9aVjCHLBM+9/MbvSBiU+OcIxSLW089Lymhq/sc5wIFH0dF944mnID8ED+YJy3Yd7
e3NX2wKBgCoDehZI8U9Ri/HLoGnPt1xI5AMt+PmmXdMRNBV6cojUQAJ+QjjTdOAD
eVXG7w9HAq1QQUWq0wXoB23Qa71rkb3TZcrDigcAuCSfwghX7V4FAcuXJLzd+cop
Hts+sRNXTKZujJ8evbgqscMhGggSzt1k/50EQdrbX6IQ7obWz/Gb
-----END RSA PRIVATE KEY-----

関連リンク