let cryptoObj = window.crypto || window.msCrypto; // for IE 11
const typedArray = new Uint32Array(10);
let filledArray = window.crypto.getRandomValues(typedArray);
filledArray === typedArray // true, same instance
let subtleCrypto = window.crypto.subtle;
subtleCrypto.decrypt(...);
subtleCrypto.deriveBits(...);
subtleCrypto.deriveKey(...);
subtleCrypto.digest(...);
subtleCrypto.encrypt(...);
subtleCrypto.exportKey(...);
subtleCrypto.generateKey(...);
subtleCrypto.importKey(...);
subtleCrypto.sign(...);
subtleCrypto.unwrapKey(...);
subtleCrypto.verify(...);
subtleCrypto.wrapKey(...);
window.crypto
.IKnowWhatIamDoing
.IacceptTheTermsAndConditions
.encrypty(...)
> sha256sum ubuntu-mate-16.10-desktop-amd64.iso
c01b39c7a35ccc3b081a3e83d2c71fa9a767ebfeb45c69f08e17dfe3ef375a7b
SHA-256
"Lorem ipsum" (data)
0x8dsf8dwl2c0 (digest)
crypto.subtle.digest(...);
function digestArrayBuffer(data: ArrayBuffer): Promise<ArrayBuffer> {
return crypto.subtle.digest('SHA-256', data);
}
async function digestString(message: string): Promise<string> {
const encoder = new TextEncoder();
const data = encoder.encode(message); // Uint8Array UTF-8
const digestBuffer = await crypto.subtle.digest('SHA-256', data);
const decoder = new TextDecoder(); // default 'utf-8'
return decoder.decode(digestBuffer);
}
HMAC
"Lorem ipsum" (data)
0x8dsf8dwl2c0 (sign)
0x9s6mh7d8bew2 (key)
let signData = await window.crypto.subtle.sign(...);
let isValid = await window.crypto.subtle.verify(...);
function signData(
data: ArrayBuffer, key: CryptoKey
): Promise<ArrayBuffer> {
return window.crypto.subtle.sign(
"HMAC", key, data
);
}
function verifyData(
data: ArrayBuffer, key: CryptoKey, sign: ArrayBuffer
): Promise<boolean> {
return window.crypto.subtle.verify(
"HMAC", key, sign, data
);
}
AES-GCM
"Lorem ipsum" (data)
0x8dsf8dwl2c0 (cipher)
0x9s6mh7d8bew2 (key)
0xd9v7fd773m2 (nonce)
window.crypto.subtle.encrypt(...);
window.crypto.subtle.decrypt(...);
await function encryptData(
data: ArrayBuffer, key: CryptoKey
) {
const nonce = window.crypto.getRandomValues(new Uint8Array(12));
const cipher = await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: nonce
},
key,
data
);
return { cipher, nonce }
}
async function decryptData(
data: ArrayBuffer, key: CryptoKey, nonce: ArrayBuffer
) {
return window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: nonce
},
key,
data
);
}
const cryptoKey = await window.crypto.subtle.generateKey(
"AES-GCM", // algorítimo q será usada
true, // essa chave por ser extraída?
["encrypt", "decrypt"] // usos dessa chave
);
const rawKey = await window.crypto.subtle.exportKey(
"raw", cryptoKey
);
const sameKey = await window.crypto.subtle.importKey(
"raw", rawKey,
"AES-GCM",
false,
["encrypt", "decrypt"]
);
PBKDF2
0x8dsf8dwl2c0 (week key)
0x8dsf8dwl2c0 (stronger key)
0x9s6mh7d8bew2 (salt)
50000 (interactions)
const encoder = new TextEncoder();
const encodedPass = encoder.encode(userPass); // Uint8Array UTF-8
const baseKey = await window.crypto.subtle.importKey(
'raw',
encodedPass,
'PBKDF2', // algoritimo de derivação q usaremos
false, // não precisamos extrair a chave de volta
['deriveKey'],
),
const salt = crypto.getRandomValues(new Uint8Array(8));
const cryptoKey = await window.crypto.subtle.deriveKey(
{
"name": "PBKDF2",
salt: salt,
"iterations": 100000,
"hash": "SHA-256"
},
baseKey,
{ "name": "AES-GCM", "length": 256 },
false,
[ "encrypt", "decrypt" ]
);
const credential = await window.navigator.credentials.create({
publicKey: generatePublicKeyOptions(
randomChallengeFromServer,
userData
)
});
function generatePublicKeyOptions(challenge, user) {
const encoder = new TextEncoder();
return {
challenge: encoder.encode(challenge),
rp: {
name: "My Website Name",
id: "my-site-domain.com",
},
user: {
id: encoder.encode(user.id),
name: user.email,
displayName: user.name,
},
pubKeyCredParams: [{alg: -7, type: "public-key"}]
}
}
const credential = await navigator.credentials.create(...);
console.log(credential);
PublicKeyCredential {
id: 'ADSUllKQmbqdGtpu4sjseh4cg2TxSvrbcHDTBsv4NSSX9...',
rawId: ArrayBuffer(59),
response: AuthenticatorAttestationResponse {
clientDataJSON: ArrayBuffer(121), // utf-8 string decoded
attestationObject: ArrayBuffer(306), // CBOR decoded
},
type: 'public-key'
}
const credential = await navigator.credentials.get({
publicKey: generatePublicKeyOptions(
randomChallengeFromServer,
credentialId
)
});
function generatePublicKeyOptions(challenge, credentialId) {
const encoder = new TextEncoder();
return {
challenge: encoder.encode(challenge),
allowCredentials: [{
id: encoder.encode(credentialId),
type: 'public-key'
}]
}
}
const credential = await navigator.credentials.get(...);
console.log(credential);
PublicKeyCredential {
id: 'ADSUllKQmbqdGtpu4sjseh4cg2TxSvrbcHDTBsv4NSSX9...',
rawId: ArrayBuffer(59),
response: AuthenticatorAttestationResponse {
clientDataJSON: ArrayBuffer(121), // dados do cliente registrado
authenticatorData: ArrayBuffer(191), // dados do autenticador
signature: ArrayBuffer(70), // assinatura com a chave privada
},
type: 'public-key'
}