Skip to content

Instantly share code, notes, and snippets.

@rynomad
Forked from Ry-Nomad/gist:b174ec37b234fbd3c315
Last active August 29, 2015 14:14
Show Gist options
  • Save rynomad/162da41bdf04d74d21b4 to your computer and use it in GitHub Desktop.
Save rynomad/162da41bdf04d74d21b4 to your computer and use it in GitHub Desktop.
//Object DetectSubtleCrypto()
//Establish the availability of various crypto.subtle API's necessary for keygen, signing, verification, hashing
function DetectSubtleCrypto(){
var supportedApis = {};
var baselineSupport = (
(crypto && crypto.subtle)
&& (
(location.protocol === "https:" || "chrome-extension:" || "chrome:")
|| (location.hostname === "localhost" || location.hostname === "127.0.0.1")
)
) ? true : false ;
if (!baselineSupport) {
supportedApis = {}
} else {
try {
crypto.subtle.generateKey(
{ name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, hash:{name:"SHA-256"}, publicExponent: new Uint8Array([0x01, 0x00, 0x01]) },
true, //exportable;
["sign", "verify"]).then(function(result){
if (result.publicKey && result.privateKey) {
supportedApis.generateRSA_SHA_256 = true;
var key = result;
var algo = {name:"RSASSA-PKCS1-v1_5",hash:{name:"SHA-256"}};
crypto.subtle.sign(algo, key.privateKey, new Uint8Array([1,2,3,4,5])).then(function(signature){
console.log("signed returned", signature);
supportedApis.signRSA_SHA_256 = true;
crypto.subtle.verify(algo, key.publicKey, signature, new Uint8Array([1,2,3,4,5])).then(function(verified){
console.log("verified returned", verified)
supportedApis.verifyRSA_SHA_256 = verified;
if (verified && supportedApis.importSPKI){
supportedApis.ndn_rsa = true;
}
});
});
try{
crypto.subtle.exportKey("pkcs8",key.privateKey).then(function(result){
supportedApis.exportPrivatePKCS8 = true;
});
} catch (e) {
console.log("error exporting private key as pkcs8")
supportedApis.exportPrivatePKCS8 = false;
}
try {
crypto.subtle.exportKey("spki",key.publicKey).then(function(result){
supportedApis.exportSPKI = true;
crypto.subtle.importKey("spki",result,algo, true, ["verify"]).then(function(key){
supportedApis.importSPKI = true;
if (supportedApis.verifyRSA_SHA_256){
supportedApis.ndn_rsa = true;
}
})
});
} catch (e) {
console.log("error exporting raw key", e)
supportedApis.exportPrivateRAW = false;
}
try {
crypto.subtle.exportKey("jwk",key.privateKey).then(function(result){
supportedApis.exportPrivateJWK = true;
})
} catch (e) {
console.log("error exporting private key as jwk", e)
supportedApis.exportPrivateJWK = false;
}
} else {
console.log("genKey failover, but no error... weird.")
supportedApis.generateRSASSAKey = false
}
});
} catch (e){
console.log("unable to generate sign/verify key", e)
supportedApis.sign = false;
supportedApis.verify = false;
}
var testDigest = new Uint8Array(1000)
try{
crypto.subtle.digest({name:"SHA-256"}, testDigest.buffer).then(function(result){
supportedApis.digestSHA256 = true;
});
} catch (e) {
console.log("digestSHA256 error", e)
supportedAPIs.digestSHA256 = false;
}
}
return function (desiredApisArray){
//what I'm thinking here is that KeyChain could supply desired api's based on default/developer needs for encrypt/decrypt, key formats, storage formats, etc. please advise.
//The most important thing about returning this closure is that it allows us to empirically test the crypto capabilities of the browser asyncronously at the beginning of runtime, and get only use the features we're sure are implimented.
return supportedApis;
}
}
module.exports = DetectSubtleCrypto();
PolicyManager.verifySha256WithRsaSignature = function
(signature, signedBlob, publicKeyDer, onComplete)
{
if (PolicyManager.verifyUsesString === null) {
var hashResult = require("crypto").createHash('sha256').digest();
// If the hash result is a string, we assume that this is a version of
// crypto where verify also uses a string signature.
PolicyManager.verifyUsesString = (typeof hashResult === 'string');
}
if (useSubtleCrypto().ndn_rsa && onComplete){
var algo = {name:"RSASSA-PKCS1-v1_5",hash:{name:"SHA-256"}};
crypto.subtle.importKey("spki", der.buffer, algo, true, ["verify"]).then(function(publicKey){
crypto.subtle.verify(algo, publicKey, signature.signature, signedBlob.signedBuf()).then(function(verified){
onComplete(verified);
});
});
} else {
onComplete = onComplete || function(v){return v;};
// The crypto verifier requires a PEM-encoded public key.
var keyBase64 = publicKeyDer.buf().toString('base64');
var keyPem = "-----BEGIN PUBLIC KEY-----\n";
for (var i = 0; i < keyBase64.length; i += 64)
keyPem += (keyBase64.substr(i, 64) + "\n");
keyPem += "-----END PUBLIC KEY-----";
var verifier = require('crypto').createVerify('RSA-SHA256');
verifier.update(signedBlob.signedBuf());
var signatureBytes = PolicyManager.verifyUsesString ?
DataUtils.toString(signature.buf()) : signature.buf();
return onComplete(verifier.verify(keyPem, signatureBytes));
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment