# crypto https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID https://w3c.github.io/webcrypto/ // crypto.getRandomValues , // crypto.randomUUID , // crypto.subtle.encrypt , crypto.subtle.decrypt , // crypto.subtle.digest (hash), // crypto.subtle.sign , crypto.subtle.verify , // crypto.subtle.generateKey (symmetric or pair), // crypto.subtle.exportKey , crypto.subtle.importKey , // crypto.subtle.wrapKey , crypto.subtle.unwrapKey , // crypto.subtle.deriveKey , crypto.subtle.deriveBits https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/decrypt https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/sign https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/verify https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveBits https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/wrapKey https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/unwrapKey https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey https://developer.mozilla.org/en-US/docs/Web/API/CryptoKeyPair https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises JWT & JWK - JSON Web Token & JSON Web Key https://w3c.github.io/webcrypto/#iana-section-jws-jwa https://w3c.github.io/webcrypto/#jwk-mapping ## sign & verify - https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/sign - https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/verify ``` const encoded = new TextEncoder().encode( "hello world" ); const keyPair = await window.crypto.subtle.generateKey( { name: "ECDSA", namedCurve: "P-384" }, true, [ "sign", "verify" ], ); const signature = await window.crypto.subtle.sign( { name: "ECDSA", hash: { name: "SHA-384" } }, keyPair.privateKey, encoded, ); const valid = await window.crypto.subtle.verify( { name: "ECDSA", hash: { name: "SHA-384" } }, keyPair.publicKey, signature, encoded, ); console.log( valid ); const raw = await crypto.subtle.exportKey( "raw", keyPair.publicKey ); const pk2 = await crypto.subtle.importKey( "raw", // vs "spki" raw, { name: "ECDSA", namedCurve: "P-384" }, false, [ "verify" ] ); const v2 = await crypto.subtle.verify( { name: "ECDSA", hash: { name: "SHA-384" } }, pk2, signature, encoded, ); console.log( v2 ); const spki = await crypto.subtle.exportKey( "spki", keyPair.publicKey ); const pk3 = await crypto.subtle.importKey( "spki", spki, { name: "ECDSA", namedCurve: "P-384" }, false, [ "verify" ] ); const v3 = await crypto.subtle.verify( { name: "ECDSA", hash: { name: "SHA-384" } }, pk3, signature, encoded, ); console.log( v3 ); ``` ---- https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto | sign() | encrypt() | digest() | deriveBits() | wrapKey() | verify() | decrypt() | | deriveKey() | unwrapKey() -------------------|------------|-------------|------------|----------------|--------------- RSASSA-PKCS1-v1_5 | ✓ | | | | RSA-PSS | ✓ | | | | ECDSA | ✓ | | | | HMAC | ✓ | | | | RSA-OAEP | | ✓ | | | ✓ AES-CTR | | ✓ | | | ✓ AES-CBC | | ✓ | | | ✓ AES-GCM | | ✓ | | | ✓ SHA-1 | | | ✓ | | SHA-256 | | | ✓ | | SHA-384 | | | ✓ | | SHA-512 | | | ✓ | | ECDH | | | | ✓ | HKDF | | | | ✓ | PBKDF2 | | | | ✓ | AES-KW | | | | | ✓ binary: array_buffer/typed_array/data_view generateKey(algorithm, extractable, keyUsages) - alorithm follows below - extractable is boolean, `exportKey()` or `wrapKey()` - [ "encrypt","decrypt", "sign","verify", "deriveKey","deriveBits", "wrapKey","unwrapKey" ] algorithm: - name: "RSASSA-PKCS1-v1_5", "RSA-PSS", "RSA-OAEP" - { name, modulusLength: number, publicExponent: Uint8Array, hash: string } - modulusLength should be > 2048, or > 4096 - publicExponent should be 65537, [ 0x01,0x00,0x01 ] - hash is one of [ "SHA-256", "SHA-384", "SHA-512" ] - https://developer.mozilla.org/en-US/docs/Web/API/RsaHashedKeyGenParams - https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyGenParams - name: "ECDSA", "ECDH" - { name, namedCurve: string } - namedCurve is one of [ "P-256", "P-384", "P-512" ] - https://www.nist.gov/ - https://developer.mozilla.org/en-US/docs/Web/API/EcKeyGenParams - https://w3c.github.io/webcrypto/#dfn-EcKeyGenParams - name: "HMAC" - { name, hash: string, ?length: number } - hash is one of [ "SHA-1", "SHA-256", "SHA-384", "SHA-512" ] - length is optional & should remain default - https://developer.mozilla.org/en-US/docs/Web/API/HmacKeyGenParams - https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams - name: "AES-CTR", "AES-CBC", "AES-GCM", "AES-KW" - { name, length: number } - length is one of [ 128, 192, 256 ] - https://developer.mozilla.org/en-US/docs/Web/API/AesKeyGenParams - https://w3c.github.io/webcrypto/#dfn-AesKeyGenParams encrypt(algorithm, key, data) decrypt(algorithm, key, data) - RsaOaep - { name: "RSA-OAEP", ?label: binary } - https://w3c.github.io/webcrypto/#dfn-RsaOaepParams - AesCtr - { name: "AES-CTR", count: binary, length: number } - count is 16 bytes (AES block size) - count is [ nonce, counter ] - length is of counter - length can be 64 b/c count is 16 bytes - https://w3c.github.io/webcrypto/#dfn-AesCtrParams - AesCbc - { name: "AES-CBC", iv: binary } - iv is 16 bytes - iv is random, public - https://w3c.github.io/webcrypto/#dfn-AesCbcParams - AesGcm - { name: "AES-GCM", iv: binary, ?additionalData: binary, ?tagLength: number } - iv should never be re-used - iv should be 96 bits (12 bytes) - iv is random, public - additionalData is optional - additionalData must have ( bitLength < 2^64-1 ) - tagLength is one of [ 32, 64, 96, 104, 112, 120, 128 ] - tagLength should be > 64 - tagLength is optional, defaults to 128 - https://w3c.github.io/webcrypto/#dfn-AesGcmParams ---- ``` var buf = new TextEncoder().encode( "hello world" ); var hash = await crypto.subtle.digest( "SHA-256", buf ); console.log( new Uint8Array( hash ) ); ``` ``` var _create = navigator.credentials.create; navigator.credentials.create = async function() { console.log( "create call", this, arguments ); try { window._create_args = [ ...arguments ]; var val = await _create.apply( this, arguments ); window._create_returned = val; console.log( "create returned", val ); return val; } catch( e ) { console.log( "create error", e ); throw e; } }; var _get = navigator.credentials.get; navigator.credentials.get = async function() { console.log( "get", this, arguments ); try { window._get_args = [ ...arguments ]; var val = await _get.apply( this, arguments ); window._get_returned = val; console.log( "get returned", val ); return val; } catch( e ) { console.log( "get error", e ); throw e; } }; ``` ``` var summary = { _create_args, _create_returned, _get_args, _get_returned, }; var publicKey = summary._create_returned.response.getPublicKey(); var signature = summary._get_returned.response.signature ; var clientDataJSON = summary._get_returned.response.clientDataJSON ; var authenticatorData = summary._get_returned.response.authenticatorData ; // https://www.w3.org/TR/webauthn-2/#sctn-op-get-assertion // (picture) authData ++ clientDataHash var clientDataHash = await crypto.subtle.digest( "SHA-256", clientDataJSON ); // var payload = new Uint8Array( [ authenticatorData, clientDataHash ] ); var payload = await new Blob( [ authenticatorData, clientDataHash ] ).arrayBuffer(); var cryptoKey = await crypto.subtle.importKey( "spki", // SubjectPublicKeyInfo publicKey, { name: "ECDSA", namedCurve: "P-256" }, false, [ "verify" ] ); var valid = await crypto.subtle.verify( { name: "ECDSA", hash: { name: "SHA-256" } }, cryptoKey, signature, payload, ); console.log( { signature, clientDataHash, payload, cryptoKey, publicKey, } ); console.log( "valid", valid ); ``` ## ASN.1 notes http://asn1js.org/ https://lapo.it/asn1js/ https://github.com/lapo-luchini/asn1js XXX https://unpkg.com/@lapo/asn1js@1.2.4/asn1.js https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/ ... ended up being `raw`-vs-`spki` param to `crypto.subtle.importKey()` rfc5280 - X.509 https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.7 https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.2 signatureAlgorithm ``` AlgorithmIdentifier ::= SEQUENCE { algorithm OBJECT IDENTIFIER, parameters ANY DEFINED BY algorithm OPTIONAL } ``` rfc8812 https://www.iana.org/assignments/cose/cose.xhtml#algorithms COSE `ES256 -7 ECDSA w/ SHA-256` rfc9053 ## misc https://jwt.io/ tab dump ---- https://dirtand.rocks/webauthn/index2.html https://webauthn.me/ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer https://developer.mozilla.org/en-US/docs/Web/API/Blob https://developer.mozilla.org/en-US/docs/Web/API/Blob/arrayBuffer https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/create#web_authentication_api https://developer.mozilla.org/en-US/docs/Web/API/AuthenticatorAttestationResponse https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/get#web_authentication_api https://developer.mozilla.org/en-US/docs/Web/API/AuthenticatorAssertionResponse https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential/response https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey https://developer.mozilla.org/en-US/docs/Web/API/EcKeyImportParams https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/verify https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey#subjectpublickeyinfo_import https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/exportKey https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.2 https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.7 https://www.w3.org/TR/webauthn-2/#clientdatajson-serialization https://www.w3.org/TR/webauthn-2/#collectedclientdata-hash-of-the-serialized-client-data https://www.w3.org/TR/webauthn-2/#collectedclientdata-json-compatible-serialization-of-client-data https://www.w3.org/TR/webauthn-2/#dictdef-collectedclientdata https://www.w3.org/TR/webauthn-2/#sctn-attested-credential-data https://www.w3.org/TR/webauthn-2/#sctn-authenticator-data https://www.w3.org/TR/webauthn-2/#sctn-getAssertion https://www.w3.org/TR/webauthn-2/#sctn-op-get-assertion https://www.w3.org/TR/webauthn-2/#sctn-public-key-easy ----