Skip to content

Commit 2ac4d17

Browse files
authored
Merge pull request #22 from npomfret/master
made `sharedPreferencesName` optional (and some other clean up)
2 parents 90883d5 + 8aaa5e0 commit 2ac4d17

3 files changed

Lines changed: 96 additions & 94 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,6 @@ example/node_modules
3535

3636
# Optional REPL history
3737
.node_repl_history
38+
39+
android/build/
40+
android/local.properties

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ android {
55
buildToolsVersion "23.0.2"
66

77
defaultConfig {
8-
minSdkVersion 18
8+
minSdkVersion 16
99
targetSdkVersion 23
1010
versionCode 1
1111
versionName "1.0"

android/src/main/java/br/com/classapp/RNSensitiveInfo/RNSensitiveInfoModule.java

Lines changed: 92 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,17 @@
66
import android.security.KeyPairGeneratorSpec;
77
import android.security.keystore.KeyGenParameterSpec;
88
import android.security.keystore.KeyProperties;
9+
import android.support.annotation.NonNull;
910
import android.util.Base64;
1011
import android.util.Log;
1112

12-
import com.facebook.react.bridge.*;
13+
import com.facebook.react.bridge.Promise;
14+
import com.facebook.react.bridge.ReactApplicationContext;
15+
import com.facebook.react.bridge.ReactContextBaseJavaModule;
16+
import com.facebook.react.bridge.ReactMethod;
17+
import com.facebook.react.bridge.ReadableMap;
18+
import com.facebook.react.bridge.WritableMap;
19+
import com.facebook.react.bridge.WritableNativeMap;
1320

1421
import java.io.ByteArrayInputStream;
1522
import java.io.ByteArrayOutputStream;
@@ -31,19 +38,18 @@
3138
import javax.security.auth.x500.X500Principal;
3239

3340
public class RNSensitiveInfoModule extends ReactContextBaseJavaModule {
34-
35-
private SharedPreferences mSharedPreferences;
41+
3642
private static final String AndroidKeyStore = "AndroidKeyStore";
37-
private static final String RSA_MODE = "RSA/ECB/PKCS1Padding";
43+
private static final String RSA_MODE = "RSA/ECB/PKCS1Padding";
3844
private static final String AES_GCM = "AES/GCM/NoPadding";
3945
private static final String AES_ECB = "AES/ECB/PKCS7Padding";
4046
private static KeyStore keyStore;
4147
private static final String KEY_ALIAS = "SHARED_PREFERENCE_KEY";
4248
private static final String ENCRYPTED_KEY = "ENCRYPTED_KEY";
4349
private static final String ENCRYPTION_SHARED_PREFERENCE_NAME = "ENCRYPTION_SHARED_PREFERENCE";
44-
private static final byte[] FIXED_IV = {0,1,2,3,4,5,6,7,8,9,0,1};
50+
private static final byte[] FIXED_IV = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1};
4551
private static Key secretKey;
46-
52+
4753
public RNSensitiveInfoModule(ReactApplicationContext reactContext) {
4854
super(reactContext);
4955
try {
@@ -52,85 +58,65 @@ public RNSensitiveInfoModule(ReactApplicationContext reactContext) {
5258
Log.d("RNSensitiveInfo", e.getCause().getMessage());
5359
}
5460
}
55-
61+
5662
@Override
5763
public String getName() {
5864
return "RNSensitiveInfo";
5965
}
60-
66+
6167
@ReactMethod
6268
public void getItem(String key, ReadableMap options, Promise pm) {
63-
64-
String name = options.getString("sharedPreferencesName");
65-
if (name == null) {
66-
name = "app";
67-
}
68-
69-
mSharedPreferences = getReactApplicationContext().getSharedPreferences(name, Context.MODE_PRIVATE);
70-
String value = mSharedPreferences.getString(key, null);
71-
if(value != null){
72-
try{
69+
70+
String name = sharedPreferences(options);
71+
72+
String value = prefs(name).getString(key, null);
73+
if (value != null) {
74+
try {
7375
value = decrypt(value);
7476
} catch (Exception e) {
7577
Log.d("RNSensitiveInfo", e.getCause().getMessage());
7678
}
7779
}
78-
80+
7981
pm.resolve(value);
8082
}
81-
83+
8284
@ReactMethod
8385
public void setItem(String key, String value, ReadableMap options, Promise pm) {
84-
85-
String name = options.getString("sharedPreferencesName");
86-
if (name == null) {
87-
name = "app";
88-
}
89-
90-
mSharedPreferences = getReactApplicationContext().getSharedPreferences(name, Context.MODE_PRIVATE);
91-
86+
87+
String name = sharedPreferences(options);
88+
9289
try {
93-
putExtra(key, value, mSharedPreferences);
90+
putExtra(key, value, prefs(name));
9491
pm.resolve(null);
9592
} catch (Exception e) {
9693
Log.d("RNSensitiveInfo", e.getCause().getMessage());
9794
pm.reject(e);
9895
}
9996
}
100-
101-
97+
98+
10299
@ReactMethod
103100
public void deleteItem(String key, ReadableMap options, Promise pm) {
104-
105-
String name = options.getString("sharedPreferencesName");
106-
if (name == null) {
107-
name = "app";
108-
}
109-
110-
mSharedPreferences = getReactApplicationContext().getSharedPreferences(name, Context.MODE_PRIVATE);
111-
112-
SharedPreferences.Editor editor = mSharedPreferences.edit();
113-
101+
102+
String name = sharedPreferences(options);
103+
104+
SharedPreferences.Editor editor = prefs(name).edit();
105+
114106
editor.remove(key).apply();
115-
107+
116108
pm.resolve(null);
117109
}
118-
119-
120-
110+
111+
121112
@ReactMethod
122113
public void getAllItems(ReadableMap options, Promise pm) {
123-
124-
String name = options.getString("sharedPreferencesName");
125-
if (name == null) {
126-
name = "app";
127-
}
128-
129-
mSharedPreferences = getReactApplicationContext().getSharedPreferences(name, Context.MODE_PRIVATE);
130-
131-
Map<String, ?> allEntries = mSharedPreferences.getAll();
114+
115+
String name = sharedPreferences(options);
116+
117+
Map<String, ?> allEntries = prefs(name).getAll();
132118
WritableMap resultData = new WritableNativeMap();
133-
119+
134120
for (Map.Entry<String, ?> entry : allEntries.entrySet()) {
135121
String value = entry.getValue().toString();
136122
try {
@@ -142,14 +128,27 @@ public void getAllItems(ReadableMap options, Promise pm) {
142128
}
143129
pm.resolve(resultData);
144130
}
145-
131+
132+
private SharedPreferences prefs(String name) {
133+
return getReactApplicationContext().getSharedPreferences(name, Context.MODE_PRIVATE);
134+
}
135+
136+
@NonNull
137+
private String sharedPreferences(ReadableMap options) {
138+
String name = options.hasKey("sharedPreferencesName") ? options.getString("sharedPreferencesName") : "app";
139+
if (name == null) {
140+
name = "app";
141+
}
142+
return name;
143+
}
144+
146145
private void putExtra(String key, String value, SharedPreferences mSharedPreferences) throws Exception {
147146
SharedPreferences.Editor editor = mSharedPreferences.edit();
148147
String encrypted = encrypt(value);
149148
editor.putString(key, encrypted).apply();
150149
}
151-
152-
private void initKeyStore(Context context) throws Exception{
150+
151+
private void initKeyStore(Context context) throws Exception {
153152
keyStore = KeyStore.getInstance(AndroidKeyStore);
154153
keyStore.load(null);
155154
// Generate the RSA key pairs
@@ -158,31 +157,31 @@ private void initKeyStore(Context context) throws Exception{
158157
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
159158
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, AndroidKeyStore);
160159
keyGenerator.init(
161-
new KeyGenParameterSpec.Builder(KEY_ALIAS,
162-
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
163-
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
164-
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
165-
.setRandomizedEncryptionRequired(false)
166-
.build());
160+
new KeyGenParameterSpec.Builder(KEY_ALIAS,
161+
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
162+
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
163+
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
164+
.setRandomizedEncryptionRequired(false)
165+
.build());
167166
keyGenerator.generateKey();
168167
} else {
169168
Calendar start = Calendar.getInstance();
170169
Calendar end = Calendar.getInstance();
171170
end.add(Calendar.YEAR, 30);
172171
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
173-
.setAlias(KEY_ALIAS)
174-
.setSubject(new X500Principal("CN=" + KEY_ALIAS))
175-
.setSerialNumber(BigInteger.TEN)
176-
.setStartDate(start.getTime())
177-
.setEndDate(end.getTime())
178-
.build();
172+
.setAlias(KEY_ALIAS)
173+
.setSubject(new X500Principal("CN=" + KEY_ALIAS))
174+
.setSerialNumber(BigInteger.TEN)
175+
.setStartDate(start.getTime())
176+
.setEndDate(end.getTime())
177+
.build();
179178
KeyPairGenerator kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, AndroidKeyStore);
180179
kpg.initialize(spec);
181180
kpg.generateKeyPair();
182181
}
183-
182+
184183
}
185-
184+
186185
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
187186
secretKey = ((KeyStore.SecretKeyEntry) keyStore.getEntry(KEY_ALIAS, null)).getSecretKey();
188187
} else {
@@ -199,52 +198,52 @@ private void initKeyStore(Context context) throws Exception{
199198
edit.putString(ENCRYPTED_KEY, encryptedKeyB64);
200199
edit.commit();
201200
}
202-
201+
203202
byte[] encryptedKey = Base64.decode(encryptedKeyB64, Base64.DEFAULT);
204203
byte[] key = rsaDecrypt(encryptedKey);
205204
secretKey = new SecretKeySpec(key, "AES");
206205
}
207-
208-
206+
207+
209208
}
210-
211-
private byte[] rsaEncrypt(byte[] secret) throws Exception{
209+
210+
private byte[] rsaEncrypt(byte[] secret) throws Exception {
212211
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(KEY_ALIAS, null);
213-
212+
214213
Cipher inputCipher = Cipher.getInstance(RSA_MODE, "AndroidOpenSSL");
215214
inputCipher.init(Cipher.ENCRYPT_MODE, privateKeyEntry.getCertificate().getPublicKey());
216-
215+
217216
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
218217
CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, inputCipher);
219218
cipherOutputStream.write(secret);
220219
cipherOutputStream.close();
221-
220+
222221
return outputStream.toByteArray();
223222
}
224-
225-
private byte[] rsaDecrypt(byte[] encrypted) throws Exception {
223+
224+
private byte[] rsaDecrypt(byte[] encrypted) throws Exception {
226225
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(KEY_ALIAS, null);
227-
226+
228227
Cipher outputCipher = Cipher.getInstance(RSA_MODE, "AndroidOpenSSL");
229228
outputCipher.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey());
230-
229+
231230
CipherInputStream cipherInputStream = new CipherInputStream(new ByteArrayInputStream(encrypted), outputCipher);
232231
ArrayList<Byte> values = new ArrayList<>();
233232
int nextByte;
234233
while ((nextByte = cipherInputStream.read()) != -1) {
235-
values.add((byte)nextByte);
234+
values.add((byte) nextByte);
236235
}
237-
236+
238237
byte[] bytes = new byte[values.size()];
239-
for(int i = 0; i < bytes.length; i++) {
238+
for (int i = 0; i < bytes.length; i++) {
240239
bytes[i] = values.get(i).byteValue();
241240
}
242241
return bytes;
243242
}
244-
243+
245244
public String encrypt(String input) throws Exception {
246245
byte[] bytes = input.getBytes();
247-
246+
248247
Cipher c;
249248
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
250249
c = Cipher.getInstance(AES_GCM);
@@ -254,15 +253,15 @@ public String encrypt(String input) throws Exception {
254253
c.init(Cipher.ENCRYPT_MODE, secretKey);
255254
}
256255
byte[] encodedBytes = c.doFinal(bytes);
257-
String encryptedBase64Encoded = Base64.encodeToString(encodedBytes, Base64.DEFAULT);
256+
String encryptedBase64Encoded = Base64.encodeToString(encodedBytes, Base64.DEFAULT);
258257
return encryptedBase64Encoded;
259258
}
260-
261-
259+
260+
262261
public String decrypt(String encrypted) throws Exception {
263262
Cipher c;
264263
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
265-
c =Cipher.getInstance(AES_GCM);
264+
c = Cipher.getInstance(AES_GCM);
266265
c.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, FIXED_IV));
267266
} else {
268267
c = Cipher.getInstance(AES_ECB, "BC");

0 commit comments

Comments
 (0)