Slide 1

Slide 1 text

Tim Taubert @ttaubert Keeping secrets with JavaScript An Introduction to the WebCrypto API September 2014, Berlin February 2015, Brussels

Slide 2

Slide 2 text

WHY A CRYPTO API?

Slide 3

Slide 3 text

NOW WITH 100% MORE CRYPTO YET ANOTHER NOTES APP

Slide 4

Slide 4 text

// var NotesStorage = { load: function () { return localforage.getItem("notes"); }, save: function (notes) { return localforage.setItem("notes", notes); } };

Slide 5

Slide 5 text

NotesStorage.save([ {title: "Return $200 to Alice"}, {title: "Buy soy milk", due: "2014-09-15"} ]);

Slide 6

Slide 6 text

INTEGRITY

Slide 7

Slide 7 text

> sha256sum ubuntu-14.10-desktop-amd64.iso 22ee4a41c010a027c7d298e3c985e9e5 \ 68c2a743ee0b0f97f0806285f44babb1

Slide 8

Slide 8 text

SHA-256 CRYPTOGRAPHIC HASH FUNCTION

Slide 9

Slide 9 text

SHA-256 "Lorem ipsum dolor sit amet" 0x8a995db78d0… (data) (digest)

Slide 10

Slide 10 text

// Compute a 256-bit digest. crypto.subtle.digest("SHA-256", data) .then(function (digest) { console.log(digest); }); // Output: ArrayBuffer {byteLength: 32} W3C API EXAMPLE https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html

Slide 11

Slide 11 text

window.crypto.subtle “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.”

Slide 12

Slide 12 text

