Skip to content
This repository was archived by the owner on Aug 11, 2021. It is now read-only.

Commit af7e003

Browse files
feat: webcrypto and sha3
In Node.js the underlying hashing functions have not changed, but the browser now uses `webcrypto` instead of JavaScript based methods for `SHA1`, `SHA2-256` and `SHA2-512`. Also `SHA3` support was added in both Node.js and the browser. BREAKING CHANGE: The api was changed to be callback based, as webcrypto only exposes async methods. Closes #10
1 parent f3b1478 commit af7e003

File tree

6 files changed

+225
-102
lines changed

6 files changed

+225
-102
lines changed

README.md

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ This module just makes working with multihashes a bit nicer.
1818
[js-multihash](//github.com/jbenet/js-multihash) is only for
1919
encoding/decoding multihashes, and does not depend on other libs.
2020
This module will depend on various implementations for each hash.
21-
For now, it just uses `crypto`, but will use `sha3` and `blake2`, etc.
21+
It currently uses `crypto` and [`sha3`](https://github.com/phusion/node-sha3) in Node.js. In the browser [`webcrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) and [`browserify-sha3`](https://github.com/wanderer/browserify-sha3) are used.
2222

2323
## Table of Contents
2424

@@ -80,16 +80,20 @@ You will need to use Node.js `Buffer` API compatible, if you are running inside
8080
var multihashing = require('multihashing')
8181
var buf = new Buffer('beep boop')
8282

83-
// by default returns a multihash.
84-
multihashing(buf, 'sha1')
83+
multihashing(buf, 'sha1', function (err, multihash) {
84+
// by default calls back with a multihash.
85+
})
8586

8687
// Use `.digest(...)` if you want only the hash digest (drops the prefix indicating the hash type).
87-
multihashing.digest(buf, 'sha1')
88+
multihashing.digest(buf, 'sha1', function (err , digest) {
89+
// digest is the raw digest
90+
})
8891

89-
// Use `.createHash(...)` for a `crypto.createHash` interface.
92+
// Use `.createHash(...)` for the raw hash functions
9093
var h = multihashing.createHash('sha1')
91-
h.update(buf)
92-
h.digest()
94+
h(buf, (err, digest) => {
95+
// digest is a buffer of the sha1 of buf
96+
})
9397
```
9498

9599
## Examples
@@ -100,39 +104,23 @@ h.digest()
100104
> var multihashing = require('multihashing')
101105
> var buf = new Buffer('beep boop')
102106

103-
> console.log(multihashing(buf, 'sha1'))
107+
> multihashing(buf, 'sha1'), function (err, mh) { console.log(mh) })
104108
// => <Buffer 11 14 7c 83 57 57 7f 51 d4 f0 a8 d3 93 aa 1a aa fb 28 86 3d 94 21>
105109

106-
> console.log(multihashing(buf, 'sha2-256'))
110+
> multihashing(buf, 'sha2-256', function (err, mh) { console.log(mh) })
107111
// => <Buffer 12 20 90 ea 68 8e 27 5d 58 05 67 32 50 32 49 2b 59 7b c7 72 21 c6 24 93 e7 63 30 b8 5d dd a1 91 ef 7c>
108112

109-
> console.log(multihashing(buf, 'sha2-512'))
113+
> multihashing(buf, 'sha2-512'), function (err, mh) { console.log(mh) })
110114
// => <Buffer 13 40 14 f3 01 f3 1b e2 43 f3 4c 56 68 93 78 83 77 1f a3 81 00 2f 1a aa 5f 31 b3 f7 8e 50 0b 66 ff 2f 4f 8e a5 e3 c9 f5 a6 1b d0 73 e2 45 2c 48 04 84 b0 ...>
111115
```
112116

113-
### Raw digest output
114-
115-
```js
116-
> var multihashing = require('multihashing')
117-
> var buf = new Buffer('beep boop')
118-
119-
> console.log(multihashing.digest(buf, 'sha1'))
120-
// => <SlowBuffer 7c 83 57 57 7f 51 d4 f0 a8 d3 93 aa 1a aa fb 28 86 3d 94 21>
121-
122-
> console.log(multihashing.digest(buf, 'sha2-256'))
123-
// => <SlowBuffer 90 ea 68 8e 27 5d 58 05 67 32 50 32 49 2b 59 7b c7 72 21 c6 24 93 e7 63 30 b8 5d dd a1 91 ef 7c>
124-
125-
> console.log(multihashing.digest(buf, 'sha2-512'))
126-
// => <SlowBuffer 14 f3 01 f3 1b e2 43 f3 4c 56 68 93 78 83 77 1f a3 81 00 2f 1a aa 5f 31 b3 f7 8e 50 0b 66 ff 2f 4f 8e a5 e3 c9 f5 a6 1b d0 73 e2 45 2c 48 04 84 b0 2e 03 ...>
127-
```
128-
129117
## API
130118

131-
### `multihashing(buf, func, length)`
119+
### `multihashing(buf, func, [length,] callback)`
132120

133-
### `digest(buf, func, length)`
121+
### `digest(buf, func, [length,] callback)`
134122

135-
### `createHash(func, length)`
123+
### `createHash(func)`
136124

137125
### `functions`
138126

package.json

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@
44
"description": "multiple hash functions",
55
"main": "lib/index.js",
66
"jsnext:main": "src/index.js",
7+
"browser": {
8+
"./src/crypto.js": "./src/crypto-browser.js"
9+
},
710
"scripts": {
8-
"test": "aegir-test",
9-
"test:browser": "aegir-test browser",
11+
"test": "PHANTOM=off aegir-test",
12+
"test:browser": "PHANTOM=off aegir-test browser",
1013
"test:node": "aegir-test node",
1114
"lint": "aegir-lint",
12-
"release": "aegir-release",
13-
"release-minor": "aegir-release minor",
14-
"release-major": "aegir-release major",
15+
"release": "PHANTOM=off aegir-release",
16+
"release-minor": "PHANTOM=off aegir-release minor",
17+
"release-major": "PHANTOM=off aegir-release major",
1518
"build": "aegir-build",
1619
"coverage": "aegir-coverage",
1720
"coverage-publish": "aegir-coverage publish"
@@ -33,11 +36,12 @@
3336
"url": "https://github.com/jbenet/js-multihashing/issues"
3437
},
3538
"dependencies": {
39+
"browserify-sha3": "0.0.2",
3640
"multihashes": "^0.2.0",
37-
"webcrypto": "^0.1.0"
41+
"sha3": "^1.2.0"
3842
},
3943
"devDependencies": {
40-
"aegir": "^2.1.1",
44+
"aegir": "^8.1.0",
4145
"chai": "^3.5.0",
4246
"pre-commit": "^1.1.2"
4347
},
@@ -48,4 +52,4 @@
4852
"Juan Batiz-Benet <[email protected]>",
4953
"dignifiedquire <[email protected]>"
5054
]
51-
}
55+
}

