Start · Sprachen · PHP · Referenz · openssl_dh_compute_key

openssl_dh_compute_key

Funktion

Berechnet das gemeinsame Geheimnis (Shared Secret) aus einem entfernten DH-Public-Key und dem lokalen privaten DH-Schlüssel.

seit PHP 5.3.0 Kategorie: crypto

Signatur

openssl_dh_compute_key(string $public_key, OpenSSLAsymmetricKey $private_key): string|false

Beschreibung

openssl_dh_compute_key setzt das Diffie-Hellman-Schlüsselaustauschverfahren um: Beide Kommunikationspartner erzeugen unabhängig voneinander ein DH-Schlüsselpaar und tauschen anschließend nur die öffentlichen Anteile aus. Mit dieser Funktion berechnet jede Seite aus dem empfangenen öffentlichen Schlüssel der Gegenstelle und dem eigenen privaten Schlüssel ein identisches gemeinsames Geheimnis, ohne dass dieses jemals über das Netzwerk übertragen werden muss.

Das Ergebnis ist ein binärer String, der typischerweise als Eingabe für eine Schlüsselableitungsfunktion (KDF) wie hash_hkdf() oder hash_pbkdf2() verwendet wird, um daraus symmetrische Verschlüsselungs- oder HMAC-Schlüssel abzuleiten. Der Roh-Wert sollte niemals direkt als Verschlüsselungsschlüssel eingesetzt werden.

Der Parameter public_key ist der rohe binäre öffentliche Schlüsselwert der Gegenstelle (DH public value, nicht PEM-kodiert). Der private_key muss ein DH-Schlüsselobjekt sein, das z. B. mit openssl_pkey_new() erzeugt wurde und die gleichen DH-Parameter (Primzahl p und Generator g) wie der öffentliche Schlüssel der Gegenstelle teilt.

Die Funktion ist für klassische DH-Schlüsselaustauschszenarien gedacht. Für elliptische Kurven (ECDH) steht openssl_pkey_derive() zur Verfügung, das in modernen Anwendungen bevorzugt werden sollte.

Parameter

Name Typ Default Beschreibung
$public_key Pflicht string Der rohe binäre öffentliche Schlüsselwert (DH public value) der Gegenstelle. Dies ist kein PEM- oder DER-kodiertes Zertifikat, sondern die reine Ganzzahl als binärer String, wie er z. B. durch openssl_pkey_get_details() im Feld dh['pub_key'] geliefert wird.
$private_key Pflicht OpenSSLAsymmetricKey Der lokale private DH-Schlüssel als OpenSSLAsymmetricKey-Objekt (vor PHP 8.0: resource). Er muss mit denselben DH-Parametern (p, g) erzeugt worden sein, die auch die Gegenstelle verwendet.

Rückgabewert

Typ
string|false
Beschreibung
Gibt das gemeinsame Geheimnis als binären String zurück. Im Fehlerfall (z. B. ungültige Schlüssel oder nicht passende DH-Parameter) wird false zurückgegeben.

Beispiele

DH-Schlüsselaustausch zwischen zwei Parteien simulieren

<?php
// Gemeinsame DH-Parameter (Primzahl p und Generator g)
// In der Praxis werden diese vorab ausgehandelt oder aus einem Standard übernommen.
$dhParams = [
    'private_key_type' => OPENSSL_KEYTYPE_DH,
    'dh' => [
        'p' => hex2bin(
            'ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd1' .
            '29024e088a67cc74020bbea63b139b22514a08798e3404dd' .
            'ef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245' .
            'e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed' .
            'ee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3d' .
            'c2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f' .
            '83655d23dca3ad961c62f356208552bb9ed529077096966d' .
            '670c354e4abc9804f1746c08ca18217c32905e462e36ce3b' .
            'e39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9' .
            'de2bcbf6955817183995497cea956ae515d2261898fa0510' .
            '15728e5a8aacaa68ffffffffffffffff'
        ),
        'g' => hex2bin('02'),
    ],
];

// Alice erzeugt ihr Schlüsselpaar
$aliceKey = openssl_pkey_new($dhParams);
$aliceDetails = openssl_pkey_get_details($aliceKey);

// Bob erzeugt sein Schlüsselpaar mit denselben Parametern
$bobKey = openssl_pkey_new($dhParams);
$bobDetails = openssl_pkey_get_details($bobKey);

// Alice berechnet das Shared Secret mit Bobs öffentlichem Schlüssel
$aliceSecret = openssl_dh_compute_key($bobDetails['dh']['pub_key'], $aliceKey);

// Bob berechnet das Shared Secret mit Alices öffentlichem Schlüssel
$bobSecret = openssl_dh_compute_key($aliceDetails['dh']['pub_key'], $bobKey);

// Beide Secrets müssen identisch sein
if ($aliceSecret !== false && $bobSecret !== false && hash_equals($aliceSecret, $bobSecret)) {
    echo 'Gemeinsames Geheimnis erfolgreich berechnet.' . PHP_EOL;
    echo 'Länge (Bytes): ' . strlen($aliceSecret) . PHP_EOL;
    echo 'Hex: ' . bin2hex($aliceSecret) . PHP_EOL;
} else {
    echo 'Fehler beim Berechnen des gemeinsamen Geheimnisses.' . PHP_EOL;
}
Gemeinsames Geheimnis erfolgreich berechnet. Länge (Bytes): 128 Hex: ...

Ableitung eines symmetrischen Schlüssels aus dem Shared Secret

<?php
// Annahme: $sharedSecret wurde bereits via openssl_dh_compute_key() berechnet
// und beide Parteien kennen denselben $salt-Wert (z. B. aus dem Protokoll).

$sharedSecret = '...'; // binärer String aus openssl_dh_compute_key()
$salt = random_bytes(32); // In der Praxis ausgetauscht oder aus Nonce abgeleitet

// AES-256-Schlüssel (32 Byte) mittels HKDF ableiten
$aesKey = hash_hkdf('sha256', $sharedSecret, 32, 'aes-256-cbc encryption', $salt);

echo 'AES-Schlüssel (hex): ' . bin2hex($aesKey) . PHP_EOL;
echo 'Länge: ' . strlen($aesKey) . ' Bytes' . PHP_EOL;
AES-Schlüssel (hex): ... Länge: 32 Bytes

// Wichtig · Fallstricke

Sicherheitshinweise:

  • Das Ergebnis von openssl_dh_compute_key darf niemals direkt als Verschlüsselungsschlüssel verwendet werden. Stets eine KDF (z. B. hash_hkdf()) nachschalten.
  • Klassisches DH (finite-field) gilt bei kleinen Gruppengrößen als schwach. Es wird empfohlen, mindestens 2048-Bit-Gruppen (RFC 3526) oder besser ECDH über openssl_pkey_derive() zu verwenden.
  • Die DH-Parameter (p und g) beider Seiten müssen exakt übereinstimmen, sonst schlägt die Berechnung fehl oder liefert ein falsches Ergebnis.
  • Der public_key-Parameter ist ein roher binärer Wert, kein PEM/DER-Schlüssel. Verwechslungen hier sind eine häufige Fehlerquelle.
  • Ab PHP 8.0 wurde der Typ des zweiten Parameters von resource auf OpenSSLAsymmetricKey umgestellt.