(appendix:algorithms)=
# Cryptographic Algorithms
This chapter privides details about the cryptographic algorithms used throughout _luca_.
All primitives have been selected in accordance with the Technical Guideline TR-02102-1 of the German BSI [^bsi_tr].
## Symmetric Encryption
```{margin}
In a future version of _luca_ we plan on using `AES-128` in Galois/Counter Mode (`GCM`) instead.
```
_luca_ uses `AES` with a key length of 128 bits in Counter Mode (`AES-128-CTR`) for symmetric encryption.
Data is authenticated using `HMAC-SHA256`.
## Asymmetric Cryptography
_luca_ uses elliptic curves for the required asymmetric cryptography.
(appendix:algorithms:asymmetric_encryption)=
### Encryption
Asymmetric encryption in _luca_ is based on the DLIES encryption scheme as specified in section 3.5 of BSI TR-02102-1 [^bsi_tr].
For the components required, _luca_ uses the following primitives:
| Component | Algorithm |
| --- | --- |
| **asymmetric key parameters** | `secp256r1` (`NIST P-256`) |
| **symmetric encryption** | `AES-128-CTR` |
| **message authentication code** | `HMAC-SHA256` |
| **key derivation function** | `SHA256` |
### Signing
We use ECDSA with the `secp256r1` (`NIST P-256`) elliptic curve.
### On the Use of `secp256r1`
The curve `secp256r1` is recommended by NIST [^nist_sp] for use with Discrete Logarithm-Based Cryptography.
It is, however, criticized for using unexplained inputs in the curve-generation process and hence rumored to be backdoored by the NSA [^safecurves].
At the time of writing, those rumors can neither be proven nor disproven.
Consequently it would be preferable to use a different curve that is generally considered safe.
However, as of 2021, `secp256r1` is the only curve widely supported by many mobile phone hardware-based key managers [^secure_enclave][^strongbox].
We chose to use `secp256r1` because we value the security benefit of using the trusted module higher than the risks laid out above.
[^bsi_tr]: [BSI TR-02102-1. Cryptographic Mechanisms: Recommendations and Key Lengths](https://www.bsi.bund.de/SharedDocs/Downloads/EN/BSI/Publications/TechGuidelines/TG02102/BSI-TR-02102-1.pdf?__blob=publicationFile&v=1), accessed 2021/03/04
[^nist_sp]: [NIST SP 800-186 (Draft). Recommendations for Discrete Logarithm-Based Cryptography: Elliptic Curve Domain Parameters](https://csrc.nist.gov/publications/detail/sp/800-186/draft) accessed 2021/03/04
[^safecurves]: [Daniel J. Bernstein and Tanja Lange. SafeCurves: choosing safe curves for elliptic-curve cryptography.](https://safecurves.cr.yp.to), accessed 2021/03/04
[^secure_enclave]: [Apple Developer documentation on SecureEnclave](https://developer.apple.com/documentation/cryptokit/secureenclave), accessed 2021/03/04
[^strongbox]: [Android Developer documentation on HSM](https://developer.android.com/training/articles/keystore#HardwareSecurityModule), accessed 2021/03/08
## Encryption Scheme
Based on the scheme specified above, asymmetric encryption is implemented by the components in _luca_ as follows:
```{code} python
# pseudocode
# given the inputs:
# * data: the data to encrypt
# * receiver_public_key: the public key of the receiver
# * iv (optional): the initialization vector
ephemeral_keys = a new secp256r1 key pair (for DLIES with the receiver's public key)
iv = random_bytes(16) # Note: in some contexts an external input (usually
# an ephemeral public key) is used as IV
dh_key = ECDH(ephemeral_keys.private, receiver_public_key)
encryption_key = SHA256(dh_key || 0x01) # truncated to 16 bytes
authentication_key = SHA256(dh_key || 0x02)
encrypted_data = AES-128-CTR(data, encryption_key, iv)
mac = HMAC-SHA256(encrypted_data, authentication_key)
```
The function's output includes `encrypted_data`, `mac`, `iv` and `ephemeral_keys.public`.
### On the Use of the ephemeral public key as IV
As indicated in the pseudocode snippet above, we sometimes re-use the DLIES ephemeral key pair's public key as the initialization vector for `AES-CTR`.
Our motivation for this is the limited capacity of the Check-In QR codes generated by the {term}`Guest App`.
The receiver of the encrypted data needs both, the ephemeral public key and the IV, to decrypt the data.
Re-using the public key as IV saves space.
This construction is uncommon, but secure.
`AES-CTR` only requires the initialization vector to be unique, which is satisfied here.
### Decryption
Accordingly, decryption and authentication is implemented as follows:
```{code} python
# pseudocode
# given the inputs:
# * encrypted_data: the data to decrypt
# * receiver_private_key: the private key of the receiver
# * iv: the initialization vector
# * ephemeral_public_key: the sender's public key for DLIES (ephemeral_keys.public)
# * mac: the message authentication code
dh_key = ECDH(receiver_private_key, ephemeral_public_key)
encryption_key = SHA256(dh_key || 0x01) # truncated to 16 bytes
authentication_key = SHA256(dh_key || 0x02)
verify_mac(mac, HMAC-SHA256(encryptedData, authentication_key))
decrypted_data = AES-128-CTR(data, encryption_key, iv)
```
If the provided `mac` is valid, the function returns the `decrypted_data`.