or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mddata-management.mdencryption.mdindex.mdinitialization.mdinstance-management.mdmulti-process.mdstorage-operations.md

encryption.mddocs/

0

# Encryption and Security

1

2

Encryption capabilities for protecting sensitive data with AES encryption, key management, and secure key rotation. MMKV provides transparent encryption/decryption for all stored data when an encryption key is provided.

3

4

## Capabilities

5

6

### Key Management

7

8

Manage encryption keys for MMKV instances with secure key operations.

9

10

```java { .api }

11

/**

12

* Get the encryption key (no more than 16 bytes).

13

* @return The encryption key, or null if no encryption is used

14

*/

15

public String cryptKey();

16

17

/**

18

* Transform plain text into encrypted text, or vice versa by passing a null encryption key.

19

* You can also change existing crypt key with a different cryptKey.

20

* @param cryptKey The new encryption key (no more than 16 bytes)

21

* @return True if success, otherwise False

22

*/

23

public boolean reKey(String cryptKey);

24

25

/**

26

* Just reset the encryption key (will not encrypt or decrypt anything).

27

* Usually you should call this method after another process has reKey() the multi-process MMKV instance.

28

* @param cryptKey The new encryption key (no more than 16 bytes)

29

*/

30

public void checkReSetCryptKey(String cryptKey);

31

```

32

33

**Usage Example:**

34

35

```java

36

// Create encrypted MMKV instance

37

MMKV encryptedKv = MMKV.mmkvWithID("secure_data", MMKV.SINGLE_PROCESS_MODE, "my_secret_key");

38

39

// Store sensitive data (automatically encrypted)

40

encryptedKv.encode("credit_card", "4111-1111-1111-1111");

41

encryptedKv.encode("api_token", "secret_api_token_12345");

42

43

// Check current encryption key

44

String currentKey = encryptedKv.cryptKey();

45

Log.d("MMKV", "Current encryption key: " + (currentKey != null ? "[ENCRYPTED]" : "None"));

46

47

// Change encryption key (re-encrypts all data)

48

boolean success = encryptedKv.reKey("new_secret_key");

49

if (success) {

50

Log.d("MMKV", "Successfully changed encryption key");

51

} else {

52

Log.e("MMKV", "Failed to change encryption key");

53

}

54

55

// Remove encryption (converts to plain text)

56

boolean removed = encryptedKv.reKey(null);

57

if (removed) {

58

Log.d("MMKV", "Encryption removed, data is now plain text");

59

}

60

```

61

62

### Multi-Process Key Synchronization

63

64

Manage encryption keys across multiple processes safely.

65

66

```java { .api }

67

/**

68

* Just reset the encryption key (will not encrypt or decrypt anything).

69

* Usually you should call this method after another process has reKey() the multi-process MMKV instance.

70

* @param cryptKey The new encryption key (no more than 16 bytes)

71

*/

72

public void checkReSetCryptKey(String cryptKey);

73

```

74

75

**Usage Example:**

76

77

```java

78

// In main process: Create encrypted multi-process instance

79

MMKV mainKv = MMKV.mmkvWithID("shared_secure", MMKV.MULTI_PROCESS_MODE, "shared_key");

80

mainKv.encode("secure_config", "sensitive_value");

81

82

// Change encryption key in main process

83

boolean keyChanged = mainKv.reKey("new_shared_key");

84

85

// In other processes: Update to new key without re-encryption

86

MMKV otherKv = MMKV.mmkvWithID("shared_secure", MMKV.MULTI_PROCESS_MODE, "shared_key");

87

if (keyChanged) {

88

// Synchronize key change from main process

89

otherKv.checkReSetCryptKey("new_shared_key");

90

}

91

92

// Now both processes can access the data with the new key

93

String config = otherKv.decodeString("secure_config", "");

94

```

95

96

### Encryption Best Practices

97

98