save: function (buffer) { // Compute the SHA-256 digest. return crypto.subtle.digest("SHA-256", buffer) .then(function (digest) { return Promise.all([ localforage.setItem("notes", buffer), localforage.setItem("notes_hash", digest) ]); }); }

Slide 13

Slide 13 text

load: function () { var values = Promise.all([ localforage.getItem("notes"), localforage.getItem("notes_hash") ]); return values.then(function ([notes, notes_hash]) { // Compute the SHA-256 digest for |notes|. return crypto.subtle.digest("SHA-256", notes) .then(function (digest) { if (compare(notes_hash, digest)) { return notes; } }); }); }

Slide 14

Slide 14 text

INTEGRITY & AUTHENTICITY

Slide 15

Slide 15 text

HMAC-SHA-256 HASH-BASED MESSAGE AUTHENTICATION CODE

Slide 16

Slide 16 text

HMAC "Lorem ipsum dolor sit amet" 0x8a995db78d0… (data) (mac) 0x1234567890a… (key)

Slide 17

Slide 17 text

// Compute a 256-bit HMAC. crypto.subtle.sign("HMAC", key, data) .then(function (mac) { console.log(mac); }); // Output: ArrayBuffer // Verify an HMAC. crypto.subtle.verify("HMAC", key, mac, data) .then(function (valid) { console.log(valid); }); // Output: bool W3C API EXAMPLE https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html

Slide 18

Slide 18 text

save: function (key, buffer) { // Generate a MAC using the given key. return crypto.subtle.sign("HMAC", key, buffer) .then(function (mac) { return Promise.all([ localforage.setItem("notes", buffer), localforage.setItem("notes_mac", mac) ]); }); }

Slide 19

Slide 19 text

load: function (key) { var values = Promise.all([ localforage.getItem("notes"), localforage.getItem("notes_mac") ]); return values.then(function ([notes, notes_mac]) { // Verify the MAC using the given key. return crypto.subtle.verify("HMAC", key, notes_mac, notes) .then(function (valid) { if (valid) { return notes; } }); }); }

Slide 20

Slide 20 text

PASSWORDS ARE NOT CRYPTOGRAPHIC KEYS

Slide 21

Slide 21 text

KEY DERIVATION

Slide 22

Slide 22 text

// Derive a new key from a given key. crypto.subtle.deriveKey(algorithm, baseKey, derivedKeyType, extractable, keyUsages) .then(function (key) { console.log(key); }); // Output: CryptoKey object W3C API EXAMPLE https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html

Slide 23

Slide 23 text

PBKDF2 PASSWORD-BASED KEY DERIVATION

Slide 24

Slide 24 text

PBKDF2 "rbW-fk8;#9" 0x8a995db78d0… (password) (key) 0x572bf6e4ef8a… (salt) 5000 (iterations)

Slide 25

Slide 25 text

function deriveKey(pwKey, salt) { var params = { name: "PBKDF2", hash: "SHA-256", salt: salt, // The more iterations the slower, but also more secure. iterations: 5000 }; // The derived key will be used to compute HMACs. var alg = {name: "HMAC", hash: "SHA-256"}; var usages = ["sign", "verify"]; return crypto.subtle.deriveKey( params, pwKey, alg, false, usages); }

Slide 26

Slide 26 text

function retrievePWKey() { // We will derive a new key from it. var usages = ["deriveKey"]; // Show a native password input dialog. return crypto.subtle.generateKey( "PBKDF2", false, usages); }

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

function getSalt() { // Try to read a stored salt. return localforage.getItem("salt") .then(function (salt) { if (salt) { return salt; } // We should generate at least 8 bytes // to allow for 2^64 possible variations. var salt = crypto.getRandomValues(new Uint8Array(8)); return localforage.setItem("salt", salt); }); }

Slide 29

Slide 29 text

var params = Promise.all([ // Get base key and salt. retrievePWKey(), getSalt() ]); var derivedKey = params.then(function ([pwKey, salt]) { // Do the PBKDF2 dance. return deriveKey(pwKey, salt); }); derivedKey.then(function (key) { // Store notes using the generated key. NotesStorage.save(key, buffer); });

Slide 30

Slide 30 text

INTEGRITY, AUTHENTICITY & SECRECY

Slide 31

Slide 31 text

// Encrypt |data| under |key| using |alg|. crypto.subtle.encrypt(alg, key, data) .then(function (ct) { console.log(ct); }); // Output: ArrayBuffer // Decrypt |data| using |key| and algorithm |alg|. crypto.subtle.decrypt(alg, key, data) .then(function (pt) { console.log(pt); }); // Output: ArrayBuffer W3C API EXAMPLE https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html

Slide 32

Slide 32 text

AES-GCM ADVANCED ENCRYPTION STANDARD IN GALOIS/COUNTER MODE

Slide 33

Slide 33 text

AES-GCM "Lorem ipsum dolor sit amet" 0xb5c73a8820a… (data) (ciphertext + mac) 0x1234567890a… (key) 0xd877fa3e919… (nonce)

Slide 34

Slide 34 text

function deriveKey(pwKey, salt) { var params = { // … }; // The derived key will be used for AES. var alg = {name: "AES-GCM", length: 256}; var usages = ["encrypt", "decrypt"]; return crypto.subtle.deriveKey( params, pwKey, alg, false, usages); }

Slide 35

Slide 35 text

save: function (key, buffer) { // Set up parameters. var nonce = crypto.getRandomValues(new Uint8Array(16)); var alg = {name: "AES-GCM", iv: nonce}; // Encrypt |buffer| under |key| using AES-GCM. return crypto.subtle.encrypt(alg, key, buffer) .then(function (notes_enc) { return Promise.all([ localforage.setItem("notes", notes_enc), localforage.setItem("nonce", nonce) ]); }); }

Slide 36

Slide 36 text

load: function (key) { var values = Promise.all([ localforage.getItem("notes"), localforage.getItem("nonce") ]); return values.then(function ([enc_notes, nonce]) { var alg = {name: "AES-GCM", iv: nonce}; return crypto.subtle.decrypt(alg, key, enc_notes) .then(null, function (err) { // Verification failed. }); }); }

Slide 37

Slide 37 text

\o/ https://github.com/ttaubert/secret-notes

Slide 38

Slide 38 text

RECAP

Slide 39

Slide 39 text

COMPARE() SHA-256 RENDER (digest) DISCARD LOAD NOTES LOAD HASH EQUAL? (yes) (no) STORAGE SAFE AGAINST CORRUPTIONS

Slide 40

Slide 40 text

HMAC-VERIFY RENDER DISCARD LOAD KEY LOAD MAC VALID? (yes) (no) STORAGE SAFE AGAINST TAMPERING LOAD NOTES

Slide 41

Slide 41 text

HMAC-VERIFY RENDER DISCARD LOAD SALT LOAD MAC VALID? (yes) (no) STORAGE SAFE AGAINST TAMPERING PROTECTED BY A USER-GIVEN PASSWORD LOAD NOTES PBKDF2 (derived key) PW PROMPT

Slide 42

Slide 42 text

AES-GCM RENDER DISCARD LOAD SALT LOAD NONCE VALID? (yes) (no) STORAGE SAFELY ENCRYPTED BY A USER-GIVEN PASSWORD LOAD NOTES PBKDF2 (derived key) PW PROMPT

Slide 43

Slide 43 text

@dreid 20 years of abstinence-only cryptography education hasn't gotten us anything but an endless supply of bad crypto in production systems.

Slide 44

Slide 44 text

Stanford - Cryptography I + II by Dan Boneh https://www.coursera.org/course/crypto Introduction to Cryptography by Christof Paar https://www.youtube.com/channel/UC1usFRN4LCMcfIV7UjHNuQg/videos LEARNING RESOURCES

Slide 45

Slide 45 text

THANKS @ttaubert tim@timtaubert.de https://timtaubert.de/talks/keeping-secrets-with-javascript/