expo-device-crypto 0.1.0

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/.eslintrc.js ADDED
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ root: true,
3
+ extends: ['universe/native', 'universe/web'],
4
+ ignorePatterns: ['build'],
5
+ };
package/README.md ADDED
@@ -0,0 +1,132 @@
1
+ ## `expo-device-crypto`
2
+
3
+ > ⚠️ This module is currently in beta and is not suitable for production use.
4
+
5
+ Hardware-backed cryptography for Expo apps using Android Keystore and Apple Secure Enclave/Keychain where available.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npx expo install expo-device-crypto
11
+ ```
12
+
13
+ If you want to allow Face ID on iOS, add this to your app config:
14
+
15
+ ```json
16
+ {
17
+ "expo": {
18
+ "ios": {
19
+ "infoPlist": {
20
+ "NSFaceIDUsageDescription": "We use Face ID to protect your cryptographic keys."
21
+ }
22
+ }
23
+ }
24
+ }
25
+ ```
26
+
27
+ ## Supported Algorithms
28
+
29
+ ### ECDSA (`ECDSA_SECP256R1_SHA256`)
30
+
31
+ - **Type:** Digital signature algorithm (asymmetric).
32
+ - **Curve:** P-256 / secp256r1.
33
+ - **Hash:** SHA-256.
34
+ - **Use it for:** Authentication challenges, message signing, and tamper detection.
35
+
36
+ ### RSA (`RSA_2048_PKCS1`)
37
+
38
+ - **Type:** Asymmetric encryption algorithm.
39
+ - **Key size:** 2048 bits.
40
+ - **Padding:** PKCS#1 v1.5.
41
+ - **Use it for:** Encrypting small secrets that only the private key holder should decrypt.
42
+
43
+ ## Biometric and Passcode Protection
44
+
45
+ You can bind private key usage to user authentication with:
46
+
47
+ - `requireAuthentication: true` when creating a key pair. (set to `false` to allow signing and decryption without authentication prompts)
48
+ - Use `AuthMethod.PASSCODE` or `AuthMethod.PASSCODE_OR_BIOMETRIC` to specify whether authentication should require only a passcode or allow biometrics when available.
49
+
50
+ Before using authentication-protected keys, verify that device authentication is available. If the user has not enabled at least a passcode, this function returns `AuthCheckResult.UNAVAILABLE`.
51
+
52
+ ```ts
53
+ import DeviceCrypto, { AuthCheckResult } from "expo-device-crypto";
54
+
55
+ const authStatus = DeviceCrypto.isAuthCheckAvailable();
56
+ if (authStatus !== AuthCheckResult.AVAILABLE) {
57
+ throw new Error(`Authentication unavailable: ${authStatus}`);
58
+ }
59
+ ```
60
+
61
+ ## Example: ECDSA with Biometric
62
+
63
+ ```ts
64
+ import DeviceCrypto, {
65
+ AuthMethod,
66
+ SigningAlgorithm,
67
+ } from "expo-device-crypto";
68
+
69
+ const alias = "user-signing-key";
70
+ const payload = "Sign this challenge payload";
71
+ const algorithmType = SigningAlgorithm.ECDSA_SECP256R1_SHA256;
72
+ const authMethod = AuthMethod.PASSCODE_OR_BIOMETRIC;
73
+
74
+ // 1) Generate an auth-protected ECDSA key pair
75
+ await DeviceCrypto.generateKeyPair(alias, {
76
+ requireAuthentication: true,
77
+ authMethod, // iOS: defined at key generation;
78
+ algorithmType,
79
+ });
80
+
81
+ // 2) Optional: share public key with backend
82
+ const publicKeyPem = DeviceCrypto.getPublicKey(alias, { format: "PEM" });
83
+
84
+ // 3) Sign with private key (prompts biometric/passcode on protected keys)
85
+ // Note: The data to sign must be in UTF-8 format.
86
+ const signature = await DeviceCrypto.sign(alias, payload, {
87
+ algorithmType,
88
+ authMethod, // Android: defined when signing
89
+ });
90
+
91
+ // 4) Verify locally (usually done server-side with stored public key)
92
+ const isValid = await DeviceCrypto.verify(alias, payload, signature ?? "", {
93
+ algorithmType,
94
+ });
95
+ ```
96
+
97
+ ## Example: RSA with Biometric
98
+
99
+ ```ts
100
+ import DeviceCrypto, {
101
+ AuthMethod,
102
+ EncryptionAlgorithm,
103
+ } from "expo-device-crypto";
104
+
105
+ const alias = "user-encryption-key";
106
+ const secret = "Sensitive token";
107
+ const algorithmType = EncryptionAlgorithm.RSA_2048_PKCS1;
108
+ const authMethod = AuthMethod.PASSCODE_OR_BIOMETRIC;
109
+
110
+ // 1) Generate an auth-protected RSA key pair
111
+ await DeviceCrypto.generateKeyPair(alias, {
112
+ algorithmType,
113
+ requireAuthentication: true,
114
+ authMethod, // iOS: defined at key generation;
115
+ });
116
+
117
+ // 2) Optional: retrieve/share public key with backend
118
+ const publicKeyPem = DeviceCrypto.getPublicKey(alias, { format: "PEM" });
119
+
120
+ // 3) Encrypt with public key
121
+ const encrypted = await DeviceCrypto.encrypt(alias, secret, {
122
+ algorithmType,
123
+ });
124
+
125
+ // 4) Decrypt with private key (prompts biometric/passcode on protected keys)
126
+ // Note: Data to encrypt must be in Base64 format.
127
+ const decrypted = await DeviceCrypto.decrypt(alias, encrypted ?? "", {
128
+ algorithmType,
129
+ authMethod, // Android: defined when decrypting
130
+ });
131
+ ```
132
+
@@ -0,0 +1,47 @@
1
+ apply plugin: 'com.android.library'
2
+
3
+ group = 'expo.modules.devicecrypto'
4
+ version = '0.1.0'
5
+
6
+ def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
7
+ apply from: expoModulesCorePlugin
8
+ applyKotlinExpoModulesCorePlugin()
9
+ useCoreDependencies()
10
+ useExpoPublishing()
11
+
12
+ // If you want to use the managed Android SDK versions from expo-modules-core, set this to true.
13
+ // The Android SDK versions will be bumped from time to time in SDK releases and may introduce breaking changes in your module code.
14
+ // Most of the time, you may like to manage the Android SDK versions yourself.
15
+ def useManagedAndroidSdkVersions = false
16
+ if (useManagedAndroidSdkVersions) {
17
+ useDefaultAndroidSdkVersions()
18
+ } else {
19
+ buildscript {
20
+ // Simple helper that allows the root project to override versions declared by this library.
21
+ ext.safeExtGet = { prop, fallback ->
22
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
23
+ }
24
+ }
25
+ project.android {
26
+ compileSdkVersion safeExtGet("compileSdkVersion", 36)
27
+ defaultConfig {
28
+ minSdkVersion safeExtGet("minSdkVersion", 24)
29
+ targetSdkVersion safeExtGet("targetSdkVersion", 36)
30
+ }
31
+ }
32
+ }
33
+
34
+ android {
35
+ namespace "expo.modules.devicecrypto"
36
+ defaultConfig {
37
+ versionCode 1
38
+ versionName "0.1.0"
39
+ }
40
+ lintOptions {
41
+ abortOnError false
42
+ }
43
+ }
44
+
45
+ dependencies {
46
+ implementation "androidx.biometric:biometric:1.1.0"
47
+ }
@@ -0,0 +1,2 @@
1
+ <manifest>
2
+ </manifest>
@@ -0,0 +1,385 @@
1
+ package expo.modules.devicecrypto
2
+
3
+ import android.content.pm.PackageManager
4
+ import android.security.keystore.KeyGenParameterSpec
5
+ import android.security.keystore.KeyInfo
6
+ import android.security.keystore.KeyProperties
7
+ import expo.modules.kotlin.modules.Module
8
+ import expo.modules.kotlin.modules.ModuleDefinition
9
+ import java.security.KeyPairGenerator
10
+ import java.security.KeyStore
11
+ import android.util.Base64
12
+ import androidx.biometric.BiometricManager
13
+ import androidx.biometric.BiometricPrompt
14
+ import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG
15
+ import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
16
+ import androidx.core.content.ContextCompat
17
+ import androidx.fragment.app.FragmentActivity
18
+ import expo.modules.kotlin.Promise
19
+ import java.security.Signature
20
+ import android.widget.Toast
21
+ import android.content.Context
22
+ import java.security.KeyFactory
23
+ import javax.crypto.Cipher
24
+
25
+ enum class GenerateKeyPairResult {
26
+ KEY_PAIR_GENERATED,
27
+ KEY_PAIR_ALREADY_EXISTS,
28
+ NOT_AVAILABLE,
29
+ }
30
+
31
+ enum class AuthCheckResult {
32
+ AVAILABLE,
33
+ UNAVAILABLE,
34
+ NO_HARDWARE,
35
+ }
36
+
37
+ enum class AuthMethod {
38
+ PASSCODE,
39
+ PASSCODE_OR_BIOMETRIC,
40
+ }
41
+
42
+ enum class AlgorithmType {
43
+ ECDSA_SECP256R1_SHA256,
44
+ RSA_2048_PKCS1,
45
+ }
46
+
47
+ class DeviceCryptoModule : Module() {
48
+ private fun toAndroidAlgo(algorithm: AlgorithmType): String {
49
+ return when (algorithm) {
50
+ AlgorithmType.ECDSA_SECP256R1_SHA256 -> "SHA256withECDSA"
51
+ AlgorithmType.RSA_2048_PKCS1 -> "RSA/ECB/PKCS1Padding"
52
+ }
53
+ }
54
+
55
+ private fun isAuthCheckAvailable(): AuthCheckResult {
56
+ val biometricManager = BiometricManager.from(appContext.reactContext as Context)
57
+ return when (biometricManager.canAuthenticate(BIOMETRIC_STRONG or DEVICE_CREDENTIAL)) {
58
+ BiometricManager.BIOMETRIC_SUCCESS -> AuthCheckResult.AVAILABLE
59
+ BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> AuthCheckResult.NO_HARDWARE
60
+ BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> AuthCheckResult.UNAVAILABLE
61
+ else -> AuthCheckResult.UNAVAILABLE
62
+ }
63
+ }
64
+
65
+ private fun isKeyStoreAvailable(): Boolean {
66
+ val pm = appContext.reactContext?.packageManager ?: return false
67
+ val appAttestKeystore = pm.hasSystemFeature(PackageManager.FEATURE_KEYSTORE_APP_ATTEST_KEY)
68
+ val hardwareKeystore = pm.hasSystemFeature(PackageManager.FEATURE_HARDWARE_KEYSTORE)
69
+ return appAttestKeystore && hardwareKeystore
70
+ }
71
+
72
+ private fun isStrongBoxAvailable(): Boolean {
73
+ val pm = appContext.reactContext?.packageManager ?: return false
74
+ val strongboxKeystore = pm.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)
75
+ return strongboxKeystore
76
+ }
77
+
78
+ private fun getAliases() = KeyStore.getInstance("AndroidKeyStore").apply {
79
+ load(null)
80
+ }.aliases().toList()
81
+
82
+ private fun isKeyStoreRequireAuthentication(entry: KeyStore.PrivateKeyEntry): Boolean {
83
+ val keyFactory = KeyFactory.getInstance(entry.privateKey.algorithm, "AndroidKeyStore")
84
+ val keyInfo = keyFactory.getKeySpec(entry.privateKey, KeyInfo::class.java)
85
+ return keyInfo.isUserAuthenticationRequired
86
+ }
87
+
88
+ private fun getKeyStoreEntry(alias: String): KeyStore.Entry? {
89
+ return KeyStore.getInstance("AndroidKeyStore").apply {
90
+ load(null)
91
+ }.getEntry(alias, null)
92
+ }
93
+
94
+ private fun retrievePublicKey(ks: KeyStore.Entry?): String? {
95
+ if (ks !is KeyStore.PrivateKeyEntry) return null
96
+
97
+ val publicKeyBytes: ByteArray = ks.certificate?.publicKey?.encoded ?: return null
98
+ return Base64.encodeToString(publicKeyBytes, Base64.NO_WRAP)
99
+ }
100
+
101
+ private fun removeKeyStoreEntry(alias: String): Boolean {
102
+ val ks = KeyStore.getInstance("AndroidKeyStore").apply {
103
+ load(null)
104
+ }
105
+ if (ks.getEntry(alias, null) == null) return false
106
+
107
+ ks.deleteEntry(alias)
108
+ return true
109
+ }
110
+
111
+ private fun buildECDSA_SECP256R1_SHA256(alias: String, reqAuth: Boolean): KeyPairGenerator {
112
+ val kpg: KeyPairGenerator = KeyPairGenerator.getInstance(
113
+ KeyProperties.KEY_ALGORITHM_EC,
114
+ "AndroidKeyStore"
115
+ )
116
+
117
+ val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder(
118
+ alias,
119
+ KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
120
+ ).run {
121
+ setDigests(KeyProperties.DIGEST_SHA256)
122
+ setIsStrongBoxBacked(false) // TODO: Prefer strong box if available
123
+ setUserAuthenticationRequired(reqAuth)
124
+ if (reqAuth) {
125
+ setUserAuthenticationParameters(
126
+ 30, // 30 seconds
127
+ KeyProperties.AUTH_BIOMETRIC_STRONG or KeyProperties.AUTH_DEVICE_CREDENTIAL
128
+ )
129
+ }
130
+ build()
131
+ }
132
+ kpg.initialize(parameterSpec)
133
+ return kpg
134
+ }
135
+
136
+ private fun buildRSA_2048_PKCS1(alias: String, reqAuth: Boolean): KeyPairGenerator {
137
+ val kpg: KeyPairGenerator = KeyPairGenerator.getInstance(
138
+ KeyProperties.KEY_ALGORITHM_RSA,
139
+ "AndroidKeyStore"
140
+ )
141
+
142
+ val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder(
143
+ alias,
144
+ KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
145
+ ).run {
146
+ setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
147
+ setIsStrongBoxBacked(false) // TODO: Prefer strong box if available
148
+ setUserAuthenticationRequired(reqAuth)
149
+ if (reqAuth) {
150
+ setUserAuthenticationParameters(
151
+ 30, // 30 seconds
152
+ KeyProperties.AUTH_BIOMETRIC_STRONG or KeyProperties.AUTH_DEVICE_CREDENTIAL
153
+ )
154
+ }
155
+ build()
156
+ }
157
+ kpg.initialize(parameterSpec)
158
+ return kpg
159
+ }
160
+
161
+
162
+ private fun showAuthPrompt(
163
+ onSuccess: () -> Unit,
164
+ onError: (String) -> Unit,
165
+ title: String = "Unlock",
166
+ subtitle: String = "Enter your PIN to continue",
167
+ authMethod: AuthMethod
168
+ ) {
169
+ val activity = appContext.currentActivity as? FragmentActivity ?: run {
170
+ onError("No active FragmentActivity found")
171
+ return
172
+ }
173
+
174
+ activity.runOnUiThread {
175
+ val executor = ContextCompat.getMainExecutor(activity)
176
+ val biometricPrompt = BiometricPrompt(
177
+ activity,
178
+ executor,
179
+ object : BiometricPrompt.AuthenticationCallback() {
180
+
181
+ override fun onAuthenticationSucceeded(
182
+ result: BiometricPrompt.AuthenticationResult
183
+ ) {
184
+ super.onAuthenticationSucceeded(result)
185
+ onSuccess()
186
+ }
187
+
188
+ override fun onAuthenticationError(
189
+ errorCode: Int,
190
+ errString: CharSequence
191
+ ) {
192
+ super.onAuthenticationError(errorCode, errString)
193
+ onError(errString.toString())
194
+ }
195
+ }
196
+ )
197
+
198
+ val promptInfo = BiometricPrompt.PromptInfo.Builder()
199
+ .setTitle(title)
200
+ .setSubtitle(subtitle)
201
+ .setAllowedAuthenticators(
202
+ when (authMethod) {
203
+ AuthMethod.PASSCODE -> BiometricManager.Authenticators.DEVICE_CREDENTIAL
204
+ AuthMethod.PASSCODE_OR_BIOMETRIC -> BiometricManager.Authenticators.BIOMETRIC_STRONG or BiometricManager.Authenticators.DEVICE_CREDENTIAL
205
+ }
206
+ )
207
+ .build()
208
+
209
+ biometricPrompt.authenticate(promptInfo)
210
+ }
211
+ }
212
+
213
+ override fun definition() = ModuleDefinition {
214
+ Name("DeviceCrypto")
215
+
216
+ Function("isAuthCheckAvailable") { ->
217
+ return@Function isAuthCheckAvailable()
218
+ }
219
+
220
+ Function("generateKeyPair") { alias: String, o: Map<String, Any?> ->
221
+ val reqAuth = o["reqAuth"] as Boolean
222
+ if (reqAuth && isAuthCheckAvailable() != AuthCheckResult.AVAILABLE) {
223
+ throw Exception("NO_AUTH_AVAILABLE")
224
+ }
225
+ if (!isKeyStoreAvailable()) {
226
+ return@Function GenerateKeyPairResult.NOT_AVAILABLE
227
+ }
228
+ if (getKeyStoreEntry(alias) != null) {
229
+ return@Function GenerateKeyPairResult.KEY_PAIR_ALREADY_EXISTS
230
+ }
231
+
232
+ val algoType = AlgorithmType.valueOf(o["algoType"] as String)
233
+ val kpg = when (algoType) {
234
+ AlgorithmType.ECDSA_SECP256R1_SHA256 -> buildECDSA_SECP256R1_SHA256(alias, reqAuth)
235
+ AlgorithmType.RSA_2048_PKCS1 -> buildRSA_2048_PKCS1(alias, reqAuth)
236
+ else -> throw Exception("INVALID_ALGORITHM_TYPE")
237
+ }
238
+
239
+ kpg.generateKeyPair()
240
+
241
+ return@Function GenerateKeyPairResult.KEY_PAIR_GENERATED
242
+ }
243
+
244
+ Function("removeKeyPair") { alias: String ->
245
+ return@Function removeKeyStoreEntry(alias)
246
+ }
247
+
248
+ Function("aliases") {
249
+ return@Function getAliases()
250
+ }
251
+
252
+ Function("getPublicKey") { alias: String ->
253
+ val entry = getKeyStoreEntry(alias)
254
+ return@Function retrievePublicKey(entry)
255
+ }
256
+
257
+ AsyncFunction("sign") { alias: String,
258
+ data: String,
259
+ o: Map<String, Any?>,
260
+ promise: Promise ->
261
+ val entry = getKeyStoreEntry(alias)
262
+ if (entry !is KeyStore.PrivateKeyEntry) {
263
+ promise.resolve(null)
264
+ return@AsyncFunction
265
+ }
266
+
267
+ val reqAuth = isKeyStoreRequireAuthentication(entry);
268
+
269
+ val title = o["title"] as String
270
+ val subtitle = o["subtitle"] as String
271
+ val authMethod = AuthMethod.valueOf(o["authMethod"] as String)
272
+ val algoType = AlgorithmType.valueOf(o["algoType"] as String)
273
+ val algo = toAndroidAlgo(algoType)
274
+
275
+ if (!reqAuth) {
276
+ val signature: ByteArray = Signature.getInstance(algo).apply {
277
+ initSign(entry.privateKey)
278
+ update(data.toByteArray(Charsets.UTF_8))
279
+ }.sign()
280
+ promise.resolve(Base64.encodeToString(signature, Base64.NO_WRAP))
281
+ return@AsyncFunction
282
+ } else {
283
+ showAuthPrompt(
284
+ onSuccess = {
285
+ val signature: ByteArray = Signature.getInstance(algo).apply {
286
+ initSign(entry.privateKey)
287
+ update(data.toByteArray(Charsets.UTF_8))
288
+ }.sign()
289
+ promise.resolve(Base64.encodeToString(signature, Base64.NO_WRAP))
290
+ },
291
+ onError = { error ->
292
+ promise.reject("ERR_AUTH_FAILED", error, null)
293
+ },
294
+ title = title,
295
+ subtitle = subtitle,
296
+ authMethod = authMethod
297
+ )
298
+ }
299
+ }
300
+
301
+ Function("verify") { alias: String,
302
+ data: String,
303
+ signature: String,
304
+ o: Map<String, Any?> ->
305
+ val entry = getKeyStoreEntry(alias)
306
+ if (entry !is KeyStore.PrivateKeyEntry) return@Function null
307
+
308
+ val algoType = AlgorithmType.valueOf(o["algoType"] as String)
309
+ val algo = toAndroidAlgo(algoType)
310
+
311
+ val valid: Boolean = Signature.getInstance(algo).apply {
312
+ initVerify(entry.certificate)
313
+ update(data.toByteArray(Charsets.UTF_8))
314
+ }.verify(Base64.decode(signature, Base64.NO_WRAP))
315
+ return@Function true
316
+ }
317
+
318
+
319
+ AsyncFunction("encrypt") { alias: String,
320
+ data: String,
321
+ o: Map<String, Any?>,
322
+ promise: Promise ->
323
+ val entry = getKeyStoreEntry(alias)
324
+ if (entry !is KeyStore.PrivateKeyEntry) {
325
+ promise.resolve(null)
326
+ return@AsyncFunction
327
+ }
328
+
329
+ val algoType = AlgorithmType.valueOf(o["algoType"] as String)
330
+ val algo = toAndroidAlgo(algoType)
331
+
332
+ val cipher = Cipher.getInstance(algo)
333
+ cipher.init(Cipher.ENCRYPT_MODE, entry.certificate.publicKey)
334
+ val encrypted: ByteArray = cipher.doFinal(data.toByteArray(Charsets.UTF_8))
335
+ promise.resolve(Base64.encodeToString(encrypted, Base64.NO_WRAP))
336
+ }
337
+
338
+ AsyncFunction("decrypt") { alias: String,
339
+ data: String,
340
+ o: Map<String, Any?>,
341
+ promise: Promise ->
342
+ val entry = getKeyStoreEntry(alias)
343
+ if (entry !is KeyStore.PrivateKeyEntry) {
344
+ promise.resolve(null)
345
+ return@AsyncFunction
346
+ }
347
+
348
+ val reqAuth = isKeyStoreRequireAuthentication(entry)
349
+
350
+ val title = o["title"] as String
351
+ val subtitle = o["subtitle"] as String
352
+ val authMethod = o["authMethod"] as String
353
+ val algoType = AlgorithmType.valueOf(o["algoType"] as String)
354
+ val algo = toAndroidAlgo(algoType)
355
+
356
+ val cipher = Cipher.getInstance(algo)
357
+ val ciphertext = Base64.decode(data, Base64.NO_WRAP)
358
+
359
+ if (!reqAuth) {
360
+ cipher.init(Cipher.DECRYPT_MODE, entry.privateKey)
361
+ val decrypted: ByteArray = cipher.doFinal(ciphertext)
362
+ promise.resolve(String(decrypted, Charsets.UTF_8))
363
+ return@AsyncFunction
364
+ } else {
365
+ showAuthPrompt(
366
+ onSuccess = {
367
+ cipher.init(Cipher.DECRYPT_MODE, entry.privateKey)
368
+ val decrypted: ByteArray = cipher.doFinal(ciphertext)
369
+ promise.resolve(String(decrypted, Charsets.UTF_8))
370
+ },
371
+ onError = { error ->
372
+ promise.reject("ERR_AUTH_FAILED", error, null)
373
+ },
374
+ title = title,
375
+ subtitle = subtitle,
376
+ authMethod = when (authMethod) {
377
+ "PASSCODE" -> AuthMethod.PASSCODE
378
+ "PASSCODE_OR_BIOMETRIC" -> AuthMethod.PASSCODE_OR_BIOMETRIC
379
+ else -> AuthMethod.PASSCODE_OR_BIOMETRIC
380
+ }
381
+ )
382
+ }
383
+ }
384
+ }
385
+ }
@@ -0,0 +1,101 @@
1
+ export declare enum GenerateKeyPairResult {
2
+ KEY_PAIR_GENERATED = "KEY_PAIR_GENERATED",
3
+ KEY_PAIR_ALREADY_EXISTS = "KEY_PAIR_ALREADY_EXISTS",
4
+ NOT_AVAILABLE = "NOT_AVAILABLE"
5
+ }
6
+ export declare enum AuthCheckResult {
7
+ AVAILABLE = "AVAILABLE",
8
+ NO_HARDWARE = "NO_HARDWARE",
9
+ UNAVAILABLE = "UNAVAILABLE"
10
+ }
11
+ export declare enum AuthMethod {
12
+ PASSCODE = "PASSCODE",
13
+ PASSCODE_OR_BIOMETRIC = "PASSCODE_OR_BIOMETRIC"
14
+ }
15
+ export declare enum SigningAlgorithm {
16
+ ECDSA_SECP256R1_SHA256 = "ECDSA_SECP256R1_SHA256"
17
+ }
18
+ export declare enum EncryptionAlgorithm {
19
+ RSA_2048_PKCS1 = "RSA_2048_PKCS1"
20
+ }
21
+ export interface GenerateKeyPairOptions {
22
+ /**
23
+ * The algorithm type of the key to generate.
24
+ */
25
+ algorithmType: SigningAlgorithm | EncryptionAlgorithm;
26
+ /**
27
+ * Whether to require authentication to sign.
28
+ * Setting this to true will prompt biometric or passcode authentication before signing.
29
+ *
30
+ * Please check the *`isAuthCheckAvailable`* function to see if authentication is available.
31
+ * If authentication is not available, generating a key pair will throw an error.
32
+ * @default false
33
+ */
34
+ requireAuthentication?: boolean;
35
+ /**
36
+ * The method of authentication to use.
37
+ * Note that on Android you have to define it when signing.
38
+ *
39
+ * If you want to allow to use Face ID, you need to add the following to your app.json config file:
40
+ * ```json
41
+ * "ios": {
42
+ * "infoPlist": {
43
+ * "NSFaceIDUsageDescription": "We use Face ID to secure your data.",
44
+ * }
45
+ * }
46
+ * ```
47
+ * @default AuthMethod.PASSCODE_OR_BIOMETRIC
48
+ * @platform ios
49
+ */
50
+ authMethod?: AuthMethod;
51
+ }
52
+ interface BaseSignDecryptOptions {
53
+ /**
54
+ * The title of the prompt to show when authentication is required.
55
+ * @default "Unlock"
56
+ * @platform android
57
+ */
58
+ promptTitle?: string;
59
+ /**
60
+ * The subtitle of the prompt to show when authentication is required.
61
+ * @default "Enter your PIN to continue"
62
+ * @platform android
63
+ */
64
+ promptSubtitle?: string;
65
+ /**
66
+ * The method of authentication to use.
67
+ * Note that on iOS you have to define it when generating the key pair.
68
+ * @default AuthMethod.PASSCODE_OR_BIOMETRIC
69
+ * @platform android
70
+ */
71
+ authMethod?: AuthMethod;
72
+ }
73
+ interface BaseSigningOptions {
74
+ /**
75
+ * The algorithm type of the key to use for signing.
76
+ */
77
+ algorithmType?: SigningAlgorithm;
78
+ }
79
+ interface BaseEncryptionOptions {
80
+ /**
81
+ * The algorithm type of the key to use for encrypting.
82
+ */
83
+ algorithmType?: EncryptionAlgorithm;
84
+ }
85
+ export interface SignOptions extends BaseSignDecryptOptions, BaseSigningOptions {
86
+ }
87
+ export interface VerifyOptions extends BaseSigningOptions {
88
+ }
89
+ export interface DecryptOptions extends BaseSignDecryptOptions, BaseEncryptionOptions {
90
+ }
91
+ export interface EncryptOptions extends BaseEncryptionOptions {
92
+ }
93
+ export interface GetPublicKeyOptions {
94
+ /**
95
+ * The format of the public key to return.
96
+ * @default "PEM" (Base64 of PEM-encoded SubjectPublicKeyInfo (SPKI) for P‑256)
97
+ */
98
+ format?: "PEM";
99
+ }
100
+ export {};
101
+ //# sourceMappingURL=DeviceCrypto.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeviceCrypto.types.d.ts","sourceRoot":"","sources":["../src/DeviceCrypto.types.ts"],"names":[],"mappings":"AAAA,oBAAY,qBAAqB;IAC/B,kBAAkB,uBAAuB;IACzC,uBAAuB,4BAA4B;IACnD,aAAa,kBAAkB;CAChC;AAED,oBAAY,eAAe;IACzB,SAAS,cAAc;IACvB,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;CAC5B;AAED,oBAAY,UAAU;IACpB,QAAQ,aAAa;IACrB,qBAAqB,0BAA0B;CAChD;AAED,oBAAY,gBAAgB;IAC1B,sBAAsB,2BAA2B;CAClD;AAED,oBAAY,mBAAmB;IAC7B,cAAc,mBAAmB;CAClC;AAED,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,aAAa,EAAE,gBAAgB,GAAG,mBAAmB,CAAC;IACtD;;;;;;;OAOG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;;;;;;;;;;;;OAcG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,UAAU,sBAAsB;IAC9B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,UAAU,kBAAkB;IAC1B;;OAEG;IACH,aAAa,CAAC,EAAE,gBAAgB,CAAC;CAClC;AAED,UAAU,qBAAqB;IAC7B;;OAEG;IACH,aAAa,CAAC,EAAE,mBAAmB,CAAC;CACrC;AAED,MAAM,WAAW,WAAY,SAAQ,sBAAsB,EAAE,kBAAkB;CAAG;AAClF,MAAM,WAAW,aAAc,SAAQ,kBAAkB;CAAG;AAE5D,MAAM,WAAW,cAAe,SAAQ,sBAAsB,EAAE,qBAAqB;CAAG;AACxF,MAAM,WAAW,cAAe,SAAQ,qBAAqB;CAAG;AAEhE,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB"}