Switch to libsodium for file encryption and decryption
This commit is contained in:
parent
44866f7ffe
commit
727a1684ce
9 changed files with 198 additions and 117 deletions
|
@ -1,6 +1,7 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:photos/models/decryption_params.dart';
|
||||
import 'package:photos/models/file_type.dart';
|
||||
import 'package:photos/models/location.dart';
|
||||
import 'package:photos/models/file.dart';
|
||||
|
@ -31,8 +32,9 @@ class FilesDB {
|
|||
static final columnCreationTime = 'creation_time';
|
||||
static final columnModificationTime = 'modification_time';
|
||||
static final columnUpdationTime = 'updation_time';
|
||||
static final columnEncryptedPassword = 'encrypted_password';
|
||||
static final columnEncryptedPasswordIV = 'encrypted_password_iv';
|
||||
static final columnFileDecryptionParams = 'file_decryption_params';
|
||||
static final columnThumbnailDecryptionParams = 'thumbnail_decryption_params';
|
||||
static final columnMetadataDecryptionParams = 'metadata_decryption_params';
|
||||
|
||||
// make this a singleton class
|
||||
FilesDB._privateConstructor();
|
||||
|
@ -74,8 +76,9 @@ class FilesDB {
|
|||
$columnCreationTime TEXT NOT NULL,
|
||||
$columnModificationTime TEXT NOT NULL,
|
||||
$columnUpdationTime TEXT,
|
||||
$columnEncryptedPassword TEXT,
|
||||
$columnEncryptedPasswordIV TEXT
|
||||
$columnFileDecryptionParams TEXT,
|
||||
$columnThumbnailDecryptionParams TEXT,
|
||||
$columnMetadataDecryptionParams TEXT
|
||||
)
|
||||
''');
|
||||
}
|
||||
|
@ -224,15 +227,18 @@ class FilesDB {
|
|||
int generatedID,
|
||||
int uploadedID,
|
||||
int updationTime,
|
||||
String encryptedKey,
|
||||
String iv,
|
||||
DecryptionParams fileDecryptionParams,
|
||||
DecryptionParams thumbnailDecryptionParams,
|
||||
DecryptionParams metadataDecryptionParams,
|
||||
) async {
|
||||
final db = await instance.database;
|
||||
final values = new Map<String, dynamic>();
|
||||
values[columnUploadedFileID] = uploadedID;
|
||||
values[columnUpdationTime] = updationTime;
|
||||
values[columnEncryptedPassword] = encryptedKey;
|
||||
values[columnEncryptedPasswordIV] = iv;
|
||||
values[columnFileDecryptionParams] = fileDecryptionParams.toJson();
|
||||
values[columnThumbnailDecryptionParams] =
|
||||
thumbnailDecryptionParams.toJson();
|
||||
values[columnMetadataDecryptionParams] = metadataDecryptionParams.toJson();
|
||||
return await db.update(
|
||||
table,
|
||||
values,
|
||||
|
@ -384,8 +390,16 @@ class FilesDB {
|
|||
row[columnCreationTime] = file.creationTime;
|
||||
row[columnModificationTime] = file.modificationTime;
|
||||
row[columnUpdationTime] = file.updationTime;
|
||||
row[columnEncryptedPassword] = file.encryptedPassword;
|
||||
row[columnEncryptedPasswordIV] = file.encryptedPasswordIV;
|
||||
row[columnFileDecryptionParams] = file.fileDecryptionParams == null
|
||||
? null
|
||||
: file.fileDecryptionParams.toJson();
|
||||
row[columnThumbnailDecryptionParams] =
|
||||
file.thumbnailDecryptionParams == null
|
||||
? null
|
||||
: file.thumbnailDecryptionParams.toJson();
|
||||
row[columnMetadataDecryptionParams] = file.metadataDecryptionParams == null
|
||||
? null
|
||||
: file.metadataDecryptionParams.toJson();
|
||||
return row;
|
||||
}
|
||||
|
||||
|
@ -408,8 +422,12 @@ class FilesDB {
|
|||
file.updationTime = row[columnUpdationTime] == null
|
||||
? -1
|
||||
: int.parse(row[columnUpdationTime]);
|
||||
file.encryptedPassword = row[columnEncryptedPassword];
|
||||
file.encryptedPasswordIV = row[columnEncryptedPasswordIV];
|
||||
file.fileDecryptionParams =
|
||||
DecryptionParams.fromJson(row[columnFileDecryptionParams]);
|
||||
file.thumbnailDecryptionParams =
|
||||
DecryptionParams.fromJson(row[columnThumbnailDecryptionParams]);
|
||||
file.metadataDecryptionParams =
|
||||
DecryptionParams.fromJson(row[columnMetadataDecryptionParams]);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:logging/logging.dart';
|
|||
import 'package:photos/core/configuration.dart';
|
||||
import 'package:photos/core/event_bus.dart';
|
||||
import 'package:photos/events/remote_sync_event.dart';
|
||||
import 'package:photos/models/decryption_params.dart';
|
||||
import 'package:photos/models/file.dart';
|
||||
import 'package:photos/utils/crypto_util.dart';
|
||||
|
||||
|
@ -28,18 +29,23 @@ class DiffFetcher {
|
|||
if (response != null) {
|
||||
Bus.instance.fire(RemoteSyncEvent(true));
|
||||
final diff = response.data["diff"] as List;
|
||||
for (final fileItem in diff) {
|
||||
for (final item in diff) {
|
||||
final file = File();
|
||||
file.uploadedFileID = fileItem["id"];
|
||||
file.ownerID = fileItem["ownerID"];
|
||||
file.updationTime = fileItem["updationTime"];
|
||||
file.uploadedFileID = item["id"];
|
||||
file.ownerID = item["ownerID"];
|
||||
file.updationTime = item["updationTime"];
|
||||
file.isEncrypted = true;
|
||||
file.encryptedPassword = fileItem["encryptedPassword"];
|
||||
file.encryptedPasswordIV = fileItem["encryptedPasswordIV"];
|
||||
file.fileDecryptionParams =
|
||||
DecryptionParams.fromMap(item["file"]["decryptionParams"]);
|
||||
file.thumbnailDecryptionParams = DecryptionParams.fromMap(
|
||||
item["thumbnail"]["decryptionParams"]);
|
||||
file.metadataDecryptionParams = DecryptionParams.fromMap(
|
||||
item["metadata"]["decryptionParams"]);
|
||||
Map<String, dynamic> metadata = jsonDecode(utf8.decode(
|
||||
await CryptoUtil.decryptDataToData(
|
||||
base64.decode(fileItem["encryptedMetadata"]),
|
||||
file.getPassword())));
|
||||
await CryptoUtil.decryptWithDecryptionParams(
|
||||
base64.decode(item["metadata"]["encryptedData"]),
|
||||
file.metadataDecryptionParams,
|
||||
Configuration.instance.getBase64EncodedKey())));
|
||||
file.applyMetadata(metadata);
|
||||
files.add(file);
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ import 'package:dio/dio.dart';
|
|||
import 'package:logging/logging.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import 'package:photos/core/constants.dart';
|
||||
import 'package:photos/models/decryption_params.dart';
|
||||
import 'package:photos/models/file.dart';
|
||||
import 'package:photos/models/file_type.dart';
|
||||
import 'package:photos/models/upload_url.dart';
|
||||
import 'package:photos/utils/crypto_util.dart';
|
||||
import 'package:photos/utils/file_name_util.dart';
|
||||
|
@ -41,46 +41,30 @@ class FileUploader {
|
|||
});
|
||||
}
|
||||
|
||||
// TODO: Remove encryption and decryption time logging
|
||||
Future<File> encryptAndUploadFile(File file) async {
|
||||
_logger.info("Uploading " + file.toString());
|
||||
|
||||
final password = CryptoUtil.getSecureRandomString(length: 32);
|
||||
final iv = CryptoUtil.getSecureRandomBytes(length: 16);
|
||||
final base64EncodedIV = base64.encode(iv);
|
||||
final encryptedKey = CryptoUtil.aesEncrypt(
|
||||
utf8.encode(password), Configuration.instance.getKey(), iv);
|
||||
final base64EncodedEncryptedKey = base64.encode(encryptedKey);
|
||||
|
||||
final encryptedFileName = file.generatedID.toString() + ".aes";
|
||||
final encryptedFileName = file.generatedID.toString() + ".encrypted";
|
||||
final tempDirectory = Configuration.instance.getTempDirectory();
|
||||
final encryptedFilePath = tempDirectory + encryptedFileName;
|
||||
|
||||
_logger.info("File size " +
|
||||
(await (await file.getAsset()).file).lengthSync().toString());
|
||||
final encryptionStartTime = DateTime.now().millisecondsSinceEpoch;
|
||||
if (file.fileType == FileType.image) {
|
||||
await CryptoUtil.encryptDataToFile(
|
||||
await getBytesFromDisk(file), encryptedFilePath, password);
|
||||
} else {
|
||||
await CryptoUtil.encryptFileToFile(
|
||||
(await (await file.getAsset()).originFile).path,
|
||||
encryptedFilePath,
|
||||
password);
|
||||
}
|
||||
final encryptionStopTime = DateTime.now().millisecondsSinceEpoch;
|
||||
_logger.info("Encryption time: " +
|
||||
(encryptionStopTime - encryptionStartTime).toString());
|
||||
|
||||
final decryptionStartTime = DateTime.now().millisecondsSinceEpoch;
|
||||
await CryptoUtil.decryptFileToData(encryptedFilePath, password);
|
||||
final decryptionStopTime = DateTime.now().millisecondsSinceEpoch;
|
||||
_logger.info("Decryption time: " +
|
||||
(decryptionStopTime - decryptionStartTime).toString());
|
||||
final sourceFile = (await (await file.getAsset()).originFile);
|
||||
final encryptedFile = io.File(encryptedFilePath);
|
||||
final fileAttributes =
|
||||
await CryptoUtil.chachaEncrypt(sourceFile, encryptedFile);
|
||||
|
||||
final fileUploadURL = await getUploadURL();
|
||||
String fileObjectKey =
|
||||
await putFile(fileUploadURL, io.File(encryptedFilePath));
|
||||
String fileObjectKey = await putFile(fileUploadURL, encryptedFile);
|
||||
|
||||
final encryptedFileKey = await CryptoUtil.encrypt(
|
||||
fileAttributes.key.bytes,
|
||||
key: Configuration.instance.getKey(),
|
||||
);
|
||||
final fileDecryptionParams = DecryptionParams(
|
||||
encryptedKey: encryptedFileKey.encryptedData.base64,
|
||||
keyDecryptionNonce: encryptedFileKey.nonce.base64,
|
||||
header: fileAttributes.header.base64,
|
||||
);
|
||||
|
||||
final thumbnailData = (await (await file.getAsset()).thumbDataWithSize(
|
||||
THUMBNAIL_LARGE_SIZE,
|
||||
|
@ -88,24 +72,50 @@ class FileUploader {
|
|||
quality: 50,
|
||||
));
|
||||
final encryptedThumbnailName =
|
||||
file.generatedID.toString() + "_thumbnail.aes";
|
||||
file.generatedID.toString() + "_thumbnail.encrypted";
|
||||
final encryptedThumbnailPath = tempDirectory + encryptedThumbnailName;
|
||||
await CryptoUtil.encryptDataToFile(
|
||||
thumbnailData, encryptedThumbnailPath, password);
|
||||
final encryptedThumbnail = await CryptoUtil.encrypt(thumbnailData);
|
||||
io.File(encryptedThumbnailPath)
|
||||
.writeAsBytesSync(encryptedThumbnail.encryptedData.bytes);
|
||||
|
||||
final thumbnailUploadURL = await getUploadURL();
|
||||
String thumbnailObjectKey =
|
||||
await putFile(thumbnailUploadURL, io.File(encryptedThumbnailPath));
|
||||
|
||||
final encryptedThumbnailKey = await CryptoUtil.encrypt(
|
||||
encryptedThumbnail.key.bytes,
|
||||
key: Configuration.instance.getKey(),
|
||||
);
|
||||
final thumbnailDecryptionParams = DecryptionParams(
|
||||
encryptedKey: encryptedThumbnailKey.encryptedData.base64,
|
||||
keyDecryptionNonce: encryptedThumbnailKey.nonce.base64,
|
||||
nonce: encryptedThumbnail.nonce.base64,
|
||||
);
|
||||
|
||||
final metadata = jsonEncode(file.getMetadata());
|
||||
final encryptedMetadata =
|
||||
await CryptoUtil.encryptDataToData(utf8.encode(metadata), password);
|
||||
final encryptedMetadata = await CryptoUtil.encrypt(utf8.encode(metadata));
|
||||
final encryptedMetadataKey = await CryptoUtil.encrypt(
|
||||
encryptedMetadata.key.bytes,
|
||||
key: Configuration.instance.getKey(),
|
||||
);
|
||||
final metadataDecryptionParams = DecryptionParams(
|
||||
encryptedKey: encryptedMetadataKey.encryptedData.base64,
|
||||
keyDecryptionNonce: encryptedMetadataKey.nonce.base64,
|
||||
nonce: encryptedMetadata.nonce.base64,
|
||||
);
|
||||
final data = {
|
||||
"fileObjectKey": fileObjectKey,
|
||||
"thumbnailObjectKey": thumbnailObjectKey,
|
||||
"encryptedMetadata": base64.encode(encryptedMetadata),
|
||||
"encryptedPassword": base64EncodedEncryptedKey,
|
||||
"encryptedPasswordIV": base64EncodedIV,
|
||||
"file": {
|
||||
"objectKey": fileObjectKey,
|
||||
"decryptionParams": fileDecryptionParams.toMap(),
|
||||
},
|
||||
"thumbnail": {
|
||||
"objectKey": thumbnailObjectKey,
|
||||
"decryptionParams": thumbnailDecryptionParams,
|
||||
},
|
||||
"metadata": {
|
||||
"encryptedData": encryptedMetadata.encryptedData.base64,
|
||||
"decryptionParams": metadataDecryptionParams,
|
||||
}
|
||||
};
|
||||
return _dio
|
||||
.post(
|
||||
|
@ -115,14 +125,15 @@ class FileUploader {
|
|||
data: data,
|
||||
)
|
||||
.then((response) {
|
||||
io.File(encryptedFilePath).deleteSync();
|
||||
encryptedFile.deleteSync();
|
||||
io.File(encryptedThumbnailPath).deleteSync();
|
||||
final data = response.data;
|
||||
file.uploadedFileID = data["id"];
|
||||
file.updationTime = data["updationTime"];
|
||||
file.ownerID = data["ownerID"];
|
||||
file.encryptedPassword = base64EncodedEncryptedKey;
|
||||
file.encryptedPasswordIV = base64EncodedIV;
|
||||
file.fileDecryptionParams = fileDecryptionParams;
|
||||
file.thumbnailDecryptionParams = thumbnailDecryptionParams;
|
||||
file.metadataDecryptionParams = metadataDecryptionParams;
|
||||
return file;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -71,11 +71,13 @@ class FolderSharingService {
|
|||
var existingPhoto =
|
||||
await FilesDB.instance.getMatchingRemoteFile(file.uploadedFileID);
|
||||
await FilesDB.instance.update(
|
||||
existingPhoto.generatedID,
|
||||
file.uploadedFileID,
|
||||
file.updationTime,
|
||||
file.encryptedPassword,
|
||||
file.encryptedPasswordIV);
|
||||
existingPhoto.generatedID,
|
||||
file.uploadedFileID,
|
||||
file.updationTime,
|
||||
file.fileDecryptionParams,
|
||||
file.thumbnailDecryptionParams,
|
||||
file.metadataDecryptionParams,
|
||||
);
|
||||
} catch (e) {
|
||||
await FilesDB.instance.insert(file);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'dart:typed_data';
|
||||
import 'package:photos/models/encryption_attribute.dart';
|
||||
|
||||
class EncryptedFileAttributes {
|
||||
final Uint8List key;
|
||||
final Uint8List header;
|
||||
class ChaChaAttributes {
|
||||
final EncryptionAttribute key;
|
||||
final EncryptionAttribute header;
|
||||
|
||||
EncryptedFileAttributes(this.key, this.header);
|
||||
ChaChaAttributes(this.key, this.header);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:photo_manager/photo_manager.dart';
|
||||
import 'package:path/path.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import 'package:photos/models/decryption_params.dart';
|
||||
import 'package:photos/models/file_type.dart';
|
||||
import 'package:photos/models/location.dart';
|
||||
import 'package:photos/utils/crypto_util.dart';
|
||||
|
||||
class File {
|
||||
int generatedID;
|
||||
|
@ -21,8 +19,9 @@ class File {
|
|||
int updationTime;
|
||||
Location location;
|
||||
FileType fileType;
|
||||
String encryptedPassword;
|
||||
String encryptedPasswordIV;
|
||||
DecryptionParams fileDecryptionParams;
|
||||
DecryptionParams thumbnailDecryptionParams;
|
||||
DecryptionParams metadataDecryptionParams;
|
||||
|
||||
File();
|
||||
|
||||
|
@ -36,8 +35,6 @@ class File {
|
|||
creationTime = json["creationTime"];
|
||||
modificationTime = json["modificationTime"];
|
||||
updationTime = json["updationTime"];
|
||||
encryptedPassword = json["encryptedPassword"];
|
||||
encryptedPasswordIV = json["encryptedPasswordIV"];
|
||||
}
|
||||
|
||||
static Future<File> fromAsset(
|
||||
|
@ -137,14 +134,6 @@ class File {
|
|||
Configuration.instance.getToken();
|
||||
}
|
||||
|
||||
String getPassword() {
|
||||
if (encryptedPassword == null) {
|
||||
return null;
|
||||
}
|
||||
return utf8.decode(CryptoUtil.aesDecrypt(base64.decode(encryptedPassword),
|
||||
Configuration.instance.getKey(), base64.decode(encryptedPasswordIV)));
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '''File(generatedId: $generatedID, uploadedFileId: $uploadedFileID,
|
||||
|
|
|
@ -223,11 +223,13 @@ class PhotoSyncManager {
|
|||
uploadedFile = await _uploader.uploadFile(file);
|
||||
}
|
||||
await _db.update(
|
||||
file.generatedID,
|
||||
uploadedFile.uploadedFileID,
|
||||
uploadedFile.updationTime,
|
||||
file.encryptedPassword,
|
||||
file.encryptedPasswordIV);
|
||||
file.generatedID,
|
||||
uploadedFile.uploadedFileID,
|
||||
uploadedFile.updationTime,
|
||||
file.fileDecryptionParams,
|
||||
file.thumbnailDecryptionParams,
|
||||
file.metadataDecryptionParams,
|
||||
);
|
||||
Bus.instance.fire(PhotoUploadEvent(
|
||||
completed: i + 1, total: filesToBeUploaded.length));
|
||||
} catch (e) {
|
||||
|
@ -248,11 +250,13 @@ class PhotoSyncManager {
|
|||
file.modificationTime,
|
||||
alternateTitle: getHEICFileNameForJPG(file));
|
||||
await _db.update(
|
||||
existingPhoto.generatedID,
|
||||
file.uploadedFileID,
|
||||
file.updationTime,
|
||||
file.encryptedPassword,
|
||||
file.encryptedPasswordIV);
|
||||
existingPhoto.generatedID,
|
||||
file.uploadedFileID,
|
||||
file.updationTime,
|
||||
file.fileDecryptionParams,
|
||||
file.thumbnailDecryptionParams,
|
||||
file.metadataDecryptionParams,
|
||||
);
|
||||
} catch (e) {
|
||||
file.localID = null; // File uploaded from a different device
|
||||
await _db.insert(file);
|
||||
|
|
|
@ -8,7 +8,10 @@ import 'package:flutter_sodium/flutter_sodium.dart';
|
|||
import 'package:logging/logging.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_file_attributes.dart';
|
||||
import 'package:photos/models/encryption_attribute.dart';
|
||||
import 'package:steel_crypt/steel_crypt.dart' as steel;
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
|
@ -19,7 +22,36 @@ class CryptoUtil {
|
|||
static int decryptionBlockSize =
|
||||
encryptionBlockSize + Sodium.cryptoSecretstreamXchacha20poly1305Abytes;
|
||||
|
||||
static Future<EncryptedFileAttributes> chachaEncrypt(
|
||||
static Future<EncryptedData> encrypt(Uint8List source,
|
||||
{Uint8List key}) async {
|
||||
if (key == null) {
|
||||
key = Sodium.cryptoSecretboxKeygen();
|
||||
}
|
||||
final nonce = Sodium.randombytesBuf(Sodium.cryptoSecretboxNoncebytes);
|
||||
final encryptedData = Sodium.cryptoSecretboxEasy(source, nonce, key);
|
||||
return EncryptedData(
|
||||
EncryptionAttribute(bytes: key),
|
||||
EncryptionAttribute(bytes: nonce),
|
||||
EncryptionAttribute(bytes: encryptedData));
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -62,13 +94,14 @@ class CryptoUtil {
|
|||
(DateTime.now().millisecondsSinceEpoch - encryptionStartTime)
|
||||
.toString());
|
||||
|
||||
return EncryptedFileAttributes(key, initPushResult.header);
|
||||
return ChaChaAttributes(EncryptionAttribute(bytes: key),
|
||||
EncryptionAttribute(bytes: initPushResult.header));
|
||||
}
|
||||
|
||||
static Future<void> chachaDecrypt(
|
||||
io.File sourceFile,
|
||||
io.File destinationFile,
|
||||
EncryptedFileAttributes attributes,
|
||||
ChaChaAttributes attributes,
|
||||
) async {
|
||||
var decryptionStartTime = DateTime.now().millisecondsSinceEpoch;
|
||||
|
||||
|
@ -79,7 +112,7 @@ class CryptoUtil {
|
|||
final outputFile =
|
||||
await (destinationFile.open(mode: io.FileMode.writeOnlyAppend));
|
||||
final pullState = Sodium.cryptoSecretstreamXchacha20poly1305InitPull(
|
||||
attributes.header, attributes.key);
|
||||
attributes.header.bytes, attributes.key.bytes);
|
||||
|
||||
var bytesRead = 0;
|
||||
var tag = Sodium.cryptoSecretstreamXchacha20poly1305TagMessage;
|
||||
|
|
|
@ -13,6 +13,8 @@ import 'package:photos/core/cache/video_cache_manager.dart';
|
|||
import 'package:photos/core/configuration.dart';
|
||||
import 'package:photos/core/constants.dart';
|
||||
import 'package:photos/db/files_db.dart';
|
||||
import 'package:photos/models/encrypted_file_attributes.dart';
|
||||
import 'package:photos/models/encryption_attribute.dart';
|
||||
import 'package:photos/models/file.dart';
|
||||
import 'package:photos/models/file_type.dart';
|
||||
|
||||
|
@ -139,23 +141,36 @@ Future<io.File> getThumbnailFromServer(File file) async {
|
|||
|
||||
Future<io.File> _downloadAndDecrypt(File file, BaseCacheManager cacheManager,
|
||||
{ProgressCallback progressCallback}) async {
|
||||
final temporaryPath = Configuration.instance.getTempDirectory() +
|
||||
final encryptedFilePath = Configuration.instance.getTempDirectory() +
|
||||
file.generatedID.toString() +
|
||||
".aes";
|
||||
".encrypted";
|
||||
final decryptedFilePath = Configuration.instance.getTempDirectory() +
|
||||
file.generatedID.toString() +
|
||||
".decrypted";
|
||||
final encryptedFile = io.File(encryptedFilePath);
|
||||
final decryptedFile = io.File(decryptedFilePath);
|
||||
return Dio()
|
||||
.download(
|
||||
file.getDownloadUrl(),
|
||||
temporaryPath,
|
||||
encryptedFilePath,
|
||||
onReceiveProgress: progressCallback,
|
||||
)
|
||||
.then((_) async {
|
||||
final data =
|
||||
await CryptoUtil.decryptFileToData(temporaryPath, file.getPassword());
|
||||
io.File(temporaryPath).deleteSync();
|
||||
var attributes = ChaChaAttributes(
|
||||
EncryptionAttribute(base64: file.fileDecryptionParams.header),
|
||||
EncryptionAttribute(
|
||||
bytes: await CryptoUtil.decrypt(
|
||||
file.fileDecryptionParams.encryptedKey,
|
||||
Configuration.instance.getBase64EncodedKey(),
|
||||
file.fileDecryptionParams.nonce,
|
||||
)));
|
||||
await CryptoUtil.chachaDecrypt(encryptedFile, decryptedFile, attributes);
|
||||
encryptedFile.deleteSync();
|
||||
decryptedFile.deleteSync();
|
||||
final fileExtension = extension(file.title).substring(1).toLowerCase();
|
||||
return cacheManager.putFile(
|
||||
file.getDownloadUrl(),
|
||||
data,
|
||||
decryptedFile.readAsBytesSync(),
|
||||
eTag: file.getDownloadUrl(),
|
||||
maxAge: Duration(days: 365),
|
||||
fileExtension: fileExtension,
|
||||
|
@ -166,11 +181,14 @@ Future<io.File> _downloadAndDecrypt(File file, BaseCacheManager cacheManager,
|
|||
Future<io.File> _downloadAndDecryptThumbnail(File file) async {
|
||||
final temporaryPath = Configuration.instance.getTempDirectory() +
|
||||
file.generatedID.toString() +
|
||||
"_thumbnail.aes";
|
||||
"_thumbnail.decrypted";
|
||||
return Dio().download(file.getThumbnailUrl(), temporaryPath).then((_) async {
|
||||
final data =
|
||||
await CryptoUtil.decryptFileToData(temporaryPath, file.getPassword());
|
||||
io.File(temporaryPath).deleteSync();
|
||||
final encryptedFile = io.File(temporaryPath);
|
||||
final data = await CryptoUtil.decryptWithDecryptionParams(
|
||||
encryptedFile.readAsBytesSync(),
|
||||
file.thumbnailDecryptionParams,
|
||||
Configuration.instance.getBase64EncodedKey());
|
||||
encryptedFile.deleteSync();
|
||||
return ThumbnailCacheManager().putFile(
|
||||
file.getThumbnailUrl(),
|
||||
data,
|
||||
|
|
Loading…
Add table
Reference in a new issue