1 ### -*- mode: python, coding: utf-8 -*-
3 ### Test symmetric algorithms
5 ### (c) 2019 Straylight/Edgeware
8 ###----- Licensing notice ---------------------------------------------------
10 ### This file is part of the Python interface to Catacomb.
12 ### Catacomb/Python is free software: you can redistribute it and/or
13 ### modify it under the terms of the GNU General Public License as
14 ### published by the Free Software Foundation; either version 2 of the
15 ### License, or (at your option) any later version.
17 ### Catacomb/Python is distributed in the hope that it will be useful, but
18 ### WITHOUT ANY WARRANTY; without even the implied warranty of
19 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ### General Public License for more details.
22 ### You should have received a copy of the GNU General Public License
23 ### along with Catacomb/Python. If not, write to the Free Software
24 ### Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
27 ###--------------------------------------------------------------------------
34 ###--------------------------------------------------------------------------
37 def bad_key_size(ksz
):
38 if isinstance(ksz
, C
.KeySZAny
): return None
39 elif isinstance(ksz
, C
.KeySZRange
):
40 if ksz
.mod
!= 1: return ksz
.min + 1
41 elif ksz
.max is not None: return ksz
.max + 1
42 elif ksz
.min != 0: return ksz
.min - 1
44 elif isinstance(ksz
, C
.KeySZSet
):
45 for sz
in sorted(ksz
.set):
46 if sz
+ 1 not in ksz
.set: return sz
+ 1
47 assert False, "That should have worked."
51 def different_key_size(ksz
, sz
):
52 if isinstance(ksz
, C
.KeySZAny
): return sz
+ 1
53 elif isinstance(ksz
, C
.KeySZRange
):
54 if sz
> ksz
.min: return sz
- ksz
.mod
55 elif ksz
.max is None or sz
< ksz
.max: return sz
+ ksz
.mod
57 elif isinstance(ksz
, C
.KeySZSet
):
58 for sz1
in sorted(ksz
.set):
59 if sz
!= sz1
: return sz1
64 class HashBufferTestMixin (U
.TestCase
):
65 """Mixin class for testing all of the various `hash...' methods."""
68 def dohash(me
, h
, op
, arg
):
69 getattr(h
, me
.HASHMETH
+ op
)(arg
)
72 def check_hashbuffer_hashn(me
, w
, bigendp
, makefn
, hashop
):
75 ## Check encoding an integer.
76 h0
, donefn0
= makefn(w
+ 2)
77 me
.dohash(h0
, "u8", 0x00)
78 me
.dohash(h0
, hashop
, T
.bytes_as_int(w
, bigendp
))
79 me
.dohash(h0
, "u8", w
+ 1)
80 h1
, donefn1
= makefn(w
+ 2)
81 me
.dohash(h1
, "", T
.span(w
+ 2))
82 me
.assertEqual(donefn0(), donefn1())
84 ## Check overflow detection.
86 me
.assertRaises(OverflowError, me
.dohash
, h0
, hashop
, 1 << 8*w
)
88 def check_hashbuffer_bufn(me
, w
, bigendp
, makefn
, hashop
):
89 """Check `hashbufN'."""
91 ## Go through a number of different sizes.
92 for n
in [0, 1, 7, 8, 19, 255, 12345, 65535, 123456]:
93 if n
>= 1 << 8*w
: continue
94 h0
, donefn0
= makefn(2 + w
+ n
)
95 me
.dohash(h0
, "u8", 0x00)
96 me
.dohash(h0
, hashop
, T
.span(n
))
97 me
.dohash(h0
, "u8", 0xff)
98 h1
, donefn1
= makefn(2 + w
+ n
)
99 me
.dohash(h1
, "", T
.prep_lenseq(w
, n
, bigendp
, True))
100 me
.assertEqual(donefn0(), donefn1())
102 ## Check blocks which are too large for the length prefix.
105 h0
, _
= makefn(w
+ n
)
106 me
.assertRaises(ValueError,
107 me
.dohash
, h0
, hashop
, C
.ByteString
.zero(n
))
109 def check_hashbuffer(me
, makefn
):
110 """Test the various `hash...' methods."""
113 me
.check_hashbuffer_hashn(1, True, makefn
, "u8")
114 me
.check_hashbuffer_hashn(2, True, makefn
, "u16")
115 me
.check_hashbuffer_hashn(2, True, makefn
, "u16b")
116 me
.check_hashbuffer_hashn(2, False, makefn
, "u16l")
117 me
.check_hashbuffer_hashn(3, True, makefn
, "u24")
118 me
.check_hashbuffer_hashn(3, True, makefn
, "u24b")
119 me
.check_hashbuffer_hashn(3, False, makefn
, "u24l")
120 me
.check_hashbuffer_hashn(4, True, makefn
, "u32")
121 me
.check_hashbuffer_hashn(4, True, makefn
, "u32b")
122 me
.check_hashbuffer_hashn(4, False, makefn
, "u32l")
123 if hasattr(makefn(0)[0], me
.HASHMETH
+ "u64"):
124 me
.check_hashbuffer_hashn(8, True, makefn
, "u64")
125 me
.check_hashbuffer_hashn(8, True, makefn
, "u64b")
126 me
.check_hashbuffer_hashn(8, False, makefn
, "u64l")
129 me
.check_hashbuffer_bufn(1, True, makefn
, "buf8")
130 me
.check_hashbuffer_bufn(2, True, makefn
, "buf16")
131 me
.check_hashbuffer_bufn(2, True, makefn
, "buf16b")
132 me
.check_hashbuffer_bufn(2, False, makefn
, "buf16l")
133 me
.check_hashbuffer_bufn(3, True, makefn
, "buf24")
134 me
.check_hashbuffer_bufn(3, True, makefn
, "buf24b")
135 me
.check_hashbuffer_bufn(3, False, makefn
, "buf24l")
136 me
.check_hashbuffer_bufn(4, True, makefn
, "buf32")
137 me
.check_hashbuffer_bufn(4, True, makefn
, "buf32b")
138 me
.check_hashbuffer_bufn(4, False, makefn
, "buf32l")
139 if hasattr(makefn(0)[0], me
.HASHMETH
+ "u64"):
140 me
.check_hashbuffer_bufn(8, True, makefn
, "buf64")
141 me
.check_hashbuffer_bufn(8, True, makefn
, "buf64b")
142 me
.check_hashbuffer_bufn(8, False, makefn
, "buf64l")
144 ###--------------------------------------------------------------------------
145 class TestKeysize (U
.TestCase
):
149 ## A typical one-byte spec.
151 me
.assertEqual(type(ksz
), C
.KeySZAny
)
152 me
.assertEqual(ksz
.default
, 20)
153 me
.assertEqual(ksz
.min, 0)
154 me
.assertEqual(ksz
.max, None)
155 for n
in [0, 12, 20, 5000]:
156 me
.assertTrue(ksz
.check(n
))
157 me
.assertEqual(ksz
.best(n
), n
)
158 me
.assertEqual(ksz
.pad(n
), n
)
160 ## A typical two-byte spec. (No published algorithms actually /need/ a
161 ## two-byte key-size spec, but all of the HMAC variants use one anyway.)
162 ksz
= C
.sha256_hmac
.keysz
163 me
.assertEqual(type(ksz
), C
.KeySZAny
)
164 me
.assertEqual(ksz
.default
, 32)
165 me
.assertEqual(ksz
.min, 0)
166 me
.assertEqual(ksz
.max, None)
167 for n
in [0, 12, 20, 5000]:
168 me
.assertTrue(ksz
.check(n
))
169 me
.assertEqual(ksz
.best(n
), n
)
170 me
.assertEqual(ksz
.pad(n
), n
)
172 ## Check construction.
174 me
.assertEqual(ksz
.default
, 15)
175 me
.assertEqual(ksz
.min, 0)
176 me
.assertEqual(ksz
.max, None)
177 me
.assertRaises(ValueError, lambda: C
.KeySZAny(-8))
178 me
.assertEqual(C
.KeySZAny(0).default
, 0)
181 ## Note that no published algorithm uses a 16-bit `set' spec.
184 ksz
= C
.salsa20
.keysz
185 me
.assertEqual(type(ksz
), C
.KeySZSet
)
186 me
.assertEqual(ksz
.default
, 32)
187 me
.assertEqual(ksz
.min, 10)
188 me
.assertEqual(ksz
.max, 32)
189 me
.assertEqual(ksz
.set, set([10, 16, 32]))
190 for x
, best
, pad
in [(9, None, 10), (10, 10, 10), (11, 10, 16),
191 (15, 10, 16), (16, 16, 16), (17, 16, 32),
192 (31, 16, 32), (32, 32, 32), (33, 32, None)]:
193 if x
== best
== pad
: me
.assertTrue(ksz
.check(x
))
194 else: me
.assertFalse(ksz
.check(x
))
195 if best
is None: me
.assertRaises(ValueError, ksz
.best
, x
)
196 else: me
.assertEqual(ksz
.best(x
), best
)
197 if pad
is None: me
.assertRaises(ValueError, ksz
.pad
, x
)
198 else: me
.assertEqual(ksz
.pad(x
), pad
)
200 ## Check construction.
202 me
.assertEqual(ksz
.default
, 7)
203 me
.assertEqual(ksz
.set, set([7]))
204 me
.assertEqual(ksz
.min, 7)
205 me
.assertEqual(ksz
.max, 7)
206 ksz
= C
.KeySZSet(7, iter([3, 6, 9]))
207 me
.assertEqual(ksz
.default
, 7)
208 me
.assertEqual(ksz
.set, set([3, 6, 7, 9]))
209 me
.assertEqual(ksz
.min, 3)
210 me
.assertEqual(ksz
.max, 9)
213 ## Note that no published algorithm uses a 16-bit `range' spec, or an
214 ## unbounded `range'.
217 ksz
= C
.rijndael
.keysz
218 me
.assertEqual(type(ksz
), C
.KeySZRange
)
219 me
.assertEqual(ksz
.default
, 32)
220 me
.assertEqual(ksz
.min, 4)
221 me
.assertEqual(ksz
.max, 32)
222 me
.assertEqual(ksz
.mod
, 4)
223 for x
, best
, pad
in [(3, None, 4), (4, 4, 4), (5, 4, 8),
224 (15, 12, 16), (16, 16, 16), (17, 16, 20),
225 (31, 28, 32), (32, 32, 32), (33, 32, None)]:
226 if x
== best
== pad
: me
.assertTrue(ksz
.check(x
))
227 else: me
.assertFalse(ksz
.check(x
))
228 if best
is None: me
.assertRaises(ValueError, ksz
.best
, x
)
229 else: me
.assertEqual(ksz
.best(x
), best
)
230 if pad
is None: me
.assertRaises(ValueError, ksz
.pad
, x
)
231 else: me
.assertEqual(ksz
.pad(x
), pad
)
233 ## Check construction.
234 ksz
= C
.KeySZRange(28, 21, 35, 7)
235 me
.assertEqual(ksz
.default
, 28)
236 me
.assertEqual(ksz
.min, 21)
237 me
.assertEqual(ksz
.max, 35)
238 me
.assertEqual(ksz
.mod
, 7)
239 ksz
= C
.KeySZRange(28, 21, None, 7)
240 me
.assertEqual(ksz
.min, 21)
241 me
.assertEqual(ksz
.max, None)
242 me
.assertEqual(ksz
.mod
, 7)
243 me
.assertEqual(ksz
.pad(36), 42)
244 me
.assertRaises(ValueError, C
.KeySZRange
, 29, 21, 35, 7)
245 me
.assertRaises(ValueError, C
.KeySZRange
, 28, 20, 35, 7)
246 me
.assertRaises(ValueError, C
.KeySZRange
, 28, 21, 34, 7)
247 me
.assertRaises(ValueError, C
.KeySZRange
, 28, -7, 35, 7)
248 me
.assertRaises(ValueError, C
.KeySZRange
, 28, 35, 21, 7)
249 me
.assertRaises(ValueError, C
.KeySZRange
, 35, 21, 28, 7)
250 me
.assertRaises(ValueError, C
.KeySZRange
, 21, 28, 35, 7)
252 def test_conversions(me
):
253 me
.assertEqual(C
.KeySZ
.fromec(256), 128)
254 me
.assertEqual(C
.KeySZ
.fromschnorr(256), 128)
255 me
.assertEqual(round(C
.KeySZ
.fromdl(2958.6875)), 128)
256 me
.assertEqual(round(C
.KeySZ
.fromif(2958.6875)), 128)
257 me
.assertEqual(C
.KeySZ
.toec(128), 256)
258 me
.assertEqual(C
.KeySZ
.toschnorr(128), 256)
259 me
.assertEqual(C
.KeySZ
.todl(128), 2958.6875)
260 me
.assertEqual(C
.KeySZ
.toif(128), 2958.6875)
262 ###--------------------------------------------------------------------------
263 class TestCipher (T
.GenericTestMixin
):
264 """Test basic symmetric ciphers."""
266 def _test_cipher(me
, ccls
):
268 ## Check the class properties.
269 me
.assertEqual(type(ccls
.name
), str)
270 me
.assertTrue(isinstance(ccls
.keysz
, C
.KeySZ
))
271 me
.assertEqual(type(ccls
.blksz
), int)
273 ## Check round-tripping.
274 k
= T
.span(ccls
.keysz
.default
)
275 iv
= T
.span(ccls
.blksz
)
280 except ValueError: can_setiv
= False
284 c0
= enc
.encrypt(m
[0:57])
286 c1
= enc
.encrypt(m
[57:189])
289 except ValueError: can_bdry
= False
293 c2
= enc
.encrypt(m
[189:253])
295 me
.assertEqual(len(c0
) + len(c1
) + len(c2
), len(m
))
296 me
.assertEqual(m0
, m
[0:57])
297 me
.assertEqual(m1
, m
[57:189])
298 me
.assertEqual(m2
, m
[189:253])
300 ## Check the `enczero' and `deczero' methods.
302 me
.assertEqual(dec
.decrypt(c3
), C
.ByteString
.zero(32))
304 me
.assertEqual(enc
.encrypt(m4
), C
.ByteString
.zero(32))
306 ## Check that ciphers which support a `boundary' operation actually
310 if can_setiv
: dec
.setiv(iv
)
311 m01
= dec
.decrypt(c0
+ c1
)
312 me
.assertEqual(m01
, m
[0:189])
314 ## Check that the boundary actually does something.
317 if can_setiv
: dec
.setiv(iv
)
318 m012
= dec
.decrypt(c0
+ c1
+ c2
)
319 me
.assertNotEqual(m012
, m
)
321 ## Check that bad key lengths are rejected.
322 badlen
= bad_key_size(ccls
.keysz
)
323 if badlen
is not None: me
.assertRaises(ValueError, ccls
, T
.span(badlen
))
325 TestCipher
.generate_testcases((name
, C
.gcciphers
[name
]) for name
in
326 ["des-ecb", "rijndael-cbc", "twofish-cfb", "serpent-ofb",
327 "blowfish-counter", "rc4", "seal", "salsa20/8", "shake128-xof"])
329 ###--------------------------------------------------------------------------
330 class TestAuthenticatedEncryption \
331 (HashBufferTestMixin
, T
.GenericTestMixin
):
332 """Test authenticated encryption schemes."""
334 def _test_aead(me
, aecls
):
336 ## Check the class properties.
337 me
.assertEqual(type(aecls
.name
), str)
338 me
.assertTrue(isinstance(aecls
.keysz
, C
.KeySZ
))
339 me
.assertTrue(isinstance(aecls
.noncesz
, C
.KeySZ
))
340 me
.assertTrue(isinstance(aecls
.tagsz
, C
.KeySZ
))
341 me
.assertEqual(type(aecls
.blksz
), int)
342 me
.assertEqual(type(aecls
.bufsz
), int)
343 me
.assertEqual(type(aecls
.ohd
), int)
344 me
.assertEqual(type(aecls
.flags
), int)
346 ## Check round-tripping, with full precommitment. First, select some
347 ## parameters. (It's conceivable that some AEAD schemes are more
348 ## restrictive than advertised by the various properties, but this works
349 ## out OK in practice.)
350 k
= T
.span(aecls
.keysz
.default
)
351 n
= T
.span(aecls
.noncesz
.default
)
352 if aecls
.flags
&C
.AEADF_NOAAD
: h
= T
.span(0)
353 else: h
= T
.span(131)
355 tsz
= aecls
.tagsz
.default
358 ## Next, encrypt a message, checking that things are proper as we go.
359 enc
= key
.enc(nonce
= n
, hsz
= len(h
), msz
= len(m
), tsz
= tsz
)
360 me
.assertEqual(enc
.hsz
, len(h
))
361 me
.assertEqual(enc
.msz
, len(m
))
362 me
.assertEqual(enc
.mlen
, 0)
363 me
.assertEqual(enc
.tsz
, tsz
)
365 if aecls
.flags
&C
.AEADF_AADNDEP
: me
.assertEqual(aad
.hsz
, len(h
))
366 else: me
.assertEqual(aad
.hsz
, None)
367 me
.assertEqual(aad
.hlen
, 0)
368 if not aecls
.flags
&C
.AEADF_NOAAD
:
370 me
.assertEqual(aad
.hlen
, 83)
372 me
.assertEqual(aad
.hlen
, 131)
373 c0
= enc
.encrypt(m
[0:57])
374 me
.assertEqual(enc
.mlen
, 57)
375 me
.assertTrue(57 - aecls
.bufsz
<= len(c0
) <= 57 + aecls
.ohd
)
376 c1
= enc
.encrypt(m
[57:189])
377 me
.assertEqual(enc
.mlen
, 189)
378 me
.assertTrue(132 - aecls
.bufsz
<= len(c1
) <=
379 132 + aecls
.bufsz
+ aecls
.ohd
)
380 c2
= enc
.encrypt(m
[189:253])
381 me
.assertEqual(enc
.mlen
, 253)
382 me
.assertTrue(64 - aecls
.bufsz
<= len(c2
) <=
383 64 + aecls
.bufsz
+ aecls
.ohd
)
384 c3
, t
= enc
.done(aad
= aad
)
385 me
.assertTrue(len(c3
) <= aecls
.bufsz
+ aecls
.ohd
)
386 c
= c0
+ c1
+ c2
+ c3
387 me
.assertTrue(len(m
) <= len(c
) <= len(m
) + aecls
.ohd
)
388 me
.assertEqual(len(t
), tsz
)
390 ## And now decrypt it again, with different record boundaries.
391 dec
= key
.dec(nonce
= n
, hsz
= len(h
), csz
= len(c
), tsz
= tsz
)
392 me
.assertEqual(dec
.hsz
, len(h
))
393 me
.assertEqual(dec
.csz
, len(c
))
394 me
.assertEqual(dec
.clen
, 0)
395 me
.assertEqual(dec
.tsz
, tsz
)
397 if aecls
.flags
&C
.AEADF_AADNDEP
: me
.assertEqual(aad
.hsz
, len(h
))
398 else: me
.assertEqual(aad
.hsz
, None)
399 me
.assertEqual(aad
.hlen
, 0)
401 m0
= dec
.decrypt(c
[0:156])
402 me
.assertTrue(156 - aecls
.bufsz
<= len(m0
) <= 156)
403 m1
= dec
.decrypt(c
[156:])
404 me
.assertTrue(len(c
) - 156 - aecls
.bufsz
<= len(m1
) <=
405 len(c
) - 156 + aecls
.bufsz
)
406 m2
= dec
.done(tag
= t
, aad
= aad
)
407 me
.assertEqual(m0
+ m1
+ m2
, m
)
409 ## And again, with the wrong tag.
410 dec
= key
.dec(nonce
= n
, hsz
= len(h
), csz
= len(c
), tsz
= tsz
)
411 aad
= dec
.aad(); aad
.hash(h
)
413 me
.assertRaises(ValueError, dec
.done
, tag
= t ^ tsz
*C
.bytes("55"))
415 ## Check that the all-in-one methods work.
416 me
.assertEqual((c
, t
),
417 key
.encrypt(n
= n
, h
= h
, m
= m
, tsz
= tsz
))
419 key
.decrypt(n
= n
, h
= h
, c
= c
, t
= t
))
421 ## Check that bad key, nonce, and tag lengths are rejected.
422 badlen
= bad_key_size(aecls
.keysz
)
423 if badlen
is not None: me
.assertRaises(ValueError, aecls
, T
.span(badlen
))
424 badlen
= bad_key_size(aecls
.noncesz
)
425 if badlen
is not None:
426 me
.assertRaises(ValueError, key
.enc
, nonce
= T
.span(badlen
),
427 hsz
= len(h
), msz
= len(m
), tsz
= tsz
)
428 me
.assertRaises(ValueError, key
.dec
, nonce
= T
.span(badlen
),
429 hsz
= len(h
), csz
= len(c
), tsz
= tsz
)
430 if not aecls
.flags
&C
.AEADF_PCTSZ
:
431 enc
= key
.enc(nonce
= n
, hsz
= 0, msz
= len(m
))
433 me
.assertRaises(ValueError, enc
.done
, tsz
= badlen
)
434 badlen
= bad_key_size(aecls
.tagsz
)
435 if badlen
is not None:
436 me
.assertRaises(ValueError, key
.enc
, nonce
= n
,
437 hsz
= len(h
), msz
= len(m
), tsz
= badlen
)
438 me
.assertRaises(ValueError, key
.dec
, nonce
= n
,
439 hsz
= len(h
), csz
= len(c
), tsz
= badlen
)
441 ## Check that we can't get a loose `aad' object from a scheme which has
442 ## nonce-dependent AAD processing.
443 if aecls
.flags
&C
.AEADF_AADNDEP
: me
.assertRaises(ValueError, key
.aad
)
445 ## Check the menagerie of AAD hashing methods.
446 if not aecls
.flags
&C
.AEADF_NOAAD
:
448 enc
= key
.enc(nonce
= n
, hsz
= hsz
, msz
= 0, tsz
= tsz
)
450 return aad
, lambda: enc
.done(aad
= aad
)[1]
451 me
.check_hashbuffer(mkhash
)
453 ## Check that encryption/decryption works with the given precommitments.
454 def quick_enc_check(**kw
):
456 aad
= enc
.aad().hash(h
)
457 c0
= enc
.encrypt(m
); c1
, tt
= enc
.done(aad
= aad
, tsz
= tsz
)
458 me
.assertEqual((c
, t
), (c0
+ c1
, tt
))
459 def quick_dec_check(**kw
):
461 aad
= dec
.aad().hash(h
)
462 m0
= dec
.decrypt(c
); m1
= dec
.done(aad
= aad
, tag
= t
)
463 me
.assertEqual(m
, m0
+ m1
)
465 ## Check that we can get away without precommitting to the header length
466 ## if and only if the AEAD scheme says it will let us.
467 if aecls
.flags
&C
.AEADF_PCHSZ
:
468 me
.assertRaises(ValueError, key
.enc
, nonce
= n
,
469 msz
= len(m
), tsz
= tsz
)
470 me
.assertRaises(ValueError, key
.dec
, nonce
= n
,
471 csz
= len(c
), tsz
= tsz
)
473 quick_enc_check(nonce
= n
, msz
= len(m
), tsz
= tsz
)
474 quick_dec_check(nonce
= n
, csz
= len(c
), tsz
= tsz
)
476 ## Check that we can get away without precommitting to the message/
477 ## ciphertext length if and only if the AEAD scheme says it will let us.
478 if aecls
.flags
&C
.AEADF_PCMSZ
:
479 me
.assertRaises(ValueError, key
.enc
, nonce
= n
,
480 hsz
= len(h
), tsz
= tsz
)
481 me
.assertRaises(ValueError, key
.dec
, nonce
= n
,
482 hsz
= len(h
), tsz
= tsz
)
484 quick_enc_check(nonce
= n
, hsz
= len(h
), tsz
= tsz
)
485 quick_dec_check(nonce
= n
, hsz
= len(h
), tsz
= tsz
)
487 ## Check that we can get away without precommitting to the tag length if
488 ## and only if the AEAD scheme says it will let us.
489 if aecls
.flags
&C
.AEADF_PCTSZ
:
490 me
.assertRaises(ValueError, key
.enc
, nonce
= n
,
491 hsz
= len(h
), msz
= len(m
))
492 me
.assertRaises(ValueError, key
.dec
, nonce
= n
,
493 hsz
= len(h
), csz
= len(c
))
495 quick_enc_check(nonce
= n
, hsz
= len(h
), msz
= len(m
))
496 quick_dec_check(nonce
= n
, hsz
= len(h
), csz
= len(c
))
498 ## Check that if we precommit to the header length, we're properly held
499 ## to the commitment.
500 if not aecls
.flags
&C
.AEADF_NOAAD
:
502 ## First, check encryption with underrun. If we must supply AAD first,
503 ## then the underrun will be reported when we start trying to encrypt;
504 ## otherwise, checking is delayed until `done'.
505 enc
= key
.enc(nonce
= n
, hsz
= len(h
), msz
= len(m
), tsz
= tsz
)
506 aad
= enc
.aad().hash(h
[0:83])
507 if aecls
.flags
&C
.AEADF_AADFIRST
:
508 me
.assertRaises(ValueError, enc
.encrypt
, m
)
511 me
.assertRaises(ValueError, enc
.done
, aad
= aad
)
513 ## Next, check decryption with underrun. If we must supply AAD first,
514 ## then the underrun will be reported when we start trying to encrypt;
515 ## otherwise, checking is delayed until `done'.
516 dec
= key
.dec(nonce
= n
, hsz
= len(h
), csz
= len(c
), tsz
= tsz
)
517 aad
= dec
.aad().hash(h
[0:83])
518 if aecls
.flags
&C
.AEADF_AADFIRST
:
519 me
.assertRaises(ValueError, dec
.decrypt
, c
)
522 me
.assertRaises(ValueError, dec
.done
, tag
= t
, aad
= aad
)
524 ## If AAD processing is nonce-dependent then an overrun will be
525 ## detected imediately.
526 if aecls
.flags
&C
.AEADF_AADNDEP
:
527 enc
= key
.enc(nonce
= n
, hsz
= len(h
), msz
= len(m
), tsz
= tsz
)
528 aad
= enc
.aad().hash(h
[0:83])
529 me
.assertRaises(ValueError, aad
.hash, h
[82:131])
530 dec
= key
.dec(nonce
= n
, hsz
= len(h
), csz
= len(c
), tsz
= tsz
)
531 aad
= dec
.aad().hash(h
[0:83])
532 me
.assertRaises(ValueError, aad
.hash, h
[82:131])
534 ## Some additional tests for nonce-dependent `aad' objects.
535 if aecls
.flags
&C
.AEADF_AADNDEP
:
537 ## Check that `aad' objects can't be used once their parents are gone.
538 enc
= key
.enc(nonce
= n
, hsz
= len(h
), msz
= len(m
), tsz
= tsz
)
541 me
.assertRaises(ValueError, aad
.hash, h
)
543 ## Check that they can't be crossed over.
544 enc0
= key
.enc(nonce
= n
, hsz
= len(h
), msz
= len(m
), tsz
= tsz
)
545 enc1
= key
.enc(nonce
= n
, hsz
= len(h
), msz
= len(m
), tsz
= tsz
)
547 aad1
= enc1
.aad().hash(h
)
549 me
.assertRaises(ValueError, enc0
.done
, tsz
= tsz
, aad
= aad1
)
552 if not aecls
.flags
&C
.AEADF_AADNDEP
and not aecls
.flags
&C
.AEADF_NOAAD
:
559 aad2
.hash(h
[83:131] ^
48*C
.bytes("ff"))
560 me
.assertEqual(key
.enc(nonce
= n
, hsz
= len(h
),
561 msz
= 0, tsz
= tsz
).done(aad
= aad0
),
562 key
.enc(nonce
= n
, hsz
= len(h
),
563 msz
= 0, tsz
= tsz
).done(aad
= aad1
))
564 me
.assertNotEqual(key
.enc(nonce
= n
, hsz
= len(h
),
565 msz
= 0, tsz
= tsz
).done(aad
= aad0
),
566 key
.enc(nonce
= n
, hsz
= len(h
),
567 msz
= 0, tsz
= tsz
).done(aad
= aad2
))
569 ## Check that if we precommit to the message length, we're properly held
570 ## to the commitment. (Fortunately, this is way simpler than the AAD
571 ## case above.) First, try an underrun.
572 enc
= key
.enc(nonce
= n
, hsz
= 0, msz
= len(m
), tsz
= tsz
)
573 _
= enc
.encrypt(m
[0:183])
574 me
.assertRaises(ValueError, enc
.done
, tsz
= tsz
)
575 dec
= key
.dec(nonce
= n
, hsz
= 0, csz
= len(c
), tsz
= tsz
)
576 _
= dec
.decrypt(c
[0:183])
577 me
.assertRaises(ValueError, dec
.done
, tag
= t
)
579 ## And now an overrun.
580 enc
= key
.enc(nonce
= n
, hsz
= 0, msz
= 183, tsz
= tsz
)
581 me
.assertRaises(ValueError, enc
.encrypt
, m
)
582 dec
= key
.dec(nonce
= n
, hsz
= 0, csz
= 183, tsz
= tsz
)
583 me
.assertRaises(ValueError, dec
.decrypt
, c
)
585 ## Finally, check that if we precommit to a tag length, we're properly
586 ## held to the commitment. This depends on being able to find a tag size
587 ## which isn't the default.
588 tsz1
= different_key_size(aecls
.tagsz
, tsz
)
590 enc
= key
.enc(nonce
= n
, hsz
= 0, msz
= len(m
), tsz
= tsz1
)
592 me
.assertRaises(ValueError, enc
.done
, tsz
= tsz
)
593 dec
= key
.dec(nonce
= n
, hsz
= len(h
), csz
= len(c
), tsz
= tsz1
)
594 aad
= dec
.aad().hash(h
)
596 me
.assertRaises(ValueError, enc
.done
, tsz
= tsz
, aad
= aad
)
598 TestAuthenticatedEncryption
.generate_testcases \
599 ((name
, C
.gcaeads
[name
]) for name
in
600 ["des3-ccm", "blowfish-ocb1", "square-ocb3", "rijndael-gcm",
601 "serpent-eax", "salsa20-naclbox", "chacha20-poly1305"])
603 ###--------------------------------------------------------------------------
604 class BaseTestHash (HashBufferTestMixin
):
605 """Base class for testing hash functions."""
607 def check_hash(me
, hcls
, need_bufsz
= True):
609 Check hash class HCLS.
611 If NEED_BUFSZ is false, then don't insist that HCLS has a working `bufsz'
612 attribute. This test is mostly reused for MACs, which don't have this
615 ## Check the class properties.
616 me
.assertEqual(type(hcls
.name
), str)
617 if need_bufsz
: me
.assertEqual(type(hcls
.bufsz
), int)
618 me
.assertEqual(type(hcls
.hashsz
), int)
620 ## Set some initial values.
622 h
= hcls().hash(m
).done()
624 ## Check that hash length comes out right.
625 me
.assertEqual(len(h
), hcls
.hashsz
)
627 ## Check that we get the same answer if we split the message up.
628 me
.assertEqual(h
, hcls().hash(m
[0:73]).hash(m
[73:131]).done())
630 ## Check the `check' method.
631 me
.assertTrue(hcls().hash(m
).check(h
))
632 me
.assertFalse(hcls().hash(m
).check(h ^ hcls
.hashsz
*C
.bytes("aa")))
634 ## Check the menagerie of random hashing methods.
638 me
.check_hashbuffer(mkhash
)
640 class TestHash (BaseTestHash
, T
.GenericTestMixin
):
641 """Test hash functions."""
642 def _test_hash(me
, hcls
): me
.check_hash(hcls
, need_bufsz
= True)
644 TestHash
.generate_testcases((name
, C
.gchashes
[name
]) for name
in
645 ["md5", "sha", "whirlpool", "sha256", "sha512/224", "sha3-384", "shake256",
648 ###--------------------------------------------------------------------------
649 class TestMessageAuthentication (BaseTestHash
, T
.GenericTestMixin
):
650 """Test message authentication codes."""
652 def _test_mac(me
, mcls
):
654 ## Check the MAC properties.
655 me
.assertEqual(type(mcls
.name
), str)
656 me
.assertTrue(isinstance(mcls
.keysz
, C
.KeySZ
))
657 me
.assertEqual(type(mcls
.tagsz
), int)
660 k
= T
.span(mcls
.keysz
.default
)
662 me
.assertEqual(key
.hashsz
, key
.tagsz
)
663 me
.check_hash(key
, need_bufsz
= False)
665 ## Check that bad key lengths are rejected.
666 badlen
= bad_key_size(mcls
.keysz
)
667 if badlen
is not None: me
.assertRaises(ValueError, mcls
, T
.span(badlen
))
669 TestMessageAuthentication
.generate_testcases \
670 ((name
, C
.gcmacs
[name
]) for name
in
671 ["sha-hmac", "rijndael-cmac", "twofish-pmac1", "kmac128"])
673 class TestPoly1305 (HashBufferTestMixin
):
674 """Check the Poly1305 one-time message authentication function."""
676 def test_poly1305(me
):
678 ## Check the MAC properties.
679 me
.assertEqual(C
.poly1305
.name
, "poly1305")
680 me
.assertEqual(type(C
.poly1305
.keysz
), C
.KeySZSet
)
681 me
.assertEqual(C
.poly1305
.keysz
.default
, 16)
682 me
.assertEqual(C
.poly1305
.keysz
.set, set([16]))
683 me
.assertEqual(C
.poly1305
.tagsz
, 16)
684 me
.assertEqual(C
.poly1305
.masksz
, 16)
686 ## Set some initial values.
691 t
= key(u
).hash(m
).done()
693 ## Check the key properties.
694 me
.assertEqual(key
.name
, "poly1305")
695 me
.assertEqual(key
.tagsz
, 16)
696 me
.assertEqual(key
.tagsz
, 16)
697 me
.assertEqual(len(t
), 16)
699 ## Check that we get the same answer if we split the message up.
700 me
.assertEqual(t
, key(u
).hash(m
[0:86]).hash(m
[86:149]).done())
702 ## Check the `check' method.
703 me
.assertTrue(key(u
).hash(m
).check(t
))
704 me
.assertFalse(key(u
).hash(m
).check(t ^
16*C
.bytes("cc")))
706 ## Check the menagerie of random hashing methods.
710 me
.check_hashbuffer(mkhash
)
712 ## Check that we can't complete hashing without a mask.
713 me
.assertRaises(ValueError, key().hash(m
).done
)
716 h0
= key().hash(m
[0:96])
717 h1
= key().hash(m
[96:117])
718 me
.assertEqual(t
, key(u
).concat(h0
, h1
).hash(m
[117:149]).done())
720 me
.assertRaises(TypeError, key().concat
, key1().hash(m
[0:96]), h1
)
721 me
.assertRaises(TypeError, key().concat
, h0
, key1().hash(m
[96:117]))
722 me
.assertRaises(ValueError, key().concat
, key().hash(m
[0:93]), h1
)
724 ###--------------------------------------------------------------------------
725 class TestHLatin (U
.TestCase
):
726 """Test the `hsalsa20' and `hchacha20' functions."""
729 kk
= [T
.span(sz
) for sz
in [10, 16, 32]]
733 for fn
in [C
.hsalsa208_prf
, C
.hsalsa2012_prf
, C
.hsalsa20_prf
,
734 C
.hchacha8_prf
, C
.hchacha12_prf
, C
.hchacha20_prf
]:
737 me
.assertEqual(len(h
), 32)
738 me
.assertRaises(ValueError, fn
, bad_k
, n
)
739 me
.assertRaises(ValueError, fn
, k
, bad_n
)
741 ###--------------------------------------------------------------------------
742 class TestKeccak (HashBufferTestMixin
):
743 """Test the Keccak-p[1600, n] sponge function."""
747 ## Make a state and feed some stuff into it.
748 m0
= T
.bin("some initial string")
749 m1
= T
.bin("awesome follow-up string")
751 me
.assertEqual(st0
.nround
, 24)
754 ## Make another step with a different round count.
755 st1
= C
.Keccak1600(23)
757 me
.assertNotEqual(st0
.extract(32), st1
.extract(32))
759 ## Check state copying and `mix' vs `set'.
761 mask
= st1
.extract(len(m1
))
764 me
.assertEqual(st0
.extract(32), st1
.extract(32))
766 ## Check error conditions.
768 me
.assertRaises(ValueError, st0
.extract
, 201)
770 me
.assertRaises(ValueError, st0
.mix
, T
.span(201))
772 me
.assertRaises(ValueError, st0
.set, T
.span(201))
773 me
.assertRaises(ValueError, st0
.set, T
.span(199))
775 def check_shake(me
, xcls
, c
, done_matches_xof
= True):
777 Test the SHAKE and cSHAKE XOFs.
779 This is also used for testing KMAC, but that sets DONE_MATCHES_XOF false
780 to indicate that the XOF output is range-separated from the fixed-length
781 outputs (unlike the basic SHAKE functions).
784 ## Check the hash attributes.
786 me
.assertEqual(x
.rate
, 200 - c
)
787 me
.assertEqual(x
.buffered
, 0)
788 me
.assertEqual(x
.state
, "absorb")
790 ## Set some initial values.
791 func
= T
.bin("TESTXOF")
792 perso
= T
.bin("catacomb-python test")
794 h0
= xcls().hash(m
).done(193)
795 me
.assertEqual(len(h0
), 193)
796 h1
= xcls(func
= func
, perso
= perso
).hash(m
).done(193)
797 me
.assertEqual(len(h1
), 193)
798 me
.assertNotEqual(h0
, h1
)
800 ## Check input and output in pieces, and the state machine.
801 if done_matches_xof
: h
= h0
802 else: h
= xcls().hash(m
).xof().get(len(h0
))
803 x
= xcls().hash(m
[0:76]).hash(m
[76:167]).xof()
804 me
.assertEqual(h
, x
.get(98) + x
.get(95))
807 x
= xcls().hash(m
).xof()
808 me
.assertEqual(x
.mask(m
), m ^ h
[0:len(m
)])
810 ## Check the `check' method.
811 me
.assertTrue(xcls().hash(m
).check(h0
))
812 me
.assertFalse(xcls().hash(m
).check(h1
))
814 ## Check the menagerie of random hashing methods.
816 x
= xcls(func
= func
, perso
= perso
)
818 me
.check_hashbuffer(mkhash
)
820 ## Check the state machine tracking.
821 x
= xcls(); me
.assertEqual(x
.state
, "absorb")
822 x
.hash(m
); me
.assertEqual(x
.state
, "absorb")
824 h
= xx
.done(); me
.assertEqual(len(h
), 100 - x
.rate
//2)
825 me
.assertEqual(xx
.state
, "dead")
826 me
.assertRaises(ValueError, xx
.done
, 1)
827 me
.assertRaises(ValueError, xx
.get
, 1)
828 me
.assertEqual(x
.state
, "absorb")
829 me
.assertRaises(ValueError, x
.get
, 1)
830 x
.xof(); me
.assertEqual(x
.state
, "squeeze")
831 me
.assertRaises(ValueError, x
.done
, 1)
833 yy
= x
.copy(); me
.assertEqual(yy
.state
, "squeeze")
835 def test_shake128(me
): me
.check_shake(C
.Shake128
, 32)
836 def test_shake256(me
): me
.check_shake(C
.Shake256
, 64)
838 def check_kmac(me
, mcls
, c
):
840 me
.check_shake(lambda func
= None, perso
= None:
841 mcls(k
, perso
= perso
),
842 c
, done_matches_xof
= False)
844 def test_kmac128(me
): me
.check_kmac(C
.KMAC128
, 32)
845 def test_kmac256(me
): me
.check_kmac(C
.KMAC256
, 64)
847 ###--------------------------------------------------------------------------
848 class TestStrobe (HashBufferTestMixin
):
857 me
.assertEqual(s0
.l
, 128)
858 me
.assertEqual(s1
.l
, 128)
860 me
.assertRaises(ValueError, C
.Strobe
, 127)
861 me
.assertRaises(ValueError, C
.Strobe
, 736)
862 me
.assertEqual(s0
.role
, C
.STRBRL_UNDCD
)
863 me
.assertEqual(s1
.role
, C
.STRBRL_UNDCD
)
865 ## `process' vs operation-specific functions. (This follows Hamburg's
866 ## `Concurrence' test.)
868 s0
.ad(h
, f
= "M"); s1
.begin(C
.STROBE_AD | C
.STRBF_M
).process(h
).done()
870 t
= s1
.begin(C
.STRBF_I | C
.STRBF_A | C
.STRBF_C
).process(10); s1
.done()
871 me
.assertEqual(s0
.prf(10), t
)
872 me
.assertEqual(t
, C
.bytes("8a13a189683bf5678170"))
875 s0
.ad(h
); s1
.begin(" A ").process(h
).done()
877 m
= T
.bin("World"); c
= s0
.encout(m
)
878 me
.assertFalse(s1
.activep
)
879 m1
= s1
.begin("IACT ").process(c
); me
.assertTrue(s1
.activep
);
880 s1
.done(); me
.assertFalse(s1
.activep
)
881 me
.assertEqual(c
, C
.bytes("123bfbee34"))
882 me
.assertEqual(m1
, m
)
883 me
.assertEqual(s0
.role
, C
.STRBRL_INIT
)
884 me
.assertEqual(s1
.role
, C
.STRBRL_RESP
)
886 m
= T
.bin("foo"); s0
.clrout(m
); s1
.begin("IA T ").process(m
).done()
887 m
= T
.bin("bar"); s0
.clrin(m
); s1
.begin(" A T ").process(m
).done()
889 c
= T
.bin("baz"); m
= s0
.encin(c
)
890 c1
= s1
.begin(" ACT ").process(m
); s1
.done()
891 me
.assertEqual(m
, C
.bytes("15e518"))
892 me
.assertEqual(c1
, c
)
895 for i
in T
.range(200):
896 c
= s0
.begin(" ACT ").process(xxx
[:i
]); s0
.done(); s1
.encin(c
)
898 t
= s1
.begin("IAC ").process(123); s1
.done()
899 me
.assertEqual(t
, C
.bytes
900 ("45476fc0806aee35e864c4f18e6ba62bd3eb1b1e8bef9042b30b0f15d00c3e9f"
901 "5d5904ab789d4c67eaed582473c15aa4424f11d52b21a296b36db3392e2ecbb2"
902 "dc6963bafba3b23882d061f1d335e86e470e8d819591bf0c223e24b925751d04"
903 "f789fc73bc55f7d2b3ed4881c625aa6321d31511b13f6d5e4ce54a"))
904 me
.assertEqual(s0
.prf(123), t
)
909 me
.assertEqual(t
, C
.bytes("171419608e11e7c907d493209e17f26b"))
910 me
.assertEqual(s2
.begin(" CT ").process(16), t
); s2
.done()
911 s3
= s1
.copy(); me
.assertFalse(s3
.macin(~t
))
912 s3
= s1
.copy(); me
.assertTrue(s3
.macin(t
))
913 s3
= s1
.copy(); me
.assertFalse(s3
.begin("I CT ").process(~t
).done())
914 me
.assertTrue(s1
.begin("I CT ").process(t
).done())
916 ## Test the remaining operations. (From the Catacomb test vectors.)
917 k
= T
.bin("this is my super-secret key")
918 s0
.key(k
); s1
.begin(" AC ").process(k
).done()
920 t
= s1
.begin(C
.STROBE_PRF
).process(32); s1
.done()
921 me
.assertEqual(t
, C
.bytes
922 ("5418e0f0ee7f982bbbdc2b4bbf49425d0088abfa98ee21d8ad8a3610d15ebb68"))
923 me
.assertEqual(s0
.prf(32), t
)
925 s0
.ratchet(32); s1
.begin("C").process(32).done()
927 t
= s1
.begin(" CT ").process(16); s1
.done()
928 me
.assertEqual(t
, C
.bytes("b2084ebdfabd50768c91eebc190132cc"))
929 me
.assertTrue(s0
.macin(t
))
931 def test_hashbuffer(me
):
933 s
= C
.Strobe(256).begin(C
.STROBE_AD
)
934 return s
, lambda: s
.done().macout(16)
935 me
.check_hashbuffer(mkhash
)
937 ###--------------------------------------------------------------------------
938 class TestPRP (T
.GenericTestMixin
):
939 """Test pseudorandom permutations (PRPs)."""
941 def _test_prp(me
, pcls
):
943 ## Check the PRP properties.
944 me
.assertEqual(type(pcls
.name
), str)
945 me
.assertTrue(isinstance(pcls
.keysz
, C
.KeySZ
))
946 me
.assertEqual(type(pcls
.blksz
), int)
948 ## Check round-tripping.
949 k
= T
.span(pcls
.keysz
.default
)
951 m
= T
.span(pcls
.blksz
)
953 me
.assertEqual(len(c
), pcls
.blksz
)
954 me
.assertEqual(m
, key
.decrypt(c
))
956 ## Check that bad key lengths are rejected.
957 badlen
= bad_key_size(pcls
.keysz
)
958 if badlen
is not None: me
.assertRaises(ValueError, pcls
, T
.span(badlen
))
960 ## Check that bad blocks are rejected.
961 badblk
= T
.span(pcls
.blksz
+ 1)
962 me
.assertRaises(ValueError, key
.encrypt
, badblk
)
963 me
.assertRaises(ValueError, key
.decrypt
, badblk
)
965 TestPRP
.generate_testcases((name
, C
.gcprps
[name
]) for name
in
966 ["desx", "blowfish", "rijndael"])
968 ###----- That's all, folks --------------------------------------------------
970 if __name__
== "__main__": U
.main()