react-native-encrypted-asyncstorage
Version:
AES-encrypted values on top of AsyncStorage for React Native (JavaScript layer).
162 lines (104 loc) • 6.94 kB
Markdown
<div align="center">
# React Native Encrypted AsyncStorage
**AES-encrypted values on top of [Async Storage](https://github.com/react-native-async-storage/async-storage)** — pure JavaScript ([crypto-js](https://www.npmjs.com/package/crypto-js)), no native modules.
[](https://www.npmjs.com/package/react-native-encrypted-asyncstorage)
[](https://www.npmjs.com/package/react-native-encrypted-asyncstorage)
[](https://github.com/abhins0554/React-Native-Encrypted-Asyncstorage/blob/HEAD/LICENSE)
[](https://github.com/abhins0554/React-Native-Encrypted-Asyncstorage/stargazers)
[](https://github.com/abhins0554/React-Native-Encrypted-Asyncstorage/network/members)
[](https://github.com/abhins0554/React-Native-Encrypted-Asyncstorage/commits)
[](https://github.com/abhins0554/React-Native-Encrypted-Asyncstorage/actions/workflows/ci.yml)
[Installation](#installation) · [Usage](#usage) · [Backward compatibility](#backward-compatibility) · [Security](#security) · [API](#api-summary)
</div>
---
## Overview
This package wraps **AsyncStorage** so values are stored as **ciphertext** instead of plain text. Use it when you want a lightweight JS layer (for example tokens or prefs) and you already manage a passphrase or key in your app.
| | |
|---|---|
| **Stack** | `crypto-js` (AES, optional PBKDF2 + HMAC v2) + `@react-native-async-storage/async-storage` |
| **RN** | 0.60+ (autolinking) |
| **Types** | Published in `index.d.ts` |
---
## Backward compatibility
Releases keep **existing apps working** without code changes:
| Topic | Behavior |
|--------|----------|
| **Default writes** | `Set_Encrypted_AsyncStorage` uses **`storageFormat: "legacy"`** when you omit options — same CryptoJS password-AES format as earlier versions. |
| **Existing data** | Values **not** starting with the `ENC2$` prefix keep using the **legacy** decrypt path. |
| **Reads** | `Get_Encrypted_AsyncStorage` **auto-detects** `v2` vs legacy; call signature is unchanged (no extra arguments). |
| **Optional v2** | Pass `{ storageFormat: "v2" }` only when you **choose** stronger PBKDF2 + HMAC for **new** writes (or after migrating keys). |
| **Invalid `type`** | Still returns `undefined` from set/get (same as older releases). |
Upgrading the package does **not** require rewriting `Get_*` calls. Opt in to `v2` per key when you are ready.
---
## When to use
- You want **opaque blobs** in AsyncStorage instead of plaintext for casual device access or backups.
- You already supply or derive an **encryption passphrase / key** in your app.
## When not to use
- You need **OS-backed** secret storage (Keychain / Keystore) for keys — consider [`react-native-keychain`](https://github.com/oblador/react-native-keychain) or similar.
- You need **hardware-only** or audited native crypto — this library runs in JavaScript.
---
## Security
- **Crypto** uses [`crypto-js`](https://www.npmjs.com/package/crypto-js) (AES, PBKDF2, HMAC-SHA256).
- **Legacy (default)** — CryptoJS password-based AES (OpenSSL-style). No integrity tag; wrong keys may yield garbage strings for `"text"`.
- **Optional `storageFormat: "v2"`** — PBKDF2-SHA256 (100k iterations), AES-256-CBC, HMAC-SHA256 over IV + ciphertext. Reads auto-detect via `ENC2$` prefix.
- **Your key** — protect `encryptionKey`; prefer deriving or loading secrets securely in production.
---
## Requirements
- React Native **0.60+**
- `@react-native-async-storage/async-storage` **≥ 1.17** (see `peerDependencies` in `package.json`)
---
## Installation
```bash
npm install react-native-encrypted-asyncstorage
```
```bash
yarn add react-native-encrypted-asyncstorage
```
No native code in this package. If Async Storage is new to your app, follow its [install steps](https://react-native-async-storage.github.io/async-storage/docs/install/) (including iOS Pods when needed).
---
## Usage
### Import
```js
import {
Set_Encrypted_AsyncStorage,
Get_Encrypted_AsyncStorage,
Remove_Encrypted_AsyncStorage,
} from "react-native-encrypted-asyncstorage";
```
### Store
`type` is `"text"` or `"object"`. Objects are `JSON.stringify`’d before encryption.
```js
const encryptionKey = "your-secret"; // derive or load securely in real apps
await Set_Encrypted_AsyncStorage("text", "user_token", tokenString, encryptionKey);
await Set_Encrypted_AsyncStorage("object", "prefs", { theme: "dark" }, encryptionKey);
// Stronger format (PBKDF2 + HMAC); reads auto-detect — same Get_* calls as before.
await Set_Encrypted_AsyncStorage("text", "user_token", tokenString, encryptionKey, {
storageFormat: "v2",
});
```
Optional fifth argument: `{ storageFormat: "legacy" }` (default) or `{ storageFormat: "v2" }`.
Returns `true` on success, or `undefined` if `type` is not `"text"` or `"object"`.
### Read
```js
const token = await Get_Encrypted_AsyncStorage("text", "user_token", encryptionKey);
const prefs = await Get_Encrypted_AsyncStorage("object", "prefs", encryptionKey);
```
Returns `null` if nothing is stored for the key. For `"object"`, returns `null` if decryption / JSON parsing fails (including wrong key for `v2`).
### Remove
```js
await Remove_Encrypted_AsyncStorage("user_token");
```
Same as `AsyncStorage.removeItem(key)`. Use `AsyncStorage.clear()` from Async Storage only if clearing **everything** is intended.
---
## TypeScript
Types are in `index.d.ts`: `EncryptedStorageType`, `EncryptedStorageSetOptions`, and overloads for `Get_Encrypted_AsyncStorage`.
---
## API summary
| Function | Purpose |
|----------|---------|
| `Set_Encrypted_AsyncStorage(type, key, data, encryptionKey, options?)` | Encrypt and store (`storageFormat`: `legacy` \| `v2`) |
| `Get_Encrypted_AsyncStorage(type, key, encryptionKey)` | Read and decrypt (detects `v2` automatically) |
| `Remove_Encrypted_AsyncStorage(key)` | Remove one key |
---
## License
MIT — see [`LICENSE`](LICENSE).