Make no assumptions about the encoding type of the key

This commit is contained in:
Vishnu Mohandas 2020-09-10 01:01:14 +05:30
parent 79b27084f5
commit 4cd93610f7
6 changed files with 56 additions and 45 deletions

View file

@ -1,5 +1,6 @@
import 'dart:convert';
import 'dart:io' as io;
import 'dart:typed_data';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:path_provider/path_provider.dart';
@ -43,17 +44,20 @@ class Configuration {
}
Future<KeyAttributes> generateAndSaveKey(String passphrase) async {
final key = CryptoUtil.getBase64EncodedSecureRandomString(length: 32);
final key = CryptoUtil.getSecureRandomBytes(length: 32);
final kekSalt = CryptoUtil.getSecureRandomBytes(length: 32);
final kek = CryptoUtil.scrypt(utf8.encode(passphrase), kekSalt);
final kekHashSalt = CryptoUtil.getSecureRandomBytes(length: 32);
final kekHash = CryptoUtil.scrypt(kek, kekHashSalt);
final iv = CryptoUtil.getBase64EncodedSecureRandomString(length: 16);
final encryptedKey =
CryptoUtil.encryptToBase64(key, base64.encode(kek), iv);
final attributes = KeyAttributes(base64.encode(kekSalt),
base64.encode(kekHash), base64.encode(kekHashSalt), encryptedKey, iv);
await setKey(key);
final iv = CryptoUtil.getSecureRandomBytes(length: 16);
final encryptedKey = CryptoUtil.aesEncrypt(key, kek, iv);
final attributes = KeyAttributes(
base64.encode(kekSalt),
base64.encode(kekHash),
base64.encode(kekHashSalt),
base64.encode(encryptedKey),
base64.encode(iv));
await setKey(base64.encode(key));
await setKeyAttributes(attributes);
return attributes;
}
@ -149,7 +153,11 @@ class Configuration {
_key = key;
}
String getKey() {
Uint8List getKey() {
return base64.decode(_key);
}
String getBase64EncodedKey() {
return _key;
}
@ -166,6 +174,6 @@ class Configuration {
}
bool hasConfiguredAccount() {
return getToken() != null && getKey() != null;
return getToken() != null && getBase64EncodedKey() != null;
}
}

View file

@ -41,16 +41,19 @@ class FileUploadManager {
}
Future<File> encryptAndUploadFile(File file) async {
final key = CryptoUtil.getBase64EncodedSecureRandomString(length: 32);
final iv = CryptoUtil.getBase64EncodedSecureRandomString(length: 16);
final key = CryptoUtil.getSecureRandomBytes(length: 32);
final base64EncodedKey = base64.encode(key);
final iv = CryptoUtil.getSecureRandomBytes(length: 16);
final base64EncodedIV = base64.encode(iv);
final encryptedKey =
CryptoUtil.encryptToBase64(key, Configuration.instance.getKey(), iv);
CryptoUtil.aesEncrypt(key, Configuration.instance.getKey(), iv);
final base64EncodedEncryptedKey = base64.encode(encryptedKey);
final encryptedFileName = file.generatedID.toString() + ".aes";
final tempDirectory = Configuration.instance.getTempDirectory();
final encryptedFilePath = tempDirectory + encryptedFileName;
await CryptoUtil.encryptDataToFile(
await getBytesFromDisk(file), encryptedFilePath, key);
await getBytesFromDisk(file), encryptedFilePath, base64EncodedKey);
final fileUploadURL = await getUploadURL();
String fileObjectKey =
@ -62,21 +65,21 @@ class FileUploadManager {
file.generatedID.toString() + "_thumbnail.aes";
final encryptedThumbnailPath = tempDirectory + encryptedThumbnailName;
await CryptoUtil.encryptDataToFile(
thumbnailData, encryptedThumbnailPath, key);
thumbnailData, encryptedThumbnailPath, base64EncodedKey);
final thumbnailUploadURL = await getUploadURL();
String thumbnailObjectKey =
await putFile(thumbnailUploadURL, io.File(encryptedThumbnailPath));
final metadata = jsonEncode(file.getMetadata());
final encryptedMetadata =
await CryptoUtil.encryptDataToData(utf8.encode(metadata), key);
final encryptedMetadata = await CryptoUtil.encryptDataToData(
utf8.encode(metadata), base64EncodedKey);
final data = {
"fileObjectKey": fileObjectKey,
"thumbnailObjectKey": thumbnailObjectKey,
"metadata": encryptedMetadata,
"encryptedKey": encryptedKey,
"encryptedKeyIV": iv,
"encryptedKey": base64EncodedEncryptedKey,
"encryptedKeyIV": base64EncodedIV,
};
return _dio
.post(
@ -92,8 +95,8 @@ class FileUploadManager {
file.uploadedFileID = data["id"];
file.updationTime = data["updationTime"];
file.ownerID = data["ownerID"];
file.encryptedKey = encryptedKey;
file.encryptedKeyIV = iv;
file.encryptedKey = base64EncodedEncryptedKey;
file.encryptedKeyIV = base64EncodedIV;
return file;
});
}

