Biometrically Authenticated Data Encryption and Decryption in Flutter βœ¨πŸ”’

Rahul Kulkarni
4 min readJul 30, 2023

--

Mobile applications often deal with sensitive data that requires robust security measures. Biometric authentication, such as fingerprint or face unlock, has become a popular method to enhance security while providing a seamless user experience. In this blog post, we will explore how to implement biometrically authenticated data encryption and decryption in Flutter. πŸš€

Requirements and Dependencies πŸ“πŸ”§

To get started, make the following changes in MainActivity.kt If you are using FlutterActivity directly, change it to FlutterFragmentActivity

import io.flutter.embedding.android.FlutterFragmentActivity;

class MainActivity: FlutterFragmentActivity() {
}

Permissions πŸ‘‰πŸ»

Update your project’s AndroidManifest.xml file to include the USE_BIOMETRIC permissions:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
<manifest>

The local_auth plugin will build and run on SDK 16+, but isDeviceSupported() will always return false before SDK 23 (Android 6.0). Make sure to change the minSdkVersion to 23 in the app levelbuild.gradle file:

minSdkVersion 23

Make sure you have the following dependencies added to your Flutter project’s pubspec.yaml file:

dependencies:
flutter:
sdk: flutter
local_auth: ^2.1.6
flutter_secure_storage: ^8.0.0
encrypt: ^5.0.1

Understanding Biometric Authentication and Data Encryption πŸ€”πŸ”

Biometric authentication is a secure way to verify a user’s identity using their unique biological traits, such as fingerprints or facial features. On the other hand, data encryption involves converting sensitive information into unreadable cipher text, which can only be decrypted with a specific cryptographic key. πŸ§¬πŸ”

Biometric Authentication with local_auth πŸ‘€πŸ”

The local_auth the package allows us to authenticate the user using biometrics on their device. Let's integrate it into our Flutter app:

import 'package:flutter/material.dart';
import 'package:local_auth/local_auth.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'dart:convert';
import 'dart:typed_data';
import 'package:encrypt/encrypt.dart';

final LocalAuthentication auth = LocalAuthentication();
final FlutterSecureStorage secureStorage = FlutterSecureStorage();

Future<void> main() async {
final int keyLength = 32;

try {
// Step 1: Biometric Authentication
bool authenticated = await auth.authenticate(
localizedReason: 'Let OS determine authentication method',
options: const AuthenticationOptions(
stickyAuth: true,
),
);

if (authenticated) {
// Step 2: Generate the Cryptographic Key
final Uint8List cryptographicKey = generateCryptographicKey(keyLength);

// Step 3: Store the Cryptographic Key in Secure Storage
await secureStorage.write(key: 'cryptographic_key', value: base64.encode(cryptographicKey));

// Step 4: Encrypt and Store Data (Not covered in this blog)

// Step 5: Use the Cryptographic Key to Decrypt Data (Not covered in this blog)
}
} catch (e) {
print('Authentication failed: $e');
}
}

we perform biometric authentication using local_auth. If the user is successfully authenticated, we generate a cryptographic key and store it securely using FlutterSecureStorage. πŸ“±πŸ”’

Generating a Cryptographic Key πŸ”‘πŸ”’

A cryptographic key is essential for data encryption and decryption. Let’s start by creating a function to generate a secure cryptographic key:

import 'dart:typed_data';
import 'package:random/random.dart';

Uint8List generateCryptographicKey(int keyLength) {
final random = Random.secure();
final key = Uint8List(keyLength);
for (int i = 0; i < key.length; i++) {
key[i] = random.nextInt(256);
}
return key;
}

In this function, we use the random package to generate a sequence of random bytes, which form the cryptographic key. πŸŽ²πŸ”

Encryption and Decryption Functions πŸ”’πŸ”“

To achieve secure data encryption and decryption, we need two functions: encryptAndStoreData and decryptData.

encryptAndStoreData

import 'package:encrypt/encrypt.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'dart:convert';

final FlutterSecureStorage secureStorage = FlutterSecureStorage();

Future<void> encryptAndStoreData(String data, Uint8List cryptographicKey) async {
final key = Key(cryptographicKey);
final iv = IV.fromLength(16);
final encrypter = Encrypter(AES(key));
final encryptedData = encrypter.encrypt(data, iv: iv);

await secureStorage.write(key: 'encrypted_data_key', value: encryptedData.base64);
}

The encryptAndStoreData function takes the sensitive data and the cryptographicKey as input. It uses the encrypt package to perform AES encryption with the provided key and initialization vector (IV). The encrypted data is then stored securely using FlutterSecureStorage. πŸ“πŸ”

decryptData

Future<String> decryptData(Uint8List cryptographicKey) async {
final String? encryptedData = await secureStorage.read(key: 'encrypted_data_key');
if (encryptedData == null) {
throw Exception('Encrypted data not found.');
}

final key = Key(cryptographicKey);
final iv = IV.fromLength(16);
final encrypter = Encrypter(AES(key));
final encrypted = Encrypted.fromBase64(encryptedData);
final decrypted = encrypter.decrypt(encrypted, iv: iv);

return decrypted;
}

The decryptData function retrieves the encrypted data from FlutterSecureStorage, and then decrypts it using the cryptographicKey provided as input. It follows the same AES decryption process with the key and IV to retrieve the original sensitive data. πŸ”πŸ”“

Security β€” Android Keystore πŸ›‘οΈ

For Android devices, the cryptographic key generated during biometric authentication is securely stored in the Android Keystore. The Android Keystore is a secure system-wide storage for cryptographic keys and certificates, making it extremely difficult for other applications to access the keys. This ensures the highest level of security for the cryptographic key used in data encryption and decryption. πŸ€–πŸ”’

Conclusion πŸπŸŽ‰

In this blog post, we explored how to implement biometrically authenticated data encryption and decryption in Flutter. By integrating biometric authentication and secure storage of cryptographic keys, we can ensure that sensitive data remains protected even if the device falls into the wrong hands. Remember to handle data encryption and decryption with care, follow security best practices, and regularly update your app’s security measures to stay ahead of potential threats. πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

With the steps outlined in this blog, you can create a secure and user-friendly experience for your users while safeguarding their sensitive data. Happy coding! πŸš€πŸ’»

You can check-out the full source code here: https://github.com/rkmonarch/flutter-biometric-encryption

--

--