Versie 0.2.0

This commit is contained in:
Atreides Assets committed 2026-10-29 11:57:29 +01:00
commit e77d8fd373
495 files changed
+81026

No files matched your search

+74
View File
@@ -0,0 +1,74 @@
// Generated, do not edit. sha256:c9e44c618374bc6218029ec68095d9d8a62c6e5839ffe1dd3084b46600ccb118
import {
secp256k1, sha256, chacha20, hkdfExtract, hkdfExpand, hmac, base64,
hexToBytes, utf8ToBytes, concatBytes,
} from '../vendor/crypto/noble-scure.js';
const VERSION = 2;
const SALT = utf8ToBytes('nip44-v2');
const MIN = 1;
const MAX = 65535;
const asBytes = (x) => (typeof x === 'string' ? hexToBytes(x) : x);
export function conversationKey(secret, pubkey) {
const shared = secp256k1.getSharedSecret(asBytes(secret), concatBytes(Uint8Array.of(2), asBytes(pubkey)));
return hkdfExtract(sha256, shared.subarray(1, 33), SALT);
}
export function messageKeys(convKey, nonce) {
const keys = hkdfExpand(sha256, asBytes(convKey), asBytes(nonce), 76);
return { chachaKey: keys.subarray(0, 32), chachaNonce: keys.subarray(32, 44), hmacKey: keys.subarray(44, 76) };
}
export function paddedLength(len) {
if (len <= 32) return 32;
const next = 1 << (Math.floor(Math.log2(len - 1)) + 1);
const chunk = next <= 256 ? 32 : next / 8;
return chunk * (Math.floor((len - 1) / chunk) + 1);
}
function pad(text) {
const bytes = utf8ToBytes(text);
if (bytes.length < MIN || bytes.length > MAX) throw new Error(`A NIP-44 message is ${MIN} to ${MAX} bytes.`);
const out = new Uint8Array(2 + paddedLength(bytes.length));
out[0] = bytes.length >> 8;
out[1] = bytes.length & 0xff;
out.set(bytes, 2);
return out;
}
function unpad(padded) {
const len = (padded[0] << 8) | padded[1];
if (len < MIN || padded.length !== 2 + paddedLength(len)) throw new Error('Invalid padding.');
return new TextDecoder('utf-8', { fatal: true }).decode(padded.subarray(2, 2 + len));
}
function sameBytes(a, b) {
if (a.length !== b.length) return false;
let d = 0;
for (let i = 0; i < a.length; i++) d |= a[i] ^ b[i];
return d === 0;
}
export function encrypt(text, convKey, nonce = crypto.getRandomValues(new Uint8Array(32))) {
const n = asBytes(nonce);
const { chachaKey, chachaNonce, hmacKey } = messageKeys(convKey, n);
const ciphertext = chacha20(chachaKey, chachaNonce, pad(text));
const mac = hmac(sha256, hmacKey, concatBytes(n, ciphertext));
return base64.encode(concatBytes(Uint8Array.of(VERSION), n, ciphertext, mac));
}
export function decrypt(payload, convKey) {
const p = String(payload ?? '');
if (!p || p[0] === '#') throw new Error('Unknown NIP-44 version.');
if (p.length < 132 || p.length > 87472) throw new Error('Invalid NIP-44 payload length.');
const data = base64.decode(p);
if (data[0] !== VERSION) throw new Error(`Unknown NIP-44 version ${data[0]}.`);
const nonce = data.subarray(1, 33);
const ciphertext = data.subarray(33, data.length - 32);
const mac = data.subarray(data.length - 32);
const { chachaKey, chachaNonce, hmacKey } = messageKeys(convKey, nonce);
if (!sameBytes(mac, hmac(sha256, hmacKey, concatBytes(nonce, ciphertext)))) throw new Error('Invalid MAC.');
return unpad(chacha20(chachaKey, chachaNonce, ciphertext));
}