cloudworker-proxy
Version:
An api gateway for cloudflare workers
304 lines (303 loc) • 12.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const webcrypto_core_1 = require("webcrypto-core");
const key_1 = require("../key");
const native = require("../native");
function b64_decode(b64url) {
return Buffer.from(webcrypto_core_1.Base64Url.decode(b64url));
}
class RsaCrypto extends webcrypto_core_1.BaseCrypto {
static generateKey(algorithm, extractable, keyUsages) {
return new Promise((resolve, reject) => {
const size = algorithm.modulusLength;
const exp = Buffer.from(algorithm.publicExponent);
let nExp = 0;
if (exp.length === 3) {
nExp = 1;
}
native.Key.generateRsa(size, nExp, (err, key) => {
try {
if (err) {
reject(new webcrypto_core_1.WebCryptoError(`Rsa: Can not generate new key\n${err.message}`));
}
else {
const prvUsages = ["sign", "decrypt", "unwrapKey"]
.filter((usage) => keyUsages.some((keyUsage) => keyUsage === usage));
const pubUsages = ["verify", "encrypt", "wrapKey"]
.filter((usage) => keyUsages.some((keyUsage) => keyUsage === usage));
resolve({
privateKey: new key_1.CryptoKey(key, algorithm, "private", extractable, prvUsages),
publicKey: new key_1.CryptoKey(key, algorithm, "public", true, pubUsages),
});
}
}
catch (e) {
reject(e);
}
});
});
}
static importKey(format, keyData, algorithm, extractable, keyUsages) {
let keyType = native.KeyType.PUBLIC;
const alg = algorithm;
return new Promise((resolve, reject) => {
const formatLC = format.toLocaleLowerCase();
switch (formatLC) {
case "jwk":
const jwk = keyData;
const data = {};
data["kty"] = jwk.kty;
data["n"] = b64_decode(jwk.n);
data["e"] = b64_decode(jwk.e);
if (jwk.d) {
keyType = native.KeyType.PRIVATE;
data["d"] = b64_decode(jwk.d);
data["p"] = b64_decode(jwk.p);
data["q"] = b64_decode(jwk.q);
data["dp"] = b64_decode(jwk.dp);
data["dq"] = b64_decode(jwk.dq);
data["qi"] = b64_decode(jwk.qi);
}
native.Key.importJwk(data, keyType, (err, key) => {
try {
if (err) {
reject(new webcrypto_core_1.WebCryptoError(`ImportKey: Cannot import key from JWK\n${err}`));
}
else {
resolve(key);
}
}
catch (e) {
reject(e);
}
});
break;
case "pkcs8":
case "spki":
if (!Buffer.isBuffer(keyData)) {
throw new webcrypto_core_1.WebCryptoError("ImportKey: keyData is not a Buffer");
}
let importFunction = native.Key.importSpki;
if (formatLC === "pkcs8") {
keyType = native.KeyType.PRIVATE;
importFunction = native.Key.importPkcs8;
}
importFunction(keyData, (err, key) => {
try {
if (err) {
reject(new webcrypto_core_1.WebCryptoError(`ImportKey: Can not import key for ${format}\n${err.message}`));
}
else {
resolve(key);
}
}
catch (e) {
reject(e);
}
});
break;
default:
throw new webcrypto_core_1.WebCryptoError(`ImportKey: Wrong format value '${format}'`);
}
})
.then((key) => {
alg.modulusLength = key.modulusLength() << 3;
alg.publicExponent = new Uint8Array(key.publicExponent());
return new key_1.CryptoKey(key, alg, keyType ? "private" : "public", extractable, keyUsages);
});
}
static exportKey(format, key) {
return new Promise((resolve, reject) => {
const nativeKey = key.native;
const type = key.type === "public" ? native.KeyType.PUBLIC : native.KeyType.PRIVATE;
switch (format.toLocaleLowerCase()) {
case "jwk":
nativeKey.exportJwk(type, (err, data) => {
try {
const jwk = { kty: "RSA" };
jwk.key_ops = key.usages;
jwk.e = webcrypto_core_1.Base64Url.encode(data.e);
jwk.n = webcrypto_core_1.Base64Url.encode(data.n);
if (key.type === "private") {
jwk.d = webcrypto_core_1.Base64Url.encode(data.d);
jwk.p = webcrypto_core_1.Base64Url.encode(data.p);
jwk.q = webcrypto_core_1.Base64Url.encode(data.q);
jwk.dp = webcrypto_core_1.Base64Url.encode(data.dp);
jwk.dq = webcrypto_core_1.Base64Url.encode(data.dq);
jwk.qi = webcrypto_core_1.Base64Url.encode(data.qi);
}
resolve(jwk);
}
catch (e) {
reject(e);
}
});
break;
case "spki":
nativeKey.exportSpki((err, raw) => {
if (err) {
reject(err);
}
else {
resolve(raw.buffer);
}
});
break;
case "pkcs8":
nativeKey.exportPkcs8((err, raw) => {
if (err) {
reject(err);
}
else {
resolve(raw.buffer);
}
});
break;
default:
throw new webcrypto_core_1.WebCryptoError(`ExportKey: Unknown export format '${format}'`);
}
});
}
static wc2ssl(algorithm) {
const alg = algorithm.hash.name.toUpperCase().replace("-", "");
return alg;
}
}
exports.RsaCrypto = RsaCrypto;
class RsaPKCS1 extends RsaCrypto {
static exportKey(format, key) {
return super.exportKey(format, key)
.then((jwk) => {
if (format === "jwk") {
const reg = /(\d+)$/;
jwk.alg = "RS" + reg.exec(key.algorithm.hash.name)[1];
jwk.ext = true;
if (key.type === "public") {
jwk.key_ops = ["verify"];
}
}
return jwk;
});
}
static sign(algorithm, key, data) {
return new Promise((resolve, reject) => {
const alg = this.wc2ssl(key.algorithm);
const nativeKey = key.native;
nativeKey.sign(alg, data, (err, signature) => {
if (err) {
reject(new webcrypto_core_1.WebCryptoError("NativeError: " + err.message));
}
else {
resolve(signature.buffer);
}
});
});
}
static verify(algorithm, key, signature, data) {
return new Promise((resolve, reject) => {
const alg = this.wc2ssl(key.algorithm);
const nativeKey = key.native;
nativeKey.verify(alg, data, signature, (err, res) => {
if (err) {
reject(new webcrypto_core_1.WebCryptoError("NativeError: " + err.message));
}
else {
resolve(res);
}
});
});
}
}
exports.RsaPKCS1 = RsaPKCS1;
class RsaPSS extends RsaCrypto {
static sign(algorithm, key, data) {
return new Promise((resolve, reject) => {
const alg = this.wc2ssl(key.algorithm);
const nativeKey = key.native;
nativeKey.RsaPssSign(alg, algorithm.saltLength, data, (err, signature) => {
if (err) {
reject(new webcrypto_core_1.WebCryptoError("NativeError: " + err.message));
}
else {
resolve(signature.buffer);
}
});
});
}
static verify(algorithm, key, signature, data) {
return new Promise((resolve, reject) => {
const alg = this.wc2ssl(key.algorithm);
const nativeKey = key.native;
nativeKey.RsaPssVerify(alg, algorithm.saltLength, data, signature, (err, res) => {
if (err) {
reject(new webcrypto_core_1.WebCryptoError("NativeError: " + err.message));
}
else {
resolve(res);
}
});
});
}
static exportKey(format, key) {
return super.exportKey(format, key)
.then((jwk) => {
if (format === "jwk") {
const reg = /(\d+)$/;
jwk.alg = "PS" + reg.exec(key.algorithm.hash.name)[1];
jwk.ext = true;
if (key.type === "public") {
jwk.key_ops = ["verify"];
}
}
return jwk;
});
}
}
exports.RsaPSS = RsaPSS;
class RsaOAEP extends RsaCrypto {
static exportKey(format, key) {
return super.exportKey(format, key)
.then((jwk) => {
if (format === "jwk") {
jwk.alg = "RSA-OAEP";
const mdSize = /(\d+)$/.exec(key.algorithm.hash.name)[1];
if (mdSize !== "1") {
jwk.alg += "-" + mdSize;
}
jwk.ext = true;
if (key.type === "public") {
jwk.key_ops = ["encrypt", "wrapKey"];
}
else {
jwk.key_ops = ["decrypt", "unwrapKey"];
}
}
return jwk;
});
}
static encrypt(algorithm, key, data) {
return this.EncryptDecrypt(algorithm, key, data, false);
}
static decrypt(algorithm, key, data) {
return this.EncryptDecrypt(algorithm, key, data, true);
}
static EncryptDecrypt(algorithm, key, data, type) {
return new Promise((resolve, reject) => {
const alg = this.wc2ssl(key.algorithm);
const nativeKey = key.native;
let label = null;
if (algorithm.label) {
label = Buffer.from(algorithm.label);
}
nativeKey.RsaOaepEncDec(alg, data, label, type, (err, res) => {
if (err) {
reject(new webcrypto_core_1.WebCryptoError("NativeError: " + err));
}
else {
resolve(res.buffer);
}
});
});
}
}
exports.RsaOAEP = RsaOAEP;