Improve English
[python-cryptoplus.git] / src / CryptoPlus / SelfTest / PublicKey / test_RSA.py
blobcd0dc9e7547ae01a4367868033a84295615afc96
1 # -*- coding: utf-8 -*-
3 # SelfTest/PublicKey/test_self.rsa.py: Self-test for the RSA primitive
5 # =======================================================================
6 # Copyright (C) 2008 Dwayne C. Litzenberger <dlitz@dlitz.net>
8 # Permission is hereby granted, free of charge, to any person obtaining
9 # a copy of this software and associated documentation files (the
10 # "Software"), to deal in the Software without restriction, including
11 # without limitation the rights to use, copy, modify, merge, publish,
12 # distribute, sublicense, and/or sell copies of the Software, and to
13 # permit persons to whom the Software is furnished to do so.
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 # =======================================================================
29 """Self-test suite for CryptoPlus.PublicKey.RSA"""
31 __revision__ = "$Id$"
33 from CryptoPlus.Util.python_compat import *
35 import unittest
36 from CryptoPlus.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex
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
44 # from oaep-int.txt
46 # TODO: PyCryptoPlus 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 """
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 """
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 """
81 e = 0x11L # public exponent
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 """
90 legacy_interface_only = 0 # Set to 1 to test the original RSA module
92 def setUp(self):
93 global RSA, Random, bytes_to_long
94 from CryptoPlus.PublicKey import RSA
95 from CryptoPlus import Random
96 from CryptoPlus.Util.number import bytes_to_long, inverse
97 self.n = bytes_to_long(a2b_hex(self.modulus))
98 self.p = bytes_to_long(a2b_hex(self.prime_factor))
100 # Compute q, d, and u from n, e, and p
101 self.q = self.n / self.p
102 self.d = inverse(self.e, (self.p-1)*(self.q-1))
103 self.u = inverse(self.p, self.q) # u = e**-1 (mod q)
105 self.rsa = RSA
107 def test_generate_1arg(self):
108 """RSA (default implementation) generated key (1 argument)"""
109 rsaObj = self.rsa.generate(1024)
110 self._check_private_key(rsaObj)
111 self._exercise_primitive(rsaObj)
112 pub = rsaObj.publickey()
113 self._check_public_key(pub)
114 self._exercise_public_primitive(rsaObj)
116 def test_generate_2arg(self):
117 """RSA (default implementation) generated key (2 arguments)"""
118 rsaObj = self.rsa.generate(1024, Random.new().read)
119 self._check_private_key(rsaObj)
120 self._exercise_primitive(rsaObj)
121 pub = rsaObj.publickey()
122 self._check_public_key(pub)
123 self._exercise_public_primitive(rsaObj)
125 def test_construct_2tuple(self):
126 """RSA (default implementation) constructed key (2-tuple)"""
127 pub = self.rsa.construct((self.n, self.e))
128 self._check_public_key(pub)
129 self._check_encryption(pub)
131 def test_construct_3tuple(self):
132 """RSA (default implementation) constructed key (3-tuple)"""
133 rsaObj = self.rsa.construct((self.n, self.e, self.d))
134 self._check_encryption(rsaObj)
135 self._check_decryption(rsaObj)
137 def test_construct_4tuple(self):
138 """RSA (default implementation) constructed key (4-tuple)"""
139 rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p))
140 self._check_encryption(rsaObj)
141 self._check_decryption(rsaObj)
143 def test_construct_5tuple(self):
144 """RSA (default implementation) constructed key (5-tuple)"""
145 rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q))
146 self._check_encryption(rsaObj)
147 self._check_decryption(rsaObj)
149 def test_construct_6tuple(self):
150 """RSA (default implementation) constructed key (6-tuple)"""
151 rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q, self.u))
152 self._check_private_key(rsaObj)
153 self._check_encryption(rsaObj)
154 self._check_decryption(rsaObj)
156 def _check_private_key(self, rsaObj):
157 # Check capabilities
158 self.assertEqual(1, rsaObj.has_private())
159 self.assertEqual(1, rsaObj.can_sign())
160 self.assertEqual(1, rsaObj.can_encrypt())
161 self.assertEqual(1, rsaObj.can_blind())
163 # Check rsaObj.[nedpqu] -> rsaObj.key.[nedpqu] mapping
164 self.assertEqual(rsaObj.n, rsaObj.key.n)
165 self.assertEqual(rsaObj.e, rsaObj.key.e)
166 self.assertEqual(rsaObj.d, rsaObj.key.d)
167 self.assertEqual(rsaObj.p, rsaObj.key.p)
168 self.assertEqual(rsaObj.q, rsaObj.key.q)
169 self.assertEqual(rsaObj.u, rsaObj.key.u)
171 # Sanity check key data
172 self.assertEqual(1, rsaObj.p < rsaObj.q) # p < q
173 self.assertEqual(rsaObj.n, rsaObj.p * rsaObj.q) # n = pq
174 self.assertEqual(1, rsaObj.d * rsaObj.e % ((rsaObj.p-1) * (rsaObj.q-1))) # ed = 1 (mod (p-1)(q-1))
175 self.assertEqual(1, rsaObj.p * rsaObj.u % rsaObj.q) # pu = 1 (mod q)
176 self.assertEqual(1, rsaObj.p > 1) # p > 1
177 self.assertEqual(1, rsaObj.q > 1) # q > 1
178 self.assertEqual(1, rsaObj.e > 1) # e > 1
179 self.assertEqual(1, rsaObj.d > 1) # d > 1
181 def _check_public_key(self, rsaObj):
182 # Check capabilities
183 self.assertEqual(0, rsaObj.has_private())
184 self.assertEqual(1, rsaObj.can_sign())
185 self.assertEqual(1, rsaObj.can_encrypt())
186 self.assertEqual(1, rsaObj.can_blind())
188 # Check rsaObj.[ne] -> rsaObj.key.[ne] mapping
189 self.assertEqual(rsaObj.n, rsaObj.key.n)
190 self.assertEqual(rsaObj.e, rsaObj.key.e)
192 # Check that private parameters are all missing
193 self.assertEqual(0, hasattr(rsaObj, 'd'))
194 self.assertEqual(0, hasattr(rsaObj, 'p'))
195 self.assertEqual(0, hasattr(rsaObj, 'q'))
196 self.assertEqual(0, hasattr(rsaObj, 'u'))
197 self.assertEqual(0, hasattr(rsaObj.key, 'd'))
198 self.assertEqual(0, hasattr(rsaObj.key, 'p'))
199 self.assertEqual(0, hasattr(rsaObj.key, 'q'))
200 self.assertEqual(0, hasattr(rsaObj.key, 'u'))
202 # Sanity check key data
203 self.assertEqual(1, rsaObj.e > 1) # e > 1
205 def _exercise_primitive(self, rsaObj):
206 # Since we're using a randomly-generated key, we can't check the test
207 # vector, but we can make sure encryption and decryption are inverse
208 # operations.
209 ciphertext = a2b_hex(self.ciphertext)
211 # Test decryption
212 plaintext = rsaObj.decrypt((ciphertext,))
214 # Test encryption (2 arguments)
215 (new_ciphertext2,) = rsaObj.encrypt(plaintext, "")
216 self.assertEqual(b2a_hex(ciphertext), b2a_hex(new_ciphertext2))
218 # Test encryption (1 argument)
219 if not self.legacy_interface_only:
220 (new_ciphertext1,) = rsaObj.encrypt(plaintext)
221 self.assertEqual(b2a_hex(ciphertext), b2a_hex(new_ciphertext1))
223 # Test blinded decryption
224 blinding_factor = Random.new().read(len(ciphertext)-1)
225 blinded_ctext = rsaObj.blind(ciphertext, blinding_factor)
226 blinded_ptext = rsaObj.decrypt((blinded_ctext,))
227 unblinded_plaintext = rsaObj.unblind(blinded_ptext, blinding_factor)
228 self.assertEqual(b2a_hex(plaintext), b2a_hex(unblinded_plaintext))
230 def _exercise_public_primitive(self, rsaObj):
231 plaintext = a2b_hex(self.plaintext)
233 # Test encryption (2 arguments)
234 (new_ciphertext2,) = rsaObj.encrypt(plaintext, "")
236 # Test encryption (1 argument)
237 if not self.legacy_interface_only:
238 (new_ciphertext1,) = rsaObj.encrypt(plaintext)
239 self.assertEqual(new_ciphertext2, new_ciphertext1)
241 def _check_encryption(self, rsaObj):
242 plaintext = a2b_hex(self.plaintext)
243 ciphertext = a2b_hex(self.ciphertext)
245 # Test encryption (2 arguments)
246 (new_ciphertext2,) = rsaObj.encrypt(plaintext, "")
247 self.assertEqual(b2a_hex(ciphertext), b2a_hex(new_ciphertext2))
249 # Test encryption (1 argument)
250 if not self.legacy_interface_only:
251 (new_ciphertext1,) = rsaObj.encrypt(plaintext)
252 self.assertEqual(b2a_hex(ciphertext), b2a_hex(new_ciphertext1))
254 def _check_decryption(self, rsaObj):
255 plaintext = a2b_hex(self.plaintext)
256 ciphertext = a2b_hex(self.ciphertext)
258 # Test plain decryption
259 new_plaintext = rsaObj.decrypt((ciphertext,))
260 self.assertEqual(b2a_hex(plaintext), b2a_hex(new_plaintext))
262 # Test blinded decryption
263 blinding_factor = Random.new().read(len(ciphertext)-1)
264 blinded_ctext = rsaObj.blind(ciphertext, blinding_factor)
265 blinded_ptext = rsaObj.decrypt((blinded_ctext,))
266 unblinded_plaintext = rsaObj.unblind(blinded_ptext, blinding_factor)
267 self.assertEqual(b2a_hex(plaintext), b2a_hex(unblinded_plaintext))
269 class RSAFastMathTest(RSATest):
270 def setUp(self):
271 RSATest.setUp(self)
272 self.rsa = RSA.RSAImplementation(use_fast_math=True)
274 def test_generate_1arg(self):
275 """RSA (_fastmath implementation) generated key (1 argument)"""
276 RSATest.test_generate_1arg(self)
278 def test_generate_2arg(self):
279 """RSA (_fastmath implementation) generated key (2 arguments)"""
280 RSATest.test_generate_2arg(self)
282 def test_construct_2tuple(self):
283 """RSA (_fastmath implementation) constructed key (2-tuple)"""
284 RSATest.test_construct_2tuple(self)
286 def test_construct_3tuple(self):
287 """RSA (_fastmath implementation) constructed key (3-tuple)"""
288 RSATest.test_construct_3tuple(self)
290 def test_construct_4tuple(self):
291 """RSA (_fastmath implementation) constructed key (4-tuple)"""
292 RSATest.test_construct_4tuple(self)
294 def test_construct_5tuple(self):
295 """RSA (_fastmath implementation) constructed key (5-tuple)"""
296 RSATest.test_construct_5tuple(self)
298 def test_construct_6tuple(self):
299 """RSA (_fastmath implementation) constructed key (6-tuple)"""
300 RSATest.test_construct_6tuple(self)
302 class RSASlowMathTest(RSATest):
303 def setUp(self):
304 RSATest.setUp(self)
305 self.rsa = RSA.RSAImplementation(use_fast_math=False)
307 def test_generate_1arg(self):
308 """RSA (_slowmath implementation) generated key (1 argument)"""
309 RSATest.test_generate_1arg(self)
311 def test_generate_2arg(self):
312 """RSA (_slowmath implementation) generated key (2 arguments)"""
313 RSATest.test_generate_2arg(self)
315 def test_construct_2tuple(self):
316 """RSA (_slowmath implementation) constructed key (2-tuple)"""
317 RSATest.test_construct_2tuple(self)
319 def test_construct_3tuple(self):
320 """RSA (_slowmath implementation) constructed key (3-tuple)"""
321 RSATest.test_construct_3tuple(self)
323 def test_construct_4tuple(self):
324 """RSA (_slowmath implementation) constructed key (4-tuple)"""
325 RSATest.test_construct_4tuple(self)
327 def test_construct_5tuple(self):
328 """RSA (_slowmath implementation) constructed key (5-tuple)"""
329 RSATest.test_construct_5tuple(self)
331 def test_construct_6tuple(self):
332 """RSA (_slowmath implementation) constructed key (6-tuple)"""
333 RSATest.test_construct_6tuple(self)
336 def get_tests():
337 tests = []
338 tests += list_test_cases(RSATest)
339 try:
340 from CryptoPlus.PublicKey import _fastmath
341 tests += list_test_cases(RSAFastMathTest)
342 except ImportError:
343 pass
344 tests += list_test_cases(RSASlowMathTest)
345 return tests
347 if __name__ == '__main__':
348 suite = lambda: unittest.TestSuite(get_tests())
349 unittest.main(defaultTest='suite')
351 # vim:set ts=4 sw=4 sts=4 expandtab: