Slide 1

Slide 1 text

Securing TodoMVC Using the Web Cryptography API Kevin Hakanson 12 September 2014

Slide 2

Slide 2 text

Kevin Hakanson @hakanson +KevinHakanson hakanson

Slide 3

Slide 3 text

Project which offers the same Todo application implemented using MV* concepts in most of the popular JavaScript MV* frameworks of today. http://todomvc.com/ https://github.com/tastejs/todomvc

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Today's Session "todos" ● Review some cryptography concepts ● Look at the Web Cryptography API ● Combine these to secure TodoMVC

Slide 6

Slide 6 text

Supporting Materials (if you want to follow along) Presentation and Source Code https://github.com/hakanson/todomvc-jquery-webcryptoapi Demo https://hakanson.github.io/todomvc-jquery-webcryptoapi

Slide 7

Slide 7 text

Why?

Slide 8

Slide 8 text

TodoMVC Uses localStorage Chrome keeps localStorage in an SQLite file: OS X: ~/Library/Application Support/Google/Chrome/Default/Local Storage Windows: %HOMEPATH%\AppData\Local\Google\Chrome\User Data\Default\Local Storage $ sqlite3 http_todomvc.com_0.localstorage sqlite> select * from ItemTable; todos-jquery|[{"id":"c8f7b7e1-88bf-451b-8aff- 04c9ac2544aa","title":"secure using Web Cryptography API","completed":false}]

Slide 9

Slide 9 text

OWASP Top 10 2013 ● A1-Injection ● A2-Broken Authentication and Session Management ● A3-Cross-Site Scripting (XSS) ● A4-Insecure Direct Object References ● A5-Security Misconfiguration ● A6-Sensitive Data Exposure ● A7-Missing Function Level Action Control ● A8-Cross-Site Request Forgery (CSRF) ● A9-Using Components with Known Vulnerabilities ● A10-Unvalidated Redirects and Forwards https://www.owasp.org/index.php/Top_10_2013

Slide 10

Slide 10 text

A6-Sensitive Data Exposure Covers sensitive data protection from the moment sensitive data is provided by the user, sent to and stored within the application, and then sent back to the browser again.

Slide 11

Slide 11 text

A6-Sensitive Data Exposure Am I Vulnerable To 'Sensitive Data Exposure'? 1. Is any of this data stored in clear text long term, including backups of this data? 2. … 3. … 4. … 5. … https://www.owasp.org/index.php/Top_10_2013-A6

Slide 12

Slide 12 text

Acceptance Criteria ● Enter password before accessing "todos" ● Data encrypted "at rest" in localStorage

Slide 13

Slide 13 text

How?

Slide 14

Slide 14 text

W3C Web Cryptography API 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. http://www.w3.org/TR/WebCryptoAPI/

Slide 15

Slide 15 text

WebCryptoAPI Use Cases ● Multi-factor Authentication ● Protected Document Exchange ● Cloud Storage ● Document Signing ● Data Integrity Protection ● Secure Messaging ● Javascript Object Signing and Encryption (JOSE) http://www.w3.org/TR/WebCryptoAPI/#use-cases

Slide 16

Slide 16 text

SubtleCrypto Interface ● Provides a set of methods for dealing with low-level cryptographic primitives and algorithms. ● 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 17

Slide 17 text

Web Cryptography Working Group Key Dates ○ April 2012: Group Formation ○ March 2014: Last Call Working Draft ○ ????: Expected Candidate Recommendation ○ ????: Expected Proposed Recommendation ○ 2015: Expected Recommendation http://www.w3.org/2012/webcrypto/Overview.html

Slide 18

Slide 18 text

Where? (Browser Support)

Slide 19

Slide 19 text

Chromium Dashboard Web Crypto API Implementation Status Enabled by default in desktop Chrome 37 (launch bug) Available in Chrome for Android release 37. Consensus & Standardization ● Firefox: In development ● Internet Explorer: In development ● Opera: Shipped in release 24 ● Opera for Android: Shipped in release 24 ● Safari: In development ● Web Developers: Mixed signals

Slide 20

Slide 20 text

http://caniuse.com/#search=Web Cryptography

Slide 21

Slide 21 text

IE Platform Status Web Crypto API Note: IE11 implementation based on spec before change from CryptoOperation to Promise based API

