|
@@ -4,31 +4,111 @@ import 'dart:io' as io;
|
|
import 'package:aes_crypt/aes_crypt.dart';
|
|
import 'package:aes_crypt/aes_crypt.dart';
|
|
import 'package:computer/computer.dart';
|
|
import 'package:computer/computer.dart';
|
|
import 'package:encrypt/encrypt.dart';
|
|
import 'package:encrypt/encrypt.dart';
|
|
|
|
+import 'package:encrypt/encrypt.dart' as e;
|
|
import 'package:flutter_sodium/flutter_sodium.dart';
|
|
import 'package:flutter_sodium/flutter_sodium.dart';
|
|
import 'package:logging/logging.dart';
|
|
import 'package:logging/logging.dart';
|
|
|
|
|
|
import 'package:photos/core/configuration.dart';
|
|
import 'package:photos/core/configuration.dart';
|
|
-import 'package:photos/models/decryption_params.dart';
|
|
|
|
import 'package:photos/models/encrypted_data_attributes.dart';
|
|
import 'package:photos/models/encrypted_data_attributes.dart';
|
|
import 'package:photos/models/encrypted_file_attributes.dart';
|
|
import 'package:photos/models/encrypted_file_attributes.dart';
|
|
import 'package:photos/models/encryption_attribute.dart';
|
|
import 'package:photos/models/encryption_attribute.dart';
|
|
import 'package:steel_crypt/steel_crypt.dart' as steel;
|
|
import 'package:steel_crypt/steel_crypt.dart' as steel;
|
|
import 'package:uuid/uuid.dart';
|
|
import 'package:uuid/uuid.dart';
|
|
|
|
|
|
-class CryptoUtil {
|
|
|
|
- static Logger _logger = Logger("CryptoUtil");
|
|
|
|
|
|
+final int encryptionChunkSize = 4 * 1024 * 1024;
|
|
|
|
+final int decryptionChunkSize =
|
|
|
|
+ encryptionChunkSize + Sodium.cryptoSecretstreamXchacha20poly1305Abytes;
|
|
|
|
+
|
|
|
|
+Uint8List cryptoSecretboxEasy(Map<String, dynamic> args) {
|
|
|
|
+ return Sodium.cryptoSecretboxEasy(args["source"], args["nonce"], args["key"]);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+Uint8List cryptoSecretboxOpenEasy(Map<String, dynamic> args) {
|
|
|
|
+ return Sodium.cryptoSecretboxOpenEasy(
|
|
|
|
+ args["cipher"], args["nonce"], args["key"]);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+ChaChaAttributes chachaEncrypt(Map<String, dynamic> args) {
|
|
|
|
+ final encryptionStartTime = DateTime.now().millisecondsSinceEpoch;
|
|
|
|
+ final logger = Logger("ChaChaEncrypt");
|
|
|
|
+ final sourceFile = io.File(args["sourceFilePath"]);
|
|
|
|
+ final destinationFile = io.File(args["destinationFilePath"]);
|
|
|
|
+ final sourceFileLength = sourceFile.lengthSync();
|
|
|
|
+ logger.info("Encrypting file of size " + sourceFileLength.toString());
|
|
|
|
+
|
|
|
|
+ final inputFile = sourceFile.openSync(mode: io.FileMode.read);
|
|
|
|
+ final key = Sodium.cryptoSecretstreamXchacha20poly1305Keygen();
|
|
|
|
+ final initPushResult =
|
|
|
|
+ Sodium.cryptoSecretstreamXchacha20poly1305InitPush(key);
|
|
|
|
+ var bytesRead = 0;
|
|
|
|
+ var tag = Sodium.cryptoSecretstreamXchacha20poly1305TagMessage;
|
|
|
|
+ while (tag != Sodium.cryptoSecretstreamXchacha20poly1305TagFinal) {
|
|
|
|
+ var chunkSize = encryptionChunkSize;
|
|
|
|
+ if (bytesRead + chunkSize >= sourceFileLength) {
|
|
|
|
+ chunkSize = sourceFileLength - bytesRead;
|
|
|
|
+ tag = Sodium.cryptoSecretstreamXchacha20poly1305TagFinal;
|
|
|
|
+ }
|
|
|
|
+ final buffer = inputFile.readSync(chunkSize);
|
|
|
|
+ bytesRead += chunkSize;
|
|
|
|
+ final encryptedData = Sodium.cryptoSecretstreamXchacha20poly1305Push(
|
|
|
|
+ initPushResult.state, buffer, null, tag);
|
|
|
|
+ destinationFile.writeAsBytesSync(encryptedData, mode: io.FileMode.append);
|
|
|
|
+ }
|
|
|
|
+ inputFile.closeSync();
|
|
|
|
+
|
|
|
|
+ logger.info("Encryption time: " +
|
|
|
|
+ (DateTime.now().millisecondsSinceEpoch - encryptionStartTime).toString());
|
|
|
|
|
|
- static int encryptionChunkSize = 4 * 1024 * 1024;
|
|
|
|
- static int decryptionChunkSize =
|
|
|
|
- encryptionChunkSize + Sodium.cryptoSecretstreamXchacha20poly1305Abytes;
|
|
|
|
|
|
+ return ChaChaAttributes(EncryptionAttribute(bytes: key),
|
|
|
|
+ EncryptionAttribute(bytes: initPushResult.header));
|
|
|
|
+}
|
|
|
|
|
|
|
|
+void chachaDecrypt(Map<String, dynamic> args) {
|
|
|
|
+ final logger = Logger("ChaChaDecrypt");
|
|
|
|
+ final decryptionStartTime = DateTime.now().millisecondsSinceEpoch;
|
|
|
|
+ final sourceFile = io.File(args["sourceFilePath"]);
|
|
|
|
+ final destinationFile = io.File(args["destinationFilePath"]);
|
|
|
|
+ final sourceFileLength = sourceFile.lengthSync();
|
|
|
|
+ logger.info("Decrypting file of size " + sourceFileLength.toString());
|
|
|
|
+
|
|
|
|
+ final inputFile = sourceFile.openSync(mode: io.FileMode.read);
|
|
|
|
+ final pullState = Sodium.cryptoSecretstreamXchacha20poly1305InitPull(
|
|
|
|
+ args["header"], args["key"]);
|
|
|
|
+
|
|
|
|
+ var bytesRead = 0;
|
|
|
|
+ var tag = Sodium.cryptoSecretstreamXchacha20poly1305TagMessage;
|
|
|
|
+ while (tag != Sodium.cryptoSecretstreamXchacha20poly1305TagFinal) {
|
|
|
|
+ var chunkSize = decryptionChunkSize;
|
|
|
|
+ if (bytesRead + chunkSize >= sourceFileLength) {
|
|
|
|
+ chunkSize = sourceFileLength - bytesRead;
|
|
|
|
+ }
|
|
|
|
+ final buffer = inputFile.readSync(chunkSize);
|
|
|
|
+ bytesRead += chunkSize;
|
|
|
|
+ final pullResult =
|
|
|
|
+ Sodium.cryptoSecretstreamXchacha20poly1305Pull(pullState, buffer, null);
|
|
|
|
+ destinationFile.writeAsBytesSync(pullResult.m, mode: io.FileMode.append);
|
|
|
|
+ tag = pullResult.tag;
|
|
|
|
+ }
|
|
|
|
+ inputFile.closeSync();
|
|
|
|
+
|
|
|
|
+ logger.info("ChaCha20 Decryption time: " +
|
|
|
|
+ (DateTime.now().millisecondsSinceEpoch - decryptionStartTime).toString());
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+class CryptoUtil {
|
|
static Future<EncryptedData> encrypt(Uint8List source,
|
|
static Future<EncryptedData> encrypt(Uint8List source,
|
|
{Uint8List key}) async {
|
|
{Uint8List key}) async {
|
|
if (key == null) {
|
|
if (key == null) {
|
|
key = Sodium.cryptoSecretboxKeygen();
|
|
key = Sodium.cryptoSecretboxKeygen();
|
|
}
|
|
}
|
|
final nonce = Sodium.randombytesBuf(Sodium.cryptoSecretboxNoncebytes);
|
|
final nonce = Sodium.randombytesBuf(Sodium.cryptoSecretboxNoncebytes);
|
|
- final encryptedData = Sodium.cryptoSecretboxEasy(source, nonce, key);
|
|
|
|
|
|
+
|
|
|
|
+ final args = Map<String, dynamic>();
|
|
|
|
+ args["source"] = source;
|
|
|
|
+ args["nonce"] = nonce;
|
|
|
|
+ args["key"] = key;
|
|
|
|
+ final encryptedData = await Computer().compute(chachaDecrypt, param: args);
|
|
|
|
+
|
|
return EncryptedData(
|
|
return EncryptedData(
|
|
EncryptionAttribute(bytes: key),
|
|
EncryptionAttribute(bytes: key),
|
|
EncryptionAttribute(bytes: nonce),
|
|
EncryptionAttribute(bytes: nonce),
|
|
@@ -36,93 +116,40 @@ class CryptoUtil {
|
|
}
|
|
}
|
|
|
|
|
|
static Future<Uint8List> decrypt(
|
|
static Future<Uint8List> decrypt(
|
|
- String base64Cipher, String base64Key, String base64Nonce) async {
|
|
|
|
- return Sodium.cryptoSecretboxOpenEasy(Sodium.base642bin(base64Cipher),
|
|
|
|
- Sodium.base642bin(base64Nonce), Sodium.base642bin(base64Key));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- static Future<Uint8List> decryptWithDecryptionParams(
|
|
|
|
- Uint8List source, DecryptionParams params, String base64Kek) async {
|
|
|
|
- final key = Sodium.cryptoSecretboxOpenEasy(
|
|
|
|
- Sodium.base642bin(params.encryptedKey),
|
|
|
|
- Sodium.base642bin(params.keyDecryptionNonce),
|
|
|
|
- Sodium.base642bin(base64Kek));
|
|
|
|
- return Sodium.cryptoSecretboxOpenEasy(
|
|
|
|
- source, Sodium.base642bin(params.nonce), key);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- static Future<ChaChaAttributes> chachaEncrypt(
|
|
|
|
- io.File sourceFile,
|
|
|
|
- io.File destinationFile,
|
|
|
|
- ) async {
|
|
|
|
- var encryptionStartTime = DateTime.now().millisecondsSinceEpoch;
|
|
|
|
-
|
|
|
|
- final sourceFileLength = sourceFile.lengthSync();
|
|
|
|
- _logger.info("Encrypting file of size " + sourceFileLength.toString());
|
|
|
|
-
|
|
|
|
- final inputFile = await (sourceFile.open(mode: io.FileMode.read));
|
|
|
|
-
|
|
|
|
- final key = Sodium.cryptoSecretstreamXchacha20poly1305Keygen();
|
|
|
|
- final initPushResult =
|
|
|
|
- Sodium.cryptoSecretstreamXchacha20poly1305InitPush(key);
|
|
|
|
-
|
|
|
|
- var bytesRead = 0;
|
|
|
|
- var tag = Sodium.cryptoSecretstreamXchacha20poly1305TagMessage;
|
|
|
|
- while (tag != Sodium.cryptoSecretstreamXchacha20poly1305TagFinal) {
|
|
|
|
- var chunkSize = encryptionChunkSize;
|
|
|
|
- if (bytesRead + chunkSize >= sourceFileLength) {
|
|
|
|
- chunkSize = sourceFileLength - bytesRead;
|
|
|
|
- tag = Sodium.cryptoSecretstreamXchacha20poly1305TagFinal;
|
|
|
|
- }
|
|
|
|
- final buffer = await inputFile.read(chunkSize);
|
|
|
|
- bytesRead += chunkSize;
|
|
|
|
- final encryptedData = Sodium.cryptoSecretstreamXchacha20poly1305Push(
|
|
|
|
- initPushResult.state, buffer, null, tag);
|
|
|
|
- destinationFile.writeAsBytesSync(encryptedData, mode: io.FileMode.append);
|
|
|
|
|
|
+ Uint8List cipher, Uint8List key, Uint8List nonce,
|
|
|
|
+ {bool background = false}) async {
|
|
|
|
+ final args = Map<String, dynamic>();
|
|
|
|
+ args["cipher"] = cipher;
|
|
|
|
+ args["nonce"] = nonce;
|
|
|
|
+ args["key"] = key;
|
|
|
|
+ if (background) {
|
|
|
|
+ return Computer().compute(chachaDecrypt, param: args);
|
|
|
|
+ } else {
|
|
|
|
+ return cryptoSecretboxOpenEasy(args);
|
|
}
|
|
}
|
|
- await inputFile.close();
|
|
|
|
-
|
|
|
|
- _logger.info("ChaCha20 Encryption time: " +
|
|
|
|
- (DateTime.now().millisecondsSinceEpoch - encryptionStartTime)
|
|
|
|
- .toString());
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- return ChaChaAttributes(EncryptionAttribute(bytes: key),
|
|
|
|
- EncryptionAttribute(bytes: initPushResult.header));
|
|
|
|
|
|
+ static Future<ChaChaAttributes> encryptFile(
|
|
|
|
+ String sourceFilePath,
|
|
|
|
+ String destinationFilePath,
|
|
|
|
+ ) {
|
|
|
|
+ final args = Map<String, dynamic>();
|
|
|
|
+ args["sourceFilePath"] = sourceFilePath;
|
|
|
|
+ args["destinationFilePath"] = destinationFilePath;
|
|
|
|
+ return Computer().compute(chachaDecrypt, param: args);
|
|
}
|
|
}
|
|
|
|
|
|
- static Future<void> chachaDecrypt(
|
|
|
|
- io.File sourceFile,
|
|
|
|
- io.File destinationFile,
|
|
|
|
|
|
+ static Future<void> decryptFile(
|
|
|
|
+ String sourceFilePath,
|
|
|
|
+ String destinationFilePath,
|
|
ChaChaAttributes attributes,
|
|
ChaChaAttributes attributes,
|
|
- ) async {
|
|
|
|
- var decryptionStartTime = DateTime.now().millisecondsSinceEpoch;
|
|
|
|
-
|
|
|
|
- final sourceFileLength = sourceFile.lengthSync();
|
|
|
|
- _logger.info("Decrypting file of size " + sourceFileLength.toString());
|
|
|
|
-
|
|
|
|
- final inputFile = await (sourceFile.open(mode: io.FileMode.read));
|
|
|
|
- final pullState = Sodium.cryptoSecretstreamXchacha20poly1305InitPull(
|
|
|
|
- attributes.header.bytes, attributes.key.bytes);
|
|
|
|
-
|
|
|
|
- var bytesRead = 0;
|
|
|
|
- var tag = Sodium.cryptoSecretstreamXchacha20poly1305TagMessage;
|
|
|
|
- while (tag != Sodium.cryptoSecretstreamXchacha20poly1305TagFinal) {
|
|
|
|
- var chunkSize = decryptionChunkSize;
|
|
|
|
- if (bytesRead + chunkSize >= sourceFileLength) {
|
|
|
|
- chunkSize = sourceFileLength - bytesRead;
|
|
|
|
- }
|
|
|
|
- final buffer = await inputFile.read(chunkSize);
|
|
|
|
- bytesRead += chunkSize;
|
|
|
|
- final pullResult = Sodium.cryptoSecretstreamXchacha20poly1305Pull(
|
|
|
|
- pullState, buffer, null);
|
|
|
|
- destinationFile.writeAsBytesSync(pullResult.m, mode: io.FileMode.append);
|
|
|
|
- tag = pullResult.tag;
|
|
|
|
- }
|
|
|
|
- await inputFile.close();
|
|
|
|
-
|
|
|
|
- _logger.info("ChaCha20 Decryption time: " +
|
|
|
|
- (DateTime.now().millisecondsSinceEpoch - decryptionStartTime)
|
|
|
|
- .toString());
|
|
|
|
|
|
+ ) {
|
|
|
|
+ final args = Map<String, dynamic>();
|
|
|
|
+ args["sourceFilePath"] = sourceFilePath;
|
|
|
|
+ args["destinationFilePath"] = destinationFilePath;
|
|
|
|
+ args["header"] = attributes.header.bytes;
|
|
|
|
+ args["key"] = attributes.key.bytes;
|
|
|
|
+ return Computer().compute(chachaDecrypt, param: args);
|
|
}
|
|
}
|
|
|
|
|
|
static Uint8List getSecureRandomBytes({int length = 32}) {
|
|
static Uint8List getSecureRandomBytes({int length = 32}) {
|
|
@@ -140,7 +167,7 @@ class CryptoUtil {
|
|
|
|
|
|
static Uint8List aesEncrypt(
|
|
static Uint8List aesEncrypt(
|
|
Uint8List plainText, Uint8List key, Uint8List iv) {
|
|
Uint8List plainText, Uint8List key, Uint8List iv) {
|
|
- final encrypter = AES(Key(key), mode: AESMode.cbc);
|
|
|
|
|
|
+ final encrypter = AES(e.Key(key), mode: AESMode.cbc);
|
|
return encrypter
|
|
return encrypter
|
|
.encrypt(
|
|
.encrypt(
|
|
plainText,
|
|
plainText,
|
|
@@ -151,7 +178,7 @@ class CryptoUtil {
|
|
|
|
|
|
static Uint8List aesDecrypt(
|
|
static Uint8List aesDecrypt(
|
|
Uint8List cipherText, Uint8List key, Uint8List iv) {
|
|
Uint8List cipherText, Uint8List key, Uint8List iv) {
|
|
- final encrypter = AES(Key(key), mode: AESMode.cbc);
|
|
|
|
|
|
+ final encrypter = AES(e.Key(key), mode: AESMode.cbc);
|
|
return encrypter.decrypt(
|
|
return encrypter.decrypt(
|
|
Encrypted(cipherText),
|
|
Encrypted(cipherText),
|
|
iv: IV(iv),
|
|
iv: IV(iv),
|