tauri-plugin-secure-element-api 0.1.0-alpha.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 +154 -0
- package/dist-js/index.cjs +58 -0
- package/dist-js/index.d.ts +24 -0
- package/dist-js/index.js +51 -0
- package/package.json +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Tauri Plugin Secure Element
|
|
2
|
+
|
|
3
|
+
A Tauri plugin for secure element functionality on iOS (Secure Enclave) and Android (Strongbox and TEE).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Generate secure keys using hardware-backed secure storage
|
|
8
|
+
- Sign data with keys stored in secure elements
|
|
9
|
+
- List and manage secure keys
|
|
10
|
+
- Check secure element support on the device
|
|
11
|
+
- Support for biometric and PIN authentication modes
|
|
12
|
+
- Cross-platform support for iOS and Android
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
### npm
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install tauri-plugin-secure-element-api
|
|
20
|
+
# or
|
|
21
|
+
pnpm add tauri-plugin-secure-element-api
|
|
22
|
+
# or
|
|
23
|
+
yarn add tauri-plugin-secure-element-api
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Cargo
|
|
27
|
+
|
|
28
|
+
```toml
|
|
29
|
+
[dependencies]
|
|
30
|
+
tauri-plugin-secure-element = "0.1.0"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Setup
|
|
34
|
+
|
|
35
|
+
Add the plugin to your `tauri.conf.json`:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"plugins": {
|
|
40
|
+
"secure-element": {
|
|
41
|
+
"all": true
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import {
|
|
51
|
+
checkSecureElementSupport,
|
|
52
|
+
generateSecureKey,
|
|
53
|
+
listKeys,
|
|
54
|
+
signWithKey,
|
|
55
|
+
deleteKey,
|
|
56
|
+
type AuthenticationMode,
|
|
57
|
+
} from "tauri-plugin-secure-element-api";
|
|
58
|
+
|
|
59
|
+
// Check if secure element is supported
|
|
60
|
+
const support = await checkSecureElementSupport();
|
|
61
|
+
console.log("Secure element supported:", support.secureElementSupported);
|
|
62
|
+
|
|
63
|
+
// Generate a new secure key
|
|
64
|
+
const { publicKey, keyName } = await generateSecureKey(
|
|
65
|
+
"my-key-name",
|
|
66
|
+
"pinOrBiometric" // or 'none' or 'biometricOnly'
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
// List all keys
|
|
70
|
+
const keys = await listKeys();
|
|
71
|
+
|
|
72
|
+
// Sign data with a key
|
|
73
|
+
const data = new Uint8Array([1, 2, 3, 4]);
|
|
74
|
+
const signature = await signWithKey("my-key-name", data);
|
|
75
|
+
|
|
76
|
+
// Delete a key
|
|
77
|
+
await deleteKey("my-key-name");
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## API Reference
|
|
81
|
+
|
|
82
|
+
### `checkSecureElementSupport()`
|
|
83
|
+
|
|
84
|
+
Returns information about secure element support on the device.
|
|
85
|
+
|
|
86
|
+
**Returns:** `Promise<SecureElementSupport>`
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
interface SecureElementSupport {
|
|
90
|
+
secureElementSupported: boolean;
|
|
91
|
+
teeSupported: boolean;
|
|
92
|
+
canEnforceBiometricOnly: boolean;
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### `generateSecureKey(keyName: string, authMode?: AuthenticationMode)`
|
|
97
|
+
|
|
98
|
+
Generates a new secure key in the device's secure element.
|
|
99
|
+
|
|
100
|
+
**Parameters:**
|
|
101
|
+
|
|
102
|
+
- `keyName`: Unique name for the key
|
|
103
|
+
- `authMode`: Authentication mode (`'none'`, `'pinOrBiometric'`, or `'biometricOnly'`)
|
|
104
|
+
|
|
105
|
+
**Returns:** `Promise<{ publicKey: string; keyName: string }>`
|
|
106
|
+
|
|
107
|
+
### `listKeys(keyName?: string, publicKey?: string)`
|
|
108
|
+
|
|
109
|
+
Lists keys stored in the secure element. Can filter by key name or public key.
|
|
110
|
+
|
|
111
|
+
**Returns:** `Promise<KeyInfo[]>`
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
interface KeyInfo {
|
|
115
|
+
keyName: string;
|
|
116
|
+
publicKey: string;
|
|
117
|
+
requiresAuthentication?: boolean;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### `signWithKey(keyName: string, data: Uint8Array)`
|
|
122
|
+
|
|
123
|
+
Signs data using a key stored in the secure element.
|
|
124
|
+
|
|
125
|
+
**Parameters:**
|
|
126
|
+
|
|
127
|
+
- `keyName`: Name of the key to use
|
|
128
|
+
- `data`: Data to sign as `Uint8Array`
|
|
129
|
+
|
|
130
|
+
**Returns:** `Promise<Uint8Array>` - The signature
|
|
131
|
+
|
|
132
|
+
### `deleteKey(keyName?: string, publicKey?: string)`
|
|
133
|
+
|
|
134
|
+
Deletes a key from the secure element. At least one parameter must be provided.
|
|
135
|
+
|
|
136
|
+
**Returns:** `Promise<boolean>` - Success status
|
|
137
|
+
|
|
138
|
+
## Platform Support
|
|
139
|
+
|
|
140
|
+
- **iOS**: Uses Secure Enclave for key generation and signing
|
|
141
|
+
- **Android**: Uses Strongbox and TEE (Trusted Execution Environment) when available
|
|
142
|
+
|
|
143
|
+
## License
|
|
144
|
+
|
|
145
|
+
Apache-2.0
|
|
146
|
+
|
|
147
|
+
## Contributing
|
|
148
|
+
|
|
149
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
150
|
+
|
|
151
|
+
## Links
|
|
152
|
+
|
|
153
|
+
- [Repository](https://github.com/dkackman/tauri-plugin-secure-element)
|
|
154
|
+
- [Issues](https://github.com/dkackman/tauri-plugin-secure-element/issues)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@tauri-apps/api/core');
|
|
4
|
+
|
|
5
|
+
async function ping(value) {
|
|
6
|
+
return await core.invoke("plugin:secure-element|ping", {
|
|
7
|
+
payload: {
|
|
8
|
+
value,
|
|
9
|
+
},
|
|
10
|
+
}).then((r) => (r.value ? r.value : null));
|
|
11
|
+
}
|
|
12
|
+
async function generateSecureKey(keyName, authMode = "pinOrBiometric") {
|
|
13
|
+
return await core.invoke("plugin:secure-element|generate_secure_key", {
|
|
14
|
+
payload: {
|
|
15
|
+
keyName,
|
|
16
|
+
authMode,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
async function listKeys(keyName, publicKey) {
|
|
21
|
+
return await core.invoke("plugin:secure-element|list_keys", {
|
|
22
|
+
payload: {
|
|
23
|
+
keyName: keyName || null,
|
|
24
|
+
publicKey: publicKey || null,
|
|
25
|
+
},
|
|
26
|
+
}).then((r) => r.keys);
|
|
27
|
+
}
|
|
28
|
+
async function signWithKey(keyName, data) {
|
|
29
|
+
return await core.invoke("plugin:secure-element|sign_with_key", {
|
|
30
|
+
payload: {
|
|
31
|
+
keyName,
|
|
32
|
+
data: Array.from(data),
|
|
33
|
+
},
|
|
34
|
+
}).then((r) => new Uint8Array(r.signature));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Delete a key by name or by public key.
|
|
38
|
+
* At least one of keyName or publicKey must be provided.
|
|
39
|
+
*/
|
|
40
|
+
async function deleteKey(keyName, publicKey) {
|
|
41
|
+
return await core.invoke("plugin:secure-element|delete_key", {
|
|
42
|
+
payload: {
|
|
43
|
+
keyName: keyName || null,
|
|
44
|
+
publicKey: publicKey || null,
|
|
45
|
+
},
|
|
46
|
+
}).then((r) => r.success);
|
|
47
|
+
}
|
|
48
|
+
async function checkSecureElementSupport() {
|
|
49
|
+
const result = await core.invoke("plugin:secure-element|check_secure_element_support");
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
exports.checkSecureElementSupport = checkSecureElementSupport;
|
|
54
|
+
exports.deleteKey = deleteKey;
|
|
55
|
+
exports.generateSecureKey = generateSecureKey;
|
|
56
|
+
exports.listKeys = listKeys;
|
|
57
|
+
exports.ping = ping;
|
|
58
|
+
exports.signWithKey = signWithKey;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface KeyInfo {
|
|
2
|
+
keyName: string;
|
|
3
|
+
publicKey: string;
|
|
4
|
+
requiresAuthentication?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function ping(value: string): Promise<string | null>;
|
|
7
|
+
export type AuthenticationMode = "none" | "pinOrBiometric" | "biometricOnly";
|
|
8
|
+
export declare function generateSecureKey(keyName: string, authMode?: AuthenticationMode): Promise<{
|
|
9
|
+
publicKey: string;
|
|
10
|
+
keyName: string;
|
|
11
|
+
}>;
|
|
12
|
+
export declare function listKeys(keyName?: string, publicKey?: string): Promise<KeyInfo[]>;
|
|
13
|
+
export declare function signWithKey(keyName: string, data: Uint8Array): Promise<Uint8Array>;
|
|
14
|
+
/**
|
|
15
|
+
* Delete a key by name or by public key.
|
|
16
|
+
* At least one of keyName or publicKey must be provided.
|
|
17
|
+
*/
|
|
18
|
+
export declare function deleteKey(keyName?: string, publicKey?: string): Promise<boolean>;
|
|
19
|
+
export interface SecureElementSupport {
|
|
20
|
+
secureElementSupported: boolean;
|
|
21
|
+
teeSupported: boolean;
|
|
22
|
+
canEnforceBiometricOnly: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function checkSecureElementSupport(): Promise<SecureElementSupport>;
|
package/dist-js/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { invoke } from '@tauri-apps/api/core';
|
|
2
|
+
|
|
3
|
+
async function ping(value) {
|
|
4
|
+
return await invoke("plugin:secure-element|ping", {
|
|
5
|
+
payload: {
|
|
6
|
+
value,
|
|
7
|
+
},
|
|
8
|
+
}).then((r) => (r.value ? r.value : null));
|
|
9
|
+
}
|
|
10
|
+
async function generateSecureKey(keyName, authMode = "pinOrBiometric") {
|
|
11
|
+
return await invoke("plugin:secure-element|generate_secure_key", {
|
|
12
|
+
payload: {
|
|
13
|
+
keyName,
|
|
14
|
+
authMode,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
async function listKeys(keyName, publicKey) {
|
|
19
|
+
return await invoke("plugin:secure-element|list_keys", {
|
|
20
|
+
payload: {
|
|
21
|
+
keyName: keyName || null,
|
|
22
|
+
publicKey: publicKey || null,
|
|
23
|
+
},
|
|
24
|
+
}).then((r) => r.keys);
|
|
25
|
+
}
|
|
26
|
+
async function signWithKey(keyName, data) {
|
|
27
|
+
return await invoke("plugin:secure-element|sign_with_key", {
|
|
28
|
+
payload: {
|
|
29
|
+
keyName,
|
|
30
|
+
data: Array.from(data),
|
|
31
|
+
},
|
|
32
|
+
}).then((r) => new Uint8Array(r.signature));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Delete a key by name or by public key.
|
|
36
|
+
* At least one of keyName or publicKey must be provided.
|
|
37
|
+
*/
|
|
38
|
+
async function deleteKey(keyName, publicKey) {
|
|
39
|
+
return await invoke("plugin:secure-element|delete_key", {
|
|
40
|
+
payload: {
|
|
41
|
+
keyName: keyName || null,
|
|
42
|
+
publicKey: publicKey || null,
|
|
43
|
+
},
|
|
44
|
+
}).then((r) => r.success);
|
|
45
|
+
}
|
|
46
|
+
async function checkSecureElementSupport() {
|
|
47
|
+
const result = await invoke("plugin:secure-element|check_secure_element_support");
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { checkSecureElementSupport, deleteKey, generateSecureKey, listKeys, ping, signWithKey };
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tauri-plugin-secure-element-api",
|
|
3
|
+
"version": "0.1.0-alpha.1",
|
|
4
|
+
"description": "Tauri plugin for secure element use on iOS (Secure Enclave) and Android (Strongbox and TEE).",
|
|
5
|
+
"repository": "https://github.com/dkackman/tauri-plugin-secure-element",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"author": "Don Kackman<dkackman@gmail.com>",
|
|
8
|
+
"homepage": "https://github.com/dkackman/tauri-plugin-secure-element",
|
|
9
|
+
"bugs": "https://github.com/dkackman/tauri-plugin-secure-element/issues",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"tauri",
|
|
12
|
+
"tauri-plugin",
|
|
13
|
+
"secure-element",
|
|
14
|
+
"secure-enclave",
|
|
15
|
+
"strongbox",
|
|
16
|
+
"tee",
|
|
17
|
+
"cryptography",
|
|
18
|
+
"keychain",
|
|
19
|
+
"keystore",
|
|
20
|
+
"mobile",
|
|
21
|
+
"ios",
|
|
22
|
+
"android"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"types": "./dist-js/index.d.ts",
|
|
26
|
+
"main": "./dist-js/index.cjs",
|
|
27
|
+
"module": "./dist-js/index.js",
|
|
28
|
+
"exports": {
|
|
29
|
+
"types": "./dist-js/index.d.ts",
|
|
30
|
+
"import": "./dist-js/index.js",
|
|
31
|
+
"require": "./dist-js/index.cjs"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist-js",
|
|
35
|
+
"README.md"
|
|
36
|
+
],
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@tauri-apps/api": "^2.0.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@rollup/plugin-typescript": "^12.0.0",
|
|
42
|
+
"@naturalcycles/ktlint": "^1.16.0",
|
|
43
|
+
"prettier": "^3.7.4",
|
|
44
|
+
"rollup": "^4.9.6",
|
|
45
|
+
"typescript": "^5.3.3",
|
|
46
|
+
"tslib": "^2.6.2"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "rollup -c",
|
|
50
|
+
"pretest": "pnpm build",
|
|
51
|
+
"format": "prettier --write . && cargo fmt && swiftformat ios/ 2>/dev/null || echo 'Note: swiftformat not installed. Install with: brew install swiftformat' && pnpm format:kotlin",
|
|
52
|
+
"format:check": "prettier --check . && cargo fmt --check && (swiftformat --lint ios/ 2>/dev/null || echo 'Note: swiftformat not installed') && pnpm format:check:kotlin",
|
|
53
|
+
"format:js": "prettier --write .",
|
|
54
|
+
"format:rust": "cargo fmt",
|
|
55
|
+
"format:swift": "swiftformat ios/ || echo 'Note: swiftformat not installed. Install with: brew install swiftformat'",
|
|
56
|
+
"format:kotlin": "ktlint -F 'android/src/**/*.kt'",
|
|
57
|
+
"format:check:kotlin": "ktlint 'android/src/**/*.kt'",
|
|
58
|
+
"lint": "cargo clippy -- -D warnings && (swiftlint lint ios/ 2>/dev/null || (command -v swiftlint >/dev/null 2>&1 || echo 'Note: swiftlint not installed. Install with: brew install swiftlint')) && pnpm lint:kotlin",
|
|
59
|
+
"lint:rust": "cargo clippy -- -D warnings",
|
|
60
|
+
"lint:swift": "swiftlint lint ios/ || (command -v swiftlint >/dev/null 2>&1 || echo 'Note: swiftlint not installed. Install with: brew install swiftlint')",
|
|
61
|
+
"lint:kotlin": "ktlint 'android/src/**/*.kt'"
|
|
62
|
+
}
|
|
63
|
+
}
|