mirror of
https://github.com/borgbackup/borg.git
synced 2026-06-11 01:41:57 -04:00
cosmetic: s/tag/mac/
mac is a more specific term, tag is too general of course it is only a real MAC if we have keys, otherwise it is a hash.
This commit is contained in:
parent
add6bd96e7
commit
3149f6a828
3 changed files with 42 additions and 42 deletions
|
|
@ -10,7 +10,7 @@ API_VERSION = 2
|
|||
AES_CTR_MODE = 1
|
||||
AES_GCM_MODE = 2
|
||||
|
||||
TAG_SIZE = 16 # bytes; 128 bits is the maximum allowed value. see "hack" below.
|
||||
MAC_SIZE = 16 # bytes; 128 bits is the maximum allowed value. see "hack" below.
|
||||
IV_SIZE = 16 # bytes; 128 bits
|
||||
|
||||
cdef extern from "openssl/rand.h":
|
||||
|
|
@ -159,13 +159,13 @@ cdef class AES:
|
|||
if not EVP_DecryptUpdate(&self.ctx, NULL, &outl, aad, aadl):
|
||||
raise Exception('EVP_DecryptUpdate failed')
|
||||
|
||||
def compute_tag_and_encrypt(self, data):
|
||||
def compute_mac_and_encrypt(self, data):
|
||||
cdef int inl = len(data)
|
||||
cdef int ctl = 0
|
||||
cdef int outl = 0
|
||||
# note: modes that use padding, need up to one extra AES block (16B)
|
||||
cdef unsigned char *out = <unsigned char *>malloc(inl+16)
|
||||
cdef unsigned char *tag = <unsigned char *>malloc(TAG_SIZE)
|
||||
cdef unsigned char *mac = <unsigned char *>malloc(MAC_SIZE)
|
||||
if not out:
|
||||
raise MemoryError
|
||||
try:
|
||||
|
|
@ -176,16 +176,16 @@ cdef class AES:
|
|||
raise Exception('EVP_EncryptFinal failed')
|
||||
ctl += outl
|
||||
if self.mode == AES_GCM_MODE:
|
||||
# Get tag (only GCM mode. for CTR, the returned tag is undefined)
|
||||
if not EVP_CIPHER_CTX_ctrl(&self.ctx, EVP_CTRL_GCM_GET_TAG, TAG_SIZE, tag):
|
||||
# Get tag (mac) - only GCM mode. for CTR, the returned mac is undefined
|
||||
if not EVP_CIPHER_CTX_ctrl(&self.ctx, EVP_CTRL_GCM_GET_TAG, MAC_SIZE, mac):
|
||||
raise Exception('EVP_CIPHER_CTX_ctrl GET TAG failed')
|
||||
# hack: caller wants 32B tags (256b), so we give back that amount
|
||||
return (tag[:TAG_SIZE] + b'\x00'*16), out[:ctl]
|
||||
return (mac[:MAC_SIZE] + b'\x00'*16), out[:ctl]
|
||||
finally:
|
||||
free(tag)
|
||||
free(mac)
|
||||
free(out)
|
||||
|
||||
def check_tag_and_decrypt(self, tag, data):
|
||||
def check_mac_and_decrypt(self, mac, data):
|
||||
cdef int inl = len(data)
|
||||
cdef int ptl = 0
|
||||
cdef int outl = 0
|
||||
|
|
@ -200,11 +200,11 @@ cdef class AES:
|
|||
raise Exception('EVP_DecryptUpdate failed')
|
||||
ptl = outl
|
||||
if self.mode == AES_GCM_MODE:
|
||||
# Set expected tag value.
|
||||
if not EVP_CIPHER_CTX_ctrl(&self.ctx, EVP_CTRL_GCM_SET_TAG, TAG_SIZE, tag):
|
||||
# Set expected tag (mac) value.
|
||||
if not EVP_CIPHER_CTX_ctrl(&self.ctx, EVP_CTRL_GCM_SET_TAG, MAC_SIZE, mac):
|
||||
raise Exception('EVP_CIPHER_CTX_ctrl SET TAG failed')
|
||||
if EVP_DecryptFinal_ex(&self.ctx, out+ptl, &outl) <= 0:
|
||||
# for GCM mode, a failure here means corrupted / tampered tag or data
|
||||
# for GCM mode, a failure here means corrupted / tampered tag (mac) or data
|
||||
raise Exception('EVP_DecryptFinal failed')
|
||||
ptl += outl
|
||||
return out[:ptl]
|
||||
|
|
|
|||
44
attic/key.py
44
attic/key.py
|
|
@ -111,8 +111,8 @@ class GHASH:
|
|||
mac_cipher = AES(mode=AES_GCM_MODE, is_encrypt=True, key=self.key, iv=b'\0' * 16)
|
||||
# GMAC = aes-gcm with all data as AAD, no data as to-be-encrypted data
|
||||
mac_cipher.add(bytes(self.data))
|
||||
tag, _ = mac_cipher.compute_tag_and_encrypt(b'')
|
||||
return tag
|
||||
hash, _ = mac_cipher.compute_mac_and_encrypt(b'')
|
||||
return hash
|
||||
|
||||
|
||||
class HMAC_SHA256(HMAC):
|
||||
|
|
@ -202,10 +202,10 @@ class PLAIN:
|
|||
def __init__(self, **kw):
|
||||
pass
|
||||
|
||||
def compute_tag_and_encrypt(self, data):
|
||||
def compute_mac_and_encrypt(self, data):
|
||||
return b'', b'', data
|
||||
|
||||
def check_tag_and_decrypt(self, tag, iv_last8, data):
|
||||
def check_mac_and_decrypt(self, mac, iv_last8, data):
|
||||
return data
|
||||
|
||||
|
||||
|
|
@ -218,22 +218,22 @@ class AES_CTR_HMAC:
|
|||
self.enc_cipher = AES(mode=AES_CTR_MODE, is_encrypt=True, key=enc_key, iv=enc_iv)
|
||||
self.dec_cipher = AES(mode=AES_CTR_MODE, is_encrypt=False, key=enc_key)
|
||||
|
||||
def compute_tag_and_encrypt(self, data):
|
||||
def compute_mac_and_encrypt(self, data):
|
||||
self.enc_cipher.reset(iv=self.enc_iv)
|
||||
iv_last8 = self.enc_iv[8:]
|
||||
_, data = self.enc_cipher.compute_tag_and_encrypt(data)
|
||||
_, data = self.enc_cipher.compute_mac_and_encrypt(data)
|
||||
# increase the IV (counter) value so same value is never used twice
|
||||
current_iv = bytes_to_long(iv_last8)
|
||||
self.enc_iv = PREFIX + long_to_bytes(current_iv + num_aes_blocks(len(data)))
|
||||
tag = HMAC(self.hmac_key, iv_last8 + data, sha256).digest() # XXX mac / hash flexibility
|
||||
return tag, iv_last8, data
|
||||
mac = HMAC(self.hmac_key, iv_last8 + data, sha256).digest() # XXX mac / hash flexibility
|
||||
return mac, iv_last8, data
|
||||
|
||||
def check_tag_and_decrypt(self, tag, iv_last8, data):
|
||||
def check_mac_and_decrypt(self, mac, iv_last8, data):
|
||||
iv = PREFIX + iv_last8
|
||||
if HMAC(self.hmac_key, iv_last8 + data, sha256).digest() != tag:
|
||||
if HMAC(self.hmac_key, iv_last8 + data, sha256).digest() != mac:
|
||||
raise IntegrityError('Encryption envelope checksum mismatch')
|
||||
self.dec_cipher.reset(iv=iv)
|
||||
data = self.dec_cipher.check_tag_and_decrypt(None, data)
|
||||
data = self.dec_cipher.check_mac_and_decrypt(None, data)
|
||||
return data
|
||||
|
||||
|
||||
|
|
@ -246,22 +246,22 @@ class AES_GCM:
|
|||
self.enc_cipher = AES(mode=AES_GCM_MODE, is_encrypt=True, key=enc_key, iv=enc_iv)
|
||||
self.dec_cipher = AES(mode=AES_GCM_MODE, is_encrypt=False, key=enc_key)
|
||||
|
||||
def compute_tag_and_encrypt(self, data):
|
||||
def compute_mac_and_encrypt(self, data):
|
||||
self.enc_cipher.reset(iv=self.enc_iv)
|
||||
iv_last8 = self.enc_iv[8:]
|
||||
self.enc_cipher.add(iv_last8)
|
||||
tag, data = self.enc_cipher.compute_tag_and_encrypt(data)
|
||||
mac, data = self.enc_cipher.compute_mac_and_encrypt(data)
|
||||
# increase the IV (counter) value so same value is never used twice
|
||||
current_iv = bytes_to_long(iv_last8)
|
||||
self.enc_iv = PREFIX + long_to_bytes(current_iv + num_aes_blocks(len(data)))
|
||||
return tag, iv_last8, data
|
||||
return mac, iv_last8, data
|
||||
|
||||
def check_tag_and_decrypt(self, tag, iv_last8, data):
|
||||
def check_mac_and_decrypt(self, mac, iv_last8, data):
|
||||
iv = PREFIX + iv_last8
|
||||
self.dec_cipher.reset(iv=iv)
|
||||
self.dec_cipher.add(iv_last8)
|
||||
try:
|
||||
data = self.dec_cipher.check_tag_and_decrypt(tag, data)
|
||||
data = self.dec_cipher.check_mac_and_decrypt(mac, data)
|
||||
except Exception:
|
||||
raise IntegrityError('Encryption envelope checksum mismatch')
|
||||
return data
|
||||
|
|
@ -300,7 +300,7 @@ class KeyBase(object):
|
|||
|
||||
def encrypt(self, data):
|
||||
data = self.compressor.compress(data)
|
||||
mac, iv_last8, data = self.cipher.compute_tag_and_encrypt(data)
|
||||
mac, iv_last8, data = self.cipher.compute_mac_and_encrypt(data)
|
||||
meta = Meta(compr_type=self.compressor.TYPE, key_type=self.TYPE,
|
||||
mac_type=self.maccer_cls.TYPE, cipher_type=self.cipher.TYPE,
|
||||
stored_iv=iv_last8)
|
||||
|
|
@ -312,7 +312,7 @@ class KeyBase(object):
|
|||
assert isinstance(self, keyer)
|
||||
assert self.maccer_cls is maccer
|
||||
assert self.cipher_cls is cipher
|
||||
data = self.cipher.check_tag_and_decrypt(mac, meta.stored_iv, data)
|
||||
data = self.cipher.check_mac_and_decrypt(mac, meta.stored_iv, data)
|
||||
data = self.compressor.decompress(data)
|
||||
if id and self.id_hash(data) != id:
|
||||
raise IntegrityError('Chunk id verification failed')
|
||||
|
|
@ -486,7 +486,7 @@ class KeyfileKey(AESKeyBase):
|
|||
key = pbkdf2_sha256(passphrase.encode('utf-8'), d[b'salt'], d[b'iterations'], 32)
|
||||
try:
|
||||
cipher = AES(mode=AES_GCM_MODE, is_encrypt=False, key=key, iv=b'\0'*16)
|
||||
data = cipher.check_tag_and_decrypt(d[b'hash'], d[b'data'])
|
||||
data = cipher.check_mac_and_decrypt(d[b'hash'], d[b'data'])
|
||||
return data
|
||||
except Exception:
|
||||
return None
|
||||
|
|
@ -496,13 +496,13 @@ class KeyfileKey(AESKeyBase):
|
|||
iterations = 100000
|
||||
key = pbkdf2_sha256(passphrase.encode('utf-8'), salt, iterations, 32)
|
||||
cipher = AES(mode=AES_GCM_MODE, is_encrypt=True, key=key, iv=b'\0'*16)
|
||||
tag, cdata = cipher.compute_tag_and_encrypt(data)
|
||||
mac, cdata = cipher.compute_mac_and_encrypt(data)
|
||||
d = {
|
||||
'version': 1,
|
||||
'salt': salt,
|
||||
'iterations': iterations,
|
||||
'algorithm': 'gmac',
|
||||
'hash': tag,
|
||||
'hash': mac,
|
||||
'data': cdata,
|
||||
}
|
||||
return msgpack.packb(d)
|
||||
|
|
@ -655,7 +655,7 @@ def parser02(all_data):
|
|||
def parser03(all_data): # new & flexible
|
||||
"""
|
||||
Payload layout:
|
||||
always: TYPE(1) + MSGPACK((tag, meta, data))
|
||||
always: TYPE(1) + MSGPACK((mac, meta, data))
|
||||
|
||||
meta is a Meta namedtuple and contains all required information about data.
|
||||
data is maybe compressed (see meta) and maybe encrypted (see meta).
|
||||
|
|
|
|||
|
|
@ -34,11 +34,11 @@ class CryptoTestCase(AtticTestCase):
|
|||
data = b'foo' * 10
|
||||
# encrypt
|
||||
aes = AES(mode=AES_CTR_MODE, is_encrypt=True, key=key, iv=iv)
|
||||
_, cdata = aes.compute_tag_and_encrypt(data)
|
||||
_, cdata = aes.compute_mac_and_encrypt(data)
|
||||
self.assert_equal(hexlify(cdata), b'c6efb702de12498f34a2c2bbc8149e759996d08bf6dc5c610aefc0c3a466')
|
||||
# decrypt (correct tag/cdata)
|
||||
# decrypt (correct mac/cdata)
|
||||
aes = AES(mode=AES_CTR_MODE, is_encrypt=False, key=key, iv=iv)
|
||||
pdata = aes.check_tag_and_decrypt(None, cdata)
|
||||
pdata = aes.check_mac_and_decrypt(None, cdata)
|
||||
self.assert_equal(data, pdata)
|
||||
|
||||
def test_aes_gcm(self):
|
||||
|
|
@ -47,14 +47,14 @@ class CryptoTestCase(AtticTestCase):
|
|||
data = b'foo' * 10
|
||||
# encrypt
|
||||
aes = AES(mode=AES_GCM_MODE, is_encrypt=True, key=key, iv=iv)
|
||||
tag, cdata = aes.compute_tag_and_encrypt(data)
|
||||
self.assert_equal(hexlify(tag), b'c98aa10eb6b7031bcc2160878d9438fb00000000000000000000000000000000')
|
||||
mac, cdata = aes.compute_mac_and_encrypt(data)
|
||||
self.assert_equal(hexlify(mac), b'c98aa10eb6b7031bcc2160878d9438fb00000000000000000000000000000000')
|
||||
self.assert_equal(hexlify(cdata), b'841bcce405df769d22ee9f7f012edf5dc7fb2594d924c7400ffd050f2741')
|
||||
# decrypt (correct tag/cdata)
|
||||
# decrypt (correct mac/cdata)
|
||||
aes = AES(mode=AES_GCM_MODE, is_encrypt=False, key=key, iv=iv)
|
||||
pdata = aes.check_tag_and_decrypt(tag, cdata)
|
||||
pdata = aes.check_mac_and_decrypt(mac, cdata)
|
||||
self.assert_equal(data, pdata)
|
||||
# decrypt (incorrect tag/cdata)
|
||||
# decrypt (incorrect mac/cdata)
|
||||
aes = AES(mode=AES_GCM_MODE, is_encrypt=False, key=key, iv=iv)
|
||||
cdata = b'x' + cdata[1:] # corrupt cdata
|
||||
self.assertRaises(Exception, aes.check_tag_and_decrypt, tag, cdata)
|
||||
self.assertRaises(Exception, aes.check_mac_and_decrypt, mac, cdata)
|
||||
|
|
|
|||
Loading…
Reference in a new issue