Slide 22

Slide 22 text

Promises/A+ A promise represents the eventual result of an asynchronous operation. The primary way of interacting with a promise is through its then method, which registers callbacks to receive either a promise's eventual value or the reason why the promise cannot be fulfilled.

Slide 23

Slide 23 text

Chromium Dashboard Promises (ES6) Implementation Status Enabled by default in desktop Chrome 32 (launch bug) Available in Chrome for Android release 32. Consensus & Standardization ● Firefox: Shipped ● Internet Explorer: Public support ● Opera: Shipped in release 19 ● Opera for Android: Shipped in release 19 ● Safari: In development ● Web Developers: Mixed signals

Slide 24

Slide 24 text

Microsoft Research JavaScript Cryptography Library ● The algorithms are exposed via the W3C WebCrypto interface, and are tested against the Internet Explorer 11 implementation of that interface. ● This library is under active development. Future updates to this library may change the programming interfaces. Date Published:17 June 2014

Slide 25

Slide 25 text

But...

Slide 26

Slide 26 text

Javascript Cryptography Considered Harmful (circa 2010) ● Opinion on browser Javascript cryptography ○ "no reliable way for any piece of Javascript code to verify its execution environment" ○ "can't outsource random number generation in a cryptosystem" ○ "practically no value to doing crypto in Javascript once you add SSL to the mix" ○ "store the key on that server [and] documents there" http://www.matasano.com/articles/javascript-cryptography/ ● Didn't consider the "offline" user experience

Slide 27

Slide 27 text

Host-Proof Hosting ● In A Blink ○ Sketch: Locked inside data cloud, key at browser. ● Solution ○ Host sensitive data in encrypted form, so that clients can only access and manipulate it by providing a pass-phrase which is never transmitted to the server. ○ All encryption and decryption takes place inside the browser itself. http://ajaxpatterns.org/Host-Proof_Hosting (July 2005)

Slide 28

Slide 28 text

Host-Proof Hosting "Requirements" ● Secure transport mechanism (HTTPS). ● Trust provider that hosts web application and serves HTML and JavaScript resources. ● Defend against and accept risk of script injection (XSS) threat. ○ However, unauthorized access by hackers only attacks users who access the application while infected, and not the entire persisted data store.

Slide 29

Slide 29 text

My "Requirement" ● Avoid proving "Schneier's Law" ○ Anyone can invent a security system that he himself cannot break.

Slide 30

Slide 30 text

What? (concepts)

Slide 31

Slide 31 text

Glossary Glossary of Key Information Security Terms http://nvlpubs.nist.gov/nistpubs/ir/2013/NIST.IR.7298r2.pdf SOURCE: NISTIR 7298

Slide 32

Slide 32 text

Cryptography The discipline that embodies principles, means, and methods for providing information security, including confidentiality, data integrity, non- repudiation, and authenticity. SOURCE: SP 800-21

Slide 33

Slide 33 text

Pseudorandom number generator (PRNG) An algorithm that produces a sequence of bits that are uniquely determined from an initial value called a seed. The output of the PRNG “appears” to be random. A cryptographic PRNG has the additional property that the output is unpredictable, given that the seed is not known. SOURCE: CNSSI-4009

Slide 34

Slide 34 text

crypto.getRandomValues() If you provide an integer-based TypedArray, the function is going fill the array with cryptographically random numbers. var buf = new Uint8Array(32); window.crypto.getRandomValues(buf); https://developer.mozilla.org/en-US/docs/DOM/window.crypto.getRandomValues http://msdn.microsoft.com/en-us/library/ie/dn302324(v=vs.85).aspx

Slide 35

Slide 35 text

Cryptographic Hash Function A function that maps a bit string of arbitrary length to a fixed length bit string. Approved hash functions satisfy the following properties: ● One-way ● Collision resistant SOURCE: SP 800-21

Slide 36

Slide 36 text

Message Digest The result of applying a hash function to a message. Also known as a “hash value” or “hash output”. SOURCE: SP 800-107

Slide 37

Slide 37 text

OpenSSL Command Line $ echo -n "The quick brown fox jumps over the lazy dog" | openssl dgst -sha256 (stdin)= d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb76 2d02d0bf37c9e592

Slide 38

