Zum Hauptinhalt springen

3. Push-Nachrichtenverschlüsselung

3. Push-Nachrichtenverschlüsselung

Die Verschlüsselung einer Push-Nachricht erfolgt in vier Phasen:

  • Ein gemeinsames Geheimnis wird mit ECDH [ECDH] abgeleitet (siehe Abschnitt 3.1 dieses Dokuments).

  • Das gemeinsame Geheimnis wird mit dem Authentifizierungsgeheimnis kombiniert, um das in [RFC8188] verwendete Eingangsschlüsselmaterial (IKM) zu erzeugen (siehe Abschnitt 3.3 dieses Dokuments).

  • Inhaltsverschlüsselungsschlüssel und Nonce werden nach dem Verfahren in [RFC8188] abgeleitet.

  • Verschlüsselung oder Entschlüsselung erfolgt gemäß [RFC8188].

Die Schlüsselableitung ist in Abschnitt 3.4 zusammengefasst. Einschränkungen für die verschlüsselte Inhaltskodierung stehen in Abschnitt 4.

3.1. Diffie-Hellman-Schlüsselvereinbarung

Für jede neue Subscription, die der User-Agent für eine Anwendung erzeugt, erzeugt er auch ein P-256-Schlüsselpaar [FIPS186] für ECDH [ECDH].

Beim Senden einer Push-Nachricht erzeugt der Anwendungsserver ebenfalls ein neues ECDH-Schlüsselpaar auf derselben P-256-Kurve.

Der öffentliche ECDH-Schlüssel des Anwendungsservers steht als Parameter „keyid“ im Header der verschlüsselten Inhaltskodierung (siehe Abschnitt 2.1 von [RFC8188]).

Der Anwendungsserver kombiniert seinen privaten ECDH-Schlüssel mit dem vom User-Agent bereitgestellten öffentlichen Schlüssel nach [ECDH]; beim Empfang der Push-Nachricht kombiniert der User-Agent seinen privaten Schlüssel mit dem vom Anwendungsserver in „keyid“ gelieferten öffentlichen Schlüssel auf dieselbe Weise. Diese Operationen ergeben denselben Wert für das gemeinsame ECDH-Geheimnis.

3.2. Authentifizierung von Push-Nachrichten

Um die korrekte Authentifizierung von Push-Nachrichten zu gewährleisten, wird den vom User-Agent erzeugten Informationen ein symmetrisches Authentifizierungsgeheimnis hinzugefügt. Es wird in das in Abschnitt 3.3 beschriebene Schlüsselableitungsverfahren einbezogen.

Ein User-Agent MUST eine schwer erratbare Folge von 16 Oktetten erzeugen und bereitstellen, die zur Authentifizierung von Push-Nachrichten dient. Sie SHOULD mit einem kryptographisch starken Zufallszahlengenerator erzeugt werden [RFC4086].

3.3. Kombination von gemeinsamem und Authentifizierungsgeheimnis

Das von ECDH erzeugte gemeinsame Geheimnis wird mit dem Authentifizierungsgeheimnis mittels der HMAC-basierten Schlüsselableitungsfunktion HKDF [RFC5869] kombiniert. Das Ergebnis ist das von [RFC8188] verwendete Eingangsschlüsselmaterial.

HKDF nutzt den Hash-Algorithmus SHA-256 [FIPS180-4] mit folgenden Eingaben:

salt: das Authentifizierungsgeheimnis

IKM: das mit ECDH abgeleitete gemeinsame Geheimnis

info: die Verkettung der ASCII-kodierten Zeichenkette „WebPush: info“ (ohne NUL-Terminator), eines Null-Oktetts, des öffentlichen ECDH-Schlüssels des User-Agents und des öffentlichen ECDH-Schlüssels des Anwendungsservers (beide öffentlichen Schlüssel im unkomprimierten Punktformat nach [X9.62]). Das heißt:

key_info = "WebPush: info" || 0x00 || ua_public || as_public

L: 32 Oktette (die Ausgabe hat die Länge der zugrunde liegenden SHA-256-HMAC-Ausgabe)

3.4. Zusammenfassung der Verschlüsselung

Daraus ergeben sich der endgültige Inhaltsverschlüsselungsschlüssel und die Nonce-Generierung in folgender Reihenfolge, hier als Pseudocode mit HKDF in diskreten Schritten mittels HMAC-SHA-256:

-- For a user agent:
ecdh_secret = ECDH(ua_private, as_public)
auth_secret = random(16)
salt = <from content coding header>

-- For an application server:
ecdh_secret = ECDH(as_private, ua_public)
auth_secret = <from user agent>
salt = random(16)

-- For both:

## Use HKDF to combine the ECDH and authentication secrets
# HKDF-Extract(salt=auth_secret, IKM=ecdh_secret)
PRK_key = HMAC-SHA-256(auth_secret, ecdh_secret)
# HKDF-Expand(PRK_key, key_info, L_key=32)
key_info = "WebPush: info" || 0x00 || ua_public || as_public
IKM = HMAC-SHA-256(PRK_key, key_info || 0x01)

## HKDF calculations from RFC 8188
# HKDF-Extract(salt, IKM)
PRK = HMAC-SHA-256(salt, IKM)
# HKDF-Expand(PRK, cek_info, L_cek=16)
cek_info = "Content-Encoding: aes128gcm" || 0x00
CEK = HMAC-SHA-256(PRK, cek_info || 0x01)[0..15]
# HKDF-Expand(PRK, nonce_info, L_nonce=12)
nonce_info = "Content-Encoding: nonce" || 0x00
NONCE = HMAC-SHA-256(PRK, nonce_info || 0x01)[0..11]

Hier fehlt das XOR der finalen Nonce mit der Datensatzsequenznummer, da Push-Nachrichten nur einen einzelnen Datensatz enthalten (siehe Abschnitt 4) und die Sequenznummer des ersten Datensatzes null ist.