1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-06-15 23:00:36 +02:00

All: Security: Added way to upgrade master key encryption and sync target encryption

This commit is contained in:
Laurent Cozic
2020-03-13 17:42:50 +00:00
parent 3917e3469d
commit f4958de885
17 changed files with 423 additions and 164 deletions

View File

@ -29,7 +29,7 @@ class EncryptionService {
this.loadedMasterKeys_ = {};
this.activeMasterKeyId_ = null;
this.defaultEncryptionMethod_ = EncryptionService.METHOD_SJCL_1A;
this.defaultMasterKeyEncryptionMethod_ = EncryptionService.METHOD_SJCL_2;
this.defaultMasterKeyEncryptionMethod_ = EncryptionService.METHOD_SJCL_4;
this.logger_ = new Logger();
this.headerTemplates_ = {
@ -107,13 +107,6 @@ class EncryptionService {
if (!password) continue;
try {
// if (mk.encryption_method != this.defaultMasterKeyEncryptionMethod_) {
// const newMkContent = await this.generateMasterKeyContent_(password);
// mk = Object.assign({}, mk, newMkContent);
// await MasterKey.save(mk);
// this.logger().info(`Master key ${mk.id} is using a deprectated encryption method. It has been upgraded to the new method.`);
// }
await this.loadMasterKey_(mk, password, activeMasterKeyId === mk.id);
} catch (error) {
this.logger().warn(`Cannot load master key ${mk.id}. Invalid password?`, error);
@ -229,6 +222,29 @@ class EncryptionService {
.join('');
}
masterKeysThatNeedUpgrading(masterKeys) {
return MasterKey.allWithoutEncryptionMethod(masterKeys, this.defaultMasterKeyEncryptionMethod_);
}
async upgradeMasterKey(model, decryptionPassword) {
const newEncryptionMethod = this.defaultMasterKeyEncryptionMethod_;
const plainText = await this.decryptMasterKey_(model, decryptionPassword);
const newContent = await this.encryptMasterKeyContent_(newEncryptionMethod, plainText, decryptionPassword);
return { ...model, ...newContent };
}
async encryptMasterKeyContent_(encryptionMethod, hexaBytes, password) {
// Checksum is not necessary since decryption will already fail if data is invalid
const checksum = encryptionMethod === EncryptionService.METHOD_SJCL_2 ? this.sha256(hexaBytes) : '';
const cipherText = await this.encrypt(encryptionMethod, password, hexaBytes);
return {
checksum: checksum,
encryption_method: encryptionMethod,
content: cipherText,
};
}
async generateMasterKeyContent_(password, options = null) {
options = Object.assign({}, {
encryptionMethod: this.defaultMasterKeyEncryptionMethod_,
@ -236,14 +252,8 @@ class EncryptionService {
const bytes = await shim.randomBytes(256);
const hexaBytes = bytes.map(a => hexPad(a.toString(16), 2)).join('');
const checksum = this.sha256(hexaBytes);
const cipherText = await this.encrypt(options.encryptionMethod, password, hexaBytes);
return {
checksum: checksum,
encryption_method: options.encryptionMethod,
content: cipherText,
};
return this.encryptMasterKeyContent_(options.encryptionMethod, hexaBytes, password);
}
async generateMasterKey(password, options = null) {
@ -259,8 +269,10 @@ class EncryptionService {
async decryptMasterKey_(model, password) {
const plainText = await this.decrypt(model.encryption_method, password, model.content);
const checksum = this.sha256(plainText);
if (checksum !== model.checksum) throw new Error('Could not decrypt master key (checksum failed)');
if (model.encryption_method === EncryptionService.METHOD_SJCL_2) {
const checksum = this.sha256(plainText);
if (checksum !== model.checksum) throw new Error('Could not decrypt master key (checksum failed)');
}
return plainText;
}