cloudworker-proxy
Version:
An api gateway for cloudflare workers
352 lines (351 loc) • 14.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const webcrypto = require("webcrypto-core");
const AlgorithmError = webcrypto.AlgorithmError;
const PrepareAlgorithm = webcrypto.PrepareAlgorithm;
const BaseCrypto = webcrypto.BaseCrypto;
const AlgorithmNames = webcrypto.AlgorithmNames;
const aes = require("./crypto/aes");
const ec = require("./crypto/ec");
const hmac = require("./crypto/hmac");
const pbkdf2 = require("./crypto/pbkdf2");
const rsa = require("./crypto/rsa");
const native = require("./native");
function PrepareData(data) {
return ab2b(data);
}
function ab2b(ab) {
if (Buffer.isBuffer(ab)) {
return ab;
}
else if (ArrayBuffer.isView(ab)) {
return Buffer.from(ab.buffer, ab.byteOffset, ab.byteLength);
}
else {
return Buffer.from(ab);
}
}
class SubtleCrypto extends webcrypto.SubtleCrypto {
digest(algorithm, data) {
return super.digest.apply(this, arguments)
.then(() => {
return new Promise((resolve, reject) => {
const alg = PrepareAlgorithm(algorithm);
const dataBytes = PrepareData(data);
const algName = alg.name.toLowerCase();
switch (algName) {
case "sha-1":
case "sha-224":
case "sha-256":
case "sha-384":
case "sha-512":
native.Core.digest(algName.replace("-", ""), dataBytes, (err, digest) => {
if (err) {
reject(err);
}
else {
resolve(digest.buffer);
}
});
break;
default:
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, algName);
}
});
});
}
generateKey(algorithm, extractable, keyUsages) {
return super.generateKey.apply(this, arguments)
.then(() => {
const alg = PrepareAlgorithm(algorithm);
let AlgClass;
switch (alg.name.toLowerCase()) {
case AlgorithmNames.RsaSSA.toLowerCase():
AlgClass = rsa.RsaPKCS1;
break;
case AlgorithmNames.RsaPSS.toLowerCase():
AlgClass = rsa.RsaPSS;
break;
case AlgorithmNames.RsaOAEP.toLowerCase():
AlgClass = rsa.RsaOAEP;
break;
case AlgorithmNames.AesECB.toLowerCase():
case AlgorithmNames.AesCBC.toLowerCase():
case AlgorithmNames.AesCTR.toLowerCase():
case AlgorithmNames.AesCTR.toLowerCase():
case AlgorithmNames.AesGCM.toLowerCase():
case AlgorithmNames.AesKW.toLowerCase():
AlgClass = aes.AesCrypto;
break;
case AlgorithmNames.EcDSA.toLowerCase():
case AlgorithmNames.EcDH.toLowerCase():
AlgClass = ec.EcCrypto;
break;
case AlgorithmNames.Hmac.toLowerCase():
AlgClass = hmac.HmacCrypto;
break;
default:
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, alg.name);
}
return AlgClass.generateKey(alg, extractable, keyUsages);
});
}
sign(algorithm, key, data) {
return super.sign.apply(this, arguments)
.then(() => {
const alg = PrepareAlgorithm(algorithm);
const dataBytes = PrepareData(data);
let AlgClass;
switch (alg.name.toLowerCase()) {
case AlgorithmNames.RsaSSA.toLowerCase():
AlgClass = rsa.RsaPKCS1;
break;
case AlgorithmNames.RsaPSS.toLowerCase():
AlgClass = rsa.RsaPSS;
break;
case AlgorithmNames.EcDSA.toLowerCase():
AlgClass = ec.EcCrypto;
break;
case AlgorithmNames.Hmac.toLowerCase():
AlgClass = hmac.HmacCrypto;
break;
default:
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, alg.name);
}
return AlgClass.sign(alg, key, dataBytes);
});
}
verify(algorithm, key, signature, data) {
return super.verify.apply(this, arguments)
.then(() => {
const alg = PrepareAlgorithm(algorithm);
const signatureBytes = PrepareData(signature);
const dataBytes = PrepareData(data);
let AlgClass;
switch (alg.name.toLowerCase()) {
case AlgorithmNames.RsaSSA.toLowerCase():
AlgClass = rsa.RsaPKCS1;
break;
case AlgorithmNames.RsaPSS.toLowerCase():
AlgClass = rsa.RsaPSS;
break;
case AlgorithmNames.EcDSA.toLowerCase():
AlgClass = ec.EcCrypto;
break;
case AlgorithmNames.Hmac.toLowerCase():
AlgClass = hmac.HmacCrypto;
break;
default:
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, alg.name);
}
return AlgClass.verify(alg, key, signatureBytes, dataBytes);
});
}
encrypt(algorithm, key, data) {
return super.encrypt.apply(this, arguments)
.then(() => {
return this.encryptDecrypt(algorithm, key, data, true);
});
}
decrypt(algorithm, key, data) {
return super.decrypt.apply(this, arguments)
.then(() => {
return this.encryptDecrypt(algorithm, key, data, false);
});
}
wrapKey(format, key, wrappingKey, wrapAlgorithm) {
return super.wrapKey.apply(this, arguments)
.then(() => {
return this.exportKey(format, key)
.then((exportedKey) => {
const alg = webcrypto.PrepareAlgorithm(wrapAlgorithm);
let dataBytes;
if (!(exportedKey instanceof ArrayBuffer)) {
dataBytes = Buffer.from(JSON.stringify(exportedKey));
}
else {
dataBytes = Buffer.from(exportedKey);
}
let CryptoClass;
if (alg.name.toUpperCase() === webcrypto.AlgorithmNames.AesKW) {
CryptoClass = aes.AesCrypto;
}
if (CryptoClass) {
return CryptoClass.encrypt(alg, wrappingKey, dataBytes);
}
else {
return this.encryptDecrypt(alg, wrappingKey, dataBytes, true);
}
});
});
}
unwrapKey(format, wrappedKey, unwrappingKey, unwrapAlgorithm, unwrappedKeyAlgorithm, extractable, keyUsages) {
return super.unwrapKey.apply(this, arguments)
.then(() => {
return Promise.resolve()
.then(() => {
const alg = webcrypto.PrepareAlgorithm(unwrapAlgorithm);
const dataBytes = PrepareData(wrappedKey);
let CryptoClass;
if (alg.name.toUpperCase() === webcrypto.AlgorithmNames.AesKW) {
CryptoClass = aes.AesCrypto;
}
if (CryptoClass) {
return CryptoClass.decrypt(alg, unwrappingKey, dataBytes);
}
else {
return this.encryptDecrypt(alg, unwrappingKey, dataBytes, false);
}
})
.then((decryptedKey) => {
let keyData;
if (format === "jwk") {
keyData = JSON.parse(Buffer.from(decryptedKey).toString());
}
else {
keyData = Buffer.from(decryptedKey);
}
return this.importKey(format, keyData, unwrappedKeyAlgorithm, extractable, keyUsages);
});
});
}
deriveKey(algorithm, baseKey, derivedKeyType, extractable, keyUsages) {
return super.deriveKey.apply(this, arguments)
.then(() => {
const alg = PrepareAlgorithm(algorithm);
const algDerivedKeyType = PrepareAlgorithm(derivedKeyType);
let AlgClass;
switch (alg.name.toLowerCase()) {
case AlgorithmNames.EcDH.toLowerCase():
AlgClass = ec.EcCrypto;
break;
case AlgorithmNames.Pbkdf2.toLowerCase():
AlgClass = pbkdf2.Pbkdf2Crypto;
break;
default:
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, alg.name);
}
return AlgClass.deriveKey(alg, baseKey, algDerivedKeyType, extractable, keyUsages);
});
}
deriveBits(algorithm, baseKey, length) {
return super.deriveBits.apply(this, arguments)
.then(() => {
const alg = PrepareAlgorithm(algorithm);
let AlgClass;
switch (alg.name.toLowerCase()) {
case AlgorithmNames.EcDH.toLowerCase():
AlgClass = ec.EcCrypto;
break;
case AlgorithmNames.Pbkdf2.toLowerCase():
AlgClass = pbkdf2.Pbkdf2Crypto;
break;
default:
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, alg.name);
}
return AlgClass.deriveBits(alg, baseKey, length);
});
}
exportKey(format, key) {
return super.exportKey.apply(this, arguments)
.then(() => {
let AlgClass;
switch (key.algorithm.name.toLowerCase()) {
case AlgorithmNames.RsaSSA.toLowerCase():
AlgClass = rsa.RsaPKCS1;
break;
case AlgorithmNames.RsaPSS.toLowerCase():
AlgClass = rsa.RsaPSS;
break;
case AlgorithmNames.RsaOAEP.toLowerCase():
AlgClass = rsa.RsaOAEP;
break;
case AlgorithmNames.AesECB.toLowerCase():
case AlgorithmNames.AesCBC.toLowerCase():
case AlgorithmNames.AesCTR.toLowerCase():
case AlgorithmNames.AesGCM.toLowerCase():
case AlgorithmNames.AesKW.toLowerCase():
AlgClass = aes.AesCrypto;
break;
case AlgorithmNames.EcDSA.toLowerCase():
case AlgorithmNames.EcDH.toLowerCase():
AlgClass = ec.EcCrypto;
break;
case AlgorithmNames.Hmac.toLowerCase():
AlgClass = hmac.HmacCrypto;
break;
default:
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, key.algorithm.name);
}
return AlgClass.exportKey(format, key);
});
}
importKey(format, keyData, algorithm, extractable, keyUsages) {
return super.importKey.apply(this, arguments)
.then(() => {
const alg = PrepareAlgorithm(algorithm);
let dataAny = keyData;
if (format !== "jwk") {
dataAny = PrepareData(dataAny);
}
let AlgClass;
switch (alg.name.toLowerCase()) {
case AlgorithmNames.RsaSSA.toLowerCase():
AlgClass = rsa.RsaPKCS1;
break;
case AlgorithmNames.RsaPSS.toLowerCase():
AlgClass = rsa.RsaPSS;
break;
case AlgorithmNames.RsaOAEP.toLowerCase():
AlgClass = rsa.RsaOAEP;
break;
case AlgorithmNames.AesECB.toLowerCase():
case AlgorithmNames.AesCBC.toLowerCase():
case AlgorithmNames.AesCTR.toLowerCase():
case AlgorithmNames.AesGCM.toLowerCase():
case AlgorithmNames.AesKW.toLowerCase():
AlgClass = aes.AesCrypto;
break;
case AlgorithmNames.EcDSA.toLowerCase():
case AlgorithmNames.EcDH.toLowerCase():
AlgClass = ec.EcCrypto;
break;
case AlgorithmNames.Hmac.toLowerCase():
AlgClass = hmac.HmacCrypto;
break;
case AlgorithmNames.Pbkdf2.toLowerCase():
AlgClass = pbkdf2.Pbkdf2Crypto;
break;
default:
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, alg.name);
}
return AlgClass.importKey(format, dataAny, alg, extractable, keyUsages);
});
}
encryptDecrypt(algorithm, key, data, encrypt) {
const alg = PrepareAlgorithm(algorithm);
const dataBytes = PrepareData(data);
let AlgClass;
switch (alg.name.toLowerCase()) {
case AlgorithmNames.RsaOAEP.toLowerCase():
AlgClass = rsa.RsaOAEP;
break;
case AlgorithmNames.AesECB.toLowerCase():
case AlgorithmNames.AesCBC.toLowerCase():
case AlgorithmNames.AesCTR.toLowerCase():
case AlgorithmNames.AesGCM.toLowerCase():
case AlgorithmNames.AesKW.toLowerCase():
AlgClass = aes.AesCrypto;
break;
default:
throw new AlgorithmError(AlgorithmError.NOT_SUPPORTED, alg.name);
}
if (encrypt) {
return AlgClass.encrypt(alg, key, dataBytes);
}
else {
return AlgClass.decrypt(alg, key, dataBytes);
}
}
}
exports.SubtleCrypto = SubtleCrypto;