Skip to content

Commit 1deb57b

Browse files
committed
support multi-byte wide typed arrays
1 parent 8938256 commit 1deb57b

File tree

2 files changed

+58
-4
lines changed

2 files changed

+58
-4
lines changed

Diff for: hash.js

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
var Buffer = require('safe-buffer').Buffer
22

3+
var useArrayBuffer = typeof ArrayBuffer !== 'undefined' &&
4+
typeof Uint8Array !== 'undefined' &&
5+
ArrayBuffer.isView
6+
37
// prototype class for hash functions
48
function Hash (blockSize, finalSize) {
59
this._block = Buffer.alloc(blockSize)
@@ -9,9 +13,35 @@ function Hash (blockSize, finalSize) {
913
}
1014

1115
Hash.prototype.update = function (data, enc) {
12-
if (typeof data === 'string') {
16+
if (data instanceof Uint8Array) {
17+
// Fast path
18+
// Already single-byte wide and 0-255
19+
} else if (typeof data === 'string') {
1320
enc = enc || 'utf8'
1421
data = Buffer.from(data, enc)
22+
} else if (useArrayBuffer && ArrayBuffer.isView(data)) {
23+
// Convert all TypedArray and DataView instances to single-byte-wide Uint8Array views
24+
var oldSize = data.byteLength
25+
data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
26+
27+
if (!(data.byteLength === oldSize && data.byteLength === data.length)) {
28+
throw new Error('Unexpected: broken Uint8Array')
29+
}
30+
} else {
31+
if (!(typeof data === 'object' && data && typeof data.length === 'number')) {
32+
throw new TypeError('Not an array-like')
33+
}
34+
35+
// non-negative 32-bit integer
36+
if ((data.length >>> 0) !== data.length) {
37+
throw new RangeError('Invalid length')
38+
}
39+
40+
for (var j = 0; j < data.length; j++) {
41+
if ((data[j] & 255) !== data[j]) {
42+
throw new Error('Not a byte array')
43+
}
44+
}
1545
}
1646

1747
var block = this._block

Diff for: test/test.js

+27-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ var inputs = [
1111
['123456789abcdef123456789abcdef123456789abcdef123456789ab', 'ascii'],
1212
['0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde', 'ascii'],
1313
['0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', 'ascii'],
14-
['foobarbaz', 'ascii']
14+
['foobarbaz', 'ascii'],
15+
[new Uint16Array([1, 2, 3])]
1516
]
1617

1718
tape("hash is the same as node's crypto", function (t) {
@@ -31,7 +32,7 @@ tape('call update multiple times', function (t) {
3132
var _hash = crypto.createHash('sha1')
3233

3334
for (var i = 0; i < v[0].length; i = (i + 1) * 2) {
34-
var s = v[0].substring(i, (i + 1) * 2)
35+
var s = v[0].slice(i, (i + 1) * 2)
3536
hash.update(s, v[1])
3637
_hash.update(s, v[1])
3738
}
@@ -70,7 +71,7 @@ tape('hex encoding', function (t) {
7071
var _hash = crypto.createHash('sha1')
7172

7273
for (var i = 0; i < v[0].length; i = (i + 1) * 2) {
73-
var s = v[0].substring(i, (i + 1) * 2)
74+
var s = v[0].slice(i, (i + 1) * 2)
7475
hash.update(Buffer.from(s, 'ascii').toString('hex'), 'hex')
7576
_hash.update(Buffer.from(s, 'ascii').toString('hex'), 'hex')
7677
}
@@ -84,6 +85,29 @@ tape('hex encoding', function (t) {
8485
t.end()
8586
})
8687

88+
tape('throws on invalid input', function (t) {
89+
var invalid = [
90+
{}, // non-arrayish
91+
{ length: 20 }, // undefined values
92+
[NaN], // non-numbers
93+
[[]], // non-numbers
94+
[1, 1.5], // non-integers
95+
[1, 256], // out of bounds
96+
[-1, 0] // out of bounds
97+
]
98+
99+
invalid.forEach(function (input) {
100+
var hash = new Sha1()
101+
102+
t.throws(() => {
103+
hash.update(input)
104+
hash.digest('hex')
105+
})
106+
})
107+
108+
t.end()
109+
})
110+
87111
tape('call digest for more than MAX_UINT32 bits of data', function (t) {
88112
var _hash = crypto.createHash('sha1')
89113
var hash = new Sha1()

0 commit comments

Comments
 (0)