expo-device-crypto 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,78 +26,36 @@ If you want to allow Face ID on iOS, add this to your app config:
26
26
 
27
27
  ## Supported Algorithms
28
28
 
29
- ### Signature Algorithms
29
+ ### ✍️ Signature Algorithms
30
30
 
31
31
  - `ECDSA_SECP256R1_SHA256`
32
32
 
33
- **Curve:** P-256 / secp256r1. </br>
34
- **Hash:** SHA-256. </br>
33
+ **Curve:** P-256 / secp256r1. </br>
34
+ **Hash:** SHA-256. </br>
35
35
 
36
- ### Encryption Algorithms
36
+ ### 🔐 Encryption Algorithms
37
37
 
38
38
  - `RSA_2048_PKCS1`
39
39
 
40
- **Key size:** 2048 bits. </br>
41
- **Padding:** PKCS#1 v1.5. </br>
40
+ **Key size:** 2048 bits. </br>
41
+ **Padding:** PKCS#1 v1.5. </br>
42
42
 
43
43
  - `RSA_2048_OAEP_SHA1`
44
44
 
45
- **Key size:** 2048 bits. </br>
46
- **Padding:** OAEP with SHA-1 and MGF1. </br>
45
+ **Key size:** 2048 bits. </br>
46
+ **Padding:** OAEP with SHA-1 and MGF1. </br>
47
47
 
48
48
  - `ECIES_P256_AES256_GCM`
49
49
 
50
- **Curve:** P-256 (secp256r1). </br>
51
- **Symmetric cipher:** AES-256-GCM. </br>
52
- **Key derivation:** HKDF-SHA256 (32-byte key from ECDH shared secret). </br>
50
+ **Curve:** P-256 (secp256r1). </br>
51
+ **Symmetric cipher:** AES-256-GCM. </br>
52
+ **Key derivation:** HKDF-SHA256 (32-byte key from ECDH shared secret). </br>
53
53
 
54
54
  **More coming soon...**
55
55
 
56
- ## Example: ECDSA with Biometric
56
+ ## Example
57
57
 
58
- ```ts
59
- import DeviceCrypto, {
60
- AuthCheckResult,
61
- AuthMethod,
62
- SigningAlgorithm,
63
- } from "expo-device-crypto";
64
-
65
- const alias = "user-signing-key";
66
- const payload = "Sign this challenge payload";
67
- const algorithmType = SigningAlgorithm.ECDSA_SECP256R1_SHA256;
68
- const authMethod = AuthMethod.PASSCODE_OR_BIOMETRIC;
69
-
70
- // 1) Ensure device authentication is configured (passcode at minimum)
71
- const authStatus = DeviceCrypto.isAuthCheckAvailable();
72
- if (authStatus !== AuthCheckResult.AVAILABLE) {
73
- throw new Error(`Authentication unavailable: ${authStatus}`);
74
- }
75
-
76
- // 2) Generate an auth-protected ECDSA key pair
77
- await DeviceCrypto.generateKeyPair(alias, {
78
- requireAuthentication: true,
79
- authMethod, // iOS: defined at key generation;
80
- algorithmType,
81
- });
82
-
83
- // 3) Optional: share public key with backend
84
- const publicKeyPem = DeviceCrypto.getPublicKey(alias, { format: "PEM" });
85
-
86
- // 4) Sign with private key (prompts biometric/passcode on protected keys)
87
- // Note: The data to sign must be in UTF-8 format.
88
- // Note: This function should display the system user authentication prompt.
89
- const signature = await DeviceCrypto.sign(alias, payload, {
90
- algorithmType,
91
- authMethod, // Android: defined when signing
92
- });
93
-
94
- // 5) Verify locally (usually done server-side with stored public key)
95
- const isValid = await DeviceCrypto.verify(alias, payload, signature ?? "", {
96
- algorithmType,
97
- });
98
- ```
99
-
100
- ## Example: RSA with Biometric
58
+ ### RSA with Biometric
101
59
 
