Skip to content

Commit

Permalink
Merge pull request #112 from tw-mosip/inji-238-invalidate-keys
Browse files Browse the repository at this point in the history
feat(#238): Handle keys getting invalidated
  • Loading branch information
swatigoel authored Aug 23, 2023
2 parents 5895e8e + 13e7d33 commit 576d56c
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 51 deletions.
1 change: 1 addition & 0 deletions machines/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export const appMachine = model.createMachine(
},
RESET_KEY_INVALIDATE_ERROR_DISMISS: {
actions: ['resetKeyInvalidateError'],
target: 'init',
},
},
states: {
Expand Down
59 changes: 12 additions & 47 deletions machines/store.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
import * as Keychain from 'react-native-keychain';
import CryptoJS from 'crypto-js';
import Storage, { HMAC_ALIAS } from '../shared/storage';
import binaryToBase64 from 'react-native/Libraries/Utilities/binaryToBase64';
import {
EventFrom,
Receiver,
sendParent,
send,
sendParent,
sendUpdate,
StateFrom,
} from 'xstate';
import { createModel } from 'xstate/lib/model';
import { generateSecureRandom } from 'react-native-securerandom';
import { log } from 'xstate/lib/actions';
import { VC_ITEM_STORE_KEY_REGEX, MY_VCS_STORE_KEY } from '../shared/constants';
import { MY_VCS_STORE_KEY, VC_ITEM_STORE_KEY_REGEX } from '../shared/constants';
import SecureKeystore from 'react-native-secure-keystore';
import { isCustomSecureKeystore } from '../shared/cryptoutil/cryptoUtil';
import { AUTH_TIMEOUT } from '../shared/cryptoutil/cryptoUtil';
import {
AUTH_TIMEOUT,
clear,
decryptJson,
encryptJson,
isCustomSecureKeystore,
} from '../shared/cryptoutil/cryptoUtil';

export const ENCRYPTION_ID = 'c7c22a6c-9759-4605-ac88-46f4041d863d';
const vcKeyRegExp = new RegExp(VC_ITEM_STORE_KEY_REGEX);
Expand Down Expand Up @@ -479,11 +483,12 @@ export async function getItem(
} catch (e) {
if (
e.message.includes('Data is tampered') ||
e.message.includes(keyinvalidatedString)
e.message.includes(keyinvalidatedString) ||
e.message.includes('Key not found') // this error happens when previous get Item calls failed due to key invalidation and data and keys are deleted
) {
throw e;
}
console.error('Exception in getting item: ' + e);
console.error(`Exception in getting item for ${key}: ${e}`);
return defaultValue;
}
}
Expand Down Expand Up @@ -618,46 +623,6 @@ export async function removeItems(
}
}

export async function clear() {
try {
console.log('clearing entire storage');
if (isCustomSecureKeystore()) {
SecureKeystore.clearKeys();
}
await Storage.clear();
} catch (e) {
console.error('error clear:', e);
throw e;
}
}

export function encryptJson(
encryptionKey: string,
data: string
): Promise<string> {
if (!isCustomSecureKeystore()) {
return CryptoJS.AES.encrypt(data, encryptionKey).toString();
}
return SecureKeystore.encryptData(ENCRYPTION_ID, data);
}

export function decryptJson(
encryptionKey: string,
encryptedData: string
): Promise<string> {
try {
if (!isCustomSecureKeystore()) {
return CryptoJS.AES.decrypt(encryptedData, encryptionKey).toString(
CryptoJS.enc.Utf8
);
}
return SecureKeystore.decryptData(ENCRYPTION_ID, encryptedData);
} catch (e) {
console.error('error decryptJson:', e);
throw e;
}
}

type State = StateFrom<typeof storeMachine>;

export function selectIsTampered(state: State) {
Expand Down
43 changes: 43 additions & 0 deletions shared/cryptoutil/cryptoUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import forge from 'node-forge';
import getAllConfigurations from '../commonprops/commonProps';
import { isIOS } from '../constants';
import SecureKeystore from 'react-native-secure-keystore';
import Storage from '../storage';
import { ENCRYPTION_ID } from '../../machines/store';
import CryptoJS from 'crypto-js';

// 5min
export const AUTH_TIMEOUT = 5 * 60;
Expand Down Expand Up @@ -101,3 +104,43 @@ export interface WalletBindingResponse {
thumbprint: string;
expireDateTime: string;
}

export async function clear() {
try {
console.log('clearing entire storage');
if (isCustomSecureKeystore()) {
SecureKeystore.clearKeys();
}
await Storage.clear();
} catch (e) {
console.error('error clear:', e);
throw e;
}
}

export async function encryptJson(
encryptionKey: string,
data: string
): Promise<string> {
if (!isCustomSecureKeystore()) {
return CryptoJS.AES.encrypt(data, encryptionKey).toString();
}
return await SecureKeystore.encryptData(ENCRYPTION_ID, data);
}

export async function decryptJson(
encryptionKey: string,
encryptedData: string
): Promise<string> {
try {
if (!isCustomSecureKeystore()) {
return CryptoJS.AES.decrypt(encryptedData, encryptionKey).toString(
CryptoJS.enc.Utf8
);
}
return await SecureKeystore.decryptData(ENCRYPTION_ID, encryptedData);
} catch (e) {
console.error('error decryptJson:', e);
throw e;
}
}
10 changes: 6 additions & 4 deletions shared/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ import {
getFreeDiskStorageSync,
} from 'react-native-device-info';
import SecureKeystore from 'react-native-secure-keystore';
import { decryptJson, ENCRYPTION_ID, encryptJson } from '../machines/store';
import { isCustomSecureKeystore } from './cryptoutil/cryptoUtil';
import {
decryptJson,
encryptJson,
isCustomSecureKeystore,
} from './cryptoutil/cryptoUtil';

const MMKV = new MMKVLoader().initialize();
const vcKeyRegExp = new RegExp(VC_ITEM_STORE_KEY_REGEX);
Expand All @@ -32,8 +35,7 @@ async function generateHmac(
if (!isCustomSecureKeystore()) {
return CryptoJS.HmacSHA256(encryptionKey, data).toString();
}
const hmacSHA256 = await SecureKeystore.generateHmacSha(HMAC_ALIAS, data);
return hmacSHA256;
return await SecureKeystore.generateHmacSha(HMAC_ALIAS, data);
}

class Storage {
Expand Down

0 comments on commit 576d56c

Please sign in to comment.