Default to sensitive limits for computation and memory for key derivation

This commit is contained in:
Vishnu Mohandas 2021-03-18 14:57:59 +05:30
parent 317bbf8f18
commit 8cb7f885b3
3 changed files with 59 additions and 57 deletions

View file

@ -114,7 +114,26 @@ class Configuration {
// Derive a key from the password that will be used to encrypt and
// decrypt the master key
final kekSalt = CryptoUtil.getSaltToDeriveKey();
final kek = CryptoUtil.deriveKey(utf8.encode(password), kekSalt);
int memLimit = Sodium.cryptoPwhashMemlimitSensitive;
final opsLimit = Sodium.cryptoPwhashOpslimitSensitive;
var kek;
try {
kek = await CryptoUtil.deriveKey(
utf8.encode(password),
kekSalt,
memLimit,
opsLimit,
);
} catch (e) {
_logger.info("Reducing memory utilization");
memLimit = Sodium.cryptoPwhashMemlimitModerate;
kek = await CryptoUtil.deriveKey(
utf8.encode(password),
kekSalt,
memLimit,
opsLimit,
);
}
// Encrypt the key with this derived key
final encryptedKeyData = CryptoUtil.encryptSync(key, kek);
@ -130,6 +149,8 @@ class Configuration {
Sodium.bin2base64(keyPair.pk),
Sodium.bin2base64(encryptedSecretKeyData.encryptedData),
Sodium.bin2base64(encryptedSecretKeyData.nonce),
memLimit,
opsLimit,
);
final privateAttributes = PrivateKeyAttributes(
Sodium.bin2base64(key), Sodium.bin2base64(keyPair.sk));
@ -138,8 +159,12 @@ class Configuration {
Future<void> decryptAndSaveKey(
String password, KeyAttributes attributes) async {
final kek = CryptoUtil.deriveKey(
utf8.encode(password), Sodium.base642bin(attributes.kekSalt));
final kek = await CryptoUtil.deriveKey(
utf8.encode(password),
Sodium.base642bin(attributes.kekSalt),
attributes.memLimit,
attributes.opsLimit,
);
var key;
try {
key = CryptoUtil.decryptSync(Sodium.base642bin(attributes.encryptedKey),

View file

@ -7,6 +7,8 @@ class KeyAttributes {
final String publicKey;
final String encryptedSecretKey;
final String secretKeyDecryptionNonce;
final int memLimit;
final int opsLimit;
KeyAttributes(
this.kekSalt,
@ -15,26 +17,10 @@ class KeyAttributes {
this.publicKey,
this.encryptedSecretKey,
this.secretKeyDecryptionNonce,
this.memLimit,
this.opsLimit,
);
KeyAttributes copyWith({
String kekSalt,
String encryptedKey,
String keyDecryptionNonce,
String publicKey,
String encryptedSecretKey,
String secretKeyDecryptionNonce,
}) {
return KeyAttributes(
kekSalt ?? this.kekSalt,
encryptedKey ?? this.encryptedKey,
keyDecryptionNonce ?? this.keyDecryptionNonce,
publicKey ?? this.publicKey,
encryptedSecretKey ?? this.encryptedSecretKey,
secretKeyDecryptionNonce ?? this.secretKeyDecryptionNonce,
);
}
Map<String, dynamic> toMap() {
return {
'kekSalt': kekSalt,
@ -43,6 +29,8 @@ class KeyAttributes {
'publicKey': publicKey,
'encryptedSecretKey': encryptedSecretKey,
'secretKeyDecryptionNonce': secretKeyDecryptionNonce,
'memLimit': memLimit,
'opsLimit': opsLimit,
};
}
@ -56,6 +44,8 @@ class KeyAttributes {
map['publicKey'],
map['encryptedSecretKey'],
map['secretKeyDecryptionNonce'],
map['memLimit'],
map['opsLimit'],
);
}
@ -63,32 +53,4 @@ class KeyAttributes {
factory KeyAttributes.fromJson(String source) =>
KeyAttributes.fromMap(json.decode(source));
@override
String toString() {
return 'KeyAttributes(kekSalt: $kekSalt, encryptedKey: $encryptedKey, keyDecryptionNonce: $keyDecryptionNonce, publicKey: $publicKey, encryptedSecretKey: $encryptedSecretKey, secretKeyDecryptionNonce: $secretKeyDecryptionNonce)';
}
@override
bool operator ==(Object o) {
if (identical(this, o)) return true;
return o is KeyAttributes &&
o.kekSalt == kekSalt &&
o.encryptedKey == encryptedKey &&
o.keyDecryptionNonce == keyDecryptionNonce &&
o.publicKey == publicKey &&
o.encryptedSecretKey == encryptedSecretKey &&
o.secretKeyDecryptionNonce == secretKeyDecryptionNonce;
}
@override
int get hashCode {
return kekSalt.hashCode ^
encryptedKey.hashCode ^
keyDecryptionNonce.hashCode ^
publicKey.hashCode ^
encryptedSecretKey.hashCode ^
secretKeyDecryptionNonce.hashCode;
}
}

View file

@ -19,6 +19,17 @@ Uint8List cryptoSecretboxOpenEasy(Map<String, dynamic> args) {
args["cipher"], args["nonce"], args["key"]);
}
Uint8List cryptoPwHash(Map<String, dynamic> args) {
return Sodium.cryptoPwhash(
Sodium.cryptoSecretboxKeybytes,
args["password"],
args["salt"],
args["opsLimit"],
args["memLimit"],
Sodium.cryptoPwhashAlgDefault,
);
}
EncryptionResult chachaEncryptFile(Map<String, dynamic> args) {
final encryptionStartTime = DateTime.now().millisecondsSinceEpoch;
final logger = Logger("ChaChaEncrypt");
@ -183,14 +194,18 @@ class CryptoUtil {
return Sodium.randombytesBuf(Sodium.cryptoPwhashSaltbytes);
}
static Uint8List deriveKey(Uint8List password, Uint8List salt) {
return Sodium.cryptoPwhash(
Sodium.cryptoSecretboxKeybytes,
password,
salt,
Sodium.cryptoPwhashOpslimitInteractive,
Sodium.cryptoPwhashMemlimitInteractive,
Sodium.cryptoPwhashAlgDefault);
static Future<Uint8List> deriveKey(
Uint8List password,
Uint8List salt,
int memLimit,
int opsLimit,
) {
return _computer.compute(cryptoPwHash, param: {
"password": password,
"salt": salt,
"memLimit": memLimit,
"opsLimit": opsLimit,
});
}
static Future<KeyPair> generateKeyPair() async {