Compare commits

...

2 Commits

Author SHA1 Message Date
nav
ccdf167daf feat: add crypto module (Ed25519 key generation, sign, verify)
Moves verifySignature, signMessage, generateKeyPair and utility functions
from Yonexus.Client into Protocol so Server no longer depends on Client
at build time or runtime.
2026-04-16 10:36:55 +00:00
h z
d2a16bcb02 Merge pull request 'dev/2026-04-08' (#1) from dev/2026-04-08 into main
Reviewed-on: #1
2026-04-13 09:33:41 +00:00
2 changed files with 50 additions and 0 deletions

49
src/crypto.ts Normal file
View File

@@ -0,0 +1,49 @@
import { randomBytes, generateKeyPair as _generateKeyPair, sign, verify } from "node:crypto";
export interface KeyPair {
readonly privateKey: string;
readonly publicKey: string;
readonly algorithm: "Ed25519";
}
export async function generateKeyPair(): Promise<KeyPair> {
const { publicKey, privateKey } = await new Promise<{ publicKey: string; privateKey: string }>((resolve, reject) => {
_generateKeyPair(
"ed25519",
{
publicKeyEncoding: { type: "spki", format: "pem" },
privateKeyEncoding: { type: "pkcs8", format: "pem" },
},
(err, pubKey, privKey) => (err ? reject(err) : resolve({ publicKey: pubKey, privateKey: privKey }))
);
});
return { privateKey, publicKey, algorithm: "Ed25519" };
}
export async function signMessage(privateKeyPem: string, message: Buffer | string): Promise<string> {
return sign(null, typeof message === "string" ? Buffer.from(message) : message, privateKeyPem).toString("base64");
}
export async function verifySignature(publicKeyPem: string, message: Buffer | string, signature: string): Promise<boolean> {
try {
return verify(null, typeof message === "string" ? Buffer.from(message) : message, publicKeyPem, Buffer.from(signature, "base64"));
} catch {
return false;
}
}
export function generatePairingCode(): string {
const bytes = randomBytes(8);
const chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
let code = "";
for (let i = 0; i < 12; i++) code += chars[bytes[i % bytes.length] % chars.length];
return `${code.slice(0, 4)}-${code.slice(4, 8)}-${code.slice(8, 12)}`;
}
export function generateSecret(): string {
return randomBytes(32).toString("base64url");
}
export function generateNonce(): string {
return randomBytes(18).toString("base64url").slice(0, 24);
}

View File

@@ -2,3 +2,4 @@ export * from "./types.js";
export * from "./codec.js"; export * from "./codec.js";
export * from "./errors.js"; export * from "./errors.js";
export * from "./auth.js"; export * from "./auth.js";
export * from "./crypto.js";