102
60
  ```ts
103
61
  import DeviceCrypto, {
@@ -107,7 +65,7 @@ import DeviceCrypto, {
107
65
  } from "expo-device-crypto";
108
66
 
109
67
  const alias = "user-encryption-key";
110
- const secret = "Sensitive token";
68
+ const dataToEncrypt = "Sensitive data";
111
69
  const algorithmType = EncryptionAlgorithm.RSA_2048_PKCS1;
112
70
  const authMethod = AuthMethod.PASSCODE_OR_BIOMETRIC;
113
71
 
@@ -125,17 +83,17 @@ await DeviceCrypto.generateKeyPair(alias, {
125
83
  });
126
84
 
127
85
  // 3) Optional: retrieve/share public key with backend
128
- const publicKeyPem = DeviceCrypto.getPublicKey(alias, { format: "PEM" });
86
+ const publicKeyPem = DeviceCrypto.getPublicKey(alias);
129
87
 
130
88
  // 4) Encrypt with public key
131
- const encrypted = await DeviceCrypto.encrypt(alias, secret, {
89
+ const encrypted = await DeviceCrypto.encrypt(alias, dataToEncrypt, {
132
90
  algorithmType,
133
91
  });
134
92
 
135
- // 5) Decrypt with private key (prompts biometric/passcode on protected keys)
93
+ // 5) Decrypt with private key
136
94
  // Note: Data to decrypt must be in Base64 format.
137
95
  // Note: This function should display the system user authentication prompt.
138
- const decrypted = await DeviceCrypto.decrypt(alias, encrypted ?? "", {
96
+ const decrypted = await DeviceCrypto.decrypt(alias, encrypted, {
139
97
  algorithmType,
140
98
  authMethod, // Android: defined when decrypting
141
99
  });
@@ -143,7 +101,11 @@ const decrypted = await DeviceCrypto.decrypt(alias, encrypted ?? "", {
143
101
 
144
102
  > ⚠️ Because iOS Keychain/Secure Enclave binds authentication policy to key creation, `authMethod` must be set in `generateKeyPair`. On Android Keystore, authentication is applied at key usage time, so `authMethod` is provided in operations like `sign` and `decrypt`.
145
103
 
146
- ### Methods
104
+ ### 📚 More examples
105
+
106
+ You can find additional usage examples in the [`examples` directory](https://github.com/piotr-pietras/expo-device-crypto/tree/master/examples) of the main repository.
107
+
108
+ ### 🛠️ Methods
147
109
 
148
110
  - `isAuthCheckAvailable(): AuthCheckResult`
149
111
  - Returns device authentication availability (`AVAILABLE`, `NO_HARDWARE`, `UNAVAILABLE`).
@@ -186,7 +148,7 @@ const decrypted = await DeviceCrypto.decrypt(alias, encrypted ?? "", {
186
148
  - `isStrongBoxAvailable(): boolean`
187
149
  - Returns `true` if StrongBox Keystore is supported on the device.
188
150
 
189
- ## Important
151
+ ## ⚠️ Important
190
152
 
191
153
  ### Enable Strong Box on Android
192
154
 
@@ -211,3 +173,7 @@ If StrongBox is not available, Android falls back to the Trusted Execution Envir
211
173
  ### Secure Enclave support on iOS
212
174
 
213
175
  On iOS, only ECDSA keys can use the [Secure Enclave processor](https://developer.apple.com/documentation/security/ksecattrtokenidsecureenclave?utm_source=chatgpt.com#Discussion). RSA private-key operations are software-backed and handled by Apple’s system cryptographic services, which still provide strong isolation and protection.
176
+
177
+ ### ECIES - EC encryption schema
178
+
179
+ For library purposes, ECIES is referred to as an encryption algorithm for simplification, even though it is technically a broader encryption scheme.
@@ -1,7 +1,7 @@
1
1
  apply plugin: 'com.android.library'
2
2
 
3
3
  group = 'expo.modules.devicecrypto'
4
- version = '0.3.0'
4
+ version = '0.3.1'
5
5
 
6
6
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
7
7
  apply from: expoModulesCorePlugin
@@ -35,7 +35,7 @@ android {
35
35
  namespace "expo.modules.devicecrypto"
36
36
  defaultConfig {
37
37
  versionCode 1
38
- versionName "0.3.0"
38
+ versionName "0.3.1"
39
39
  }
40
40
  lintOptions {
41
41
  abortOnError false
@@ -38,7 +38,7 @@ export type GenerateKeyPairOptions = {
38
38
  requireAuthentication?: boolean;
39
39
  /**
40
40
  * The method of authentication to use.
41
- * Note that on Android you have to define it when signing.
41
+ * Note that on Android you have to define it when signing or decrypting.
42
42
  *
43
43
  * If you want to allow to use Face ID, you need to add the following to your app.json config file:
44
44
  * ```json
