Browse Source

move credentials classes into their own file.

pull/5/head
Herbert Poul 3 years ago
parent
commit
e2fd1686c4
  1. 15
      lib/kdbx.dart
  2. 43
      lib/src/credentials/credentials.dart
  3. 77
      lib/src/credentials/keyfile.dart
  4. 1
      lib/src/kdbx_file.dart
  5. 104
      lib/src/kdbx_format.dart

15
lib/kdbx.dart

@ -1,6 +1,9 @@
/// dart library for reading keepass file format (kdbx). /// dart library for reading keepass file format (kdbx).
library kdbx; library kdbx;
export 'src/credentials/credentials.dart'
show Credentials, CredentialsPart, HashCredentials, PasswordCredentials;
export 'src/credentials/keyfile.dart' show KeyFileComposite, KeyFileCredentials;
export 'src/crypto/key_encrypter_kdf.dart' export 'src/crypto/key_encrypter_kdf.dart'
show KeyEncrypterKdf, KdfType, KdfField; show KeyEncrypterKdf, KdfType, KdfField;
export 'src/crypto/protected_value.dart' export 'src/crypto/protected_value.dart'
@ -12,17 +15,7 @@ export 'src/kdbx_dao.dart' show KdbxDao;
export 'src/kdbx_entry.dart' show KdbxEntry, KdbxKey, KdbxKeyCommon; export 'src/kdbx_entry.dart' show KdbxEntry, KdbxKey, KdbxKeyCommon;
export 'src/kdbx_exceptions.dart'; export 'src/kdbx_exceptions.dart';
export 'src/kdbx_file.dart'; export 'src/kdbx_file.dart';
export 'src/kdbx_format.dart' export 'src/kdbx_format.dart' show KdbxBody, MergeContext, KdbxFormat;
show
KdbxBody,
Credentials,
CredentialsPart,
HashCredentials,
MergeContext,
KdbxFormat,
KeyFileComposite,
KeyFileCredentials,
PasswordCredentials;
export 'src/kdbx_group.dart' show KdbxGroup; export 'src/kdbx_group.dart' show KdbxGroup;
export 'src/kdbx_header.dart' show KdbxVersion; export 'src/kdbx_header.dart' show KdbxVersion;
export 'src/kdbx_meta.dart'; export 'src/kdbx_meta.dart';

43
lib/src/credentials/credentials.dart

@ -0,0 +1,43 @@
import 'dart:typed_data';
import 'package:kdbx/src/credentials/keyfile.dart';
import 'package:kdbx/src/crypto/protected_value.dart';
import 'package:kdbx/src/internal/extension_utils.dart';
abstract class CredentialsPart {
Uint8List getBinary();
}
abstract class Credentials {
factory Credentials(ProtectedValue password) =>
Credentials.composite(password, null); //PasswordCredentials(password);
factory Credentials.composite(ProtectedValue? password, Uint8List? keyFile) =>
KeyFileComposite(
password: password?.let((that) => PasswordCredentials(that)),
keyFile: keyFile == null ? null : KeyFileCredentials(keyFile),
);
factory Credentials.fromHash(Uint8List hash) => HashCredentials(hash);
Uint8List getHash();
}
class PasswordCredentials implements CredentialsPart {
PasswordCredentials(this._password);
final ProtectedValue _password;
@override
Uint8List getBinary() {
return _password.hash;
}
}
class HashCredentials implements Credentials {
HashCredentials(this.hash);
final Uint8List hash;
@override
Uint8List getHash() => hash;
}

77
lib/src/credentials/keyfile.dart

