/
index.js
157 lines (147 loc) · 4.89 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/**
* @fileoverview Provides an interface to hashing functions available in Node.js or external libraries.
* @see {@link https://github.com/asmcrypto/asmcrypto.js|asmCrypto}
* @see {@link https://github.com/indutny/hash.js|hash.js}
* @module crypto/hash
* @private
*/
import { Sha1 } from '@openpgp/asmcrypto.js/dist_es8/hash/sha1/sha1';
import { Sha256 } from '@openpgp/asmcrypto.js/dist_es8/hash/sha256/sha256';
import sha224 from 'hash.js/lib/hash/sha/224';
import sha384 from 'hash.js/lib/hash/sha/384';
import sha512 from 'hash.js/lib/hash/sha/512';
import { ripemd160 } from 'hash.js/lib/hash/ripemd';
import * as stream from '@openpgp/web-stream-tools';
import md5 from './md5';
import util from '../../util';
import defaultConfig from '../../config';
import enums from '../../enums';
const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto();
function nodeHash(type) {
return async function (data) {
const shasum = nodeCrypto.createHash(type);
return stream.transform(data, value => {
shasum.update(value);
}, () => new Uint8Array(shasum.digest()));
};
}
function hashjsHash(hash, webCryptoHash) {
return async function(data, config = defaultConfig) {
if (stream.isArrayStream(data)) {
data = await stream.readToEnd(data);
}
if (!util.isStream(data) && webCrypto && webCryptoHash && data.length >= config.minBytesForWebCrypto) {
return new Uint8Array(await webCrypto.digest(webCryptoHash, data));
}
const hashInstance = hash();
return stream.transform(data, value => {
hashInstance.update(value);
}, () => new Uint8Array(hashInstance.digest()));
};
}
function asmcryptoHash(hash, webCryptoHash) {
return async function(data, config = defaultConfig) {
if (stream.isArrayStream(data)) {
data = await stream.readToEnd(data);
}
if (util.isStream(data)) {
const hashInstance = new hash();
return stream.transform(data, value => {
hashInstance.process(value);
}, () => hashInstance.finish().result);
} else if (webCrypto && webCryptoHash && data.length >= config.minBytesForWebCrypto) {
return new Uint8Array(await webCrypto.digest(webCryptoHash, data));
} else {
return hash.bytes(data);
}
};
}
let hashFunctions;
if (nodeCrypto) { // Use Node native crypto for all hash functions
hashFunctions = {
md5: nodeHash('md5'),
sha1: nodeHash('sha1'),
sha224: nodeHash('sha224'),
sha256: nodeHash('sha256'),
sha384: nodeHash('sha384'),
sha512: nodeHash('sha512'),
ripemd: nodeHash('ripemd160')
};
} else { // Use JS fallbacks
hashFunctions = {
md5: md5,
sha1: asmcryptoHash(Sha1, navigator.userAgent.indexOf('Edge') === -1 && 'SHA-1'),
sha224: hashjsHash(sha224),
sha256: asmcryptoHash(Sha256, 'SHA-256'),
sha384: hashjsHash(sha384, 'SHA-384'),
sha512: hashjsHash(sha512, 'SHA-512'), // asmcrypto sha512 is huge.
ripemd: hashjsHash(ripemd160)
};
}
export default {
/** @see module:md5 */
md5: hashFunctions.md5,
/** @see asmCrypto */
sha1: hashFunctions.sha1,
/** @see hash.js */
sha224: hashFunctions.sha224,
/** @see asmCrypto */
sha256: hashFunctions.sha256,
/** @see hash.js */
sha384: hashFunctions.sha384,
/** @see asmCrypto */
sha512: hashFunctions.sha512,
/** @see hash.js */
ripemd: hashFunctions.ripemd,
/**
* Create a hash on the specified data using the specified algorithm
* @param {module:enums.hash} algo - Hash algorithm type (see {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4})
* @param {Uint8Array} data - Data to be hashed
* @returns {Promise<Uint8Array>} Hash value.
*/
digest: function(algo, data) {
switch (algo) {
case enums.hash.md5:
return this.md5(data);
case enums.hash.sha1:
return this.sha1(data);
case enums.hash.ripemd:
return this.ripemd(data);
case enums.hash.sha256:
return this.sha256(data);
case enums.hash.sha384:
return this.sha384(data);
case enums.hash.sha512:
return this.sha512(data);
case enums.hash.sha224:
return this.sha224(data);
default:
throw new Error('Invalid hash function.');
}
},
/**
* Returns the hash size in bytes of the specified hash algorithm type
* @param {module:enums.hash} algo - Hash algorithm type (See {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4})
* @returns {Integer} Size in bytes of the resulting hash.
*/
getHashByteLength: function(algo) {
switch (algo) {
case enums.hash.md5:
return 16;
case enums.hash.sha1:
case enums.hash.ripemd:
return 20;
case enums.hash.sha256:
return 32;
case enums.hash.sha384:
return 48;
case enums.hash.sha512:
return 64;
case enums.hash.sha224:
return 28;
default:
throw new Error('Invalid hash algorithm.');
}
}
};