import 'dart:typed_data'; import 'package:sodium/sodium_sumo.dart'; import 'package:test/test.dart'; /// [hex] as bytes. Uint8List _bytes(String hex) => Uint8List.fromList([ for (var i = 0; i < hex.length; i += 2) int.parse(hex.substring(i, i + 2), radix: 16), ]); /// [bytes] in lower-case hex. String _hex(List bytes) => bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join(); Future main() async { final sodium = await SodiumSumoInit.init(); // libsodium's own known answers for crypto_pwhash with Argon2id // (libsodium 1.0.18, test/default/pwhash_argon2id.c's tv(), vectors 0 // and 6, and their lines 1 and 7 of pwhash_argon2id.exp): the password // and salt as the test cuts them (the password to its length, the salt // to 16 bytes), the output length, the passes and the memory. const vectors = < ({ String password, int length, String salt, int outLen, int opsLimit, int memLimit, String expected, }) >[ ( password: 'a347ae92bce9f80f6f595a4480fc9c2fe7e7d7148d371e9487d75f5c23008ffa' 'e065577a928febd9b1973a5a95073acdbeb6a030cfc0d79caa2dc5cd011cef02' 'c08da232d76d52dfbca38ca8dcbd665b17d1665f7cf5fe59772ec909733b24de' '97d6f58d220b20c60d7c07ec1fd93c52c31020300c6c1facd77937a597c7a6', length: 127, salt: '5541fbc995d5c197ba290346d2c559de', outLen: 155, opsLimit: 5, memLimit: 7256678, expected: '18acec5d6507739f203d1f5d9f1d862f7c2cdac4f19d2bdff64487e60d969e3c' 'ed615337b9eec6ac4461c6ca07f0939741e57c24d0005c7ea171a0ee1e734824' '9d135b38f222e4dad7b9a033ed83f5ca27277393e316582033c74affe2566a2b' 'ea47f91f0fd9fe49ece7e1f79f3ad6e9b23e0277c8ecc4b313225748dd2a80f5' '679534a0700e246a79a49b3f74eb89ec6205fe1eeb941c73b1fcf1', ), ( password: 'b540beb016a5366524d4605156493f9874514a5aa58818cd0c6dfffaa9e90205' 'f17b', length: 34, salt: '44071f6d181561670bda728d43fb79b4', outLen: 231, opsLimit: 1, memLimit: 1631659, expected: '7fb72409b0987f8190c3729710e98c3f80c5a8727d425fdcde7f3644d467fe97' '3f5b5fee683bd3fce812cb9ae5e9921a2d06c2f1905e4e839692f2b934b682f1' '1a2fe2b90482ea5dd234863516dba6f52dc0702d324ec77d860c2e181f84472b' 'd7104fedce071ffa93c5309494ad51623d214447a7b2b1462dc7d5d55a1f6fd5' 'b54ce024118d86f0c6489d16545aaa87b6689dad9f2fb47fda9894f8e12b87d9' '78b483ccd4cc5fd9595cdc7a818452f915ce2f7df95ec12b1c72e3788d473441' 'd884f9748eb14703c21b45d82fd667b85f5b2d98c13303b3fe76285531a826b6' 'fc0fe8e3dddecf', ), ]; for (final (index, vector) in vectors.indexed) { test("Argon2id gives libsodium's known answer $index", () { final key = sodium.crypto.pwhash.callRaw( outLen: vector.outLen, password: Int8List.fromList(_bytes(vector.password)), salt: _bytes(vector.salt), opsLimit: vector.opsLimit, memLimit: vector.memLimit, alg: CryptoPwhashAlgorithm.argon2id13, ); expect(_bytes(vector.password), hasLength(vector.length)); expect(_hex(key.extractBytes()), vector.expected); key.dispose(); }); } }