├── .eslintrc ├── .github ├── FUNDING.yml └── workflows │ ├── node-aught.yml │ ├── node-pretest.yml │ ├── node-tens.yml │ ├── node-twenties.yml │ ├── rebase.yml │ └── require-allow-edits.yml ├── .gitignore ├── .npmrc ├── LICENSE ├── README.md ├── SECURITY.md ├── browser.js ├── browser.noble.js ├── browser.old.js ├── index.js ├── md5.js ├── package.json └── test └── index.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | 4 | "extends": "@ljharb", 5 | 6 | "rules": { 7 | "func-style": "off", 8 | }, 9 | 10 | "overrides": [ 11 | { 12 | "files": "browser.js", 13 | "rules": { 14 | "global-require": "off", 15 | }, 16 | }, 17 | { 18 | "files": [ 19 | "browser.*.js", 20 | ], 21 | "rules": { 22 | "no-underscore-dangle": "warn", 23 | "sort-keys": "off", 24 | }, 25 | }, 26 | ], 27 | } 28 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [ljharb] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: npm/create-hash 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/workflows/node-aught.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: node.js < 10' 2 | 3 | on: [pull_request, push] 4 | 5 | jobs: 6 | tests: 7 | uses: ljharb/actions/.github/workflows/node.yml@main 8 | with: 9 | range: '0.10 - 10' 10 | type: minors 11 | command: npm run tests-only 12 | -------------------------------------------------------------------------------- /.github/workflows/node-pretest.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: pretest/posttest' 2 | 3 | on: [pull_request, push] 4 | 5 | jobs: 6 | tests: 7 | uses: ljharb/actions/.github/workflows/pretest.yml@main 8 | -------------------------------------------------------------------------------- /.github/workflows/node-tens.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: node.js 10 - 20' 2 | 3 | on: [pull_request, push] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | tests: 10 | uses: ljharb/actions/.github/workflows/node.yml@main 11 | with: 12 | range: '>= 10 < 20' 13 | type: minors 14 | command: npm run tests-only 15 | -------------------------------------------------------------------------------- /.github/workflows/node-twenties.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: node.js >= 20' 2 | 3 | on: [pull_request, push] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | tests: 10 | uses: ljharb/actions/.github/workflows/node.yml@main 11 | with: 12 | range: '>= 20' 13 | type: minors 14 | command: npm run tests-only 15 | -------------------------------------------------------------------------------- /.github/workflows/rebase.yml: -------------------------------------------------------------------------------- 1 | name: Automatic Rebase 2 | 3 | on: [pull_request_target] 4 | 5 | jobs: 6 | _: 7 | uses: ljharb/actions/.github/workflows/rebase.yml@main 8 | secrets: 9 | token: ${{ secrets.GITHUB_TOKEN }} 10 | -------------------------------------------------------------------------------- /.github/workflows/require-allow-edits.yml: -------------------------------------------------------------------------------- 1 | name: Require “Allow Edits” 2 | 3 | on: [pull_request_target] 4 | 5 | jobs: 6 | _: 7 | name: "Require “Allow Edits”" 8 | 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: ljharb/require-allow-edits@main 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | # Only apps should have lockfiles 4 | npm-shrinkwrap.json 5 | package-lock.json 6 | yarn.lock 7 | 8 | .npmignore 9 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 crypto-browserify contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # create-hash 2 | 3 | [![Build Status](https://travis-ci.org/crypto-browserify/createHash.svg)](https://travis-ci.org/crypto-browserify/createHash) 4 | 5 | Node style hashes for use in the browser, with native hash functions in node. 6 | 7 | API is the same as hashes in node: 8 | ```js 9 | var createHash = require('create-hash') 10 | var hash = createHash('sha224') 11 | hash.update('synchronous write') // optional encoding parameter 12 | hash.digest() // synchronously get result with optional encoding parameter 13 | 14 | hash.write('write to it as a stream') 15 | hash.end() // remember it's a stream 16 | hash.read() // only if you ended it as a stream though 17 | ``` 18 | 19 | To get the JavaScript version even in node do `require('create-hash/browser')` 20 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report. 4 | -------------------------------------------------------------------------------- /browser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (typeof BigInt === 'undefined') { 4 | module.exports = require('./browser.old.js'); 5 | } else { 6 | try { 7 | module.exports = require('./browser.noble.js'); 8 | } catch (err) { 9 | module.exports = require('./browser.old.js'); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /browser.noble.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sha1 = require('@noble/hashes/sha1'); 4 | var ripemd160 = require('@noble/hashes/ripemd160'); 5 | var sha2 = require('@noble/hashes/sha2'); 6 | var sha3 = require('@noble/hashes/sha3'); 7 | var blake2b = require('@noble/hashes/blake2b'); 8 | var blake2s = require('@noble/hashes/blake2s'); 9 | var inherits = require('inherits'); 10 | var MD5 = require('md5.js'); 11 | var Base = require('cipher-base'); 12 | var Buffer = require('safe-buffer').Buffer; 13 | 14 | function Hash(hash) { 15 | Base.call(this, 'digest'); 16 | 17 | this._hash = hash; 18 | } 19 | 20 | inherits(Hash, Base); 21 | 22 | Hash.prototype._update = function (data) { 23 | this._hash.update(data); 24 | }; 25 | 26 | Hash.prototype._final = function () { 27 | var uarr = this._hash.digest(); 28 | return Buffer.from(uarr.buffer, uarr.byteOffset, uarr.byteLength); 29 | }; 30 | 31 | var hashes = { 32 | // Supported by browser.old.js 33 | sha1: sha1.sha1, 34 | sha224: sha2.sha224, 35 | sha256: sha2.sha256, 36 | sha384: sha2.sha384, 37 | sha512: sha2.sha512, 38 | ripemd160: ripemd160.ripemd160, 39 | rmd160: ripemd160.ripemd160, 40 | 41 | // Not supported by browser.old.js (until sha.js updates?) 42 | 'sha512-224': sha2.sha512_224, // for browser.old.js: https://github.com/browserify/sha.js/pull/67 43 | 'sha512-256': sha2.sha512_256, // for browser.old.js: https://github.com/browserify/sha.js/pull/67 44 | 'sha3-224': sha3.sha3_224, 45 | 'sha3-256': sha3.sha3_256, 46 | 'sha3-384': sha3.sha3_384, 47 | 'sha3-512': sha3.sha3_512, 48 | blake2b512: blake2b.blake2b, // 512 is the default size 49 | blake2s256: blake2s.blake2s // 256 is the default size 50 | }; 51 | 52 | module.exports = function createHash(algorithm) { 53 | var alg = algorithm.toLowerCase(); 54 | 55 | if (alg === 'md5') { 56 | return new MD5(); 57 | } 58 | 59 | if (!Object.prototype.hasOwnProperty.call(hashes, alg)) { 60 | throw new Error('Digest method not supported'); 61 | } 62 | 63 | return new Hash(hashes[alg].create()); 64 | }; 65 | -------------------------------------------------------------------------------- /browser.old.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var inherits = require('inherits'); 4 | var MD5 = require('md5.js'); 5 | var RIPEMD160 = require('ripemd160'); 6 | var sha = require('sha.js'); 7 | var Base = require('cipher-base'); 8 | 9 | function Hash(hash) { 10 | Base.call(this, 'digest'); 11 | 12 | this._hash = hash; 13 | } 14 | 15 | inherits(Hash, Base); 16 | 17 | Hash.prototype._update = function (data) { 18 | this._hash.update(data); 19 | }; 20 | 21 | Hash.prototype._final = function () { 22 | return this._hash.digest(); 23 | }; 24 | 25 | module.exports = function createHash(algorithm) { 26 | var alg = algorithm.toLowerCase(); 27 | if (alg === 'md5') { 28 | return new MD5(); 29 | } 30 | if (alg === 'rmd160' || alg === 'ripemd160') { 31 | return new RIPEMD160(); 32 | } 33 | 34 | return new Hash(sha(alg)); 35 | }; 36 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = require('crypto').createHash; 4 | -------------------------------------------------------------------------------- /md5.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var MD5 = require('md5.js'); 4 | 5 | module.exports = function (buffer) { 6 | return new MD5().update(buffer).digest(); 7 | }; 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-hash", 3 | "version": "1.2.0", 4 | "description": "create hashes for browserify", 5 | "browser": "browser.js", 6 | "main": "index.js", 7 | "scripts": { 8 | "prepack": "npmignore --auto --commentLines=autogenerated", 9 | "lint": "eslint --ext=js,mjs .", 10 | "pretest": "npm run lint", 11 | "test": "npm run tests-only", 12 | "tests-only": "tape 'test/**/*.js'", 13 | "posttest": "npx npm@'>=10.2' audit --production" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git@github.com:crypto-browserify/createHash.git" 18 | }, 19 | "keywords": [ 20 | "crypto" 21 | ], 22 | "author": "", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/crypto-browserify/createHash/issues" 26 | }, 27 | "homepage": "https://github.com/crypto-browserify/createHash", 28 | "dependencies": { 29 | "cipher-base": "^1.0.4", 30 | "hash-base": "=3.0.3", 31 | "inherits": "^2.0.4", 32 | "md5.js": "^1.3.5", 33 | "readable-stream": "^2.3.8", 34 | "ripemd160": "^2.0.2", 35 | "safe-buffer": "^5.2.1", 36 | "sha.js": "^2.4.11" 37 | }, 38 | "optionalDependencies": { 39 | "@noble/hashes": "^1.3.3" 40 | }, 41 | "devDependencies": { 42 | "@ljharb/eslint-config": "^21.1.1", 43 | "eslint": "=8.8.0", 44 | "hash-test-vectors": "^1.3.2", 45 | "npmignore": "^0.3.1", 46 | "tape": "^5.9.0" 47 | }, 48 | "publishConfig": { 49 | "ignore": [ 50 | ".github/workflows" 51 | ] 52 | }, 53 | "engines": { 54 | "node": ">= 0.8" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tape'); 4 | 5 | var Buffer = require('safe-buffer').Buffer; 6 | var algorithms = ['sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'md5', 'rmd160', 'ripemd160']; 7 | var encodings = ['hex', 'base64']; // ignore binary 8 | var vectors = require('hash-test-vectors'); 9 | vectors.forEach(function (vector) { 10 | // eslint-disable-next-line no-param-reassign 11 | vector.ripemd160 = vector.rmd160; 12 | }); 13 | var createHashOld = require('../browser.old.js'); 14 | var createHashAuto = require('../browser.js'); 15 | 16 | var implementations = [createHashOld]; 17 | if (createHashAuto !== createHashOld) { implementations.push(createHashAuto); } 18 | 19 | implementations.forEach(function (createHash) { 20 | algorithms.forEach(function (algorithm) { 21 | test('test ' + algorithm + ' against test vectors', function (t) { 22 | vectors.forEach(function (obj, i) { 23 | var input = Buffer.from(obj.input, 'base64'); 24 | var node = obj[algorithm]; 25 | var js = createHash(algorithm).update(input).digest('hex'); 26 | t.equal(js, node, algorithm + '(testVector[' + i + ']) == ' + node); 27 | }); 28 | 29 | encodings.forEach(function (encoding) { 30 | vectors.forEach(function (obj, i) { 31 | var input = Buffer.from(obj.input, 'base64').toString(encoding); 32 | var node = obj[algorithm]; 33 | var js = createHash(algorithm).update(input, encoding).digest('hex'); 34 | t.equal(js, node, algorithm + '(testVector[' + i + '], ' + encoding + ') == ' + node); 35 | }); 36 | }); 37 | 38 | vectors.forEach(function (obj, i) { 39 | var input = Buffer.from(obj.input, 'base64'); 40 | var node = obj[algorithm]; 41 | var hash = createHash(algorithm); 42 | hash.end(input); 43 | var js = hash.read().toString('hex'); 44 | t.equal(js, node, algorithm + '(testVector[' + i + ']) == ' + node); 45 | }); 46 | 47 | t.end(); 48 | }); 49 | }); 50 | }); 51 | 52 | var createHashNode = require('crypto').createHash; 53 | var randomBytes = require('crypto').randomBytes; 54 | 55 | function crossTest(createHashTest, createHashBase, algs) { 56 | var data = randomBytes(32); 57 | test('test against base implementation', function (t) { 58 | algs.forEach(function (algorithm) { 59 | var a = createHashTest(algorithm).update(data).digest('hex'); 60 | var b; 61 | try { 62 | b = createHashBase(algorithm).update(data).digest('hex'); 63 | } catch (err) {} 64 | var label = algorithm + '(' + data.toString('hex') + ')'; 65 | if (b) { 66 | t.equal(a, b, label); 67 | } else { 68 | t.skip(label); // Node.js version doesn't support it 69 | } 70 | }); 71 | t.end(); 72 | }); 73 | } 74 | 75 | var baseHashes = ['sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'ripemd160', 'rmd160']; 76 | var extraHashes = ['sha512-224', 'sha512-256', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512', 'blake2b512', 'blake2s256']; 77 | 78 | crossTest(createHashOld, createHashNode, baseHashes); 79 | 80 | // Only new version supports additional hashes 81 | if (createHashAuto !== createHashOld) { 82 | crossTest(createHashAuto, createHashNode, baseHashes); 83 | crossTest(createHashAuto, createHashNode, extraHashes); 84 | } 85 | --------------------------------------------------------------------------------