Slide 38 text

QUnit Test QUnit.test( 'SHA-256', function ( assert ) { var testVector = { data: 'The quick brown fox jumps over the lazy dog', sha256Hash : 'd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592' }; var encoder = new TextEncoder(); var dataBuf = encoder.encode( testVector.data ); assert.promise( crypto.subtle.digest( { name: 'sha-256' }, dataBuf ) .then( function (result) { var hash = $.Uint8Util.toHexString( new Uint8Array( result ) ); assert.equal( hash, testVector.sha256Hash ); })); });

Slide 39

Slide 39 text

QUnit Extension QUnit.extend( QUnit.assert, { promise: function ( promise ) { var assert = this; QUnit.stop(); promise.catch( function ( err ) { assert.ok( false, err.message ); }).then( function ( ) { QUnit.start(); }); } });

Slide 40

Slide 40 text

ex: DOMException code: 9 message: "WebCrypto is only supported over secure origins. See http://crbug.com/373032" name: "NotSupportedError" __proto__: DOMException For example these are considered secure origins: ● chrome-extension://xxx ● https://xxx ● wss://xxx ● file://xxx ● http://localhost/ ● http://127.0.0.1/ Whereas these are considered insecure: ● http://foobar ● ws://foobar

Slide 41

Slide 41 text

TextEncoder Encoding API Script API to allow encoding/decoding of strings from binary data. Firefox 19 https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder Intent to Ship in Chrome 38 Issue 243354: Implement Text Encoding API Polyfill https://github.com/inexorabletash/text-encoding

Slide 42

Slide 42 text

$.Uint8Util toHexString( buf : Uint8Array ) : string fromHexString ( s : string ) : Uint8Array (still looking for a better way)

Slide 43

Slide 43 text

$.WebCryptoAPI Wrapper around: ● crypto (WebCrypto spec) ● msCrypto (IE11) ● msrCrypto (Microsoft Research) ● webkitSubtle (Webkit Nightly) Implemented as jQuery Utility Plugin

Slide 44

Slide 44 text

Hash-based Message Authentication Code (HMAC) A message authentication code that uses a cryptographic key in conjunction with a hash function. SOURCE: FIPS 201; CNSSI-4009

Slide 45

Slide 45 text

Cryptographic Key A parameter used in conjunction with a cryptographic algorithm that determines ● the transformation of plaintext data into ciphertext data, ● the transformation of ciphertext data into plaintext data, ● a digital signature computed from data, ● ... SOURCE: FIPS 140-2

Slide 46

Slide 46 text

Symmetric Key A cryptographic key that is used to perform both the cryptographic operation and its inverse, for example to encrypt and decrypt, or create a message authentication code and to verify the code. SOURCE: SP 800-63; CNSSI-4009

Slide 47

Slide 47 text

Digital Signature The result of a cryptographic transformation of data which, when properly implemented, provides the services of: 1. origin authentication, 2. data integrity, and 3. signer non-repudiation. SOURCE: FIPS 140-2

Slide 48

Slide 48 text

OpenSSL Command Line $ echo -n "The quick brown fox jumps over the lazy dog" | openssl dgst - sha256 -hmac "key" (stdin)= f7bc83f430538424b13298e6aa6fb143ef4d59 a14946175997479dbc2d1a3cd8

Slide 49

Slide 49 text

QUnit.test( 'HMAC using SHA-256', function ( assert ) { var testVector = { data: 'The quick brown fox jumps over the lazy dog', key: 'key', hash : 'f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8' }; var hmacSha256 = { name: 'hmac', hash: { name: 'sha-256' } }; var encoder = new TextEncoder(); var dataBuf = encoder.encode( testVector.data ); var keyBuf = encoder.encode( testVector.key ); });

Slide 50

Slide 50 text

QUnit.test( 'HMAC using SHA-256', function ( assert ) { var testVector = { data: 'The quick brown fox jumps over the lazy dog', key: 'key', hash : 'f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8' }; var hmacSha256 = { name: 'hmac', hash: { name: 'sha-256' } }; var encoder = new TextEncoder(); var dataBuf = encoder.encode( testVector.data ); var keyBuf = encoder.encode( testVector.key ); assert.promise( crypto.subtle.importKey( 'raw', keyBuf, hmacSha256, true, ['sign', 'verify'] ) .then( function ( keyResult ) { })); });

