Skip to content

Commit

Permalink
Add encryption mode with keyed hash nonce, issue linuxboot#159
Browse files Browse the repository at this point in the history
  • Loading branch information
tasket committed Apr 30, 2023
1 parent 9d2b271 commit e04116b
Showing 1 changed file with 49 additions and 6 deletions.
55 changes: 49 additions & 6 deletions src/wyng
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,7 @@ class DataCryptography:
b"10": ("aes-256-siv", "aes-256-siv"),
b"20": ("aes-256-cbc", "aes-256-siv"),
b"30": ("xchacha20", "xchacha20-poly1305"),
b"33": ("xchacha20-t1", "xchacha20-poly1305-t1"),
b"40": ("xchacha20-poly1305", "xchacha20-poly1305")}

__slots__ = ("key","keyfile","ci_type","counter","ctstart","ctcadence","countsz","max_count",
Expand All @@ -778,6 +779,9 @@ class DataCryptography:
assert passphrase is None or type(passphrase) == bytearray
assert type(cadence) is int and cadence > 0

if ci_type.startswith("xchacha20") and Cryptodome.version_info[0:2] < (3,9):
raise RuntimeError("Cryptodome version >= 3.9 required for xchacha20 cipher.")

if not issubclass(type(keyfile), io.IOBase):
if not exists(keyfile) and init: open(keyfile, "wb").close()
keyfile = open(keyfile, "r+b", buffering=0)
Expand Down Expand Up @@ -805,8 +809,6 @@ class DataCryptography:
self.decrypt = self.auth = self._dec_aes_256_siv

elif ci_type == "xchacha20":
if Cryptodome.version_info[0:2] < (3,9):
raise RuntimeError("Cryptodome version >= 3.9 required for xchacha20 cipher.")
self.key_sz = kbits//8 ; self.max_count = 2**80-64
self.nonce_sz= 24 ; self.buf_start = self.nonce_sz
self.countsz = self.max_count.bit_length() // 8
Expand All @@ -816,8 +818,6 @@ class DataCryptography:
self.decrypt = self._dec_chacha20

elif ci_type == "xchacha20-poly1305":
if Cryptodome.version_info[0:2] < (3,9):
raise RuntimeError("Cryptodome version >= 3.9 required for xchacha20 cipher.")
self.key_sz = kbits//8 ; self.max_count = 2**80-64 ; self.tag_sz = 16
self.nonce_sz= 24 ; self.buf_start = self.nonce_sz + self.tag_sz
self.countsz = self.max_count.bit_length() // 8
Expand All @@ -826,6 +826,22 @@ class DataCryptography:
self.encrypt = self._enc_chacha20_poly1305
self.decrypt = self.auth = self._dec_chacha20_poly1305

elif ci_type == "xchacha20-t1":
self.key_sz = kbits//8 ; self.max_count = 2**80-64
self.nonce_sz= 24 ; self.buf_start = self.nonce_sz
self.countsz = self.max_count.bit_length() // 8
self.ChaCha20_new = Cipher_ChaCha20.new
self.encrypt = self._enc_chacha20_t1
self.decrypt = self._dec_chacha20

elif ci_type == "xchacha20-poly1305-t1":
self.key_sz = kbits//8 ; self.max_count = 2**80-64 ; self.tag_sz = 16
self.nonce_sz= 24 ; self.buf_start = self.nonce_sz + self.tag_sz
self.countsz = self.max_count.bit_length() // 8
self.ChaCha20_Poly1305_new = Cipher_ChaCha20_Poly1305.new
self.encrypt = self._enc_chacha20_poly1305_t1
self.decrypt = self.auth = self._dec_chacha20_poly1305

else:
raise ValueError("Invalid cipher spec "+ci_type)

Expand Down Expand Up @@ -938,6 +954,33 @@ class DataCryptography:
cipher = self.ChaCha20_Poly1305_new(key=self.key, nonce=nonce)
return cipher.decrypt_and_verify(untrusted_buf[self.buf_start:], ci_tag)

# Encrypt [X]ChaCha20 (hash nonce)
def _enc_chacha20_t1(self, buf):
self.counter += 1
if self.counter % self.ctcadence == 0: self.save_counter()
if self.counter > self.max_count: raise ValueError("Key exhaustion.")

# Nonce from keyed hash of rnd || buf
nonce_h = hashlib.blake2b(self.get_rnd(24), key=self.key, digest_size=self.nonce_sz)
nonce_h.update(buf)
nonce = nonce_h.digest()
cipher = self.ChaCha20_new(key=self.key, nonce=nonce)
return nonce, cipher.encrypt(buf)

# Encrypt [X]ChaCha20-Poly1305 (hash nonce)
def _enc_chacha20_poly1305_t1(self, buf):
self.counter += 1
if self.counter % self.ctcadence == 0: self.save_counter()
if self.counter > self.max_count: raise ValueError("Key exhaustion.")

# Nonce composed from: 32bit current time offset + 80bit rnd + 80bit counter
nonce_h = hashlib.blake2b(self.get_rnd(24), key=self.key, digest_size=self.nonce_sz)
nonce_h.update(buf)
nonce = nonce_h.digest()
cipher = self.ChaCha20_Poly1305_new(key=self.key, nonce=nonce)
buf, ci_tag = cipher.encrypt_and_digest(buf)
return b''.join((nonce, ci_tag)), buf


# Define absolute paths of commands

Expand Down Expand Up @@ -1508,7 +1551,7 @@ def arch_init(aset, opts):

aset.data_cipher = opts.encrypt.lower()
# Fix: duplicates code in aset... move to aset class.
if aset.data_cipher in ("off","xchacha20"):
if aset.data_cipher in ("off","xchacha20","xchacha20-t1"):
#if aset.data_cipher in (x[0] for x in DataCryptography.crypto_codes.values()):
aset.ci_mode, ci= [(x,y) for x,y in DataCryptography.crypto_codes.items()
if y[0] == aset.data_cipher][0]
Expand Down Expand Up @@ -4047,7 +4090,7 @@ def cleanup():

# Constants / Globals
prog_name = "wyng"
prog_version = "0.4alpha3" ; prog_date = "20230427"
prog_version = "0.4alpha3" ; prog_date = "20230429"
format_version = 3 ; debug = False ; tmpdir = None
admin_permission = os.getuid() == 0
time_start = time.time()
Expand Down

0 comments on commit e04116b

Please sign in to comment.