158 lines
4.7 KiB
Dart

// Author: Hugo Pointcheval
// Email: git@pcl.ovh
// -----
// File: cipher_page.dart
// Created Date: 28/12/2021 13:33:15
// Last Modified: 27/05/2022 16:42:10
// -----
// Copyright (c) 2021
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:native_crypto/native_crypto.dart';
import 'package:native_crypto/native_crypto_ext.dart';
import 'package:native_crypto_example/widgets/button.dart';
import '../session.dart';
import '../widgets/output.dart';
// ignore: must_be_immutable
class CipherPage extends ConsumerWidget {
CipherPage({Key? key}) : super(key: key);
final Output keyContent = Output();
final Output encryptionStatus = Output();
final Output decryptionStatus = Output();
final TextEditingController _plainTextController = TextEditingController()
..text = 'PlainText';
CipherTextWrapper? cipherText;
Future<void> _encrypt(WidgetRef ref, Cipher cipher) async {
Session state = ref.read(sessionProvider.state).state;
final plainText = _plainTextController.text.trim();
if (state.secretKey.bytes.isEmpty) {
encryptionStatus
.print('No SecretKey!\nGo in Key tab and generate or derive one.');
} else if (plainText.isEmpty) {
encryptionStatus.print('Entry is empty');
} else {
var stringToBytes = plainText.toBytes();
cipherText = await cipher.encrypt(stringToBytes);
encryptionStatus.print('String successfully encrypted:\n');
CipherText unwrap = cipherText!.unwrap<CipherText>();
encryptionStatus.append(unwrap.base16);
}
}
Future<void> _alter() async {
if (cipherText == null) {
decryptionStatus.print('Encrypt before altering CipherText!');
} else {
// Add 1 to the first byte
Uint8List _altered = cipherText!.unwrap<CipherText>().bytes;
_altered[0] += 1;
// Recreate cipher text with altered data
cipherText = CipherTextWrapper.fromBytes(
_altered,
ivLength: AESMode.gcm.ivLength,
tagLength: AESMode.gcm.tagLength,
);
encryptionStatus.print('String successfully encrypted:\n');
CipherText unwrap = cipherText!.unwrap();
encryptionStatus.appendln(unwrap.base16);
decryptionStatus.print('CipherText altered!\nDecryption will fail.');
}
}
void _decrypt(WidgetRef ref, Cipher cipher) async {
Session state = ref.read(sessionProvider.state).state;
if (state.secretKey.bytes.isEmpty) {
decryptionStatus
.print('No SecretKey!\nGo in Key tab and generate or derive one.');
} else if (cipherText == null) {
decryptionStatus.print('Encrypt before decrypting!');
} else {
try {
Uint8List plainText = await cipher.decrypt(cipherText!);
var bytesToString = plainText.toStr();
decryptionStatus
.print('String successfully decrypted:\n\n$bytesToString');
} on NativeCryptoException catch (e) {
decryptionStatus.print(e.message ?? 'Decryption failed!');
}
}
}
@override
Widget build(BuildContext context, WidgetRef ref) {
Session state = ref.read(sessionProvider.state).state;
if (state.secretKey.bytes.isEmpty) {
keyContent
.print('No SecretKey!\nGo in Key tab and generate or derive one.');
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
const Align(
child: Text("Secret Key"),
alignment: Alignment.centerLeft,
),
keyContent,
],
),
),
);
}
keyContent.print(state.secretKey.bytes.toString());
AES cipher = AES(state.secretKey);
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
const Align(
child: Text("Secret Key"),
alignment: Alignment.centerLeft,
),
keyContent,
TextField(
controller: _plainTextController,
decoration: const InputDecoration(
hintText: 'Plain text',
),
),
Button(
() => _encrypt(ref, cipher),
"Encrypt",
),
encryptionStatus,
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Button(
_alter,
"Alter cipher",
),
Button(
() => _decrypt(ref, cipher),
"Decrypt",
),
],
),
decryptionStatus,
],
),
),
);
}
}