2222import com .facebook .react .bridge .WritableNativeMap ;
2323import com .facebook .react .modules .core .DeviceEventManagerModule ;
2424
25+ import java .security .Key ;
2526import java .security .KeyStore ;
2627import java .util .HashMap ;
2728import java .util .Map ;
3031import javax .crypto .KeyGenerator ;
3132import javax .crypto .SecretKey ;
3233import javax .crypto .SecretKeyFactory ;
34+ import javax .crypto .spec .GCMParameterSpec ;
3335import javax .crypto .spec .IvParameterSpec ;
3436
3537import br .com .classapp .RNSensitiveInfo .utils .AppConstants ;
@@ -47,8 +49,12 @@ public class RNSensitiveInfoModule extends ReactContextBaseJavaModule {
4749 KeyProperties .BLOCK_MODE_CBC + "/" +
4850 KeyProperties .ENCRYPTION_PADDING_PKCS7 ;
4951
52+ private static final byte [] FIXED_IV = {0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 , 1 };
53+ private static final String KEY_ALIAS = "MySharedPreferenceKeyAlias" ;
5054 private static final String KEY_ALIAS_AES = "MyAesKeyAlias" ;
5155 private static final String DELIMITER = "]" ;
56+ private static final String AES_GCM = "AES/GCM/NoPadding" ;
57+ private static final String AES_ECB = "AES/ECB/PKCS7Padding" ;
5258
5359 private FingerprintManager mFingerprintManager ;
5460 private KeyStore mKeyStore ;
@@ -133,7 +139,11 @@ public void getItem(String key, ReadableMap options, Promise pm) {
133139
134140 decryptWithAes (value , showModal , strings , pm , null );
135141 } else {
136- pm .resolve (value );
142+ try {
143+ pm .resolve (decrypt (value ));
144+ } catch (Exception e ) {
145+ pm .reject (e );
146+ }
137147 }
138148 }
139149
@@ -149,7 +159,7 @@ public void setItem(String key, String value, ReadableMap options, Promise pm) {
149159 putExtraWithAES (key , value , prefs (name ), showModal , strings , pm , null );
150160 } else {
151161 try {
152- putExtra (key , value , prefs (name ));
162+ putExtra (key , encrypt ( value ) , prefs (name ));
153163 pm .resolve (value );
154164 } catch (Exception e ) {
155165 Log .d ("RNSensitiveInfo" , e .getCause ().getMessage ());
@@ -208,19 +218,9 @@ private String sharedPreferences(ReadableMap options) {
208218 }
209219
210220
211- private void putExtra (String key , Object value , SharedPreferences mSharedPreferences ) {
221+ private void putExtra (String key , String value , SharedPreferences mSharedPreferences ) {
212222 SharedPreferences .Editor editor = mSharedPreferences .edit ();
213- if (value instanceof String ) {
214- editor .putString (key , (String ) value ).apply ();
215- } else if (value instanceof Boolean ) {
216- editor .putBoolean (key , (Boolean ) value ).apply ();
217- } else if (value instanceof Integer ) {
218- editor .putInt (key , (Integer ) value ).apply ();
219- } else if (value instanceof Long ) {
220- editor .putLong (key , (Long ) value ).apply ();
221- } else if (value instanceof Float ) {
222- editor .putFloat (key , (Float ) value ).apply ();
223- }
223+ editor .putString (key , value ).apply ();
224224 }
225225
226226 /**
@@ -232,6 +232,17 @@ private void initKeyStore() {
232232 mKeyStore = KeyStore .getInstance (ANDROID_KEYSTORE_PROVIDER );
233233 mKeyStore .load (null );
234234
235+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
236+ KeyGenerator keyGenerator = KeyGenerator .getInstance (KeyProperties .KEY_ALGORITHM_AES , ANDROID_KEYSTORE_PROVIDER );
237+ keyGenerator .init (
238+ new KeyGenParameterSpec .Builder (KEY_ALIAS ,
239+ KeyProperties .PURPOSE_ENCRYPT | KeyProperties .PURPOSE_DECRYPT )
240+ .setBlockModes (KeyProperties .BLOCK_MODE_GCM )
241+ .setEncryptionPaddings (KeyProperties .ENCRYPTION_PADDING_NONE )
242+ .setRandomizedEncryptionRequired (false )
243+ .build ());
244+ keyGenerator .generateKey ();
245+ }
235246 // Check if a generated key exists under the KEY_ALIAS_AES .
236247 if (!mKeyStore .containsAlias (KEY_ALIAS_AES )) {
237248 prepareKey ();
@@ -244,6 +255,7 @@ private void prepareKey() throws Exception {
244255 if (android .os .Build .VERSION .SDK_INT < android .os .Build .VERSION_CODES .M ) {
245256 return ;
246257 }
258+
247259 KeyGenerator keyGenerator = KeyGenerator .getInstance (
248260 KeyProperties .KEY_ALGORITHM_AES , ANDROID_KEYSTORE_PROVIDER );
249261
@@ -477,4 +489,45 @@ public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult re
477489 pm .reject ("Fingerprint not supported" , "Fingerprint not supported" );
478490 }
479491 }
492+
493+ public String encrypt (String input ) throws Exception {
494+
495+ Key secretKey = ((KeyStore .SecretKeyEntry ) mKeyStore .getEntry (KEY_ALIAS , null )).getSecretKey ();
496+ byte [] bytes = input .getBytes ();
497+
498+ Cipher c ;
499+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
500+ c = Cipher .getInstance (AES_GCM );
501+ c .init (Cipher .ENCRYPT_MODE , secretKey , new GCMParameterSpec (128 , FIXED_IV ));
502+ } else {
503+ c = Cipher .getInstance (AES_ECB , "BC" );
504+ c .init (Cipher .ENCRYPT_MODE , secretKey );
505+ }
506+ byte [] encodedBytes = c .doFinal (bytes );
507+ String encryptedBase64Encoded = Base64 .encodeToString (encodedBytes , Base64 .DEFAULT );
508+ return encryptedBase64Encoded ;
509+ }
510+
511+
512+ public String decrypt (String encrypted ) throws Exception {
513+ if (encrypted == null ) {
514+ Exception cause = new RuntimeException ("Invalid argument at decrypt function" );
515+ throw new RuntimeException ("encrypted argument can't be null" , cause );
516+ }
517+
518+ Cipher c ;
519+ KeyStore keyStore = KeyStore .getInstance (ANDROID_KEYSTORE_PROVIDER );
520+ keyStore .load (null );
521+ Key secretKey = ((KeyStore .SecretKeyEntry ) mKeyStore .getEntry (KEY_ALIAS , null )).getSecretKey ();
522+
523+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
524+ c = Cipher .getInstance (AES_GCM );
525+ c .init (Cipher .DECRYPT_MODE , secretKey , new GCMParameterSpec (128 , FIXED_IV ));
526+ } else {
527+ c = Cipher .getInstance (AES_ECB , "BC" );
528+ c .init (Cipher .DECRYPT_MODE , secretKey );
529+ }
530+ byte [] decodedBytes = c .doFinal (Base64 .decode (encrypted , Base64 .DEFAULT ));
531+ return new String (decodedBytes );
532+ }
480533}
0 commit comments