@@ -1 +1 @@
1
- {"version":3,"file":"DeviceCrypto.types.js","sourceRoot":"","sources":["../src/DeviceCrypto.types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,qBAIX;AAJD,WAAY,qBAAqB;IAC/B,kEAAyC,CAAA;IACzC,4EAAmD,CAAA;IACnD,wDAA+B,CAAA;AACjC,CAAC,EAJW,qBAAqB,KAArB,qBAAqB,QAIhC;AAED,MAAM,CAAN,IAAY,eAIX;AAJD,WAAY,eAAe;IACzB,0CAAuB,CAAA;IACvB,8CAA2B,CAAA;IAC3B,8CAA2B,CAAA;AAC7B,CAAC,EAJW,eAAe,KAAf,eAAe,QAI1B;AAED,MAAM,CAAN,IAAY,UAGX;AAHD,WAAY,UAAU;IACpB,mCAAqB,CAAA;IACrB,6DAA+C,CAAA;AACjD,CAAC,EAHW,UAAU,KAAV,UAAU,QAGrB;AAED,MAAM,CAAN,IAAY,gBAEX;AAFD,WAAY,gBAAgB;IAC1B,qEAAiD,CAAA;AACnD,CAAC,EAFW,gBAAgB,KAAhB,gBAAgB,QAE3B;AAID,MAAM,CAAN,IAAY,mBAIX;AAJD,WAAY,mBAAmB;IAC7B,wDAAiC,CAAA;IACjC,gEAAyC,CAAA;IACzC,sEAA+C,CAAA;AACjD,CAAC,EAJW,mBAAmB,KAAnB,mBAAmB,QAI9B","sourcesContent":["export enum GenerateKeyPairResult {\n KEY_PAIR_GENERATED = \"KEY_PAIR_GENERATED\",\n KEY_PAIR_ALREADY_EXISTS = \"KEY_PAIR_ALREADY_EXISTS\",\n NOT_AVAILABLE = \"NOT_AVAILABLE\",\n}\n\nexport enum AuthCheckResult {\n AVAILABLE = \"AVAILABLE\",\n NO_HARDWARE = \"NO_HARDWARE\",\n UNAVAILABLE = \"UNAVAILABLE\",\n}\n\nexport enum AuthMethod {\n PASSCODE = \"PASSCODE\",\n PASSCODE_OR_BIOMETRIC = \"PASSCODE_OR_BIOMETRIC\",\n}\n\nexport enum SigningAlgorithm {\n ECDSA_SECP256R1_SHA256 = \"ECDSA_SECP256R1_SHA256\",\n}\n\ntype EciesAlgorithm = \"ECIES_P256_AES256_GCM\";\ntype RsaAlgorithm = \"RSA_2048_PKCS1\" | \"RSA_2048_OAEP_SHA1\";\nexport enum EncryptionAlgorithm {\n RSA_2048_PKCS1 = \"RSA_2048_PKCS1\",\n RSA_2048_OAEP_SHA1 = \"RSA_2048_OAEP_SHA1\",\n ECIES_P256_AES256_GCM = \"ECIES_P256_AES256_GCM\",\n}\n\nexport type GenerateKeyPairOptions = {\n /**\n * The algorithm type of the key to generate.\n */\n algorithmType: SigningAlgorithm | EncryptionAlgorithm;\n /**\n * Whether to require authentication to sign.\n * Setting this to true will prompt biometric or passcode authentication before signing.\n *\n * Please check the *`isAuthCheckAvailable`* function to see if authentication is available.\n * If authentication is not available, generating a key pair will throw an error.\n * @default false\n */\n requireAuthentication?: boolean;\n /**\n * The method of authentication to use.\n * Note that on Android you have to define it when signing.\n *\n * If you want to allow to use Face ID, you need to add the following to your app.json config file:\n * ```json\n * \"ios\": {\n * \"infoPlist\": {\n * \"NSFaceIDUsageDescription\": \"We use Face ID to secure your data.\",\n * }\n * }\n * ```\n * @default AuthMethod.PASSCODE_OR_BIOMETRIC\n * @platform ios 🍏\n */\n authMethod?: AuthMethod;\n /**\n * If the Strong Box is available, it will be used instead of the Trusted Execution Environment (TEE).\n * @default false\n * @platform android 🤖\n */\n preferStrongBox?: boolean;\n}\n\ntype BaseAuthOptions = {\n /**\n * The title of the prompt to show when authentication is required.\n * @default \"Unlock\"\n * @platform android 🤖\n */\n promptTitle?: string;\n /**\n * The subtitle of the prompt to show when authentication is required.\n * @default \"Enter your PIN to continue\"\n * @platform android 🤖\n */\n promptSubtitle?: string;\n /**\n * The method of authentication to use.\n * Note that on iOS you have to define it when generating the key pair.\n * @default AuthMethod.PASSCODE_OR_BIOMETRIC\n * @platform android 🤖\n */\n authMethod?: AuthMethod;\n}\n\ntype BaseSigningOptions = {\n /**\n * The algorithm type of the key to use for signing.\n */\n algorithmType: SigningAlgorithm;\n};\ntype BaseVerifyOptions = BaseSigningOptions;\n\ntype BaseRsaEncryptionOptions = {\n /**\n * The algorithm type of the key to use for encrypting.\n */\n algorithmType: RsaAlgorithm;\n};\ntype BaseRsaDecryptionOptions = BaseRsaEncryptionOptions;\n\ntype BaseEciesEncryptionOptions = {\n /**\n * The algorithm type of the key to use for encrypting.\n */\n algorithmType: EciesAlgorithm;\n /**\n * The peer public key to use for ECIES.\n */\n peerPublicKey: string;\n};\ntype BaseEciesDecryptionOptions = BaseEciesEncryptionOptions;\n\nexport type SignOptions = BaseAuthOptions & BaseSigningOptions;\nexport type VerifyOptions = BaseVerifyOptions;\n\nexport type DecryptOptions =\n | (BaseAuthOptions & BaseEciesDecryptionOptions)\n | (BaseAuthOptions & BaseRsaDecryptionOptions);\nexport type EncryptOptions =\n | (BaseAuthOptions & BaseEciesEncryptionOptions)\n | BaseRsaEncryptionOptions;\n\nexport interface GetPublicKeyOptions {\n /**\n * The format of the public key to return.\n * @default \"PEM\" (Base64 of PEM-encoded SubjectPublicKeyInfo (SPKI) for P‑256)\n */\n format?: \"PEM\" | \"BASE64\";\n}\n"]}
1
+ {"version":3,"file":"DeviceCrypto.types.js","sourceRoot":"","sources":["../src/DeviceCrypto.types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,qBAIX;AAJD,WAAY,qBAAqB;IAC/B,kEAAyC,CAAA;IACzC,4EAAmD,CAAA;IACnD,wDAA+B,CAAA;AACjC,CAAC,EAJW,qBAAqB,KAArB,qBAAqB,QAIhC;AAED,MAAM,CAAN,IAAY,eAIX;AAJD,WAAY,eAAe;IACzB,0CAAuB,CAAA;IACvB,8CAA2B,CAAA;IAC3B,8CAA2B,CAAA;AAC7B,CAAC,EAJW,eAAe,KAAf,eAAe,QAI1B;AAED,MAAM,CAAN,IAAY,UAGX;AAHD,WAAY,UAAU;IACpB,mCAAqB,CAAA;IACrB,6DAA+C,CAAA;AACjD,CAAC,EAHW,UAAU,KAAV,UAAU,QAGrB;AAED,MAAM,CAAN,IAAY,gBAEX;AAFD,WAAY,gBAAgB;IAC1B,qEAAiD,CAAA;AACnD,CAAC,EAFW,gBAAgB,KAAhB,gBAAgB,QAE3B;AAID,MAAM,CAAN,IAAY,mBAIX;AAJD,WAAY,mBAAmB;IAC7B,wDAAiC,CAAA;IACjC,gEAAyC,CAAA;IACzC,sEAA+C,CAAA;AACjD,CAAC,EAJW,mBAAmB,KAAnB,mBAAmB,QAI9B","sourcesContent":["export enum GenerateKeyPairResult {\n KEY_PAIR_GENERATED = \"KEY_PAIR_GENERATED\",\n KEY_PAIR_ALREADY_EXISTS = \"KEY_PAIR_ALREADY_EXISTS\",\n NOT_AVAILABLE = \"NOT_AVAILABLE\",\n}\n\nexport enum AuthCheckResult {\n AVAILABLE = \"AVAILABLE\",\n NO_HARDWARE = \"NO_HARDWARE\",\n UNAVAILABLE = \"UNAVAILABLE\",\n}\n\nexport enum AuthMethod {\n PASSCODE = \"PASSCODE\",\n PASSCODE_OR_BIOMETRIC = \"PASSCODE_OR_BIOMETRIC\",\n}\n\nexport enum SigningAlgorithm {\n ECDSA_SECP256R1_SHA256 = \"ECDSA_SECP256R1_SHA256\",\n}\n\ntype EciesAlgorithm = \"ECIES_P256_AES256_GCM\";\ntype RsaAlgorithm = \"RSA_2048_PKCS1\" | \"RSA_2048_OAEP_SHA1\";\nexport enum EncryptionAlgorithm {\n RSA_2048_PKCS1 = \"RSA_2048_PKCS1\",\n RSA_2048_OAEP_SHA1 = \"RSA_2048_OAEP_SHA1\",\n ECIES_P256_AES256_GCM = \"ECIES_P256_AES256_GCM\",\n}\n\nexport type GenerateKeyPairOptions = {\n /**\n * The algorithm type of the key to generate.\n */\n algorithmType: SigningAlgorithm | EncryptionAlgorithm;\n /**\n * Whether to require authentication to sign.\n * Setting this to true will prompt biometric or passcode authentication before signing.\n *\n * Please check the *`isAuthCheckAvailable`* function to see if authentication is available.\n * If authentication is not available, generating a key pair will throw an error.\n * @default false\n */\n requireAuthentication?: boolean;\n /**\n * The method of authentication to use.\n * Note that on Android you have to define it when signing or decrypting.\n *\n * If you want to allow to use Face ID, you need to add the following to your app.json config file:\n * ```json\n * \"ios\": {\n * \"infoPlist\": {\n * \"NSFaceIDUsageDescription\": \"We use Face ID to secure your data.\",\n * }\n * }\n * ```\n * @default AuthMethod.PASSCODE_OR_BIOMETRIC\n * @platform ios 🍏\n */\n authMethod?: AuthMethod;\n /**\n * If the Strong Box is available, it will be used instead of the Trusted Execution Environment (TEE).\n * @default false\n * @platform android 🤖\n */\n preferStrongBox?: boolean;\n}\n\ntype BaseAuthOptions = {\n /**\n * The title of the prompt to show when authentication is required.\n * @default \"Unlock\"\n * @platform android 🤖\n */\n promptTitle?: string;\n /**\n * The subtitle of the prompt to show when authentication is required.\n * @default \"Enter your PIN to continue\"\n * @platform android 🤖\n */\n promptSubtitle?: string;\n /**\n * The method of authentication to use.\n * Note that on iOS you have to define it when generating the key pair.\n * @default AuthMethod.PASSCODE_OR_BIOMETRIC\n * @platform android 🤖\n */\n authMethod?: AuthMethod;\n}\n\ntype BaseSigningOptions = {\n /**\n * The algorithm type of the key to use for signing.\n */\n algorithmType: SigningAlgorithm;\n};\ntype BaseVerifyOptions = BaseSigningOptions;\n\ntype BaseRsaEncryptionOptions = {\n /**\n * The algorithm type of the key to use for encrypting.\n */\n algorithmType: RsaAlgorithm;\n};\ntype BaseRsaDecryptionOptions = BaseRsaEncryptionOptions;\n\ntype BaseEciesEncryptionOptions = {\n /**\n * The algorithm type of the key to use for encrypting.\n */\n algorithmType: EciesAlgorithm;\n /**\n * The peer public key to use for ECIES.\n */\n peerPublicKey: string;\n};\ntype BaseEciesDecryptionOptions = BaseEciesEncryptionOptions;\n\nexport type SignOptions = BaseAuthOptions & BaseSigningOptions;\nexport type VerifyOptions = BaseVerifyOptions;\n\nexport type DecryptOptions =\n | (BaseAuthOptions & BaseEciesDecryptionOptions)\n | (BaseAuthOptions & BaseRsaDecryptionOptions);\nexport type EncryptOptions =\n | (BaseAuthOptions & BaseEciesEncryptionOptions)\n | BaseRsaEncryptionOptions;\n\nexport interface GetPublicKeyOptions {\n /**\n * The format of the public key to return.\n * @default \"PEM\" (Base64 of PEM-encoded SubjectPublicKeyInfo (SPKI) for P‑256)\n */\n format?: \"PEM\" | \"BASE64\";\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = 'DeviceCrypto'
3
- s.version = '0.3.0'
3
+ s.version = '0.3.1'
4
4
  s.summary = 'Device crypto'
5
5
  s.description = 'Device crypto for Expo using device hardware capabilities'
6
6
  s.author = 'Piotr Pietras'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-device-crypto",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Crypto for Expo using device hardware capabilities",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -43,7 +43,7 @@ export type GenerateKeyPairOptions = {
43
43
  requireAuthentication?: boolean;
44
44
  /**
45
45
  * The method of authentication to use.
46
- * Note that on Android you have to define it when signing.
46
+ * Note that on Android you have to define it when signing or decrypting.
47
47
  *
48
48
  * If you want to allow to use Face ID, you need to add the following to your app.json config file:
49
49
  * ```json