mirror of
https://github.com/kmc7468/arkvault.git
synced 2026-11-04 08:10:28 +09:00
69 lines
2.1 KiB
TypeScript
69 lines
2.1 KiB
TypeScript
import {
|
|
constants,
|
|
randomBytes,
|
|
createPublicKey,
|
|
publicEncrypt,
|
|
verify,
|
|
createHmac,
|
|
timingSafeEqual,
|
|
} from "crypto";
|
|
import { promisify } from "util";
|
|
|
|
const makePubKeyToPem = (pubKey: string) =>
|
|
`-----BEGIN PUBLIC KEY-----\n${pubKey}\n-----END PUBLIC KEY-----`;
|
|
|
|
export const verifyPubKey = (pubKey: string) => {
|
|
const pubKeyPem = makePubKeyToPem(pubKey);
|
|
const pubKeyObject = createPublicKey(pubKeyPem);
|
|
return (
|
|
pubKeyObject.asymmetricKeyType === "rsa" &&
|
|
pubKeyObject.asymmetricKeyDetails?.modulusLength === 4096
|
|
);
|
|
};
|
|
|
|
export const encryptAsymmetric = (data: Buffer, encPubKey: string) => {
|
|
return publicEncrypt({ key: makePubKeyToPem(encPubKey), oaepHash: "sha256" }, data);
|
|
};
|
|
|
|
export const verifySignature = (data: Buffer, signature: string, sigPubKey: string) => {
|
|
return verify(
|
|
"rsa-sha256",
|
|
data,
|
|
{
|
|
key: makePubKeyToPem(sigPubKey),
|
|
padding: constants.RSA_PKCS1_PSS_PADDING,
|
|
},
|
|
Buffer.from(signature, "base64"),
|
|
);
|
|
};
|
|
|
|
export const generateChallenge = async (length: number, encPubKey: string) => {
|
|
const answer = await promisify(randomBytes)(length);
|
|
const challenge = encryptAsymmetric(answer, encPubKey);
|
|
return { answer, challenge };
|
|
};
|
|
|
|
export const issueSessionId = async (length: number, secret: string) => {
|
|
const sessionId = await promisify(randomBytes)(length);
|
|
const sessionIdHex = sessionId.toString("hex");
|
|
const sessionIdHmac = createHmac("sha256", secret).update(sessionId).digest("hex");
|
|
return {
|
|
sessionId: sessionIdHex,
|
|
sessionIdSigned: `${sessionIdHex}.${sessionIdHmac}`,
|
|
};
|
|
};
|
|
|
|
export const verifySessionId = (sessionIdSigned: string, secret: string) => {
|
|
const [sessionIdHex, sessionIdHmac] = sessionIdSigned.split(".");
|
|
if (!sessionIdHex || !sessionIdHmac) return;
|
|
|
|
const actualHmac = Buffer.from(sessionIdHmac, "hex");
|
|
const expectedHmac = createHmac("sha256", secret)
|
|
.update(Buffer.from(sessionIdHex, "hex"))
|
|
.digest();
|
|
// `timingSafeEqual` throws if the lengths differ (e.g. malformed hex)
|
|
if (actualHmac.length === expectedHmac.length && timingSafeEqual(actualHmac, expectedHmac)) {
|
|
return sessionIdHex;
|
|
}
|
|
};
|