@isomorphic-pgp/sign-and-verify
Version:
Create and verify OpenPGP signatures
53 lines (41 loc) • 2.22 kB
JavaScript
const { BigInteger } = require("jsbn");
const { hashes } = require("./hashes.js");
const arrayBufferToHex = require("array-buffer-to-hex");
const { encode } = require("isomorphic-textencoder");
const Message = require("@isomorphic-pgp/parser/Message.js");
const UrlSafeBase64 = require("@isomorphic-pgp/parser/UrlSafeBase64.js");
const EMSA = require("@isomorphic-pgp/parser/emsa.js");
const { HashAlgorithm } = require("@isomorphic-pgp/parser/constants.js");
const { payloadSignatureHashData } = require("@isomorphic-pgp/parser/payloadSignatureHashData.js");
const { trimZeros } = require("@isomorphic-pgp/util/trimZeros.js");
module.exports.verify = async function verify(openpgpPublicKey, openpgpSignature, payload) {
let parsedPublicKey = Message.parse(openpgpPublicKey);
let publicKeyPacket = parsedPublicKey.packets[0].packet;
let userIdPacket = parsedPublicKey.packets[1].packet;
let selfSignaturePacket = parsedPublicKey.packets[2].packet;
let n = UrlSafeBase64.serialize(publicKeyPacket.mpi.n);
let e = UrlSafeBase64.serialize(publicKeyPacket.mpi.e);
let parsedSignature = Message.parse(openpgpSignature);
let signaturePacket = parsedSignature.packets[0].packet;
let signature = UrlSafeBase64.serialize(signaturePacket.mpi.signature);
const hashType = HashAlgorithm[signaturePacket.hash]
payload = typeof payload === "string" ? encode(payload) : payload;
let buffer = await payloadSignatureHashData(payload, signaturePacket);
let hash = await hashes[hashType](buffer, { outputFormat: "buffer" });
hash = new Uint8Array(hash);
let left16 = (hash[0] << 8) + hash[1];
if (left16 !== signaturePacket.left16) {
throw new Error("Signature failed left16 hash check");
}
// Wrap `hash` in the dumbass EMSA-PKCS1-v1_5 padded message format:
hash = EMSA.encode(hashType, hash, n.byteLength);
let S = new BigInteger(arrayBufferToHex(signature), 16);
let N = new BigInteger(arrayBufferToHex(n), 16);
let E = new BigInteger(arrayBufferToHex(e), 16);
let M = S.modPow(E, N);
let _hashbytes = M.toByteArray();
let _hash = new Uint8Array(_hashbytes);
_hash = trimZeros(_hash);
let valid = hash.every((byte, index) => byte === _hash[index]);
return valid;
}