react-native-quick-crypto 0.2.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 (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +84 -0
  3. package/android/.DS_Store +0 -0
  4. package/android/CMakeLists.txt +117 -0
  5. package/android/build.gradle +367 -0
  6. package/android/gradle/.DS_Store +0 -0
  7. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  8. package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  9. package/android/gradle.properties +6 -0
  10. package/android/gradlew +183 -0
  11. package/android/gradlew.bat +100 -0
  12. package/android/src/.DS_Store +0 -0
  13. package/android/src/main/.DS_Store +0 -0
  14. package/android/src/main/AndroidManifest.xml +4 -0
  15. package/android/src/main/cpp/cpp-adapter.cpp +60 -0
  16. package/android/src/main/java/.DS_Store +0 -0
  17. package/android/src/main/java/com/.DS_Store +0 -0
  18. package/android/src/main/java/com/reactnativequickcrypto/QuickCryptoModule.java +70 -0
  19. package/android/src/main/java/com/reactnativequickcrypto/QuickCryptoPackage.java +26 -0
  20. package/cpp/.DS_Store +0 -0
  21. package/cpp/Cipher/MGLCipherHostObject.cpp +632 -0
  22. package/cpp/Cipher/MGLCipherHostObject.h +90 -0
  23. package/cpp/Cipher/MGLCreateCipherInstaller.cpp +74 -0
  24. package/cpp/Cipher/MGLCreateCipherInstaller.h +17 -0
  25. package/cpp/Cipher/MGLCreateDecipherInstaller.cpp +74 -0
  26. package/cpp/Cipher/MGLCreateDecipherInstaller.h +17 -0
  27. package/cpp/HMAC/MGLHmacHostObject.cpp +95 -0
  28. package/cpp/HMAC/MGLHmacHostObject.h +39 -0
  29. package/cpp/HMAC/MGLHmacInstaller.cpp +43 -0
  30. package/cpp/HMAC/MGLHmacInstaller.h +20 -0
  31. package/cpp/Hash/MGLHashHostObject.cpp +147 -0
  32. package/cpp/Hash/MGLHashHostObject.h +53 -0
  33. package/cpp/Hash/MGLHashInstaller.cpp +46 -0
  34. package/cpp/Hash/MGLHashInstaller.h +20 -0
  35. package/cpp/JSIUtils/MGLJSIMacros.h +37 -0
  36. package/cpp/JSIUtils/MGLSmartHostObject.cpp +43 -0
  37. package/cpp/JSIUtils/MGLSmartHostObject.h +46 -0
  38. package/cpp/JSIUtils/MGLThreadAwareHostObject.cpp +24 -0
  39. package/cpp/JSIUtils/MGLThreadAwareHostObject.h +43 -0
  40. package/cpp/JSIUtils/MGLTypedArray.cpp +325 -0
  41. package/cpp/JSIUtils/MGLTypedArray.h +160 -0
  42. package/cpp/MGLQuickCryptoHostObject.cpp +64 -0
  43. package/cpp/MGLQuickCryptoHostObject.h +30 -0
  44. package/cpp/Random/MGLRandomHostObject.cpp +89 -0
  45. package/cpp/Random/MGLRandomHostObject.h +27 -0
  46. package/cpp/Utils/MGLDispatchQueue.cpp +75 -0
  47. package/cpp/Utils/MGLDispatchQueue.h +55 -0
  48. package/cpp/Utils/logs.h +38 -0
  49. package/cpp/fastpbkdf2/MGLPbkdf2HostObject.cpp +164 -0
  50. package/cpp/fastpbkdf2/MGLPbkdf2HostObject.h +29 -0
  51. package/cpp/fastpbkdf2/fastpbkdf2.c +352 -0
  52. package/cpp/fastpbkdf2/fastpbkdf2.h +68 -0
  53. package/ios/.DS_Store +0 -0
  54. package/ios/QuickCrypto.xcodeproj/project.pbxproj +274 -0
  55. package/ios/QuickCryptoModule.h +5 -0
  56. package/ios/QuickCryptoModule.mm +42 -0
  57. package/lib/.DS_Store +0 -0
  58. package/lib/commonjs/Cipher.js +293 -0
  59. package/lib/commonjs/Cipher.js.map +1 -0
  60. package/lib/commonjs/Hash.js +102 -0
  61. package/lib/commonjs/Hash.js.map +1 -0
  62. package/lib/commonjs/Hmac.js +104 -0
  63. package/lib/commonjs/Hmac.js.map +1 -0
  64. package/lib/commonjs/NativeQuickCrypto/Cipher.js +6 -0
  65. package/lib/commonjs/NativeQuickCrypto/Cipher.js.map +1 -0
  66. package/lib/commonjs/NativeQuickCrypto/NativeQuickCrypto.js +61 -0
  67. package/lib/commonjs/NativeQuickCrypto/NativeQuickCrypto.js.map +1 -0
  68. package/lib/commonjs/NativeQuickCrypto/hash.js +2 -0
  69. package/lib/commonjs/NativeQuickCrypto/hash.js.map +1 -0
  70. package/lib/commonjs/NativeQuickCrypto/hmac.js +2 -0
  71. package/lib/commonjs/NativeQuickCrypto/hmac.js.map +1 -0
  72. package/lib/commonjs/NativeQuickCrypto/pbkdf2.js +2 -0
  73. package/lib/commonjs/NativeQuickCrypto/pbkdf2.js.map +1 -0
  74. package/lib/commonjs/NativeQuickCrypto/random.js +2 -0
  75. package/lib/commonjs/NativeQuickCrypto/random.js.map +1 -0
  76. package/lib/commonjs/QuickCrypto.js +35 -0
  77. package/lib/commonjs/QuickCrypto.js.map +1 -0
  78. package/lib/commonjs/Utils.js +152 -0
  79. package/lib/commonjs/Utils.js.map +1 -0
  80. package/lib/commonjs/index.js +19 -0
  81. package/lib/commonjs/index.js.map +1 -0
  82. package/lib/commonjs/pbkdf2.js +64 -0
  83. package/lib/commonjs/pbkdf2.js.map +1 -0
  84. package/lib/commonjs/random.js +213 -0
  85. package/lib/commonjs/random.js.map +1 -0
  86. package/lib/module/Cipher.js +287 -0
  87. package/lib/module/Cipher.js.map +1 -0
  88. package/lib/module/Hash.js +87 -0
  89. package/lib/module/Hash.js.map +1 -0
  90. package/lib/module/Hmac.js +90 -0
  91. package/lib/module/Hmac.js.map +1 -0
  92. package/lib/module/NativeQuickCrypto/Cipher.js +2 -0
  93. package/lib/module/NativeQuickCrypto/Cipher.js.map +1 -0
  94. package/lib/module/NativeQuickCrypto/NativeQuickCrypto.js +53 -0
  95. package/lib/module/NativeQuickCrypto/NativeQuickCrypto.js.map +1 -0
  96. package/lib/module/NativeQuickCrypto/hash.js +2 -0
  97. package/lib/module/NativeQuickCrypto/hash.js.map +1 -0
  98. package/lib/module/NativeQuickCrypto/hmac.js +2 -0
  99. package/lib/module/NativeQuickCrypto/hmac.js.map +1 -0
  100. package/lib/module/NativeQuickCrypto/pbkdf2.js +2 -0
  101. package/lib/module/NativeQuickCrypto/pbkdf2.js.map +1 -0
  102. package/lib/module/NativeQuickCrypto/random.js +2 -0
  103. package/lib/module/NativeQuickCrypto/random.js.map +1 -0
  104. package/lib/module/QuickCrypto.js +18 -0
  105. package/lib/module/QuickCrypto.js.map +1 -0
  106. package/lib/module/Utils.js +131 -0
  107. package/lib/module/Utils.js.map +1 -0
  108. package/lib/module/index.js +2 -0
  109. package/lib/module/index.js.map +1 -0
  110. package/lib/module/pbkdf2.js +51 -0
  111. package/lib/module/pbkdf2.js.map +1 -0
  112. package/lib/module/random.js +190 -0
  113. package/lib/module/random.js.map +1 -0
  114. package/lib/typescript/Cipher.d.ts +30 -0
  115. package/lib/typescript/Hash.d.ts +44 -0
  116. package/lib/typescript/Hmac.d.ts +37 -0
  117. package/lib/typescript/NativeQuickCrypto/Cipher.d.ts +22 -0
  118. package/lib/typescript/NativeQuickCrypto/NativeQuickCrypto.d.ts +19 -0
  119. package/lib/typescript/NativeQuickCrypto/hash.d.ts +6 -0
  120. package/lib/typescript/NativeQuickCrypto/hmac.d.ts +5 -0
  121. package/lib/typescript/NativeQuickCrypto/pbkdf2.d.ts +4 -0
  122. package/lib/typescript/NativeQuickCrypto/random.d.ts +4 -0
  123. package/lib/typescript/QuickCrypto.d.ts +31 -0
  124. package/lib/typescript/Utils.d.ts +13 -0
  125. package/lib/typescript/index.d.ts +1 -0
  126. package/lib/typescript/pbkdf2.d.ts +9 -0
  127. package/lib/typescript/random.d.ts +20 -0
  128. package/package.json +168 -0
  129. package/react-native-quick-crypto.podspec +44 -0
  130. package/src/Cipher.ts +322 -0
  131. package/src/Hash.ts +98 -0
  132. package/src/Hmac.ts +107 -0
  133. package/src/NativeQuickCrypto/Cipher.ts +25 -0
  134. package/src/NativeQuickCrypto/NativeQuickCrypto.ts +79 -0
  135. package/src/NativeQuickCrypto/hash.ts +10 -0
  136. package/src/NativeQuickCrypto/hmac.ts +9 -0
  137. package/src/NativeQuickCrypto/pbkdf2.ts +16 -0
  138. package/src/NativeQuickCrypto/random.ts +12 -0
  139. package/src/QuickCrypto.ts +23 -0
  140. package/src/Utils.ts +151 -0
  141. package/src/index.ts +1 -0
  142. package/src/pbkdf2.ts +96 -0
  143. package/src/random.ts +277 -0
@@ -0,0 +1,16 @@
1
+ export type Pbkdf2Object = {
2
+ pbkdf2: (
3
+ password: ArrayBuffer,
4
+ salt: ArrayBuffer,
5
+ iterations: number,
6
+ keylen: number,
7
+ digest: string
8
+ ) => Promise<ArrayBuffer>;
9
+ pbkdf2Sync: (
10
+ password: ArrayBuffer,
11
+ salt: ArrayBuffer,
12
+ iterations: number,
13
+ keylen: number,
14
+ digest: string
15
+ ) => ArrayBuffer;
16
+ };
@@ -0,0 +1,12 @@
1
+ export type RandomObject = {
2
+ randomFill: (
3
+ buffer: ArrayBuffer,
4
+ offset: number,
5
+ size: number
6
+ ) => Promise<ArrayBuffer>;
7
+ randomFillSync: (
8
+ buffer: ArrayBuffer,
9
+ offset: number,
10
+ size: number
11
+ ) => ArrayBuffer;
12
+ };
@@ -0,0 +1,23 @@
1
+ import * as pbkdf2 from './pbkdf2';
2
+ import * as random from './random';
3
+ import {
4
+ createCipher,
5
+ createCipheriv,
6
+ createDecipher,
7
+ createDecipheriv,
8
+ } from './Cipher';
9
+ import { createHmac } from './Hmac';
10
+ import { createHash } from './Hash';
11
+
12
+ export const QuickCrypto = {
13
+ createHmac,
14
+ Hmac: createHmac,
15
+ Hash: createHash,
16
+ createHash,
17
+ createCipher,
18
+ createCipheriv,
19
+ createDecipher,
20
+ createDecipheriv,
21
+ ...pbkdf2,
22
+ ...random,
23
+ };
package/src/Utils.ts ADDED
@@ -0,0 +1,151 @@
1
+ import { Buffer } from '@craftzdog/react-native-buffer';
2
+
3
+ export type BinaryLike = string | ArrayBuffer | Buffer;
4
+
5
+ export type BinaryToTextEncoding = 'base64' | 'base64url' | 'hex' | 'binary';
6
+ export type CharacterEncoding = 'utf8' | 'utf-8' | 'utf16le' | 'latin1';
7
+ export type LegacyCharacterEncoding = 'ascii' | 'binary' | 'ucs2' | 'ucs-2';
8
+ export type Encoding =
9
+ | BinaryToTextEncoding
10
+ | CharacterEncoding
11
+ | LegacyCharacterEncoding;
12
+
13
+ // TODO(osp) should buffer be part of the Encoding type?
14
+ export type CipherEncoding = Encoding | 'buffer';
15
+
16
+ // Mimics node behavior for default global encoding
17
+ let defaultEncoding: CipherEncoding = 'buffer';
18
+
19
+ export function setDefaultEncoding(encoding: CipherEncoding) {
20
+ defaultEncoding = encoding;
21
+ }
22
+
23
+ export function getDefaultEncoding(): CipherEncoding {
24
+ return defaultEncoding;
25
+ }
26
+
27
+ // function slowCases(enc: string) {
28
+ // switch (enc.length) {
29
+ // case 4:
30
+ // if (enc === 'UTF8') return 'utf8';
31
+ // if (enc === 'ucs2' || enc === 'UCS2') return 'utf16le';
32
+ // enc = `${enc}`.toLowerCase();
33
+ // if (enc === 'utf8') return 'utf8';
34
+ // if (enc === 'ucs2') return 'utf16le';
35
+ // break;
36
+ // case 3:
37
+ // if (enc === 'hex' || enc === 'HEX' || `${enc}`.toLowerCase() === 'hex')
38
+ // return 'hex';
39
+ // break;
40
+ // case 5:
41
+ // if (enc === 'ascii') return 'ascii';
42
+ // if (enc === 'ucs-2') return 'utf16le';
43
+ // if (enc === 'UTF-8') return 'utf8';
44
+ // if (enc === 'ASCII') return 'ascii';
45
+ // if (enc === 'UCS-2') return 'utf16le';
46
+ // enc = `${enc}`.toLowerCase();
47
+ // if (enc === 'utf-8') return 'utf8';
48
+ // if (enc === 'ascii') return 'ascii';
49
+ // if (enc === 'ucs-2') return 'utf16le';
50
+ // break;
51
+ // case 6:
52
+ // if (enc === 'base64') return 'base64';
53
+ // if (enc === 'latin1' || enc === 'binary') return 'latin1';
54
+ // if (enc === 'BASE64') return 'base64';
55
+ // if (enc === 'LATIN1' || enc === 'BINARY') return 'latin1';
56
+ // enc = `${enc}`.toLowerCase();
57
+ // if (enc === 'base64') return 'base64';
58
+ // if (enc === 'latin1' || enc === 'binary') return 'latin1';
59
+ // break;
60
+ // case 7:
61
+ // if (
62
+ // enc === 'utf16le' ||
63
+ // enc === 'UTF16LE' ||
64
+ // `${enc}`.toLowerCase() === 'utf16le'
65
+ // )
66
+ // return 'utf16le';
67
+ // break;
68
+ // case 8:
69
+ // if (
70
+ // enc === 'utf-16le' ||
71
+ // enc === 'UTF-16LE' ||
72
+ // `${enc}`.toLowerCase() === 'utf-16le'
73
+ // )
74
+ // return 'utf16le';
75
+ // break;
76
+ // case 9:
77
+ // if (
78
+ // enc === 'base64url' ||
79
+ // enc === 'BASE64URL' ||
80
+ // `${enc}`.toLowerCase() === 'base64url'
81
+ // )
82
+ // return 'base64url';
83
+ // break;
84
+ // default:
85
+ // if (enc === '') return 'utf8';
86
+ // }
87
+ // }
88
+
89
+ // // Return undefined if there is no match.
90
+ // // Move the "slow cases" to a separate function to make sure this function gets
91
+ // // inlined properly. That prioritizes the common case.
92
+ // export function normalizeEncoding(enc?: string) {
93
+ // if (enc == null || enc === 'utf8' || enc === 'utf-8') return 'utf8';
94
+ // return slowCases(enc);
95
+ // }
96
+
97
+ export function isBuffer(buf: any): buf is Buffer {
98
+ return buf instanceof Buffer || buf?.constructor?.name === 'Buffer';
99
+ }
100
+
101
+ export function toArrayBuffer(buf: Buffer): ArrayBuffer {
102
+ if (buf?.buffer?.slice) {
103
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
104
+ }
105
+ const ab = new ArrayBuffer(buf.length);
106
+ const view = new Uint8Array(ab);
107
+ for (let i = 0; i < buf.length; ++i) {
108
+ view[i] = buf[i];
109
+ }
110
+ return ab;
111
+ }
112
+
113
+ export function binaryLikeToArrayBuffer(
114
+ input: BinaryLike,
115
+ encoding: string = 'utf-8'
116
+ ): ArrayBuffer {
117
+ if (typeof input === 'string') {
118
+ const buffer = Buffer.from(input, encoding);
119
+
120
+ return buffer.buffer.slice(
121
+ buffer.byteOffset,
122
+ buffer.byteOffset + buffer.byteLength
123
+ );
124
+ }
125
+
126
+ if (isBuffer(input)) {
127
+ return toArrayBuffer(input);
128
+ }
129
+
130
+ // TODO add further binary types to BinaryLike, UInt8Array and so for have this array as property
131
+ if ((input as any).buffer) {
132
+ return (input as any).buffer;
133
+ }
134
+
135
+ if (!(input instanceof ArrayBuffer)) {
136
+ try {
137
+ const buffer = Buffer.from(input);
138
+ return buffer.buffer.slice(
139
+ buffer.byteOffset,
140
+ buffer.byteOffset + buffer.byteLength
141
+ );
142
+ } catch {
143
+ throw 'error';
144
+ }
145
+ }
146
+ return input;
147
+ }
148
+
149
+ export function ab2str(buf: ArrayBuffer, encoding: string = 'hex') {
150
+ return Buffer.from(buf).toString(encoding);
151
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './QuickCrypto';
package/src/pbkdf2.ts ADDED
@@ -0,0 +1,96 @@
1
+ import { NativeQuickCrypto } from './NativeQuickCrypto/NativeQuickCrypto';
2
+ import { Buffer } from '@craftzdog/react-native-buffer';
3
+ import { BinaryLike, binaryLikeToArrayBuffer } from './Utils';
4
+
5
+ const WRONG_PASS =
6
+ 'Password must be a string, a Buffer, a typed array or a DataView';
7
+ const WRON_SALT = `Salt must be a string, a Buffer, a typed array or a DataView`;
8
+
9
+ type Password = BinaryLike;
10
+ type Salt = BinaryLike;
11
+ type Pbkdf2Callback = (err: Error | null, derivedKey?: Buffer) => void;
12
+
13
+ function sanitizeInput(input: BinaryLike, errorMsg: string): ArrayBuffer {
14
+ try {
15
+ return binaryLikeToArrayBuffer(input);
16
+ } catch (e: any) {
17
+ throw errorMsg;
18
+ }
19
+ }
20
+
21
+ const nativePbkdf2 = NativeQuickCrypto.pbkdf2;
22
+
23
+ export function pbkdf2(
24
+ password: Password,
25
+ salt: Salt,
26
+ iterations: number,
27
+ keylen: number,
28
+ digest: string,
29
+ callback: Pbkdf2Callback
30
+ ): void;
31
+ export function pbkdf2(
32
+ password: Password,
33
+ salt: Salt,
34
+ iterations: number,
35
+ keylen: number,
36
+ callback: Pbkdf2Callback
37
+ ): void;
38
+ export function pbkdf2(
39
+ password: Password,
40
+ salt: Salt,
41
+ iterations: number,
42
+ keylen: number,
43
+ arg0?: unknown,
44
+ arg1?: unknown
45
+ ): void {
46
+ let digest = 'sha1';
47
+ let callback: undefined | Pbkdf2Callback;
48
+ if (typeof arg0 === 'string') {
49
+ digest = arg0;
50
+ if (typeof arg1 === 'function') {
51
+ callback = arg1 as Pbkdf2Callback;
52
+ }
53
+ } else {
54
+ if (typeof arg0 === 'function') {
55
+ callback = arg0 as Pbkdf2Callback;
56
+ }
57
+ }
58
+ if (callback === undefined) {
59
+ throw new Error('No callback provided to pbkdf2');
60
+ }
61
+
62
+ const sanitizedPassword = sanitizeInput(password, WRONG_PASS);
63
+ const sanitizedSalt = sanitizeInput(salt, WRON_SALT);
64
+
65
+ nativePbkdf2
66
+ .pbkdf2(sanitizedPassword, sanitizedSalt, iterations, keylen, digest)
67
+ .then(
68
+ (res: ArrayBuffer) => {
69
+ callback!(null, Buffer.from(res));
70
+ },
71
+ (e: Error) => {
72
+ callback!(e);
73
+ }
74
+ );
75
+ }
76
+ export function pbkdf2Sync(
77
+ password: Password,
78
+ salt: Salt,
79
+ iterations: number,
80
+ keylen: number,
81
+ digest?: string
82
+ ): Buffer {
83
+ const sanitizedPassword = sanitizeInput(password, WRONG_PASS);
84
+ const sanitizedSalt = sanitizeInput(salt, WRON_SALT);
85
+
86
+ const algo = digest ? digest : 'sha1';
87
+ let result: ArrayBuffer = nativePbkdf2.pbkdf2Sync(
88
+ sanitizedPassword,
89
+ sanitizedSalt,
90
+ iterations,
91
+ keylen,
92
+ algo
93
+ );
94
+
95
+ return Buffer.from(result);
96
+ }
package/src/random.ts ADDED
@@ -0,0 +1,277 @@
1
+ import { NativeQuickCrypto } from './NativeQuickCrypto/NativeQuickCrypto';
2
+ import { Buffer } from '@craftzdog/react-native-buffer';
3
+ import { isBuffer } from '../src/Utils';
4
+
5
+ const random = NativeQuickCrypto.random;
6
+
7
+ type TypedArray =
8
+ | Uint8Array
9
+ | Uint8ClampedArray
10
+ | Uint16Array
11
+ | Uint32Array
12
+ | Int8Array
13
+ | Int16Array
14
+ | Int32Array
15
+ | Float32Array
16
+ | Float64Array;
17
+ type ArrayBufferView = TypedArray | DataView | ArrayBufferLike | Buffer;
18
+
19
+ export function randomFill<T extends ArrayBufferView>(
20
+ buffer: T,
21
+ callback: (err: Error | null, buf: T) => void
22
+ ): void;
23
+
24
+ export function randomFill<T extends ArrayBufferView>(
25
+ buffer: T,
26
+ offset: number,
27
+ callback: (err: Error | null, buf: T) => void
28
+ ): void;
29
+
30
+ export function randomFill<T extends ArrayBufferView>(
31
+ buffer: T,
32
+ offset: number,
33
+ size: number,
34
+ callback: (err: Error | null, buf: T) => void
35
+ ): void;
36
+
37
+ export function randomFill(buffer: any, ...rest: any[]): void {
38
+ if (typeof rest[rest.length - 1] !== 'function') {
39
+ throw new Error('No callback provided to randomDill');
40
+ }
41
+
42
+ const callback = rest[rest.length - 1] as any as (
43
+ err: Error | null,
44
+ buf?: ArrayBuffer
45
+ ) => void;
46
+
47
+ let offset: number = 0;
48
+ let size: number = buffer.byteLength;
49
+
50
+ if (typeof rest[2] === 'function') {
51
+ offset = rest[0];
52
+ size = rest[1];
53
+ }
54
+
55
+ if (typeof rest[1] === 'function') {
56
+ offset = rest[0];
57
+ }
58
+
59
+ random
60
+ .randomFill(isBuffer(buffer) ? buffer.buffer : buffer, offset, size)
61
+ .then(
62
+ () => {
63
+ callback(null, buffer);
64
+ },
65
+ (e: Error) => {
66
+ callback(e);
67
+ }
68
+ );
69
+ }
70
+
71
+ export function randomFillSync<T extends ArrayBufferView>(
72
+ buffer: T,
73
+ offset?: number,
74
+ size?: number
75
+ ): T;
76
+
77
+ export function randomFillSync(buffer: any, offset: number = 0, size?: number) {
78
+ random.randomFillSync(
79
+ buffer.buffer ? buffer.buffer : buffer,
80
+ offset,
81
+ size ?? buffer.byteLength
82
+ );
83
+ return buffer;
84
+ }
85
+
86
+ export function randomBytes(size: number): ArrayBuffer;
87
+
88
+ export function randomBytes(
89
+ size: number,
90
+ callback: (err: Error | null, buf?: ArrayBuffer) => void
91
+ ): void;
92
+
93
+ export function randomBytes(
94
+ size: number,
95
+ callback?: (err: Error | null, buf?: ArrayBuffer) => void
96
+ ): void | ArrayBuffer {
97
+ const buf = new Buffer(size);
98
+
99
+ if (callback === undefined) {
100
+ randomFillSync(buf.buffer, 0, size);
101
+ return buf;
102
+ }
103
+
104
+ randomFill(buf.buffer, 0, size, (error: Error | null) => {
105
+ if (error) {
106
+ callback(error);
107
+ }
108
+ callback(null, buf);
109
+ });
110
+ }
111
+
112
+ export const rng = randomBytes;
113
+ export const pseudoRandomBytes = randomBytes;
114
+ export const prng = randomBytes;
115
+
116
+ type RandomIntCallback = (err: Error | null, value: number) => void;
117
+ type Task = {
118
+ min: number;
119
+ max: number;
120
+ callback: RandomIntCallback;
121
+ };
122
+
123
+ // The rest of the file is taken from https://github.com/nodejs/node/blob/master/lib/internal/crypto/random.js
124
+
125
+ // Largest integer we can read from a buffer.
126
+ // e.g.: Buffer.from("ff".repeat(6), "hex").readUIntBE(0, 6);
127
+ const RAND_MAX = 0xffff_ffff_ffff;
128
+
129
+ // Cache random data to use in randomInt. The cache size must be evenly
130
+ // divisible by 6 because each attempt to obtain a random int uses 6 bytes.
131
+ const randomCache = new Buffer(6 * 1024);
132
+ let randomCacheOffset = randomCache.length;
133
+ let asyncCacheFillInProgress = false;
134
+ const asyncCachePendingTasks: Task[] = [];
135
+
136
+ // Generates an integer in [min, max) range where min is inclusive and max is
137
+ // exclusive.
138
+
139
+ export function randomInt(max: number, callback: RandomIntCallback): void;
140
+ export function randomInt(max: number): number;
141
+ export function randomInt(
142
+ min: number,
143
+ max: number,
144
+ callback: RandomIntCallback
145
+ ): void;
146
+ export function randomInt(min: number, max: number): number;
147
+ export function randomInt(
148
+ arg1: number,
149
+ arg2?: number | RandomIntCallback,
150
+ callback?: RandomIntCallback
151
+ ): void | number {
152
+ // Detect optional min syntax
153
+ // randomInt(max)
154
+ // randomInt(max, callback)
155
+ let max: number;
156
+ let min: number;
157
+ const minNotSpecified =
158
+ typeof arg2 === 'undefined' || typeof arg2 === 'function';
159
+
160
+ if (minNotSpecified) {
161
+ callback = arg2 as any as undefined | RandomIntCallback;
162
+ max = arg1;
163
+ min = 0;
164
+ } else {
165
+ min = arg1;
166
+ max = arg2 as any as number;
167
+ }
168
+
169
+ const isSync = typeof callback === 'undefined';
170
+ if (!Number.isSafeInteger(min)) {
171
+ // todo throw new ERR_INVALID_ARG_TYPE('min', 'a safe integer', min);
172
+ throw 'ERR_INVALID_ARG_TYPE';
173
+ }
174
+ if (!Number.isSafeInteger(max)) {
175
+ // todo throw new ERR_INVALID_ARG_TYPE('max', 'a safe integer', max);
176
+ throw 'ERR_INVALID_ARG_TYPE';
177
+ }
178
+ if (max <= min) {
179
+ /* todo throw new ERR_OUT_OF_RANGE(
180
+ 'max',
181
+ `greater than the value of "min" (${min})`,
182
+ max
183
+ );*/
184
+ throw 'ERR_OUT_OF_RANGE';
185
+ }
186
+
187
+ // First we generate a random int between [0..range)
188
+ const range = max - min;
189
+
190
+ if (!(range <= RAND_MAX)) {
191
+ /* todo throw new ERR_OUT_OF_RANGE(
192
+ `max${minNotSpecified ? '' : ' - min'}`,
193
+ `<= ${RAND_MAX}`,
194
+ range
195
+ );*/
196
+ throw 'ERR_OUT_OF_RANGE';
197
+ }
198
+
199
+ // For (x % range) to produce an unbiased value greater than or equal to 0 and
200
+ // less than range, x must be drawn randomly from the set of integers greater
201
+ // than or equal to 0 and less than randLimit.
202
+ const randLimit = RAND_MAX - (RAND_MAX % range);
203
+
204
+ // If we don't have a callback, or if there is still data in the cache, we can
205
+ // do this synchronously, which is super fast.
206
+ while (isSync || randomCacheOffset < randomCache.length) {
207
+ if (randomCacheOffset === randomCache.length) {
208
+ // This might block the thread for a bit, but we are in sync mode.
209
+ randomFillSync(randomCache);
210
+ randomCacheOffset = 0;
211
+ }
212
+
213
+ const x = randomCache.readUIntBE(randomCacheOffset, 6);
214
+ randomCacheOffset += 6;
215
+
216
+ if (x < randLimit) {
217
+ const n = (x % range) + min;
218
+ if (isSync) return n;
219
+ process.nextTick(callback as Function, undefined, n);
220
+ return;
221
+ }
222
+ }
223
+
224
+ // At this point, we are in async mode with no data in the cache. We cannot
225
+ // simply refill the cache, because another async call to randomInt might
226
+ // already be doing that. Instead, queue this call for when the cache has
227
+ // been refilled.
228
+ if (callback !== undefined) {
229
+ // it is (typescript doesn't know it)
230
+ asyncCachePendingTasks.push({ min, max, callback });
231
+ asyncRefillRandomIntCache();
232
+ }
233
+ }
234
+
235
+ function asyncRefillRandomIntCache() {
236
+ if (asyncCacheFillInProgress) return;
237
+
238
+ asyncCacheFillInProgress = true;
239
+ randomFill(randomCache, (err) => {
240
+ asyncCacheFillInProgress = false;
241
+
242
+ const tasks = asyncCachePendingTasks;
243
+ const errorReceiver = err && tasks.shift();
244
+ if (!err) randomCacheOffset = 0;
245
+
246
+ // Restart all pending tasks. If an error occurred, we only notify a single
247
+ // callback (errorReceiver) about it. This way, every async call to
248
+ // randomInt has a chance of being successful, and it avoids complex
249
+ // exception handling here.
250
+ tasks.splice(0).forEach((task) => {
251
+ randomInt(task.min, task.max, task.callback);
252
+ });
253
+
254
+ // This is the only call that might throw, and is therefore done at the end.
255
+ if (errorReceiver) errorReceiver.callback(err, 0);
256
+ });
257
+ }
258
+
259
+ // Really just the Web Crypto API alternative
260
+ // to require('crypto').randomFillSync() with an
261
+ // additional limitation that the input buffer is
262
+ // not allowed to exceed 65536 bytes, and can only
263
+ // be an integer-type TypedArray.
264
+ type DataType =
265
+ | Int8Array
266
+ | Int16Array
267
+ | Int32Array
268
+ | Uint8Array
269
+ | Uint16Array
270
+ | Uint32Array;
271
+ export function getRandomValues(data: DataType) {
272
+ if (data.byteLength > 65536) {
273
+ throw new Error('The requested length exceeds 65,536 bytes');
274
+ }
275
+ randomFillSync(data, 0);
276
+ return data;
277
+ }