View file

@ -140,7 +140,7 @@ class File {
return null;
}
return CryptoUtil.decryptFromBase64(
encryptedKey, Configuration.instance.getKey(), encryptedKeyIV);
encryptedKey, Configuration.instance.getBase64EncodedKey(), encryptedKeyIV);
}
@override

View file

@ -290,7 +290,7 @@ class PhotoSyncManager {
file.encryptedKey = json["encryptedKey"];
file.encryptedKeyIV = json["encryptedKeyIV"];
final key = CryptoUtil.decryptFromBase64(file.encryptedKey,
Configuration.instance.getKey(), file.encryptedKeyIV);
Configuration.instance.getBase64EncodedKey(), file.encryptedKeyIV);
Map<String, dynamic> metadata = jsonDecode(utf8.decode(
await CryptoUtil.decryptDataToData(json["metadata"], key)));
file.applyMetadata(metadata);

View file

@ -208,7 +208,7 @@ class DebugWidget extends StatelessWidget {
content: SingleChildScrollView(
child: Column(children: [
Text("Key", style: TextStyle(fontWeight: FontWeight.bold)),
Text(Configuration.instance.getKey()),
Text(Configuration.instance.getBase64EncodedKey()),
Padding(padding: EdgeInsets.all(12)),
Text("Encrypted Key", style: TextStyle(fontWeight: FontWeight.bold)),
Text(keyAttributes.encryptedKey),

View file

@ -11,10 +11,6 @@ import 'package:steel_crypt/steel_crypt.dart' as steel;
import 'package:uuid/uuid.dart';
class CryptoUtil {
static String getBase64EncodedSecureRandomString({int length = 32}) {
return SecureRandom(length).base64;
}
static Uint8List getSecureRandomBytes({int length = 32}) {
return SecureRandom(length).bytes;
}
@ -28,15 +24,15 @@ class CryptoUtil {
return base64.encode(scrypt(plainText, salt)) == base64.encode(hash);
}
static String encryptToBase64(
String plainText, String base64Key, String base64IV) {
final encrypter = AES(Key.fromBase64(base64Key));
static Uint8List aesEncrypt(
Uint8List plainText, Uint8List key, Uint8List iv) {
final encrypter = AES(Key(key));
return encrypter
.encrypt(
utf8.encode(plainText),
iv: IV.fromBase64(base64IV),
plainText,
iv: IV(iv),
)
.base64;
.bytes;
}
static String decryptFromBase64(
@ -58,18 +54,20 @@ class CryptoUtil {
}
static Future<String> encryptDataToFile(
Uint8List source, String destinationPath, String key) async {
Uint8List source, String destinationPath, String base64EncodedKey) async {
final args = Map<String, dynamic>();
args["key"] = key;
args["key"] = base64EncodedKey;
args["source"] = source;
args["destination"] = destinationPath;
return Computer().compute(runEncryptDataToFile, param: args);
}
static Future<String> encryptDataToData(Uint8List source, String key) async {
static Future<String> encryptDataToData(
Uint8List source, String base64EncodedKey) async {
final destinationPath =
Configuration.instance.getTempDirectory() + Uuid().v4();
return encryptDataToFile(source, destinationPath, key).then((value) {
return encryptDataToFile(source, destinationPath, base64EncodedKey)
.then((value) {
final file = io.File(destinationPath);
final data = file.readAsBytesSync();
file.deleteSync();
@ -77,27 +75,29 @@ class CryptoUtil {
});
}
static Future<void> decryptFileToFile(
String sourcePath, String destinationPath, String key) async {
static Future<void> decryptFileToFile(String sourcePath,
String destinationPath, String base64EncodedKey) async {
final args = Map<String, String>();
args["key"] = key;
args["key"] = base64EncodedKey;
args["source"] = sourcePath;
args["destination"] = destinationPath;
return Computer().compute(runDecryptFileToFile, param: args);
}
static Future<Uint8List> decryptFileToData(String sourcePath, String key) {
static Future<Uint8List> decryptFileToData(
String sourcePath, String base64EncodedKey) {
final args = Map<String, String>();
args["key"] = key;
args["key"] = base64EncodedKey;
args["source"] = sourcePath;
return Computer().compute(runDecryptFileToData, param: args);
}
static Future<Uint8List> decryptDataToData(String source, String key) {
static Future<Uint8List> decryptDataToData(
Uint8List source, String base64EncodedKey) {
final sourcePath = Configuration.instance.getTempDirectory() + Uuid().v4();
final file = io.File(sourcePath);
file.writeAsBytesSync(base64.decode(source));
return decryptFileToData(sourcePath, key).then((value) {
file.writeAsBytesSync(source);
return decryptFileToData(sourcePath, base64EncodedKey).then((value) {
file.deleteSync();
return value;
});