@synet/keys
Version:
Zero-dependency, secure key generation library. Supports ed25519, x25519, secp256k1, RSA, and WireGuard keys.
223 lines (222 loc) • 7.31 kB
JavaScript
"use strict";
/**
* Cryptographic verification functions
* Pure functions for signature verification across different algorithms
*
* These functions are designed to be:
* - Pure (no side effects)
* - Testable in isolation
* - Reusable across different units
* - Well-validated with proper error handling
*
* @author Synet Team
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.isValidBase64 = isValidBase64;
exports.isValidBase64Url = isValidBase64Url;
exports.normalizeSignature = normalizeSignature;
exports.verifyEd25519 = verifyEd25519;
exports.verifyRSA = verifyRSA;
exports.verifySecp256k1 = verifySecp256k1;
exports.verifySignature = verifySignature;
const crypto = __importStar(require("node:crypto"));
const utils_1 = require("./utils");
/**
* Validate base64 format
* Ensures the signature is properly formatted base64 before crypto operations
*/
function isValidBase64(str) {
try {
// Empty strings are not valid base64
if (!str || str === '') {
return false;
}
// Check if string contains only valid base64 characters
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
if (!base64Regex.test(str)) {
return false;
}
// Check if the decoded and re-encoded string matches the original
const decoded = Buffer.from(str, 'base64');
const reencoded = decoded.toString('base64');
return reencoded === str;
}
catch {
return false;
}
}
/**
* Validate base64url format
* Ensures the signature is properly formatted base64url before crypto operations
*/
function isValidBase64Url(str) {
try {
// Empty strings are not valid base64url
if (!str || str === '') {
return false;
}
// Check if string contains only valid base64url characters
const base64UrlRegex = /^[A-Za-z0-9_-]*$/;
if (!base64UrlRegex.test(str)) {
return false;
}
// Try to convert to base64 and validate
const base64 = (0, utils_1.base64UrlToBase64)(str);
return isValidBase64(base64);
}
catch {
return false;
}
}
/**
* Normalize signature to base64 format for crypto operations
* Accepts both base64 and base64url formats
*/
function normalizeSignature(signature) {
// Check if it's already valid base64
if (isValidBase64(signature)) {
return signature;
}
// Check if it's base64url and convert
if (isValidBase64Url(signature)) {
return (0, utils_1.base64UrlToBase64)(signature);
}
return null;
}
/**
* Verify Ed25519 signature
* @param data The original data that was signed
* @param signature The signature in base64 or base64url format
* @param publicKey The public key in PEM format
* @returns true if signature is valid, false otherwise
*/
function verifyEd25519(data, signature, publicKey) {
try {
// Validate inputs
if (!data || !signature || !publicKey) {
return false;
}
// Normalize signature to base64 format
const normalizedSignature = normalizeSignature(signature);
if (!normalizedSignature) {
return false;
}
return crypto.verify(null, Buffer.from(data), {
key: publicKey,
format: 'pem',
}, Buffer.from(normalizedSignature, 'base64'));
}
catch {
return false;
}
}
/**
* Verify RSA signature
* @param data The original data that was signed
* @param signature The signature in base64 or base64url format
* @param publicKey The public key in PEM format
* @returns true if signature is valid, false otherwise
*/
function verifyRSA(data, signature, publicKey) {
try {
// Validate inputs
if (!data || !signature || !publicKey) {
return false;
}
// Normalize signature to base64 format
const normalizedSignature = normalizeSignature(signature);
if (!normalizedSignature) {
return false;
}
const verify = crypto.createVerify('SHA256');
verify.update(data);
verify.end();
return verify.verify(publicKey, normalizedSignature, 'base64');
}
catch {
return false;
}
}
/**
* Verify secp256k1 signature
* @param data The original data that was signed
* @param signature The signature in base64 or base64url format
* @param publicKey The public key in PEM format
* @returns true if signature is valid, false otherwise
*/
function verifySecp256k1(data, signature, publicKey) {
try {
// Validate inputs
if (!data || !signature || !publicKey) {
return false;
}
// Normalize signature to base64 format
const normalizedSignature = normalizeSignature(signature);
if (!normalizedSignature) {
return false;
}
const verify = crypto.createVerify('SHA256');
verify.update(data);
verify.end();
return verify.verify(publicKey, normalizedSignature, 'base64');
}
catch {
return false;
}
}
/**
* Generic verification function that dispatches to specific algorithms
* @param data The original data that was signed
* @param signature The signature in base64 or base64url format
* @param publicKey The public key in PEM format
* @param keyType The key type/algorithm
* @returns true if signature is valid, false otherwise
*/
function verifySignature(data, signature, publicKey, keyType) {
switch (keyType) {
case 'ed25519':
return verifyEd25519(data, signature, publicKey);
case 'rsa':
return verifyRSA(data, signature, publicKey);
case 'secp256k1':
return verifySecp256k1(data, signature, publicKey);
case 'x25519':
case 'wireguard':
return false; // These are not for signing
default:
return false;
}
}