Make no assumptions about the encoding type of the key
This commit is contained in:
parent
79b27084f5
commit
4cd93610f7
6 changed files with 56 additions and 45 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ class File {
|
|||
return null;
|
||||
}
|
||||
return CryptoUtil.decryptFromBase64(
|
||||
encryptedKey, Configuration.instance.getKey(), encryptedKeyIV);
|
||||
encryptedKey, Configuration.instance.getBase64EncodedKey(), encryptedKeyIV);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue