11import { NativeModules } from 'react-native' ;
22import { Encryptor } from './Encryptor' ;
3- import { ENCRYPTION_LIBRARY , LEGACY_DERIVATION_PARAMS } from './constants' ;
3+ import { ENCRYPTION_LIBRARY , LEGACY_DERIVATION_OPTIONS } from './constants' ;
44
55const Aes = NativeModules . Aes ;
66const AesForked = NativeModules . AesForked ;
@@ -9,14 +9,12 @@ describe('Encryptor', () => {
99 let encryptor : Encryptor ;
1010
1111 beforeEach ( ( ) => {
12- encryptor = new Encryptor ( { derivationParams : LEGACY_DERIVATION_PARAMS } ) ;
12+ encryptor = new Encryptor ( {
13+ keyDerivationOptions : LEGACY_DERIVATION_OPTIONS ,
14+ } ) ;
1315 } ) ;
1416
1517 describe ( 'encrypt' , ( ) => {
16- afterEach ( ( ) => {
17- jest . clearAllMocks ( ) ;
18- } ) ;
19-
2018 it ( 'should encrypt an object correctly' , async ( ) => {
2119 const password = 'testPassword' ;
2220 const objectToEncrypt = { key : 'value' } ;
@@ -41,45 +39,36 @@ describe('Encryptor', () => {
4139 pbkdf2AesForkedSpy : jest . SpyInstance ;
4240
4341 beforeEach ( ( ) => {
44- decryptAesSpy = jest
45- . spyOn ( Aes , 'decrypt' )
46- . mockResolvedValue ( '{"mockData": "mockedPlainText"}' ) ;
47- pbkdf2AesSpy = jest
48- . spyOn ( Aes , 'pbkdf2' )
49- . mockResolvedValue ( 'mockedAesKey' ) ;
50- decryptAesForkedSpy = jest
51- . spyOn ( AesForked , 'decrypt' )
52- . mockResolvedValue ( '{"mockData": "mockedPlainText"}' ) ;
53- pbkdf2AesForkedSpy = jest
54- . spyOn ( AesForked , 'pbkdf2' )
55- . mockResolvedValue ( 'mockedAesForkedKey' ) ;
42+ decryptAesSpy = jest . spyOn ( Aes , 'decrypt' ) ;
43+ pbkdf2AesSpy = jest . spyOn ( Aes , 'pbkdf2' ) ;
44+ decryptAesForkedSpy = jest . spyOn ( AesForked , 'decrypt' ) ;
45+ pbkdf2AesForkedSpy = jest . spyOn ( AesForked , 'pbkdf2' ) ;
5646 } ) ;
5747
5848 afterEach ( ( ) => {
59- decryptAesSpy . mockRestore ( ) ;
60- pbkdf2AesSpy . mockRestore ( ) ;
61- decryptAesForkedSpy . mockRestore ( ) ;
62- pbkdf2AesForkedSpy . mockRestore ( ) ;
49+ jest . clearAllMocks ( ) ;
6350 } ) ;
6451
6552 it . each ( [
66- {
67- lib : ENCRYPTION_LIBRARY . original ,
68- expectedKey : 'mockedAesKey' ,
69- expectedPBKDF2Args : [ 'testPassword' , 'mockedSalt' , 5000 , 256 ] ,
70- description :
71- 'with original library and legacy iterations number for key generation' ,
72- } ,
73- {
74- lib : 'random-lib' , // Assuming not using "original" should lead to AesForked
75- expectedKey : 'mockedAesForkedKey' ,
76- expectedPBKDF2Args : [ 'testPassword' , 'mockedSalt' ] ,
77- description :
78- 'with library different to "original" and legacy iterations number for key generation' ,
79- } ,
53+ [
54+ 'with original library and legacy iterations number for key generation' ,
55+ {
56+ lib : ENCRYPTION_LIBRARY . original ,
57+ expectedKeyValue : 'mockedKey' ,
58+ expectedPBKDF2Args : [ 'testPassword' , 'mockedSalt' , 5000 , 256 ] ,
59+ } ,
60+ ] ,
61+ [
62+ 'with library different to "original" and legacy iterations number for key generation' ,
63+ {
64+ lib : 'random-lib' , // Assuming not using "original" should lead to AesForked
65+ expectedKeyValue : 'mockedKeyForked' ,
66+ expectedPBKDF2Args : [ 'testPassword' , 'mockedSalt' ] ,
67+ } ,
68+ ] ,
8069 ] ) (
81- 'decrypts a string correctly $description ' ,
82- async ( { lib, expectedKey , expectedPBKDF2Args } ) => {
70+ 'decrypts a string correctly %s ' ,
71+ async ( _ , { lib, expectedKeyValue , expectedPBKDF2Args } ) => {
8372 const password = 'testPassword' ;
8473 const mockVault = {
8574 cipher : 'mockedCipher' ,
@@ -98,7 +87,11 @@ describe('Encryptor', () => {
9887 lib === ENCRYPTION_LIBRARY . original
9988 ? decryptAesSpy
10089 : decryptAesForkedSpy ,
101- ) . toHaveBeenCalledWith ( mockVault . cipher , expectedKey , mockVault . iv ) ;
90+ ) . toHaveBeenCalledWith (
91+ mockVault . cipher ,
92+ expectedKeyValue ,
93+ mockVault . iv ,
94+ ) ;
10295 expect (
10396 lib === ENCRYPTION_LIBRARY . original
10497 ? pbkdf2AesSpy
@@ -117,7 +110,7 @@ describe('Encryptor', () => {
117110 iv : 'mockedIV' ,
118111 salt : 'mockedSalt' ,
119112 lib : 'original' ,
120- keyMetadata : LEGACY_DERIVATION_PARAMS ,
113+ keyMetadata : LEGACY_DERIVATION_OPTIONS ,
121114 } ) ,
122115 ) ,
123116 ) . toBe ( true ) ;
@@ -136,4 +129,153 @@ describe('Encryptor', () => {
136129 ) . toBe ( false ) ;
137130 } ) ;
138131 } ) ;
132+
133+ describe ( 'keyFromPassword' , ( ) => {
134+ it . each ( [
135+ [
136+ 'exportable with original lib' ,
137+ {
138+ lib : ENCRYPTION_LIBRARY . original ,
139+ exportable : true ,
140+ keyMetadata : LEGACY_DERIVATION_OPTIONS ,
141+ } ,
142+ ] ,
143+ [
144+ 'non-exportable with original lib' ,
145+ {
146+ lib : ENCRYPTION_LIBRARY . original ,
147+ exportable : false ,
148+ keyMetadata : LEGACY_DERIVATION_OPTIONS ,
149+ } ,
150+ ] ,
151+ [
152+ 'exportable with random lib' ,
153+ {
154+ lib : 'random-lib' ,
155+ exportable : true ,
156+ keyMetadata : LEGACY_DERIVATION_OPTIONS ,
157+ } ,
158+ ] ,
159+ [
160+ 'non-exportable with random lib' ,
161+ {
162+ lib : 'random-lib' ,
163+ exportable : false ,
164+ keyMetadata : LEGACY_DERIVATION_OPTIONS ,
165+ } ,
166+ ] ,
167+ ] ) (
168+ 'generates a key with the right attributes: %s' ,
169+ async ( _ , { lib, exportable, keyMetadata } ) => {
170+ const key = await encryptor . keyFromPassword (
171+ 'mockPassword' ,
172+ encryptor . generateSalt ( ) ,
173+ exportable ,
174+ keyMetadata ,
175+ lib ,
176+ ) ;
177+
178+ expect ( key . key ) . not . toBe ( undefined ) ;
179+ expect ( key . lib ) . toBe ( lib ) ;
180+ expect ( key . exportable ) . toBe ( exportable ) ;
181+ expect ( key . keyMetadata ) . toBe ( keyMetadata ) ;
182+ } ,
183+ ) ;
184+ } ) ;
185+
186+ describe ( 'exportKey' , ( ) => {
187+ it ( 'exports a key' , async ( ) => {
188+ const key = await encryptor . keyFromPassword (
189+ 'mockPassword' ,
190+ encryptor . generateSalt ( ) ,
191+ true ,
192+ ) ;
193+
194+ const exportedKey = await encryptor . exportKey ( key ) ;
195+ expect ( exportedKey ) . not . toBe ( undefined ) ;
196+ } ) ;
197+
198+ it ( 'does not export a key if not exportable' , async ( ) => {
199+ const key = await encryptor . keyFromPassword (
200+ 'mockPassword' ,
201+ encryptor . generateSalt ( ) ,
202+ false ,
203+ ) ;
204+
205+ expect ( async ( ) => await encryptor . exportKey ( key ) ) . rejects . toThrow (
206+ 'Key is not exportable' ,
207+ ) ;
208+ } ) ;
209+ } ) ;
210+
211+ describe ( 'importKey' , ( ) => {
212+ const serializeKey = ( data : object ) =>
213+ Buffer . from ( JSON . stringify ( data ) ) . toString ( 'base64' ) ;
214+
215+ it ( 'imports a key' , async ( ) => {
216+ const testKey = await encryptor . keyFromPassword (
217+ 'mockPassword' ,
218+ encryptor . generateSalt ( ) ,
219+ true ,
220+ ) ;
221+ const exportedKey = await encryptor . exportKey ( testKey ) ;
222+
223+ const key = await encryptor . importKey ( exportedKey ) ;
224+ expect ( key ) . toStrictEqual ( testKey ) ;
225+ } ) ;
226+
227+ it . each ( [
228+ '' ,
229+ '{}' ,
230+ Buffer . from ( '' ) . toString ( 'base64' ) ,
231+ Buffer . from ( '{ not: json }' ) . toString ( 'base64' ) ,
232+ ] ) ( 'does not import a bad serialized key: %s' , async ( badFormattedKey ) => {
233+ expect (
234+ async ( ) => await encryptor . importKey ( badFormattedKey ) ,
235+ ) . rejects . toThrow ( 'Invalid exported key serialization format' ) ;
236+ } ) ;
237+
238+ it . each ( [
239+ [
240+ 'missing lib' ,
241+ {
242+ exportable : true ,
243+ key : 'a-key' ,
244+ keyMetadata : LEGACY_DERIVATION_OPTIONS ,
245+ } ,
246+ ] ,
247+ [
248+ 'missing key' ,
249+ {
250+ lib : ENCRYPTION_LIBRARY . original ,
251+ exportable : true ,
252+ keyMetadata : LEGACY_DERIVATION_OPTIONS ,
253+ } ,
254+ ] ,
255+ [
256+ 'missing keyMetadata' ,
257+ {
258+ lib : ENCRYPTION_LIBRARY . original ,
259+ exportable : true ,
260+ key : 'a-key' ,
261+ } ,
262+ ] ,
263+ [
264+ 'invalid keyMetadata' ,
265+ {
266+ lib : ENCRYPTION_LIBRARY . original ,
267+ exportable : true ,
268+ key : 'a-key' ,
269+ keyMatadata : { } ,
270+ } ,
271+ ] ,
272+ ] ) (
273+ 'does not import a bad structured key: %s' ,
274+ async ( _ , badStructuredKey ) => {
275+ expect (
276+ async ( ) => await encryptor . importKey ( serializeKey ( badStructuredKey ) ) ,
277+ ) . rejects . toThrow ( 'Invalid exported key structure' ) ;
278+ } ,
279+ ) ;
280+ } ) ;
139281} ) ;
0 commit comments