OLD | NEW |
(Empty) | |
| 1 # -*- coding: utf-8 -*- |
| 2 # |
| 3 # SelfTest/PublicKey/test_importKey.py: Self-test for importing RSA keys |
| 4 # |
| 5 # =================================================================== |
| 6 # The contents of this file are dedicated to the public domain. To |
| 7 # the extent that dedication to the public domain is not available, |
| 8 # everyone is granted a worldwide, perpetual, royalty-free, |
| 9 # non-exclusive license to exercise all rights associated with the |
| 10 # contents of this file for any purpose whatsoever. |
| 11 # No rights are reserved. |
| 12 # |
| 13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 14 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 15 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 16 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| 17 # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| 18 # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| 19 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 20 # SOFTWARE. |
| 21 # =================================================================== |
| 22 |
| 23 from __future__ import nested_scopes |
| 24 |
| 25 __revision__ = "$Id$" |
| 26 |
| 27 import unittest |
| 28 |
| 29 from Crypto.PublicKey import RSA |
| 30 from Crypto.SelfTest.st_common import * |
| 31 from Crypto.Util.py3compat import * |
| 32 from Crypto.Util.number import inverse |
| 33 from Crypto.Util import asn1 |
| 34 |
| 35 def der2pem(der, text='PUBLIC'): |
| 36 import binascii |
| 37 chunks = [ binascii.b2a_base64(der[i:i+48]) for i in range(0, len(der), 48)
] |
| 38 pem = b('-----BEGIN %s KEY-----\n' % text) |
| 39 pem += b('').join(chunks) |
| 40 pem += b('-----END %s KEY-----' % text) |
| 41 return pem |
| 42 |
| 43 class ImportKeyTests(unittest.TestCase): |
| 44 # 512-bit RSA key generated with openssl |
| 45 rsaKeyPEM = u'''-----BEGIN RSA PRIVATE KEY----- |
| 46 MIIBOwIBAAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+TLr7UkvEtFrRhDDKMtuII |
| 47 q19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQJACUSDEp8RTe32ftq8IwG8 |
| 48 Wojl5mAd1wFiIOrZ/Uv8b963WJOJiuQcVN29vxU5+My9GPZ7RA3hrDBEAoHUDPrI |
| 49 OQIhAPIPLz4dphiD9imAkivY31Rc5AfHJiQRA7XixTcjEkojAiEAyh/pJHks/Mlr |
| 50 +rdPNEpotBjfV4M4BkgGAA/ipcmaAjcCIQCHvhwwKVBLzzTscT2HeUdEeBMoiXXK |
| 51 JACAr3sJQJGxIQIgarRp+m1WSKV1MciwMaTOnbU7wxFs9DP1pva76lYBzgUCIQC9 |
| 52 n0CnZCJ6IZYqSt0H5N7+Q+2Ro64nuwV/OSQfM6sBwQ== |
| 53 -----END RSA PRIVATE KEY-----''' |
| 54 |
| 55 # As above, but this is actually an unencrypted PKCS#8 key |
| 56 rsaKeyPEM8 = u'''-----BEGIN PRIVATE KEY----- |
| 57 MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvx4nkAqgiyNRGlwS |
| 58 ga5tkzEsPv6RP5MuvtSS8S0WtGEMMoy24girX0WsvilQgzKY8xIsGfeEkt7fQPDj |
| 59 wZAzhQIDAQABAkAJRIMSnxFN7fZ+2rwjAbxaiOXmYB3XAWIg6tn9S/xv3rdYk4mK |
| 60 5BxU3b2/FTn4zL0Y9ntEDeGsMEQCgdQM+sg5AiEA8g8vPh2mGIP2KYCSK9jfVFzk |
| 61 B8cmJBEDteLFNyMSSiMCIQDKH+kkeSz8yWv6t080Smi0GN9XgzgGSAYAD+KlyZoC |
| 62 NwIhAIe+HDApUEvPNOxxPYd5R0R4EyiJdcokAICvewlAkbEhAiBqtGn6bVZIpXUx |
| 63 yLAxpM6dtTvDEWz0M/Wm9rvqVgHOBQIhAL2fQKdkInohlipK3Qfk3v5D7ZGjrie7 |
| 64 BX85JB8zqwHB |
| 65 -----END PRIVATE KEY-----''' |
| 66 |
| 67 # The same RSA private key as in rsaKeyPEM, but now encrypted |
| 68 rsaKeyEncryptedPEM=( |
| 69 |
| 70 # With DES and passphrase 'test' |
| 71 ('test', u'''-----BEGIN RSA PRIVATE KEY----- |
| 72 Proc-Type: 4,ENCRYPTED |
| 73 DEK-Info: DES-CBC,AF8F9A40BD2FA2FC |
| 74 |
| 75 Ckl9ex1kaVEWhYC2QBmfaF+YPiR4NFkRXA7nj3dcnuFEzBnY5XULupqQpQI3qbfA |
| 76 u8GYS7+b3toWWiHZivHbAAUBPDIZG9hKDyB9Sq2VMARGsX1yW1zhNvZLIiVJzUHs |
| 77 C6NxQ1IJWOXzTew/xM2I26kPwHIvadq+/VaT8gLQdjdH0jOiVNaevjWnLgrn1mLP |
| 78 BCNRMdcexozWtAFNNqSzfW58MJL2OdMi21ED184EFytIc1BlB+FZiGZduwKGuaKy |
| 79 9bMbdb/1PSvsSzPsqW7KSSrTw6MgJAFJg6lzIYvR5F4poTVBxwBX3+EyEmShiaNY |
| 80 IRX3TgQI0IjrVuLmvlZKbGWP18FXj7I7k9tSsNOOzllTTdq3ny5vgM3A+ynfAaxp |
| 81 dysKznQ6P+IoqML1WxAID4aGRMWka+uArOJ148Rbj9s= |
| 82 -----END RSA PRIVATE KEY-----''', |
| 83 "\xAF\x8F\x9A\x40\xBD\x2F\xA2\xFC"), |
| 84 |
| 85 # With Triple-DES and passphrase 'rocking' |
| 86 ('rocking', u'''-----BEGIN RSA PRIVATE KEY----- |
| 87 Proc-Type: 4,ENCRYPTED |
| 88 DEK-Info: DES-EDE3-CBC,C05D6C07F7FC02F6 |
| 89 |
| 90 w4lwQrXaVoTTJ0GgwY566htTA2/t1YlimhxkxYt9AEeCcidS5M0Wq9ClPiPz9O7F |
| 91 m6K5QpM1rxo1RUE/ZyI85gglRNPdNwkeTOqit+kum7nN73AToX17+irVmOA4Z9E+ |
| 92 4O07t91GxGMcjUSIFk0ucwEU4jgxRvYscbvOMvNbuZszGdVNzBTVddnShKCsy9i7 |
| 93 nJbPlXeEKYi/OkRgO4PtfqqWQu5GIEFVUf9ev1QV7AvC+kyWTR1wWYnHX265jU5c |
| 94 sopxQQtP8XEHIJEdd5/p1oieRcWTCNyY8EkslxDSsrf0OtZp6mZH9N+KU47cgQtt |
| 95 9qGORmlWnsIoFFKcDohbtOaWBTKhkj5h6OkLjFjfU/sBeV1c+7wDT3dAy5tawXjG |
| 96 YSxC7qDQIT/RECvV3+oQKEcmpEujn45wAnkTi12BH30= |
| 97 -----END RSA PRIVATE KEY-----''', |
| 98 "\xC0\x5D\x6C\x07\xF7\xFC\x02\xF6"), |
| 99 ) |
| 100 |
| 101 rsaPublicKeyPEM = u'''-----BEGIN PUBLIC KEY----- |
| 102 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+T |
| 103 Lr7UkvEtFrRhDDKMtuIIq19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQ== |
| 104 -----END PUBLIC KEY-----''' |
| 105 |
| 106 # Obtained using 'ssh-keygen -i -m PKCS8 -f rsaPublicKeyPEM' |
| 107 rsaPublicKeyOpenSSH = '''ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQC/HieQCqCLI1E
aXBKBrm2TMSw+/pE/ky6+1JLxLRa0YQwyjLbiCKtfRay+KVCDMpjzEiwZ94SS3t9A8OPBkDOF commen
t\n''' |
| 108 |
| 109 # The private key, in PKCS#1 format encoded with DER |
| 110 rsaKeyDER = a2b_hex( |
| 111 '''3082013b020100024100bf1e27900aa08b23511a5c1281ae6d93312c3efe |
| 112 913f932ebed492f12d16b4610c328cb6e208ab5f45acbe2950833298f312 |
| 113 2c19f78492dedf40f0e3c190338502030100010240094483129f114dedf6 |
| 114 7edabc2301bc5a88e5e6601dd7016220ead9fd4bfc6fdeb75893898ae41c |
| 115 54ddbdbf1539f8ccbd18f67b440de1ac30440281d40cfac839022100f20f |
| 116 2f3e1da61883f62980922bd8df545ce407c726241103b5e2c53723124a23 |
| 117 022100ca1fe924792cfcc96bfab74f344a68b418df578338064806000fe2 |
| 118 a5c99a023702210087be1c3029504bcf34ec713d877947447813288975ca |
| 119 240080af7b094091b12102206ab469fa6d5648a57531c8b031a4ce9db53b |
| 120 c3116cf433f5a6f6bbea5601ce05022100bd9f40a764227a21962a4add07 |
| 121 e4defe43ed91a3ae27bb057f39241f33ab01c1 |
| 122 '''.replace(" ","")) |
| 123 |
| 124 # The private key, in unencrypted PKCS#8 format encoded with DER |
| 125 rsaKeyDER8 = a2b_hex( |
| 126 '''30820155020100300d06092a864886f70d01010105000482013f3082013 |
| 127 b020100024100bf1e27900aa08b23511a5c1281ae6d93312c3efe913f932 |
| 128 ebed492f12d16b4610c328cb6e208ab5f45acbe2950833298f3122c19f78 |
| 129 492dedf40f0e3c190338502030100010240094483129f114dedf67edabc2 |
| 130 301bc5a88e5e6601dd7016220ead9fd4bfc6fdeb75893898ae41c54ddbdb |
| 131 f1539f8ccbd18f67b440de1ac30440281d40cfac839022100f20f2f3e1da |
| 132 61883f62980922bd8df545ce407c726241103b5e2c53723124a23022100c |
| 133 a1fe924792cfcc96bfab74f344a68b418df578338064806000fe2a5c99a0 |
| 134 23702210087be1c3029504bcf34ec713d877947447813288975ca240080a |
| 135 f7b094091b12102206ab469fa6d5648a57531c8b031a4ce9db53bc3116cf |
| 136 433f5a6f6bbea5601ce05022100bd9f40a764227a21962a4add07e4defe4 |
| 137 3ed91a3ae27bb057f39241f33ab01c1 |
| 138 '''.replace(" ","")) |
| 139 |
| 140 rsaPublicKeyDER = a2b_hex( |
| 141 '''305c300d06092a864886f70d0101010500034b003048024100bf1e27900a |
| 142 a08b23511a5c1281ae6d93312c3efe913f932ebed492f12d16b4610c328c |
| 143 b6e208ab5f45acbe2950833298f3122c19f78492dedf40f0e3c190338502 |
| 144 03010001 |
| 145 '''.replace(" ","")) |
| 146 |
| 147 n = long('BF 1E 27 90 0A A0 8B 23 51 1A 5C 12 81 AE 6D 93 31 2C 3E FE 91 3F
93 2E BE D4 92 F1 2D 16 B4 61 0C 32 8C B6 E2 08 AB 5F 45 AC BE 29 50 83 32 98 F3
12 2C 19 F7 84 92 DE DF 40 F0 E3 C1 90 33 85'.replace(" ",""),16) |
| 148 e = 65537L |
| 149 d = long('09 44 83 12 9F 11 4D ED F6 7E DA BC 23 01 BC 5A 88 E5 E6 60 1D D7
01 62 20 EA D9 FD 4B FC 6F DE B7 58 93 89 8A E4 1C 54 DD BD BF 15 39 F8 CC BD 18
F6 7B 44 0D E1 AC 30 44 02 81 D4 0C FA C8 39'.replace(" ",""),16) |
| 150 p = long('00 F2 0F 2F 3E 1D A6 18 83 F6 29 80 92 2B D8 DF 54 5C E4 07 C7 26
24 11 03 B5 E2 C5 37 23 12 4A 23'.replace(" ",""),16) |
| 151 q = long('00 CA 1F E9 24 79 2C FC C9 6B FA B7 4F 34 4A 68 B4 18 DF 57 83 38
06 48 06 00 0F E2 A5 C9 9A 02 37'.replace(" ",""),16) |
| 152 |
| 153 # This is q^{-1} mod p). fastmath and slowmath use pInv (p^{-1} |
| 154 # mod q) instead! |
| 155 qInv = long('00 BD 9F 40 A7 64 22 7A 21 96 2A 4A DD 07 E4 DE FE 43 ED 91 A3
AE 27 BB 05 7F 39 24 1F 33 AB 01 C1'.replace(" ",""),16) |
| 156 pInv = inverse(p,q) |
| 157 |
| 158 def testImportKey1(self): |
| 159 """Verify import of RSAPrivateKey DER SEQUENCE""" |
| 160 key = self.rsa.importKey(self.rsaKeyDER) |
| 161 self.failUnless(key.has_private()) |
| 162 self.assertEqual(key.n, self.n) |
| 163 self.assertEqual(key.e, self.e) |
| 164 self.assertEqual(key.d, self.d) |
| 165 self.assertEqual(key.p, self.p) |
| 166 self.assertEqual(key.q, self.q) |
| 167 |
| 168 def testImportKey2(self): |
| 169 """Verify import of SubjectPublicKeyInfo DER SEQUENCE""" |
| 170 key = self.rsa.importKey(self.rsaPublicKeyDER) |
| 171 self.failIf(key.has_private()) |
| 172 self.assertEqual(key.n, self.n) |
| 173 self.assertEqual(key.e, self.e) |
| 174 |
| 175 def testImportKey3unicode(self): |
| 176 """Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as unic
ode""" |
| 177 key = RSA.importKey(self.rsaKeyPEM) |
| 178 self.assertEqual(key.has_private(),True) # assert_ |
| 179 self.assertEqual(key.n, self.n) |
| 180 self.assertEqual(key.e, self.e) |
| 181 self.assertEqual(key.d, self.d) |
| 182 self.assertEqual(key.p, self.p) |
| 183 self.assertEqual(key.q, self.q) |
| 184 |
| 185 def testImportKey3bytes(self): |
| 186 """Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as byte
string""" |
| 187 key = RSA.importKey(b(self.rsaKeyPEM)) |
| 188 self.assertEqual(key.has_private(),True) # assert_ |
| 189 self.assertEqual(key.n, self.n) |
| 190 self.assertEqual(key.e, self.e) |
| 191 self.assertEqual(key.d, self.d) |
| 192 self.assertEqual(key.p, self.p) |
| 193 self.assertEqual(key.q, self.q) |
| 194 |
| 195 def testImportKey4unicode(self): |
| 196 """Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as unic
ode""" |
| 197 key = RSA.importKey(self.rsaPublicKeyPEM) |
| 198 self.assertEqual(key.has_private(),False) # failIf |
| 199 self.assertEqual(key.n, self.n) |
| 200 self.assertEqual(key.e, self.e) |
| 201 |
| 202 def testImportKey4bytes(self): |
| 203 """Verify import of SubjectPublicKeyInfo DER SEQUENCE, encoded with PEM
as byte string""" |
| 204 key = RSA.importKey(b(self.rsaPublicKeyPEM)) |
| 205 self.assertEqual(key.has_private(),False) # failIf |
| 206 self.assertEqual(key.n, self.n) |
| 207 self.assertEqual(key.e, self.e) |
| 208 |
| 209 def testImportKey5(self): |
| 210 """Verifies that the imported key is still a valid RSA pair""" |
| 211 key = RSA.importKey(self.rsaKeyPEM) |
| 212 idem = key.encrypt(key.decrypt(b("Test")),0) |
| 213 self.assertEqual(idem[0],b("Test")) |
| 214 |
| 215 def testImportKey6(self): |
| 216 """Verifies that the imported key is still a valid RSA pair""" |
| 217 key = RSA.importKey(self.rsaKeyDER) |
| 218 idem = key.encrypt(key.decrypt(b("Test")),0) |
| 219 self.assertEqual(idem[0],b("Test")) |
| 220 |
| 221 def testImportKey7(self): |
| 222 """Verify import of OpenSSH public key""" |
| 223 key = self.rsa.importKey(self.rsaPublicKeyOpenSSH) |
| 224 self.assertEqual(key.n, self.n) |
| 225 self.assertEqual(key.e, self.e) |
| 226 |
| 227 def testImportKey8(self): |
| 228 """Verify import of encrypted PrivateKeyInfo DER SEQUENCE""" |
| 229 for t in self.rsaKeyEncryptedPEM: |
| 230 key = self.rsa.importKey(t[1], t[0]) |
| 231 self.failUnless(key.has_private()) |
| 232 self.assertEqual(key.n, self.n) |
| 233 self.assertEqual(key.e, self.e) |
| 234 self.assertEqual(key.d, self.d) |
| 235 self.assertEqual(key.p, self.p) |
| 236 self.assertEqual(key.q, self.q) |
| 237 |
| 238 def testImportKey9(self): |
| 239 """Verify import of unencrypted PrivateKeyInfo DER SEQUENCE""" |
| 240 key = self.rsa.importKey(self.rsaKeyDER8) |
| 241 self.failUnless(key.has_private()) |
| 242 self.assertEqual(key.n, self.n) |
| 243 self.assertEqual(key.e, self.e) |
| 244 self.assertEqual(key.d, self.d) |
| 245 self.assertEqual(key.p, self.p) |
| 246 self.assertEqual(key.q, self.q) |
| 247 |
| 248 def testImportKey10(self): |
| 249 """Verify import of unencrypted PrivateKeyInfo DER SEQUENCE, encoded wit
h PEM""" |
| 250 key = self.rsa.importKey(self.rsaKeyPEM8) |
| 251 self.failUnless(key.has_private()) |
| 252 self.assertEqual(key.n, self.n) |
| 253 self.assertEqual(key.e, self.e) |
| 254 self.assertEqual(key.d, self.d) |
| 255 self.assertEqual(key.p, self.p) |
| 256 self.assertEqual(key.q, self.q) |
| 257 |
| 258 def testImportKey11(self): |
| 259 """Verify import of RSAPublicKey DER SEQUENCE""" |
| 260 der = asn1.DerSequence([17, 3]).encode() |
| 261 key = self.rsa.importKey(der) |
| 262 self.assertEqual(key.n, 17) |
| 263 self.assertEqual(key.e, 3) |
| 264 |
| 265 def testImportKey12(self): |
| 266 """Verify import of RSAPublicKey DER SEQUENCE, encoded with PEM""" |
| 267 der = asn1.DerSequence([17, 3]).encode() |
| 268 pem = der2pem(der) |
| 269 key = self.rsa.importKey(pem) |
| 270 self.assertEqual(key.n, 17) |
| 271 self.assertEqual(key.e, 3) |
| 272 |
| 273 ### |
| 274 def testExportKey1(self): |
| 275 key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.p
Inv]) |
| 276 derKey = key.exportKey("DER") |
| 277 self.assertEqual(derKey, self.rsaKeyDER) |
| 278 |
| 279 def testExportKey2(self): |
| 280 key = self.rsa.construct([self.n, self.e]) |
| 281 derKey = key.exportKey("DER") |
| 282 self.assertEqual(derKey, self.rsaPublicKeyDER) |
| 283 |
| 284 def testExportKey3(self): |
| 285 key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.p
Inv]) |
| 286 pemKey = key.exportKey("PEM") |
| 287 self.assertEqual(pemKey, b(self.rsaKeyPEM)) |
| 288 |
| 289 def testExportKey4(self): |
| 290 key = self.rsa.construct([self.n, self.e]) |
| 291 pemKey = key.exportKey("PEM") |
| 292 self.assertEqual(pemKey, b(self.rsaPublicKeyPEM)) |
| 293 |
| 294 def testExportKey5(self): |
| 295 key = self.rsa.construct([self.n, self.e]) |
| 296 openssh_1 = key.exportKey("OpenSSH").split() |
| 297 openssh_2 = self.rsaPublicKeyOpenSSH.split() |
| 298 self.assertEqual(openssh_1[0], openssh_2[0]) |
| 299 self.assertEqual(openssh_1[1], openssh_2[1]) |
| 300 |
| 301 def testExportKey4(self): |
| 302 key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.p
Inv]) |
| 303 # Tuple with index #1 is encrypted with 3DES |
| 304 t = map(b,self.rsaKeyEncryptedPEM[1]) |
| 305 # Force the salt being used when exporting |
| 306 key._randfunc = lambda N: (t[2]*divmod(N+len(t[2]),len(t[2]))[0])[:N] |
| 307 pemKey = key.exportKey("PEM", t[0]) |
| 308 self.assertEqual(pemKey, t[1]) |
| 309 |
| 310 def testExportKey5(self): |
| 311 key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.p
Inv]) |
| 312 derKey = key.exportKey("DER", pkcs=8) |
| 313 self.assertEqual(derKey, self.rsaKeyDER8) |
| 314 |
| 315 def testExportKey6(self): |
| 316 key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.p
Inv]) |
| 317 pemKey = key.exportKey("PEM", pkcs=8) |
| 318 self.assertEqual(pemKey, b(self.rsaKeyPEM8)) |
| 319 |
| 320 class ImportKeyTestsSlow(ImportKeyTests): |
| 321 def setUp(self): |
| 322 self.rsa = RSA.RSAImplementation(use_fast_math=0) |
| 323 |
| 324 class ImportKeyTestsFast(ImportKeyTests): |
| 325 def setUp(self): |
| 326 self.rsa = RSA.RSAImplementation(use_fast_math=1) |
| 327 |
| 328 if __name__ == '__main__': |
| 329 unittest.main() |
| 330 |
| 331 def get_tests(config={}): |
| 332 tests = [] |
| 333 try: |
| 334 from Crypto.PublicKey import _fastmath |
| 335 tests += list_test_cases(ImportKeyTestsFast) |
| 336 except ImportError: |
| 337 pass |
| 338 tests += list_test_cases(ImportKeyTestsSlow) |
| 339 return tests |
| 340 |
| 341 if __name__ == '__main__': |
| 342 suite = lambda: unittest.TestSuite(get_tests()) |
| 343 unittest.main(defaultTest='suite') |
| 344 |
| 345 # vim:set ts=4 sw=4 sts=4 expandtab: |
OLD | NEW |