6 changed files with 116 additions and 6 deletions
			
			
		@ -0,0 +1,38 @@
					 | 
				
			||||
import 'dart:typed_data'; | 
				
			||||
 | 
				
			||||
import 'package:argon2_ffi_base/argon2_ffi_base.dart'; | 
				
			||||
import 'package:pointycastle/export.dart' as pc; | 
				
			||||
import 'package:pointycastle/pointycastle.dart' as pc; | 
				
			||||
 | 
				
			||||
/// Dart-only implementation using pointycastle's Argon KDF. | 
				
			||||
class PointyCastleArgon2 extends Argon2 { | 
				
			||||
  const PointyCastleArgon2(); | 
				
			||||
 | 
				
			||||
  @override | 
				
			||||
  bool get isFfi => false; | 
				
			||||
 | 
				
			||||
  @override | 
				
			||||
  bool get isImplemented => true; | 
				
			||||
 | 
				
			||||
  pc.KeyDerivator argon2Kdf() => pc.Argon2BytesGenerator(); | 
				
			||||
 | 
				
			||||
  @override | 
				
			||||
  Uint8List argon2(Argon2Arguments args) { | 
				
			||||
    final kdf = argon2Kdf(); | 
				
			||||
    kdf.init(pc.Argon2Parameters( | 
				
			||||
      args.type, | 
				
			||||
      args.salt, | 
				
			||||
      desiredKeyLength: args.length, | 
				
			||||
      iterations: args.iterations, | 
				
			||||
      memory: args.memory, | 
				
			||||
      lanes: args.parallelism, | 
				
			||||
      version: args.version, | 
				
			||||
    )); | 
				
			||||
    return kdf.process(args.key); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @override | 
				
			||||
  Future<Uint8List> argon2Async(Argon2Arguments args) { | 
				
			||||
    return Future.value(argon2(args)); | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,59 @@
					 | 
				
			||||
import 'dart:io'; | 
				
			||||
 | 
				
			||||
import 'package:kdbx/kdbx.dart'; | 
				
			||||
import 'package:kdbx/src/kdbx_header.dart'; | 
				
			||||
 | 
				
			||||
import 'package:logging/logging.dart'; | 
				
			||||
import 'package:test/test.dart'; | 
				
			||||
 | 
				
			||||
import 'internal/test_utils.dart'; | 
				
			||||
 | 
				
			||||
final _logger = Logger('kdbx4_test_pointycastle'); | 
				
			||||
 | 
				
			||||
void main() { | 
				
			||||
  // ignore: unused_local_variable | 
				
			||||
  final testUtil = TestUtil(); | 
				
			||||
  final kdbxFormat = KdbxFormat(); | 
				
			||||
  if (kdbxFormat.argon2.isFfi) { | 
				
			||||
    throw StateError('Expected non-ffi implementation.'); | 
				
			||||
  } | 
				
			||||
  _logger.fine('argon2 implementation: ${kdbxFormat.argon2}'); | 
				
			||||
  group('Reading pointycastle argon2', () { | 
				
			||||
    test('pc: Reading kdbx4_keeweb', () async { | 
				
			||||
      final data = await File('test/kdbx4_keeweb.kdbx').readAsBytes(); | 
				
			||||
      final file = await kdbxFormat.read( | 
				
			||||
          data, Credentials(ProtectedValue.fromString('asdf'))); | 
				
			||||
      final firstEntry = file.body.rootGroup.entries.first; | 
				
			||||
      final pwd = firstEntry.getString(KdbxKeyCommon.PASSWORD)!.getText(); | 
				
			||||
      expect(pwd, 'def'); | 
				
			||||
    }); | 
				
			||||
  }); | 
				
			||||
  group('Writing pointycastle argon2', () { | 
				
			||||
    test('Create and save', () async { | 
				
			||||
      final credentials = Credentials(ProtectedValue.fromString('asdf')); | 
				
			||||
      final kdbx = kdbxFormat.create( | 
				
			||||
        credentials, | 
				
			||||
        'Test Keystore', | 
				
			||||
        header: KdbxHeader.createV4(), | 
				
			||||
      ); | 
				
			||||
      final rootGroup = kdbx.body.rootGroup; | 
				
			||||
      _createEntry(kdbx, rootGroup, 'user1', 'LoremIpsum'); | 
				
			||||
      _createEntry(kdbx, rootGroup, 'user2', 'Second Password'); | 
				
			||||
      final saved = await kdbx.save(); | 
				
			||||
 | 
				
			||||
      final loadedKdbx = await kdbxFormat.read( | 
				
			||||
          saved, Credentials(ProtectedValue.fromString('asdf'))); | 
				
			||||
      _logger.fine('Successfully loaded kdbx $loadedKdbx'); | 
				
			||||
      File('test_v4x.kdbx').writeAsBytesSync(saved); | 
				
			||||
    }); | 
				
			||||
  }); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
KdbxEntry _createEntry( | 
				
			||||
    KdbxFile file, KdbxGroup group, String username, String password) { | 
				
			||||
  final entry = KdbxEntry.create(file, group); | 
				
			||||
  group.addEntry(entry); | 
				
			||||
  entry.setString(KdbxKeyCommon.USER_NAME, PlainValue(username)); | 
				
			||||
  entry.setString(KdbxKeyCommon.PASSWORD, ProtectedValue.fromString(password)); | 
				
			||||
  return entry; | 
				
			||||
} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue