@lakutata/security 3.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +143 -0
  3. package/THIRD_PARTY_NOTICES.md +36 -0
  4. package/dist/cjs/exceptions/DecryptionFailedException.d.ts +13 -0
  5. package/dist/cjs/exceptions/DecryptionFailedException.js +20 -0
  6. package/dist/cjs/exceptions/InvalidSignatureException.d.ts +13 -0
  7. package/dist/cjs/exceptions/InvalidSignatureException.js +20 -0
  8. package/dist/cjs/exceptions/PasswordTooLongException.d.ts +12 -0
  9. package/dist/cjs/exceptions/PasswordTooLongException.js +19 -0
  10. package/dist/cjs/exports/Security.d.ts +19 -0
  11. package/dist/cjs/exports/Security.js +38 -0
  12. package/dist/cjs/functions/Encryption.d.ts +95 -0
  13. package/dist/cjs/functions/Encryption.js +208 -0
  14. package/dist/cjs/functions/GenerateSecret.d.ts +20 -0
  15. package/dist/cjs/functions/GenerateSecret.js +26 -0
  16. package/dist/cjs/functions/HMAC.d.ts +50 -0
  17. package/dist/cjs/functions/HMAC.js +58 -0
  18. package/dist/cjs/functions/TimingSafeEqual.d.ts +18 -0
  19. package/dist/cjs/functions/TimingSafeEqual.js +30 -0
  20. package/dist/cjs/lib/AssertKey.d.ts +5 -0
  21. package/dist/cjs/lib/AssertKey.js +11 -0
  22. package/dist/cjs/lib/bcrypt/constants.d.ts +13 -0
  23. package/dist/cjs/lib/bcrypt/constants.js +213 -0
  24. package/dist/cjs/lib/bcrypt/index.d.ts +84 -0
  25. package/dist/cjs/lib/bcrypt/index.js +658 -0
  26. package/dist/cjs/package.json +1 -0
  27. package/dist/cjs/providers/Crypt.d.ts +71 -0
  28. package/dist/cjs/providers/Crypt.js +88 -0
  29. package/dist/cjs/providers/Mac.d.ts +86 -0
  30. package/dist/cjs/providers/Mac.js +114 -0
  31. package/dist/cjs/providers/PasswordHash.d.ts +78 -0
  32. package/dist/cjs/providers/PasswordHash.js +146 -0
  33. package/dist/esm/exceptions/DecryptionFailedException.js +16 -0
  34. package/dist/esm/exceptions/InvalidSignatureException.js +16 -0
  35. package/dist/esm/exceptions/PasswordTooLongException.js +15 -0
  36. package/dist/esm/exports/Security.js +19 -0
  37. package/dist/esm/functions/Encryption.js +202 -0
  38. package/dist/esm/functions/GenerateSecret.js +23 -0
  39. package/dist/esm/functions/HMAC.js +54 -0
  40. package/dist/esm/functions/TimingSafeEqual.js +27 -0
  41. package/dist/esm/lib/AssertKey.js +8 -0
  42. package/dist/esm/lib/bcrypt/constants.js +202 -0
  43. package/dist/esm/lib/bcrypt/index.js +645 -0
  44. package/dist/esm/providers/Crypt.js +84 -0
  45. package/dist/esm/providers/Mac.js +110 -0
  46. package/dist/esm/providers/PasswordHash.js +109 -0
  47. package/dist/types/exceptions/DecryptionFailedException.d.ts +13 -0
  48. package/dist/types/exceptions/InvalidSignatureException.d.ts +13 -0
  49. package/dist/types/exceptions/PasswordTooLongException.d.ts +12 -0
  50. package/dist/types/exports/Security.d.ts +19 -0
  51. package/dist/types/functions/Encryption.d.ts +95 -0
  52. package/dist/types/functions/GenerateSecret.d.ts +20 -0
  53. package/dist/types/functions/HMAC.d.ts +50 -0
  54. package/dist/types/functions/TimingSafeEqual.d.ts +18 -0
  55. package/dist/types/lib/AssertKey.d.ts +5 -0
  56. package/dist/types/lib/bcrypt/constants.d.ts +13 -0
  57. package/dist/types/lib/bcrypt/index.d.ts +84 -0
  58. package/dist/types/providers/Crypt.d.ts +71 -0
  59. package/dist/types/providers/Mac.d.ts +86 -0
  60. package/dist/types/providers/PasswordHash.d.ts +78 -0
  61. package/package.json +45 -0
