A plugin for signing data using RSA or Ed25519. Enables the user to rotate the keys and clean unused ones. It is based on simple signing plugin.

Features

  • Delivers EDDSA crypto primitive to Android, iOS and MacOS, as they have no native support
  • Will allow in the future to deliver a next gen asymmetric crypto algo to a device if it will not have the native support for the algorithm
  • Allows the prerotation of keys, as it generates 2 key pairs by default.

Getting started

Android

Generating keys and data signing requires the screen lock to be enabled on the device. It can be easily checked by checkIfDeviceSecure method:

isDeviceSecure = await checkIfDeviceSecure(); //returns true if screen lock is set  

Working with RSA algorithm without checking whether the screen lock is set may cause functions to throw the DeviceNotSecuredException.

To start working with the plugin it is necessary to initialize the signer object for Ed25519 or RSA method:

void main() async{    
  WidgetsFlutterBinding.ensureInitialized();  
 var isDeviceSecure = await AsymmetricCryptoPrimitives.checkIfDeviceSecure(); if (isDeviceSecure) { var signer = await AsymmetricCryptoPrimitives.establishForRSA(); runApp(MyApp( signer: signer, )); }}  

Most of the plugin methods are available through signer object.

Features of Android version:
  • The RSA keys are generated by and stored in KeyStore.
  • The Ed25519 keys are generated with Libsodium and stored in Shared Preferences.
  • The keys stored in Shared Preferences are encrypted with AES.
  • The AES keys are generated by and stored in KeyStore.
  • Signing messages is protected with local authentication.
  • writeData() method stores data in Shared Preferences, encrypted.
  • Signing messages without local authentication is possible

iOS

Currently the only supported algorithm is Ed25519. RSA is available, however the work is in progress and some functions do not work properly yet.

The default authentication method is PIN. Due to Apple's policy, in order to activate FaceID, it is necessary to edit your app's Info.plist file and add the following lines:

<key>NSFaceIDUsageDescription</key>  
<string>iOS</string>  

The rest of the setup would look like the one described for Android.

Features of iOS version:
  • The Ed25519 keys are generated with Libsodium and stored in NSUserDefaults.
  • The keys stored in NSUserDefaults are encrypted with EC keys.
  • The EC keys are generated by and stored in Secure Enclave
  • Signing messages is protected with local authentication.
  • writeData() method stores data in NSUserDefaults, encrypted.

MacOS

Currently the only supported algorithm is Ed25519 with RSA not available yet. As signing of the data is protected with user's password, the plugin checks if the authentication is available on the device. So, as described for android, it is necessary to use checkIfDeviceSecure() to avoid further errors.

Features of MacOS version:
  • The Ed25519 keys are generated with Libsodium and stored in KeyChain.
  • As KeyChain natively encrypts data with AES, no other keys are needed.
  • Signing messages is protected with local authentication.
  • writeData() method stores data in NSUserDefaults, not encrypted as no keys are stored in there.

Windows

:warning: The Windows version of the plugin is still under development. Currently the keys are stored in a public directory with no encryption! :warning:

The only supported algorithm is Ed25519 with RSA not available yet. Sodium features are working through Rust plugin.

Features of Windows version:
  • The Ed25519 keys are generated with Libsodium using a Windows plugin with Rust and stored in passFile.txt file in Roaming AppData directory.
  • Signing messages is protected with local authentication (by plugin, not natively).
  • writeData() method stores data in Roaming AppData directory, not encrypted

Usage

Signing data

String strToSign = 'Sign me!';  
signature = await signer.sign(strToSign);  

Getting keys

String currentKey = '';  
String nextKey = '';  
currentKey = await signer.getCurrentPubKey();  
nextKey = await signer.getNextPubKey();  

Rotating keys

String currentKey = 'current key here!';  
String nextKey = 'next key here!';  
await signer.rotateForEd25519();  
//To see the results of the rotation  
currentKey = await signer.getCurrentPubKey();  
nextKey = await signer.getNextPubKey();  

Warning: The rotation doesn't currently work for RSA algorithm. Work in progress.

Getting the signer's uique UUID

String uuid = '';  
uuid = await signer.getUuid();  

Getting a previously used signer object

void main() async{  
 WidgetsFlutterBinding.ensureInitialized(); var signer = await AsymmetricCryptoPrimitives.getEd25519SignerFromUuid('ecd886f1-1af6-4e62-a6b2-825e2b15ebd2');  //or getRSASignerFromUuid() runApp(MyApp(signer: signer,));}  

This method will throw an IncorrectUuidException if no keys associated with the entered UUID were saved to the device.

Clean up

await AsymmetricCryptoPrimitives.cleanUp(signer);  

Removes all the keys that were associated with this signer object.

Data storing functions

//Writing data example  
String _data = 'Data';  
String _key = 'Key';  
var result = await AsymmetricCryptoPrimitives.writeData(_key, _data); //returns true if everything goes fine. Can throw a SharedPreferencesException or DeviceNotSecuredException  
//Reading data example  
String _key = 'Key';  
var result = await AsymmetricCryptoPrimitives.readData(_key); //returns data written under key if everything goes fine. Can throw a InvalidSignatureException, DeviceNotSecuredException or NoKeyInStorageException  
//Deleting data example  
String _key = 'Key';  
var result = await AsymmetricCryptoPrimitives.deleteData(_key); //returns true if everything goes fine. Can throw a SharedPreferencesException or DeviceNotSecuredException  
//Editing data example  
String _data = 'Data';  
String _key = 'Key';  
var result = await AsymmetricCryptoPrimitives.editData(_key, _data); //returns true if everything goes fine. Can throw a SharedPreferencesException or DeviceNotSecuredException