Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Web Crypto API: end-to-end encryption & privacy

Web Crypto API: end-to-end encryption & privacy

mathieuancelin

April 17, 2019
Tweet

More Decks by mathieuancelin

Other Decks in Programming

Transcript

  1. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah La crypto pour les nuls développeurs
  2. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Hachage Fonction = Input => Digest Identification unique (collision !!!), obfuscation des données, dans le cas du hash de password, salage pour ajouter de l’entropie (si salt unique et aléatoire) ◦ Génération pseudo-aléatoire du salt ◦ Dérivation cryptographique sur [salt + password] (genre bcrypt) ◦ Stockage de tous les éléments en base ◦ Stockage d'une signature HMAC du payload
  3. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Chiffrement symétrique Chiffrement basé sur une clé unique utilisée pour chiffrer et déchiffrer (AES, Blowfish, IDEA) Hello Alice Hello Alice MTYxYWY1Yz ZmNGU3NTE3 YjMwMzQyOD IwMzk= Encrypt : secret Decrypt : secret Bob Alice
  4. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Chiffrement asymétrique Chiffrement basé sur des paires de clés (publique / privée) (RSA) Hello Alice Hello Alice MTYxYWY1Yz ZmNGU3NTE3 YjMwMzQyOD IwMzk= Encrypt Alice public Decrypt Alice private Bob Alice
  5. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Signature Chiffrement asymétrique inversé Permet de valider la provenance de données Hello Alice From Bob ✅ MTYxYWY1Yz ZmNGU3NTE3 YjMwMzQyOD IwMzk= Sign Bob private Verify Bob public Bob Alice
  6. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Web Crypto API • Recommandation du W3C ◦ https://www.w3.org/TR/WebCryptoAPI • Version finale datant du 26 janvier 2017 ◦ commencée en décembre 2012 • Implémenté et supporté par la majorité des navigateurs This specification describes a JavaScript API for performing basic cryptographic operations in web applications, such as hashing, signature generation and verification, and encryption and decryption. Additionally, it describes an API for applications to generate and/or manage the keying material necessary to perform these operations. Uses for this API range from user or service authentication, document or code signing, and the confidentiality and integrity of communications.
  7. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Web Crypto API ArrayBufferView getRandomValues(ArrayBufferView array); Permet d’obtenir des valeurs pseudo-aléatoires cryptographiquement satisfaisantes. SubtleCrypto subtle; Promise<any> encrypt(AlgorithmIdentifier algorithm,CryptoKey key, BufferSource data); Promise<any> decrypt(AlgorithmIdentifier algorithm,CryptoKey key,BufferSource data); Promise<any> sign(AlgorithmIdentifier algorithm,CryptoKey key,BufferSource data); Promise<any> verify(AlgorithmIdentifier algorithm, CryptoKey key,BufferSource signature,BufferSource data); Promise<any> generateKey(AlgorithmIdentifier algorithm,boolean extractable, sequence<KeyUsage> keyUsages ); Promise<CryptoKey> importKey(KeyFormat format,(BufferSource or JsonWebKey) keyData, AlgorithmIdentifier algorithm,boolean extractable,sequence<KeyUsage> keyUsages ); Promise<any> exportKey(KeyFormat format, CryptoKey key); ...
  8. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah window.crypto.subtle The SubtleCrypto interface provides a set of methods for dealing with low-level cryptographic primitives and algorithms. It is named SubtleCrypto to reflect the fact that many of these algorithms have subtle usage requirements in order to provide the required algorithmic security guarantees. Web Crypto API
  9. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Algorithmes (peut-être) supportés • dérivation de clé: PBKDF2, HKDF, DH, CONCAT, ECDH • hachage: SHA-1, SHA-256, SHA-384, SHA-512 • key wrapping: AES-KW, AES-GCM, AES-CFB, AES-CBC, AES-CTR, RSA-OAEP • sign / verify: HMAC, AES-CMAC, ECDSA, RSA-PSS, RSASSA-PKCS1-v1_5 • encrypt / decrypt: AES-GCM, AES-CBC, AES-CFB, AES-CTR, RSA-OAEP
  10. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Mais pourquoi c’est utile ?
  11. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Mais pourquoi c’est utile ? • Globalement permet d’implémenter le chiffrement de bout en bout ◦ chiffrement directement dans le client ◦ utile pour implémenter des applications de type Zero knowledge architectures • Par exemple ◦ Multi-factor Authentication ◦ Protected Document Exchange ◦ Cloud Storage with encryption on the client ◦ Document Signing ◦ Data Integrity Protection ◦ Secure Messaging
  12. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Notre application de messagerie e2ee • chiffrée de bout en bout ◦ tout se passe dans le client • n’utilise pas de local storage ou autre pour stocker la session ◦ tout est dérivé du mot de de passe utilisé pour se connecter • volontairement simple (pour des raisons pédagogiques) ◦ pas de chiffrement côté serveur pour permettre d’inspecter l’état ◦ pas de signature des messages ni les hash de password ◦ métadonnées explicites qu’il serait facile d’éviter • nous ne sommes pas des experts en sécurité • surement pas à l’état de l’art ◦ nous n’implémentons pas le protocole Signal ;)
  13. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Notre application de messagerie e2ee https://github.com/mathieuancelin/devoxx-web-crypto-demo Démo
  14. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Lors de la création du compte • Initialisation ◦ hachage bcrypt du mot de passe ▪ passwordHash = bcrypt.hash(password, bcrypt.generateSalt(10)) ◦ génération d’un sel propre à l’utilisateur ▪ salt = bcrypt.generateSalt(10) ◦ génération d’un couple de clés (publique/privée) propre à l’utilisateur • Chiffrement de la clé privée et du sel ◦ chiffrement AES du sel avec le mot de passe de l’utilisateur ▪ encryptedSalt = aes.encrypt(salt, password) ◦ création d’un hash bcrypt du mot de passe avec le sel pour chiffrer (AES) la clé privée avec ▪ encryptedPrivateKey = aes.encrypt(privateKey, bcrypt.hash(password, salt)) • Stockage sur le serveur ◦ email, nom, clé publique, passwordHash, encryptedSalt, encryptedPrivateKey { "email": "[email protected]", "name": "Bobby Boby", "password": "$2b$2$FtXnxAf6EU", "salt": "Y2JkZmZkMTg0NWF==", "publicKey": null, "privateKey": null }
  15. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Lors de la création du compte { "email": "[email protected]", "name": "Bobby Boby", "password": "secret", "salt": null, "publicKey": null, "privateKey": null }
  16. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Lors de la création du compte • Initialisation ◦ hachage bcrypt du mot de passe ▪ passwordHash = bcrypt.hash(password, bcrypt.generateSalt(10)) { "email": "[email protected]", "name": "Bobby Boby", "password": "$2b$2$FtXnxAf6EU", "salt": null, "publicKey": null, "privateKey": null }
  17. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Lors de la création du compte • Initialisation ◦ hachage bcrypt du mot de passe ▪ passwordHash = bcrypt.hash(password, bcrypt.generateSalt(10)) ◦ génération d’un sel propre à l’utilisateur ▪ salt = bcrypt.generateSalt(10) { "email": "[email protected]", "name": "Bobby Boby", "password": "$2b$2$FtXnxAf6EU", "salt": "salty salt", "publicKey": null, "privateKey": null }
  18. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Lors de la création du compte • Initialisation ◦ hachage bcrypt du mot de passe ▪ passwordHash = bcrypt.hash(password, bcrypt.generateSalt(10)) ◦ génération d’un sel propre à l’utilisateur ▪ salt = bcrypt.generateSalt(10) ◦ génération d’un couple de clés (publique/privée) propre à l’utilisateur { "email": "[email protected]", "name": "Bobby Boby", "password": "$2b$2$FtXnxAf6EU", "salt": "salty salt", "publicKey": "a public key", "privateKey": "a private key" }
  19. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Lors de la création du compte • Initialisation ◦ hachage bcrypt du mot de passe ▪ passwordHash = bcrypt.hash(password, bcrypt.generateSalt(10)) ◦ génération d’un sel propre à l’utilisateur ▪ salt = bcrypt.generateSalt(10) ◦ génération d’un couple de clés (publique/privée) propre à l’utilisateur • Chiffrement de la clé privée et du sel ◦ chiffrement AES du sel avec le mot de passe de l’utilisateur ▪ encryptedSalt = aes.encrypt(salt, password) { "email": "[email protected]", "name": "Bobby Boby", "password": "$2b$2$FtXnxAf6EU", "salt": "wMTRhODAwYWVlYTA3Zj", "publicKey": "a public key", "privateKey": "a private key" }
  20. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Lors de la création du compte • Initialisation ◦ hachage bcrypt du mot de passe ▪ passwordHash = bcrypt.hash(password, bcrypt.generateSalt(10)) ◦ génération d’un sel propre à l’utilisateur ▪ salt = bcrypt.generateSalt(10) ◦ génération d’un couple de clés (publique/privée) propre à l’utilisateur • Chiffrement de la clé privée et du sel ◦ chiffrement AES du sel avec le mot de passe de l’utilisateur ▪ encryptedSalt = aes.encrypt(salt, password) ◦ création d’un hash bcrypt du mot de passe avec le sel pour chiffrer (AES) la clé privée avec ▪ encryptedPrivateKey = aes.encrypt(privateKey, bcrypt.hash(password, salt)) { "email": "[email protected]", "name": "Bobby Boby", "password": "$2b$2$FtXnxAf6EU", "salt": "wMTRhODAwYWVlYTA3Zj", "publicKey": "a public key", "privateKey": "BueD6aAB2L6" }
  21. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Lors de la création du compte • Initialisation ◦ hachage bcrypt du mot de passe ▪ passwordHash = bcrypt.hash(password, bcrypt.generateSalt(10)) ◦ génération d’un sel propre à l’utilisateur ▪ salt = bcrypt.generateSalt(10) ◦ génération d’un couple de clés (publique/privée) propre à l’utilisateur • Chiffrement de la clé privée et du sel ◦ chiffrement AES du sel avec le mot de passe de l’utilisateur ▪ encryptedSalt = aes.encrypt(salt, password) ◦ création d’un hash bcrypt du mot de passe avec le sel pour chiffrer (AES) la clé privée avec ▪ encryptedPrivateKey = aes.encrypt(privateKey, bcrypt.hash(password, salt)) • Stockage sur le serveur ◦ email, nom, clé publique, passwordHash, encryptedSalt, encryptedPrivateKey { "email": "[email protected]", "name": "Bobby Boby", "password": "$2b$2$FtXnxAf6EU", "salt": "wMTRhODAwYWVlYTA3Zj", "publicKey": "a public key", "privateKey": "BueD6aAB2L6" }
  22. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Lors du login • Vérification serveur ◦ couple email / bcrypt.compareSync(password, passwordHash) ◦ retourne (email, nom, clé publique, passwordHash, encryptedSalt, encryptedPrivateKey) • Déchiffrement du sel ◦ salt = aes.decrypt(user.encryptedSalt, password) • Déchiffrement de la clé privée ◦ privateKey = aes.decrypt(user.encryptedPrivateKey, bcrypt.hash(password, salt)) • On oublie le mot de passe !!!
  23. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Envoi d’un message • Génération d’une clé aléatoire ◦ randomKey = crypto.getRandomValues() • Chiffrement AES du contenu du message avec la clé aléatoire ◦ encryptedMessage = aes.encrypt(message, randomKey) • Chiffrement RSA de la clé aléatoire avec la clé publique du destinataire ◦ encryptedRandomKey = rsa.encrypt(randomKey, alicePublicKey) • Stockage serveur ◦ (from, to, date, id, encryptedRandomKey, encryptedMessage)
  24. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Envoi d’un message { "key": null, "content": "un message", "from": "[email protected]", "to": "[email protected]", "at": 1555451160579, "id": "Fv+mPQxNtqJpa9E28wrW2w==" }
  25. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Envoi d’un message • Génération d’une clé aléatoire (unique / message) ◦ randomKey = crypto.getRandomValues() { "key": "a random value", "content": "un message", "from": "[email protected]", "to": "[email protected]", "at": 1555451160579, "id": "Fv+mPQxNtqJpa9E28wrW2w==" }
  26. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Envoi d’un message • Génération d’une clé aléatoire ◦ randomKey = crypto.getRandomValues() • Chiffrement AES du contenu du message avec la clé aléatoire ◦ encryptedMessage = aes.encrypt(message, randomKey) { "key": "a random value", "content": "ZWVhOTU4ODUxZDFi", "from": "[email protected]", "to": "[email protected]", "at": 1555451160579, "id": "Fv+mPQxNtqJpa9E28wrW2w==" }
  27. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Envoi d’un message • Génération d’une clé aléatoire ◦ randomKey = crypto.getRandomValues() • Chiffrement AES du contenu du message avec la clé aléatoire ◦ encryptedMessage = aes.encrypt(message, randomKey) • Chiffrement RSA de la clé aléatoire avec la clé publique du destinataire ◦ encryptedRandomKey = rsa.encrypt(randomKey, alicePublicKey) { "key": "MGQ1MTUwZTU2ZWRmNWMxY", "content": "ZWVhOTU4ODUxZDFi", "from": "[email protected]", "to": "[email protected]", "at": 1555451160579, "id": "Fv+mPQxNtqJpa9E28wrW2w==" }
  28. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Envoi d’un message • Génération d’une clé aléatoire ◦ randomKey = crypto.getRandomValues() • Chiffrement AES du contenu du message avec la clé aléatoire ◦ encryptedMessage = aes.encrypt(message, randomKey) • Chiffrement RSA de la clé aléatoire avec la clé publique du destinataire ◦ encryptedRandomKey = rsa.encrypt(randomKey, alicePublicKey) • Stockage serveur ◦ (from, to, date, id, encryptedRandomKey, encryptedMessage) { "key": "MGQ1MTUwZTU2ZWRmNWMxY", "content": "ZWVhOTU4ODUxZDFi", "from": "[email protected]", "to": "[email protected]", "at": 1555451160579, "id": "Fv+mPQxNtqJpa9E28wrW2w==" }
  29. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Lecture d’un message • Déchiffrement RSA de la clé aléatoire du message avec la clé privée ◦ randomKey = rsa.decrypt(message.encryptedRandomKey, alicePrivateKey) • Déchiffrement AES du contenu du message avec la clé aléatoire ◦ content = aes.decrypt(message.encryptedMessage, randomKey)
  30. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Lecture d’un message { "key": "MGQ1MTUwZTU2ZWRmNWMxY", "content": "ZWVhOTU4ODUxZDFi", "from": "[email protected]", "to": "[email protected]", "at": 1555451160579, "id": "Fv+mPQxNtqJpa9E28wrW2w==" }
  31. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Lecture d’un message • Déchiffrement RSA de la clé aléatoire du message avec la clé privée ◦ randomKey = rsa.decrypt(message.encryptedRandomKey, alicePrivateKey) { "key": "a random value", "content": "ZWVhOTU4ODUxZDFi", "from": "[email protected]", "to": "[email protected]", "at": 1555451160579, "id": "Fv+mPQxNtqJpa9E28wrW2w==" }
  32. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Lecture d’un message • Déchiffrement RSA de la clé aléatoire du message avec la clé privée ◦ randomKey = rsa.decrypt(message.encryptedRandomKey, alicePrivateKey) • Déchiffrement AES du contenu du message avec la clé aléatoire ◦ content = aes.decrypt(message.encryptedMessage, randomKey) { "key": "a random value", "content": "un message", "from": "[email protected]", "to": "[email protected]", "at": 1555451160579, "id": "Fv+mPQxNtqJpa9E28wrW2w==" }
  33. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Utilisation de la Web Crypto API https://github.com/diafygi/webcrypto-example
  34. Mathieu ANCELIN @TrevorReznik / Fedy Salah @fedysalah Mathieu ANCELIN @TrevorReznik

    / Fedy Salah @fedysalah Utilisez des librairies Il est très facile de se tromper en utilisant la Web Crypto API (comme vous l’avez vu, il faut être un peu du coin) De nombreuses librairies existent pour éviter d’avoir à gérer tout ça à la main. Parfois ce sont des wrapper de la Web Crypto API, parfois des ré-implémentations complètes • JSEncrypt • js-nacl • openpgp.js • ... https://gist.github.com/jo/8619441