@ -0,0 +1,77 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:collection/collection.dart' show IterableExtension;
import 'package:convert/convert.dart' as convert;
import 'package:kdbx/src/credentials/credentials.dart';
import 'package:kdbx/src/crypto/protected_value.dart';
import 'package:xml/xml.dart' as xml;
import 'package:crypto/crypto.dart' as crypto;
import 'package:logging/logging.dart';
final _logger = Logger('keyfile');
class KeyFileCredentials implements CredentialsPart {
factory KeyFileCredentials(Uint8List keyFileContents) {
try {
final keyFileAsString = utf8.decode(keyFileContents);
if (_hexValuePattern.hasMatch(keyFileAsString)) {
return KeyFileCredentials._(ProtectedValue.fromBinary(
convert.hex.decode(keyFileAsString) as Uint8List));
}
final xmlContent = xml.XmlDocument.parse(keyFileAsString);
final metaVersion =
xmlContent.findAllElements('Version').singleOrNull?.text;
final key = xmlContent.findAllElements('Key').single;
final dataString = key.findElements('Data').single;
final encoded = dataString.text.replaceAll(RegExp(r'\s'), '');
Uint8List dataBytes;
if (metaVersion != null && metaVersion.startsWith('2.')) {
dataBytes = convert.hex.decode(encoded) as Uint8List;
} else {
dataBytes = base64.decode(encoded);
}
_logger.finer('Decoded base64 of keyfile.');
return KeyFileCredentials._(ProtectedValue.fromBinary(dataBytes));
} catch (e, stackTrace) {
_logger.warning(
'Unable to parse key file as hex or XML, use as is.', e, stackTrace);
final bytes = crypto.sha256.convert(keyFileContents).bytes as Uint8List;
return KeyFileCredentials._(ProtectedValue.fromBinary(bytes));
}
}
KeyFileCredentials._(this._keyFileValue);
static final RegExp _hexValuePattern =
RegExp(r'^[a-f\d]{64}', caseSensitive: false);
final ProtectedValue _keyFileValue;
@override
Uint8List getBinary() {
return _keyFileValue.binaryValue;
// return crypto.sha256.convert(_keyFileValue.binaryValue).bytes as Uint8List;
}
}
class KeyFileComposite implements Credentials {
KeyFileComposite({required this.password, required this.keyFile});
PasswordCredentials? password;
KeyFileCredentials? keyFile;
@override
Uint8List getHash() {
final buffer = [...?password?.getBinary(), ...?keyFile?.getBinary()];
return crypto.sha256.convert(buffer).bytes as Uint8List;
// final output = convert.AccumulatorSink<crypto.Digest>();
// final input = crypto.sha256.startChunkedConversion(output);
//// input.add(password.getHash());
// input.add(buffer);
// input.close();
// return output.events.single.bytes as Uint8List;
}
}

1
lib/src/kdbx_file.dart

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:kdbx/src/credentials/credentials.dart';
import 'package:kdbx/src/crypto/protected_value.dart'; import 'package:kdbx/src/crypto/protected_value.dart';
import 'package:kdbx/src/kdbx_consts.dart'; import 'package:kdbx/src/kdbx_consts.dart';
import 'package:kdbx/src/kdbx_dao.dart'; import 'package:kdbx/src/kdbx_dao.dart';

104
lib/src/kdbx_format.dart

