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,
176 for i, blob in enumerate (data, 1):
177 fname = "%s_%d" % (TEST_DUMMY_FILENAME, i)
178 header_dummy = encryptor.next (fname)
179 _, _ = encryptor.process (blob)
180 _, header, _ = encryptor.done (header_dummy)
181 assert len (encryptor.get_used_ivs ()) == i
183 return encryptor.get_used_ivs ()
185 ivs1 = enc (0x0042, [TEST_PLAINTEXT, b"none of your business"])
186 ivs2 = enc (0x1337, [b"read me if you can", b"for British eyes only!"])
188 # No reuse in general.
189 assert len (ivs1 & ivs2) == 0
194 # Counters of used IVs must match what we passed explicitly.
195 def extract_counters (ivs):
197 _, cnt = struct.unpack (crypto.FMT_I2N_IV, iv)
199 return list (map (getcount, ivs))
201 cnt1 = extract_counters (ivs1)
202 cnt2 = extract_counters (ivs2)
204 assert 0x0042 in cnt1
205 assert 0x0043 in cnt1
207 assert 0x1337 in cnt2
208 assert 0x1338 in cnt2
211 def test_crypto_aes_gcm_enc_chunk_size (self):
212 password = str (os.urandom (42))
213 encryptor = crypto.Encrypt (TEST_VERSION,
216 nacl=TEST_STATIC_NACL)
218 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
219 _, ciphertext = encryptor.process (TEST_PLAINTEXT)
220 assert len (ciphertext) == len (TEST_PLAINTEXT)
221 rest, header, fixed = encryptor.done (header_dummy)
222 assert len (rest) == 0
225 def test_crypto_aes_gcm_dec_ctor (self):
227 Ensure that only either key or password is accepted.
229 password = str (os.urandom (42))
230 key = os.urandom (16) # scrypt sized
232 decryptor = crypto.Decrypt (password=password)
233 decryptor = crypto.Decrypt (key=key)
235 with self.assertRaises (crypto.InvalidParameter): # both password and key
236 decryptor = crypto.Decrypt (password=password, key=key)
238 with self.assertRaises (crypto.InvalidParameter): # neither password nor key
239 decryptor = crypto.Decrypt (password=None, key=None)
241 with self.assertRaises (crypto.InvalidParameter): # # empty password
242 decryptor = crypto.Decrypt (password="")
245 def test_crypto_aes_gcm_dec_simple (self):
246 password = str (os.urandom (42))
247 encryptor = crypto.Encrypt (TEST_VERSION,
250 nacl=TEST_STATIC_NACL)
252 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
253 _, ciphertext = encryptor.process (TEST_PLAINTEXT)
254 rest, header, fixed = encryptor.done (header_dummy)
257 decryptor = crypto.Decrypt (password=password, fixedparts=fixed)
258 decryptor.next (header)
259 plaintext = decryptor.process (ciphertext)
260 rest = decryptor.done ()
263 assert plaintext == TEST_PLAINTEXT
266 def test_crypto_aes_gcm_dec_plain_bad (self):
268 Downgrade to plaintext must not be allowed in parameters
269 obtained from headers.
271 password = str (os.urandom (42))
272 encryptor = crypto.Encrypt (TEST_VERSION,
275 nacl=TEST_STATIC_NACL)
277 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
278 _, ciphertext = encryptor.process (TEST_PLAINTEXT)
279 rest, header, fixed = encryptor.done (header_dummy)
282 header = crypto.hdr_read (header)
283 header ["paramversion"] = PLAIN_PARAMVERSION
284 ok, header = crypto.hdr_make (header)
287 decryptor = crypto.Decrypt (password=password, fixedparts=fixed)
288 with self.assertRaises (crypto.InvalidParameter):
289 decryptor.next (header)
292 def test_crypto_aes_gcm_dec_plain_ok_insecure (self):
294 Allow plaintext crypto mode if *insecure* flag is passed.
296 password = str (os.urandom (42))
297 encryptor = crypto.Encrypt (TEST_VERSION,
300 nacl=TEST_STATIC_NACL,
303 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
304 _, ciphertext = encryptor.process (TEST_PLAINTEXT)
305 rest, header, fixed = encryptor.done (header_dummy)
308 header = crypto.hdr_read (header)
309 header ["paramversion"] = PLAIN_PARAMVERSION
310 ok, header = crypto.hdr_make (header)
313 decryptor = crypto.Decrypt (password=password,
316 decryptor.next (header)
317 plaintext = decryptor.process (ciphertext)
318 rest = decryptor.done ()
321 assert plaintext == TEST_PLAINTEXT
324 def test_crypto_aes_gcm_dec_bad_tag (self):
325 password = str (os.urandom (42))
326 encryptor = crypto.Encrypt (TEST_VERSION,
329 nacl=TEST_STATIC_NACL)
331 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
332 _, ciphertext = encryptor.process (TEST_PLAINTEXT)
333 ciphertext2, header, fixed = encryptor.done (header_dummy)
335 mut_header = bytearray (header)
336 mut_header_vw = memoryview (mut_header)
337 # replace one byte in the tag part of the header
338 second_byte = mut_header_vw [crypto.HDR_OFF_TAG + 2]
339 mut_header_vw [crypto.HDR_OFF_TAG + 2] = (second_byte + 0x2a) % 256
340 header = bytes (mut_header)
342 decryptor = crypto.Decrypt (password=password, fixedparts=fixed)
343 decryptor.next (header)
344 plaintext = decryptor.process (ciphertext)
345 with self.assertRaises (crypto.InvalidGCMTag):
346 _ = decryptor.done ()
349 def test_crypto_aes_gcm_enc_multicnk (self):
351 pt = fill_mod (1 << 14)
352 password = str (os.urandom (42))
353 encryptor = crypto.Encrypt (TEST_VERSION,
356 nacl=TEST_STATIC_NACL)
357 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
361 while off < len (pt):
362 upto = min (off + cnksiz, len (pt))
363 _, cnk = encryptor.process (pt [off:upto])
366 cnk, header, fixed = encryptor.done (header_dummy)
369 assert len (pt) == len (ct)
372 def test_crypto_aes_gcm_enc_multicnk_strict_ivs (self):
374 pt = fill_mod (1 << 14)
375 password = str (os.urandom (42))
376 encryptor = crypto.Encrypt (TEST_VERSION,
379 nacl=TEST_STATIC_NACL,
381 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
385 while off < len (pt):
386 upto = min (off + cnksiz, len (pt))
387 _, cnk = encryptor.process (pt [off:upto])
390 cnk, header, fixed = encryptor.done (header_dummy)
393 assert len (pt) == len (ct)
396 def test_crypto_aes_gcm_enc_multiobj (self):
398 password = str (os.urandom (42))
399 encryptor = crypto.Encrypt (TEST_VERSION,
402 nacl=TEST_STATIC_NACL,
406 pt = fill_mod (1 << 14, off=i)
407 header_dummy = encryptor.next ("%s_%d" % (TEST_DUMMY_FILENAME, i))
411 while off < len (pt):
412 upto = min (off + cnksiz, len (pt))
413 _, cnk = encryptor.process (pt [off:upto])
416 cnk, header, fixed = encryptor.done (header_dummy)
419 assert len (pt) == len (ct)
421 for i in range (5): addobj (i)
423 assert len (encryptor.fixed) == 1
426 def test_crypto_aes_gcm_enc_multiobj_strict_ivs (self):
428 password = str (os.urandom (42))
429 encryptor = crypto.Encrypt (TEST_VERSION,
432 nacl=TEST_STATIC_NACL,
434 curfixed = None # must remain constant after first
437 pt = fill_mod (1 << 14, off=i)
438 header_dummy = encryptor.next ("%s_%d" % (TEST_DUMMY_FILENAME, i))
442 while off < len (pt):
443 upto = min (off + cnksiz, len (pt))
444 _, cnk = encryptor.process (pt [off:upto])
447 cnk, header, fixed = encryptor.done (header_dummy)
452 assert fixed == curfixed
455 assert len (pt) == len (ct)
457 for i in range (5): addobj (i)
459 assert len (encryptor.fixed) == 1
462 def test_crypto_aes_gcm_enc_multiobj_cnt_wrap (self):
464 Test behavior when the file counter tops out.
466 Artificially lower the maximum possible file counter. Considering
467 invalid (0) and reserved (1, 2) values, the smallest possible file counter
468 for normal objects is 3. Starting from that, the header of the (max -
469 3)rd object must have both a different IV fixed part and a counter.
473 crypto._testing_set_AES_GCM_IV_CNT_MAX \
474 ("I am fully aware that this will void my warranty.", new_max)
476 password = str (os.urandom (42))
477 encryptor = crypto.Encrypt (TEST_VERSION,
480 nacl=TEST_STATIC_NACL,
486 def addobj (i, wrap=False):
489 pt = fill_mod (1 << 14, off=i)
490 header_dummy = encryptor.next ("%s_%d" % (TEST_DUMMY_FILENAME, i))
494 while off < len (pt):
495 upto = min (off + cnksiz, len (pt))
496 _, cnk = encryptor.process (pt [off:upto])
499 cnk, header, fixed = encryptor.done (header_dummy)
500 this_iv = crypto.hdr_read (header) ["iv"]
501 if last_iv is not None:
502 this_fixed, this_cnt = struct.unpack (crypto.FMT_I2N_IV, this_iv)
503 last_fixed, last_cnt = struct.unpack (crypto.FMT_I2N_IV, last_iv)
505 assert last_fixed == this_fixed
506 assert last_cnt == this_cnt - 1
508 assert last_fixed != this_fixed
509 assert this_cnt == minimum
513 assert len (pt) == len (ct)
515 for i in range (minimum, new_max + 1): addobj (i) # counter range: [3, 8]
516 addobj (i + 1, True) # counter wraps to 3
518 for j in range (i + 2, i + new_max - 1): addobj (j) # counter range: [4, 8]
519 addobj (j + 1, True) # counter wraps to 3 again
521 assert len (encryptor.fixed) == 3
524 def test_crypto_aes_gcm_enc_multiobj_cnt_wrap_badfixed (self):
526 Test behavior when the file counter tops out and the transition to
527 the next IV fixed part fails on account of a bad random generator.
529 Replaces the ``urandom`` reference in ``os`` with a deterministic
530 function. The encryptor context must communicate this condition with an
531 ``IVFixedPartError``.
535 crypto._testing_set_AES_GCM_IV_CNT_MAX \
536 ("I am fully aware that this will void my warranty.", new_max)
538 os.urandom = lambda n: bytes (bytearray ([n % 256] * n))
539 password = str (os.urandom (42))
540 encryptor = crypto.Encrypt (TEST_VERSION,
543 nacl=TEST_STATIC_NACL,
547 pt = fill_mod (1 << 14, off=i)
548 header_dummy = encryptor.next ("%s_%d" % (TEST_DUMMY_FILENAME, i))
551 while off < len (pt):
552 upto = min (off + cnksiz, len (pt))
553 _, cnk = encryptor.process (pt [off:upto])
556 for i in range (minimum, new_max): addobj (42 + i)
558 with self.assertRaises (crypto.IVFixedPartError):
563 def test_crypto_aes_gcm_enc_length_cap (self):
565 Artificially lower the maximum allowable data length and attempt to
566 encrypt a larger object. Verify that the crypto handler only encrypts
567 data up to the size limit. A downstream user detects that condition by
568 testing whether the encryption step yielded less bytes than the
571 The sibling to this test is test_restore_backup_max_file_length()
572 in test_delatar.py. Deltatar will transparently create a splitted object
573 with an increased IV file counter.
576 crypto._testing_set_PDTCRYPT_MAX_OBJ_SIZE \
577 ("I am fully aware that this will void my warranty.", new_max)
579 password = str (os.urandom (42))
580 encryptor = crypto.Encrypt (TEST_VERSION,
583 nacl=TEST_STATIC_NACL)
586 pt, ct = fill_mod (s), None
587 header_dummy = encryptor.next ("%s_%d" % (TEST_DUMMY_FILENAME, s))
589 n, ct = encryptor.process (pt)
590 rest, _, _ = encryptor.done (header_dummy)
592 # NB: If this check *ever* fails, then something changed in the
593 # encoding layer. AES-GCM is a stream cipher so each encoding
594 # step will yield the exact number of ciphertext bytes that
595 # was provided as plaintext. Thus there cannot be any encoded
596 # data left when calling the finalizers. None of the crypo code
597 # depends on that assumption but nevertheless we check it here
598 # in case anything changes upstream in the Cryptography
599 # library. In case there actually is a rest, replace the
600 # assertion below with ``ct += rest``.
601 assert (len (rest) == 0)
603 if len (pt) > new_max:
604 # If the plaintext was longer than the artificially lowered
605 # maximum, then the number of ciphertext bytes must be clamped
609 assert n == len (pt) == len (ct)
611 for i in range (16): encobj (1 << i)
614 def test_crypto_aes_gcm_dec_length_cap (self):
616 The decryptor must reject headers with an object size that exceeds
617 the PDTCRYPT maximum. Longer files split into multiple objects.
619 password = str (os.urandom (42))
621 meta ["ctsize"] = crypto.PDTCRYPT_MAX_OBJ_SIZE + 1
622 ok, header = crypto.hdr_make (meta)
626 # Set up decryption with bogus header.
627 decryptor = crypto.Decrypt (password=password, fixedparts=[])
629 with self.assertRaises (crypto.InvalidHeader):
630 decryptor.next (header)
633 def test_crypto_aes_gcm_dec_length_mismatch (self):
635 Catch attempts at decrypting more data than what was stated in the
639 orig_pt = fill_mod (1 << 14)
640 password = str (os.urandom (42))
641 encryptor = crypto.Encrypt (TEST_VERSION,
644 nacl=TEST_STATIC_NACL)
645 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
649 while off < len (orig_pt):
650 upto = min (off + cnksiz, len (orig_pt))
651 _n, cnk = encryptor.process (orig_pt [off:upto])
654 cnk, header, fixed = encryptor.done (header_dummy)
657 decryptor = crypto.Decrypt (password=password, fixedparts=fixed)
659 decryptor.next (header)
662 while off < len (orig_pt):
663 upto = min (off + cnksiz, len (orig_pt))
664 cnk = decryptor.process (ct [off:upto])
668 with self.assertRaises (crypto.CiphertextTooLong):
669 # Try and decrypt one byte more than was encrypted.
670 # This must be caught in crypto.py.
671 _ = decryptor.process (ct [0:1])
674 def test_crypto_aes_gcm_dec_multicnk (self):
676 orig_pt = fill_mod (1 << 14)
677 password = str (os.urandom (42))
678 encryptor = crypto.Encrypt (TEST_VERSION,
681 nacl=TEST_STATIC_NACL)
682 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
686 while off < len (orig_pt):
687 upto = min (off + cnksiz, len (orig_pt))
688 _n, cnk = encryptor.process (orig_pt [off:upto])
691 cnk, header, fixed = encryptor.done (header_dummy)
694 decryptor = crypto.Decrypt (password=password,
696 decryptor.next (header)
699 while off < len (orig_pt):
700 upto = min (off + cnksiz, len (orig_pt))
701 cnk = decryptor.process (ct [off:upto])
706 pt += decryptor.done ()
710 def test_crypto_aes_gcm_dec_multicnk_bad_tag (self):
712 orig_pt = fill_mod (1 << 14)
713 password = str (os.urandom (42))
714 encryptor = crypto.Encrypt (TEST_VERSION,
717 nacl=TEST_STATIC_NACL)
718 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
722 while off < len (orig_pt):
723 upto = min (off + cnksiz, len (orig_pt))
724 _n, cnk = encryptor.process (orig_pt [off:upto])
727 cnk, header, fixed = encryptor.done (header_dummy)
730 mut_header = bytearray (header)
731 mut_header_vw = memoryview (mut_header)
732 # replace one byte in the tag part of the header
733 second_byte = mut_header_vw [crypto.HDR_OFF_TAG + 2]
734 mut_header_vw [crypto.HDR_OFF_TAG + 2] = (second_byte + 0x2a) % 256
735 header = bytes (mut_header)
737 decryptor = crypto.Decrypt (password=password,
739 decryptor.next (header)
742 while off < len (orig_pt):
743 upto = min (off + cnksiz, len (orig_pt))
744 cnk = decryptor.process (ct [off:upto])
748 with self.assertRaises (crypto.InvalidGCMTag):
749 _ = decryptor.done ()
752 def test_crypto_aes_gcm_dec_iv_gap (self):
754 Encrypt multiple objects using non-consecutive IVs and verify that the
755 decryptor errors out with an exception in strict mode but keeps quiet
759 orig_pt_1 = fill_mod (1 << 10)
760 orig_pt_2 = fill_mod (1 << 10, 23)
761 orig_pt_3 = fill_mod (1 << 10, 42)
762 password = str (os.urandom (42))
763 encryptor = crypto.Encrypt (TEST_VERSION,
766 nacl=TEST_STATIC_NACL)
769 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
773 while off < len (pt):
774 upto = min (off + cnksiz, len (pt))
775 _n, cnk = encryptor.process (pt [off:upto])
778 cnk, header, fixed = encryptor.done (header_dummy)
779 return ct + cnk, header, fixed
781 ct_1, hdr_1, _____ = enc (orig_pt_1)
783 ## Here we bump the iv of the encryptor, breaking the series.
784 encryptor.set_object_counter (encryptor.cnt + 1)
785 ct_2, hdr_2, fixed = enc (orig_pt_2)
787 ## IV of final object is again in-sequence.
788 ct_3, hdr_3, fixed = enc (orig_pt_3)
790 def decrypt (strict_ivs):
791 decryptor = crypto.Decrypt (password=password, fixedparts=fixed,
792 strict_ivs=strict_ivs)
798 while off < len (ct):
799 upto = min (off + cnksiz, len (ct))
800 cnk = decryptor.process (ct [off:upto])
803 return pt + decryptor.done ()
805 decr_pt_1 = dec (hdr_1, ct_1)
806 decr_pt_2 = dec (hdr_2, ct_2) ## ← good header, non-consecutive IV
807 decr_pt_3 = dec (hdr_3, ct_3)
809 assert decr_pt_1 == orig_pt_1
810 assert decr_pt_2 == orig_pt_2
811 assert decr_pt_3 == orig_pt_3
813 with self.assertRaises (crypto.NonConsecutiveIV):
816 decrypt (False) # Sequence passes
819 def test_crypto_aes_gcm_dec_iv_reuse (self):
821 Meddle with encrypted content: extract the IV from one object
822 and inject it into the header of another. This must be rejected
826 orig_pt_1 = fill_mod (1 << 10)
827 orig_pt_2 = fill_mod (1 << 10, 42)
828 password = str (os.urandom (42))
829 encryptor = crypto.Encrypt (TEST_VERSION,
832 nacl=TEST_STATIC_NACL)
835 header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
839 while off < len (pt):
840 upto = min (off + cnksiz, len (pt))
841 _n, cnk = encryptor.process (pt [off:upto])
844 cnk, header, fixed = encryptor.done (header_dummy)
845 return ct + cnk, header, fixed
847 ct_1, hdr_1, _____ = enc (orig_pt_1)
848 encryptor.cnt -= 1 # induce error by forcing an identical IV on next step
850 with self.assertRaises (crypto.DuplicateIV): # reuse detected
851 ct_2, hdr_2, fixed = enc (orig_pt_2)
854 class HeaderTest (CryptoLayerTest):
856 def test_crypto_fmt_hdr_make (self):
858 ok, hdr = crypto.hdr_make (meta)
860 assert len (hdr) == crypto.PDTCRYPT_HDR_SIZE
863 def test_crypto_fmt_hdr_make_useless (self):
864 ok, ret = crypto.hdr_make ({ 42: "x" })
866 assert ret.startswith ("error assembling header:")
869 def test_crypto_fmt_hdr_read (self):
871 ok, hdr = crypto.hdr_make (meta)
873 assert hdr is not None
874 mmeta = crypto.hdr_read (hdr)
875 assert mmeta is not None
877 if meta [k] != mmeta [k]:
878 raise "header mismatch after reading: expected %r, got %r" \
879 % (meta [k], mmeta [k])
882 def test_crypto_fmt_hdr_read_trailing_garbage (self):
884 ok, hdr = crypto.hdr_make (meta)
885 ok, hdr = crypto.hdr_make (meta)
887 assert hdr is not None
889 with self.assertRaises (crypto.InvalidHeader):
890 _ = crypto.hdr_read (hdr)
893 def test_crypto_fmt_hdr_read_leading_garbage (self):
895 ok, hdr = crypto.hdr_make (meta)
896 ok, hdr = crypto.hdr_make (meta)
898 assert hdr is not None
900 with self.assertRaises (crypto.InvalidHeader):
901 _ = crypto.hdr_read (hdr)
904 def test_crypto_fmt_hdr_inner_garbage (self):
906 ok, hdr = crypto.hdr_make (meta)
908 data = hdr[:len(hdr)//2] + b"junk-" + hdr[len(hdr)//2:]
909 with self.assertRaises (crypto.InvalidHeader):
910 _ = crypto.hdr_read (data)