KeepassX format implementation in pure dart.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

123 lines
3.3 KiB

import 'dart:convert';
import 'dart:typed_data';
import 'package:kdbx/kdbx.dart';
import 'package:kdbx/src/internal/byte_utils.dart';
import 'package:kdbx/src/kdbx_var_dictionary.dart';
import 'package:logging/logging.dart';
final _logger = Logger('key_encrypter_kdf');
enum KdfType {
Argon2,
Aes,
}
class KdfField<T> {
KdfField(this.field, this.type);
final String field;
final ValueType<T> type;
static final uuid = KdfField('\$UUID', ValueType.typeBytes);
static final salt = KdfField('S', ValueType.typeBytes);
static final parallelism = KdfField('P', ValueType.typeUInt32);
static final memory = KdfField('M', ValueType.typeUInt64);
static final iterations = KdfField('I', ValueType.typeUInt64);
static final version = KdfField('V', ValueType.typeUInt32);
static final secretKey = KdfField('K', ValueType.typeBytes);
static final assocData = KdfField('A', ValueType.typeBytes);
static final rounds = KdfField('R', ValueType.typeInt64);
static final fields = [
salt,
parallelism,
memory,
iterations,
version,
secretKey,
assocData,
rounds
];
static void debugAll(VarDictionary dict) {
_logger
.fine('VarDictionary{\n${fields.map((f) => f.debug(dict)).join('\n')}');
}
T read(VarDictionary dict) => dict.get(type, field);
void write(VarDictionary dict, T value) => dict.set(type, field, value);
VarDictionaryItem<T> item(T value) =>
VarDictionaryItem<T>(field, type, value);
String debug(VarDictionary dict) {
final value = dict.get(type, field);
final strValue = type == ValueType.typeBytes
? ByteUtils.toHexList(value as Uint8List)
: value;
return '$field=$strValue';
}
}
class KeyEncrypterKdf {
KeyEncrypterKdf(this.argon2);
static const kdfUuids = <String, KdfType>{
'72Nt34wpREuR96mkA+MKDA==': KdfType.Argon2,
'ydnzmmKKRGC/dA0IwYpP6g==': KdfType.Aes,
};
static KdbxUuid kdfUuidForType(KdfType type) {
String uuid =
kdfUuids.entries.firstWhere((element) => element.value == type).key;
return KdbxUuid(uuid);
}
final Argon2 argon2;
Uint8List encrypt(Uint8List key, VarDictionary kdfParameters) {
final uuid = kdfParameters.get(ValueType.typeBytes, '\$UUID');
if (uuid == null) {
throw KdbxCorruptedFileException('No Kdf UUID');
}
final kdfUuid = base64.encode(uuid);
switch (kdfUuids[kdfUuid]) {
case KdfType.Argon2:
_logger.fine('Must be using argon2');
return encryptArgon2(key, kdfParameters);
break;
case KdfType.Aes:
_logger.fine('Must be using aes');
break;
}
throw UnsupportedError('unsupported encrypt stuff.');
}
Uint8List encryptArgon2(Uint8List key, VarDictionary kdfParameters) {
_logger.fine('argon2():');
_logger.fine('key: ${ByteUtils.toHexList(key)}');
KdfField.debugAll(kdfParameters);
return argon2.argon2(
key,
KdfField.salt.read(kdfParameters),
65536, //KdfField.memory.read(kdfParameters),
KdfField.iterations.read(kdfParameters),
32,
KdfField.parallelism.read(kdfParameters),
0,
KdfField.version.read(kdfParameters),
);
}
}
abstract class Argon2 {
Uint8List argon2(
Uint8List key,
Uint8List salt,
int memory,
int iterations,
int length,
int parallelism,
int type,
int version,
);
}