Apple Secure Enclave implementaton for Flutter
The Secure Enclave is a dedicated secure subsystem integrated into Apple systems on chip (SoCs). The Secure Enclave is isolated from the main processor to provide an extra layer of security and is designed to keep sensitive user data secure even when the Application Processor kernel becomes compromised. https://support.apple.com/en-ie/guide/security/sec59b0b31ff/web
✅ Check tag status
✅ Generate Key Pair
✅ Get Public Key
✅ Encrypt
✅ Encrypt with Public Key
✅ Decrypt
✅ Sign
✅ Verify
✅ Flags (reference)
- devicePasscode ✅
- biometryAny ✅
- biometryCurrentSet ✅
- userPresence ✅
- watch ✅
- and ✅
- or ✅
- applicationPassword ✅
- privateKeyUsage ✅
🚧 Accessible (reference)
- kSecAttrAccessibleWhenUnlockedThisDeviceOnly ✅
- kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly ⌛
- kSecAttrAccessibleWhenUnlocked ⌛
- kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly ⌛
- kSecAttrAccessibleAfterFirstUnlock ⌛
🚧 Algorithm (reference)
- eciesEncryptionCofactorVariableIVX963SHA256AESGCM ✅
- ecdsaSignatureMessageX962SHA256 ✅
- others ... ⌛
📈 Check tag status :
final _secureEnclavePlugin = SecureEnclave();
final bool status = (await _secureEnclavePlugin.isKeyCreated(tag: 'kota')).value;
🔑 Generate Key Pair :
final _secureEnclavePlugin = SecureEnclave();
ResultModel res = await _secureEnclavePlugin.generateKeyPair(
accessControl: AccessControlModel(
password: 'jakarta123',
options: [
AccessControlOption.applicationPassword,
AccessControlOption.privateKeyUsage,
],
tag: 'kota',
),
);
if (res.error != null) {
print(res.error!.desc.toString());
} else {
print(res.value);
}
📢 Get Public Key :
final _secureEnclavePlugin = SecureEnclave();
ResultModel res = await _secureEnclavePlugin.getPublicKey(tag: 'kota');
if (res.error != null) {
print(res.error!.desc.toString());
} else {
print(res.value);
}
🔒 Encrypt :
final _secureEnclavePlugin = SecureEnclave();
ResultModel res = await _secureEnclavePlugin.encrypt(
message: 'hello jakarta',
tag: 'kota',
password: 'jakarta123',
);
if (res.error != null) {
print(res.error!.desc.toString());
} else {
print(res.value); // Uint8List
}
🔐 Encrypt with Public Key:
final _secureEnclavePlugin = SecureEnclave();
ResultModel res = await _secureEnclavePlugin.encrypt(
message: 'hello jakarta',
publicKey: 'T57xZkDf2WPN8BT2Qlg2LiaBEVCRDw1Xq8aWQQfil' // base64 encode
);
if (res.error != null) {
print(res.error!.desc.toString());
} else {
print(res.value); // Uint8List
}
🔓 Decrypt :
final _secureEnclavePlugin = SecureEnclave();
ResultModel res = await _secureEnclavePlugin.decrypt(
message: Uint8List.fromList(hex.decode('iasjfoiaj2EL3EL')), // hex => Uint8List
tag: 'kota',
password: 'jakarta123',
);
if (res.error != null) {
print(res.error!.desc.toString());
} else {
print(res.value);
}
🔏 Sign :
final _secureEnclavePlugin = SecureEnclave();
ResultModel res = await _secureEnclavePlugin.sign(
message: Uint8List.fromList('hello jakarta'.codeUnits), // String => Uint8List
tag: 'kota',
password: 'jakarta123',
);
if (res.error != null) {
print(res.error!.desc.toString());
} else {
print(res.value);
}
✅ Verify :
final _secureEnclavePlugin = SecureEnclave();
ResultModel res = await _secureEnclavePlugin.verify(
plainText: 'hello jakarta',
signature: 'fDrPlGl48R8DPCGNTsAticYfx3RoWPKxEHQ2pHWrBDGk887UwWYGVTSSUj6LciietChBULEs ',
tag: 'kota',
password: 'jakarta123',
);
if (res.error != null) {
print(res.error!.desc.toString());
} else {
print(res.value);
}