Gerne wird bei Produkten eine Ende-zu-Ende-Verschlüsselung (E2EE) angepriesen, aber wie genau funktioniert das eigentlich? Wie kommen überhaupt die passenden Schlüssel vom Sender zum Empfänger und auch wieder zurück? Wie werden diese Schlüssel überhaupt übertragen und wie speichert der Anbieter diese Informationen?
Ich versuche jetzt mal anhand eines Beispiels das Szenario durchzuspielen und zwar von Anfang bis Ende. In diesem Falle schreibe ich über ProtonMail, da wir dies dort auch belegen können anhand von Code Schnipseln.
Fangen wir bei der Registrierung und dem Login an. Wir geben in der Regel unseren Benutzernamen oder E-Mail an + das zugehörige Passwort. Man könnte meinen hier wird das Passwort übertragen, aber dem ist nicht so. Proton nutzt in diesem Falle und überall da wo man seine Logindaten angeben muss das Secure Remote Password (SRP) Protokoll. Der Server erhält darüber nicht das Passwort, sondern nur ein Beweis, dass das eingegebene Passwort Richtig sein muss. Also wird kein Passwort übertragen. Dies gilt natürlich auch für die diversen Smartphone Apps, Windows Software und Webapps.
const result = await getSrp(data, credentials)
sendToServer({
clientEphemeral: result.clientEphemeral,
clientProof: result.clientProof
})Ein ganz wichtiger Part ist auch das beim Erstellen deines Accounts ein für dich generiertes Schlüsselpärchen angelegt worden ist. Das besondere, der Private Schlüssel wird nochmals verschlüsselt mit deinem Passwort. So hat auch Proton keinen Zugriff auf deinen privaten Schlüssel, sondern nur du mit deinem Geheimen Passwort.
Fassen wir zusammen, dein Passwort liegt nicht gehashed auf dem Server, dein Privater Schlüssel ist verschlüsselt mit deinem Passwort und dein öffentlicher Schlüssel ist zugängig für andere die dich erreichen wollen. Also alles was irgendwie dich gefährden könnte, wird bei dir am PC / Smartphone im Javascript ausgeführt, damit das auch niemals dein Endgerät verlässt. Überprüfen können wir das im Opensource Quellcode.
// 1. keypair erzeugen
const key = await openpgp.generateKey({
type: 'ecc',
curve: 'curve25519',
userIDs: [{ email }]
})
// 2. passphrase aus user password ableiten
const keyEncryptionKey = bcrypt(password, salt)
// 3. private key verschlüsseln
const encryptedPrivateKey =
AES256_encrypt(key.privateKey, keyEncryptionKey)
// 4. an server senden
api.post("/keys", {
PublicKey: key.publicKey,
PrivateKey: encryptedPrivateKey
})Versenden einer verschlüsselten Mail
Nehmen wir an, du versendest von deiner ProtonMail Adresse an eine anderen ProtonMail Adresse. Den Inhalt hast du nun geschrieben und den Empfänger eingetragen, danach drückst du auf „Absenden“. Folgender Prozess startet nun, bis die Mail wieder leserlich beim Empfänger an kommt er und diesen unverschlüsselt in Klartext lesen kann.
Als erstes wird der öffentliche Schlüssel vom ProtonMail Empfänger abgefragt (der ist ja frei zugänglich). Dein Client erstellt/generiert einen neuen symmetrischen Schlüssel und verschlüsselt den gesamten Mailinhalt damit. Der soeben erstelle symmetrische Schlüssel, wird jetzt mit dem öffentlichen Schlüssel des Mailempfängers verschlüsselt. Das Ergebnis ist ein PGP-Message-Block. Optional würde es sogar noch ein Signieren geben, das lasse ich aber mal außen vor.
const encrypted = await openpgp.encrypt({
message: await openpgp.createMessage({ text: body }),
encryptionKeys: recipientPublicKeys,
signingKeys: senderPrivateKey
});Die Mail kommt also nun komplett verschlüsselt beim Empfänger an. Proton hatte bis hier her niemals die Chance irgendwas lesen zu können.
Empfang der verschlüsselten Mail
Die Mail liegt nun im Postfach auf dem Server und wir öffnen unsere ProtonMail App. Der Prozess mit der Anmeldung durchläuft, niemand sieht ein Passwort oder ähnliches. Dadurch das wir ja unser eigenes Passwort haben, kommen wir auch an unseren eigenen Private Key zum entschlüsseln von Daten heran. Mit diesem Privaten Schlüssel können wir und auch nur wir, nun den übertragenen PGP-Message-Block entschlüsseln und die Mail im Klartext lesen.
Es wird alles an der Mail verschlüsselt, also auch Header Informationen.
import * as openpgp from 'openpgp';
export async function decryptMessage({
armoredMessage,
privateKeys,
publicKeys
}) {
const message = await openpgp.readMessage({
armoredMessage
});
const { data, signatures } = await openpgp.decrypt({
message,
decryptionKeys: privateKeys,
verificationKeys: publicKeys
});
return {
data,
signatures
};
}Ein paar Daten kennt Proton dann doch
Naja, ein paar Daten kennt Proton ja dann doch von dir. Den Absender und Empfänger, den Zeitstempel, ggf. eine Versionsnummer von deinem Client und natürlich deine eigene IP-Adresse. Aber zum verschleiern deiner IP, gibt es ja den eigenen VPN Dienst oder viele Alternativen. Wer sich also verstecken will, der sollte auch den Client wechseln und ggf. mal ältere Versionen nutzen etc.. Aber das geht hier zu weit. 😉
ProtonPass funktioniert ähnlich
Bei dem Produkt ProtonPass ist die Herangehensweise sehr ähnlich, auch dort wird über deinen eigenen Key + zusätzlich zu einem Vault-Key verschlüsselt. Damit liegen wieder die Daten auf dem Server, aber nur du mit deinem Passwort kommst an die Daten heran.
Fazit
Ich muss zunächst erwähnen ich schreibe diesen Beitrag hier unbezahlt und ohne Aufforderung von Proton. Ich bin von der Art und Weise wie Proton mit deinen Daten umgeht begeistert und das gleichzeitig bei völliger Offenheit. Es wird auf die aktuellsten Kryptografie-Standards gesetzt und alles wird auf dem Client ausgeführt. Ich nutze nun seit über 1 Jahr nun ProtonMail & ProtonPass und bin von der Integration begeistert. Von mir gibt es dafür eine 1+ mit Sternchen, aber mehr geht immer. 🙂
Wenn Ihr Bock habt das ganze zu testen, dann nutzt gerne meine Links, da bekommt Ihr bis zu 50% Rabatt. Hier ist der Link.

Quelle von den Code-Schnippseln (GitHub): https://github.com/ProtonMail/WebClients



Schreibe einen Kommentar