@@ -0,0 +1,202 @@
1
+ import { createCipheriv, createDecipheriv, hkdfSync, randomBytes, scrypt as scryptCallback } from 'node:crypto';
2
+ import { DecryptionFailedException } from '../exceptions/DecryptionFailedException.js';
3
+ import { assertKey } from '../lib/AssertKey.js';
4
+ /**
5
+ * The versions of the encrypted data: the key derivation (the cipher is AES-256-GCM)
6
+ */
7
+ const KEY_VERSION = 1;
8
+ const PASSWORD_VERSION = 2;
9
+ const SALT_LENGTH = 16;
10
+ const IV_LENGTH = 12;
11
+ const TAG_LENGTH = 16;
12
+ const HEADER_LENGTH = 1 + SALT_LENGTH + IV_LENGTH;
13
+ const KEY_LENGTH = 32;
14
+ /**
15
+ * The scrypt parameters of the password version (about 16 MB and a few tens of milliseconds)
16
+ */
17
+ const SCRYPT_OPTIONS = { N: 16384, r: 8, p: 1 };
18
+ /**
19
+ * The key of a message: derived from the key with the salt of the message (HKDF-sha256)
20
+ * @param key
21
+ * @param salt
22
+ */
23
+ function deriveKey(key, salt) {
24
+ return Buffer.from(hkdfSync('sha256', key, salt, 'lakutata-encryption', KEY_LENGTH));
25
+ }
26
+ /**
27
+ * The key of a message: derived from the password with the salt of the message (scrypt)
28
+ * @param password
29
+ * @param salt
30
+ */
31
+ function derivePasswordKey(password, salt) {
32
+ return new Promise((resolve, reject) => scryptCallback(password, salt, KEY_LENGTH, SCRYPT_OPTIONS, (error, key) => error ? reject(error) : resolve(key)));
33
+ }
34
+ /**
35
+ * Encrypt with a key: version, salt, iv, tag and ciphertext, base64url encoded
36
+ * @param version
37
+ * @param salt
38
+ * @param key
39
+ * @param data
40
+ */
41
+ function seal(version, salt, key, data) {
42
+ const iv = randomBytes(IV_LENGTH);
43
+ const header = Buffer.concat([Buffer.from([version]), salt, iv]);
44
+ const cipher = createCipheriv('aes-256-gcm', key, iv);
45
+ //The header is authenticated too
46
+ cipher.setAAD(header);
47
+ const ciphertext = Buffer.concat([cipher.update(data), cipher.final()]);
48
+ return Buffer.concat([header, cipher.getAuthTag(), ciphertext]).toString('base64url');
49
+ }
50
+ /**
51
+ * The parts of encrypted data (undefined: not encrypted data of the version)
52
+ * @param encrypted
53
+ * @param version
54
+ */
55
+ function parts(encrypted, version) {
56
+ const buffer = Buffer.from(encrypted, 'base64url');
57
+ if (buffer.length < HEADER_LENGTH + TAG_LENGTH || buffer[0] !== version)
58
+ return undefined;
59
+ return {
60
+ header: buffer.subarray(0, HEADER_LENGTH),
61
+ salt: buffer.subarray(1, 1 + SALT_LENGTH),
62
+ iv: buffer.subarray(1 + SALT_LENGTH, HEADER_LENGTH),
63
+ tag: buffer.subarray(HEADER_LENGTH, HEADER_LENGTH + TAG_LENGTH),
64
+ ciphertext: buffer.subarray(HEADER_LENGTH + TAG_LENGTH)
65
+ };
66
+ }
67
+ /**
68
+ * Decrypt the parts with a key (undefined: the key does not decrypt them, or they were changed)
69
+ * @param part
70
+ * @param key
71
+ */
72
+ function open(part, key) {
73
+ try {
74
+ const decipher = createDecipheriv('aes-256-gcm', key, part.iv);
75
+ decipher.setAAD(part.header);
76
+ decipher.setAuthTag(part.tag);
77
+ return Buffer.concat([decipher.update(part.ciphertext), decipher.final()]);
78
+ }
79
+ catch {
80
+ return undefined;
81
+ }
82
+ }
83
+ /**
84
+ * Encrypt data with a secret key, using AES-256-GCM (authenticated encryption): the output is confidential and
85
+ * tamper-proof. Each call derives a fresh key from the key and a random 16-byte salt (HKDF-sha256) and uses a random
86
+ * 12-byte IV, so encrypting the same data twice gives different outputs. The {@link Crypt} provider does the same with
87
+ * configured keys and key rotation.
88
+ *
89
+ * The key must be random (see {@link generateSecret}): its derivation is fast, so a password used as a key is open to
90
+ * brute force; use {@link encryptByPassword} for passwords. The function refuses an empty key, but does not check
91
+ * the key's length or strength otherwise.
92
+ * @param data The data to encrypt: a string (encrypted as its UTF-8 bytes) or bytes.
93
+ * @param key The secret key: a string (used as its UTF-8 bytes, not decoded from base64) or bytes, not empty; 32
94
+ * random bytes recommended.
95
+ * @returns The encrypted data, base64url encoded without padding: 1 version byte, the salt, the IV, a 16-byte
96
+ * authentication tag and the ciphertext (45 bytes more than the data, before base64url).
97
+ * @throws {RangeError} When the key is empty.
98
+ * @example
99
+ * ```typescript
100
+ * import {decryptByKey, encryptByKey, generateSecret} from 'lakutata/security'
101
+ *
102
+ * const key: string = process.env.CRYPT_KEY ?? generateSecret()
103
+ * const encrypted: string = encryptByKey('card ending 4242', key)
104
+ * console.log(decryptByKey(encrypted, key).toString('utf8'))
105
+ * ```
106
+ */
107
+ export function encryptByKey(data, key) {
108
+ assertKey(key);
109
+ const salt = randomBytes(SALT_LENGTH);
110
+ return seal(KEY_VERSION, salt, deriveKey(key, salt), data);
111
+ }
112
+ /**
113
+ * Decrypt data encrypted by {@link encryptByKey} (or {@link Crypt.encrypt}) with one of the keys, tried in order: list
114
+ * the current key and the previous ones during a key rotation. The authentication tag is checked before anything is
115
+ * returned, so changed data is never decrypted.
116
+ * @param encrypted The encrypted data, base64url as {@link encryptByKey} returns it.
117
+ * @param keys The key, or the keys to try: strings (used as their UTF-8 bytes) or bytes, none empty.
118
+ * @returns The decrypted bytes (call `.toString('utf8')` for a string).
119
+ * @throws {DecryptionFailedException} When no key decrypts the data, or it was changed, truncated or not produced by
120
+ * {@link encryptByKey} (data encrypted by {@link encryptByPassword} included).
121
+ * @throws {RangeError} When a key is empty.
122
+ * @example
123
+ * ```typescript
124
+ * import {decryptByKey, DecryptionFailedException} from 'lakutata/security'
125
+ *
126
+ * declare const encrypted: string
127
+ * declare const currentKey: string
128
+ * declare const previousKey: string
129
+ *
130
+ * try {
131
+ * //The new key first, the previous one while old data remains
132
+ * const secret: string = decryptByKey(encrypted, [currentKey, previousKey]).toString('utf8')
133
+ * console.log(secret)
134
+ * } catch (error) {
135
+ * if (error instanceof DecryptionFailedException) console.log('Changed, or encrypted with an unknown key')
136
+ * }
137
+ * ```
138
+ */
139
+ export function decryptByKey(encrypted, keys) {
140
+ const candidates = Array.isArray(keys) ? keys : [keys];
141
+ candidates.forEach(assertKey);
142
+ const part = parts(encrypted, KEY_VERSION);
143
+ if (part) {
144
+ for (const key of candidates) {
145
+ const decrypted = open(part, deriveKey(key, part.salt));
146
+ if (decrypted)
147
+ return decrypted;
148
+ }
149
+ }
150
+ throw new DecryptionFailedException('The data cannot be decrypted');
151
+ }
152
+ /**
153
+ * Encrypt data with a password chosen by a person, using AES-256-GCM (authenticated encryption) with a key derived
154
+ * from the password and a random 16-byte salt by scrypt (N = 16384, r = 8, p = 1: about 16 MB of memory and a few
155
+ * tens of milliseconds per call, off the main thread). The slow derivation makes guessing the password costly; a
156
+ * strong password still matters. For a random key, {@link encryptByKey} is faster. To check a login password, use
157
+ * {@link PasswordHash} instead.
158
+ * @param data The data to encrypt: a string (encrypted as its UTF-8 bytes) or bytes.
159
+ * @param password The password: a string (used as its UTF-8 bytes) or bytes. Its length is not checked.
160
+ * @returns The encrypted data, base64url encoded without padding, in the format of {@link encryptByKey} with another
161
+ * version byte: the two are not interchangeable.
162
+ * @example
163
+ * ```typescript
164
+ * import {decryptByPassword, encryptByPassword} from 'lakutata/security'
165
+ *
166
+ * const encrypted: string = await encryptByPassword('backup contents', 'a long passphrase of the user')
167
+ * console.log((await decryptByPassword(encrypted, 'a long passphrase of the user')).toString('utf8'))
168
+ * ```
169
+ */
170
+ export async function encryptByPassword(data, password) {
171
+ const salt = randomBytes(SALT_LENGTH);
172
+ return seal(PASSWORD_VERSION, salt, await derivePasswordKey(password, salt), data);
173
+ }
174
+ /**
175
+ * Decrypt data encrypted by {@link encryptByPassword}, deriving the key from the password and the salt stored in the
176
+ * data (the same scrypt cost).
177
+ * @param encrypted The encrypted data, base64url as {@link encryptByPassword} returns it.
178
+ * @param password The password it was encrypted with: a string (used as its UTF-8 bytes) or bytes.
179
+ * @returns The decrypted bytes (call `.toString('utf8')` for a string).
180
+ * @throws {DecryptionFailedException} When the password is wrong, or the data was changed, truncated or not produced
181
+ * by {@link encryptByPassword} (data encrypted by {@link encryptByKey} included).
182
+ * @example
183
+ * ```typescript
184
+ * import {decryptByPassword, DecryptionFailedException} from 'lakutata/security'
185
+ *
186
+ * declare const encrypted: string
187
+ * declare const passphrase: string
188
+ *
189
+ * try {
190
+ * console.log((await decryptByPassword(encrypted, passphrase)).toString('utf8'))
191
+ * } catch (error) {
192
+ * if (error instanceof DecryptionFailedException) console.log('Wrong passphrase, or changed data')
193
+ * }
194
+ * ```
195
+ */
196
+ export async function decryptByPassword(encrypted, password) {
197
+ const part = parts(encrypted, PASSWORD_VERSION);
198
+ const decrypted = part ? open(part, await derivePasswordKey(password, part.salt)) : undefined;
199
+ if (decrypted)
200
+ return decrypted;
201
+ throw new DecryptionFailedException('The data cannot be decrypted');
202
+ }
@@ -0,0 +1,23 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ /**
3
+ * Generate a random secret key from the operating system's cryptographically secure generator (`crypto.randomBytes`),
4
+ * suited to the keys of {@link Mac} and {@link Crypt}, {@link hmac} and {@link encryptByKey}, and to random tokens
5
+ * (session IDs, reset links). It is not a password and should be stored as a secret (an environment variable, a vault).
6
+ * @param bytes The number of random bytes; 32 (256 bits) by default, at least 16 for a secret (0 gives an empty
7
+ * string). The keys of {@link Mac} and {@link Crypt} need 12 bytes or more to reach their 16-character minimum.
8
+ * @returns The random bytes, base64url encoded without padding: 43 characters for 32 bytes, 22 for 16.
9
+ * @throws {RangeError} When `bytes` is negative or larger than 2^31 - 1.
10
+ * @example
11
+ * ```typescript
12
+ * import {generateSecret} from 'lakutata/security'
13
+ *
14
+ * //A 256-bit key, for MAC_KEY or CRYPT_KEY
15
+ * console.log(generateSecret())
16
+ * //A 128-bit token
17
+ * const token: string = generateSecret(16)
18
+ * console.log(token)
19
+ * ```
20
+ */
21
+ export function generateSecret(bytes = 32) {
22
+ return randomBytes(bytes).toString('base64url');
23
+ }
@@ -0,0 +1,54 @@
1
+ import { createHmac } from 'node:crypto';
2
+ import { constantTimeEqual } from './TimingSafeEqual.js';
3
+ import { assertKey } from '../lib/AssertKey.js';
4
+ /**
5
+ * Sign data with a key: compute its hmac, a keyed hash that only a holder of the key can produce. Use it to detect
6
+ * tampering (webhooks, signed links); it does not hide the data, and is not a password hash. The {@link Mac} provider
7
+ * does the same with configured keys and key rotation.
8
+ * @param data The data to sign: a string (signed as its UTF-8 bytes) or bytes.
9
+ * @param key The secret key: a string (used as its UTF-8 bytes, not decoded) or bytes, not empty. Use a random key of
10
+ * 32 bytes, such as {@link generateSecret} returns.
11
+ * @param algorithm The hash function; `'sha256'` by default.
12
+ * @returns The hmac, base64url encoded without padding.
13
+ * @throws {RangeError} When the key is empty.
14
+ * @example
15
+ * ```typescript
16
+ * import {generateSecret, hmac, verifyHMAC} from 'lakutata/security'
17
+ *
18
+ * const key: string = process.env.WEBHOOK_KEY ?? generateSecret()
19
+ * const body: string = JSON.stringify({order: 42, status: 'paid'})
20
+ * //Sent in a header along with the body
21
+ * const signature: string = hmac(body, key, 'sha256')
22
+ * console.log(verifyHMAC(body, signature, key, 'sha256'))
23
+ * ```
24
+ */
25
+ export function hmac(data, key, algorithm = 'sha256') {
26
+ assertKey(key);
27
+ return createHmac(algorithm, key).update(data).digest('base64url');
28
+ }
29
+ /**
30
+ * Check that a signature is the HMAC of data with a key, in a time that does not depend on the signature (see
31
+ * {@link constantTimeEqual}).
32
+ * @param data The signed data, exactly as it was signed (the raw request body, not a re-serialized copy).
33
+ * @param signature The signature to check, base64url encoded without padding as {@link hmac} returns it; a hex or
34
+ * padded signature does not match.
35
+ * @param key The secret key the data was signed with: a string (used as its UTF-8 bytes) or bytes, not empty.
36
+ * @param algorithm The hash function the data was signed with; `'sha256'` by default.
37
+ * @returns `true` when the signature matches.
38
+ * @throws {RangeError} When the key is empty.
39
+ * @example
40
+ * ```typescript
41
+ * import {InvalidSignatureException, verifyHMAC} from 'lakutata/security'
42
+ *
43
+ * declare const rawBody: string
44
+ * declare const signatureHeader: string
45
+ * declare const webhookKey: string
46
+ *
47
+ * if (!verifyHMAC(rawBody, signatureHeader, webhookKey)) {
48
+ * throw new InvalidSignatureException('The signature of the webhook is not valid')
49
+ * }
50
+ * ```
51
+ */
52
+ export function verifyHMAC(data, signature, key, algorithm = 'sha256') {
53
+ return constantTimeEqual(hmac(data, key, algorithm), signature);
54
+ }
@@ -0,0 +1,27 @@
1
+ import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
2
+ /**
3
+ * A random key of the process: the compared values are digested with it, so the comparison does not reveal their length
4
+ */
5
+ const COMPARISON_KEY = randomBytes(32);
6
+ /**
7
+ * Compare two secrets (signatures, tokens, API keys) in a time that does not depend on their content or their lengths,
8
+ * so an attacker cannot guess a secret by timing the comparisons. Values of different lengths are compared too, and
9
+ * are unequal. Use it instead of `===` whenever one side is a secret; to check a password, use
10
+ * {@link PasswordHash.validate} instead.
11
+ * @param a The first value: a string (compared as its UTF-8 bytes) or bytes.
12
+ * @param b The second value: a string (compared as its UTF-8 bytes) or bytes.
13
+ * @returns `true` when both values hold the same bytes.
14
+ * @example
15
+ * ```typescript
16
+ * import {constantTimeEqual} from 'lakutata/security'
17
+ *
18
+ * declare const presentedApiKey: string
19
+ *
20
+ * if (!constantTimeEqual(presentedApiKey, process.env.API_KEY ?? '')) throw new Error('Unauthorized')
21
+ * ```
22
+ */
23
+ export function constantTimeEqual(a, b) {
24
+ const digestA = createHmac('sha256', COMPARISON_KEY).update(a).digest();
25
+ const digestB = createHmac('sha256', COMPARISON_KEY).update(b).digest();
26
+ return timingSafeEqual(digestA, digestB);
27
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Refuse an empty key: HMAC and HKDF accept it, but data signed or encrypted with it is open to anyone
3
+ * @param key
4
+ */
5
+ export function assertKey(key) {
6
+ if (key.length === 0)
7
+ throw new RangeError('The key is empty');
8
+ }
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Derived from the upstream index.js (see UPSTREAM.md; BSD-3-Clause, see THIRD_PARTY_NOTICES.md)
3
+ */
4
+ //bcrypt's own non-standard base64 alphabet
5
+ const BASE64_CODE = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.split('');
6
+ const BASE64_INDEX = [
7
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
8
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
9
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1,
10
+ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1,
11
+ -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
12
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1,
13
+ -1, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
14
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, -1, -1, -1, -1, -1
15
+ ];
16
+ const BCRYPT_SALT_LEN = 16;
17
+ const GENSALT_DEFAULT_LOG2_ROUNDS = 10;
18
+ const BLOWFISH_NUM_ROUNDS = 16;
19
+ //The longest synchronous run of the asynchronous hashing, in milliseconds
20
+ const MAX_EXECUTION_TIME = 100;
21
+ const P_ORIG = [
22
+ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
23
+ 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
24
+ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
25
+ ];
26
+ const S_ORIG = [
27
+ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
28
+ 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
29
+ 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
30
+ 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
31
+ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
32
+ 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
33
+ 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
34
+ 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
35
+ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
36
+ 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
37
+ 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
38
+ 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
39
+ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
40
+ 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
41
+ 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
42
+ 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
43
+ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
44
+ 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
45
+ 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
46
+ 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
47
+ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
48
+ 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
49
+ 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
50
+ 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
51
+ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
52
+ 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
53
+ 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
54
+ 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
55
+ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
56
+ 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
57
+ 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
58
+ 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
59
+ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
60
+ 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
61
+ 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
62
+ 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
63
+ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
64
+ 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
65
+ 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
66
+ 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
67
+ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
68
+ 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
69
+ 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, 0x4b7a70e9, 0xb5b32944,
70
+ 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
71
+ 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29,
72
+ 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
73
+ 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26,
74
+ 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
75
+ 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c,
76
+ 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
77
+ 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6,
78
+ 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
79
+ 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f,
80
+ 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
81
+ 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810,
82
+ 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
83
+ 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa,
84
+ 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
85
+ 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55,
86
+ 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
87
+ 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1,
88
+ 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
89
+ 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78,
90
+ 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
91
+ 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883,
92
+ 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
93
+ 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170,
94
+ 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
95
+ 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7,
96
+ 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
97
+ 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099,
98
+ 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
99
+ 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263,
100
+ 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
101
+ 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3,
102
+ 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
103
+ 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7,
104
+ 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
105
+ 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x095bbf00, 0xad19489d,
106
+ 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
107
+ 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460,
108
+ 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
109
+ 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484,
110
+ 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
111
+ 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a,
112
+ 0xe6e39f2b, 0xdb83adf7, 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
113
+ 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a,
114
+ 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
115
+ 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785,
116
+ 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
117
+ 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900,
118
+ 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
119
+ 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9,
120
+ 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
121
+ 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397,
122
+ 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
123
+ 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9,
124
+ 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
125
+ 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f,
126
+ 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
127
+ 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e,
128
+ 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
129
+ 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd,
130
+ 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
131
+ 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8,
132
+ 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
133
+ 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c,
134
+ 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
135
+ 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b,
136
+ 0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
137
+ 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386,
138
+ 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
139
+ 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0,
140
+ 0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
141
+ 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2,
142
+ 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
143
+ 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770,
144
+ 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
145
+ 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c,
146
+ 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
147
+ 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa,
148
+ 0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
149
+ 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63,
150
+ 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
151
+ 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9,
152
+ 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
153
+ 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4,
154
+ 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
155
+ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
156
+ 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
157
+ 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
158
+ 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
159
+ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
160
+ 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
161
+ 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
162
+ 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
163
+ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
164
+ 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
165
+ 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
166
+ 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
167
+ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
168
+ 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
169
+ 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
170
+ 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
171
+ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
172
+ 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
173
+ 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
174
+ 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
175
+ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
176
+ 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
177
+ 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
178
+ 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
179
+ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
180
+ 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
181
+ 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
182
+ 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
183
+ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
184
+ 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
185
+ 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
186
+ 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
187
+ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
188
+ 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
189
+ 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
190
+ 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
191
+ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
192
+ 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
193
+ 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
194
+ 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
195
+ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
196
+ 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
197
+ 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
198
+ ];
199
+ const C_ORIG = [
200
+ 0x4f727068, 0x65616e42, 0x65686f6c, 0x64657253, 0x63727944, 0x6f756274
201
+ ];
202
+ export { BASE64_CODE, BASE64_INDEX, BCRYPT_SALT_LEN, GENSALT_DEFAULT_LOG2_ROUNDS, BLOWFISH_NUM_ROUNDS, MAX_EXECUTION_TIME, P_ORIG, S_ORIG, C_ORIG };