7 import deltatar.crypto as crypto
12 return s.encode("UTF-8")
17 TEST_PLAINTEXT = b("gentlemen don’t read each other’s mail")
18 TEST_PASSPHRASE = b"test1234"
19 TEST_AES_GCM_AAD = b"authenticated plain text"
20 TEST_DUMMY_FILENAME = "insurance-file.txt"
23 TEST_STATIC_NACL = os.urandom (CRYPTO_NACL_SIZE)
24 PLAIN_PARAMVERSION = 0
26 def faux_hdr (ctsize=1337, iv=None):
29 , "paramversion" : 2187
30 , "nacl" : binascii.unhexlify(b"0011223344556677"
32 , "iv" : iv or binascii.unhexlify(b"0011223344556677"
35 , "tag" : binascii.unhexlify(b"deadbeefbadb100d"
41 def fill_mod (n, off=0):
44 m = FILL_MOD_MEMO.get (k, None)
48 bufv = memoryview (buf)
52 struct.pack_into ("c", bufv, i, chr(c).encode("UTF-8"))
62 class CryptoLayerTest (unittest.TestCase):
66 class AESGCMTest (CryptoLayerTest):
68 os_urandom = os.urandom
71 """Reset globals altered for testing."""
72 _ = crypto._testing_set_AES_GCM_IV_CNT_MAX \
73 ("I am fully aware that this will void my warranty.")
74 _ = crypto._testing_set_PDTCRYPT_MAX_OBJ_SIZE \
75 ("I am fully aware that this will void my warranty.")
76 os.urandom = self.os_urandom
78 def test_crypto_aes_gcm_enc_ctor (self):
79 password = str (os.urandom (42))
80 encryptor = crypto.Encrypt (TEST_VERSION,
83 nacl=TEST_STATIC_NACL)
85 def test_crypto_aes_gcm_enc_ctor_bad_plainparams (self):
86 """Refuse plaintext passthrough mode by default."""
87 password = str (os.urandom (42))
88 with self.assertRaises (crypto.InvalidParameter):
89 encryptor = crypto.Encrypt (TEST_VERSION,
92 nacl=TEST_STATIC_NACL)
95 def test_crypto_aes_gcm_enc_ctor_ok_insecure_plainparams (self):
97 Comply with request for plaintext passthrough mode if the
98 *insecure* flag is passed.
100 password = str (os.urandom (42))
101 encryptor = crypto.Encrypt (TEST_VERSION,
104 nacl=TEST_STATIC_NACL,
108 def test_crypto_aes_gcm_enc_ctor_key (self):
109 key = os.urandom (42)
110 encryptor = crypto.Encrypt (TEST_VERSION,
113 nacl=TEST_STATIC_NACL)
116 def test_crypto_aes_gcm_enc_ctor_no_key_pw (self):
118 Either key (+nacl) or password must be supplied, not both.
120 with self.assertRaises (crypto.InvalidParameter): # neither key nor pw
121 encryptor = crypto.Encrypt (TEST_VERSION,
123 nacl=TEST_STATIC_NACL)
125 password = str (os.urandom (42))
126 key = os.urandom (16) # scrypt sized
127 with self.assertRaises (crypto.InvalidParameter): # both key and pw
128 encryptor = crypto.Encrypt (TEST_VERSION,
132 nacl=TEST_STATIC_NACL)
134 with self.assertRaises (crypto.InvalidParameter): # key, but salt missing
135 encryptor = crypto.Encrypt (TEST_VERSION,
140 with self.assertRaises (crypto.InvalidParameter): # empty pw
141 encryptor = crypto.Encrypt (TEST_VERSION,
144 nacl=TEST_STATIC_NACL)
147 def test_crypto_aes_gcm_enc_header_size (self):
148 password = str (os.urandom (42))
149 encryptor = crypto.Encrypt (TEST_VERSION,
152 nacl=TEST_STATIC_NACL)
154 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
155 assert len (header_dummy) == crypto.PDTCRYPT_HDR_SIZE
156 _, _ = encryptor.process (TEST_PLAINTEXT)
157 _, header, _ = encryptor.done (header_dummy)
158 assert len (header) == crypto.PDTCRYPT_HDR_SIZE
161 def test_crypto_aes_gcm_enc_multi_ivs_ok_explicit_counter (self):
163 Access the list of IVs used during encryption and check reuse. Start
164 from explicit counters so the inputs don’t overlap. IVs must not have
168 def enc (start_count, data):
169 password = str (os.urandom (42))
170 encryptor = crypto.Encrypt (TEST_VERSION,
173 nacl=TEST_STATIC_NACL,
177 for i, blob in enumerate (data, 1):
178 fname = "%s_%d" % (TEST_DUMMY_FILENAME, i)
179 header_dummy = encryptor.next (fname)
180 _, _ = encryptor.process (blob)
181 _, header, _ = encryptor.done (header_dummy)
182 assert len (encryptor.get_used_ivs ()) == i
184 return encryptor.get_used_ivs ()
186 ivs1 = enc (0x0042, [TEST_PLAINTEXT, b"none of your business"])
187 ivs2 = enc (0x1337, [b"read me if you can", b"for British eyes only!"])
189 # No reuse in general.
190 assert len (ivs1 & ivs2) == 0
195 # Counters of used IVs must match what we passed explicitly.
196 def extract_counters (ivs):
198 _, cnt = struct.unpack (crypto.FMT_I2N_IV, iv)
200 return list (map (getcount, ivs))
202 cnt1 = extract_counters (ivs1)
203 cnt2 = extract_counters (ivs2)
205 assert 0x0042 in cnt1
206 assert 0x0043 in cnt1
208 assert 0x1337 in cnt2
209 assert 0x1338 in cnt2
212 def test_crypto_aes_gcm_enc_chunk_size (self):
213 password = str (os.urandom (42))
214 encryptor = crypto.Encrypt (TEST_VERSION,
217 nacl=TEST_STATIC_NACL)
219 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
220 _, ciphertext = encryptor.process (TEST_PLAINTEXT)
221 assert len (ciphertext) == len (TEST_PLAINTEXT)
222 rest, header, fixed = encryptor.done (header_dummy)
223 assert len (rest) == 0
226 def test_crypto_aes_gcm_dec_ctor (self):
228 Ensure that only either key or password is accepted.
230 password = str (os.urandom (42))
231 key = os.urandom (16) # scrypt sized
233 decryptor = crypto.Decrypt (password=password)
234 decryptor = crypto.Decrypt (key=key)
236 with self.assertRaises (crypto.InvalidParameter): # both password and key
237 decryptor = crypto.Decrypt (password=password, key=key)
239 with self.assertRaises (crypto.InvalidParameter): # neither password nor key
240 decryptor = crypto.Decrypt (password=None, key=None)
242 with self.assertRaises (crypto.InvalidParameter): # # empty password
243 decryptor = crypto.Decrypt (password="")
246 def test_crypto_aes_gcm_dec_simple (self):
247 password = str (os.urandom (42))
248 encryptor = crypto.Encrypt (TEST_VERSION,
251 nacl=TEST_STATIC_NACL)
253 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
254 _, ciphertext = encryptor.process (TEST_PLAINTEXT)
255 rest, header, fixed = encryptor.done (header_dummy)
258 decryptor = crypto.Decrypt (password=password, fixedparts=fixed)
259 decryptor.next (header)
260 plaintext = decryptor.process (ciphertext)
261 rest = decryptor.done ()
264 assert plaintext == TEST_PLAINTEXT
267 def test_crypto_aes_gcm_dec_plain_bad (self):
269 Downgrade to plaintext must not be allowed in parameters
270 obtained from headers.
272 password = str (os.urandom (42))
273 encryptor = crypto.Encrypt (TEST_VERSION,
276 nacl=TEST_STATIC_NACL)
278 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
279 _, ciphertext = encryptor.process (TEST_PLAINTEXT)
280 rest, header, fixed = encryptor.done (header_dummy)
283 header = crypto.hdr_read (header)
284 header ["paramversion"] = PLAIN_PARAMVERSION
285 ok, header = crypto.hdr_make (header)
288 decryptor = crypto.Decrypt (password=password, fixedparts=fixed)
289 with self.assertRaises (crypto.InvalidParameter):
290 decryptor.next (header)
293 def test_crypto_aes_gcm_dec_plain_ok_insecure (self):
295 Allow plaintext crypto mode if *insecure* flag is passed.
297 password = str (os.urandom (42))
298 encryptor = crypto.Encrypt (TEST_VERSION,
301 nacl=TEST_STATIC_NACL,
304 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
305 _, ciphertext = encryptor.process (TEST_PLAINTEXT)
306 rest, header, fixed = encryptor.done (header_dummy)
309 header = crypto.hdr_read (header)
310 header ["paramversion"] = PLAIN_PARAMVERSION
311 ok, header = crypto.hdr_make (header)
314 decryptor = crypto.Decrypt (password=password,
317 decryptor.next (header)
318 plaintext = decryptor.process (ciphertext)
319 rest = decryptor.done ()
322 assert plaintext == TEST_PLAINTEXT
325 def test_crypto_aes_gcm_dec_bad_tag (self):
326 password = str (os.urandom (42))
327 encryptor = crypto.Encrypt (TEST_VERSION,
330 nacl=TEST_STATIC_NACL)
332 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
333 _, ciphertext = encryptor.process (TEST_PLAINTEXT)
334 ciphertext2, header, fixed = encryptor.done (header_dummy)
336 mut_header = bytearray (header)
337 mut_header_vw = memoryview (mut_header)
338 # replace one byte in the tag part of the header
339 second_byte = mut_header_vw [crypto.HDR_OFF_TAG + 2]
340 mut_header_vw [crypto.HDR_OFF_TAG + 2] = (second_byte + 0x2a) % 256
341 header = bytes (mut_header)
343 decryptor = crypto.Decrypt (password=password, fixedparts=fixed)
344 decryptor.next (header)
345 plaintext = decryptor.process (ciphertext)
346 with self.assertRaises (crypto.InvalidGCMTag):
347 _ = decryptor.done ()
350 def test_crypto_aes_gcm_enc_multicnk (self):
352 pt = fill_mod (1 << 14)
353 password = str (os.urandom (42))
354 encryptor = crypto.Encrypt (TEST_VERSION,
357 nacl=TEST_STATIC_NACL)
358 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
362 while off < len (pt):
363 upto = min (off + cnksiz, len (pt))
364 _, cnk = encryptor.process (pt [off:upto])
367 cnk, header, fixed = encryptor.done (header_dummy)
370 assert len (pt) == len (ct)
373 def test_crypto_aes_gcm_enc_multicnk_strict_ivs (self):
375 pt = fill_mod (1 << 14)
376 password = str (os.urandom (42))
377 encryptor = crypto.Encrypt (TEST_VERSION,
380 nacl=TEST_STATIC_NACL,
382 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
386 while off < len (pt):
387 upto = min (off + cnksiz, len (pt))
388 _, cnk = encryptor.process (pt [off:upto])
391 cnk, header, fixed = encryptor.done (header_dummy)
394 assert len (pt) == len (ct)
397 def test_crypto_aes_gcm_enc_multiobj (self):
399 password = str (os.urandom (42))
400 encryptor = crypto.Encrypt (TEST_VERSION,
403 nacl=TEST_STATIC_NACL,
407 pt = fill_mod (1 << 14, off=i)
408 header_dummy = encryptor.next ("%s_%d" % (TEST_DUMMY_FILENAME, i))
412 while off < len (pt):
413 upto = min (off + cnksiz, len (pt))
414 _, cnk = encryptor.process (pt [off:upto])
417 cnk, header, fixed = encryptor.done (header_dummy)
420 assert len (pt) == len (ct)
422 for i in range (5): addobj (i)
424 assert len (encryptor.fixed) == 1
427 def test_crypto_aes_gcm_enc_multiobj_strict_ivs (self):
429 password = str (os.urandom (42))
430 encryptor = crypto.Encrypt (TEST_VERSION,
433 nacl=TEST_STATIC_NACL,
435 curfixed = None # must remain constant after first
438 pt = fill_mod (1 << 14, off=i)
439 header_dummy = encryptor.next ("%s_%d" % (TEST_DUMMY_FILENAME, i))
443 while off < len (pt):
444 upto = min (off + cnksiz, len (pt))
445 _, cnk = encryptor.process (pt [off:upto])
448 cnk, header, fixed = encryptor.done (header_dummy)
453 assert fixed == curfixed
456 assert len (pt) == len (ct)
458 for i in range (5): addobj (i)
460 assert len (encryptor.fixed) == 1
463 def test_crypto_aes_gcm_enc_multiobj_cnt_wrap (self):
465 Test behavior when the file counter tops out.
467 Artificially lower the maximum possible file counter. Considering
468 invalid (0) and reserved (1, 2) values, the smallest possible file counter
469 for normal objects is 3. Starting from that, the header of the (max -
470 3)rd object must have both a different IV fixed part and a counter.
474 crypto._testing_set_AES_GCM_IV_CNT_MAX \
475 ("I am fully aware that this will void my warranty.", new_max)
477 password = str (os.urandom (42))
478 encryptor = crypto.Encrypt (TEST_VERSION,
481 nacl=TEST_STATIC_NACL,
487 def addobj (i, wrap=False):
490 pt = fill_mod (1 << 14, off=i)
491 header_dummy = encryptor.next ("%s_%d" % (TEST_DUMMY_FILENAME, i))
495 while off < len (pt):
496 upto = min (off + cnksiz, len (pt))
497 _, cnk = encryptor.process (pt [off:upto])
500 cnk, header, fixed = encryptor.done (header_dummy)
501 this_iv = crypto.hdr_read (header) ["iv"]
502 if last_iv is not None:
503 this_fixed, this_cnt = struct.unpack (crypto.FMT_I2N_IV, this_iv)
504 last_fixed, last_cnt = struct.unpack (crypto.FMT_I2N_IV, last_iv)
506 assert last_fixed == this_fixed
507 assert last_cnt == this_cnt - 1
509 assert last_fixed != this_fixed
510 assert this_cnt == minimum
514 assert len (pt) == len (ct)
516 for i in range (minimum, new_max + 1): addobj (i) # counter range: [3, 8]
517 addobj (i + 1, True) # counter wraps to 3
519 for j in range (i + 2, i + new_max - 1): addobj (j) # counter range: [4, 8]
520 addobj (j + 1, True) # counter wraps to 3 again
522 assert len (encryptor.fixed) == 3
525 def test_crypto_aes_gcm_enc_multiobj_cnt_wrap_badfixed (self):
527 Test behavior when the file counter tops out and the transition to
528 the next IV fixed part fails on account of a bad random generator.
530 Replaces the ``urandom`` reference in ``os`` with a deterministic
531 function. The encryptor context must communicate this condition with an
532 ``IVFixedPartError``.
536 crypto._testing_set_AES_GCM_IV_CNT_MAX \
537 ("I am fully aware that this will void my warranty.", new_max)
539 os.urandom = lambda n: bytes (bytearray ([n % 256] * n))
540 password = str (os.urandom (42))
541 encryptor = crypto.Encrypt (TEST_VERSION,
544 nacl=TEST_STATIC_NACL,
548 pt = fill_mod (1 << 14, off=i)
549 header_dummy = encryptor.next ("%s_%d" % (TEST_DUMMY_FILENAME, i))
552 while off < len (pt):
553 upto = min (off + cnksiz, len (pt))
554 _, cnk = encryptor.process (pt [off:upto])
557 for i in range (minimum, new_max): addobj (42 + i)
559 with self.assertRaises (crypto.IVFixedPartError):
564 def test_crypto_aes_gcm_enc_length_cap (self):
566 Artificially lower the maximum allowable data length and attempt to
567 encrypt a larger object. Verify that the crypto handler only encrypts
568 data up to the size limit. A downstream user detects that condition by
569 testing whether the encryption step yielded less bytes than the
572 The sibling to this test is test_restore_backup_max_file_length()
573 in test_delatar.py. Deltatar will transparently create a splitted object
574 with an increased IV file counter.
577 crypto._testing_set_PDTCRYPT_MAX_OBJ_SIZE \
578 ("I am fully aware that this will void my warranty.", new_max)
580 password = str (os.urandom (42))
581 encryptor = crypto.Encrypt (TEST_VERSION,
584 nacl=TEST_STATIC_NACL)
587 pt, ct = fill_mod (s), None
588 header_dummy = encryptor.next ("%s_%d" % (TEST_DUMMY_FILENAME, s))
590 n, ct = encryptor.process (pt)
591 rest, _, _ = encryptor.done (header_dummy)
593 # NB: If this check *ever* fails, then something changed in the
594 # encoding layer. AES-GCM is a stream cipher so each encoding
595 # step will yield the exact number of ciphertext bytes that
596 # was provided as plaintext. Thus there cannot be any encoded
597 # data left when calling the finalizers. None of the crypo code
598 # depends on that assumption but nevertheless we check it here
599 # in case anything changes upstream in the Cryptography
600 # library. In case there actually is a rest, replace the
601 # assertion below with ``ct += rest``.
602 assert (len (rest) == 0)
604 if len (pt) > new_max:
605 # If the plaintext was longer than the artificially lowered
606 # maximum, then the number of ciphertext bytes must be clamped
610 assert n == len (pt) == len (ct)
612 for i in range (16): encobj (1 << i)
615 def test_crypto_aes_gcm_dec_length_cap (self):
617 The decryptor must reject headers with an object size that exceeds
618 the PDTCRYPT maximum. Longer files split into multiple objects.
620 password = str (os.urandom (42))
622 meta ["ctsize"] = crypto.PDTCRYPT_MAX_OBJ_SIZE + 1
623 ok, header = crypto.hdr_make (meta)
627 # Set up decryption with bogus header.
628 decryptor = crypto.Decrypt (password=password, fixedparts=[])
630 with self.assertRaises (crypto.InvalidHeader):
631 decryptor.next (header)
634 def test_crypto_aes_gcm_dec_length_mismatch (self):
636 Catch attempts at decrypting more data than what was stated in the
640 orig_pt = fill_mod (1 << 14)
641 password = str (os.urandom (42))
642 encryptor = crypto.Encrypt (TEST_VERSION,
645 nacl=TEST_STATIC_NACL)
646 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
650 while off < len (orig_pt):
651 upto = min (off + cnksiz, len (orig_pt))
652 _n, cnk = encryptor.process (orig_pt [off:upto])
655 cnk, header, fixed = encryptor.done (header_dummy)
658 decryptor = crypto.Decrypt (password=password, fixedparts=fixed)
660 decryptor.next (header)
663 while off < len (orig_pt):
664 upto = min (off + cnksiz, len (orig_pt))
665 cnk = decryptor.process (ct [off:upto])
669 with self.assertRaises (crypto.CiphertextTooLong):
670 # Try and decrypt one byte more than was encrypted.
671 # This must be caught in crypto.py.
672 _ = decryptor.process (ct [0:1])
675 def test_crypto_aes_gcm_dec_multicnk (self):
677 orig_pt = fill_mod (1 << 14)
678 password = str (os.urandom (42))
679 encryptor = crypto.Encrypt (TEST_VERSION,
682 nacl=TEST_STATIC_NACL)
683 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
687 while off < len (orig_pt):
688 upto = min (off + cnksiz, len (orig_pt))
689 _n, cnk = encryptor.process (orig_pt [off:upto])
692 cnk, header, fixed = encryptor.done (header_dummy)
695 decryptor = crypto.Decrypt (password=password,
697 decryptor.next (header)
700 while off < len (orig_pt):
701 upto = min (off + cnksiz, len (orig_pt))
702 cnk = decryptor.process (ct [off:upto])
707 pt += decryptor.done ()
711 def test_crypto_aes_gcm_dec_multicnk_bad_tag (self):
713 orig_pt = fill_mod (1 << 14)
714 password = str (os.urandom (42))
715 encryptor = crypto.Encrypt (TEST_VERSION,
718 nacl=TEST_STATIC_NACL)
719 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
723 while off < len (orig_pt):
724 upto = min (off + cnksiz, len (orig_pt))
725 _n, cnk = encryptor.process (orig_pt [off:upto])
728 cnk, header, fixed = encryptor.done (header_dummy)
731 mut_header = bytearray (header)
732 mut_header_vw = memoryview (mut_header)
733 # replace one byte in the tag part of the header
734 second_byte = mut_header_vw [crypto.HDR_OFF_TAG + 2]
735 mut_header_vw [crypto.HDR_OFF_TAG + 2] = (second_byte + 0x2a) % 256
736 header = bytes (mut_header)
738 decryptor = crypto.Decrypt (password=password,
740 decryptor.next (header)
743 while off < len (orig_pt):
744 upto = min (off + cnksiz, len (orig_pt))
745 cnk = decryptor.process (ct [off:upto])
749 with self.assertRaises (crypto.InvalidGCMTag):
750 _ = decryptor.done ()
753 def test_crypto_aes_gcm_dec_iv_gap (self):
755 Encrypt multiple objects using non-consecutive IVs and verify that the
756 decryptor errors out with an exception in strict mode but keeps quiet
760 orig_pt_1 = fill_mod (1 << 10)
761 orig_pt_2 = fill_mod (1 << 10, 23)
762 orig_pt_3 = fill_mod (1 << 10, 42)
763 password = str (os.urandom (42))
764 encryptor = crypto.Encrypt (TEST_VERSION,
767 nacl=TEST_STATIC_NACL)
770 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
774 while off < len (pt):
775 upto = min (off + cnksiz, len (pt))
776 _n, cnk = encryptor.process (pt [off:upto])
779 cnk, header, fixed = encryptor.done (header_dummy)
780 return ct + cnk, header, fixed
782 ct_1, hdr_1, _____ = enc (orig_pt_1)
784 ## Here we bump the iv of the encryptor, breaking the series.
785 encryptor.set_object_counter (encryptor.cnt + 1)
786 ct_2, hdr_2, fixed = enc (orig_pt_2)
788 ## IV of final object is again in-sequence.
789 ct_3, hdr_3, fixed = enc (orig_pt_3)
791 def decrypt (strict_ivs):
792 decryptor = crypto.Decrypt (password=password, fixedparts=fixed,
793 strict_ivs=strict_ivs)
799 while off < len (ct):
800 upto = min (off + cnksiz, len (ct))
801 cnk = decryptor.process (ct [off:upto])
804 return pt + decryptor.done ()
806 decr_pt_1 = dec (hdr_1, ct_1)
807 decr_pt_2 = dec (hdr_2, ct_2) ## ← good header, non-consecutive IV
808 decr_pt_3 = dec (hdr_3, ct_3)
810 assert decr_pt_1 == orig_pt_1
811 assert decr_pt_2 == orig_pt_2
812 assert decr_pt_3 == orig_pt_3
814 with self.assertRaises (crypto.NonConsecutiveIV):
817 decrypt (False) # Sequence passes
820 def test_crypto_aes_gcm_dec_iv_reuse (self):
822 Meddle with encrypted content: extract the IV from one object
823 and inject it into the header of another. This must be rejected
824 by the decryptor with paranoid IV checking enabled.
827 orig_pt_1 = fill_mod (1 << 10)
828 orig_pt_2 = fill_mod (1 << 10, 42)
829 password = str (os.urandom (42))
830 encryptor = crypto.Encrypt (TEST_VERSION,
833 nacl=TEST_STATIC_NACL,
837 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
841 while off < len (pt):
842 upto = min (off + cnksiz, len (pt))
843 _n, cnk = encryptor.process (pt [off:upto])
846 cnk, header, fixed = encryptor.done (header_dummy)
847 return ct + cnk, header, fixed
849 ct_1, hdr_1, _____ = enc (orig_pt_1)
850 encryptor.cnt -= 1 # induce error by forcing an identical IV on next step
852 with self.assertRaises (crypto.DuplicateIV): # reuse detected
853 ct_2, hdr_2, fixed = enc (orig_pt_2)
856 class HeaderTest (CryptoLayerTest):
858 def test_crypto_fmt_hdr_make (self):
860 ok, hdr = crypto.hdr_make (meta)
862 assert len (hdr) == crypto.PDTCRYPT_HDR_SIZE
865 def test_crypto_fmt_hdr_make_useless (self):
866 ok, ret = crypto.hdr_make ({ 42: "x" })
868 assert ret.startswith ("error assembling header:")
871 def test_crypto_fmt_hdr_read (self):
873 ok, hdr = crypto.hdr_make (meta)
875 assert hdr is not None
876 mmeta = crypto.hdr_read (hdr)
877 assert mmeta is not None
879 if meta [k] != mmeta [k]:
880 raise "header mismatch after reading: expected %r, got %r" \
881 % (meta [k], mmeta [k])
884 def test_crypto_fmt_hdr_read_trailing_garbage (self):
886 ok, hdr = crypto.hdr_make (meta)
887 ok, hdr = crypto.hdr_make (meta)
889 assert hdr is not None
891 with self.assertRaises (crypto.InvalidHeader):
892 _ = crypto.hdr_read (hdr)
895 def test_crypto_fmt_hdr_read_leading_garbage (self):
897 ok, hdr = crypto.hdr_make (meta)
898 ok, hdr = crypto.hdr_make (meta)
900 assert hdr is not None
902 with self.assertRaises (crypto.InvalidHeader):
903 _ = crypto.hdr_read (hdr)
906 def test_crypto_fmt_hdr_inner_garbage (self):
908 ok, hdr = crypto.hdr_make (meta)
910 data = hdr[:len(hdr)//2] + b"junk-" + hdr[len(hdr)//2:]
911 with self.assertRaises (crypto.InvalidHeader):
912 _ = crypto.hdr_read (data)