From ebb6fe309473de33a6a7706a38f04bb60b97a7bb Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Fri, 15 Nov 2024 16:49:11 -0800 Subject: [PATCH 1/8] [Deps] update `cipher-base`, `inherits`, `md5-js`, `ripemd160`, `sha.js` --- package.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 6fa087c..18e4f2f 100644 --- a/package.json +++ b/package.json @@ -25,13 +25,14 @@ }, "homepage": "https://github.com/crypto-browserify/createHash", "dependencies": { - "cipher-base": "^1.0.1", + "cipher-base": "^1.0.4", "hash-base": "=3.0.3", - "inherits": "^2.0.1", + "inherits": "^2.0.4", + "md5-js": "^0.0.3", "md5.js": "^1.3.4", "readable-stream": "^2.3.8", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" + "ripemd160": "^2.0.2", + "sha.js": "^2.4.11" }, "devDependencies": { "@ljharb/eslint-config": "^21.1.1", From abf9b2957cc6a6ebc510fc5a0c3edf4c3042bfc6 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Fri, 15 Nov 2024 16:59:27 -0800 Subject: [PATCH 2/8] [Deps] remove mistakenly added dep --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 18e4f2f..bdc270f 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "cipher-base": "^1.0.4", "hash-base": "=3.0.3", "inherits": "^2.0.4", - "md5-js": "^0.0.3", "md5.js": "^1.3.4", "readable-stream": "^2.3.8", "ripemd160": "^2.0.2", From 53fa3fa277070eef0e326e9e153e932f40980d71 Mon Sep 17 00:00:00 2001 From: Nikita Skovoroda Date: Fri, 15 Nov 2024 23:45:26 +0400 Subject: [PATCH 3/8] [New] add a new noble-based implementation in modern browsers --- .eslintrc | 9 ++++- browser.js | 40 +++++----------------- browser.noble.js | 64 +++++++++++++++++++++++++++++++++++ browser.old.js | 35 ++++++++++++++++++++ package.json | 5 ++- test/index.js | 86 +++++++++++++++++++++++++++++++++++------------- 6 files changed, 182 insertions(+), 57 deletions(-) create mode 100644 browser.noble.js create mode 100644 browser.old.js diff --git a/.eslintrc b/.eslintrc index 19181f2..4f29db2 100644 --- a/.eslintrc +++ b/.eslintrc @@ -8,12 +8,19 @@ }, "overrides": [ + { + "files": "browser.js", + "rules": { + "global-require": "off", + }, + }, { "files": [ - "browser.js", + "browser.*.js", ], "rules": { "no-underscore-dangle": "warn", + "sort-keys": "off", }, }, ], diff --git a/browser.js b/browser.js index d8f9cbf..71ebe5a 100644 --- a/browser.js +++ b/browser.js @@ -1,35 +1,11 @@ 'use strict'; -var inherits = require('inherits'); -var MD5 = require('md5.js'); -var RIPEMD160 = require('ripemd160'); -var sha = require('sha.js'); -var Base = require('cipher-base'); - -function Hash(hash) { - Base.call(this, 'digest'); - - this._hash = hash; -} - -inherits(Hash, Base); - -Hash.prototype._update = function (data) { - this._hash.update(data); -}; - -Hash.prototype._final = function () { - return this._hash.digest(); -}; - -module.exports = function createHash(algorithm) { - var alg = algorithm.toLowerCase(); - if (alg === 'md5') { - return new MD5(); - } - if (alg === 'rmd160' || alg === 'ripemd160') { - return new RIPEMD160(); +if (typeof BigInt === 'undefined') { + module.exports = require('./browser.old.js'); +} else { + try { + module.exports = require('./browser.noble.js'); + } catch (err) { + module.exports = require('./browser.old.js'); } - - return new Hash(sha(alg)); -}; +} diff --git a/browser.noble.js b/browser.noble.js new file mode 100644 index 0000000..2032499 --- /dev/null +++ b/browser.noble.js @@ -0,0 +1,64 @@ +'use strict'; + +var sha1 = require('@noble/hashes/sha1'); +var ripemd160 = require('@noble/hashes/ripemd160'); +var sha2 = require('@noble/hashes/sha2'); +var sha3 = require('@noble/hashes/sha3'); +var blake2b = require('@noble/hashes/blake2b'); +var blake2s = require('@noble/hashes/blake2s'); +var inherits = require('inherits'); +var MD5 = require('md5.js'); +var Base = require('cipher-base'); +var Buffer = require('safe-buffer').Buffer; + +function Hash(hash) { + Base.call(this, 'digest'); + + this._hash = hash; +} + +inherits(Hash, Base); + +Hash.prototype._update = function (data) { + this._hash.update(data); +}; + +Hash.prototype._final = function () { + var uarr = this._hash.digest(); + return Buffer.from(uarr.buffer, uarr.byteOffset, uarr.byteLength); +}; + +var hashes = { + // Supported by browser.old.js + sha1: sha1.sha1, + sha224: sha2.sha224, + sha256: sha2.sha256, + sha384: sha2.sha384, + sha512: sha2.sha512, + ripemd160: ripemd160.ripemd160, + rmd160: ripemd160.ripemd160, + + // Not supported by browser.old.js (until sha.js updates?) + 'sha512-224': sha2.sha512_224, // for browser.old.js: https://github.com/browserify/sha.js/pull/67 + 'sha512-256': sha2.sha512_256, // for browser.old.js: https://github.com/browserify/sha.js/pull/67 + 'sha3-224': sha3.sha3_224, + 'sha3-256': sha3.sha3_256, + 'sha3-384': sha3.sha3_384, + 'sha3-512': sha3.sha3_512, + blake2b512: blake2b.blake2b, // 512 is the default size + blake2s256: blake2s.blake2s // 256 is the default size +}; + +module.exports = function createHash(algorithm) { + var alg = algorithm.toLowerCase(); + + if (alg === 'md5') { + return new MD5(); + } + + if (!Object.prototype.hasOwnProperty.call(hashes, alg)) { + throw new Error('Digest method not supported'); + } + + return new Hash(hashes[alg].create()); +}; diff --git a/browser.old.js b/browser.old.js new file mode 100644 index 0000000..d8f9cbf --- /dev/null +++ b/browser.old.js @@ -0,0 +1,35 @@ +'use strict'; + +var inherits = require('inherits'); +var MD5 = require('md5.js'); +var RIPEMD160 = require('ripemd160'); +var sha = require('sha.js'); +var Base = require('cipher-base'); + +function Hash(hash) { + Base.call(this, 'digest'); + + this._hash = hash; +} + +inherits(Hash, Base); + +Hash.prototype._update = function (data) { + this._hash.update(data); +}; + +Hash.prototype._final = function () { + return this._hash.digest(); +}; + +module.exports = function createHash(algorithm) { + var alg = algorithm.toLowerCase(); + if (alg === 'md5') { + return new MD5(); + } + if (alg === 'rmd160' || alg === 'ripemd160') { + return new RIPEMD160(); + } + + return new Hash(sha(alg)); +}; diff --git a/package.json b/package.json index bdc270f..8acf100 100644 --- a/package.json +++ b/package.json @@ -31,13 +31,16 @@ "md5.js": "^1.3.4", "readable-stream": "^2.3.8", "ripemd160": "^2.0.2", + "safe-buffer": "^5.0.1", "sha.js": "^2.4.11" }, + "optionalDependencies": { + "@noble/hashes": "^1.3.3" + }, "devDependencies": { "@ljharb/eslint-config": "^21.1.1", "eslint": "=8.8.0", "hash-test-vectors": "^1.3.2", - "safe-buffer": "^5.2.1", "tape": "^5.9.0" }, "engines": { diff --git a/test/index.js b/test/index.js index dacff62..2eec2ca 100644 --- a/test/index.js +++ b/test/index.js @@ -10,35 +10,75 @@ vectors.forEach(function (vector) { // eslint-disable-next-line no-param-reassign vector.ripemd160 = vector.rmd160; }); -var createHash = require('../browser'); - -algorithms.forEach(function (algorithm) { - test('test ' + algorithm + ' against test vectors', function (t) { - vectors.forEach(function (obj, i) { - var input = Buffer.from(obj.input, 'base64'); - var node = obj[algorithm]; - var js = createHash(algorithm).update(input).digest('hex'); - t.equal(js, node, algorithm + '(testVector[' + i + ']) == ' + node); - }); +var createHashOld = require('../browser.old.js'); +var createHashAuto = require('../browser.js'); + +var implementations = [createHashOld]; +if (createHashAuto !== createHashOld) { implementations.push(createHashAuto); } - encodings.forEach(function (encoding) { +implementations.forEach(function (createHash) { + algorithms.forEach(function (algorithm) { + test('test ' + algorithm + ' against test vectors', function (t) { vectors.forEach(function (obj, i) { - var input = Buffer.from(obj.input, 'base64').toString(encoding); + var input = Buffer.from(obj.input, 'base64'); var node = obj[algorithm]; - var js = createHash(algorithm).update(input, encoding).digest('hex'); - t.equal(js, node, algorithm + '(testVector[' + i + '], ' + encoding + ') == ' + node); + var js = createHash(algorithm).update(input).digest('hex'); + t.equal(js, node, algorithm + '(testVector[' + i + ']) == ' + node); + }); + + encodings.forEach(function (encoding) { + vectors.forEach(function (obj, i) { + var input = Buffer.from(obj.input, 'base64').toString(encoding); + var node = obj[algorithm]; + var js = createHash(algorithm).update(input, encoding).digest('hex'); + t.equal(js, node, algorithm + '(testVector[' + i + '], ' + encoding + ') == ' + node); + }); + }); + + vectors.forEach(function (obj, i) { + var input = Buffer.from(obj.input, 'base64'); + var node = obj[algorithm]; + var hash = createHash(algorithm); + hash.end(input); + var js = hash.read().toString('hex'); + t.equal(js, node, algorithm + '(testVector[' + i + ']) == ' + node); }); - }); - vectors.forEach(function (obj, i) { - var input = Buffer.from(obj.input, 'base64'); - var node = obj[algorithm]; - var hash = createHash(algorithm); - hash.end(input); - var js = hash.read().toString('hex'); - t.equal(js, node, algorithm + '(testVector[' + i + ']) == ' + node); + t.end(); }); + }); +}); +var createHashNode = require('crypto').createHash; +var randomBytes = require('crypto').randomBytes; + +function crossTest(createHashTest, createHashBase, algs) { + var data = randomBytes(32); + test('test against base implementation', function (t) { + algs.forEach(function (algorithm) { + var a = createHashTest(algorithm).update(data).digest('hex'); + var b; + try { + b = createHashBase(algorithm).update(data).digest('hex'); + } catch (err) {} + var label = algorithm + '(' + data.toString('hex') + ')'; + if (b) { + t.equal(a, b, label); + } else { + t.skip(label); // Node.js version doesn't support it + } + }); t.end(); }); -}); +} + +var baseHashes = ['sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'ripemd160', 'rmd160']; +var extraHashes = ['sha512-224', 'sha512-256', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512', 'blake2b512', 'blake2s256']; + +crossTest(createHashOld, createHashNode, baseHashes); + +// Only new version supports additional hashes +if (createHashAuto !== createHashOld) { + crossTest(createHashAuto, createHashNode, baseHashes); + crossTest(createHashAuto, createHashNode, extraHashes); +} From 7cfa0dac090b278129a6d4614114fe93c638f35e Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Sat, 16 Nov 2024 13:52:44 -0800 Subject: [PATCH 4/8] [Deps] update `md5.js`, `safe-buffer` --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8acf100..7b3b756 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,10 @@ "cipher-base": "^1.0.4", "hash-base": "=3.0.3", "inherits": "^2.0.4", - "md5.js": "^1.3.4", + "md5.js": "^1.3.5", "readable-stream": "^2.3.8", "ripemd160": "^2.0.2", - "safe-buffer": "^5.0.1", + "safe-buffer": "^5.2.1", "sha.js": "^2.4.11" }, "optionalDependencies": { From 597be5a8e7f6b409407ac55bd23abada27dc2063 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Sat, 16 Nov 2024 13:55:22 -0800 Subject: [PATCH 5/8] [meta] use `npmignore` --- .gitignore | 2 ++ package.json | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index d029b6e..34aaa91 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ node_modules npm-shrinkwrap.json package-lock.json yarn.lock + +.npmignore diff --git a/package.json b/package.json index 7b3b756..8bfdaf8 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "browser": "browser.js", "main": "index.js", "scripts": { + "prepack": "npmignore --auto --commentLines=autogenerated", "lint": "eslint --ext=js,mjs .", "pretest": "npm run lint", "test": "npm run tests-only", @@ -41,8 +42,14 @@ "@ljharb/eslint-config": "^21.1.1", "eslint": "=8.8.0", "hash-test-vectors": "^1.3.2", + "npmignore": "^0.3.1", "tape": "^5.9.0" }, + "publishConfig": { + "ignore": [ + ".github/workflows" + ] + }, "engines": { "node": ">= 0.8" } From 0bc497d7719852b6559721fbd6f6429f92f090fe Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Sat, 16 Nov 2024 13:55:35 -0800 Subject: [PATCH 6/8] [meta] fix package.json indentation --- package.json | 108 +++++++++++++++++++++++++-------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/package.json b/package.json index 8bfdaf8..a5ae04c 100644 --- a/package.json +++ b/package.json @@ -1,56 +1,56 @@ { - "name": "create-hash", - "version": "1.2.0", - "description": "create hashes for browserify", - "browser": "browser.js", - "main": "index.js", - "scripts": { - "prepack": "npmignore --auto --commentLines=autogenerated", - "lint": "eslint --ext=js,mjs .", - "pretest": "npm run lint", - "test": "npm run tests-only", - "tests-only": "tape 'test/**/*.js'", - "posttest": "npx npm@'>=10.2' audit --production" - }, - "repository": { - "type": "git", - "url": "git@github.com:crypto-browserify/createHash.git" - }, - "keywords": [ - "crypto" - ], - "author": "", - "license": "MIT", - "bugs": { - "url": "https://github.com/crypto-browserify/createHash/issues" - }, - "homepage": "https://github.com/crypto-browserify/createHash", - "dependencies": { - "cipher-base": "^1.0.4", - "hash-base": "=3.0.3", - "inherits": "^2.0.4", - "md5.js": "^1.3.5", - "readable-stream": "^2.3.8", - "ripemd160": "^2.0.2", - "safe-buffer": "^5.2.1", - "sha.js": "^2.4.11" - }, - "optionalDependencies": { - "@noble/hashes": "^1.3.3" - }, - "devDependencies": { - "@ljharb/eslint-config": "^21.1.1", - "eslint": "=8.8.0", - "hash-test-vectors": "^1.3.2", - "npmignore": "^0.3.1", - "tape": "^5.9.0" - }, - "publishConfig": { - "ignore": [ - ".github/workflows" - ] - }, - "engines": { - "node": ">= 0.8" - } + "name": "create-hash", + "version": "1.2.0", + "description": "create hashes for browserify", + "browser": "browser.js", + "main": "index.js", + "scripts": { + "prepack": "npmignore --auto --commentLines=autogenerated", + "lint": "eslint --ext=js,mjs .", + "pretest": "npm run lint", + "test": "npm run tests-only", + "tests-only": "tape 'test/**/*.js'", + "posttest": "npx npm@'>=10.2' audit --production" + }, + "repository": { + "type": "git", + "url": "git@github.com:crypto-browserify/createHash.git" + }, + "keywords": [ + "crypto" + ], + "author": "", + "license": "MIT", + "bugs": { + "url": "https://github.com/crypto-browserify/createHash/issues" + }, + "homepage": "https://github.com/crypto-browserify/createHash", + "dependencies": { + "cipher-base": "^1.0.4", + "hash-base": "=3.0.3", + "inherits": "^2.0.4", + "md5.js": "^1.3.5", + "readable-stream": "^2.3.8", + "ripemd160": "^2.0.2", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.11" + }, + "optionalDependencies": { + "@noble/hashes": "^1.3.3" + }, + "devDependencies": { + "@ljharb/eslint-config": "^21.1.1", + "eslint": "=8.8.0", + "hash-test-vectors": "^1.3.2", + "npmignore": "^0.3.1", + "tape": "^5.9.0" + }, + "publishConfig": { + "ignore": [ + ".github/workflows" + ] + }, + "engines": { + "node": ">= 0.8" + } } From 71e450aa6448dff870e941c46768d09a83f5b31b Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Sat, 16 Nov 2024 13:56:07 -0800 Subject: [PATCH 7/8] [meta] add `SECURITY.md` --- SECURITY.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..82e4285 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,3 @@ +# Security + +Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report. From ab58e51c49e3fa283a4a88d6d3bdd3ce98f56518 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Tue, 24 Feb 2026 16:55:24 -0800 Subject: [PATCH 8/8] [meta] remove `SECURITY.md` in favor of org-level policy --- SECURITY.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 82e4285..0000000 --- a/SECURITY.md +++ /dev/null @@ -1,3 +0,0 @@ -# Security - -Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report.