```java

99

// 1. Use strong, randomly generated keys

100

SecureRandom random = new SecureRandom();

101

byte[] keyBytes = new byte[16]; // 16 bytes for AES-128

102

random.nextBytes(keyBytes);

103

String encryptionKey = Base64.encodeToString(keyBytes, Base64.NO_WRAP);

104

105

MMKV secureKv = MMKV.mmkvWithID("user_secrets", MMKV.SINGLE_PROCESS_MODE, encryptionKey);

106

107

// 2. Store encryption keys securely (Android Keystore)

108

private String getOrCreateEncryptionKey() {

109

// Use Android Keystore for key management

110

return KeystoreManager.getOrCreateKey("mmkv_encryption_key");

111

}

112

113

// 3. Separate encrypted and unencrypted data

114

MMKV publicKv = MMKV.mmkvWithID("public_data"); // No encryption for non-sensitive data

115

MMKV privateKv = MMKV.mmkvWithID("private_data", MMKV.SINGLE_PROCESS_MODE, getEncryptionKey());

116

117

publicKv.encode("app_version", "1.0.0");

118

publicKv.encode("user_preferences", "theme:dark");

119

120

privateKv.encode("auth_token", userToken);

121

privateKv.encode("biometric_data", biometricInfo);

122

123

// 4. Handle key rotation securely

124

private void rotateEncryptionKey(MMKV kv) {

125

String oldKey = kv.cryptKey();

126

String newKey = generateNewKey();

127

128

// Create backup before key rotation

129

boolean backupSuccess = MMKV.backupOneToDirectory(

130

kv.mmapID(),

131

getBackupDirectory(),

132

null

133

);

134

135

if (backupSuccess) {

136

boolean rotationSuccess = kv.reKey(newKey);

137

if (rotationSuccess) {

138

Log.d("MMKV", "Key rotation successful");

139

// Update stored key reference

140

updateStoredEncryptionKey(newKey);

141

} else {

142

Log.e("MMKV", "Key rotation failed, keeping old key");

143

}

144

}

145

}

146

147

// 5. Verify encryption status

148

private boolean isEncrypted(MMKV kv) {

149

return kv.cryptKey() != null;

150

}

151

152

// 6. Handle encryption errors gracefully

153

private void safeEncryptedOperation(MMKV kv, String key, String value) {

154

try {

155

if (isEncrypted(kv)) {

156

boolean success = kv.encode(key, value);

157

if (!success) {

158

Log.e("MMKV", "Failed to encrypt and store data");

159

// Handle encryption failure

160

}

161

} else {

162

Log.w("MMKV", "Storing sensitive data without encryption");

163

kv.encode(key, value);

164

}

165

} catch (Exception e) {

166

Log.e("MMKV", "Encryption operation failed", e);

167

// Handle error appropriately

168

}

169

}

170

```

171

172

### Encrypted Anonymous Shared Memory

173

174

Use encryption with Anonymous Shared Memory for secure inter-process communication.

175

176

```java { .api }

177

/**

178

* Create an MMKV instance base on Anonymous Shared Memory with encryption.

179

* @param context The context of Android App

180

* @param mmapID The unique ID of the MMKV instance

181

* @param size The maximum size of the underlying Anonymous Shared Memory

182

* @param mode The process mode of the MMKV instance

183

* @param cryptKey The encryption key (no more than 16 bytes)

184

* @return MMKV instance

185

* @throws RuntimeException if there's a runtime error

186

*/

187

public static MMKV mmkvWithAshmemID(Context context, String mmapID, int size, int mode, String cryptKey);

188

```

189

190

**Usage Example:**

191

192

```java

193

// Create encrypted ashmem instance for secure IPC

194

String sharedKey = getSharedEncryptionKey(); // Securely shared between processes

195

MMKV secureIPC = MMKV.mmkvWithAshmemID(

196

this,

197

"secure_ipc_channel",

198

1024 * 1024, // 1MB

199

MMKV.MULTI_PROCESS_MODE,

200

sharedKey

201

);

202

203

// Share encrypted data between processes

204

secureIPC.encode("sensitive_message", "confidential_data");

205

secureIPC.encode("auth_credentials", userCredentials);

206

207

// Data is automatically encrypted in memory and during IPC

208

ParcelableMMKV parcelable = new ParcelableMMKV(secureIPC);

209

// Pass parcelable to other process...

210

```