src/crypto-browser.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
'use strict'
2+
3+
const SHA3 = require('browserify-sha3')
4+
5+
const webCrypto = getWebCrypto()
6+
7+
function getWebCrypto () {
8+
if (typeof window !== 'undefined') {
9+
if (window.crypto) {
10+
return window.crypto.subtle || window.crypto.webkitSubtle
11+
}
12+
13+
if (window.msCrypto) {
14+
return window.msCrypto.subtle
15+
}
16+
}
17+
}
18+
19+
function webCryptoHash (type) {
20+
if (!webCrypto) {
21+
throw new Error('Please use a browser with webcrypto support')
22+
}
23+
24+
return (data, callback) => {
25+
const res = webCrypto.digest({ name: type }, data)
26+
27+
if (typeof res.then !== 'function') { // IE11
28+
res.onerror = () => {
29+
callback(`Error hashing data using ${type}`)
30+
}
31+
res.oncomplete = (e) => {
32+
callback(null, e.target.result)
33+
}
34+
return
35+
}
36+
37+
return res.then((arrbuf) => {
38+
callback(null, new Buffer(new Uint8Array(arrbuf)))
39+
}).catch((err) => callback(err))
40+
}
41+
}
42+
43+
function sha1 (buf, callback) {
44+
webCryptoHash('SHA-1')(buf, callback)
45+
}
46+
47+
function sha2256 (buf, callback) {
48+
webCryptoHash('SHA-256')(buf, callback)
49+
}
50+
51+
function sha2512 (buf, callback) {
52+
webCryptoHash('SHA-512')(buf, callback)
53+
}
54+
55+
function sha3 (buf, callback) {
56+
const d = new SHA3.SHA3Hash()
57+
const digest = new Buffer(d.update(buf).digest('hex'), 'hex')
58+
callback(null, digest)
59+
}
60+
61+
module.exports = {
62+
sha1: sha1,
63+
sha2256: sha2256,
64+
sha2512: sha2512,
65+
sha3: sha3
66+
}

