Welcome to mirror list, hosted at ThFree Co, Russian Federation.

index.js « hash « crypto « src - github.com/openpgpjs/openpgpjs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 76deb9c6bc01453baa4755b570b767490c16a936 (plain)
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
158
159
160
161
162
163
/**
 * @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';

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 1:
        // - MD5 [HAC]
        return this.md5(data);
      case 2:
        // - SHA-1 [FIPS180]
        return this.sha1(data);
      case 3:
        // - RIPE-MD/160 [HAC]
        return this.ripemd(data);
      case 8:
        // - SHA256 [FIPS180]
        return this.sha256(data);
      case 9:
        // - SHA384 [FIPS180]
        return this.sha384(data);
      case 10:
        // - SHA512 [FIPS180]
        return this.sha512(data);
      case 11:
        // - SHA224 [FIPS180]
        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 1: // - MD5 [HAC]
        return 16;
      case 2: // - SHA-1 [FIPS180]
      case 3: // - RIPE-MD/160 [HAC]
        return 20;
      case 8: // - SHA256 [FIPS180]
        return 32;
      case 9: // - SHA384 [FIPS180]
        return 48;
      case 10: // - SHA512 [FIPS180]
        return 64;
      case 11: // - SHA224 [FIPS180]
        return 28;
      default:
        throw new Error('Invalid hash algorithm.');
    }
  }
};