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."""
67 def check_hashbuffer_hashn(me
, w
, bigendp
, makefn
, hashfn
):
70 ## Check encoding an integer.
71 h0
, donefn0
= makefn(w
+ 2)
72 hashfn(h0
.hashu8(0x00), T
.bytes_as_int(w
, bigendp
)).hashu8(w
+ 1)
73 h1
, donefn1
= makefn(w
+ 2)
74 h1
.hash(T
.span(w
+ 2))
75 me
.assertEqual(donefn0(), donefn1())
77 ## Check overflow detection.
79 me
.assertRaises((OverflowError, ValueError),
82 def check_hashbuffer_bufn(me
, w
, bigendp
, makefn
, hashfn
):
83 """Check `hashbufN'."""
85 ## Go through a number of different sizes.
86 for n
in [0, 1, 7, 8, 19, 255, 12345, 65535, 123456]:
87 if n
>= 1 << 8*w
: continue
88 h0
, donefn0
= makefn(2 + w
+ n
)
89 hashfn(h0
.hashu8(0x00), T
.span(n
)).hashu8(0xff)
90 h1
, donefn1
= makefn(2 + w
+ n
)
91 h1
.hash(T
.prep_lenseq(w
, n
, bigendp
, True))
92 me
.assertEqual(donefn0(), donefn1())
94 ## Check blocks which are too large for the length prefix.
98 me
.assertRaises(ValueError, hashfn
, h0
, C
.ByteString
.zero(n
))
100 def check_hashbuffer(me
, makefn
):
101 """Test the various `hash...' methods."""
104 me
.check_hashbuffer_hashn(1, True, makefn
, lambda h
, n
: h
.hashu8(n
))
105 me
.check_hashbuffer_hashn(2, True, makefn
, lambda h
, n
: h
.hashu16(n
))
106 me
.check_hashbuffer_hashn(2, True, makefn
, lambda h
, n
: h
.hashu16b(n
))
107 me
.check_hashbuffer_hashn(2, False, makefn
, lambda h
, n
: h
.hashu16l(n
))
108 me
.check_hashbuffer_hashn(3, True, makefn
, lambda h
, n
: h
.hashu24(n
))
109 me
.check_hashbuffer_hashn(3, True, makefn
, lambda h
, n
: h
.hashu24b(n
))
110 me
.check_hashbuffer_hashn(3, False, makefn
, lambda h
, n
: h
.hashu24l(n
))
111 me
.check_hashbuffer_hashn(4, True, makefn
, lambda h
, n
: h
.hashu32(n
))
112 me
.check_hashbuffer_hashn(4, True, makefn
, lambda h
, n
: h
.hashu32b(n
))
113 me
.check_hashbuffer_hashn(4, False, makefn
, lambda h
, n
: h
.hashu32l(n
))
114 if hasattr(makefn(0)[0], "hashu64"):
115 me
.check_hashbuffer_hashn(8, True, makefn
, lambda h
, n
: h
.hashu64(n
))
116 me
.check_hashbuffer_hashn(8, True, makefn
, lambda h
, n
: h
.hashu64b(n
))
117 me
.check_hashbuffer_hashn(8, False, makefn
, lambda h
, n
: h
.hashu64l(n
))
120 me
.check_hashbuffer_bufn(1, True, makefn
, lambda h
, x
: h
.hashbuf8(x
))
121 me
.check_hashbuffer_bufn(2, True, makefn
, lambda h
, x
: h
.hashbuf16(x
))
122 me
.check_hashbuffer_bufn(2, True, makefn
, lambda h
, x
: h
.hashbuf16b(x
))
123 me
.check_hashbuffer_bufn(2, False, makefn
, lambda h
, x
: h
.hashbuf16l(x
))
124 me
.check_hashbuffer_bufn(3, True, makefn
, lambda h
, x
: h
.hashbuf24(x
))
125 me
.check_hashbuffer_bufn(3, True, makefn
, lambda h
, x
: h
.hashbuf24b(x
))
126 me
.check_hashbuffer_bufn(3, False, makefn
, lambda h
, x
: h
.hashbuf24l(x
))
127 me
.check_hashbuffer_bufn(4, True, makefn
, lambda h
, x
: h
.hashbuf32(x
))
128 me
.check_hashbuffer_bufn(4, True, makefn
, lambda h
, x
: h
.hashbuf32b(x
))
129 me
.check_hashbuffer_bufn(4, False, makefn
, lambda h
, x
: h
.hashbuf32l(x
))
130 if hasattr(makefn(0)[0], "hashbuf64"):
131 me
.check_hashbuffer_bufn(8, True, makefn
, lambda h
, x
: h
.hashbuf64(x
))
132 me
.check_hashbuffer_bufn(8, True, makefn
, lambda h
, x
: h
.hashbuf64b(x
))
133 me
.check_hashbuffer_bufn(8, False, makefn
, lambda h
, x
: h
.hashbuf64l(x
))
135 ###--------------------------------------------------------------------------
136 class TestKeysize (U
.TestCase
):
140 ## A typical one-byte spec.
142 me
.assertEqual(type(ksz
), C
.KeySZAny
)
143 me
.assertEqual(ksz
.default
, 20)
144 me
.assertEqual(ksz
.min, 0)
145 me
.assertEqual(ksz
.max, None)
146 for n
in [0, 12, 20, 5000]:
147 me
.assertTrue(ksz
.check(n
))
148 me
.assertEqual(ksz
.best(n
), n
)
149 me
.assertEqual(ksz
.pad(n
), n
)
151 ## A typical two-byte spec. (No published algorithms actually /need/ a
152 ## two-byte key-size spec, but all of the HMAC variants use one anyway.)
153 ksz
= C
.sha256_hmac
.keysz
154 me
.assertEqual(type(ksz
), C
.KeySZAny
)
155 me
.assertEqual(ksz
.default
, 32)
156 me
.assertEqual(ksz
.min, 0)
157 me
.assertEqual(ksz
.max, None)
158 for n
in [0, 12, 20, 5000]:
159 me
.assertTrue(ksz
.check(n
))
160 me
.assertEqual(ksz
.best(n
), n
)
161 me
.assertEqual(ksz
.pad(n
), n
)
163 ## Check construction.
165 me
.assertEqual(ksz
.default
, 15)
166 me
.assertEqual(ksz
.min, 0)
167 me
.assertEqual(ksz
.max, None)
168 me
.assertRaises(ValueError, lambda: C
.KeySZAny(-8))
169 me
.assertEqual(C
.KeySZAny(0).default
, 0)
172 ## Note that no published algorithm uses a 16-bit `set' spec.
175 ksz
= C
.salsa20
.keysz
176 me
.assertEqual(type(ksz
), C
.KeySZSet
)
177 me
.assertEqual(ksz
.default
, 32)
178 me
.assertEqual(ksz
.min, 10)
179 me
.assertEqual(ksz
.max, 32)
180 me
.assertEqual(ksz
.set, set([10, 16, 32]))
181 for x
, best
, pad
in [(9, None, 10), (10, 10, 10), (11, 10, 16),
182 (15, 10, 16), (16, 16, 16), (17, 16, 32),
183 (31, 16, 32), (32, 32, 32), (33, 32, None)]:
184 if x
== best
== pad
: me
.assertTrue(ksz
.check(x
))
185 else: me
.assertFalse(ksz
.check(x
))
186 if best
is None: me
.assertRaises(ValueError, ksz
.best
, x
)
187 else: me
.assertEqual(ksz
.best(x
), best
)
188 if pad
is None: me
.assertRaises(ValueError, ksz
.pad
, x
)
189 else: me
.assertEqual(ksz
.pad(x
), pad
)
191 ## Check construction.
193 me
.assertEqual(ksz
.default
, 7)
194 me
.assertEqual(ksz
.set, set([7]))
195 me
.assertEqual(ksz
.min, 7)
196 me
.assertEqual(ksz
.max, 7)
197 ksz
= C
.KeySZSet(7, iter([3, 6, 9]))
198 me
.assertEqual(ksz
.default
, 7)
199 me
.assertEqual(ksz
.set, set([3, 6, 7, 9]))
200 me
.assertEqual(ksz
.min, 3)
201 me
.assertEqual(ksz
.max, 9)
204 ## Note that no published algorithm uses a 16-bit `range' spec, or an
205 ## unbounded `range'.
208 ksz
= C
.rijndael
.keysz
209 me
.assertEqual(type(ksz
), C
.KeySZRange
)
210 me
.assertEqual(ksz
.default
, 32)
211 me
.assertEqual(ksz
.min, 4)
212 me
.assertEqual(ksz
.max, 32)
213 me
.assertEqual(ksz
.mod
, 4)
214 for x
, best
, pad
in [(3, None, 4), (4, 4, 4), (5, 4, 8),
215 (15, 12, 16), (16, 16, 16), (17, 16, 20),
216 (31, 28, 32), (32, 32, 32), (33, 32, None)]:
217 if x
== best
== pad
: me
.assertTrue(ksz
.check(x
))
218 else: me
.assertFalse(ksz
.check(x
))
219 if best
is None: me
.assertRaises(ValueError, ksz
.best
, x
)
220 else: me
.assertEqual(ksz
.best(x
), best
)
221 if pad
is None: me
.assertRaises(ValueError, ksz
.pad
, x
)
222 else: me
.assertEqual(ksz
.pad(x
), pad
)
224 ## Check construction.
225 ksz
= C
.KeySZRange(28, 21, 35, 7)
226 me
.assertEqual(ksz
.default
, 28)
227 me
.assertEqual(ksz
.min, 21)
228 me
.assertEqual(ksz
.max, 35)
229 me
.assertEqual(ksz
.mod
, 7)
230 ksz
= C
.KeySZRange(28, 21, None, 7)
231 me
.assertEqual(ksz
.min, 21)
232 me
.assertEqual(ksz
.max, None)
233 me
.assertEqual(ksz
.mod
, 7)
234 me
.assertEqual(ksz
.pad(36), 42)
235 me
.assertRaises(ValueError, C
.KeySZRange
, 29, 21, 35, 7)
236 me
.assertRaises(ValueError, C
.KeySZRange
, 28, 20, 35, 7)
237 me
.assertRaises(ValueError, C
.KeySZRange
, 28, 21, 34, 7)
238 me
.assertRaises(ValueError, C
.KeySZRange
, 28, -7, 35, 7)
239 me
.assertRaises(ValueError, C
.KeySZRange
, 28, 35, 21, 7)
240 me
.assertRaises(ValueError, C
.KeySZRange
, 35, 21, 28, 7)
241 me
.assertRaises(ValueError, C
.KeySZRange
, 21, 28, 35, 7)
243 def test_conversions(me
):
244 me
.assertEqual(C
.KeySZ
.fromec(256), 128)
245 me
.assertEqual(C
.KeySZ
.fromschnorr(256), 128)
246 me
.assertEqual(round(C
.KeySZ
.fromdl(2958.6875)), 128)
247 me
.assertEqual(round(C
.KeySZ
.fromif(2958.6875)), 128)
248 me
.assertEqual(C
.KeySZ
.toec(128), 256)
249 me
.assertEqual(C
.KeySZ
.toschnorr(128), 256)
250 me
.assertEqual(C
.KeySZ
.todl(128), 2958.6875)
251 me
.assertEqual(C
.KeySZ
.toif(128), 2958.6875)
253 ###--------------------------------------------------------------------------
254 class TestCipher (T
.GenericTestMixin
):
255 """Test basic symmetric ciphers."""
257 def _test_cipher(me
, ccls
):
259 ## Check the class properties.
260 me
.assertEqual(type(ccls
.name
), str)
261 me
.assertTrue(isinstance(ccls
.keysz
, C
.KeySZ
))
262 me
.assertEqual(type(ccls
.blksz
), int)
264 ## Check round-tripping.
265 k
= T
.span(ccls
.keysz
.default
)
266 iv
= T
.span(ccls
.blksz
)
271 except ValueError: can_setiv
= False
275 c0
= enc
.encrypt(m
[0:57])
277 c1
= enc
.encrypt(m
[57:189])
280 except ValueError: can_bdry
= False
284 c2
= enc
.encrypt(m
[189:253])
286 me
.assertEqual(len(c0
) + len(c1
) + len(c2
), len(m
))
287 me
.assertEqual(m0
, m
[0:57])
288 me
.assertEqual(m1
, m
[57:189])
289 me
.assertEqual(m2
, m
[189:253])
291 ## Check the `enczero' and `deczero' methods.
293 me
.assertEqual(dec
.decrypt(c3
), C
.ByteString
.zero(32))
295 me
.assertEqual(enc
.encrypt(m4
), C
.ByteString
.zero(32))
297 ## Check that ciphers which support a `boundary' operation actually
301 if can_setiv
: dec
.setiv(iv
)
302 m01
= dec
.decrypt(c0
+ c1
)
303 me
.assertEqual(m01
, m
[0:189])
305 ## Check that the boundary actually does something.
308 if can_setiv
: dec
.setiv(iv
)
309 m012
= dec
.decrypt(c0
+ c1
+ c2
)
310 me
.assertNotEqual(m012
, m
)
312 ## Check that bad key lengths are rejected.
313 badlen
= bad_key_size(ccls
.keysz
)
314 if badlen
is not None: me
.assertRaises(ValueError, ccls
, T
.span(badlen
))
316 TestCipher
.generate_testcases((name
, C
.gcciphers
[name
]) for name
in
317 ["des-ecb", "rijndael-cbc", "twofish-cfb", "serpent-ofb",
318 "blowfish-counter", "rc4", "seal", "salsa20/8", "shake128-xof"])
320 ###--------------------------------------------------------------------------
321 class TestAuthenticatedEncryption \
322 (HashBufferTestMixin
, T
.GenericTestMixin
):
323 """Test authenticated encryption schemes."""
325 def _test_aead(me
, aecls
):
327 ## Check the class properties.
328 me
.assertEqual(type(aecls
.name
), str)
329 me
.assertTrue(isinstance(aecls
.keysz
, C
.KeySZ
))
330 me
.assertTrue(isinstance(aecls
.noncesz
, C
.KeySZ
))
331 me
.assertTrue(isinstance(aecls
.tagsz
, C
.KeySZ
))
332 me
.assertEqual(type(aecls
.blksz
), int)
333 me
.assertEqual(type(aecls
.bufsz
), int)
334 me
.assertEqual(type(aecls
.ohd
), int)
335 me
.assertEqual(type(aecls
.flags
), int)
337 ## Check round-tripping, with full precommitment. First, select some
338 ## parameters. (It's conceivable that some AEAD schemes are more
339 ## restrictive than advertised by the various properties, but this works
340 ## out OK in practice.)
341 k
= T
.span(aecls
.keysz
.default
)
342 n
= T
.span(aecls
.noncesz
.default
)
343 if aecls
.flags
&C
.AEADF_NOAAD
: h
= T
.span(0)
344 else: h
= T
.span(131)
346 tsz
= aecls
.tagsz
.default
349 ## Next, encrypt a message, checking that things are proper as we go.
350 enc
= key
.enc(nonce
= n
, hsz
= len(h
), msz
= len(m
), tsz
= tsz
)
351 me
.assertEqual(enc
.hsz
, len(h
))
352 me
.assertEqual(enc
.msz
, len(m
))
353 me
.assertEqual(enc
.mlen
, 0)
354 me
.assertEqual(enc
.tsz
, tsz
)
356 if aecls
.flags
&C
.AEADF_AADNDEP
: me
.assertEqual(aad
.hsz
, len(h
))
357 else: me
.assertEqual(aad
.hsz
, None)
358 me
.assertEqual(aad
.hlen
, 0)
359 if not aecls
.flags
&C
.AEADF_NOAAD
:
361 me
.assertEqual(aad
.hlen
, 83)
363 me
.assertEqual(aad
.hlen
, 131)
364 c0
= enc
.encrypt(m
[0:57])
365 me
.assertEqual(enc
.mlen
, 57)
366 me
.assertTrue(57 - aecls
.bufsz
<= len(c0
) <= 57 + aecls
.ohd
)
367 c1
= enc
.encrypt(m
[57:189])
368 me
.assertEqual(enc
.mlen
, 189)
369 me
.assertTrue(132 - aecls
.bufsz
<= len(c1
) <=
370 132 + aecls
.bufsz
+ aecls
.ohd
)
371 c2
= enc
.encrypt(m
[189:253])
372 me
.assertEqual(enc
.mlen
, 253)
373 me
.assertTrue(64 - aecls
.bufsz
<= len(c2
) <=
374 64 + aecls
.bufsz
+ aecls
.ohd
)
375 c3
, t
= enc
.done(aad
= aad
)
376 me
.assertTrue(len(c3
) <= aecls
.bufsz
+ aecls
.ohd
)
377 c
= c0
+ c1
+ c2
+ c3
378 me
.assertTrue(len(m
) <= len(c
) <= len(m
) + aecls
.ohd
)
379 me
.assertEqual(len(t
), tsz
)
381 ## And now decrypt it again, with different record boundaries.
382 dec
= key
.dec(nonce
= n
, hsz
= len(h
), csz
= len(c
), tsz
= tsz
)
383 me
.assertEqual(dec
.hsz
, len(h
))
384 me
.assertEqual(dec
.csz
, len(c
))
385 me
.assertEqual(dec
.clen
, 0)
386 me
.assertEqual(dec
.tsz
, tsz
)
388 if aecls
.flags
&C
.AEADF_AADNDEP
: me
.assertEqual(aad
.hsz
, len(h
))
389 else: me
.assertEqual(aad
.hsz
, None)
390 me
.assertEqual(aad
.hlen
, 0)
392 m0
= dec
.decrypt(c
[0:156])
393 me
.assertTrue(156 - aecls
.bufsz
<= len(m0
) <= 156)
394 m1
= dec
.decrypt(c
[156:])
395 me
.assertTrue(len(c
) - 156 - aecls
.bufsz
<= len(m1
) <=
396 len(c
) - 156 + aecls
.bufsz
)
397 m2
= dec
.done(tag
= t
, aad
= aad
)
398 me
.assertEqual(m0
+ m1
+ m2
, m
)
400 ## And again, with the wrong tag.
401 dec
= key
.dec(nonce
= n
, hsz
= len(h
), csz
= len(c
), tsz
= tsz
)
402 aad
= dec
.aad(); aad
.hash(h
)
404 me
.assertRaises(ValueError, dec
.done
, tag
= t ^ tsz
*C
.bytes("55"))
406 ## Check that the all-in-one methods work.
407 me
.assertEqual((c
, t
),
408 key
.encrypt(n
= n
, h
= h
, m
= m
, tsz
= tsz
))
410 key
.decrypt(n
= n
, h
= h
, c
= c
, t
= t
))
412 ## Check that bad key, nonce, and tag lengths are rejected.
413 badlen
= bad_key_size(aecls
.keysz
)
414 if badlen
is not None: me
.assertRaises(ValueError, aecls
, T
.span(badlen
))
415 badlen
= bad_key_size(aecls
.noncesz
)
416 if badlen
is not None:
417 me
.assertRaises(ValueError, key
.enc
, nonce
= T
.span(badlen
),
418 hsz
= len(h
), msz
= len(m
), tsz
= tsz
)
419 me
.assertRaises(ValueError, key
.dec
, nonce
= T
.span(badlen
),
420 hsz
= len(h
), csz
= len(c
), tsz
= tsz
)
421 if not aecls
.flags
&C
.AEADF_PCTSZ
:
422 enc
= key
.enc(nonce
= n
, hsz
= 0, msz
= len(m
))
424 me
.assertRaises(ValueError, enc
.done
, tsz
= badlen
)
425 badlen
= bad_key_size(aecls
.tagsz
)
426 if badlen
is not None:
427 me
.assertRaises(ValueError, key
.enc
, nonce
= n
,
428 hsz
= len(h
), msz
= len(m
), tsz
= badlen
)
429 me
.assertRaises(ValueError, key
.dec
, nonce
= n
,
430 hsz
= len(h
), csz
= len(c
), tsz
= badlen
)
432 ## Check that we can't get a loose `aad' object from a scheme which has
433 ## nonce-dependent AAD processing.
434 if aecls
.flags
&C
.AEADF_AADNDEP
: me
.assertRaises(ValueError, key
.aad
)
436 ## Check the menagerie of AAD hashing methods.
437 if not aecls
.flags
&C
.AEADF_NOAAD
:
439 enc
= key
.enc(nonce
= n
, hsz
= hsz
, msz
= 0, tsz
= tsz
)
441 return aad
, lambda: enc
.done(aad
= aad
)[1]
442 me
.check_hashbuffer(mkhash
)
444 ## Check that encryption/decryption works with the given precommitments.
445 def quick_enc_check(**kw
):
447 aad
= enc
.aad().hash(h
)
448 c0
= enc
.encrypt(m
); c1
, tt
= enc
.done(aad
= aad
, tsz
= tsz
)
449 me
.assertEqual((c
, t
), (c0
+ c1
, tt
))
450 def quick_dec_check(**kw
):
452 aad
= dec
.aad().hash(h
)
453 m0
= dec
.decrypt(c
); m1
= dec
.done(aad
= aad
, tag
= t
)
454 me
.assertEqual(m
, m0
+ m1
)
456 ## Check that we can get away without precommitting to the header length
457 ## if and only if the AEAD scheme says it will let us.
458 if aecls
.flags
&C
.AEADF_PCHSZ
:
459 me
.assertRaises(ValueError, key
.enc
, nonce
= n
,
460 msz
= len(m
), tsz
= tsz
)
461 me
.assertRaises(ValueError, key
.dec
, nonce
= n
,
462 csz
= len(c
), tsz
= tsz
)
464 quick_enc_check(nonce
= n
, msz
= len(m
), tsz
= tsz
)
465 quick_dec_check(nonce
= n
, csz
= len(c
), tsz
= tsz
)
467 ## Check that we can get away without precommitting to the message/
468 ## ciphertext length if and only if the AEAD scheme says it will let us.
469 if aecls
.flags
&C
.AEADF_PCMSZ
:
470 me
.assertRaises(ValueError, key
.enc
, nonce
= n
,
471 hsz
= len(h
), tsz
= tsz
)
472 me
.assertRaises(ValueError, key
.dec
, nonce
= n
,
473 hsz
= len(h
), tsz
= tsz
)
475 quick_enc_check(nonce
= n
, hsz
= len(h
), tsz
= tsz
)
476 quick_dec_check(nonce
= n
, hsz
= len(h
), tsz
= tsz
)
478 ## Check that we can get away without precommitting to the tag length if
479 ## and only if the AEAD scheme says it will let us.
480 if aecls
.flags
&C
.AEADF_PCTSZ
:
481 me
.assertRaises(ValueError, key
.enc
, nonce
= n
,
482 hsz
= len(h
), msz
= len(m
))
483 me
.assertRaises(ValueError, key
.dec
, nonce
= n
,
484 hsz
= len(h
), csz
= len(c
))
486 quick_enc_check(nonce
= n
, hsz
= len(h
), msz
= len(m
))
487 quick_dec_check(nonce
= n
, hsz
= len(h
), csz
= len(c
))
489 ## Check that if we precommit to the header length, we're properly held
490 ## to the commitment.
491 if not aecls
.flags
&C
.AEADF_NOAAD
:
493 ## First, check encryption with underrun. If we must supply AAD first,
494 ## then the underrun will be reported when we start trying to encrypt;
495 ## otherwise, checking is delayed until `done'.
496 enc
= key
.enc(nonce
= n
, hsz
= len(h
), msz
= len(m
), tsz
= tsz
)
497 aad
= enc
.aad().hash(h
[0:83])
498 if aecls
.flags
&C
.AEADF_AADFIRST
:
499 me
.assertRaises(ValueError, enc
.encrypt
, m
)
502 me
.assertRaises(ValueError, enc
.done
, aad
= aad
)
504 ## Next, check decryption with underrun. If we must supply AAD first,
505 ## then the underrun will be reported when we start trying to encrypt;
506 ## otherwise, checking is delayed until `done'.
507 dec
= key
.dec(nonce
= n
, hsz
= len(h
), csz
= len(c
), tsz
= tsz
)
508 aad
= dec
.aad().hash(h
[0:83])
509 if aecls
.flags
&C
.AEADF_AADFIRST
:
510 me
.assertRaises(ValueError, dec
.decrypt
, c
)
513 me
.assertRaises(ValueError, dec
.done
, tag
= t
, aad
= aad
)
515 ## If AAD processing is nonce-dependent then an overrun will be
516 ## detected imediately.
517 if aecls
.flags
&C
.AEADF_AADNDEP
:
518 enc
= key
.enc(nonce
= n
, hsz
= len(h
), msz
= len(m
), tsz
= tsz
)
519 aad
= enc
.aad().hash(h
[0:83])
520 me
.assertRaises(ValueError, aad
.hash, h
[82:131])
521 dec
= key
.dec(nonce
= n
, hsz
= len(h
), csz
= len(c
), tsz
= tsz
)
522 aad
= dec
.aad().hash(h
[0:83])
523 me
.assertRaises(ValueError, aad
.hash, h
[82:131])
525 ## Some additional tests for nonce-dependent `aad' objects.
526 if aecls
.flags
&C
.AEADF_AADNDEP
:
528 ## Check that `aad' objects can't be used once their parents are gone.
529 enc
= key
.enc(nonce
= n
, hsz
= len(h
), msz
= len(m
), tsz
= tsz
)
532 me
.assertRaises(ValueError, aad
.hash, h
)
534 ## Check that they can't be crossed over.
535 enc0
= key
.enc(nonce
= n
, hsz
= len(h
), msz
= len(m
), tsz
= tsz
)
536 enc1
= key
.enc(nonce
= n
, hsz
= len(h
), msz
= len(m
), tsz
= tsz
)
538 aad1
= enc1
.aad().hash(h
)
540 me
.assertRaises(ValueError, enc0
.done
, tsz
= tsz
, aad
= aad1
)
543 if not aecls
.flags
&C
.AEADF_AADNDEP
and not aecls
.flags
&C
.AEADF_NOAAD
:
550 aad2
.hash(h
[83:131] ^
48*C
.bytes("ff"))
551 me
.assertEqual(key
.enc(nonce
= n
, hsz
= len(h
),
552 msz
= 0, tsz
= tsz
).done(aad
= aad0
),
553 key
.enc(nonce
= n
, hsz
= len(h
),
554 msz
= 0, tsz
= tsz
).done(aad
= aad1
))
555 me
.assertNotEqual(key
.enc(nonce
= n
, hsz
= len(h
),
556 msz
= 0, tsz
= tsz
).done(aad
= aad0
),
557 key
.enc(nonce
= n
, hsz
= len(h
),
558 msz
= 0, tsz
= tsz
).done(aad
= aad2
))
560 ## Check that if we precommit to the message length, we're properly held
561 ## to the commitment. (Fortunately, this is way simpler than the AAD
562 ## case above.) First, try an underrun.
563 enc
= key
.enc(nonce
= n
, hsz
= 0, msz
= len(m
), tsz
= tsz
)
564 _
= enc
.encrypt(m
[0:183])
565 me
.assertRaises(ValueError, enc
.done
, tsz
= tsz
)
566 dec
= key
.dec(nonce
= n
, hsz
= 0, csz
= len(c
), tsz
= tsz
)
567 _
= dec
.decrypt(c
[0:183])
568 me
.assertRaises(ValueError, dec
.done
, tag
= t
)
570 ## And now an overrun.
571 enc
= key
.enc(nonce
= n
, hsz
= 0, msz
= 183, tsz
= tsz
)
572 me
.assertRaises(ValueError, enc
.encrypt
, m
)
573 dec
= key
.dec(nonce
= n
, hsz
= 0, csz
= 183, tsz
= tsz
)
574 me
.assertRaises(ValueError, dec
.decrypt
, c
)
576 ## Finally, check that if we precommit to a tag length, we're properly
577 ## held to the commitment. This depends on being able to find a tag size
578 ## which isn't the default.
579 tsz1
= different_key_size(aecls
.tagsz
, tsz
)
581 enc
= key
.enc(nonce
= n
, hsz
= 0, msz
= len(m
), tsz
= tsz1
)
583 me
.assertRaises(ValueError, enc
.done
, tsz
= tsz
)
584 dec
= key
.dec(nonce
= n
, hsz
= len(h
), csz
= len(c
), tsz
= tsz1
)
585 aad
= dec
.aad().hash(h
)
587 me
.assertRaises(ValueError, enc
.done
, tsz
= tsz
, aad
= aad
)
589 TestAuthenticatedEncryption
.generate_testcases \
590 ((name
, C
.gcaeads
[name
]) for name
in
591 ["des3-ccm", "blowfish-ocb1", "square-ocb3", "rijndael-gcm",
592 "serpent-eax", "salsa20-naclbox", "chacha20-poly1305"])
594 ###--------------------------------------------------------------------------
595 class BaseTestHash (HashBufferTestMixin
):
596 """Base class for testing hash functions."""
598 def check_hash(me
, hcls
, need_bufsz
= True):
600 Check hash class HCLS.
602 If NEED_BUFSZ is false, then don't insist that HCLS has a working `bufsz'
603 attribute. This test is mostly reused for MACs, which don't have this
606 ## Check the class properties.
607 me
.assertEqual(type(hcls
.name
), str)
608 if need_bufsz
: me
.assertEqual(type(hcls
.bufsz
), int)
609 me
.assertEqual(type(hcls
.hashsz
), int)
611 ## Set some initial values.
613 h
= hcls().hash(m
).done()
615 ## Check that hash length comes out right.
616 me
.assertEqual(len(h
), hcls
.hashsz
)
618 ## Check that we get the same answer if we split the message up.
619 me
.assertEqual(h
, hcls().hash(m
[0:73]).hash(m
[73:131]).done())
621 ## Check the `check' method.
622 me
.assertTrue(hcls().hash(m
).check(h
))
623 me
.assertFalse(hcls().hash(m
).check(h ^ hcls
.hashsz
*C
.bytes("aa")))
625 ## Check the menagerie of random hashing methods.
629 me
.check_hashbuffer(mkhash
)
631 class TestHash (BaseTestHash
, T
.GenericTestMixin
):
632 """Test hash functions."""
633 def _test_hash(me
, hcls
): me
.check_hash(hcls
, need_bufsz
= True)
635 TestHash
.generate_testcases((name
, C
.gchashes
[name
]) for name
in
636 ["md5", "sha", "whirlpool", "sha256", "sha512/224", "sha3-384", "shake256",
639 ###--------------------------------------------------------------------------
640 class TestMessageAuthentication (BaseTestHash
, T
.GenericTestMixin
):
641 """Test message authentication codes."""
643 def _test_mac(me
, mcls
):
645 ## Check the MAC properties.
646 me
.assertEqual(type(mcls
.name
), str)
647 me
.assertTrue(isinstance(mcls
.keysz
, C
.KeySZ
))
648 me
.assertEqual(type(mcls
.tagsz
), int)
651 k
= T
.span(mcls
.keysz
.default
)
653 me
.assertEqual(key
.hashsz
, key
.tagsz
)
654 me
.check_hash(key
, need_bufsz
= False)
656 ## Check that bad key lengths are rejected.
657 badlen
= bad_key_size(mcls
.keysz
)
658 if badlen
is not None: me
.assertRaises(ValueError, mcls
, T
.span(badlen
))
660 TestMessageAuthentication
.generate_testcases \
661 ((name
, C
.gcmacs
[name
]) for name
in
662 ["sha-hmac", "rijndael-cmac", "twofish-pmac1", "kmac128"])
664 class TestPoly1305 (HashBufferTestMixin
):
665 """Check the Poly1305 one-time message authentication function."""
667 def test_poly1305(me
):
669 ## Check the MAC properties.
670 me
.assertEqual(C
.poly1305
.name
, "poly1305")
671 me
.assertEqual(type(C
.poly1305
.keysz
), C
.KeySZSet
)
672 me
.assertEqual(C
.poly1305
.keysz
.default
, 16)
673 me
.assertEqual(C
.poly1305
.keysz
.set, set([16]))
674 me
.assertEqual(C
.poly1305
.tagsz
, 16)
675 me
.assertEqual(C
.poly1305
.masksz
, 16)
677 ## Set some initial values.
682 t
= key(u
).hash(m
).done()
684 ## Check the key properties.
685 me
.assertEqual(key
.name
, "poly1305")
686 me
.assertEqual(key
.tagsz
, 16)
687 me
.assertEqual(key
.tagsz
, 16)
688 me
.assertEqual(len(t
), 16)
690 ## Check that we get the same answer if we split the message up.
691 me
.assertEqual(t
, key(u
).hash(m
[0:86]).hash(m
[86:149]).done())
693 ## Check the `check' method.
694 me
.assertTrue(key(u
).hash(m
).check(t
))
695 me
.assertFalse(key(u
).hash(m
).check(t ^
16*C
.bytes("cc")))
697 ## Check the menagerie of random hashing methods.
701 me
.check_hashbuffer(mkhash
)
703 ## Check that we can't complete hashing without a mask.
704 me
.assertRaises(ValueError, key().hash(m
).done
)
707 h0
= key().hash(m
[0:96])
708 h1
= key().hash(m
[96:117])
709 me
.assertEqual(t
, key(u
).concat(h0
, h1
).hash(m
[117:149]).done())
711 me
.assertRaises(TypeError, key().concat
, key1().hash(m
[0:96]), h1
)
712 me
.assertRaises(TypeError, key().concat
, h0
, key1().hash(m
[96:117]))
713 me
.assertRaises(ValueError, key().concat
, key().hash(m
[0:93]), h1
)
715 ###--------------------------------------------------------------------------
716 class TestHLatin (U
.TestCase
):
717 """Test the `hsalsa20' and `hchacha20' functions."""
720 kk
= [T
.span(sz
) for sz
in [10, 16, 32]]
724 for fn
in [C
.hsalsa208_prf
, C
.hsalsa2012_prf
, C
.hsalsa20_prf
,
725 C
.hchacha8_prf
, C
.hchacha12_prf
, C
.hchacha20_prf
]:
728 me
.assertEqual(len(h
), 32)
729 me
.assertRaises(ValueError, fn
, bad_k
, n
)
730 me
.assertRaises(ValueError, fn
, k
, bad_n
)
732 ###--------------------------------------------------------------------------
733 class TestKeccak (HashBufferTestMixin
):
734 """Test the Keccak-p[1600, n] sponge function."""
738 ## Make a state and feed some stuff into it.
739 m0
= T
.bin("some initial string")
740 m1
= T
.bin("awesome follow-up string")
742 me
.assertEqual(st0
.nround
, 24)
745 ## Make another step with a different round count.
746 st1
= C
.Keccak1600(23)
748 me
.assertNotEqual(st0
.extract(32), st1
.extract(32))
750 ## Check state copying.
752 mask
= st1
.extract(len(m1
))
755 me
.assertEqual(st0
.extract(32), st1
.extract(32))
757 ## Check error conditions.
759 me
.assertRaises(ValueError, st0
.extract
, 201)
761 me
.assertRaises(ValueError, st0
.mix
, T
.span(201))
763 def check_shake(me
, xcls
, c
, done_matches_xof
= True):
765 Test the SHAKE and cSHAKE XOFs.
767 This is also used for testing KMAC, but that sets DONE_MATCHES_XOF false
768 to indicate that the XOF output is range-separated from the fixed-length
769 outputs (unlike the basic SHAKE functions).
772 ## Check the hash attributes.
774 me
.assertEqual(x
.rate
, 200 - c
)
775 me
.assertEqual(x
.buffered
, 0)
776 me
.assertEqual(x
.state
, "absorb")
778 ## Set some initial values.
779 func
= T
.bin("TESTXOF")
780 perso
= T
.bin("catacomb-python test")
782 h0
= xcls().hash(m
).done(193)
783 me
.assertEqual(len(h0
), 193)
784 h1
= xcls(func
= func
, perso
= perso
).hash(m
).done(193)
785 me
.assertEqual(len(h1
), 193)
786 me
.assertNotEqual(h0
, h1
)
788 ## Check input and output in pieces, and the state machine.
789 if done_matches_xof
: h
= h0
790 else: h
= xcls().hash(m
).xof().get(len(h0
))
791 x
= xcls().hash(m
[0:76]).hash(m
[76:167]).xof()
792 me
.assertEqual(h
, x
.get(98) + x
.get(95))
795 x
= xcls().hash(m
).xof()
796 me
.assertEqual(x
.mask(m
), m ^ h
[0:len(m
)])
798 ## Check the `check' method.
799 me
.assertTrue(xcls().hash(m
).check(h0
))
800 me
.assertFalse(xcls().hash(m
).check(h1
))
802 ## Check the menagerie of random hashing methods.
804 x
= xcls(func
= func
, perso
= perso
)
806 me
.check_hashbuffer(mkhash
)
808 ## Check the state machine tracking.
809 x
= xcls(); me
.assertEqual(x
.state
, "absorb")
810 x
.hash(m
); me
.assertEqual(x
.state
, "absorb")
812 h
= xx
.done(); me
.assertEqual(len(h
), 100 - x
.rate
//2)
813 me
.assertEqual(xx
.state
, "dead")
814 me
.assertRaises(ValueError, xx
.done
, 1)
815 me
.assertRaises(ValueError, xx
.get
, 1)
816 me
.assertEqual(x
.state
, "absorb")
817 me
.assertRaises(ValueError, x
.get
, 1)
818 x
.xof(); me
.assertEqual(x
.state
, "squeeze")
819 me
.assertRaises(ValueError, x
.done
, 1)
821 yy
= x
.copy(); me
.assertEqual(yy
.state
, "squeeze")
823 def test_shake128(me
): me
.check_shake(C
.Shake128
, 32)
824 def test_shake256(me
): me
.check_shake(C
.Shake256
, 64)
826 def check_kmac(me
, mcls
, c
):
828 me
.check_shake(lambda func
= None, perso
= None:
829 mcls(k
, perso
= perso
),
830 c
, done_matches_xof
= False)
832 def test_kmac128(me
): me
.check_kmac(C
.KMAC128
, 32)
833 def test_kmac256(me
): me
.check_kmac(C
.KMAC256
, 64)
835 ###--------------------------------------------------------------------------
836 class TestPRP (T
.GenericTestMixin
):
837 """Test pseudorandom permutations (PRPs)."""
839 def _test_prp(me
, pcls
):
841 ## Check the PRP properties.
842 me
.assertEqual(type(pcls
.name
), str)
843 me
.assertTrue(isinstance(pcls
.keysz
, C
.KeySZ
))
844 me
.assertEqual(type(pcls
.blksz
), int)
846 ## Check round-tripping.
847 k
= T
.span(pcls
.keysz
.default
)
849 m
= T
.span(pcls
.blksz
)
851 me
.assertEqual(len(c
), pcls
.blksz
)
852 me
.assertEqual(m
, key
.decrypt(c
))
854 ## Check that bad key lengths are rejected.
855 badlen
= bad_key_size(pcls
.keysz
)
856 if badlen
is not None: me
.assertRaises(ValueError, pcls
, T
.span(badlen
))
858 ## Check that bad blocks are rejected.
859 badblk
= T
.span(pcls
.blksz
+ 1)
860 me
.assertRaises(ValueError, key
.encrypt
, badblk
)
861 me
.assertRaises(ValueError, key
.decrypt
, badblk
)
863 TestPRP
.generate_testcases((name
, C
.gcprps
[name
]) for name
in
864 ["desx", "blowfish", "rijndael"])
866 ###----- That's all, folks --------------------------------------------------
868 if __name__
== "__main__": U
.main()