fix(ext/sw): sshsig hashes the exact payload view; hoist TextEncoder

This commit is contained in:
adlee-was-taken
2026-06-25 23:40:16 -04:00
parent b3db292474
commit 273fe5cf30

View File

@@ -44,10 +44,10 @@ export async function buildSshSig(
rawSign: (data: Uint8Array) => Uint8Array | Promise<Uint8Array>,
): Promise<string> {
// Step 1: H = SHA-512(payload).
// SubtleCrypto requires a plain ArrayBuffer (not ArrayBufferLike) in TS 5.9+;
// callers always pass a freshly allocated Uint8Array so .buffer is the full buffer.
// slice(0) allocates a fresh backing buffer whose extent exactly matches the
// view bytes, making this correct even when `payload` is a subarray/offset view.
const H = new Uint8Array(
await crypto.subtle.digest('SHA-512', payload.buffer as ArrayBuffer),
await crypto.subtle.digest('SHA-512', payload.slice(0).buffer as ArrayBuffer),
);
// Step 2: signedBlob — "SSHSIG" (no length prefix) || str("git") || str("") || str("sha512") || str(H)
@@ -91,9 +91,12 @@ export async function buildSshSig(
/** Empty byte array (reused for str("") calls). */
const EMPTY = new Uint8Array(0);
/** Module-scope encoder — avoids allocating a new TextEncoder on every call. */
const ENC = new TextEncoder();
/** Encode a plain ASCII string as UTF-8 bytes (Relicario uses only ASCII names). */
function enc(s: string): Uint8Array {
return new TextEncoder().encode(s);
return ENC.encode(s);
}
/** 4-byte big-endian unsigned integer. */