OLD | NEW |
(Empty) | |
| 1 # -*- coding: utf-8 -*- |
| 2 # |
| 3 # SelfTest/PublicKey/test_RSA.py: Self-test for the RSA primitive |
| 4 # |
| 5 # Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net> |
| 6 # |
| 7 # =================================================================== |
| 8 # The contents of this file are dedicated to the public domain. To |
| 9 # the extent that dedication to the public domain is not available, |
| 10 # everyone is granted a worldwide, perpetual, royalty-free, |
| 11 # non-exclusive license to exercise all rights associated with the |
| 12 # contents of this file for any purpose whatsoever. |
| 13 # No rights are reserved. |
| 14 # |
| 15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 16 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 17 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| 19 # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| 20 # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| 21 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 22 # SOFTWARE. |
| 23 # =================================================================== |
| 24 |
| 25 """Self-test suite for Crypto.PublicKey.RSA""" |
| 26 |
| 27 __revision__ = "$Id$" |
| 28 |
| 29 import sys |
| 30 import os |
| 31 if sys.version_info[0] == 2 and sys.version_info[1] == 1: |
| 32 from Crypto.Util.py21compat import * |
| 33 from Crypto.Util.py3compat import * |
| 34 |
| 35 import unittest |
| 36 from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex |
| 37 |
| 38 class RSATest(unittest.TestCase): |
| 39 # Test vectors from "RSA-OAEP and RSA-PSS test vectors (.zip file)" |
| 40 # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip |
| 41 # See RSADSI's PKCS#1 page at |
| 42 # http://www.rsa.com/rsalabs/node.asp?id=2125 |
| 43 |
| 44 # from oaep-int.txt |
| 45 |
| 46 # TODO: PyCrypto treats the message as starting *after* the leading "00" |
| 47 # TODO: That behaviour should probably be changed in the future. |
| 48 plaintext = """ |
| 49 eb 7a 19 ac e9 e3 00 63 50 e3 29 50 4b 45 e2 |
| 50 ca 82 31 0b 26 dc d8 7d 5c 68 f1 ee a8 f5 52 67 |
| 51 c3 1b 2e 8b b4 25 1f 84 d7 e0 b2 c0 46 26 f5 af |
| 52 f9 3e dc fb 25 c9 c2 b3 ff 8a e1 0e 83 9a 2d db |
| 53 4c dc fe 4f f4 77 28 b4 a1 b7 c1 36 2b aa d2 9a |
| 54 b4 8d 28 69 d5 02 41 21 43 58 11 59 1b e3 92 f9 |
| 55 82 fb 3e 87 d0 95 ae b4 04 48 db 97 2f 3a c1 4f |
| 56 7b c2 75 19 52 81 ce 32 d2 f1 b7 6d 4d 35 3e 2d |
| 57 """ |
| 58 |
| 59 ciphertext = """ |
| 60 12 53 e0 4d c0 a5 39 7b b4 4a 7a b8 7e 9b f2 a0 |
| 61 39 a3 3d 1e 99 6f c8 2a 94 cc d3 00 74 c9 5d f7 |
| 62 63 72 20 17 06 9e 52 68 da 5d 1c 0b 4f 87 2c f6 |
| 63 53 c1 1d f8 23 14 a6 79 68 df ea e2 8d ef 04 bb |
| 64 6d 84 b1 c3 1d 65 4a 19 70 e5 78 3b d6 eb 96 a0 |
| 65 24 c2 ca 2f 4a 90 fe 9f 2e f5 c9 c1 40 e5 bb 48 |
| 66 da 95 36 ad 87 00 c8 4f c9 13 0a de a7 4e 55 8d |
| 67 51 a7 4d df 85 d8 b5 0d e9 68 38 d6 06 3e 09 55 |
| 68 """ |
| 69 |
| 70 modulus = """ |
| 71 bb f8 2f 09 06 82 ce 9c 23 38 ac 2b 9d a8 71 f7 |
| 72 36 8d 07 ee d4 10 43 a4 40 d6 b6 f0 74 54 f5 1f |
| 73 b8 df ba af 03 5c 02 ab 61 ea 48 ce eb 6f cd 48 |
| 74 76 ed 52 0d 60 e1 ec 46 19 71 9d 8a 5b 8b 80 7f |
| 75 af b8 e0 a3 df c7 37 72 3e e6 b4 b7 d9 3a 25 84 |
| 76 ee 6a 64 9d 06 09 53 74 88 34 b2 45 45 98 39 4e |
| 77 e0 aa b1 2d 7b 61 a5 1f 52 7a 9a 41 f6 c1 68 7f |
| 78 e2 53 72 98 ca 2a 8f 59 46 f8 e5 fd 09 1d bd cb |
| 79 """ |
| 80 |
| 81 e = 0x11L # public exponent |
| 82 |
| 83 prime_factor = """ |
| 84 c9 7f b1 f0 27 f4 53 f6 34 12 33 ea aa d1 d9 35 |
| 85 3f 6c 42 d0 88 66 b1 d0 5a 0f 20 35 02 8b 9d 86 |
| 86 98 40 b4 16 66 b4 2e 92 ea 0d a3 b4 32 04 b5 cf |
| 87 ce 33 52 52 4d 04 16 a5 a4 41 e7 00 af 46 15 03 |
| 88 """ |
| 89 |
| 90 def setUp(self): |
| 91 global RSA, Random, bytes_to_long |
| 92 from Crypto.PublicKey import RSA |
| 93 from Crypto import Random |
| 94 from Crypto.Util.number import bytes_to_long, inverse |
| 95 self.n = bytes_to_long(a2b_hex(self.modulus)) |
| 96 self.p = bytes_to_long(a2b_hex(self.prime_factor)) |
| 97 |
| 98 # Compute q, d, and u from n, e, and p |
| 99 self.q = divmod(self.n, self.p)[0] |
| 100 self.d = inverse(self.e, (self.p-1)*(self.q-1)) |
| 101 self.u = inverse(self.p, self.q) # u = e**-1 (mod q) |
| 102 |
| 103 self.rsa = RSA |
| 104 |
| 105 def test_generate_1arg(self): |
| 106 """RSA (default implementation) generated key (1 argument)""" |
| 107 rsaObj = self.rsa.generate(1024) |
| 108 self._check_private_key(rsaObj) |
| 109 self._exercise_primitive(rsaObj) |
| 110 pub = rsaObj.publickey() |
| 111 self._check_public_key(pub) |
| 112 self._exercise_public_primitive(rsaObj) |
| 113 |
| 114 def test_generate_2arg(self): |
| 115 """RSA (default implementation) generated key (2 arguments)""" |
| 116 rsaObj = self.rsa.generate(1024, Random.new().read) |
| 117 self._check_private_key(rsaObj) |
| 118 self._exercise_primitive(rsaObj) |
| 119 pub = rsaObj.publickey() |
| 120 self._check_public_key(pub) |
| 121 self._exercise_public_primitive(rsaObj) |
| 122 |
| 123 def test_generate_3args(self): |
| 124 rsaObj = self.rsa.generate(1024, Random.new().read,e=65537) |
| 125 self._check_private_key(rsaObj) |
| 126 self._exercise_primitive(rsaObj) |
| 127 pub = rsaObj.publickey() |
| 128 self._check_public_key(pub) |
| 129 self._exercise_public_primitive(rsaObj) |
| 130 self.assertEqual(65537,rsaObj.e) |
| 131 |
| 132 def test_construct_2tuple(self): |
| 133 """RSA (default implementation) constructed key (2-tuple)""" |
| 134 pub = self.rsa.construct((self.n, self.e)) |
| 135 self._check_public_key(pub) |
| 136 self._check_encryption(pub) |
| 137 self._check_verification(pub) |
| 138 |
| 139 def test_construct_3tuple(self): |
| 140 """RSA (default implementation) constructed key (3-tuple)""" |
| 141 rsaObj = self.rsa.construct((self.n, self.e, self.d)) |
| 142 self._check_encryption(rsaObj) |
| 143 self._check_decryption(rsaObj) |
| 144 self._check_signing(rsaObj) |
| 145 self._check_verification(rsaObj) |
| 146 |
| 147 def test_construct_4tuple(self): |
| 148 """RSA (default implementation) constructed key (4-tuple)""" |
| 149 rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p)) |
| 150 self._check_encryption(rsaObj) |
| 151 self._check_decryption(rsaObj) |
| 152 self._check_signing(rsaObj) |
| 153 self._check_verification(rsaObj) |
| 154 |
| 155 def test_construct_5tuple(self): |
| 156 """RSA (default implementation) constructed key (5-tuple)""" |
| 157 rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q)) |
| 158 self._check_private_key(rsaObj) |
| 159 self._check_encryption(rsaObj) |
| 160 self._check_decryption(rsaObj) |
| 161 self._check_signing(rsaObj) |
| 162 self._check_verification(rsaObj) |
| 163 |
| 164 def test_construct_6tuple(self): |
| 165 """RSA (default implementation) constructed key (6-tuple)""" |
| 166 rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q, sel
f.u)) |
| 167 self._check_private_key(rsaObj) |
| 168 self._check_encryption(rsaObj) |
| 169 self._check_decryption(rsaObj) |
| 170 self._check_signing(rsaObj) |
| 171 self._check_verification(rsaObj) |
| 172 |
| 173 def test_factoring(self): |
| 174 rsaObj = self.rsa.construct([self.n, self.e, self.d]) |
| 175 self.failUnless(rsaObj.p==self.p or rsaObj.p==self.q) |
| 176 self.failUnless(rsaObj.q==self.p or rsaObj.q==self.q) |
| 177 self.failUnless(rsaObj.q*rsaObj.p == self.n) |
| 178 |
| 179 self.assertRaises(ValueError, self.rsa.construct, [self.n, self.e, self.
n-1]) |
| 180 |
| 181 def _check_private_key(self, rsaObj): |
| 182 # Check capabilities |
| 183 self.assertEqual(1, rsaObj.has_private()) |
| 184 self.assertEqual(1, rsaObj.can_sign()) |
| 185 self.assertEqual(1, rsaObj.can_encrypt()) |
| 186 self.assertEqual(1, rsaObj.can_blind()) |
| 187 |
| 188 # Check rsaObj.[nedpqu] -> rsaObj.key.[nedpqu] mapping |
| 189 self.assertEqual(rsaObj.n, rsaObj.key.n) |
| 190 self.assertEqual(rsaObj.e, rsaObj.key.e) |
| 191 self.assertEqual(rsaObj.d, rsaObj.key.d) |
| 192 self.assertEqual(rsaObj.p, rsaObj.key.p) |
| 193 self.assertEqual(rsaObj.q, rsaObj.key.q) |
| 194 self.assertEqual(rsaObj.u, rsaObj.key.u) |
| 195 |
| 196 # Sanity check key data |
| 197 self.assertEqual(rsaObj.n, rsaObj.p * rsaObj.q) # n = pq |
| 198 self.assertEqual(1, rsaObj.d * rsaObj.e % ((rsaObj.p-1) * (rsaObj.q-1)))
# ed = 1 (mod (p-1)(q-1)) |
| 199 self.assertEqual(1, rsaObj.p * rsaObj.u % rsaObj.q) # pu = 1 (mod q) |
| 200 self.assertEqual(1, rsaObj.p > 1) # p > 1 |
| 201 self.assertEqual(1, rsaObj.q > 1) # q > 1 |
| 202 self.assertEqual(1, rsaObj.e > 1) # e > 1 |
| 203 self.assertEqual(1, rsaObj.d > 1) # d > 1 |
| 204 |
| 205 def _check_public_key(self, rsaObj): |
| 206 ciphertext = a2b_hex(self.ciphertext) |
| 207 |
| 208 # Check capabilities |
| 209 self.assertEqual(0, rsaObj.has_private()) |
| 210 self.assertEqual(1, rsaObj.can_sign()) |
| 211 self.assertEqual(1, rsaObj.can_encrypt()) |
| 212 self.assertEqual(1, rsaObj.can_blind()) |
| 213 |
| 214 # Check rsaObj.[ne] -> rsaObj.key.[ne] mapping |
| 215 self.assertEqual(rsaObj.n, rsaObj.key.n) |
| 216 self.assertEqual(rsaObj.e, rsaObj.key.e) |
| 217 |
| 218 # Check that private parameters are all missing |
| 219 self.assertEqual(0, hasattr(rsaObj, 'd')) |
| 220 self.assertEqual(0, hasattr(rsaObj, 'p')) |
| 221 self.assertEqual(0, hasattr(rsaObj, 'q')) |
| 222 self.assertEqual(0, hasattr(rsaObj, 'u')) |
| 223 self.assertEqual(0, hasattr(rsaObj.key, 'd')) |
| 224 self.assertEqual(0, hasattr(rsaObj.key, 'p')) |
| 225 self.assertEqual(0, hasattr(rsaObj.key, 'q')) |
| 226 self.assertEqual(0, hasattr(rsaObj.key, 'u')) |
| 227 |
| 228 # Sanity check key data |
| 229 self.assertEqual(1, rsaObj.e > 1) # e > 1 |
| 230 |
| 231 # Public keys should not be able to sign or decrypt |
| 232 self.assertRaises(TypeError, rsaObj.sign, ciphertext, b("")) |
| 233 self.assertRaises(TypeError, rsaObj.decrypt, ciphertext) |
| 234 |
| 235 # Check __eq__ and __ne__ |
| 236 self.assertEqual(rsaObj.publickey() == rsaObj.publickey(),True) # assert
_ |
| 237 self.assertEqual(rsaObj.publickey() != rsaObj.publickey(),False) # failI
f |
| 238 |
| 239 def _exercise_primitive(self, rsaObj): |
| 240 # Since we're using a randomly-generated key, we can't check the test |
| 241 # vector, but we can make sure encryption and decryption are inverse |
| 242 # operations. |
| 243 ciphertext = a2b_hex(self.ciphertext) |
| 244 |
| 245 # Test decryption |
| 246 plaintext = rsaObj.decrypt((ciphertext,)) |
| 247 |
| 248 # Test encryption (2 arguments) |
| 249 (new_ciphertext2,) = rsaObj.encrypt(plaintext, b("")) |
| 250 self.assertEqual(b2a_hex(ciphertext), b2a_hex(new_ciphertext2)) |
| 251 |
| 252 # Test blinded decryption |
| 253 blinding_factor = Random.new().read(len(ciphertext)-1) |
| 254 blinded_ctext = rsaObj.blind(ciphertext, blinding_factor) |
| 255 blinded_ptext = rsaObj.decrypt((blinded_ctext,)) |
| 256 unblinded_plaintext = rsaObj.unblind(blinded_ptext, blinding_factor) |
| 257 self.assertEqual(b2a_hex(plaintext), b2a_hex(unblinded_plaintext)) |
| 258 |
| 259 # Test signing (2 arguments) |
| 260 signature2 = rsaObj.sign(ciphertext, b("")) |
| 261 self.assertEqual((bytes_to_long(plaintext),), signature2) |
| 262 |
| 263 # Test verification |
| 264 self.assertEqual(1, rsaObj.verify(ciphertext, (bytes_to_long(plaintext),
))) |
| 265 |
| 266 def _exercise_public_primitive(self, rsaObj): |
| 267 plaintext = a2b_hex(self.plaintext) |
| 268 |
| 269 # Test encryption (2 arguments) |
| 270 (new_ciphertext2,) = rsaObj.encrypt(plaintext, b("")) |
| 271 |
| 272 # Exercise verification |
| 273 rsaObj.verify(new_ciphertext2, (bytes_to_long(plaintext),)) |
| 274 |
| 275 def _check_encryption(self, rsaObj): |
| 276 plaintext = a2b_hex(self.plaintext) |
| 277 ciphertext = a2b_hex(self.ciphertext) |
| 278 |
| 279 # Test encryption (2 arguments) |
| 280 (new_ciphertext2,) = rsaObj.encrypt(plaintext, b("")) |
| 281 self.assertEqual(b2a_hex(ciphertext), b2a_hex(new_ciphertext2)) |
| 282 |
| 283 def _check_decryption(self, rsaObj): |
| 284 plaintext = a2b_hex(self.plaintext) |
| 285 ciphertext = a2b_hex(self.ciphertext) |
| 286 |
| 287 # Test plain decryption |
| 288 new_plaintext = rsaObj.decrypt((ciphertext,)) |
| 289 self.assertEqual(b2a_hex(plaintext), b2a_hex(new_plaintext)) |
| 290 |
| 291 # Test blinded decryption |
| 292 blinding_factor = Random.new().read(len(ciphertext)-1) |
| 293 blinded_ctext = rsaObj.blind(ciphertext, blinding_factor) |
| 294 blinded_ptext = rsaObj.decrypt((blinded_ctext,)) |
| 295 unblinded_plaintext = rsaObj.unblind(blinded_ptext, blinding_factor) |
| 296 self.assertEqual(b2a_hex(plaintext), b2a_hex(unblinded_plaintext)) |
| 297 |
| 298 def _check_verification(self, rsaObj): |
| 299 signature = bytes_to_long(a2b_hex(self.plaintext)) |
| 300 message = a2b_hex(self.ciphertext) |
| 301 |
| 302 # Test verification |
| 303 t = (signature,) # rsaObj.verify expects a tuple |
| 304 self.assertEqual(1, rsaObj.verify(message, t)) |
| 305 |
| 306 # Test verification with overlong tuple (this is a |
| 307 # backward-compatibility hack to support some harmless misuse of the |
| 308 # API) |
| 309 t2 = (signature, '') |
| 310 self.assertEqual(1, rsaObj.verify(message, t2)) # extra garbage at end o
f tuple |
| 311 |
| 312 def _check_signing(self, rsaObj): |
| 313 signature = bytes_to_long(a2b_hex(self.plaintext)) |
| 314 message = a2b_hex(self.ciphertext) |
| 315 |
| 316 # Test signing (2 argument) |
| 317 self.assertEqual((signature,), rsaObj.sign(message, b(""))) |
| 318 |
| 319 class RSAFastMathTest(RSATest): |
| 320 def setUp(self): |
| 321 RSATest.setUp(self) |
| 322 self.rsa = RSA.RSAImplementation(use_fast_math=True) |
| 323 |
| 324 def test_generate_1arg(self): |
| 325 """RSA (_fastmath implementation) generated key (1 argument)""" |
| 326 RSATest.test_generate_1arg(self) |
| 327 |
| 328 def test_generate_2arg(self): |
| 329 """RSA (_fastmath implementation) generated key (2 arguments)""" |
| 330 RSATest.test_generate_2arg(self) |
| 331 |
| 332 def test_construct_2tuple(self): |
| 333 """RSA (_fastmath implementation) constructed key (2-tuple)""" |
| 334 RSATest.test_construct_2tuple(self) |
| 335 |
| 336 def test_construct_3tuple(self): |
| 337 """RSA (_fastmath implementation) constructed key (3-tuple)""" |
| 338 RSATest.test_construct_3tuple(self) |
| 339 |
| 340 def test_construct_4tuple(self): |
| 341 """RSA (_fastmath implementation) constructed key (4-tuple)""" |
| 342 RSATest.test_construct_4tuple(self) |
| 343 |
| 344 def test_construct_5tuple(self): |
| 345 """RSA (_fastmath implementation) constructed key (5-tuple)""" |
| 346 RSATest.test_construct_5tuple(self) |
| 347 |
| 348 def test_construct_6tuple(self): |
| 349 """RSA (_fastmath implementation) constructed key (6-tuple)""" |
| 350 RSATest.test_construct_6tuple(self) |
| 351 |
| 352 def test_factoring(self): |
| 353 RSATest.test_factoring(self) |
| 354 |
| 355 class RSASlowMathTest(RSATest): |
| 356 def setUp(self): |
| 357 RSATest.setUp(self) |
| 358 self.rsa = RSA.RSAImplementation(use_fast_math=False) |
| 359 |
| 360 def test_generate_1arg(self): |
| 361 """RSA (_slowmath implementation) generated key (1 argument)""" |
| 362 RSATest.test_generate_1arg(self) |
| 363 |
| 364 def test_generate_2arg(self): |
| 365 """RSA (_slowmath implementation) generated key (2 arguments)""" |
| 366 RSATest.test_generate_2arg(self) |
| 367 |
| 368 def test_construct_2tuple(self): |
| 369 """RSA (_slowmath implementation) constructed key (2-tuple)""" |
| 370 RSATest.test_construct_2tuple(self) |
| 371 |
| 372 def test_construct_3tuple(self): |
| 373 """RSA (_slowmath implementation) constructed key (3-tuple)""" |
| 374 RSATest.test_construct_3tuple(self) |
| 375 |
| 376 def test_construct_4tuple(self): |
| 377 """RSA (_slowmath implementation) constructed key (4-tuple)""" |
| 378 RSATest.test_construct_4tuple(self) |
| 379 |
| 380 def test_construct_5tuple(self): |
| 381 """RSA (_slowmath implementation) constructed key (5-tuple)""" |
| 382 RSATest.test_construct_5tuple(self) |
| 383 |
| 384 def test_construct_6tuple(self): |
| 385 """RSA (_slowmath implementation) constructed key (6-tuple)""" |
| 386 RSATest.test_construct_6tuple(self) |
| 387 |
| 388 def test_factoring(self): |
| 389 RSATest.test_factoring(self) |
| 390 |
| 391 def get_tests(config={}): |
| 392 tests = [] |
| 393 tests += list_test_cases(RSATest) |
| 394 try: |
| 395 from Crypto.PublicKey import _fastmath |
| 396 tests += list_test_cases(RSAFastMathTest) |
| 397 except ImportError: |
| 398 from distutils.sysconfig import get_config_var |
| 399 import inspect |
| 400 _fm_path = os.path.normpath(os.path.dirname(os.path.abspath( |
| 401 inspect.getfile(inspect.currentframe()))) |
| 402 +"/../../PublicKey/_fastmath"+get_config_var("SO")) |
| 403 if os.path.exists(_fm_path): |
| 404 raise ImportError("While the _fastmath module exists, importing "+ |
| 405 "it failed. This may point to the gmp or mpir shared library "+ |
| 406 "not being in the path. _fastmath was found at "+_fm_path) |
| 407 if config.get('slow_tests',1): |
| 408 tests += list_test_cases(RSASlowMathTest) |
| 409 return tests |
| 410 |
| 411 if __name__ == '__main__': |
| 412 suite = lambda: unittest.TestSuite(get_tests()) |
| 413 unittest.main(defaultTest='suite') |
| 414 |
| 415 # vim:set ts=4 sw=4 sts=4 expandtab: |
OLD | NEW |