Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(node/crypto): add public-encrypt #1982

Merged
merged 14 commits into from
Mar 7, 2022
47 changes: 47 additions & 0 deletions node/_crypto/crypto_browserify/browserify_rsa.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2017 crypto-browserify. All rights reserved. MIT license.

import { BN } from "./bn.js/bn.js";
import { randomBytes } from "./randombytes.ts";
import { Buffer } from "../../buffer.ts";

function blind(priv) {
const r = getr(priv);
const blinder = r.toRed(BN.mont(priv.modulus)).redPow(
new BN(priv.publicExponent),
).fromRed();
return { blinder: blinder, unblinder: r.invm(priv.modulus) };
}

function getr(priv) {
const len = priv.modulus.byteLength();
let r;
do {
r = new BN(randomBytes(len));
} while (
r.cmp(priv.modulus) >= 0 || !r.umod(priv.prime1) || !r.umod(priv.prime2)
);
return r;
}

function crt(msg, priv) {
const blinds = blind(priv);
const len = priv.modulus.byteLength();
const blinded = new BN(msg).mul(blinds.blinder).umod(priv.modulus);
const c1 = blinded.toRed(BN.mont(priv.prime1));
const c2 = blinded.toRed(BN.mont(priv.prime2));
const qinv = priv.coefficient;
const p = priv.prime1;
const q = priv.prime2;
const m1 = c1.redPow(priv.exponent1).fromRed();
const m2 = c2.redPow(priv.exponent2).fromRed();
const h = m1.isub(m2).imul(qinv).umod(p).imul(q);
return m2.iadd(h).imul(blinds.unblinder).umod(priv.modulus).toArrayLike(
Buffer,
"be",
len,
);
}
crt.getr = getr;

export default crt;
25 changes: 25 additions & 0 deletions node/_crypto/crypto_browserify/browserify_rsa_test.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

117 changes: 117 additions & 0 deletions node/_crypto/crypto_browserify/parse_asn1/asn1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2017 crypto-browserify. All rights reserved. MIT license.
// from https://github.com/indutny/self-signed/blob/gh-pages/lib/asn1.js

import asn1 from "../asn1.js/mod.js";
import certificate from "./certificate.js";
export { certificate };

export const RSAPrivateKey = asn1.define("RSAPrivateKey", function () {
this.seq().obj(
this.key("version").int(),
this.key("modulus").int(),
this.key("publicExponent").int(),
this.key("privateExponent").int(),
this.key("prime1").int(),
this.key("prime2").int(),
this.key("exponent1").int(),
this.key("exponent2").int(),
this.key("coefficient").int(),
);
});

export const RSAPublicKey = asn1.define("RSAPublicKey", function () {
this.seq().obj(
this.key("modulus").int(),
this.key("publicExponent").int(),
);
});

export const PublicKey = asn1.define("SubjectPublicKeyInfo", function () {
this.seq().obj(
this.key("algorithm").use(AlgorithmIdentifier),
this.key("subjectPublicKey").bitstr(),
);
});

const AlgorithmIdentifier = asn1.define("AlgorithmIdentifier", function () {
this.seq().obj(
this.key("algorithm").objid(),
this.key("none").null_().optional(),
this.key("curve").objid().optional(),
this.key("params").seq().obj(
this.key("p").int(),
this.key("q").int(),
this.key("g").int(),
).optional(),
);
});

export const PrivateKey = asn1.define("PrivateKeyInfo", function () {
this.seq().obj(
this.key("version").int(),
this.key("algorithm").use(AlgorithmIdentifier),
this.key("subjectPrivateKey").octstr(),
);
});
export const EncryptedPrivateKey = asn1.define(
"EncryptedPrivateKeyInfo",
function () {
this.seq().obj(
this.key("algorithm").seq().obj(
this.key("id").objid(),
this.key("decrypt").seq().obj(
this.key("kde").seq().obj(
this.key("id").objid(),
this.key("kdeparams").seq().obj(
this.key("salt").octstr(),
this.key("iters").int(),
),
),
this.key("cipher").seq().obj(
this.key("algo").objid(),
this.key("iv").octstr(),
),
),
),
this.key("subjectPrivateKey").octstr(),
);
},
);

export const DSAPrivateKey = asn1.define("DSAPrivateKey", function () {
this.seq().obj(
this.key("version").int(),
this.key("p").int(),
this.key("q").int(),
this.key("g").int(),
this.key("pub_key").int(),
this.key("priv_key").int(),
);
});

export const DSAparam = asn1.define("DSAparam", function () {
this.int();
});

export const ECPrivateKey = asn1.define("ECPrivateKey", function () {
this.seq().obj(
this.key("version").int(),
this.key("privateKey").octstr(),
this.key("parameters").optional().explicit(0).use(ECParameters),
this.key("publicKey").optional().explicit(1).bitstr(),
);
});

