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"""
33 from CryptoPlus
.Util
.python_compat
import *
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
46 # TODO: PyCryptoPlus treats the message as starting *after* the leading "00"
47 # TODO: That behaviour should probably be changed in the future.
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
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
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
81 e
= 0x11L
# public exponent
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
90 legacy_interface_only
= 0 # Set to 1 to test the original RSA module
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)
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
):
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
):
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
209 ciphertext
= a2b_hex(self
.ciphertext
)
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
):
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
):
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
)
338 tests
+= list_test_cases(RSATest
)
340 from CryptoPlus
.PublicKey
import _fastmath
341 tests
+= list_test_cases(RSAFastMathTest
)
344 tests
+= list_test_cases(RSASlowMathTest
)
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: