fix: build hashes and recovery-phrase entropy come from ethers (closes #758)
build.js and script/lib/package.js hash with sha256 from ethers, with the 0x prefix stripped so the build receipt and SHA256SUMS keep bare lowercase hex. generateMnemonic() takes its 16 bytes of entropy from randomBytes in ethers. The README Crypto policy no longer lists these as exceptions. Model: opus-5-5
This commit is contained in:
1 parent
6d158bf1b1
commit
ded29b3a9c
5 files changed
+27
-18
No files matched your search
@@ -1647,11 +1647,10 @@ The development dependencies ship nowhere:
|
||||
|
||||
### Crypto policy
|
||||
|
||||
Hashing, key derivation, signing and encryption go through `ethers` or
|
||||
`libsodium-wrappers-sumo`. No primitive is implemented in this repository. A new
|
||||
recovery phrase draws its random bytes from the browser's
|
||||
`crypto.getRandomValues()`. The build tooling, `build.js` and `script/lib/`,
|
||||
hashes files with Node's `crypto`; none of it ships in the extension.
|
||||
In the extension, hashing, key derivation, signing and encryption go through
|
||||
`ethers` or `libsodium-wrappers-sumo`. A new recovery phrase takes its random
|
||||
bytes from `ethers`. `build.js` and `script/lib/package.js` also hash files with
|
||||
`ethers`. No primitive is implemented in this repository.
|
||||
|
||||
### Content Security Policy
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const crypto = require("crypto");
|
||||
const { execSync } = require("child_process");
|
||||
const esbuild = require("esbuild");
|
||||
const { sha256 } = require("ethers");
|
||||
const { resolveVersion } = require("./script/lib/version");
|
||||
const {
|
||||
BACKGROUND_ENTRY_PREFIX,
|
||||
@@ -314,10 +314,8 @@ function copyIcons(distDir) {
|
||||
}
|
||||
|
||||
function sha256File(absPath) {
|
||||
return crypto
|
||||
.createHash("sha256")
|
||||
.update(fs.readFileSync(absPath))
|
||||
.digest("hex");
|
||||
// ethers prefixes the hex with 0x; the receipt holds bare hex.
|
||||
return sha256(fs.readFileSync(absPath)).slice(2);
|
||||
}
|
||||
|
||||
// Write the receipt for the files this build emitted. Deliberately records no
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const crypto = require("crypto");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const ethers = require("ethers");
|
||||
|
||||
const { readZip, writeZip } = require("./zip");
|
||||
const { resolveVersion } = require("./version");
|
||||
@@ -60,8 +60,9 @@ function fail(message) {
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
// Lowercase hex without the 0x prefix ethers adds, as sha256sum prints it.
|
||||
function sha256(buf) {
|
||||
return crypto.createHash("sha256").update(buf).digest("hex");
|
||||
return ethers.sha256(buf).slice(2);
|
||||
}
|
||||
|
||||
// Every regular file under dir, as archive-root-relative forward-slashed
|
||||
@@ -291,4 +292,9 @@ if (require.main === module) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { checkSelfContained, htmlReferences, manifestReferences };
|
||||
module.exports = {
|
||||
checkSelfContained,
|
||||
htmlReferences,
|
||||
manifestReferences,
|
||||
sha256,
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
// Wallet operations: mnemonic generation, HD derivation, signing.
|
||||
// All crypto delegated to ethers.js.
|
||||
|
||||
const { Mnemonic, HDNodeWallet, Wallet } = require("ethers");
|
||||
const { Mnemonic, HDNodeWallet, Wallet, randomBytes } = require("ethers");
|
||||
const { DEBUG, DEBUG_MNEMONIC, BIP44_ETH_PATH } = require("./constants");
|
||||
|
||||
function generateMnemonic() {
|
||||
@@ -10,10 +10,7 @@ function generateMnemonic() {
|
||||
// settings toggle drives, which would let a user of a release build turn
|
||||
// the hardcoded, publicly known test phrase back on for real wallets.
|
||||
if (DEBUG) return DEBUG_MNEMONIC;
|
||||
const m = Mnemonic.fromEntropy(
|
||||
globalThis.crypto.getRandomValues(new Uint8Array(16)),
|
||||
);
|
||||
return m.phrase;
|
||||
return Mnemonic.fromEntropy(randomBytes(16)).phrase;
|
||||
}
|
||||
|
||||
// Every extended key (xprv or xpub) entering the app goes through this.
|
||||
|
||||
@@ -17,6 +17,7 @@ const {
|
||||
checkSelfContained,
|
||||
htmlReferences,
|
||||
manifestReferences,
|
||||
sha256,
|
||||
} = require("../script/lib/package");
|
||||
const { readZip, writeZip } = require("../script/lib/zip");
|
||||
|
||||
@@ -142,6 +143,14 @@ describe("archive self-containment", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// release/SHA256SUMS is checked with `sha256sum -c`, which needs the digest
|
||||
// as bare lowercase hex. The expected value is the FIPS 180-2 digest of "abc".
|
||||
test("sha256 prints the digest as sha256sum does", () => {
|
||||
expect(sha256(Buffer.from("abc"))).toBe(
|
||||
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
|
||||
);
|
||||
});
|
||||
|
||||
describe("the zip container", () => {
|
||||
const files = [
|
||||
{ name: "manifest.json", data: Buffer.from('{"a":1}') },
|
||||
|
||||
Reference in new issue
Block a user