Reputation: 31
I'm building a React Native app that is using redux-persist
and redux-persist-transform-encrypt
to store app state encrypted on the device. redux-persist-transform-encrypt
uses CryptoJs
to encrypt data via AES: CryptoJS.AES.encrypt('serialized app state', 'some-secret-key')
.
My question: (I'm a crypto novice) is there a best practice for generating some-secret-key
? My plan is to generate this key randomly when the app boots for the first time and store it securely in the device keychain.
Upvotes: 3
Views: 2074
Reputation: 199
You can use some uuid generator to generate random secret key. then store it in the keychain as @jimchao said. If you are using expo you can write something as follows:
import Expo from 'expo';
export const getFromSecureStore = (key, options) =>
Expo.SecureStore.getItemAsync(key, options);
export const saveToSecureStore = (key, value, options) =>
Expo.SecureStore.setItemAsync(key, value, options);
then use it as:
// while signing in
function* handleSignInRequest(action) {
try {
const resp = yield RequestService.post(
action.payload.url,
action.payload.body,
);
yield put({ type: SIGN_IN_SUCCEEDED, payload: resp.data });
const { username, password } = action.payload.body;
yield saveToSecureStore('username', username, {
keychainAccessible: Expo.SecureStore.ALWAYS, // can be changed as per usage
});
yield saveToSecureStore('password', password, {
keychainAccessible: Expo.SecureStore.ALWAYS,
});
} catch (error) {
console.log('======>> signin error', error);
yield put({ type: SIGN_IN_FAILED, error: error.response });
}
}
// at app start
async handleSignInAtBootstrap() {
try {
const username = await getFromSecureStore('username');
const password = await getFromSecureStore('password');
this.props.signInUser(username, password); //dispatch an action
} catch (error) {
console.log('======>>>', error);
}
}
here's Expo secure store docs to explore various configs
Upvotes: 0
Reputation: 1468
We use React Native Keychain to store the random generate key, to ensure the key is harder to get even if the attacker have access to file system:
let secretKey
async function getSecretKey() {
let {password} = await Keychain.getGenericPassword()
if (!password) {
password = generateRandomKey()
await Keychain.setGenericPassword(appName, password)
}
return password
}
const encrypt = async function(state) {
if (!secretKey) {
secretKey = await getSecretKey()
}
if (typeof state !== 'string') {
state = stringify(state);
}
return CryptoJS.AES.encrypt(state, secretKey).toString()
}
Upvotes: 1