mirror of
https://github.com/borgbackup/borg.git
synced 2026-06-11 09:59:19 -04:00
allow different MACs, implement blake2b MAC
This commit is contained in:
parent
945b5e25e2
commit
68ef5e8a4b
2 changed files with 98 additions and 34 deletions
|
|
@ -223,12 +223,10 @@ class UNENCRYPTED:
|
|||
return 0
|
||||
|
||||
|
||||
cdef class AES256_CTR_HMAC_SHA256:
|
||||
# Layout: HEADER + HMAC 32 + IV 8 + CT (same as attic / borg < 1.2 IF HEADER = TYPE_BYTE, no AAD)
|
||||
cdef class AES256_CTR_BASE:
|
||||
# Layout: HEADER + MAC 32 + IV 8 + CT (same as attic / borg < 1.2 IF HEADER = TYPE_BYTE, no AAD)
|
||||
|
||||
cdef EVP_CIPHER_CTX *ctx
|
||||
cdef HMAC_CTX *hmac_ctx
|
||||
cdef unsigned char *mac_key
|
||||
cdef unsigned char *enc_key
|
||||
cdef int cipher_blk_len
|
||||
cdef int iv_len, iv_len_short
|
||||
|
|
@ -245,7 +243,6 @@ cdef class AES256_CTR_HMAC_SHA256:
|
|||
|
||||
def __init__(self, mac_key, enc_key, iv=None, header_len=1, aad_offset=1):
|
||||
self.requirements_check()
|
||||
assert isinstance(mac_key, bytes) and len(mac_key) == 32
|
||||
assert isinstance(enc_key, bytes) and len(enc_key) == 32
|
||||
self.cipher_blk_len = 16
|
||||
self.iv_len = sizeof(self.iv)
|
||||
|
|
@ -254,7 +251,6 @@ cdef class AES256_CTR_HMAC_SHA256:
|
|||
self.aad_offset = aad_offset
|
||||
self.header_len = header_len
|
||||
self.mac_len = 32
|
||||
self.mac_key = mac_key
|
||||
self.enc_key = enc_key
|
||||
if iv is not None:
|
||||
self.set_iv(iv)
|
||||
|
|
@ -263,11 +259,19 @@ cdef class AES256_CTR_HMAC_SHA256:
|
|||
|
||||
def __cinit__(self, mac_key, enc_key, iv=None, header_len=1, aad_offset=1):
|
||||
self.ctx = EVP_CIPHER_CTX_new()
|
||||
self.hmac_ctx = HMAC_CTX_new()
|
||||
|
||||
def __dealloc__(self):
|
||||
EVP_CIPHER_CTX_free(self.ctx)
|
||||
HMAC_CTX_free(self.hmac_ctx)
|
||||
|
||||
cdef mac_compute(self, const unsigned char *data1, int data1_len,
|
||||
const unsigned char *data2, int data2_len,
|
||||
const unsigned char *mac_buf):
|
||||
raise NotImplementedError
|
||||
|
||||
cdef mac_verify(self, const unsigned char *data1, int data1_len,
|
||||
const unsigned char *data2, int data2_len,
|
||||
const unsigned char *mac_buf, const unsigned char *mac_wanted):
|
||||
raise NotImplementedError
|
||||
|
||||
def encrypt(self, data, header=b'', iv=None):
|
||||
"""
|
||||
|
|
@ -309,14 +313,9 @@ cdef class AES256_CTR_HMAC_SHA256:
|
|||
if not rc:
|
||||
raise CryptoError('EVP_EncryptFinal_ex failed')
|
||||
offset += olen
|
||||
if not HMAC_Init_ex(self.hmac_ctx, self.mac_key, self.mac_len, EVP_sha256(), NULL):
|
||||
raise CryptoError('HMAC_Init_ex failed')
|
||||
if not HMAC_Update(self.hmac_ctx, <const unsigned char *> hdata.buf+aoffset, alen):
|
||||
raise CryptoError('HMAC_Update failed')
|
||||
if not HMAC_Update(self.hmac_ctx, odata+hlen+self.mac_len, offset-hlen-self.mac_len):
|
||||
raise CryptoError('HMAC_Update failed')
|
||||
if not HMAC_Final(self.hmac_ctx, odata+hlen, NULL):
|
||||
raise CryptoError('HMAC_Final failed')
|
||||
self.mac_compute(<const unsigned char *> hdata.buf+aoffset, alen,
|
||||
odata+hlen+self.mac_len, offset-hlen-self.mac_len,
|
||||
odata+hlen)
|
||||
self.blocks += self.block_count(ilen)
|
||||
return odata[:offset]
|
||||
finally:
|
||||
|
|
@ -338,20 +337,13 @@ cdef class AES256_CTR_HMAC_SHA256:
|
|||
raise MemoryError
|
||||
cdef int olen
|
||||
cdef int offset
|
||||
cdef unsigned char hmac_buf[32]
|
||||
assert sizeof(hmac_buf) == self.mac_len
|
||||
cdef unsigned char mac_buf[32]
|
||||
assert sizeof(mac_buf) == self.mac_len
|
||||
cdef Py_buffer idata = ro_buffer(envelope)
|
||||
try:
|
||||
if not HMAC_Init_ex(self.hmac_ctx, self.mac_key, self.mac_len, EVP_sha256(), NULL):
|
||||
raise CryptoError('HMAC_Init_ex failed')
|
||||
if not HMAC_Update(self.hmac_ctx, <const unsigned char *> idata.buf+aoffset, alen):
|
||||
raise CryptoError('HMAC_Update failed')
|
||||
if not HMAC_Update(self.hmac_ctx, <const unsigned char *> idata.buf+hlen+self.mac_len, ilen-hlen-self.mac_len):
|
||||
raise CryptoError('HMAC_Update failed')
|
||||
if not HMAC_Final(self.hmac_ctx, hmac_buf, NULL):
|
||||
raise CryptoError('HMAC_Final failed')
|
||||
if CRYPTO_memcmp(hmac_buf, idata.buf+hlen, self.mac_len):
|
||||
raise IntegrityError('HMAC Authentication failed')
|
||||
self.mac_verify(<const unsigned char *> idata.buf+aoffset, alen,
|
||||
<const unsigned char *> idata.buf+hlen+self.mac_len, ilen-hlen-self.mac_len,
|
||||
mac_buf, <const unsigned char *> idata.buf+hlen)
|
||||
iv = self.fetch_iv(<unsigned char *> idata.buf+hlen+self.mac_len)
|
||||
self.set_iv(iv)
|
||||
if not EVP_DecryptInit_ex(self.ctx, EVP_aes_256_ctr(), NULL, self.enc_key, iv):
|
||||
|
|
@ -405,7 +397,81 @@ cdef class AES256_CTR_HMAC_SHA256:
|
|||
return bytes_to_long(envelope[offset:offset+self.iv_len_short])
|
||||
|
||||
|
||||
AES256_CTR_BLAKE2b = AES256_CTR_HMAC_SHA256 # TODO this is a dummy
|
||||
cdef class AES256_CTR_HMAC_SHA256(AES256_CTR_BASE):
|
||||
cdef HMAC_CTX *hmac_ctx
|
||||
cdef unsigned char *mac_key
|
||||
|
||||
def __init__(self, mac_key, enc_key, iv=None, header_len=1, aad_offset=1):
|
||||
assert isinstance(mac_key, bytes) and len(mac_key) == 32
|
||||
self.mac_key = mac_key
|
||||
super().__init__(mac_key, enc_key, iv=iv, header_len=header_len, aad_offset=aad_offset)
|
||||
|
||||
def __cinit__(self, mac_key, enc_key, iv=None, header_len=1, aad_offset=1):
|
||||
self.hmac_ctx = HMAC_CTX_new()
|
||||
|
||||
def __dealloc__(self):
|
||||
HMAC_CTX_free(self.hmac_ctx)
|
||||
|
||||
cdef mac_compute(self, const unsigned char *data1, int data1_len,
|
||||
const unsigned char *data2, int data2_len,
|
||||
const unsigned char *mac_buf):
|
||||
if not HMAC_Init_ex(self.hmac_ctx, self.mac_key, self.mac_len, EVP_sha256(), NULL):
|
||||
raise CryptoError('HMAC_Init_ex failed')
|
||||
if not HMAC_Update(self.hmac_ctx, data1, data1_len):
|
||||
raise CryptoError('HMAC_Update failed')
|
||||
if not HMAC_Update(self.hmac_ctx, data2, data2_len):
|
||||
raise CryptoError('HMAC_Update failed')
|
||||
if not HMAC_Final(self.hmac_ctx, mac_buf, NULL):
|
||||
raise CryptoError('HMAC_Final failed')
|
||||
|
||||
cdef mac_verify(self, const unsigned char *data1, int data1_len,
|
||||
const unsigned char *data2, int data2_len,
|
||||
const unsigned char *mac_buf, const unsigned char *mac_wanted):
|
||||
self.mac_compute(data1, data1_len, data2, data2_len, mac_buf)
|
||||
if CRYPTO_memcmp(mac_buf, mac_wanted, self.mac_len):
|
||||
raise IntegrityError('MAC Authentication failed')
|
||||
|
||||
|
||||
cdef class AES256_CTR_BLAKE2b(AES256_CTR_BASE):
|
||||
cdef unsigned char *mac_key
|
||||
|
||||
def __init__(self, mac_key, enc_key, iv=None, header_len=1, aad_offset=1):
|
||||
assert isinstance(mac_key, bytes) and len(mac_key) == 128
|
||||
self.mac_key = mac_key
|
||||
super().__init__(mac_key, enc_key, iv=iv, header_len=header_len, aad_offset=aad_offset)
|
||||
|
||||
def __cinit__(self, mac_key, enc_key, iv=None, header_len=1, aad_offset=1):
|
||||
pass
|
||||
|
||||
def __dealloc__(self):
|
||||
pass
|
||||
|
||||
cdef mac_compute(self, const unsigned char *data1, int data1_len,
|
||||
const unsigned char *data2, int data2_len,
|
||||
const unsigned char *mac_buf):
|
||||
cdef blake2b_state state
|
||||
cdef int rc
|
||||
rc = blake2b_init(&state, self.mac_len)
|
||||
if rc == -1:
|
||||
raise Exception('blake2b_init() failed')
|
||||
with nogil:
|
||||
rc = blake2b_update(&state, self.mac_key, 128)
|
||||
if rc != -1:
|
||||
rc = blake2b_update(&state, data1, data1_len)
|
||||
if rc != -1:
|
||||
rc = blake2b_update(&state, data2, data2_len)
|
||||
if rc == -1:
|
||||
raise Exception('blake2b_update() failed')
|
||||
rc = blake2b_final(&state, mac_buf, self.mac_len)
|
||||
if rc == -1:
|
||||
raise Exception('blake2b_final() failed')
|
||||
|
||||
cdef mac_verify(self, const unsigned char *data1, int data1_len,
|
||||
const unsigned char *data2, int data2_len,
|
||||
const unsigned char *mac_buf, const unsigned char *mac_wanted):
|
||||
self.mac_compute(data1, data1_len, data2, data2_len, mac_buf)
|
||||
if CRYPTO_memcmp(mac_buf, mac_wanted, self.mac_len):
|
||||
raise IntegrityError('MAC Authentication failed')
|
||||
|
||||
|
||||
ctypedef const EVP_CIPHER * (* CIPHER)()
|
||||
|
|
|
|||
|
|
@ -77,10 +77,9 @@ class TestKey:
|
|||
KeyfileKey,
|
||||
RepoKey,
|
||||
AuthenticatedKey,
|
||||
# TODO temporarily disabled for branch merging XXX
|
||||
#Blake2KeyfileKey,
|
||||
#Blake2RepoKey,
|
||||
#Blake2AuthenticatedKey,
|
||||
Blake2KeyfileKey,
|
||||
Blake2RepoKey,
|
||||
Blake2AuthenticatedKey,
|
||||
))
|
||||
def key(self, request, monkeypatch):
|
||||
monkeypatch.setenv('BORG_PASSPHRASE', 'test')
|
||||
|
|
@ -176,7 +175,6 @@ class TestKey:
|
|||
key = KeyfileKey.detect(self.MockRepository(), self.keyfile2_cdata)
|
||||
assert key.decrypt(self.keyfile2_id, self.keyfile2_cdata) == b'payload'
|
||||
|
||||
@pytest.mark.skip("temporarily disabled for branch merge") # TODO
|
||||
def test_keyfile_blake2(self, monkeypatch, keys_dir):
|
||||
with keys_dir.join('keyfile').open('w') as fd:
|
||||
fd.write(self.keyfile_blake2_key_file)
|
||||
|
|
|
|||
Loading…
Reference in a new issue