src/crypto.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
'use strict'
2+
3+
const SHA3 = require('sha3')
4+
const crypto = require('crypto')
5+
6+
function sha1 (buf, callback) {
7+
const digest = crypto.createHash('sha1').update(buf).digest()
8+
callback(null, digest)
9+
}
10+
11+
function sha2256 (buf, callback) {
12+
const digest = crypto.createHash('sha256').update(buf).digest()
13+
callback(null, digest)
14+
}
15+
16+
function sha2512 (buf, callback) {
17+
const digest = crypto.createHash('sha512').update(buf).digest()
18+
callback(null, digest)
19+
}
20+
21+
function sha3 (buf, callback) {
22+
const d = new SHA3.SHA3Hash()
23+
const digest = new Buffer(d.update(buf).digest('hex'), 'hex')
24+
callback(null, digest)
25+
}
26+
27+
module.exports = {
28+
sha1: sha1,
29+
sha2256: sha2256,
30+
sha2512: sha2512,
31+
sha3: sha3
32+
}

src/index.js

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,75 @@
11
'use strict'
22

33
const multihash = require('multihashes')
4-
const crypto = require('webcrypto')
4+
const crypto = require('./crypto')
55

6-
const mh = module.exports = Multihashing
6+
module.exports = Multihashing
77

8-
mh.Buffer = Buffer // for browser things
8+
function Multihashing (buf, func, length, callback) {
9+
if (typeof length === 'function') {
10+
callback = length
11+
length = undefined
12+
}
13+
14+
Multihashing.digest(buf, func, length, (err, digest) => {
15+
if (err) {
16+
return callback(err)
17+
}
918

10-
function Multihashing (buf, func, length) {
11-
return multihash.encode(mh.digest(buf, func, length), func, length)
19+
callback(null, multihash.encode(digest, func, length))
20+
})
1221
}
1322

23+
Multihashing.Buffer = Buffer // for browser things
24+
1425
// expose multihash itself, to avoid silly double requires.
15-
mh.multihash = multihash
26+
Multihashing.multihash = multihash
27+
28+
Multihashing.digest = function (buf, func, length, callback) {
29+
if (typeof length === 'function') {
30+
callback = length
31+
length = undefined
32+
}
1633

17-
mh.digest = function (buf, func, length) {
18-
let digest = mh.createHash(func).update(buf).digest()
34+
if (!callback) {
35+
throw new Error('Missing callback')
36+
}
1937

38+
let cb = callback
2039
if (length) {
21-
digest = digest.slice(0, length)
40+
cb = (err, digest) => {
41+
if (err) {
42+
return callback(err)
43+
}
44+
45+
callback(null, digest.slice(0, length))
46+
}
2247
}
2348

24-
return digest
49+
let hash
50+
try {
51+
hash = Multihashing.createHash(func)
52+
} catch (err) {
53+
return cb(err)
54+
}
55+
56+
hash(buf, cb)
2557
}
2658

27-
mh.createHash = function (func, length) {
59+
Multihashing.createHash = function (func) {
2860
func = multihash.coerceCode(func)
29-
if (!mh.functions[func]) {
61+
if (!Multihashing.functions[func]) {
3062
throw new Error('multihash function ' + func + ' not yet supported')
3163
}
3264

33-
return mh.functions[func]()
65+
return Multihashing.functions[func]
3466
}
3567

36-
mh.functions = {
37-
0x11: gsha1,
38-
0x12: gsha2_256,
39-
0x13: gsha2_512
40-
// 0x14: gsha3 // not implemented yet
68+
Multihashing.functions = {
69+
0x11: crypto.sha1,
70+
0x12: crypto.sha2256,
71+
0x13: crypto.sha2512,
72+
0x14: crypto.sha3
4173
// 0x40: blake2b, // not implemented yet
4274
// 0x41: blake2s, // not implemented yet
4375
}
44-
45-
function gsha1 () {
46-
return crypto.createHash('sha1')
47-
}
48-
49-
function gsha2_256 () {
50-
return crypto.createHash('sha256')
51-
}
52-
53-
function gsha2_512 () {
54-
return crypto.createHash('sha512')
55-
}

0 commit comments

Comments
 (0)