Overview
Relying only the information contained in this repository it seems to be the case that it is possible for a malicious user to generate a forged check-in QR code in such a way that the forgery is not detectable by the venue or the Luca backend. If I am correct this would allow a malicious user to successfully check into a venue without disclosing any information necessary for contact tracing.
Introduction
https://github.com/lucaapp/security-concept/blob/main/content/processes/guest_app_checkin.md describes the data which is encoded in the QR code generated by the Luca app which is intended to be scanned by the venue:
- version (QR code protocol version)
- device_type
- key_id (ID of the daily keypair used for this Check-In)
- timestamp
- trace_id
- enc_data
- ephemeral_keys.public
- verification_tag
- checksum
where
timestamp = UNIX timestamp rounded down to the last full minute (little endian encoding)
trace_id = HMAC-SHA256(user_id || timestamp, tracing_secret) # truncated to 16 bytes
ephemeral_keys = a new secp256r1 key pair (for DLIES with the daily public key)
dh_key = ECDH(ephemeral_keys.private, daily_keypair.public)
enc_key = SHA256(dh_key || 0x01) # truncated to 16 bytes
iv = ephemeral_keys.public # truncated to 16 bytes
enc_data = AES-128-CTR(userId || data_secret, enc_key, iv)
verification_tag = HMAC-SHA256(timestamp || enc_data, data_authentication_key)
and the tracing_secret, the data_secret and the data_authentication key are neither known by the venue, nor by the attacker nor by the Luca backend. Additionally it is assumed that daily_keypair.public, key_id, version and device_type are public information.
Description of the attack
In order to perform the attack a maliciuous user has to generate a QR code containing the information mentioned above which is accepted by the scanning venue and the Luca backend. So let's have a look at all elements of the QR code:
version
Public information
device_type
Public information
key_id
Public information
timestamp
Public information
trace_id
For an honest user the trace_id is calculated as follows:
HMAC-SHA256(user_id || timestamp, tracing_secret) # truncated to 16 bytes
The attacker does not know the tracing_secret but neither do the venue nor the Luca backend. This in turn means that any 16 byte random information has to be accepted by the venue and the Luca backend, because they can not verify it.
enc_data
For an honest user this value is calculated as
ephemeral_keys = a new secp256r1 key pair (for DLIES with the daily public key)
dh_key = ECDH(ephemeral_keys.private, daily_keypair.public)
enc_key = SHA256(dh_key || 0x01) # truncated to 16 bytes
iv = ephemeral_keys.public # truncated to 16 bytes
enc_data = AES-128-CTR(userId || data_secret, enc_key, iv)
It has to be noted that none of the involved parties knows the data_secret but the other information can be generated by the attacker. If the attacker performs the calculations above using a random value (of correct length) for the data_secret and the user_id the results have to be accepted by the backend and the venue because neither of them holds the private daily_key and therefore can not perform the decryption operation which would be necessary in order to detect the forgery.
ephemeral_keys.public
Can be generated by the attacker.
verification_tag
For an honest user this value is caclulated as follows:
verification_tag = HMAC-SHA256(timestamp || enc_data, data_authentication_key)
For this calculation the data_authentication_key is needed. This key is not known to the attacker, the venue and the Luca backend. This again means that any random 8 (the HMAC is truncated to 8 bytes according to this documentation) byte value has to be accepted by the venue as well as the backend because they have no means to verify it.
checksum
Checksum is the SHA-256 hash truncated to 4 bytes of the previously described data and can be easily generated by an attacker.
Conclusion
If I have not missed a central piece of information an attacker can easily create a QR code which can be used to check in to a venue but is unusable for contact tracing and does not disclose the identity of the attacker.