# Web5 JS Key Management ![](https://hackmd.io/_uploads/HytZm5Nv2.png) :::info :information_source: **Info** All of the following are written with the _**SDK developer experience**_ in mind becase it isn't intended nor expected for an app developer who is building DWAs on the Web5 platform abstraction to be directly interacting with `KeyManager` or `KeyManagementSystem` implementations directly. ::: ## Use Case DevEx (Single KMS) :::info :notebook: **Note** --- Describes the most simplistic case when there is a single KMS. As a result, the `kms` property can be omitted in method options because `KeyManager` will automatically use the only KMS that is registered. ::: ### `secp256k1` #### Create a key pair Creates an `secp256k1` key pair using the. The spec `secp256k1` is an alias for ECDSA using the secp256k1 curve and SHA-256. ```typescript const keyPair = await agent.keyManager.createKey({ spec: 'secp256k1', usages : ['sign', 'verify'] }); /* // Detail of the key pair that this operation creates: { "privateKey": { "id": "559f3ee2-4f0a-4028-80b5-bea0b6e7e4af", "algorithm": { "name": "ECDSA", "namedCurve": "K-256" }, "spec": "ECDSA_K-256", "state": "Enabled", "type": "private", "usages": [ "sign" ] }, "publicKey": { "id": "559f3ee2-4f0a-4028-80b5-bea0b6e7e4af", "algorithm": { "name": "ECDSA", "namedCurve": "K-256" }, "material": ArrayBuffer(33), "spec": "ECDSA_K-256", "state": "Enabled", "type": "public", "usages": [ "verify" ] } } */ ``` #### Sign Data Data can be signed by referencing a key by `id` or `alias` property, or by passing in the CryptoKey object directly. The latter mimics the interface for the W3C WebCrypto API. ```typescript // Define and encode the message to be signed. const message = `Are You There Bob? It's Me, Alice.`; const encodedMessage = new TextEncoder().encode(message); ``` By passing an alias that is a `kid` from a DID document: ```typescript const signature = await agent.keyManager.sign({ keyRef: 'did:ion:EiClkZMDxPKqC9c-umQfTkR8vvZ9JPhl_xLDI9Nfk38w5w#authz', data: encodedMessage, signerOptions: { hash: 'SHA-256' } }) ``` --OR-- Using a CryptoKey instance: ```typescript // Signing operation const signature = await agent.keyManager.verify({ key: keyPair.publicKey, data: encodedMessage, signerOptions: { hash: 'SHA-256' } }); ``` #### Verify Signed Data By passing an alias that is a `kid` from a DID document: ```typescript const signature = await agent.keyManager.sign({ keyRef: 'did:ion:EiClkZMDxPKqC9c-umQfTkR8vvZ9JPhl_xLDI9Nfk38w5w#authz', signature: signature, data: encodedMessage, signerOptions: { hash: 'SHA-256' } }) ``` --OR-- Using a CryptoKey instance: ```typescript // Signing operation const signature = await agent.keyManager.sign({ key: keyPair.privateKey, signature: signature, data: encodedMessage, verifierOptions: { hash: 'SHA-256' } }); ``` #### Derive a Symmetric Key to Encrypt Messages In this example Alice and Bob each generate an ECDH key pair, then exchange public keys. They then use deriveKey() to derive a shared AES key, that they could use to encrypt messages. A more likely scenario in the context of using DIDs is that the `secp256k1` public keys of both Alice and Bob would already be published in their DID documents. Each party would obtain the public key of the other after resolving their DID document. ```typescript const alicesKeyPair = await agent.keyManager.createKey({ spec : 'ECDH_K-256', usages : ['deriveKey'] }); const bobsKeyPair = await agent.keyManager.createKey({ spec : 'ECDH_K-256', usages : ['deriveKey'] }) return window.crypto.subtle.deriveKey( { name: "ECDH", public: publicKey, }, privateKey, { name: "AES-GCM", length: 256, }, false, ["encrypt", "decrypt"] ); ``` ## `KeyManager` DevEx ### Default Algorithms | Spec Name | Crypto Primitive | Algorithm Description | Aliases | | --- | --- | --- | --- | | `AES-GCM_256` | AES | AES GCM using 256-bit key | `A256GCM` | | `ECDSA_K-256` | ECC | ECDSA using secp256k1 curve and SHA-256 | `ES256K`, `secp256k1` | | `EdDSA_Ed25519` | ECC | EdDSA using Ed25519 curve | `Ed25519` | | `HMAC_SHA256` | HMAC | HMAC with a SHA-256 digest | `HS256` | **Typical Usage** ![](https://hackmd.io/_uploads/HJz0SPVvn.png) ## Open Questions --- ### Should the `KeyManager` and `KeyManagementSystem` interfaces be modeled as a request/response API? In other words, rather than ```typescript async createKey(options: KeyManagerCreateOptions): Promise<ManagedKey | ManagedKeyPair> ``` ```typescript async createKey(request: KeyManagerCreateRequest): Promise<ManagedKey | ManagedKeyPair> ``` AWS API ```javascript var params = { KeyId: "1234abcd-12ab-34cd-56ef-1234567890ab"// An identifier for the KMS key. You can use the key ID, key ARN, alias name, alias ARN of the KMS key. }; kms.describeKey(params, function(err, data) { if (err) console.log(err, err.stack); // an error occurred else console.log(data); // successful response /* data = { KeyMetadata: { AWSAccountId: "111122223333", Arn: "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", CreationDate: <Date Representation>, CustomerMasterKeySpec: "RSA_2048", Description: "", Enabled: false, KeyId: "1234abcd-12ab-34cd-56ef-1234567890ab", KeyManager: "CUSTOMER", KeySpec: "RSA_2048", KeyState: "Disabled", KeyUsage: "SIGN_VERIFY", MultiRegion: false, Origin: "AWS_KMS", SigningAlgorithms: [ "RSASSA_PKCS1_V1_5_SHA_256", "RSASSA_PKCS1_V1_5_SHA_384", "RSASSA_PKCS1_V1_5_SHA_512", "RSASSA_PSS_SHA_256", "RSASSA_PSS_SHA_384", "RSASSA_PSS_SHA_512" ] } } */ }); ``` GCP API ```javascript const {KeyManagementServiceClient} = require('@google-cloud/kms').v1; // Instantiates a client const kmsClient = new KeyManagementServiceClient(); // Construct request const request = { name, }; // Run request const response = await kmsClient.getCryptoKey(request); console.log(response); ``` # Convo # Web Cryptography API Examples ## RSASSA-PKCS1-v1_5 #### RSASSA-PKCS1-v1_5 - generateKey ```javascript window.crypto.subtle.generateKey( { name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, //can be 1024, 2048, or 4096 publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" }, false, //whether the key is extractable (i.e. can be used in exportKey) ["sign", "verify"] //can be any combination of "sign" and "verify" ) .then(function(key){ //returns a keypair object console.log(key); console.log(key.publicKey); console.log(key.privateKey); }) .catch(function(err){ console.error(err); }); ``` #### RSASSA-PKCS1-v1_5 - importKey ```javascript window.crypto.subtle.importKey( "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only) { //this is an example jwk key, other key types are Uint8Array objects kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RS256", ext: true, }, { //these are the algorithm options name: "RSASSA-PKCS1-v1_5", hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" }, false, //whether the key is extractable (i.e. can be used in exportKey) ["verify"] //"verify" for public key import, "sign" for private key imports ) .then(function(publicKey){ //returns a publicKey (or privateKey if you are importing a private key) console.log(publicKey); }) .catch(function(err){ console.error(err); }); ``` #### RSASSA-PKCS1-v1_5 - exportKey ```javascript window.crypto.subtle.exportKey( "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only) publicKey //can be a publicKey or privateKey, as long as extractable was true ) .then(function(keydata){ //returns the exported key data console.log(keydata); }) .catch(function(err){ console.error(err); }); ``` #### RSASSA-PKCS1-v1_5 - sign ```javascript window.crypto.subtle.sign( { name: "RSASSA-PKCS1-v1_5", }, privateKey, //from generateKey or importKey above data //ArrayBuffer of data you want to sign ) .then(function(signature){ //returns an ArrayBuffer containing the signature console.log(new Uint8Array(signature)); }) .catch(function(err){ console.error(err); }); ``` #### RSASSA-PKCS1-v1_5 - verify ```javascript window.crypto.subtle.verify( { name: "RSASSA-PKCS1-v1_5", }, publicKey, //from generateKey or importKey above signature, //ArrayBuffer of the signature data //ArrayBuffer of the data ) .then(function(isvalid){ //returns a boolean on whether the signature is true or not console.log(isvalid); }) .catch(function(err){ console.error(err); }); ``` ## RSA-PSS #### RSA-PSS - generateKey ```javascript window.crypto.subtle.generateKey( { name: "RSA-PSS", modulusLength: 2048, //can be 1024, 2048, or 4096 publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" }, false, //whether the key is extractable (i.e. can be used in exportKey) ["sign", "verify"] //can be any combination of "sign" and "verify" ) .then(function(key){ //returns a keypair object console.log(key); console.log(key.publicKey); console.log(key.privateKey); }) .catch(function(err){ console.error(err); }); ``` #### RSA-PSS - importKey ```javascript window.crypto.subtle.importKey( "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only) { //this is an example jwk key, other key types are Uint8Array objects kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "PS256", ext: true, }, { //these are the algorithm options name: "RSA-PSS", hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" }, false, //whether the key is extractable (i.e. can be used in exportKey) ["verify"] //"verify" for public key import, "sign" for private key imports ) .then(function(publicKey){ //returns a publicKey (or privateKey if you are importing a private key) console.log(publicKey); }) .catch(function(err){ console.error(err); }); ``` #### RSA-PSS - exportKey ```javascript window.crypto.subtle.exportKey( "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only) publicKey //can be a publicKey or privateKey, as long as extractable was true ) .then(function(keydata){ //returns the exported key data console.log(keydata); }) .catch(function(err){ console.error(err); }); ``` #### RSA-PSS - sign ```javascript window.crypto.subtle.sign( { name: "RSA-PSS", saltLength: 128, //the length of the salt }, privateKey, //from generateKey or importKey above data //ArrayBuffer of data you want to sign ) .then(function(signature){ //returns an ArrayBuffer containing the signature console.log(new Uint8Array(signature)); }) .catch(function(err){ console.error(err); }); ``` #### RSA-PSS - verify ```javascript window.crypto.subtle.verify( { name: "RSA-PSS", saltLength: 128, //the length of the salt }, publicKey, //from generateKey or importKey above signature, //ArrayBuffer of the signature data //ArrayBuffer of the data ) .then(function(isvalid){ //returns a boolean on whether the signature is true or not console.log(isvalid); }) .catch(function(err){ console.error(err); }); ``` ## RSA-OAEP #### RSA-OAEP - generateKey ```javascript window.crypto.subtle.generateKey( { name: "RSA-OAEP", modulusLength: 2048, //can be 1024, 2048, or 4096 publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //must be ["encrypt", "decrypt"] or ["wrapKey", "unwrapKey"] ) .then(function(key){ //returns a keypair object console.log(key); console.log(key.publicKey); console.log(key.privateKey); }) .catch(function(err){ console.error(err); }); ``` #### RSA-OAEP - importKey ```javascript window.crypto.subtle.importKey( "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only) { //this is an example jwk key, other key types are Uint8Array objects kty: "RSA", e: "AQAB", n: "vGO3eU16ag9zRkJ4AK8ZUZrjbtp5xWK0LyFMNT8933evJoHeczexMUzSiXaLrEFSyQZortk81zJH3y41MBO_UFDO_X0crAquNrkjZDrf9Scc5-MdxlWU2Jl7Gc4Z18AC9aNibWVmXhgvHYkEoFdLCFG-2Sq-qIyW4KFkjan05IE", alg: "RSA-OAEP-256", ext: true, }, { //these are the algorithm options name: "RSA-OAEP", hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt"] //"encrypt" or "wrapKey" for public key import or //"decrypt" or "unwrapKey" for private key imports ) .then(function(publicKey){ //returns a publicKey (or privateKey if you are importing a private key) console.log(publicKey); }) .catch(function(err){ console.error(err); }); ``` #### RSA-OAEP - exportKey ```javascript window.crypto.subtle.exportKey( "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only) publicKey //can be a publicKey or privateKey, as long as extractable was true ) .then(function(keydata){ //returns the exported key data console.log(keydata); }) .catch(function(err){ console.error(err); }); ``` #### RSA-OAEP - encrypt ```javascript window.crypto.subtle.encrypt( { name: "RSA-OAEP", //label: Uint8Array([...]) //optional }, publicKey, //from generateKey or importKey above data //ArrayBuffer of data you want to encrypt ) .then(function(encrypted){ //returns an ArrayBuffer containing the encrypted data console.log(new Uint8Array(encrypted)); }) .catch(function(err){ console.error(err); }); ``` #### RSA-OAEP - decrypt ```javascript window.crypto.subtle.decrypt( { name: "RSA-OAEP", //label: Uint8Array([...]) //optional }, privateKey, //from generateKey or importKey above data //ArrayBuffer of the data ) .then(function(decrypted){ //returns an ArrayBuffer containing the decrypted data console.log(new Uint8Array(decrypted)); }) .catch(function(err){ console.error(err); }); ``` #### RSA-OAEP - wrapKey ```javascript window.crypto.subtle.wrapKey( "raw", //the export format, must be "raw" (only available sometimes) key, //the key you want to wrap, must be able to fit in RSA-OAEP padding publicKey, //the public key with "wrapKey" usage flag { //these are the wrapping key's algorithm options name: "RSA-OAEP", hash: {name: "SHA-256"}, } ) .then(function(wrapped){ //returns an ArrayBuffer containing the encrypted data console.log(new Uint8Array(wrapped)); }) .catch(function(err){ console.error(err); }); ``` #### RSA-OAEP - unwrapKey ```javascript window.crypto.subtle.unwrapKey( "raw", //the import format, must be "raw" (only available sometimes) wrapped, //the key you want to unwrap privateKey, //the private key with "unwrapKey" usage flag { //these are the wrapping key's algorithm options name: "RSA-OAEP", modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: {name: "SHA-256"}, }, { //this what you want the wrapped key to become (same as when wrapping) name: "AES-GCM", length: 256 }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //the usages you want the unwrapped key to have ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` ## ECDSA #### ECDSA - generateKey ```javascript window.crypto.subtle.generateKey( { name: "ECDSA", namedCurve: "P-256", //can be "P-256", "P-384", or "P-521" }, false, //whether the key is extractable (i.e. can be used in exportKey) ["sign", "verify"] //can be any combination of "sign" and "verify" ) .then(function(key){ //returns a keypair object console.log(key); console.log(key.publicKey); console.log(key.privateKey); }) .catch(function(err){ console.error(err); }); ``` #### ECDSA - importKey ```javascript window.crypto.subtle.importKey( "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only) { //this is an example jwk key, other key types are Uint8Array objects kty: "EC", crv: "P-256", x: "zCQ5BPHPCLZYgdpo1n-x_90P2Ij52d53YVwTh3ZdiMo", y: "pDfQTUx0-OiZc5ZuKMcA7v2Q7ZPKsQwzB58bft0JTko", ext: true, }, { //these are the algorithm options name: "ECDSA", namedCurve: "P-256", //can be "P-256", "P-384", or "P-521" }, false, //whether the key is extractable (i.e. can be used in exportKey) ["verify"] //"verify" for public key import, "sign" for private key imports ) .then(function(publicKey){ //returns a publicKey (or privateKey if you are importing a private key) console.log(publicKey); }) .catch(function(err){ console.error(err); }); ``` #### ECDSA - exportKey ```javascript window.crypto.subtle.exportKey( "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only) publicKey //can be a publicKey or privateKey, as long as extractable was true ) .then(function(keydata){ //returns the exported key data console.log(keydata); }) .catch(function(err){ console.error(err); }); ``` #### ECDSA - sign ```javascript window.crypto.subtle.sign( { name: "ECDSA", hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" }, privateKey, //from generateKey or importKey above data //ArrayBuffer of data you want to sign ) .then(function(signature){ //returns an ArrayBuffer containing the signature console.log(new Uint8Array(signature)); }) .catch(function(err){ console.error(err); }); ``` #### ECDSA - verify ```javascript window.crypto.subtle.verify( { name: "ECDSA", hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" }, publicKey, //from generateKey or importKey above signature, //ArrayBuffer of the signature data //ArrayBuffer of the data ) .then(function(isvalid){ //returns a boolean on whether the signature is true or not console.log(isvalid); }) .catch(function(err){ console.error(err); }); ``` ## ECDH #### ECDH - generateKey ```javascript window.crypto.subtle.generateKey( { name: "ECDH", namedCurve: "P-256", //can be "P-256", "P-384", or "P-521" }, false, //whether the key is extractable (i.e. can be used in exportKey) ["deriveKey", "deriveBits"] //can be any combination of "deriveKey" and "deriveBits" ) .then(function(key){ //returns a keypair object console.log(key); console.log(key.publicKey); console.log(key.privateKey); }) .catch(function(err){ console.error(err); }); ``` #### ECDH - importKey ```javascript window.crypto.subtle.importKey( "jwk", //can be "jwk" (public or private), "raw" (public only), "spki" (public only), or "pkcs8" (private only) { //this is an example jwk key, other key types are Uint8Array objects kty: "EC", crv: "P-256", x: "kgR_PqO07L8sZOBbw6rvv7O_f7clqDeiE3WnMkb5EoI", y: "djI-XqCqSyO9GFk_QT_stROMCAROIvU8KOORBgQUemE", d: "5aPFSt0UFVXYGu-ZKyC9FQIUOAMmnjzdIwkxCMe3Iok", ext: true, }, { //these are the algorithm options name: "ECDH", namedCurve: "P-256", //can be "P-256", "P-384", or "P-521" }, false, //whether the key is extractable (i.e. can be used in exportKey) ["deriveKey", "deriveBits"] //"deriveKey" and/or "deriveBits" for private keys only (just put an empty list if importing a public key) ) .then(function(privateKey){ //returns a privateKey (or publicKey if you are importing a public key) console.log(privateKey); }) .catch(function(err){ console.error(err); }); ``` #### ECDH - exportKey ```javascript window.crypto.subtle.exportKey( "jwk", //can be "jwk" (public or private), "raw" (public only), "spki" (public only), or "pkcs8" (private only) publicKey //can be a publicKey or privateKey, as long as extractable was true ) .then(function(keydata){ //returns the exported key data console.log(keydata); }) .catch(function(err){ console.error(err); }); ``` #### ECDH - deriveKey ```javascript window.crypto.subtle.deriveKey( { name: "ECDH", namedCurve: "P-256", //can be "P-256", "P-384", or "P-521" public: publicKey, //an ECDH public key from generateKey or importKey }, privateKey, //your ECDH private key from generateKey or importKey { //the key type you want to create based on the derived bits name: "AES-CTR", //can be any AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH", or "HMAC") //the generateKey parameters for that type of algorithm length: 256, //can be 128, 192, or 256 }, false, //whether the derived key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //limited to the options in that algorithm's importKey ) .then(function(keydata){ //returns the exported key data console.log(keydata); }) .catch(function(err){ console.error(err); }); ``` #### ECDH - deriveBits ```javascript window.crypto.subtle.deriveBits( { name: "ECDH", namedCurve: "P-256", //can be "P-256", "P-384", or "P-521" public: publicKey, //an ECDH public key from generateKey or importKey }, privateKey, //your ECDH private key from generateKey or importKey 256 //the number of bits you want to derive ) .then(function(bits){ //returns the derived bits as an ArrayBuffer console.log(new Uint8Array(bits)); }) .catch(function(err){ console.error(err); }); ``` ## AES-CTR #### AES-CTR - generateKey ```javascript window.crypto.subtle.generateKey( { name: "AES-CTR", length: 256, //can be 128, 192, or 256 }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //can "encrypt", "decrypt", "wrapKey", or "unwrapKey" ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### AES-CTR - importKey ```javascript window.crypto.subtle.importKey( "jwk", //can be "jwk" or "raw" { //this is an example jwk key, "raw" would be an ArrayBuffer kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CTR", ext: true, }, { //this is the algorithm options name: "AES-CTR", }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //can "encrypt", "decrypt", "wrapKey", or "unwrapKey" ) .then(function(key){ //returns the symmetric key console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### AES-CTR - exportKey ```javascript window.crypto.subtle.exportKey( "jwk", //can be "jwk" or "raw" key //extractable must be true ) .then(function(keydata){ //returns the exported key data console.log(keydata); }) .catch(function(err){ console.error(err); }); ``` #### AES-CTR - encrypt ```javascript window.crypto.subtle.encrypt( { name: "AES-CTR", //Don't re-use counters! //Always use a new counter every time your encrypt! counter: new Uint8Array(16), length: 128, //can be 1-128 }, key, //from generateKey or importKey above data //ArrayBuffer of data you want to encrypt ) .then(function(encrypted){ //returns an ArrayBuffer containing the encrypted data console.log(new Uint8Array(encrypted)); }) .catch(function(err){ console.error(err); }); ``` #### AES-CTR - decrypt ```javascript window.crypto.subtle.decrypt( { name: "AES-CTR", counter: ArrayBuffer(16), //The same counter you used to encrypt length: 128, //The same length you used to encrypt }, key, //from generateKey or importKey above data //ArrayBuffer of the data ) .then(function(decrypted){ //returns an ArrayBuffer containing the decrypted data console.log(new Uint8Array(decrypted)); }) .catch(function(err){ console.error(err); }); ``` #### AES-CTR - wrapKey ```javascript window.crypto.subtle.wrapKey( "jwk", //can be "jwk", "raw", "spki", or "pkcs8" key, //the key you want to wrap, must be able to export to "raw" format wrappingKey, //the AES-CTR key with "wrapKey" usage flag { //these are the wrapping key's algorithm options name: "AES-CTR", //Don't re-use counters! //Always use a new counter every time your encrypt! counter: new Uint8Array(16), length: 128, //can be 1-128 } ) .then(function(wrapped){ //returns an ArrayBuffer containing the encrypted data console.log(new Uint8Array(wrapped)); }) .catch(function(err){ console.error(err); }); ``` #### AES-CTR - unwrapKey ```javascript window.crypto.subtle.unwrapKey( "jwk", //"jwk", "raw", "spki", or "pkcs8" (whatever was used in wrapping) wrapped, //the key you want to unwrap wrappingKey, //the AES-CTR key with "unwrapKey" usage flag { //these are the wrapping key's algorithm options name: "AES-CTR", //Don't re-use counters! //Always use a new counter every time your encrypt! counter: new Uint8Array(16), length: 128, //can be 1-128 }, { //this what you want the wrapped key to become (same as when wrapping) name: "AES-GCM", length: 256 }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //the usages you want the unwrapped key to have ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` ## AES-CBC #### AES-CBC - generateKey ```javascript window.crypto.subtle.generateKey( { name: "AES-CBC", length: 256, //can be 128, 192, or 256 }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //can be "encrypt", "decrypt", "wrapKey", or "unwrapKey" ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### AES-CBC - importKey ```javascript window.crypto.subtle.importKey( "jwk", //can be "jwk" or "raw" { //this is an example jwk key, "raw" would be an ArrayBuffer kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CBC", ext: true, }, { //this is the algorithm options name: "AES-CBC", }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //can be "encrypt", "decrypt", "wrapKey", or "unwrapKey" ) .then(function(key){ //returns the symmetric key console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### AES-CBC - exportKey ```javascript window.crypto.subtle.exportKey( "jwk", //can be "jwk" or "raw" key //extractable must be true ) .then(function(keydata){ //returns the exported key data console.log(keydata); }) .catch(function(err){ console.error(err); }); ``` #### AES-CBC - encrypt ```javascript window.crypto.subtle.encrypt( { name: "AES-CBC", //Don't re-use initialization vectors! //Always generate a new iv every time your encrypt! iv: window.crypto.getRandomValues(new Uint8Array(16)), }, key, //from generateKey or importKey above data //ArrayBuffer of data you want to encrypt ) .then(function(encrypted){ //returns an ArrayBuffer containing the encrypted data console.log(new Uint8Array(encrypted)); }) .catch(function(err){ console.error(err); }); ``` #### AES-CBC - decrypt ```javascript window.crypto.subtle.decrypt( { name: "AES-CBC", iv: ArrayBuffer(16), //The initialization vector you used to encrypt }, key, //from generateKey or importKey above data //ArrayBuffer of the data ) .then(function(decrypted){ //returns an ArrayBuffer containing the decrypted data console.log(new Uint8Array(decrypted)); }) .catch(function(err){ console.error(err); }); ``` #### AES-CBC - wrapKey ```javascript window.crypto.subtle.wrapKey( "jwk", //can be "jwk", "raw", "spki", or "pkcs8" key, //the key you want to wrap, must be able to export to above format wrappingKey, //the AES-CBC key with "wrapKey" usage flag { //these are the wrapping key's algorithm options name: "AES-CBC", //Don't re-use initialization vectors! //Always generate a new iv every time your encrypt! iv: window.crypto.getRandomValues(new Uint8Array(16)), } ) .then(function(wrapped){ //returns an ArrayBuffer containing the encrypted data console.log(new Uint8Array(wrapped)); }) .catch(function(err){ console.error(err); }); ``` #### AES-CBC - unwrapKey ```javascript window.crypto.subtle.unwrapKey( "jwk", //"jwk", "raw", "spki", or "pkcs8" (whatever was used in wrapping) wrapped, //the key you want to unwrap wrappingKey, //the AES-CBC key with "unwrapKey" usage flag { //these are the wrapping key's algorithm options name: "AES-CBC", iv: ArrayBuffer(16), //The initialization vector you used to encrypt }, { //this what you want the wrapped key to become (same as when wrapping) name: "AES-GCM", length: 256 }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //the usages you want the unwrapped key to have ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` ## AES-CMAC #### AES-CMAC - generateKey ```javascript window.crypto.subtle.generateKey( { name: "AES-CMAC", length: 256, //can be 128, 192, or 256 }, false, //whether the key is extractable (i.e. can be used in exportKey) ["sign", "verify"] //can be any combination of "sign" and "verify" ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### AES-CMAC - importKey ```javascript window.crypto.subtle.importKey( "jwk", //can be "jwk" or "raw" { //this is an example jwk key, "raw" would be an ArrayBuffer kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CMAC", ext: true, }, { //this is the algorithm options name: "AES-CMAC", }, false, //whether the key is extractable (i.e. can be used in exportKey) ["sign", "verify"] //can be any combination of "sign" and "verify" ) .then(function(key){ //returns the symmetric key console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### AES-CMAC - exportKey ```javascript window.crypto.subtle.exportKey( "jwk", //can be "jwk" or "raw" key //extractable must be true ) .then(function(keydata){ //returns the exported key data console.log(keydata); }) .catch(function(err){ console.error(err); }); ``` #### AES-CMAC - sign ```javascript window.crypto.subtle.sign( { name: "AES-CMAC", length: 256, //bit length of the MAC }, key, //from generateKey or importKey above data //ArrayBuffer of data you want to sign ) .then(function(signature){ //returns an ArrayBuffer containing the signature console.log(new Uint8Array(signature)); }) .catch(function(err){ console.error(err); }); ``` #### AES-CMAC - verify ```javascript window.crypto.subtle.verify( { name: "AES-CMAC", length: 256, //bit length of the MAC }, key, //from generateKey or importKey above signature, //ArrayBuffer of the signature data //ArrayBuffer of the data ) .then(function(isvalid){ //returns a boolean on whether the signature is true or not console.log(isvalid); }) .catch(function(err){ console.error(err); }); ``` ## AES-GCM #### AES-GCM - generateKey ```javascript window.crypto.subtle.generateKey( { name: "AES-GCM", length: 256, //can be 128, 192, or 256 }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //can "encrypt", "decrypt", "wrapKey", or "unwrapKey" ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### AES-GCM - importKey ```javascript window.crypto.subtle.importKey( "jwk", //can be "jwk" or "raw" { //this is an example jwk key, "raw" would be an ArrayBuffer kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256GCM", ext: true, }, { //this is the algorithm options name: "AES-GCM", }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //can "encrypt", "decrypt", "wrapKey", or "unwrapKey" ) .then(function(key){ //returns the symmetric key console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### AES-GCM - exportKey ```javascript window.crypto.subtle.exportKey( "jwk", //can be "jwk" or "raw" key //extractable must be true ) .then(function(keydata){ //returns the exported key data console.log(keydata); }) .catch(function(err){ console.error(err); }); ``` #### AES-GCM - encrypt ```javascript window.crypto.subtle.encrypt( { name: "AES-GCM", //Don't re-use initialization vectors! //Always generate a new iv every time your encrypt! //Recommended to use 12 bytes length iv: window.crypto.getRandomValues(new Uint8Array(12)), //Additional authentication data (optional) additionalData: ArrayBuffer, //Tag length (optional) tagLength: 128, //can be 32, 64, 96, 104, 112, 120 or 128 (default) }, key, //from generateKey or importKey above data //ArrayBuffer of data you want to encrypt ) .then(function(encrypted){ //returns an ArrayBuffer containing the encrypted data console.log(new Uint8Array(encrypted)); }) .catch(function(err){ console.error(err); }); ``` #### AES-GCM - decrypt ```javascript window.crypto.subtle.decrypt( { name: "AES-GCM", iv: ArrayBuffer(12), //The initialization vector you used to encrypt additionalData: ArrayBuffer, //The addtionalData you used to encrypt (if any) tagLength: 128, //The tagLength you used to encrypt (if any) }, key, //from generateKey or importKey above data //ArrayBuffer of the data ) .then(function(decrypted){ //returns an ArrayBuffer containing the decrypted data console.log(new Uint8Array(decrypted)); }) .catch(function(err){ console.error(err); }); ``` #### AES-GCM - wrapKey ```javascript window.crypto.subtle.wrapKey( "jwk", //can be "jwk", "raw", "spki", or "pkcs8" key, //the key you want to wrap, must be able to export to above format wrappingKey, //the AES-GCM key with "wrapKey" usage flag { //these are the wrapping key's algorithm options name: "AES-GCM", //Don't re-use initialization vectors! //Always generate a new iv every time your encrypt! //Recommended to use 12 bytes length iv: window.crypto.getRandomValues(new Uint8Array(12)), //Additional authentication data (optional) additionalData: ArrayBuffer, //Tag length (optional) tagLength: 128, //can be 32, 64, 96, 104, 112, 120 or 128 (default) } ) .then(function(wrapped){ //returns an ArrayBuffer containing the encrypted data console.log(new Uint8Array(wrapped)); }) .catch(function(err){ console.error(err); }); ``` #### AES-GCM - unwrapKey ```javascript window.crypto.subtle.unwrapKey( "jwk", //"jwk", "raw", "spki", or "pkcs8" (whatever was used in wrapping) wrapped, //the key you want to unwrap wrappingKey, //the AES-GCM key with "unwrapKey" usage flag { //these are the wrapping key's algorithm options name: "AES-GCM", iv: ArrayBuffer(12), //The initialization vector you used to encrypt additionalData: ArrayBuffer, //The addtionalData you used to encrypt (if any) tagLength: 128, //The tagLength you used to encrypt (if any) }, { //this what you want the wrapped key to become (same as when wrapping) name: "AES-CBC", length: 256 }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //the usages you want the unwrapped key to have ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` ## AES-CFB #### AES-CFB - generateKey ```javascript window.crypto.subtle.generateKey( { name: "AES-CFB-8", length: 256, //can be 128, 192, or 256 }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //can "encrypt", "decrypt", "wrapKey", or "unwrapKey" ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### AES-CFB - importKey ```javascript window.crypto.subtle.importKey( "jwk", //can be "jwk" or "raw" { //this is an example jwk key, "raw" would be an ArrayBuffer kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256CFB8", ext: true, }, { //this is the algorithm options name: "AES-CFB-8", }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //can "encrypt", "decrypt", "wrapKey", or "unwrapKey" ) .then(function(key){ //returns the symmetric key console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### AES-CFB - exportKey ```javascript window.crypto.subtle.exportKey( "jwk", //can be "jwk" or "raw" key //extractable must be true ) .then(function(keydata){ //returns the exported key data console.log(keydata); }) .catch(function(err){ console.error(err); }); ``` #### AES-CFB - encrypt ```javascript window.crypto.subtle.encrypt( { name: "AES-CFB-8", //Don't re-use initialization vectors! //Always generate a new iv every time your encrypt! iv: window.crypto.getRandomValues(new Uint8Array(16)), }, key, //from generateKey or importKey above data //ArrayBuffer of data you want to encrypt ) .then(function(encrypted){ //returns an ArrayBuffer containing the encrypted data console.log(new Uint8Array(encrypted)); }) .catch(function(err){ console.error(err); }); ``` #### AES-CFB - decrypt ```javascript window.crypto.subtle.decrypt( { name: "AES-CFB-8", iv: ArrayBuffer(16), //The initialization vector you used to encrypt }, key, //from generateKey or importKey above data //ArrayBuffer of the data ) .then(function(decrypted){ //returns an ArrayBuffer containing the decrypted data console.log(new Uint8Array(decrypted)); }) .catch(function(err){ console.error(err); }); ``` #### AES-CFB - wrapKey ```javascript window.crypto.subtle.wrapKey( "jwk", //can be "jwk", "raw", "spki", or "pkcs8" key, //the key you want to wrap, must be able to export to above format wrappingKey, //the AES-CFB key with "wrapKey" usage flag { //these are the wrapping key's algorithm options name: "AES-CFB", //Don't re-use initialization vectors! //Always generate a new iv every time your encrypt! iv: window.crypto.getRandomValues(new Uint8Array(16)), } ) .then(function(wrapped){ //returns an ArrayBuffer containing the encrypted data console.log(new Uint8Array(wrapped)); }) .catch(function(err){ console.error(err); }); ``` #### AES-CFB - unwrapKey ```javascript window.crypto.subtle.unwrapKey( "jwk", //"jwk", "raw", "spki", or "pkcs8" (whatever was used in wrapping) wrapped, //the key you want to unwrap wrappingKey, //the AES-CFB key with "unwrapKey" usage flag { //these are the wrapping key's algorithm options name: "AES-CFB", iv: ArrayBuffer(16), //The initialization vector you used to encrypt }, { //this what you want the wrapped key to become (same as when wrapping) name: "AES-GCM", length: 256 }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //the usages you want the unwrapped key to have ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` ## AES-KW #### AES-KW - generateKey ```javascript window.crypto.subtle.generateKey( { name: "AES-KW", length: 256, //can be 128, 192, or 256 }, false, //whether the key is extractable (i.e. can be used in exportKey) ["wrapKey", "unwrapKey"] //can be any combination of "wrapKey" and "unwrapKey" ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### AES-KW - importKey ```javascript window.crypto.subtle.importKey( "jwk", //can be "jwk" or "raw" { //this is an example jwk key, "raw" would be an ArrayBuffer kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "A256KW", ext: true, }, { //this is the algorithm options name: "AES-KW", }, false, //whether the key is extractable (i.e. can be used in exportKey) ["wrapKey", "unwrapKey"] //can be any combination of "wrapKey" and "unwrapKey" ) .then(function(key){ //returns the symmetric key console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### AES-KW - exportKey ```javascript window.crypto.subtle.exportKey( "jwk", //can be "jwk" or "raw" key //extractable must be true ) .then(function(keydata){ //returns the exported key data console.log(keydata); }) .catch(function(err){ console.error(err); }); ``` #### AES-KW - wrapKey ```javascript window.crypto.subtle.wrapKey( "raw", //the export format, must be "raw" (only available sometimes) key, //the key you want to wrap, must export in 8 byte increments wrappingKey, //the AES-KW key with "wrapKey" usage flag { //these are the wrapping key's algorithm options name: "AES-KW", } ) .then(function(wrapped){ //returns an ArrayBuffer containing the encrypted data console.log(new Uint8Array(wrapped)); }) .catch(function(err){ console.error(err); }); ``` #### AES-KW - unwrapKey ```javascript window.crypto.subtle.unwrapKey( "raw", //the import format, must be "raw" (only available sometimes) wrapped, //the key you want to unwrap wrappingKey, //the AES-KW key with "unwrapKey" usage flag { //these are the wrapping key's algorithm options name: "AES-KW", }, { //this what you want the wrapped key to become (same as when wrapping) name: "AES-GCM", length: 256 }, false, //whether the key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //the usages you want the unwrapped key to have ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` ## HMAC #### HMAC - generateKey ```javascript window.crypto.subtle.generateKey( { name: "HMAC", hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" //length: 256, //optional, if you want your key length to differ from the hash function's block length }, false, //whether the key is extractable (i.e. can be used in exportKey) ["sign", "verify"] //can be any combination of "sign" and "verify" ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### HMAC - importKey ```javascript window.crypto.subtle.importKey( "jwk", //can be "jwk" or "raw" { //this is an example jwk key, "raw" would be an ArrayBuffer kty: "oct", k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE", alg: "HS256", ext: true, }, { //this is the algorithm options name: "HMAC", hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" //length: 256, //optional, if you want your key length to differ from the hash function's block length }, false, //whether the key is extractable (i.e. can be used in exportKey) ["sign", "verify"] //can be any combination of "sign" and "verify" ) .then(function(key){ //returns the symmetric key console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### HMAC - exportKey ```javascript window.crypto.subtle.exportKey( "jwk", //can be "jwk" or "raw" key //extractable must be true ) .then(function(keydata){ //returns the exported key data console.log(keydata); }) .catch(function(err){ console.error(err); }); ``` #### HMAC - sign ```javascript window.crypto.subtle.sign( { name: "HMAC", }, key, //from generateKey or importKey above data //ArrayBuffer of data you want to sign ) .then(function(signature){ //returns an ArrayBuffer containing the signature console.log(new Uint8Array(signature)); }) .catch(function(err){ console.error(err); }); ``` #### HMAC - verify ```javascript window.crypto.subtle.verify( { name: "HMAC", }, key, //from generateKey or importKey above signature, //ArrayBuffer of the signature data //ArrayBuffer of the data ) .then(function(isvalid){ //returns a boolean on whether the signature is true or not console.log(isvalid); }) .catch(function(err){ console.error(err); }); ``` ## DH #### DH - generateKey ```javascript window.crypto.subtle.generateKey( { name: "DH", //NOTE: THIS IS A SMALL PRIME FOR TESTING ONLY! DO NOT USE IT FOR REAL! //See http://datatracker.ietf.org/doc/rfc3526/ for better primes prime: new Uint8Array([ 255,255,255,255,255,255,255,255,201,15,218,162,33,104,194,52,196,198,98,139, 128,220,28,209,41,2,78,8,138,103,204,116,2,11,190,166,59,19,155,34,81,74,8, 121,142,52,4,221,239,149,25,179,205,58,67,27,48,43,10,109,242,95,20,55,79,225, 53,109,109,81,194,69,228,133,181,118,98,94,126,198,244,76,66,233,166,55,237, 107,11,255,92,182,244,6,183,237,238,56,107,251,90,137,159,165,174,159,36,17, 124,75,31,230,73,40,102,81,236,228,91,61,194,0,124,184,161,99,191,5,152,218, 72,54,28,85,211,154,105,22,63,168,253,36,207,95,131,101,93,35,220,163,173, 150,28,98,243,86,32,133,82,187,158,213,41,7,112,150,150,109,103,12,53,78,74, 188,152,4,241,116,108,8,202,35,115,39,255,255,255,255,255,255,255,255 ]), generator: new Uint8Array([2]), }, false, //whether the key is extractable (i.e. can be used in exportKey) ["deriveKey", "deriveBits"] //can be any combination of "deriveKey" and "deriveBits" ) .then(function(key){ //returns a keypair object console.log(key); console.log(key.publicKey); console.log(key.privateKey); }) .catch(function(err){ console.error(err); }); ``` #### DH - importKey ```javascript window.crypto.subtle.importKey( "raw", //can be "raw" (public only), "spki" (public only), or "pkcs8" (private only) new Uint8Array([ //this is an example raw key, "raw" would be an ArrayBuffer 203,25,0,203,43,75,46,159,217,37,185,181,25,220,71,187,112,195,251,233,152,56,206, 93,18,96,87,132,17,113,166,110,123,190,194,168,100,147,21,174,131,80,8,247,125,35, 210,70,103,141,152,173,99,74,34,132,92,134,216,55,171,186,89,167,189,217,164,119, 22,139,55,26,239,242,30,241,140,139,202,116,174,137,77,11,29,4,30,47,118,170,84,243, 97,132,86,58,24,82,36,149,45,185,23,172,67,162,48,43,110,251,175,20,102,237,113,148, 5,242,29,209,34,173,52,72,251,254,84,86,226,151,202,110,61,145,198,244,80,227,65, 203,118,217,91,45,58,172,165,224,122,230,50,135,120,124,37,190,186,204,103,218,19, 91,246,115,6,199,45,121,156,149,6,208,85,26,94,171,165,228,58,200,49,82,210,170,243, 154,190,15,2,225,143,159 ]), { //these are the algorithm options name: "DH", //NOTE: THIS IS A SMALL PRIME FOR TESTING ONLY! DO NOT USE IT FOR REAL! //See http://datatracker.ietf.org/doc/rfc3526/ for better primes prime: new Uint8Array([ 255,255,255,255,255,255,255,255,201,15,218,162,33,104,194,52,196,198,98,139, 128,220,28,209,41,2,78,8,138,103,204,116,2,11,190,166,59,19,155,34,81,74,8, 121,142,52,4,221,239,149,25,179,205,58,67,27,48,43,10,109,242,95,20,55,79,225, 53,109,109,81,194,69,228,133,181,118,98,94,126,198,244,76,66,233,166,55,237, 107,11,255,92,182,244,6,183,237,238,56,107,251,90,137,159,165,174,159,36,17, 124,75,31,230,73,40,102,81,236,228,91,61,194,0,124,184,161,99,191,5,152,218, 72,54,28,85,211,154,105,22,63,168,253,36,207,95,131,101,93,35,220,163,173, 150,28,98,243,86,32,133,82,187,158,213,41,7,112,150,150,109,103,12,53,78,74, 188,152,4,241,116,108,8,202,35,115,39,255,255,255,255,255,255,255,255 ]), generator: new Uint8Array([2]), }, false, //whether the key is extractable (i.e. can be used in exportKey) [] //use ["deriveKey", "deriveBits"] if importing a private key ) .then(function(publicKey){ //returns a publicKey (or privateKey if you are importing a private key) console.log(publicKey); }) .catch(function(err){ console.error(err); }); ``` #### DH - exportKey ```javascript window.crypto.subtle.exportKey( "jwk", //can be "raw" (public or private), "spki" (public only), or "pkcs8" (private only) publicKey //can be a publicKey or privateKey, as long as extractable was true ) .then(function(keydata){ //returns the exported key data console.log(keydata); }) .catch(function(err){ console.error(err); }); ``` #### DH - deriveKey ```javascript window.crypto.subtle.deriveKey( { name: "DH", //NOTE: THIS IS A SMALL PRIME FOR TESTING ONLY! DO NOT USE IT FOR REAL! //See http://datatracker.ietf.org/doc/rfc3526/ for better primes prime: new Uint8Array([ 255,255,255,255,255,255,255,255,201,15,218,162,33,104,194,52,196,198,98,139, 128,220,28,209,41,2,78,8,138,103,204,116,2,11,190,166,59,19,155,34,81,74,8, 121,142,52,4,221,239,149,25,179,205,58,67,27,48,43,10,109,242,95,20,55,79,225, 53,109,109,81,194,69,228,133,181,118,98,94,126,198,244,76,66,233,166,55,237, 107,11,255,92,182,244,6,183,237,238,56,107,251,90,137,159,165,174,159,36,17, 124,75,31,230,73,40,102,81,236,228,91,61,194,0,124,184,161,99,191,5,152,218, 72,54,28,85,211,154,105,22,63,168,253,36,207,95,131,101,93,35,220,163,173, 150,28,98,243,86,32,133,82,187,158,213,41,7,112,150,150,109,103,12,53,78,74, 188,152,4,241,116,108,8,202,35,115,39,255,255,255,255,255,255,255,255 ]), generator: new Uint8Array([2]), public: publicKey, //a DH public key from generateKey or importKey }, privateKey, //your DH private key from generateKey or importKey { //the key type you want to create based on the derived bits name: "AES-CTR", //can be any AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH", or "HMAC") //the generateKey parameters for that type of algorithm length: 256, //can be 128, 192, or 256 }, false, //whether the derived key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //limited to the options in that algorithm's importKey ) .then(function(key){ //returns the derived key console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### DH - deriveBits ```javascript window.crypto.subtle.deriveBits( { name: "DH", //NOTE: THIS IS A SMALL PRIME FOR TESTING ONLY! DO NOT USE IT FOR REAL! //See http://datatracker.ietf.org/doc/rfc3526/ for better primes prime: new Uint8Array([ 255,255,255,255,255,255,255,255,201,15,218,162,33,104,194,52,196,198,98,139, 128,220,28,209,41,2,78,8,138,103,204,116,2,11,190,166,59,19,155,34,81,74,8, 121,142,52,4,221,239,149,25,179,205,58,67,27,48,43,10,109,242,95,20,55,79,225, 53,109,109,81,194,69,228,133,181,118,98,94,126,198,244,76,66,233,166,55,237, 107,11,255,92,182,244,6,183,237,238,56,107,251,90,137,159,165,174,159,36,17, 124,75,31,230,73,40,102,81,236,228,91,61,194,0,124,184,161,99,191,5,152,218, 72,54,28,85,211,154,105,22,63,168,253,36,207,95,131,101,93,35,220,163,173, 150,28,98,243,86,32,133,82,187,158,213,41,7,112,150,150,109,103,12,53,78,74, 188,152,4,241,116,108,8,202,35,115,39,255,255,255,255,255,255,255,255 ]), generator: new Uint8Array([2]), public: publicKey, //a DH public key from generateKey or importKey }, privateKey, //your DH private key from generateKey or importKey 256 //the number of bits you want to derive ) .then(function(bits){ //returns the derived bits as an ArrayBuffer console.log(new Uint8Array(bits)); }) .catch(function(err){ console.error(err); }); ``` ## SHA #### SHA-1 - digest ```javascript window.crypto.subtle.digest( { name: "SHA-1", }, new Uint8Array([1,2,3,4]) //The data you want to hash as an ArrayBuffer ) .then(function(hash){ //returns the hash as an ArrayBuffer console.log(new Uint8Array(hash)); }) .catch(function(err){ console.error(err); }); ``` #### SHA-256 - digest ```javascript window.crypto.subtle.digest( { name: "SHA-256", }, new Uint8Array([1,2,3,4]) //The data you want to hash as an ArrayBuffer ) .then(function(hash){ //returns the hash as an ArrayBuffer console.log(new Uint8Array(hash)); }) .catch(function(err){ console.error(err); }); ``` #### SHA-384 - digest ```javascript window.crypto.subtle.digest( { name: "SHA-384", }, new Uint8Array([1,2,3,4]) //The data you want to hash as an ArrayBuffer ) .then(function(hash){ //returns the hash as an ArrayBuffer console.log(new Uint8Array(hash)); }) .catch(function(err){ console.error(err); }); ``` #### SHA-512 - digest ```javascript window.crypto.subtle.digest( { name: "SHA-512", }, new Uint8Array([1,2,3,4]) //The data you want to hash as an ArrayBuffer ) .then(function(hash){ //returns the hash as an ArrayBuffer console.log(new Uint8Array(hash)); }) .catch(function(err){ console.error(err); }); ``` ## CONCAT #### CONCAT - importKey ```javascript window.crypto.subtle.importKey( "raw", //only "raw" is allowed keydata, //your raw key data as an ArrayBuffer { name: "CONCAT", }, false, //whether the key is extractable (i.e. can be used in exportKey) ["deriveKey", "deriveBits"] //can be any combination of "deriveKey" and "deriveBits" ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### CONCAT - deriveKey ```javascript window.crypto.subtle.deriveKey( { "name": "CONCAT", algorithmId: ArrayBuffer, //?????? I don't know what this should be partyUInfo: ArrayBuffer, //?????? I don't know what this should be partyVInfo: ArrayBuffer, //?????? I don't know what this should be publicInfo: ArrayBuffer, //?????? I don't know what this should be privateInfo: ArrayBuffer, //?????? I don't know what this should be hash: {name: "SHA-1"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" }, key, //your key from importKey { //the key type you want to create based on the derived bits name: "AES-CTR", //can be any AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH", or "HMAC") //the generateKey parameters for that type of algorithm length: 256, //can be 128, 192, or 256 }, false, //whether the derived key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //limited to the options in that algorithm's importKey ) .then(function(key){ //returns the derived key console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### CONCAT - deriveBits ```javascript window.crypto.subtle.deriveBits( { "name": "CONCAT", algorithmId: ArrayBuffer, //?????? I don't know what this should be partyUInfo: ArrayBuffer, //?????? I don't know what this should be partyVInfo: ArrayBuffer, //?????? I don't know what this should be publicInfo: ArrayBuffer, //?????? I don't know what this should be privateInfo: ArrayBuffer, //?????? I don't know what this should be hash: {name: "SHA-1"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" }, key, //your key importKey 256 //the number of bits you want to derive ) .then(function(bits){ //returns the derived bits as an ArrayBuffer console.log(new Uint8Array(bits)); }) .catch(function(err){ console.error(err); }); ``` ## HKDF-CTR #### HKDF-CTR - importKey ```javascript window.crypto.subtle.importKey( "raw", //only "raw" is allowed keydata, //your raw key data as an ArrayBuffer { name: "HKDF-CTR", }, false, //whether the key is extractable (i.e. can be used in exportKey) ["deriveKey", "deriveBits"] //can be any combination of "deriveKey" and "deriveBits" ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### HKDF-CTR - deriveKey ```javascript window.crypto.subtle.deriveKey( { "name": "HKDF-CTR", label: ArrayBuffer, //?????? I don't know what this should be context: ArrayBuffer, //?????? I don't know what this should be hash: {name: "SHA-1"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" }, key, //your key from importKey { //the key type you want to create based on the derived bits name: "AES-CTR", //can be any AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH", or "HMAC") //the generateKey parameters for that type of algorithm length: 256, //can be 128, 192, or 256 }, false, //whether the derived key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //limited to the options in that algorithm's importKey ) .then(function(key){ //returns the derived key console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### HKDF-CTR - deriveBits ```javascript window.crypto.subtle.deriveBits( { "name": "HKDF-CTR", label: ArrayBuffer, //?????? I don't know what this should be context: ArrayBuffer, //?????? I don't know what this should be hash: {name: "SHA-1"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" }, key, //your key importKey 256 //the number of bits you want to derive ) .then(function(bits){ //returns the derived bits as an ArrayBuffer console.log(new Uint8Array(bits)); }) .catch(function(err){ console.error(err); }); ``` ## PBKDF2 #### PBKDF2 - generateKey ```javascript //NOTE: This prompts the user to enter a password. window.crypto.subtle.generateKey( { name: "PBKDF2", }, false, //whether the key is extractable (i.e. can be used in exportKey) ["deriveKey", "deriveBits"] //can be any combination of "deriveKey" and "deriveBits" ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### PBKDF2 - importKey ```javascript window.crypto.subtle.importKey( "raw", //only "raw" is allowed window.crypto.getRandomValues(new Uint8Array(16)), //your password { name: "PBKDF2", }, false, //whether the key is extractable (i.e. can be used in exportKey) ["deriveKey", "deriveBits"] //can be any combination of "deriveKey" and "deriveBits" ) .then(function(key){ //returns a key object console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### PBKDF2 - deriveKey ```javascript window.crypto.subtle.deriveKey( { "name": "PBKDF2", salt: window.crypto.getRandomValues(new Uint8Array(16)), iterations: 1000, hash: {name: "SHA-1"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" }, key, //your key from generateKey or importKey { //the key type you want to create based on the derived bits name: "AES-CTR", //can be any AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH", or "HMAC") //the generateKey parameters for that type of algorithm length: 256, //can be 128, 192, or 256 }, false, //whether the derived key is extractable (i.e. can be used in exportKey) ["encrypt", "decrypt"] //limited to the options in that algorithm's importKey ) .then(function(key){ //returns the derived key console.log(key); }) .catch(function(err){ console.error(err); }); ``` #### PBKDF2 - deriveBits ```javascript window.crypto.subtle.deriveBits( { "name": "PBKDF2", salt: window.crypto.getRandomValues(new Uint8Array(16)), iterations: 1000, hash: {name: "SHA-1"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" }, key, //your key from generateKey or importKey 256 //the number of bits you want to derive ) .then(function(bits){ //returns the derived bits as an ArrayBuffer console.log(new Uint8Array(bits)); }) .catch(function(err){ console.error(err); }); ``` ```typescript const privateKeyBytes = jwkToBytes(privateKeyJwk) const signatureBytes = crypto.sign(..., key: privateKeyBytes) const signatureJWS = signatureToJwsSignature(signatureBytes, header, data) const signatureJws = crypto.sign(..., key: privateKeyJwk, inputEncoder: jwkToBytes(), outputEncoder: ..) ```