@ -6,9 +6,9 @@ import 'dart:typed_data';
import 'package:archive/archive.dart'; import 'package:archive/archive.dart';
import 'package:argon2_ffi_base/argon2_ffi_base.dart'; import 'package:argon2_ffi_base/argon2_ffi_base.dart';
import 'package:collection/collection.dart' show IterableExtension; import 'package:collection/collection.dart' show IterableExtension;
import 'package:convert/convert.dart' as convert;
import 'package:crypto/crypto.dart' as crypto; import 'package:crypto/crypto.dart' as crypto;
import 'package:kdbx/kdbx.dart'; import 'package:kdbx/kdbx.dart';
import 'package:kdbx/src/credentials/credentials.dart';
import 'package:kdbx/src/crypto/key_encrypter_kdf.dart'; import 'package:kdbx/src/crypto/key_encrypter_kdf.dart';
import 'package:kdbx/src/crypto/protected_salt_generator.dart'; import 'package:kdbx/src/crypto/protected_salt_generator.dart';
import 'package:kdbx/src/internal/consts.dart'; import 'package:kdbx/src/internal/consts.dart';
@ -31,40 +31,6 @@ import 'package:xml/xml.dart' as xml;
final _logger = Logger('kdbx.format'); final _logger = Logger('kdbx.format');
abstract class Credentials {
factory Credentials(ProtectedValue password) =>
Credentials.composite(password, null); //PasswordCredentials(password);
factory Credentials.composite(ProtectedValue? password, Uint8List? keyFile) =>
KeyFileComposite(
password: password?.let((that) => PasswordCredentials(that)),
keyFile: keyFile == null ? null : KeyFileCredentials(keyFile),
);
factory Credentials.fromHash(Uint8List hash) => HashCredentials(hash);
Uint8List getHash();
}
class KeyFileComposite implements Credentials {
KeyFileComposite({required this.password, required this.keyFile});
PasswordCredentials? password;
KeyFileCredentials? keyFile;
@override
Uint8List getHash() {
final buffer = [...?password?.getBinary(), ...?keyFile?.getBinary()];
return crypto.sha256.convert(buffer).bytes as Uint8List;
// final output = convert.AccumulatorSink<crypto.Digest>();
// final input = crypto.sha256.startChunkedConversion(output);
//// input.add(password.getHash());
// input.add(buffer);
// input.close();
// return output.events.single.bytes as Uint8List;
}
}
/// Context used during reading and writing. /// Context used during reading and writing.
class KdbxReadWriteContext { class KdbxReadWriteContext {
KdbxReadWriteContext({ KdbxReadWriteContext({
@ -147,74 +113,6 @@ class KdbxReadWriteContext {
} }
} }
abstract class CredentialsPart {
Uint8List getBinary();
}
class KeyFileCredentials implements CredentialsPart {
factory KeyFileCredentials(Uint8List keyFileContents) {
try {
final keyFileAsString = utf8.decode(keyFileContents);
if (_hexValuePattern.hasMatch(keyFileAsString)) {
return KeyFileCredentials._(ProtectedValue.fromBinary(
convert.hex.decode(keyFileAsString) as Uint8List));
}
final xmlContent = xml.XmlDocument.parse(keyFileAsString);
final metaVersion =
xmlContent.findAllElements('Version').singleOrNull?.text;
final key = xmlContent.findAllElements('Key').single;
final dataString = key.findElements('Data').single;
final encoded = dataString.text.replaceAll(RegExp(r'\s'), '');
Uint8List dataBytes;
if (metaVersion != null && metaVersion.startsWith('2.')) {
dataBytes = convert.hex.decode(encoded) as Uint8List;
} else {
dataBytes = base64.decode(encoded);
}
_logger.finer('Decoded base64 of keyfile.');
return KeyFileCredentials._(ProtectedValue.fromBinary(dataBytes));
} catch (e, stackTrace) {
_logger.warning(
'Unable to parse key file as hex or XML, use as is.', e, stackTrace);
final bytes = crypto.sha256.convert(keyFileContents).bytes as Uint8List;
return KeyFileCredentials._(ProtectedValue.fromBinary(bytes));
}
}
KeyFileCredentials._(this._keyFileValue);
static final RegExp _hexValuePattern =
RegExp(r'^[a-f\d]{64}', caseSensitive: false);
final ProtectedValue _keyFileValue;
@override
Uint8List getBinary() {
return _keyFileValue.binaryValue;
// return crypto.sha256.convert(_keyFileValue.binaryValue).bytes as Uint8List;
}
}
class PasswordCredentials implements CredentialsPart {
PasswordCredentials(this._password);
final ProtectedValue _password;
@override
Uint8List getBinary() {
return _password.hash;
}
}
class HashCredentials implements Credentials {
HashCredentials(this.hash);
final Uint8List hash;
@override
Uint8List getHash() => hash;
}
class KdbxBody extends KdbxNode { class KdbxBody extends KdbxNode {
KdbxBody.create(this.meta, this.rootGroup) : super.create('KeePassFile') { KdbxBody.create(this.meta, this.rootGroup) : super.create('KeePassFile') {
node.children.add(meta.node); node.children.add(meta.node);

Loading…
Cancel
Save