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 1.

Symmetric Encryption

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.


Asymmetric encryption in luca is based on the DLIES encryption scheme as specified in section 3.5 of BSI TR-02102-1 1. For the components required, luca uses the following primitives:



asymmetric key parameters

secp256r1 (NIST P-256)

symmetric encryption


message authentication code


key derivation function



We use ECDSA with the secp256r1 (NIST P-256) elliptic curve.

On the Use of secp256r1

The curve secp256r1 is recommended by NIST 2 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 3. 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 45. We chose to use secp256r1 because we value the security benefit of using the trusted module higher than the risks laid out above.

Encryption Scheme

Based on the scheme specified above, asymmetric encryption is implemented by the components in luca as follows:

# 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 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.


Accordingly, decryption and authentication is implemented as follows:

# 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.


BSI TR-02102-1. Cryptographic Mechanisms: Recommendations and Key Lengths, accessed 2021/03/04


NIST SP 800-186 (Draft). Recommendations for Discrete Logarithm-Based Cryptography: Elliptic Curve Domain Parameters accessed 2021/03/04


Daniel J. Bernstein and Tanja Lange. SafeCurves: choosing safe curves for elliptic-curve cryptography., accessed 2021/03/04


Apple Developer documentation on SecureEnclave, accessed 2021/03/04


Android Developer documentation on HSM, accessed 2021/03/08