55 lines
1.7 KiB
JavaScript
55 lines
1.7 KiB
JavaScript
/**
|
|
* Node (brittle-node tests / `node index.js`): lazy `require('bare-crypto')` inside try/catch.
|
|
* `bare-crypto` is Bare-oriented and typically throws under Node; callers still get a boolean.
|
|
*/
|
|
|
|
import b4a from 'b4a'
|
|
import path from 'path'
|
|
import { createRequire } from 'node:module'
|
|
|
|
const require = createRequire(import.meta.url)
|
|
|
|
function loadEd25519PublicKeyCtor() {
|
|
const pkgJson = require.resolve('bare-crypto/package')
|
|
const keyModule = path.join(path.dirname(pkgJson), 'lib', 'key.js')
|
|
return require(keyModule).Ed25519PublicKey
|
|
}
|
|
|
|
/**
|
|
* @param {Uint8Array | null | undefined} manifestBytes
|
|
* @param {Uint8Array | null | undefined} signatureBytes
|
|
* @param {string} publicKeyHex 64 hex chars (32-byte Ed25519 public key)
|
|
* @returns {boolean}
|
|
*/
|
|
export function verifyBootManifestEd25519(manifestBytes, signatureBytes, publicKeyHex) {
|
|
if (!manifestBytes?.length || !signatureBytes?.length) return false
|
|
const hex = String(publicKeyHex || '').trim().toLowerCase().replace(/^0x/, '')
|
|
if (!/^[0-9a-f]{64}$/.test(hex)) return false
|
|
/** @type {Uint8Array} */
|
|
let sig
|
|
if (signatureBytes.length === 64) {
|
|
sig = signatureBytes
|
|
} else {
|
|
const t = b4a.toString(signatureBytes, 'utf8').trim()
|
|
if (/^[0-9a-f]{128}$/i.test(t)) {
|
|
sig = b4a.from(t, 'hex')
|
|
} else {
|
|
try {
|
|
sig = b4a.from(t, 'base64')
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
if (sig.length !== 64) return false
|
|
try {
|
|
const { verify } = require('bare-crypto')
|
|
const Ed25519PublicKey = loadEd25519PublicKeyCtor()
|
|
const pub = b4a.from(hex, 'hex')
|
|
const key = new Ed25519PublicKey(pub)
|
|
return verify('ed25519', manifestBytes, key, sig)
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|