const ECParameters = asn1.define("ECParameters", function () {
this.choice({
namedCurve: this.objid(),
});
});

export const signature = asn1.define("signature", function () {
this.seq().obj(
this.key("r").int(),
this.key("s").int(),
);
});
90 changes: 90 additions & 0 deletions node/_crypto/crypto_browserify/parse_asn1/certificate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2017 crypto-browserify. All rights reserved. MIT license.

import * as asn from "../asn1.js/mod.js";

const Time = asn.define("Time", function () {
this.choice({
utcTime: this.utctime(),
generalTime: this.gentime(),
});
});

const AttributeTypeValue = asn.define("AttributeTypeValue", function () {
this.seq().obj(
this.key("type").objid(),
this.key("value").any(),
);
});

const AlgorithmIdentifier = asn.define("AlgorithmIdentifier", function () {
this.seq().obj(
this.key("algorithm").objid(),
this.key("parameters").optional(),
this.key("curve").objid().optional(),
);
});

const SubjectPublicKeyInfo = asn.define("SubjectPublicKeyInfo", function () {
this.seq().obj(
this.key("algorithm").use(AlgorithmIdentifier),
this.key("subjectPublicKey").bitstr(),
);
});

const RelativeDistinguishedName = asn.define(
"RelativeDistinguishedName",
function () {
this.setof(AttributeTypeValue);
},
);

const RDNSequence = asn.define("RDNSequence", function () {
this.seqof(RelativeDistinguishedName);
});

const Name = asn.define("Name", function () {
this.choice({
rdnSequence: this.use(RDNSequence),
});
});

const Validity = asn.define("Validity", function () {
this.seq().obj(
this.key("notBefore").use(Time),
this.key("notAfter").use(Time),
);
});

const Extension = asn.define("Extension", function () {
this.seq().obj(
this.key("extnID").objid(),
this.key("critical").bool().def(false),
this.key("extnValue").octstr(),
);
});

const TBSCertificate = asn.define("TBSCertificate", function () {
this.seq().obj(
this.key("version").explicit(0).int().optional(),
this.key("serialNumber").int(),
this.key("signature").use(AlgorithmIdentifier),
this.key("issuer").use(Name),
this.key("validity").use(Validity),
this.key("subject").use(Name),
this.key("subjectPublicKeyInfo").use(SubjectPublicKeyInfo),
this.key("issuerUniqueID").implicit(1).bitstr().optional(),
this.key("subjectUniqueID").implicit(2).bitstr().optional(),
this.key("extensions").explicit(3).seqof(Extension).optional(),
);
});

export const X509Certificate = asn.define("X509Certificate", function () {
this.seq().obj(
this.key("tbsCertificate").use(TBSCertificate),
this.key("signatureAlgorithm").use(AlgorithmIdentifier),
this.key("signatureValue").bitstr(),
);
});

export default X509Certificate;
37 changes: 37 additions & 0 deletions node/_crypto/crypto_browserify/parse_asn1/fix_proc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2017 crypto-browserify. All rights reserved. MIT license.
// adapted from https://github.com/apatil/pemstrip

import evp from "../evp_bytes_to_key.ts";
import * as ciphers from "../browserify_aes/mod.js";
import { Buffer } from "../../../buffer.ts";

const findProc =
/Proc-Type: 4,ENCRYPTED[\n\r]+DEK-Info: AES-((?:128)|(?:192)|(?:256))-CBC,([0-9A-H]+)[\n\r]+([0-9A-z\n\r+/=]+)[\n\r]+/m;
const startRegex = /^-----BEGIN ((?:.*? KEY)|CERTIFICATE)-----/m;
const fullRegex =
/^-----BEGIN ((?:.*? KEY)|CERTIFICATE)-----([0-9A-z\n\r+/=]+)-----END \1-----$/m;
export default function (okey, password) {
const key = okey.toString();
const match = key.match(findProc);
let decrypted;
if (!match) {
const match2 = key.match(fullRegex);
decrypted = Buffer.from(match2[2].replace(/[\r\n]/g, ""), "base64");
} else {
const suite = "aes" + match[1];
const iv = Buffer.from(match[2], "hex");
const cipherText = Buffer.from(match[3].replace(/[\r\n]/g, ""), "base64");
const cipherKey = evp(password, iv.slice(0, 8), parseInt(match[1], 10)).key;
const out = [];
const cipher = ciphers.createDecipheriv(suite, cipherKey, iv);
out.push(cipher.update(cipherText));
out.push(cipher.final());
decrypted = Buffer.concat(out);
}
const tag = key.match(startRegex)[1];
return {
tag: tag,
data: decrypted,
};
}
Loading