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,44 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "react-native-quick-crypto"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["authors"]
12
+
13
+ s.platforms = { :ios => "11.0", :tvos => "12.0", :osx => "10.14" }
14
+ s.source = { :git => "https://github.com/mrousavy/react-native-quick-crypto.git", :tag => "#{s.version}" }
15
+
16
+ # All source files that should be publicly visible
17
+ # Note how this does not include headers, since those can nameclash.
18
+ s.source_files = [
19
+ "ios/**/*.{h,m,mm}",
20
+ "cpp/**/*.{h,c,cpp}",
21
+ "ios/QuickCryptoModule.h"
22
+ ]
23
+ # Any private headers that are not globally unique should be mentioned here.
24
+ # Otherwise there will be a nameclash, since CocoaPods flattens out any header directories
25
+ # See https://github.com/firebase/firebase-ios-sdk/issues/4035 for more details.
26
+ # s.preserve_paths = [
27
+ # 'ios/**/*.h',
28
+ # 'cpp/**/*.h'
29
+ # ]
30
+
31
+ s.pod_target_xcconfig = {
32
+ "USE_HEADERMAP" => "YES",
33
+ "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_TARGET_SRCROOT)\" \"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/boost-for-react-native\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/Headers/Private/React-Core\" "
34
+ }
35
+ s.xcconfig = {
36
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++14",
37
+ "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/boost-for-react-native\" \"$(PODS_ROOT)/glog\" \"${PODS_ROOT}/Headers/Public/React-hermes\" \"${PODS_ROOT}/Headers/Public/hermes-engine\""
38
+ }
39
+
40
+ s.dependency "OpenSSL-Universal", "~> 1.1.1300"
41
+ s.dependency "React-Core"
42
+ s.dependency "React"
43
+ s.dependency "React-callinvoker"
44
+ end
package/src/Cipher.ts ADDED
@@ -0,0 +1,322 @@
1
+ /* eslint-disable no-dupe-class-members */
2
+ import { NativeQuickCrypto } from './NativeQuickCrypto/NativeQuickCrypto';
3
+ import Stream from 'stream';
4
+ import {
5
+ BinaryLike,
6
+ binaryLikeToArrayBuffer,
7
+ CipherEncoding,
8
+ Encoding,
9
+ getDefaultEncoding,
10
+ } from './Utils';
11
+ import type { InternalCipher } from './NativeQuickCrypto/Cipher';
12
+ // TODO(osp) re-enable type specific constructors
13
+ // They are nice to have but not absolutely necessary
14
+ // import type {
15
+ // CipherCCMOptions,
16
+ // CipherCCMTypes,
17
+ // CipherGCMTypes,
18
+ // CipherGCMOptions,
19
+ // // CipherKey,
20
+ // // KeyObject,
21
+ // // TODO @Szymon20000 This types seem to be missing? Where did you get this definitions from?
22
+ // // CipherOCBTypes,
23
+ // // CipherOCBOptions,
24
+ // } from 'crypto'; // Node crypto typings
25
+ import { StringDecoder } from 'string_decoder';
26
+ import type { Buffer } from '@craftzdog/react-native-buffer';
27
+ import { Buffer as SBuffer } from 'safe-buffer';
28
+
29
+ const createInternalCipher = NativeQuickCrypto.createCipher;
30
+ const createInternalDecipher = NativeQuickCrypto.createDecipher;
31
+
32
+ function getUIntOption(options: Record<string, any>, key: string) {
33
+ let value;
34
+ if (options && (value = options[key]) != null) {
35
+ // >>> Turns any type into a positive integer (also sets the sign bit to 0)
36
+ // eslint-disable-next-line no-bitwise
37
+ if (value >>> 0 !== value) throw new Error(`options.${key}: ${value}`);
38
+ return value;
39
+ }
40
+ return -1;
41
+ }
42
+
43
+ function normalizeEncoding(enc: string) {
44
+ if (!enc) return 'utf8';
45
+ var retried;
46
+ while (true) {
47
+ switch (enc) {
48
+ case 'utf8':
49
+ case 'utf-8':
50
+ return 'utf8';
51
+ case 'ucs2':
52
+ case 'ucs-2':
53
+ case 'utf16le':
54
+ case 'utf-16le':
55
+ return 'utf16le';
56
+ case 'latin1':
57
+ case 'binary':
58
+ return 'latin1';
59
+ case 'base64':
60
+ case 'ascii':
61
+ case 'hex':
62
+ return enc;
63
+ default:
64
+ if (retried) return; // undefined
65
+ enc = ('' + enc).toLowerCase();
66
+ retried = true;
67
+ }
68
+ }
69
+ }
70
+
71
+ function validateEncoding(data: string, encoding: string) {
72
+ const normalizedEncoding = normalizeEncoding(encoding);
73
+ const length = data.length;
74
+
75
+ if (normalizedEncoding === 'hex' && length % 2 !== 0) {
76
+ throw new Error(`Encoding ${encoding} not valid for data length ${length}`);
77
+ }
78
+ }
79
+
80
+ function getDecoder(decoder?: StringDecoder, encoding?: BufferEncoding) {
81
+ return decoder ?? new StringDecoder(encoding);
82
+ }
83
+
84
+ class CipherCommon extends Stream.Transform {
85
+ private internal: InternalCipher;
86
+ private decoder: StringDecoder | undefined;
87
+
88
+ constructor(
89
+ cipherType: string,
90
+ cipherKey: BinaryLike,
91
+ isCipher: boolean,
92
+ options: Record<string, any> = {},
93
+ iv?: BinaryLike | null
94
+ ) {
95
+ super(options);
96
+ const cipherKeyBuffer = binaryLikeToArrayBuffer(cipherKey);
97
+ // TODO(osp) This might not be smart, check again after release
98
+ const authTagLength = getUIntOption(options, 'authTagLength');
99
+ const args = {
100
+ cipher_type: cipherType,
101
+ cipher_key: cipherKeyBuffer,
102
+ iv,
103
+ ...options,
104
+ auth_tag_len: authTagLength,
105
+ };
106
+ this.internal = isCipher
107
+ ? createInternalCipher(args)
108
+ : createInternalDecipher(args);
109
+ }
110
+
111
+ update(
112
+ data: BinaryLike,
113
+ inputEncoding?: CipherEncoding,
114
+ outputEncoding?: CipherEncoding
115
+ ): ArrayBuffer | string {
116
+ const defaultEncoding = getDefaultEncoding();
117
+ inputEncoding = inputEncoding ?? defaultEncoding;
118
+ outputEncoding = outputEncoding ?? defaultEncoding;
119
+
120
+ if (typeof data === 'string') {
121
+ validateEncoding(data, inputEncoding);
122
+ } else if (!ArrayBuffer.isView(data)) {
123
+ throw new Error('Invalid data argument');
124
+ }
125
+
126
+ if (typeof data === 'string') {
127
+ // On node this is handled on the native side
128
+ // on our case we need to correctly send the arraybuffer to the jsi side
129
+ inputEncoding = inputEncoding === 'buffer' ? 'utf8' : inputEncoding;
130
+ data = binaryLikeToArrayBuffer(data, inputEncoding);
131
+ } else {
132
+ data = binaryLikeToArrayBuffer(data as any, inputEncoding);
133
+ }
134
+
135
+ const ret = this.internal.update(data);
136
+
137
+ if (outputEncoding && outputEncoding !== 'buffer') {
138
+ this.decoder = getDecoder(this.decoder, outputEncoding);
139
+
140
+ return this.decoder!.write(SBuffer.from(ret) as any);
141
+ }
142
+
143
+ return ret;
144
+ }
145
+
146
+ final(): ArrayBuffer;
147
+ final(outputEncoding: BufferEncoding | 'buffer'): string;
148
+ final(outputEncoding?: BufferEncoding | 'buffer'): ArrayBuffer | string {
149
+ const ret = this.internal.final();
150
+
151
+ if (outputEncoding && outputEncoding !== 'buffer') {
152
+ this.decoder = getDecoder(this.decoder, outputEncoding);
153
+
154
+ return this.decoder!.end(SBuffer.from(ret) as any);
155
+ }
156
+
157
+ return ret;
158
+ }
159
+
160
+ _transform(chunk: BinaryLike, encoding: Encoding, callback: () => void) {
161
+ this.push(this.update(chunk, encoding));
162
+ callback();
163
+ }
164
+
165
+ _flush(callback: () => void) {
166
+ this.push(this.final());
167
+ callback();
168
+ }
169
+
170
+ public setAutoPadding(autoPadding?: boolean): this {
171
+ this.internal.setAutoPadding(!!autoPadding);
172
+ return this;
173
+ }
174
+
175
+ public setAAD(
176
+ buffer: Buffer,
177
+ options?: {
178
+ plaintextLength: number;
179
+ }
180
+ ): this {
181
+ this.internal.setAAD({
182
+ data: buffer.buffer,
183
+ plaintextLength: options?.plaintextLength,
184
+ });
185
+ return this;
186
+ }
187
+
188
+ // protected getAuthTag(): Buffer {
189
+ // return Buffer.from(this.internal.getAuthTag());
190
+ // }
191
+
192
+ public setAuthTag(tag: Buffer): this {
193
+ this.internal.setAuthTag(tag.buffer);
194
+ return this;
195
+ }
196
+ }
197
+
198
+ class Cipher extends CipherCommon {
199
+ constructor(
200
+ cipherType: string,
201
+ cipherKey: BinaryLike,
202
+ options: Record<string, any> = {},
203
+ iv?: BinaryLike | null
204
+ ) {
205
+ if (iv != null) {
206
+ iv = binaryLikeToArrayBuffer(iv);
207
+ }
208
+ super(cipherType, cipherKey, true, options, iv);
209
+ }
210
+ }
211
+
212
+ class Decipher extends CipherCommon {
213
+ constructor(
214
+ cipherType: string,
215
+ cipherKey: BinaryLike,
216
+ options: Record<string, any> = {},
217
+ iv?: BinaryLike | null
218
+ ) {
219
+ if (iv != null) {
220
+ iv = binaryLikeToArrayBuffer(iv);
221
+ }
222
+
223
+ super(cipherType, cipherKey, false, options, iv);
224
+ }
225
+ }
226
+
227
+ // TODO(osp) This definitions cause typescript errors when using the API
228
+ // export function createDecipher(
229
+ // algorithm: CipherCCMTypes,
230
+ // password: BinaryLike,
231
+ // options: CipherCCMOptions
232
+ // ): Decipher;
233
+ // export function createDecipher(
234
+ // algorithm: CipherGCMTypes,
235
+ // password: BinaryLike,
236
+ // options?: CipherGCMOptions
237
+ // ): Decipher;
238
+ export function createDecipher(
239
+ algorithm: string,
240
+ password: BinaryLike,
241
+ options?: Stream.TransformOptions
242
+ ): Decipher {
243
+ return new Decipher(algorithm, password, options);
244
+ }
245
+
246
+ // TODO(osp) This definitions cause typescript errors when using the API
247
+ // export function createDecipheriv(
248
+ // algorithm: CipherCCMTypes,
249
+ // key: BinaryLike,
250
+ // iv: BinaryLike,
251
+ // options: CipherCCMOptions
252
+ // ): Decipher;
253
+ // export function createDecipheriv(
254
+ // algorithm: CipherOCBTypes,
255
+ // key: BinaryLike,
256
+ // iv: BinaryLike,
257
+ // options: CipherOCBOptions
258
+ // ): DecipherOCB;
259
+ // export function createDecipheriv(
260
+ // algorithm: CipherGCMTypes,
261
+ // key: BinaryLike,
262
+ // iv: BinaryLike,
263
+ // options?: CipherGCMOptions
264
+ // ): Decipher;
265
+ export function createDecipheriv(
266
+ algorithm: string,
267
+ key: BinaryLike,
268
+ iv: BinaryLike | null,
269
+ options?: Stream.TransformOptions
270
+ ): Decipher {
271
+ return new Decipher(algorithm, key, options, iv);
272
+ }
273
+
274
+ // TODO(osp) This definitions cause typescript errors when using the API
275
+ // commenting them out for now
276
+ // export function createCipher(
277
+ // algorithm: CipherCCMTypes,
278
+ // password: BinaryLike,
279
+ // options: CipherCCMOptions
280
+ // ): Cipher;
281
+ // export function createCipher(
282
+ // algorithm: CipherGCMTypes,
283
+ // password: BinaryLike,
284
+ // options?: CipherGCMOptions
285
+ // ): Cipher;
286
+ export function createCipher(
287
+ algorithm: string,
288
+ password: BinaryLike,
289
+ options?: Stream.TransformOptions
290
+ ): Cipher {
291
+ return new Cipher(algorithm, password, options);
292
+ }
293
+
294
+ // TODO(osp) on all the createCipheriv methods, node seems to use a "KeyObject" is seems to be a thread safe
295
+ // object that creates keys and what not. Not sure if we should support it.
296
+ // Fow now I replaced all of them to BinaryLike
297
+ // export function createCipheriv(
298
+ // algorithm: CipherCCMTypes,
299
+ // key: BinaryLike,
300
+ // iv: BinaryLike,
301
+ // options: CipherCCMOptions
302
+ // ): Cipher;
303
+ // export function createCipheriv(
304
+ // algorithm: CipherOCBTypes,
305
+ // key: BinaryLike,
306
+ // iv: BinaryLike,
307
+ // options: CipherOCBOptions
308
+ // ): CipherOCB;
309
+ // export function createCipheriv(
310
+ // algorithm: CipherGCMTypes,
311
+ // key: BinaryLike,
312
+ // iv: BinaryLike,
313
+ // options?: CipherGCMOptions
314
+ // ): Cipher;
315
+ export function createCipheriv(
316
+ algorithm: string,
317
+ key: BinaryLike,
318
+ iv: BinaryLike | null,
319
+ options?: Stream.TransformOptions
320
+ ): Cipher {
321
+ return new Cipher(algorithm, key, options, iv);
322
+ }
package/src/Hash.ts ADDED
@@ -0,0 +1,98 @@
1
+ /* eslint-disable no-dupe-class-members */
2
+ import 'react-native';
3
+ import { NativeQuickCrypto } from './NativeQuickCrypto/NativeQuickCrypto';
4
+ import type { InternalHash } from './NativeQuickCrypto/hash';
5
+ import { Encoding, toArrayBuffer } from './Utils';
6
+ import Stream from 'stream';
7
+ import { Buffer } from '@craftzdog/react-native-buffer';
8
+ interface HashOptionsBase extends Stream.TransformOptions {
9
+ outputLength?: number | undefined;
10
+ }
11
+
12
+ type HashOptions = null | undefined | HashOptionsBase;
13
+
14
+ global.process.nextTick = setImmediate;
15
+
16
+ const createInternalHash = NativeQuickCrypto.createHash;
17
+
18
+ type BinaryLike = ArrayBuffer;
19
+
20
+ export function createHash(algorithm: string, options?: HashOptions) {
21
+ return new Hash(algorithm, options);
22
+ }
23
+
24
+ class Hash extends Stream.Transform {
25
+ private internalHash: InternalHash;
26
+
27
+ constructor(other: Hash, options?: HashOptions);
28
+ constructor(algorithm: string, options?: HashOptions);
29
+ constructor(arg: string | Hash, options?: HashOptions) {
30
+ super(options ?? undefined);
31
+ if (arg instanceof Hash) {
32
+ this.internalHash = arg.internalHash.copy(options?.outputLength);
33
+ } else {
34
+ this.internalHash = createInternalHash(arg, options?.outputLength);
35
+ }
36
+ }
37
+
38
+ copy(options?: HashOptionsBase): Hash {
39
+ const copy = new Hash(this, options);
40
+ return copy;
41
+ }
42
+ /**
43
+ * Updates the hash content with the given `data`, the encoding of which
44
+ * is given in `inputEncoding`.
45
+ * If `encoding` is not provided, and the `data` is a string, an
46
+ * encoding of `'utf8'` is enforced. If `data` is a `Buffer`, `TypedArray`, or`DataView`, then `inputEncoding` is ignored.
47
+ *
48
+ * This can be called many times with new data as it is streamed.
49
+ * @since v0.1.92
50
+ * @param inputEncoding The `encoding` of the `data` string.
51
+ */
52
+ update(data: string | BinaryLike, inputEncoding?: Encoding): Hash {
53
+ if (data instanceof ArrayBuffer) {
54
+ this.internalHash.update(data);
55
+ return this;
56
+ }
57
+ const buffer = Buffer.from(data, inputEncoding);
58
+ this.internalHash.update(toArrayBuffer(buffer));
59
+ return this;
60
+ }
61
+
62
+ _transform(
63
+ chunk: string | BinaryLike,
64
+ encoding: Encoding,
65
+ callback: () => void
66
+ ) {
67
+ this.update(chunk, encoding);
68
+ callback();
69
+ }
70
+
71
+ _flush(callback: () => void) {
72
+ this.push(this.digest());
73
+ callback();
74
+ }
75
+
76
+ /**
77
+ * Calculates the digest of all of the data passed to be hashed (using the `hash.update()` method).
78
+ * If `encoding` is provided a string will be returned; otherwise
79
+ * a `Buffer` is returned.
80
+ *
81
+ * The `Hash` object can not be used again after `hash.digest()` method has been
82
+ * called. Multiple calls will cause an error to be thrown.
83
+ * @since v0.1.92
84
+ * @param encoding The `encoding` of the return value.
85
+ */
86
+ digest(): Buffer;
87
+ digest(encoding: 'buffer'): Buffer;
88
+ digest(encoding: Encoding): string;
89
+ digest(encoding?: Encoding | 'buffer'): string | Buffer {
90
+ const result: ArrayBuffer = this.internalHash.digest();
91
+
92
+ if (encoding && encoding !== 'buffer') {
93
+ return Buffer.from(result).toString(encoding);
94
+ }
95
+
96
+ return Buffer.from(result);
97
+ }
98
+ }
package/src/Hmac.ts ADDED
@@ -0,0 +1,107 @@
1
+ /* eslint-disable no-dupe-class-members */
2
+ import { NativeQuickCrypto } from './NativeQuickCrypto/NativeQuickCrypto';
3
+ import type { InternalHmac } from './NativeQuickCrypto/hmac';
4
+ import {
5
+ Encoding,
6
+ toArrayBuffer,
7
+ BinaryLike,
8
+ binaryLikeToArrayBuffer,
9
+ } from './Utils';
10
+ import Stream from 'stream';
11
+ import { Buffer } from '@craftzdog/react-native-buffer';
12
+
13
+ const createInternalHmac = NativeQuickCrypto.createHmac;
14
+
15
+ export function createHmac(
16
+ algorithm: string,
17
+ key: BinaryLike,
18
+ options?: Stream.TransformOptions
19
+ ) {
20
+ return new Hmac(algorithm, key, options);
21
+ }
22
+
23
+ class Hmac extends Stream.Transform {
24
+ private internalHmac: InternalHmac;
25
+ private isFinalized: boolean = false;
26
+
27
+ constructor(
28
+ algorithm: string,
29
+ key: BinaryLike,
30
+ _options?: Stream.TransformOptions
31
+ ) {
32
+ super();
33
+ let keyAsString = binaryLikeToArrayBuffer(key);
34
+
35
+ if (keyAsString === undefined) {
36
+ throw 'Wrong key type';
37
+ }
38
+
39
+ this.internalHmac = createInternalHmac(
40
+ algorithm,
41
+ keyAsString as ArrayBuffer
42
+ );
43
+ }
44
+
45
+ /**
46
+ * Updates the `Hmac` content with the given `data`, the encoding of which
47
+ * is given in `inputEncoding`.
48
+ * If `encoding` is not provided, and the `data` is a string, an
49
+ * encoding of `'utf8'` is enforced. If `data` is a `Buffer`, `TypedArray`, or`DataView`, then `inputEncoding` is ignored.
50
+ *
51
+ * This can be called many times with new data as it is streamed.
52
+ * @since v0.1.94
53
+ * @param inputEncoding The `encoding` of the `data` string.
54
+ */
55
+ update(data: string | BinaryLike, inputEncoding?: Encoding): Hmac {
56
+ if (data instanceof ArrayBuffer) {
57
+ this.internalHmac.update(data);
58
+ return this;
59
+ }
60
+ if (typeof data === 'string') {
61
+ const buffer = Buffer.from(data, inputEncoding);
62
+ this.internalHmac.update(toArrayBuffer(buffer));
63
+ return this;
64
+ }
65
+
66
+ this.internalHmac.update(binaryLikeToArrayBuffer(data));
67
+ return this;
68
+ }
69
+
70
+ _transform(
71
+ chunk: string | BinaryLike,
72
+ encoding: Encoding,
73
+ callback: () => void
74
+ ) {
75
+ this.update(chunk, encoding);
76
+ callback();
77
+ }
78
+
79
+ _flush(callback: () => void) {
80
+ this.push(this.digest());
81
+ callback();
82
+ }
83
+
84
+ /**
85
+ * Calculates the HMAC digest of all of the data passed using `hmac.update()`.
86
+ * If `encoding` is
87
+ * provided a string is returned; otherwise a `Buffer` is returned;
88
+ *
89
+ * The `Hmac` object can not be used again after `hmac.digest()` has been
90
+ * called. Multiple calls to `hmac.digest()` will result in an error being thrown.
91
+ * @since v0.1.94
92
+ * @param encoding The `encoding` of the return value.
93
+ */
94
+ digest(): Buffer;
95
+ digest(encoding: 'buffer'): Buffer;
96
+ digest(encoding: Encoding): string;
97
+ digest(encoding?: Encoding | 'buffer'): string | Buffer {
98
+ const result: ArrayBuffer = this.isFinalized
99
+ ? new ArrayBuffer(0)
100
+ : this.internalHmac.digest();
101
+ this.isFinalized = true;
102
+ if (encoding && encoding !== 'buffer') {
103
+ return Buffer.from(result).toString(encoding);
104
+ }
105
+ return Buffer.from(result);
106
+ }
107
+ }
@@ -0,0 +1,25 @@
1
+ import type { BinaryLike } from 'src/Utils';
2
+
3
+ export type InternalCipher = {
4
+ update: (data: BinaryLike | ArrayBufferView) => ArrayBuffer;
5
+ final: () => ArrayBuffer;
6
+ copy: () => void;
7
+ setAAD: (args: {
8
+ data: BinaryLike;
9
+ plaintextLength?: number;
10
+ }) => InternalCipher;
11
+ setAutoPadding: (autoPad: boolean) => boolean;
12
+ setAuthTag: (tag: ArrayBuffer) => boolean;
13
+ };
14
+
15
+ export type CreateCipherMethod = (params: {
16
+ cipher_type: string;
17
+ cipher_key: ArrayBuffer;
18
+ auth_tag_len: number;
19
+ }) => InternalCipher;
20
+
21
+ export type CreateDecipherMethod = (params: {
22
+ cipher_type: string;
23
+ cipher_key: ArrayBuffer;
24
+ auth_tag_len: number;
25
+ }) => InternalCipher;
@@ -0,0 +1,79 @@
1
+ import { NativeModules, Platform } from 'react-native';
2
+ import type { CreateHmacMethod } from './hmac';
3
+ import type { CreateHashMethod } from './hash';
4
+ import type { Pbkdf2Object } from './pbkdf2';
5
+ import type { RandomObject } from './random';
6
+ import type { CreateCipherMethod, CreateDecipherMethod } from './Cipher';
7
+
8
+ interface NativeQuickCryptoSpec {
9
+ createHmac: CreateHmacMethod;
10
+ pbkdf2: Pbkdf2Object;
11
+ random: RandomObject;
12
+ createHash: CreateHashMethod;
13
+ createCipher: CreateCipherMethod;
14
+ createDecipher: CreateDecipherMethod;
15
+ }
16
+
17
+ // global func declaration for JSI functions
18
+ declare global {
19
+ function nativeCallSyncHook(): unknown;
20
+ var __QuickCryptoProxy: object | undefined;
21
+ }
22
+
23
+ // Check if the constructor exists. If not, try installing the JSI bindings.
24
+ if (global.__QuickCryptoProxy == null) {
25
+ // Get the native QuickCrypto ReactModule
26
+ const QuickCryptoModule = NativeModules.QuickCrypto;
27
+ if (QuickCryptoModule == null) {
28
+ let message =
29
+ 'Failed to install react-native-quick-crypto: The native `QuickCrypto` Module could not be found.';
30
+ message +=
31
+ '\n* Make sure react-native-quick-crypto is correctly autolinked (run `npx react-native config` to verify)';
32
+ if (Platform.OS === 'ios' || Platform.OS === 'macos') {
33
+ message += '\n* Make sure you ran `pod install` in the ios/ directory.';
34
+ }
35
+ if (Platform.OS === 'android') {
36
+ message += '\n* Make sure gradle is synced.';
37
+ }
38
+ // check if Expo
39
+ const ExpoConstants =
40
+ NativeModules.NativeUnimoduleProxy?.modulesConstants?.ExponentConstants;
41
+ if (ExpoConstants != null) {
42
+ if (ExpoConstants.appOwnership === 'expo') {
43
+ // We're running Expo Go
44
+ throw new Error(
45
+ 'react-native-quick-crypto is not supported in Expo Go! Use EAS (`expo prebuild`) or eject to a bare workflow instead.'
46
+ );
47
+ } else {
48
+ // We're running Expo bare / standalone
49
+ message += '\n* Make sure you ran `expo prebuild`.';
50
+ }
51
+ }
52
+
53
+ message += '\n* Make sure you rebuilt the app.';
54
+ throw new Error(message);
55
+ }
56
+
57
+ // Check if we are running on-device (JSI)
58
+ if (global.nativeCallSyncHook == null || QuickCryptoModule.install == null) {
59
+ throw new Error(
60
+ 'Failed to install react-native-quick-crypto: React Native is not running on-device. QuickCrypto can only be used when synchronous method invocations (JSI) are possible. If you are using a remote debugger (e.g. Chrome), switch to an on-device debugger (e.g. Flipper) instead.'
61
+ );
62
+ }
63
+
64
+ // Call the synchronous blocking install() function
65
+ const result = QuickCryptoModule.install();
66
+ if (result !== true)
67
+ throw new Error(
68
+ `Failed to install react-native-quick-crypto: The native QuickCrypto Module could not be installed! Looks like something went wrong when installing JSI bindings: ${result}`
69
+ );
70
+
71
+ // Check again if the constructor now exists. If not, throw an error.
72
+ if (global.__QuickCryptoProxy == null)
73
+ throw new Error(
74
+ 'Failed to install react-native-quick-crypto, the native initializer function does not exist. Are you trying to use QuickCrypto from different JS Runtimes?'
75
+ );
76
+ }
77
+
78
+ const proxy = global.__QuickCryptoProxy;
79
+ export const NativeQuickCrypto = proxy as any as NativeQuickCryptoSpec;
@@ -0,0 +1,10 @@
1
+ export type InternalHash = {
2
+ update: (data: ArrayBuffer) => InternalHash;
3
+ digest: () => ArrayBuffer;
4
+ copy: (len?: number) => InternalHash;
5
+ };
6
+
7
+ export type CreateHashMethod = (
8
+ algorithm: string,
9
+ outputLength?: number
10
+ ) => InternalHash;
@@ -0,0 +1,9 @@
1
+ export type InternalHmac = {
2
+ update: (data: ArrayBuffer) => InternalHmac;
3
+ digest: () => ArrayBuffer;
4
+ };
5
+
6
+ export type CreateHmacMethod = (
7
+ algorithm: string,
8
+ key?: ArrayBuffer
9
+ ) => InternalHmac;