}
-def fill_mod (n):
+def fill_mod (n, off=0):
buf = bytearray (n)
bufv = memoryview (buf)
for i in range (n):
- c = i % 64 + 32
+ off += 1
+ c = off % 64 + 32
struct.pack_into ("c", bufv, i, chr(c).encode("UTF-8"))
return bytes (buf)
pass
+ def test_crypto_aes_gcm_dec_iv_reuse (self):
+ """
+ Meddle with encrypted content: extract the IV from one object
+ and inject it into the header of another. This must be rejected
+ by the decryptor.
+ """
+ cnksiz = 1 << 10
+ orig_pt_1 = fill_mod (1 << 10)
+ orig_pt_2 = fill_mod (1 << 10, 42)
+ password = str (os.urandom (42))
+ encryptor = crypto.Encrypt (password, TEST_VERSION,
+ TEST_PARAMVERSION,
+ nacl=TEST_STATIC_NACL)
+
+ def enc (pt):
+ header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
+
+ off = 0
+ ct = b""
+ while off < len (pt):
+ upto = min (off + cnksiz, len (pt))
+ cnk = encryptor.process (pt [off:upto])
+ ct += cnk
+ off += cnksiz
+ cnk, header, fixed = encryptor.done (header_dummy)
+ return ct + cnk, header, fixed
+
+ ct_1, hdr_1, _____ = enc (orig_pt_1)
+ ct_2, hdr_2, fixed = enc (orig_pt_2)
+
+ mut_hdr_2 = bytearray (hdr_2)
+ mut_hdr_2_vw = memoryview (mut_hdr_2)
+ # get IV
+ iv_lo = crypto.HDR_OFF_IV
+ iv_hi = crypto.HDR_OFF_IV + crypto.PDTCRYPT_HDR_SIZE_IV
+ iv_1 = hdr_1 [iv_lo : iv_hi]
+ # transplant into other header
+ mut_hdr_2_vw [iv_lo : iv_hi] = iv_1
+ hdr_2_mod = bytes (mut_hdr_2)
+ decryptor = crypto.Decrypt (password, fixedparts=fixed,
+ strict_ivs=True)
+
+ def dec (hdr, ct):
+ decryptor.next (hdr)
+ off = 0
+ pt = b""
+ while off < len (ct):
+ upto = min (off + cnksiz, len (ct))
+ cnk = decryptor.process (ct [off:upto])
+ pt += cnk
+ off += cnksiz
+ return pt + decryptor.done ()
+
+ decr_pt_1 = dec (hdr_1, ct_1)
+ decr_pt_2 = dec (hdr_2, ct_2) # good header, different IV
+ try:
+ decr_pt_2 = dec (hdr_2_mod, ct_2)
+ except crypto.DuplicateIV: # bad header, reuse detected
+ pass
+
+
class HeaderTest (CryptoLayerTest):
def test_crypto_fmt_hdr_make (self):