Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
Update of 1.2-maint as suggested in borgbackup#6667
  • Loading branch information
Christopher Klooz authored May 14, 2022
1 parent bcac974 commit 283fd81
Showing 1 changed file with 98 additions and 20 deletions.
118 changes: 98 additions & 20 deletions docs/internals/security.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,32 +124,116 @@ prompt is a set BORG_PASSPHRASE. See issue :issue:`2169` for details.
Encryption
----------

Encryption is currently based on the Encrypt-then-MAC construction,
AEAD modes
~~~~~~~~~~

Modes: --encryption (repokey|keyfile)-[blake2-](aes-ocb|chacha20-poly1305)

Supported: borg 1.3+

This comment has been minimized.

Copy link
@ThomasWaldmann

ThomasWaldmann May 14, 2022

yeah, it was planned to be 1.3.

considering my recent "breaking" PRs it might well be (if we merge these) that it will be 2.0.


Encryption with these modes is based on AEAD ciphers (authenticated encryption
with associated data) and session keys.

Depending on the chosen mode (see :ref:`borg_init`) different AEAD ciphers are used:

- AES-256-OCB - super fast, single-pass algorithm IF you have hw accelerated AES.
- chacha20-poly1305 - very fast, purely software based AEAD cipher.

The chunk ID is derived via a MAC over the plaintext (mac key taken from borg key):

- HMAC-SHA256 - super fast IF you have hw accelerated SHA256 (see section "Encryption" below).
- Blake2b - very fast, purely software based algorithm.

For each borg invocation, a new session id is generated by `os.urandom`_.

From that session id, the initial key material (ikm, taken from the borg key)
and an application and cipher specific salt, borg derives a session key via HKDF.

For each session key, IVs (nonces) are generated by a counter which increments for
each encrypted message.

Session::

sessionid = os.urandom(24)
ikm = enc_key || enc_hmac_key
salt = "borg-session-key-CIPHERNAME"
sessionkey = HKDF(ikm, sessionid, salt)
message_iv = 0

Encryption::

id = MAC(id_key, data)
compressed = compress(data)

header = type-byte || 00h || message_iv || sessionid
aad = id || header
message_iv++
encrypted, auth_tag = AEAD_encrypt(session_key, message_iv, compressed, aad)
authenticated = header || auth_tag || encrypted

Decryption::

# Given: input *authenticated* data and a *chunk-id* to assert
type-byte, past_message_iv, past_sessionid, auth_tag, encrypted = SPLIT(authenticated)

ASSERT(type-byte is correct)

past_key = HKDF(ikm, past_sessionid, salt)
decrypted = AEAD_decrypt(past_key, past_message_iv, authenticated)

decompressed = decompress(decrypted)

ASSERT( CONSTANT-TIME-COMPARISON( chunk-id, MAC(id_key, decompressed) ) )

Notable:

- More modern and often faster AEAD ciphers instead of self-assembled stuff.
- Due to the usage of session keys, IVs (nonces) do not need special care here as
they did for the legacy encryption modes.
- The id is now also input into the authentication tag computation.
This strongly associates the id with the written data (== associates the key with
the value). When later reading the data for some id, authentication will only
succeed if what we get was really written by us for that id.


Legacy modes
~~~~~~~~~~~~

Modes: --encryption (repokey|keyfile)-[blake2]

Supported: all borg versions, blake2 since 1.1

DEPRECATED. We strongly suggest you use the safer AEAD modes, see above.

This comment has been minimized.

Copy link
@ThomasWaldmann

ThomasWaldmann May 14, 2022

If we merge the breaking PRs, users will have to create new repos and AES-CTR will not be supported any more for new repos.

This comment has been minimized.

Copy link
@ThomasWaldmann

ThomasWaldmann May 14, 2022

Existing repos might get transferred via borg transfer (which auths, decrypts, keeps compressed data to not have to recompress, encrypts, auths).


Encryption with these modes is based on the Encrypt-then-MAC construction,
which is generally seen as the most robust way to create an authenticated
encryption scheme from encryption and message authentication primitives.

Every operation (encryption, MAC / authentication, chunk ID derivation)
uses independent, random keys generated by `os.urandom`_ [#]_.
uses independent, random keys generated by `os.urandom`_.

Borg does not support unauthenticated encryption -- only authenticated encryption
schemes are supported. No unauthenticated encryption schemes will be added
in the future.

Depending on the chosen mode (see :ref:`borg_init`) different primitives are used:

- The actual encryption is currently always AES-256 in CTR mode. The
- Legacy encryption modes use AES-256 in CTR mode. The
counter is added in plaintext, since it is needed for decryption,
and is also tracked locally on the client to avoid counter reuse.

- The authentication primitive is either HMAC-SHA-256 or BLAKE2b-256
in a keyed mode. HMAC-SHA-256 uses 256 bit keys, while BLAKE2b-256
uses 512 bit keys.

The latter is secure not only because BLAKE2b itself is not
susceptible to `length extension`_, but also since it truncates the
hash output from 512 bits to 256 bits, which would make the
construction safe even if BLAKE2b were broken regarding length
extension or similar attacks.
in a keyed mode.

Both HMAC-SHA-256 and BLAKE2b have undergone extensive cryptanalysis
and have proven secure against known attacks. The known vulnerability
of SHA-256 against length extension attacks does not apply to HMAC-SHA-256.

The authentication primitive should be chosen based upon SHA hardware support:
all AMD Ryzen, Intel 10th+ generation mobile and Intel 11th+ generation
desktop processors, Apple M1+ and most current ARM64 architectures support
SHA extensions and are likely to perform best with HMAC-SHA-256.
64-bit CPUs without SHA extensions are likely to perform best with BLAKE2b.

- The primitive used for authentication is always the same primitive
that is used for deriving the chunk ID, but they are always
Expand Down Expand Up @@ -208,13 +292,6 @@ untrusted, but a trusted synchronization channel exists between
clients, the security database could be synchronized between them over
said trusted channel. This is not part of Borg's functionality.

.. [#] Using the :ref:`borg key migrate-to-repokey <borg_key_migrate-to-repokey>`
command a user can convert repositories created using Attic in "passphrase"
mode to "repokey" mode. In this case the keys were directly derived from
the user's passphrase at some point using PBKDF2.
Borg does not support "passphrase" mode otherwise any more.
.. _key_encryption:

Offline key security
Expand Down Expand Up @@ -260,7 +337,7 @@ Implementations used
We do not implement cryptographic primitives ourselves, but rely
on widely used libraries providing them:

- AES-CTR and HMAC-SHA-256 from OpenSSL 1.0 / 1.1 are used,
- AES-CTR, AES-OCB, CHACHA20-POLY1305 and HMAC-SHA-256 from OpenSSL 1.1 are used,
which is also linked into the static binaries we provide.
We think this is not an additional risk, since we don't ever
use OpenSSL's networking, TLS or X.509 code, but only their
Expand All @@ -275,7 +352,8 @@ on widely used libraries providing them:

Implemented cryptographic constructions are:

- Encrypt-then-MAC based on AES-256-CTR and either HMAC-SHA-256
- AEAD modes: AES-OCB and CHACHA20-POLY1305 are straight from OpenSSL.
- Legacy modes: Encrypt-then-MAC based on AES-256-CTR and either HMAC-SHA-256
or keyed BLAKE2b256 as described above under Encryption_.
- Encrypt-and-MAC based on AES-256-CTR and HMAC-SHA-256
as described above under `Offline key security`_.
Expand Down

0 comments on commit 283fd81

Please sign in to comment.