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 23from __future__ import nested_scopes 24 25__revision__ = "$Id$" 26 27import unittest 28 29from Crypto.PublicKey import RSA 30from Crypto.SelfTest.st_common import * 31from Crypto.Util.py3compat import * 32from Crypto.Util.number import inverse 33from Crypto.Util import asn1 34 35def 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 43class ImportKeyTests(unittest.TestCase): 44 # 512-bit RSA key generated with openssl 45 rsaKeyPEM = u'''-----BEGIN RSA PRIVATE KEY----- 46MIIBOwIBAAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+TLr7UkvEtFrRhDDKMtuII 47q19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQJACUSDEp8RTe32ftq8IwG8 48Wojl5mAd1wFiIOrZ/Uv8b963WJOJiuQcVN29vxU5+My9GPZ7RA3hrDBEAoHUDPrI 49OQIhAPIPLz4dphiD9imAkivY31Rc5AfHJiQRA7XixTcjEkojAiEAyh/pJHks/Mlr 50+rdPNEpotBjfV4M4BkgGAA/ipcmaAjcCIQCHvhwwKVBLzzTscT2HeUdEeBMoiXXK 51JACAr3sJQJGxIQIgarRp+m1WSKV1MciwMaTOnbU7wxFs9DP1pva76lYBzgUCIQC9 52n0CnZCJ6IZYqSt0H5N7+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----- 57MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvx4nkAqgiyNRGlwS 58ga5tkzEsPv6RP5MuvtSS8S0WtGEMMoy24girX0WsvilQgzKY8xIsGfeEkt7fQPDj 59wZAzhQIDAQABAkAJRIMSnxFN7fZ+2rwjAbxaiOXmYB3XAWIg6tn9S/xv3rdYk4mK 605BxU3b2/FTn4zL0Y9ntEDeGsMEQCgdQM+sg5AiEA8g8vPh2mGIP2KYCSK9jfVFzk 61B8cmJBEDteLFNyMSSiMCIQDKH+kkeSz8yWv6t080Smi0GN9XgzgGSAYAD+KlyZoC 62NwIhAIe+HDApUEvPNOxxPYd5R0R4EyiJdcokAICvewlAkbEhAiBqtGn6bVZIpXUx 63yLAxpM6dtTvDEWz0M/Wm9rvqVgHOBQIhAL2fQKdkInohlipK3Qfk3v5D7ZGjrie7 64BX85JB8zqwHB 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----- 72Proc-Type: 4,ENCRYPTED 73DEK-Info: DES-CBC,AF8F9A40BD2FA2FC 74 75Ckl9ex1kaVEWhYC2QBmfaF+YPiR4NFkRXA7nj3dcnuFEzBnY5XULupqQpQI3qbfA 76u8GYS7+b3toWWiHZivHbAAUBPDIZG9hKDyB9Sq2VMARGsX1yW1zhNvZLIiVJzUHs 77C6NxQ1IJWOXzTew/xM2I26kPwHIvadq+/VaT8gLQdjdH0jOiVNaevjWnLgrn1mLP 78BCNRMdcexozWtAFNNqSzfW58MJL2OdMi21ED184EFytIc1BlB+FZiGZduwKGuaKy 799bMbdb/1PSvsSzPsqW7KSSrTw6MgJAFJg6lzIYvR5F4poTVBxwBX3+EyEmShiaNY 80IRX3TgQI0IjrVuLmvlZKbGWP18FXj7I7k9tSsNOOzllTTdq3ny5vgM3A+ynfAaxp 81dysKznQ6P+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----- 87Proc-Type: 4,ENCRYPTED 88DEK-Info: DES-EDE3-CBC,C05D6C07F7FC02F6 89 90w4lwQrXaVoTTJ0GgwY566htTA2/t1YlimhxkxYt9AEeCcidS5M0Wq9ClPiPz9O7F 91m6K5QpM1rxo1RUE/ZyI85gglRNPdNwkeTOqit+kum7nN73AToX17+irVmOA4Z9E+ 924O07t91GxGMcjUSIFk0ucwEU4jgxRvYscbvOMvNbuZszGdVNzBTVddnShKCsy9i7 93nJbPlXeEKYi/OkRgO4PtfqqWQu5GIEFVUf9ev1QV7AvC+kyWTR1wWYnHX265jU5c 94sopxQQtP8XEHIJEdd5/p1oieRcWTCNyY8EkslxDSsrf0OtZp6mZH9N+KU47cgQtt 959qGORmlWnsIoFFKcDohbtOaWBTKhkj5h6OkLjFjfU/sBeV1c+7wDT3dAy5tawXjG 96YSxC7qDQIT/RECvV3+oQKEcmpEujn45wAnkTi12BH30= 97-----END RSA PRIVATE KEY-----''', 98 "\xC0\x5D\x6C\x07\xF7\xFC\x02\xF6"), 99 ) 100 101 rsaPublicKeyPEM = u'''-----BEGIN PUBLIC KEY----- 102MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+T 103Lr7UkvEtFrRhDDKMtuIIq19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQ== 104-----END PUBLIC KEY-----''' 105 106 # Obtained using 'ssh-keygen -i -m PKCS8 -f rsaPublicKeyPEM' 107 rsaPublicKeyOpenSSH = '''ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQC/HieQCqCLI1EaXBKBrm2TMSw+/pE/ky6+1JLxLRa0YQwyjLbiCKtfRay+KVCDMpjzEiwZ94SS3t9A8OPBkDOF comment\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 unicode""" 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 unicode""" 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 with 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.pInv]) 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.pInv]) 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.pInv]) 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.pInv]) 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.pInv]) 317 pemKey = key.exportKey("PEM", pkcs=8) 318 self.assertEqual(pemKey, b(self.rsaKeyPEM8)) 319 320class ImportKeyTestsSlow(ImportKeyTests): 321 def setUp(self): 322 self.rsa = RSA.RSAImplementation(use_fast_math=0) 323 324class ImportKeyTestsFast(ImportKeyTests): 325 def setUp(self): 326 self.rsa = RSA.RSAImplementation(use_fast_math=1) 327 328if __name__ == '__main__': 329 unittest.main() 330 331def 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 341if __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: 346