Slide 51

Slide 51 text

QUnit.test( 'HMAC using SHA-256', function ( assert ) { var testVector = { data: 'The quick brown fox jumps over the lazy dog', key: 'key', hash : 'f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8' }; var hmacSha256 = { name: 'hmac', hash: { name: 'sha-256' } }; var encoder = new TextEncoder(); var dataBuf = encoder.encode( testVector.data ); var keyBuf = encoder.encode( testVector.key ); assert.promise( crypto.subtle.importKey( 'raw', keyBuf, hmacSha256, true, ['sign', 'verify'] ) .then( function ( keyResult ) { return crypto.subtle.sign( hmacSha256, keyResult, dataBuf ) .then( function ( signResult ) { var hash = $.Uint8Util.toHexString( new Uint8Array( signResult ) ); assert.equal( hash, testVector.hash ); }) })); });

Slide 52

Slide 52 text

KJH-256 Hash QUnit.test( 'KJH-256', function ( assert ) { var testVector = { data: 'The quick brown fox jumps over the lazy dog', }; var encoder = new TextEncoder(); var dataBuf = encoder.encode( testVector.data ); assert.promise( crypto.subtle.digest( { name: 'kjh-256' }, dataBuf ) .then( function ( result ) { var hash = $.Uint8Util.toHexString( new Uint8Array( result ) ); assert.equal( hash, 'kjh' ); })); });

Slide 53

Slide 53 text

Error Results IE 11 NotSupportedError Chrome 37 Algorithm: Unrecognized name Firefox 35 An invalid or illegal string was specified Opera 24 Algorithm: Unrecognized name MSR Crypto 1.2 unsupported algorithm Webkit Nightly NotSupportedError: DOM Exception 9

Slide 54

Slide 54 text

QUnit.test( 'HMAC using KJH-256', function ( assert ) { var testVector = { data: 'The quick brown fox jumps over the lazy dog', key: 'key' }; var encoder = new TextEncoder(); var dataBuf = encoder.encode( testVector.data ); var keyBuf = encoder.encode( testVector.key ); var hmacKjh256 = { name: 'hmac', hash: { name: 'kjh-256' } }; assert.promise( crypto.subtle.importKey( 'raw', keyBuf, hmacKjh256, true, ['sign', 'verify'] ) .then( function ( keyResult ) { return crypto.subtle.sign( hmacKjh256, keyResult, dataBuf ) .then( function ( signResult ) { var hash = $.Uint8Util.toHexString( new Uint8Array( signResult ) ); assert.equal( hash, 'kjh' ); }) })); });

Slide 55

Slide 55 text

Error Results IE 11 failed, expected argument to be truthy, was: false Chrome 37 HmacImportParams: hash: Algorithm: Unrecognized name Firefox 35 An invalid or illegal string was specified Opera 24 HmacImportParams: hash: Algorithm: Unrecognized name MSR Crypto 1.2 Error: unsupported hash alorithm (sha-224, sha-256, sha-384, sha-512) Webkit Nightly NotSupportedError: DOM Exception 9

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

Cipher, Plaintext and Ciphertext Cipher - Series of transformations that converts plaintext to ciphertext using the Cipher Key. See Also: Inverse Cipher SOURCE: FIPS 197

Slide 58

Slide 58 text

AES The Advanced Encryption Standard specifies a U.S. government approved cryptographic algorithm that can be used to protect electronic data. The AES algorithm is a symmetric block cipher that can encrypt (encipher) and decrypt (decipher) information. SOURCE: FIPS 197

Slide 59

Slide 59 text

(CC BY 3.0) http://www.moserware.com/2009/09/stick-figure-guide-to-advanced.html

Slide 60

Slide 60 text

Initialization Vector (IV) A vector used in defining the starting point of an encryption process within a cryptographic algorithm. SOURCE: FIPS 140-2

Slide 61

Slide 61 text

OpenSSL Command Line $ echo -n "Message" | openssl enc - aes256 -K 0CD1D07EB67E19EF56EA0F3A9A8F8A7C957A2C B208327E0E536608FF83256C96 -iv 6C4C31BDAB7BAFD35B23691EC521E28D | xxd -p 23e5ebe72d99cf302c99183c05cf050a