211

212

### Encryption Performance Considerations

213

214

```java

215

// Encryption impacts performance - use judiciously

216

public class EncryptionStrategy {

217

private MMKV publicKv;

218

private MMKV encryptedKv;

219

220

public EncryptionStrategy() {

221

// Fast access for non-sensitive data

222

publicKv = MMKV.mmkvWithID("public_data");

223

224

// Encrypted storage for sensitive data

225

encryptedKv = MMKV.mmkvWithID("sensitive_data", MMKV.SINGLE_PROCESS_MODE, getEncryptionKey());

226

}

227

228

public void storeUserPreference(String key, String value) {

229

// Non-sensitive preferences - use fast unencrypted storage

230

publicKv.encode(key, value);

231

}

232

233

public void storeAuthToken(String token) {

234

// Sensitive data - use encrypted storage

235

encryptedKv.encode("auth_token", token);

236

}

237

238

public void storeBiometricTemplate(byte[] template) {

239

// Highly sensitive data - use encrypted storage

240

encryptedKv.encode("biometric_template", template);

241

}

242

}

243

```

244

245

### Integration with Android Keystore

246

247

```java

248

// Secure key management using Android Keystore

249

public class SecureMMKVManager {

250

private static final String KEYSTORE_ALIAS = "mmkv_encryption_key";

251

252

public MMKV createSecureInstance(String instanceId) {

253

String encryptionKey = getOrCreateKeystoreKey();

254

return MMKV.mmkvWithID(instanceId, MMKV.SINGLE_PROCESS_MODE, encryptionKey);

255

}

256

257

private String getOrCreateKeystoreKey() {

258

try {

259

KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");

260

keyStore.load(null);

261

262

if (!keyStore.containsAlias(KEYSTORE_ALIAS)) {

263

// Generate new key in Android Keystore

264

generateKeystoreKey();

265

}

266

267

// Retrieve and use key for MMKV encryption

268

return retrieveKeystoreKey();

269

} catch (Exception e) {

270

Log.e("MMKV", "Keystore operation failed", e);

271

return null;

272

}

273

}

274

275

private void generateKeystoreKey() {

276

// Implementation depends on Android version and requirements

277

// Use KeyGenerator with AndroidKeyStore provider

278

}

279

280

private String retrieveKeystoreKey() {

281

// Retrieve key from Android Keystore

282

// Convert to format suitable for MMKV

283

return "keystore_derived_key";

284

}

285

}

286

```

287

288

### Encryption Limitations and Considerations

289

290

```java

291

// Important encryption considerations:

292

293

// 1. Key length limit (16 bytes maximum)

294

String validKey = "1234567890123456"; // 16 bytes - OK

295

String invalidKey = "12345678901234567"; // 17 bytes - Will be truncated

296

297

// 2. Performance impact

298

long startTime = System.currentTimeMillis();

299

for (int i = 0; i < 1000; i++) {

300

encryptedKv.encode("key" + i, "value" + i);

301

}

302

long encryptedTime = System.currentTimeMillis() - startTime;

303

304

startTime = System.currentTimeMillis();

305

for (int i = 0; i < 1000; i++) {

306

plainKv.encode("key" + i, "value" + i);

307

}

308

long plainTime = System.currentTimeMillis() - startTime;

309

310

Log.d("MMKV", "Encrypted: " + encryptedTime + "ms, Plain: " + plainTime + "ms");

311

312

// 3. Incompatibility with compare-before-set optimization

313

MMKV encryptedKv = MMKV.mmkvWithID("test", MMKV.SINGLE_PROCESS_MODE, "key");

314

try {

315

encryptedKv.enableCompareBeforeSet(); // Will throw exception

316

} catch (RuntimeException e) {

317

Log.w("MMKV", "Compare-before-set not available with encryption");

318

}

319

320

// 4. Multi-process key synchronization complexity

321

// Ensure all processes use the same key and synchronize key changes

322

```