def b(s):
return s.encode("UTF-8")
-TEST_PLAINTEXT = b("gentlemen don’t read each other’s mail")
-TEST_PASSPHRASE = b"test1234"
-TEST_AES_GCM_AAD = b"authenticated plain text"
-
-CRYPTO_NACL_SIZE = 12
+CRYPTO_NACL_SIZE = 16
CRYPTO_KEY_SIZE = 16
-CRYPTO_TAG_SIZE = 16
+
+TEST_PLAINTEXT = b("gentlemen don’t read each other’s mail")
+TEST_PASSPHRASE = b"test1234"
+TEST_AES_GCM_AAD = b"authenticated plain text"
+TEST_DUMMY_FILENAME = "insurance-file.txt"
+TEST_VERSION = 1
+TEST_PARAMVERSION = 1
+TEST_STATIC_NACL = os.urandom (CRYPTO_NACL_SIZE)
def faux_hdr (ctsize=1337, iv=None):
return \
, "iv" : iv or binascii.unhexlify(b"0011223344556677"
b"8899aabb")
, "ctsize" : ctsize
+ , "tag" : binascii.unhexlify(b"deadbeefbadb100d"
+ b"b1eedc0ffeedea15")
}
class AESGCMTest (CryptoLayerTest):
- def test_crypto_aes_gcm_enc_simple (self):
- NaCl = os.urandom (CRYPTO_NACL_SIZE)
- key = os.urandom (CRYPTO_KEY_SIZE)
- enc = crypto.AES_GCM_context (crypto.ENCRYPT, key, TEST_AES_GCM_AAD)
-
-
- def test_crypto_aes_gcm_enc_tag_retrieve (self):
- NaCl = os.urandom (CRYPTO_NACL_SIZE)
- key = os.urandom (CRYPTO_KEY_SIZE)
- enc = crypto.AES_GCM_context (crypto.ENCRYPT, key, TEST_AES_GCM_AAD)
- ok, ct = enc.process_chunk (TEST_PLAINTEXT)
- if ok is False or ct is None:
- raise "error encrypting chunk [%s]" % TEST_PLAINTEXT
- ok, ct, tag = enc.done ()
- if ok is False or ct is None:
- raise "error finalizing encryption"
- if not tag:
- raise "no tag received upon completing the encryption"
-
-
- def test_crypto_aes_gcm_enc_tag_size (self):
- NaCl = os.urandom (CRYPTO_NACL_SIZE)
- key = os.urandom (CRYPTO_KEY_SIZE)
- enc = crypto.AES_GCM_context (crypto.ENCRYPT, key, TEST_AES_GCM_AAD)
- ok, ct = enc.process_chunk (TEST_PLAINTEXT)
- if ok is False or ct is None:
- raise "error encrypting chunk [%s]" % TEST_PLAINTEXT
- ok, ct, tag = enc.done ()
- if ok is False or ct is None:
- raise "error finalizing encryption"
- if not tag:
- raise "no tag received upon completing the encryption"
- assert len (tag) == CRYPTO_TAG_SIZE
+ def test_crypto_aes_gcm_enc_ctor (self):
+ password = str (os.urandom (42))
+ encryptor = crypto.Encrypt (password, TEST_VERSION,
+ TEST_PARAMVERSION, nacl=TEST_STATIC_NACL)
+
+
+ def test_crypto_aes_gcm_enc_header_size (self):
+ password = str (os.urandom (42))
+ encryptor = crypto.Encrypt (password, TEST_VERSION,
+ TEST_PARAMVERSION,
+ nacl=TEST_STATIC_NACL)
+
+ header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
+ assert len (header_dummy) == crypto.PDTCRYPT_HDR_SIZE
+ _ = encryptor.process (TEST_PLAINTEXT)
+ _, header, _ = encryptor.done (header_dummy)
+ assert len (header) == crypto.PDTCRYPT_HDR_SIZE
def test_crypto_aes_gcm_enc_chunk_size (self):
- NaCl = os.urandom (CRYPTO_NACL_SIZE)
- key = os.urandom (CRYPTO_KEY_SIZE)
- enc = crypto.AES_GCM_context (crypto.ENCRYPT, key, TEST_AES_GCM_AAD)
- ok, ct = enc.process_chunk (TEST_PLAINTEXT)
- if ok is False or ct is None:
- raise "error encrypting chunk [%s]" % TEST_PLAINTEXT
- assert len (ct) == len (TEST_PLAINTEXT)
- ok, ct, tag = enc.done ()
- if ok is False or ct is None:
- raise "error finalizing encryption"
- if not tag:
- raise "no tag received upon completing the encryption"
- assert len (ct) == 0
+ password = str (os.urandom (42))
+ encryptor = crypto.Encrypt (password, TEST_VERSION,
+ TEST_PARAMVERSION,
+ nacl=TEST_STATIC_NACL)
+
+ header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
+ ciphertext = encryptor.process (TEST_PLAINTEXT)
+ assert len (ciphertext) == len (TEST_PLAINTEXT)
+ rest, header, fixed = encryptor.done (header_dummy)
+ assert len (rest) == 0
def test_crypto_aes_gcm_dec_simple (self):
- NaCl = os.urandom (CRYPTO_NACL_SIZE)
- key = os.urandom (CRYPTO_KEY_SIZE)
- enc = crypto.AES_GCM_context (crypto.ENCRYPT, key, TEST_AES_GCM_AAD)
- iv = enc.iv
- dec = crypto.AES_GCM_context (crypto.DECRYPT, key, TEST_AES_GCM_AAD, iv = iv)
- ok, ct = enc.process_chunk (TEST_PLAINTEXT)
- ok, _, tag = enc.done ()
- ok, pt = dec.process_chunk (ct)
- ok, _, _ = dec.done (tag)
- assert pt == TEST_PLAINTEXT
-
-
- def test_crypto_aes_gcm_dec_missing_tag (self):
- NaCl = os.urandom (CRYPTO_NACL_SIZE)
- key = os.urandom (CRYPTO_KEY_SIZE)
- enc = crypto.AES_GCM_context (crypto.ENCRYPT, key, TEST_AES_GCM_AAD)
- iv = enc.iv
- dec = crypto.AES_GCM_context (crypto.DECRYPT, key, TEST_AES_GCM_AAD, iv = iv)
- ok, ct = enc.process_chunk (TEST_PLAINTEXT)
- ok, _, tag = enc.done ()
- ok, pt = dec.process_chunk (ct)
- with pytest.raises (ValueError):
- ok, _, _ = dec.done ()
+ password = str (os.urandom (42))
+ encryptor = crypto.Encrypt (password, TEST_VERSION,
+ TEST_PARAMVERSION,
+ nacl=TEST_STATIC_NACL)
+
+ header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
+ ciphertext = encryptor.process (TEST_PLAINTEXT)
+ rest, header, fixed = encryptor.done (header_dummy)
+ ciphertext += rest
+
+ decryptor = crypto.Decrypt (password, fixedparts=fixed)
+ decryptor.next (header)
+ plaintext = decryptor.process (ciphertext)
+ ok, rest = decryptor.done ()
+ plaintext += rest
+
+ assert ok
+ assert plaintext == TEST_PLAINTEXT
def test_crypto_aes_gcm_dec_bad_tag (self):
- NaCl = os.urandom (CRYPTO_NACL_SIZE)
- key = os.urandom (CRYPTO_KEY_SIZE)
- enc = crypto.AES_GCM_context (crypto.ENCRYPT, key, TEST_AES_GCM_AAD)
- iv = enc.iv
- dec = crypto.AES_GCM_context (crypto.DECRYPT, key, TEST_AES_GCM_AAD, iv = iv)
- ok, ct = enc.process_chunk (TEST_PLAINTEXT)
- ok, _, tag = enc.done ()
- ok, pt = dec.process_chunk (ct)
- with pytest.raises (cryptography.exceptions.InvalidTag):
- tag = tag[1:] + b"X"
- ok, _, _ = dec.done (tag)
+ password = str (os.urandom (42))
+ encryptor = crypto.Encrypt (password, TEST_VERSION,
+ TEST_PARAMVERSION,
+ nacl=TEST_STATIC_NACL)
+
+ header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
+ ciphertext = encryptor.process (TEST_PLAINTEXT)
+ ciphertext2, header, fixed = encryptor.done (header_dummy)
+
+ mut_header = bytearray (header)
+ mut_header_vw = memoryview (mut_header)
+ # replace one byte in the tag part of the header
+ second_byte = mut_header_vw [crypto.HDR_OFF_TAG + 2]
+ mut_header_vw [crypto.HDR_OFF_TAG + 2] = (second_byte + 0x2a) % 256
+ header = bytes (mut_header)
+
+ decryptor = crypto.Decrypt (password, fixedparts=fixed)
+ decryptor.next (header)
+ plaintext = decryptor.process (ciphertext)
+ ok, err = decryptor.done ()
+
+ assert ok is False
+ assert err == "InvalidTag()"
def test_crypto_aes_gcm_enc_multicnk (self):
cnksiz = 1 << 10
- orig_pt = fill_mod (1 << 14)
- NaCl = os.urandom (CRYPTO_NACL_SIZE)
- key = os.urandom (CRYPTO_KEY_SIZE)
- enc = crypto.AES_GCM_context (crypto.ENCRYPT, key, TEST_AES_GCM_AAD)
- iv = enc.iv
- dec = crypto.AES_GCM_context (crypto.DECRYPT, key, TEST_AES_GCM_AAD, iv = iv)
+ pt = fill_mod (1 << 14)
+ password = str (os.urandom (42))
+ encryptor = crypto.Encrypt (password, TEST_VERSION,
+ TEST_PARAMVERSION,
+ nacl=TEST_STATIC_NACL)
+ header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
off = 0
ct = b""
- while off < len (orig_pt):
- upto = min (off + cnksiz, len (orig_pt))
- ok, cnk = enc.process_chunk (orig_pt [off:upto])
- assert ok
+ while off < len (pt):
+ upto = min (off + cnksiz, len (pt))
+ cnk = encryptor.process (pt [off:upto])
ct += cnk
off += cnksiz
- ok, _, tag = enc.done ()
- assert ok
- assert tag
- assert len (ct) == len (orig_pt)
+ cnk, header, fixed = encryptor.done (header_dummy)
+ ct += cnk
+
+ assert len (pt) == len (ct)
def test_crypto_aes_gcm_dec_multicnk (self):
- cnksiz = 1 << 10
- orig_pt = fill_mod (1 << 14)
- NaCl = os.urandom (CRYPTO_NACL_SIZE)
- key = os.urandom (CRYPTO_KEY_SIZE)
- enc = crypto.AES_GCM_context (crypto.ENCRYPT, key, TEST_AES_GCM_AAD)
- iv = enc.iv
- dec = crypto.AES_GCM_context (crypto.DECRYPT, key, TEST_AES_GCM_AAD, iv = iv)
+ cnksiz = 1 << 10
+ orig_pt = fill_mod (1 << 14)
+ password = str (os.urandom (42))
+ encryptor = crypto.Encrypt (password, TEST_VERSION,
+ TEST_PARAMVERSION,
+ nacl=TEST_STATIC_NACL)
+ header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
off = 0
ct = b""
while off < len (orig_pt):
upto = min (off + cnksiz, len (orig_pt))
- ok, cnk = enc.process_chunk (orig_pt [off:upto])
+ cnk = encryptor.process (orig_pt [off:upto])
ct += cnk
off += cnksiz
- ok, _, tag = enc.done ()
+ cnk, header, fixed = encryptor.done (header_dummy)
+ ct += cnk
+ decryptor = crypto.Decrypt (password, fixedparts=fixed)
+ decryptor.next (header)
off = 0
- pt = b""
+ pt = b""
while off < len (orig_pt):
upto = min (off + cnksiz, len (orig_pt))
- ok, cnk = dec.process_chunk (ct [off:upto])
+ cnk = decryptor.process (ct [off:upto])
pt += cnk
off += cnksiz
- ok, _, _ = dec.done (tag)
+ ok, cnk = decryptor.done ()
+ assert ok
+
+ pt += cnk
assert pt == orig_pt
def test_crypto_aes_gcm_dec_multicnk_bad_tag (self):
- cnksiz = 1 << 10
- orig_pt = fill_mod (1 << 14)
- NaCl = os.urandom (CRYPTO_NACL_SIZE)
- key = os.urandom (CRYPTO_KEY_SIZE)
- enc = crypto.AES_GCM_context (crypto.ENCRYPT, key, TEST_AES_GCM_AAD)
- iv = enc.iv
- dec = crypto.AES_GCM_context (crypto.DECRYPT, key, TEST_AES_GCM_AAD, iv = iv)
+ cnksiz = 1 << 10
+ orig_pt = fill_mod (1 << 14)
+ password = str (os.urandom (42))
+ encryptor = crypto.Encrypt (password, TEST_VERSION,
+ TEST_PARAMVERSION,
+ nacl=TEST_STATIC_NACL)
+ header_dummy = encryptor.next (TEST_DUMMY_FILENAME)
off = 0
ct = b""
while off < len (orig_pt):
upto = min (off + cnksiz, len (orig_pt))
- ok, cnk = enc.process_chunk (orig_pt [off:upto])
+ cnk = encryptor.process (orig_pt [off:upto])
ct += cnk
off += cnksiz
- ok, _, tag = enc.done ()
-
+ cnk, header, fixed = encryptor.done (header_dummy)
+ ct += cnk
+
+ mut_header = bytearray (header)
+ mut_header_vw = memoryview (mut_header)
+ # replace one byte in the tag part of the header
+ second_byte = mut_header_vw [crypto.HDR_OFF_TAG + 2]
+ mut_header_vw [crypto.HDR_OFF_TAG + 2] = (second_byte + 0x2a) % 256
+ header = bytes (mut_header)
+
+ decryptor = crypto.Decrypt (password, fixedparts=fixed)
+ decryptor.next (header)
off = 0
- pt = b""
+ pt = b""
while off < len (orig_pt):
upto = min (off + cnksiz, len (orig_pt))
- ok, cnk = dec.process_chunk (ct [off:upto])
+ cnk = decryptor.process (ct [off:upto])
pt += cnk
off += cnksiz
- with pytest.raises (cryptography.exceptions.InvalidTag):
- tag = b"Y" + tag[:-1]
- ok, _, _ = dec.done (tag)
-
-
- def test_crypto_aes_gcm_dec_multicnk_missing_tag (self):
- cnksiz = 1 << 10
- orig_pt = fill_mod (1 << 14)
- NaCl = os.urandom (CRYPTO_NACL_SIZE)
- key = os.urandom (CRYPTO_KEY_SIZE)
- enc = crypto.AES_GCM_context (crypto.ENCRYPT, key, TEST_AES_GCM_AAD)
- iv = enc.iv
- dec = crypto.AES_GCM_context (crypto.DECRYPT, key, TEST_AES_GCM_AAD, iv = iv)
-
- off = 0
- ct = b""
- while off < len (orig_pt):
- upto = min (off + cnksiz, len (orig_pt))
- ok, cnk = enc.process_chunk (orig_pt [off:upto])
- ct += cnk
- off += cnksiz
- ok, _, tag = enc.done ()
-
- off = 0
- pt = b""
- while off < len (orig_pt):
- upto = min (off + cnksiz, len (orig_pt))
- ok, cnk = dec.process_chunk (ct [off:upto])
- pt += cnk
- off += cnksiz
-
- with pytest.raises (ValueError):
- ok, _, _ = dec.done ()
-
-
-class ScryptTest (CryptoLayerTest):
-
- nacl_len = 16
- nacl = binascii.unhexlify(b"0011223344556677"
- b"8899aabbccddeeff")
-
-# def test_scrypt_keygen (self):
-# nacl, k = crypto.scrypt_derive (TEST_PASSPHRASE, self.nacl)
-# assert len (k) == CRYPTO_KEY_SIZE
-# assert nacl == self.nacl
-
- ## excessively slow, so disabled
-# def test_scrypt_keygen_salt_random (self):
-# _, salted_a = crypto.scrypt_derive (TEST_PASSPHRASE, None)
-# _, salted_b = crypto.scrypt_derive (TEST_PASSPHRASE, None)
-# assert salted_a != salted_b
+ ok, err = decryptor.done ()
+ assert ok is False
+ assert err == "InvalidTag()"
class HeaderTest (CryptoLayerTest):
meta = faux_hdr()
ok, hdr = crypto.hdr_make (meta)
assert ok
- assert len (hdr) == crypto.I2N_HDR_SIZE
+ assert len (hdr) == crypto.PDTCRYPT_HDR_SIZE
def test_crypto_fmt_hdr_make_useless (self):
def test_crypto_fmt_hdr_read (self):
meta = faux_hdr()
ok, hdr = crypto.hdr_make (meta)
- assert ok
- ok, mmeta = crypto.hdr_read (hdr)
- assert ok
+ assert ok is True
+ assert hdr is not None
+ mmeta = crypto.hdr_read (hdr)
+ assert mmeta is not None
for k in meta:
if meta [k] != mmeta [k]:
raise "header mismatch after reading: expected %r, got %r" \
def test_crypto_fmt_hdr_read_trailing_garbage (self):
meta = faux_hdr()
ok, hdr = crypto.hdr_make (meta)
+ ok, hdr = crypto.hdr_make (meta)
+ assert ok is True
+ assert hdr is not None
hdr += b"-junk"
- ok, msg = crypto.hdr_read (hdr)
- assert ok is False
- assert msg.startswith ("error reading header from")
+ with pytest.raises (crypto.InvalidHeader):
+ _ = crypto.hdr_read (hdr)
def test_crypto_fmt_hdr_read_leading_garbage (self):
meta = faux_hdr()
ok, hdr = crypto.hdr_make (meta)
+ ok, hdr = crypto.hdr_make (meta)
+ assert ok is True
+ assert hdr is not None
hdr = b"junk-" + hdr
- ok, msg = crypto.hdr_read (hdr)
- assert ok is False
- assert msg.startswith ("error reading header from")
+ with pytest.raises (crypto.InvalidHeader):
+ _ = crypto.hdr_read (hdr)
def test_crypto_fmt_hdr_inner_garbage (self):
meta = faux_hdr()
ok, hdr = crypto.hdr_make (meta)
- hdr = hdr[:len(hdr)//2] + b"junk-" + hdr[len(hdr)//2:]
- ok, msg = crypto.hdr_read (hdr)
- assert ok is False
- assert msg.startswith ("error reading header from")
-
-class TagTest (CryptoLayerTest):
-
- def test_crypto_tag_fmt (self):
- key = os.urandom (CRYPTO_KEY_SIZE)
- enc = crypto.AES_GCM_context (crypto.ENCRYPT, key, TEST_AES_GCM_AAD)
- ok, _ = enc.process_chunk (TEST_PLAINTEXT)
- assert ok
- ok, _, tag = enc.done ()
- assert ok
- assert tag
- tagged = crypto.tag_fmt (tag)
- assert len (tagged) == CRYPTO_TAG_SIZE
-
-
- def test_crypto_tag_read (self):
- key = os.urandom (CRYPTO_KEY_SIZE)
- enc = crypto.AES_GCM_context (crypto.ENCRYPT, key, TEST_AES_GCM_AAD)
- ok, _ = enc.process_chunk (TEST_PLAINTEXT)
- assert ok
- ok, _, tag = enc.done ()
- assert ok
- assert tag
- tagged = crypto.tag_fmt (tag)
- (ok, ttag) = crypto.tag_read (tagged)
assert ok
- assert tag == ttag
+ data = hdr[:len(hdr)//2] + b"junk-" + hdr[len(hdr)//2:]
+ with pytest.raises (crypto.InvalidHeader):
+ _ = crypto.hdr_read (data)