Slide 62

Slide 62 text

QUnit.test( 'AES-CBC', function ( assert ) { var testVector = { plaintext: 'Message', iv: '6C4C31BDAB7BAFD35B23691EC521E28D', key: '0CD1D07EB67E19EF56EA0F3A9A8F8A7C957A2CB208327E0E536608FF83256C96', ciphertext: '23e5ebe72d99cf302c99183c05cf050a' }; var encoder = new TextEncoder(); var decoder = new TextDecoder(); var buf = encoder.encode( testVector.plaintext ); var keyBuf = $.Uint8Util.fromHexString( testVector.key ); var ivBuf = $.Uint8Util.fromHexString( testVector.iv ); var aesCbc = { name: 'AES-CBC', iv: ivBuf }; // import key, encrypt, decrypt and compare });

Slide 63

Slide 63 text

assert.promise( crypto.subtle.importKey( 'raw', keyBuf, { name: 'AES-CBC' }, true, ['encrypt', 'decrypt'] ) .then( function ( encryptionKey ) { }));

Slide 64

Slide 64 text

assert.promise( crypto.subtle.importKey( 'raw', keyBuf, { name: 'AES-CBC' }, true, ['encrypt', 'decrypt'] ) .then( function ( encryptionKey ) { return crypto.subtle.encrypt( aesCbc, encryptionKey, buf ) .then( function ( encryptResult ) { var encryptBuf = new Uint8Array( encryptResult ); var ciphertext = $.Uint8Util.toHexString( encryptBuf ); assert.equal( ciphertext, testVector.ciphertext ); }); }));

Slide 65

Slide 65 text

assert.promise( crypto.subtle.importKey( 'raw', keyBuf, { name: 'AES-CBC' }, true, ['encrypt', 'decrypt'] ) .then( function ( encryptionKey ) { return crypto.subtle.encrypt( aesCbc, encryptionKey, buf ) .then( function ( encryptResult ) { var encryptBuf = new Uint8Array( encryptResult ); var ciphertext = $.Uint8Util.toHexString( encryptBuf ); assert.equal( ciphertext, testVector.ciphertext ); return crypto.subtle.decrypt( aesCbc, encryptionKey, encryptBuf ) .then( function ( decryptResult ) { var plaintext = decoder.decode( new Uint8Array( decryptResult ) ); assert.equal( plaintext, testVector.plaintext ); }); }); }));

Slide 66

Slide 66 text

redux chained vs. nested promises

Slide 67

Slide 67 text

function importKey () { return crypto.subtle.importKey( 'raw', keyBuf, { name: 'AES-CBC' }, true, ['encrypt', 'decrypt'] ) } function encrypt ( importedKey ) { encryptionKey = importedKey; return crypto.subtle.encrypt( aesCbc, encryptionKey, buf ); } function decrypt ( encryptResult ) { var encryptBuf = new Uint8Array( encryptResult ); var ciphertext = $.Uint8Util.toHexString( encryptBuf ); assert.equal( ciphertext, testVector.ciphertext ); return crypto.subtle.decrypt( aesCbc, encryptionKey, encryptBuf ); }

Slide 68

Slide 68 text

function compare ( decryptResult ) { var plaintext = decoder.decode( new Uint8Array( decryptResult ) ); assert.equal( plaintext, testVector.plaintext ); } assert.promise( importKey() .then( encrypt ) .then( decrypt ) .then( compare ); );

Slide 69

Slide 69 text

No content

Slide 70

Slide 70 text

Password-Based Key Derivation Functions (PBKDF) ● The randomness of cryptographic keys is essential for the security of cryptographic applications. SOURCE: SP 800-132

Slide 71

Slide 71 text

Password-Based Key Derivation Functions (PBKDF) ● The randomness of cryptographic keys is essential for the security of cryptographic applications. ● Most user-chosen passwords have low entropy and weak randomness properties. ○ shall not be used directly as cryptographic keys SOURCE: SP 800-132

Slide 72

Slide 72 text

Password-Based Key Derivation Functions (PBKDF) ● The randomness of cryptographic keys is essential for the security of cryptographic applications. ● Most user-chosen passwords have low entropy and weak randomness properties. ○ shall not be used directly as cryptographic keys ● KDFs are deterministic algorithms that are used to derive cryptographic keying material from a secret value, such as a password. SOURCE: SP 800-132

Slide 73

Slide 73 text

Salt A non-secret value that is used in a cryptographic process, usually to ensure that the results of computations for one instance cannot be reused by an Attacker. SOURCE: SP 800-63; CNSSI-4009

Slide 74

Slide 74 text

PBKDF Specification Input: P Password S Salt C Iteration count kLen Length of MK in bits; at most (232-1) x hLen Parameter: PRF HMAC with an approved hash function hlen Digest size of the hash function Output: mk Master key http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf

Slide 75

Slide 75 text

QUnit.test( 'PBKDF2', function ( assert ) { var testVector = { password : 'password', salt: 'cf7488cd1e48e84990f51b3f121e161318ba2098aa6c993ded1012c955d5a3e8', iterations: 100, key: 'c12b2e03a08f3f0d23f3c4429c248c275a728814053a093835e803bc8e695b4e' }; var alg = { name: 'PBKDF2', hash: 'SHA-1', salt: $.Uint8Util.fromHexString( testVector.salt ), iterations: testVector.iterations }; // import key, derive bits and compare });

Slide 76

Slide 76 text

var passwordBuf = decoder.decode( testVector.password ); assert.promise( crypto.subtle.importKey('raw', passwordBuf, 'PBKDF2', false, ['deriveKey']) .then(function ( keyResult ) { }));

Slide 77

Slide 77 text

var passwordBuf = decoder.decode( testVector.password ); assert.promise( crypto.subtle.importKey('raw', passwordBuf, 'PBKDF2', false, ['deriveKey']) .then(function ( keyResult ) { return crypto.subtle.deriveBits( alg, keyResult, 256 ) .then(function ( deriveResult ) { var deriveBuf = new Uint8Array( deriveResult ); var key = $.Uint8Util.toHexString( deriveBuf ); assert.equal( key, testVector.key ); }); }));

Slide 78

Slide 78 text

No content

Slide 79

Slide 79 text

Data Flow and Storage (expected) ● Salt = initial random ● IV = initial random ● Ciphertext = AES( todos, Key, IV )

Slide 80

Slide 80 text

Data Flow and Storage (actual) ● PBKDF2 only implemented in Firefox 33 ● Substitute HMAC to generate 256 bit key ○ (do not try this at home)

Slide 81

Slide 81 text

Set and Confirm Password On first use, password must be established.

Slide 82

Slide 82 text

Password Entry Field

secure todos

Slide 83

Slide 83 text

Render Password Entry Field render: function () { var todos, placeholder; if (this.todos) { this.$password.addClass('hidden'); // todos list rendering... } else { if (!cryptoStorage.initialized) { placeholder = (this.$password.data('confirm') ? 'Confirm Password' : 'Set Password'); this.$password.attr('placeholder', placeholder); } this.$password.removeClass('hidden').focus(); } }

Slide 84

Slide 84 text

Enter and Validate Password On subsequent uses, password must be entered to unlock todos. An invalid password will shake the password input field and outline in red.

Slide 85

Slide 85 text

CSS3 Shake Animation #todo-password.invalid { margin-left: 50px; padding: 3px 3px 3px 7px; border: 3px solid; width: 493px; border-radius: 6px; border-color: red; outline-color: red; animation: shake .5s linear; } @keyframes shake { 8%, 41% { transform: translateX(-10px); } 25%, 58% { transform: translateX(10px); } 75% { transform: translateX(-5px); } 92% { transform: translateX(5px); } 0%, 100% { transform: translateX(0); } }

Slide 86

Slide 86 text

Demo

Slide 87

Slide 87 text

validatePassword: function (password, confirmPassword) { var that = this; if (confirmPassword && confirmPassword != password) { return new Promise(function (resolve, reject) { reject(new Error('passwords do not match')); }); } return cryptoStorage.authenticate(password).then(function () { return util.store(); }).then(function (result) { that.todos = result; }) }

Slide 88

Slide 88 text

Convert store to return a Promise store: function (data) { if (data) { return cryptoStorage.setItem(data); } else { return cryptoStorage.getItem(); } }

Slide 89

Slide 89 text

Data Flow and Storage (API)

Slide 90

Slide 90 text

Random IV and Salt if ( !this.initialized ) { this.salt = new Uint8Array( 32 ); $.WebCryptoAPI.getRandomValues( this.salt ); this.hexSalt = $.Uint8Util.toHexString( this.salt ); this.iv = new Uint8Array( 16 ); $.WebCryptoAPI.getRandomValues( this.iv ); this.hexIV = $.Uint8Util.toHexString( this.iv ); this.initialized = true; }

Slide 91

Slide 91 text

return $.WebCryptoAPI.subtle.importKey('raw', this.salt, hmacSha256, true, ['sign', 'verify']) .then(function (keyResult) { }); Generate Key from Password

Slide 92

Slide 92 text

return $.WebCryptoAPI.subtle.importKey('raw', this.salt, hmacSha256, true, ['sign', 'verify']) .then(function (keyResult) { return $.WebCryptoAPI.subtle.sign(hmacSha256, keyResult, buf) .then(function (signResult) { }); }); Generate Key from Password

Slide 93

Slide 93 text

return $.WebCryptoAPI.subtle.importKey('raw', this.salt, hmacSha256, true, ['sign', 'verify']) .then(function (keyResult) { return $.WebCryptoAPI.subtle.sign(hmacSha256, keyResult, buf) .then(function (signResult) { var keyBuf = new Uint8Array(signResult); // importKey for later AES encryption return $.WebCryptoAPI.subtle.importKey('raw', keyBuf, {name: 'AES-CBC'}, true, ['encrypt', 'decrypt']) .then(function (result) { }); }); }); Generate Key from Password

Slide 94

Slide 94 text

return $.WebCryptoAPI.subtle.importKey('raw', this.salt, hmacSha256, true, ['sign', 'verify']) .then(function (keyResult) { return $.WebCryptoAPI.subtle.sign(hmacSha256, keyResult, buf) .then(function (signResult) { var keyBuf = new Uint8Array(signResult); // importKey for later AES encryption return $.WebCryptoAPI.subtle.importKey('raw', keyBuf, {name: 'AES-CBC'}, true, ['encrypt', 'decrypt']) .then(function (result) { that.encryptionKey = result; if (!that.hasTodos) { return that.setItem([]); } }); }); }); Generate Key from Password

Slide 95

Slide 95 text

Encrypt and Store var encoder = new TextEncoder(); var todosBuf = encoder.encode(JSON.stringify(value)); var aesCbc = {name: 'AES-CBC', iv: this.iv }; var data = { salt: this.hexSalt, iv: this.hexIV, ciphertext: null }; return $.WebCryptoAPI.subtle.encrypt(aesCbc, this.encryptionKey, todosBuf) .then(function (result) { data.ciphertext = $.Uint8Util.toHexString(new Uint8Array(result)); localStorage.setItem(NAMESPACE, JSON.stringify(data)); });

Slide 96

Slide 96 text

Decrypt var todosBuf = $.Uint8Util.fromHexString(data.ciphertext); var aesCbc = {name: 'AES-CBC', iv: this.iv }; $.WebCryptoAPI.subtle.decrypt(aesCbc, this.encryptionKey, todosBuf) .then(function (result) { var decoder = new TextDecoder(); var plaintext = decoder.decode(new Uint8Array(result)); try { data.todos = JSON.parse(plaintext); resolve(data.todos); } catch (err) { reject(err); } }, function (err) { reject(err); });

Slide 97

Slide 97 text

Encrypted in localStorage sqlite> select * from ItemTable; todos-jquery-webcryptoapi|{"salt":" 455ad2b6be02de86226c8c10fe32ebfc439b197f6b0a7918 94dab6f6920e22ff","iv":" 29b0b0092148e5fa849931c821627ea7","ciphertext":" b1770f7729edde3736eb4c26df6f4a56a236e01c525e157c f24ce76b35f8c622845a97f561c2c13942677db765e0638e f2ed90f191d5d57dcfc22fc7cd4c712716fc0e6e8748fb95 0430cb11a7e5c66ca4c55df4d88551d5b88666cd7fa4330c 85f20e88e30da752adf24ad71913bfb9"}

Slide 98

Slide 98 text

No content

Slide 99

Slide 99 text

Questions? (and hopefully answers)