Skip to content

Instantly share code, notes, and snippets.

@rynomad
Last active August 29, 2015 14:14
Show Gist options
  • Save rynomad/db7b4babd0df09c0c631 to your computer and use it in GitHub Desktop.
Save rynomad/db7b4babd0df09c0c631 to your computer and use it in GitHub Desktop.
crypto.subtle algorithm and feature detector
function testGenerateImportExport(cipher){
return crypto.subtle.generateKey(cipher, true, cipher.usage).then(function(keys){
if (keys.type === "secret") //only one secret key (e.g. with HMAC)
cipher.keys = [keys];
else
cipher.keys = [keys.privateKey, keys.publicKey];
var exportProms = [];
for (var i = 0; i < cipher.keys.length; i++){
exportProms.push(crypto.subtle.exportKey("jwk", cipher.keys[i]));
}
console.log()
return Promise.all(exportProms);
}).then(function(exportedKeys){
var importProms = [];
cipher.keys.jwk = exportedKeys;
for (var i = 0; i < cipher.keys.length; i++){
importProms.push(crypto.subtle.importKey("jwk", exportedKeys[i], cipher, true, cipher.keys[i].usages));
}
return Promise.all(importProms);
}).then(function(importedKeys){
console.log("generate/import/export completed, ", cipher.name)
return cipher;
}).catch(function(err){
if (cipher.name === "ECDSA")
return cipher;
console.log("generate/import/export failed, ", cipher.name, err)
});
}
function testSignVerify (cipher){
var toSign = new Uint8Array([1,1,2,3,5,8,13,21,44,65,109]);
var signKey = cipher.keys[0]
var verKey = (signKey.type === "secret") ? signKey : cipher.keys[1];
return crypto.subtle.sign(cipher, signKey, toSign).then(function(signature){
return crypto.subtle.verify(cipher, verKey, signature, toSign);
}).then(function(verified){
if (verified){
return [cipher, true];
} else {
return [cipher, false];
}
});
}
function testEncryptDecrypt (cipher){
var toEncrypt = new Uint8Array([1,1,2,3,5,8,13,21,44,65,109])
, enKey, deKey;
for(var i = 0; i < cipher.keys.length; i++){
for (var j = 0; j < cipher.keys[i].usages.length; j++){
if (cipher.keys[i].usages[j] === "encrypt")
enKey = cipher.keys[i];
if (cipher.keys[i].usages[j] === "decrypt")
deKey = cipher.keys[i];
}
}
console.log("?",cipher.keys,enKey, deKey);
return crypto.subtle.encrypt(cipher, enKey, toEncrypt).then(function(encrypted){
return crypto.subtle.decrypt(cipher, deKey, encrypted);
}).then(function(unencrypted){
return [cipher, true];
}).catch(function(er){
console.log("encrypt/decrypt failed with cs" + cipher.set ,";", cipher.name, "error: ", er);
return [cipher, false];
});
}
function DetectSubtleCiphers(){
var ciphers = {
"1a" : {}
, "2a" : {}
};
function evaluateAndAttach (cipherAndResult){
var cipher = cipherAndResult[0]
, result = cipherAndResult[1];
if (result)
ciphers[cipher.set][cipher.name] = cipher;
else
ciphers[cipher.set][cipher.name] = false;
console.log("cs",cipher.set,";" ,cipher.name, "supported by crypto.subtle: ", result);
}
function supportedCiphers (){
return ciphers;
}
if (crypto && crypto.subtle){
//start testing our necessary apis, assign the each algorithm its respective dictionary for crypto subtle.
//If supported, we will attach it to the returned ciphers object for use in telehash.
//additionally, overload exported algorithm dictionary with 'usage' array:
//It's technically the last argument in keygen, but having it there in the dictionary doesn't hurt and allows
//more streamlining.
var aesiv = crypto.getRandomValues(new Uint8Array(12))
var cs1a_ECC = false // not in w3c spec, though possible to specify? maybe?
// http://www.w3.org/TR/WebCryptoAPI/#dfn-ecdsa-extended-namedcurve-values
// http://www.w3.org/TR/WebCryptoAPI/#algorithms
, cs1a_HMAC = { name: "HMAC"
, set : "1a"
, hash: {name: "SHA-256"}
, usage: ["sign","verify"]
}
, cs1a_AES = { name: "AES-CTR"
, set : "1a"
, length: 128
, usage: ["encrypt","decrypt"]
}
, cs2a_RSA = { name: "RSA-OAEP"
, set: "2a"
, hash: {name: "SHA-256"}
, modulusLength:2048
, publicExponent : new Uint8Array([0x01,0x00,0x01])
, usage: ["encrypt","decrypt"]
}
, cs2a_ECC = { name: "ECDSA"
, set : "2a"
, namedCurve: "P-256"
, usage: ["sign","verify"]
}
, cs2a_AES = { name: "AES-GCM"
, set : "2a"
, length: 256
, iv : crypto.getRandomValues(new Uint8Array(12)).buffer
, usage: ["decrypt","encrypt"]
};
//for each algorithm, test generate/import/export/(sign/verify)||(encrypt/decrypt).
//if everything works, attach algorithm to ciphers object
Promise.all([
testGenerateImportExport(cs1a_HMAC)
.then(testSignVerify)
.then(evaluateAndAttach)
,
testGenerateImportExport(cs1a_AES)
.then(testEncryptDecrypt)
.then(evaluateAndAttach)
,
testGenerateImportExport(cs2a_ECC)
.then(testSignVerify)
.then(evaluateAndAttach)
,
testGenerateImportExport(cs2a_AES)
.then(testEncryptDecrypt)
.then(evaluateAndAttach)
,
testGenerateImportExport(cs2a_RSA)
.then(testEncryptDecrypt)
.then(evaluateAndAttach)
,
]).catch(function(er){
console.log("one graceful, silent error message", er);
})
}
return supportedCiphers;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment