Check-In via Mobile Phone App¶
The following secrets are involved in this process:
Use / Purpose
The Guest’s secret seed to derive both the data encryption key and the data authentication key. This seed will be encrypted for the Health Department in this process before being transported to the Scanner Frontend via a QR code and protects the Guest’s Contact Data stored on the Luca Server.
Securely stored locally on the mobile device (see Guest Registration for further details)
Securely stored locally on the mobile device
Verifies the authenticity of the daily keypair public key by checking its signature.
This describes how Guests use luca’s Guest App to generate so-called Check-Ins at specific venues. For that, Venue Owners deploy Scanner Frontends that read QR codes generated by the Guest App. Note that there are other ways a Guest might check-in to a venue: Please refer to Badge Check-In and Check-In via a Printed QR Code for further details.
Check-Ins can be used at a later time by Health Departments to reconstruct an Infected Guest’s Check-In History (given that the Infected Guest has given their consent). Check-Ins of other Guests can be associated with the Infected Guest’s Check-In History to allow for Tracing the Check-In History of an Infected Guest.
In any case the Check-In data that is transferred and stored on the Luca Server does not reveal information about the Guest’s identity (O1, O2). Neither does the Luca system learn about a Guest’s habits (O3).
Before generating any QR codes to perform Check-Ins the Guest App will fetch the latest daily keypair public key from the Luca Server (see Daily Public Key Rotation). The provided public key comes with a reference to the issuing Health Department, a creation timestamp and a signature by a Health Department’s HDSKP certificate. The Guest App must verify the trust chain of the HDSKP certificate as well as the signature of the daily keypair (see Verification of Health Department Keypair Certificates). Furthermore, keys that are older than seven days are not considered valid anymore.
QR codes generated by the Guest App are valid for a short period of time and the whole generation process described below is repeated every minute.
Each trace ID is generated as HMAC-SHA256 of the Guest’s user ID and a current quantized timestamp (clamped to the latest full minute) as
data and the tracing secret as
The resulting value is truncated to the first 16 bytes.
Subsequently, the Guest App asymmetrically encrypts the Guest’s user ID and the data secret for the daily keypair.
The IV is defined as the first 16 bytes of the ephemeral public key used in the DLIES.
The Guest App then calculates a verification tag as HMAC-SHA256 of the timestamp and the encrypted data as
data and the data authentication key as key, truncated to the first 8 bytes.
A four-byte checksum (truncated SHA256) of all the previously generated data blob is appended as an integrity check to detect faulty QR code reads 2.
QR Code Generation and Check-In¶
The app generates a new QR code every minute, for each code the app generates the following:
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)
The trace ID (
trace_id) depends on the user ID (
user_id) of the Guest, the current quantized timestamp and the Guest’s tracing secret.
Hence, all trace IDs for any given minute can be calculated given the user ID and the tracing secret (which is stored securely inside the Guest App).
Without the tracing secret, the Guest’s trace IDs can neither be linked to (a) the Guest themselves (fulfilling O2) nor (b) to other trace IDs of the same Guest (fulfilling O3).
If tested positive for Sars-CoV2 a Guest may consent to sharing their tracing secret with the Health Department (rendering them an Infected Guest). This facilitates the Health Department to trace the Infected Guest’s Check-In History (fulfilling O4). See Tracing the Check-In History of an Infected Guest for further details.
To restrict the disclosed time interval of the Infected Guest’s Check-In History the Guest App regularly changes the tracing secret (see Rotating the Tracing Secret). The Guest App shares only the tracing secrets that were valid in an epidemiologically relevant time frame (about two weeks) with the Health Department (fulfilling O5).
The encrypted data
enc_data is not authenticated as it would usually be the case (cf. Encrypt-then-MAC).
We assume that neither the Luca Server nor the Venue Owner can benefit from altering
enc_data in any meaningful way.
verification_tag binds the Check-In’s timestamp to the data secret to avoid replay attacks by an adversary that learned about
enc_data but not the data secret.
Otherwise, said adversary might use
enc_data to create Check-Ins with the identity of the Guest that owns the data secret.
timestamp to the data secret mitigates this replay to a short window of opportunity (about one minute) assuming that the Scanner Frontend validates that
timestamps in Check-Ins are recent.
QR Code Construction¶
The App then displays a QR code containing:
version(QR code protocol version)
key_id(ID of the daily keypair used for this Check-In)
The payload is concatenated and encoded with ASCII85 to be displayed as a QR code.
QR Code Scanning, Validation and Check-In Upload¶
The Scanner Frontend reads the above QR code using either a mobile phone camera or a dedicated scanner hardware.
Before doing any further processing, it validates the
checksum to detect reader errors.
Furthermore, the contained
timestamp is compared to the Scanner’s local clock with a reasonable grace period.
If either the
checksum or the
timestamp checks fail, no further processing is performed.
Any further cryptographic validity checks cannot be performed by the Scanner Frontend.
eph_scanner_keys = a new secp256r1 key pair (for DLIES with the venue public key) dh_key = ECDH(eph_scanner_keys.private, venue_keypair.public) enc_key = SHA256(dh_key || 0x01) # truncated to 16 bytes auth_key = SHA256(dh_key || 0x02) iv = random_bytes(16) version = 0x03 # protocol version of the encrypted data record check_in_data = version || key_id || ephemeral_keys.public || verification_tag || enc_data venue_enc_data = AES-128-CTR(check_in_data, enc_key, iv) venue_enc_data_mac = HMAC-SHA256(venue_enc_data, auth_key)
When storing this information the Luca Server associates it with the
venue_id (determined via the
scanner_id) and the Check-In time.
No further processing is done in the Luca Server.
Second Layer of Encryption¶
As required by O6: Venue Consent, the Health Department shall be prevented from single-handedly decrypting Guest’s Contact Data. The Luca system is designed to “replace” the paper-based guest lists in physical venues that provide the same security guarantee. Hence, Scanner Frontends encrypt the already encrypted Contact Data in Check-Ins and remove this encryption layer only on authoritative request of a Health Department. See Tracing the Check-In History of an Infected Guest for further details.
Authenticity of venue keypair¶
When encrypting the (encrypted) user data (
enc_data) and the additional data with the venue keypair’s public key the authenticity of that public key is crucial.
Plese refer to the security considerations regarding Venue Registration for further details.
scanner_id sent as part of the Check-In data is the only indicator luca can use in order to infer the associated venue.
Forging a non-existent
scanner_id could potentially allow an attacker to send bogus data to the Luca Server.
However, this does not reveal any information to the attacker in any scenario.
On a similar note, knowing the
scanner_id of a venue basically allows the impersonation of the venue’s Scanner Frontend.
This is accepted; more specifically, this is specifically desired in the Self Check-In scenario.
QR Code Scanning Feedback¶
The described process relies on the uni-directional communication from the Guest App to the Scanner Frontend to perform a Check-In by scanning a dynamic QR code. Theoretically, this allows Guest Check-Ins even without a constant internet connection of the Guest App. Nevertheless, user feedback by the Guest App for a successfully scanned QR code is seen as desirable.
Therefore, the Guest App polls the Luca Server via an unauthenticated connection. This inquires whether a Check-In was uploaded by a Scanner Frontend with a trace ID that the Guest App recently generated. Once this inquiry polling request is acknowledged by the Luca Server, the Guest App assumes that a successful QR code scan and Check-In was performed. Some UI feedback is provided to the Guest.
This polling request might leak information about the association of a just checked-in trace ID and the identity of the Guest (directly contradicting O2). As mobile phone network typically use NAT, the fact that the Luca Server does not log any IP addresses and the connection being unauthenticated, we do accept this risk.
The QR code standard already includes an error correction mechanism. However, some dedicated QR code scanner hardware acts as keyboard input device to forward QR code data to the luca web application. As this data transfer appears to be error prone, we added checksumming on application level as well.