Skip to content

Commit 1af6f44

Browse files
committed
Adds support for PBKDF2Security
1 parent b9dfe4f commit 1af6f44

23 files changed

+320
-218
lines changed

BENCHMARK.md

+8-7
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,14 @@ With 10B message (100000 iterations):
102102

103103
Key derivator algorithm benchmarks on different security parameters:
104104

105-
| Algorithms | test | little | moderate | good | strong |
106-
| ---------- | -------- | -------- | --------- | ---------- | ----------- |
107-
| scrypt | 0.056 ms | 1.495 ms | 27.024 ms | 88.235 ms | 2945.416 ms |
108-
| bcrypt | 0.226 ms | 2.124 ms | 17.19 ms | 270.562 ms | 2159.172 ms |
109-
| argon2i | 0.334 ms | 2.548 ms | 16.994 ms | 213.406 ms | 2556.027 ms |
110-
| argon2d | 0.265 ms | 2.475 ms | 17.222 ms | 211.376 ms | 2528.972 ms |
111-
| argon2id | 0.276 ms | 2.549 ms | 19.534 ms | 213.577 ms | 2547.892 ms |
105+
| Algorithms | little | moderate | good | strong |
106+
| ---------- | -------- | --------- | ---------- | ----------- |
107+
| scrypt | 1.589 ms | 16.688 ms | 91.663 ms | 2937.545 ms |
108+
| bcrypt | 2.24 ms | 17.077 ms | 273.729 ms | 2155.139 ms |
109+
| pbkdf2 | 0.849 ms | 17.091 ms | 283.537 ms | 3419.39 ms |
110+
| argon2i | 3.914 ms | 16.474 ms | 215.783 ms | 2598.387 ms |
111+
| argon2d | 2.981 ms | 16.98 ms | 207.425 ms | 2563.844 ms |
112+
| argon2id | 2.311 ms | 16.491 ms | 205.25 ms | 2576.335 ms |
112113

113114
> All benchmarks are done on _AMD Ryzen 7 5800X_ processor and _3200MHz_ RAM using compiled _exe_
114115
>

README.md

+13-12
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,8 @@ void main() {
150150
print('Keccak-512 => ${keccak512.string(text)}');
151151
print('SHAKE-128 => ${shake128.of(20).string(text)}');
152152
print('SHAKE-256 => ${shake256.of(20).string(text)}');
153-
print('BLAKE-2s/256 => ${blake2s256.string(text)}');
154-
print('BLAKE-2b/512 => ${blake2b512.string(text)}');
153+
print('BLAKE2s-256 => ${blake2s256.string(text)}');
154+
print('BLAKE2b-512 => ${blake2b512.string(text)}');
155155
print('SM3] => ${sm3.string(text)}');
156156
print('');
157157
@@ -160,16 +160,16 @@ void main() {
160160
print('HMAC/SHA1 => ${sha1.hmac.byString(text)}');
161161
print('HMAC/SHA256 => ${sha256.hmac.byString(key).string(text)}');
162162
print('HMAC/SHA3-256 => ${HMAC(sha3_256).by(pw).string(text)}');
163-
print("HMAC/BLAKE-2b/256 => ${blake2b512.hmac.by(pw).string(text)}");
163+
print("HMAC/BLAKE2b-256 => ${blake2b512.hmac.by(pw).string(text)}");
164164
print("BLAKE-2b-MAC/256 => ${blake2b256.mac.by(pw).string(text)}");
165165
print("BLAKE-2b-MAC/224 => ${Blake2b(28).mac.by(pw).string(text)}");
166166
print('');
167167
168168
// Examples of PBKDF2 key derivation
169169
print("SHA256/HMAC/PBKDF2 => ${pbkdf2(pw, iv, 100).hex()}");
170170
print("SHA1/HMAC/PBKDF2 => ${sha1.pbkdf2(iv, 100).hex(pw)}");
171-
print("BLAKE-2b/256/HMAC/PBKDF2 => ${blake2b256.pbkdf2(iv, 100).hex(pw)}");
172-
print("BLAKE-2b/256/MAC/PBKDF2 => ${blake2b256.mac.pbkdf2(iv, 100).hex(pw)}");
171+
print("BLAKE2b-256/HMAC/PBKDF2 => ${blake2b256.pbkdf2(iv, 100).hex(pw)}");
172+
print("BLAKE2b-256/MAC/PBKDF2 => ${blake2b256.mac.pbkdf2(iv, 100).hex(pw)}");
173173
print('');
174174
175175
// Examples of OTP generation
@@ -303,13 +303,14 @@ With 10B message (100000 iterations):
303303

304304
Key derivator algorithm benchmarks on different security parameters:
305305

306-
| Algorithms | test | little | moderate | good | strong |
307-
| ---------- | -------- | -------- | --------- | ---------- | ----------- |
308-
| scrypt | 0.056 ms | 1.495 ms | 27.024 ms | 88.235 ms | 2945.416 ms |
309-
| bcrypt | 0.226 ms | 2.124 ms | 17.19 ms | 270.562 ms | 2159.172 ms |
310-
| argon2i | 0.334 ms | 2.548 ms | 16.994 ms | 213.406 ms | 2556.027 ms |
311-
| argon2d | 0.265 ms | 2.475 ms | 17.222 ms | 211.376 ms | 2528.972 ms |
312-
| argon2id | 0.276 ms | 2.549 ms | 19.534 ms | 213.577 ms | 2547.892 ms |
306+
| Algorithms | little | moderate | good | strong |
307+
| ---------- | -------- | --------- | ---------- | ----------- |
308+
| scrypt | 1.589 ms | 16.688 ms | 91.663 ms | 2937.545 ms |
309+
| bcrypt | 2.24 ms | 17.077 ms | 273.729 ms | 2155.139 ms |
310+
| pbkdf2 | 0.849 ms | 17.091 ms | 283.537 ms | 3419.39 ms |
311+
| argon2i | 3.914 ms | 16.474 ms | 215.783 ms | 2598.387 ms |
312+
| argon2d | 2.981 ms | 16.98 ms | 207.425 ms | 2563.844 ms |
313+
| argon2id | 2.311 ms | 16.491 ms | 205.25 ms | 2576.335 ms |
313314

314315
> All benchmarks are done on _AMD Ryzen 7 5800X_ processor and _3200MHz_ RAM using compiled _exe_
315316
>

benchmark/benchmark.dart

+52-35
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import 'hmac_md5.dart' as md5_hmac;
1515
import 'hmac_sha1.dart' as sha1_hmac;
1616
import 'hmac_sha256.dart' as sha256_hmac;
1717
import 'md4.dart' as md4;
18+
import 'pbkdf2.dart' as pbkdf2;
1819
import 'md5.dart' as md5;
1920
import 'poly1305.dart' as poly1305;
2021
import 'ripemd128.dart' as ripemd128;
@@ -234,51 +235,67 @@ void measureHashFunctions() {
234235
void measureKeyDerivation() {
235236
dump('Key derivator algorithm benchmarks on different security parameters:');
236237
dump('');
237-
var argon2Levels = [
238-
Argon2Security.test,
239-
Argon2Security.little,
240-
Argon2Security.moderate,
241-
Argon2Security.good,
242-
Argon2Security.strong,
243-
];
244-
var scryptLevels = [
245-
ScryptSecurity.test,
246-
ScryptSecurity.little,
247-
ScryptSecurity.moderate,
248-
ScryptSecurity.good,
249-
ScryptSecurity.strong,
250-
];
251-
var bcryptLevels = [
252-
BcryptSecurity.test,
253-
BcryptSecurity.little,
254-
BcryptSecurity.moderate,
255-
BcryptSecurity.good,
256-
BcryptSecurity.strong,
257-
];
238+
var argon2Levels = {
239+
'little': Argon2Security.little,
240+
'moderate': Argon2Security.moderate,
241+
'good': Argon2Security.good,
242+
'strong': Argon2Security.strong,
243+
};
244+
var scryptLevels = {
245+
'little': ScryptSecurity.little,
246+
'moderate': ScryptSecurity.moderate,
247+
'good': ScryptSecurity.good,
248+
'strong': ScryptSecurity.strong,
249+
};
250+
var bcryptLevels = {
251+
'little': BcryptSecurity.little,
252+
'moderate': BcryptSecurity.moderate,
253+
'good': BcryptSecurity.good,
254+
'strong': BcryptSecurity.strong,
255+
};
256+
var pbkdf2Levels = {
257+
'little': PBKDF2Security.little,
258+
'moderate': PBKDF2Security.moderate,
259+
'good': PBKDF2Security.good,
260+
'strong': PBKDF2Security.strong,
261+
};
258262
var algorithms = {
259-
'scrypt': scryptLevels.map((e) => scrypt.HashlibBenchmark(e)),
260-
'bcrypt': bcryptLevels.map((e) => bcrypt.HashlibBenchmark(e)),
261-
'argon2i': argon2Levels.map((e) => argon2.HashlibArgon2iBenchmark(e)),
262-
'argon2d': argon2Levels.map((e) => argon2.HashlibArgon2dBenchmark(e)),
263-
'argon2id': argon2Levels.map((e) => argon2.HashlibArgon2idBenchmark(e)),
263+
'scrypt':
264+
scryptLevels.map((k, s) => MapEntry(k, scrypt.HashlibBenchmark(s))),
265+
'bcrypt':
266+
bcryptLevels.map((k, s) => MapEntry(k, bcrypt.HashlibBenchmark(s))),
267+
'pbkdf2':
268+
pbkdf2Levels.map((k, s) => MapEntry(k, pbkdf2.HashlibBenchmark(s))),
269+
'argon2i': argon2Levels
270+
.map((k, s) => MapEntry(k, argon2.HashlibArgon2iBenchmark(s))),
271+
'argon2d': argon2Levels
272+
.map((k, s) => MapEntry(k, argon2.HashlibArgon2dBenchmark(s))),
273+
'argon2id': argon2Levels
274+
.map((k, s) => MapEntry(k, argon2.HashlibArgon2idBenchmark(s))),
264275
};
265276

266277
var names = {
267-
...argon2Levels.map((e) => e.name),
268-
...scryptLevels.map((e) => e.name),
269-
...bcryptLevels.map((e) => e.name),
278+
...argon2Levels.keys,
279+
...scryptLevels.keys,
280+
...bcryptLevels.keys,
270281
}.toList();
271282
var separator = names.map((e) => ('-' * (e.length + 2)));
272-
dump('| Algorithms | ${argon2Levels.map((e) => e.name).join(' | ')} |');
283+
284+
dump('| Algorithms | ${names.join(' | ')} |');
273285
dump('|------------|${separator.join('|')}|');
274286
for (var entry in algorithms.entries) {
275287
var algorithm = entry.key;
276-
var items = entry.value;
277-
var message = '| $algorithm |';
278-
for (var item in items) {
279-
var runtime = item.measure();
280-
message += ' ${runtime / 1000} ms |';
288+
var instances = entry.value;
289+
var message = '| $algorithm ';
290+
for (var name in names) {
291+
message += ' | ';
292+
var item = instances[name];
293+
if (item != null) {
294+
var runtime = item.measure();
295+
message += '${runtime / 1000} ms';
296+
}
281297
}
298+
message += '|';
282299
dump(message);
283300
}
284301
dump('');

benchmark/pbkdf2.dart

+47-40
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import 'dart:math';
55
import 'dart:typed_data';
66

7-
import 'package:hashlib/hashlib.dart' as hashlib;
7+
import 'package:hashlib/hashlib.dart';
88
import 'package:pointycastle/export.dart' show Pbkdf2Parameters;
99
import 'package:pointycastle/pointycastle.dart' as pc;
1010

@@ -14,58 +14,65 @@ Random random = Random();
1414

1515
final salt = Uint8List.fromList(List.generate(16, (i) => random.nextInt(256)));
1616

17-
class HashlibBenchmark extends Benchmark {
18-
HashlibBenchmark(int size, int iter) : super('hashlib', size, iter);
17+
class HashlibBenchmark extends KDFBenchmarkBase {
18+
final PBKDF2Security security;
1919

20-
@override
21-
void run() {
22-
hashlib.sha256.hmac.pbkdf2(salt, iter, 64).convert(input);
23-
}
20+
HashlibBenchmark(this.security) : super('hashlib');
2421

2522
@override
26-
void exercise() {
27-
run();
23+
void run() {
24+
final salt = Uint8List.fromList("some salt".codeUnits);
25+
final pass = Uint8List.fromList("some password".codeUnits);
26+
PBKDF2.fromSecurity(security, salt: salt, keyLength: 64).convert(pass);
2827
}
2928
}
3029

31-
class PointyCastleBenchmark extends Benchmark {
32-
Uint8List _input = Uint8List(0);
33-
PointyCastleBenchmark(int size, int iter) : super('PointyCastle', size, iter);
30+
class PointyCastleBenchmark extends KDFBenchmarkBase {
31+
final PBKDF2Security security;
3432

35-
@override
36-
void setup() {
37-
super.setup();
38-
_input = Uint8List.fromList(input);
39-
}
33+
PointyCastleBenchmark(this.security) : super('hashlib');
4034

4135
@override
4236
void run() {
37+
final salt = Uint8List.fromList("some salt".codeUnits);
38+
final pass = Uint8List.fromList("some password".codeUnits);
39+
var pbkdf2 = pc.KeyDerivator('SHA-256/HMAC/PBKDF2');
40+
pbkdf2.init(Pbkdf2Parameters(salt, security.c, 64));
4341
var out = Uint8List(64);
44-
var d = pc.KeyDerivator('SHA-256/HMAC/PBKDF2');
45-
d.init(Pbkdf2Parameters(salt, iter, 64));
46-
d.deriveKey(_input, 0, out, 0);
47-
}
48-
49-
@override
50-
void exercise() {
51-
run();
42+
pbkdf2.deriveKey(pass, 0, out, 0);
5243
}
5344
}
5445

5546
void main() {
56-
print('----- PBKDF2-HMAC(SHA256) -----');
57-
final conditions = [
58-
[32, 100000],
59-
[32, 1000],
60-
[32, 10],
61-
];
62-
for (var condition in conditions) {
63-
int size = condition[0];
64-
int iter = condition[1];
65-
print('---- size: ${formatSize(size)} | iterations: $iter ----');
66-
HashlibBenchmark(size, iter).measureDiff([
67-
PointyCastleBenchmark(size, iter),
68-
]);
69-
print('');
70-
}
47+
double runtime;
48+
print('--------- Hashlib/PBKDF2 ----------');
49+
runtime = HashlibBenchmark(PBKDF2Security.test).measure();
50+
print('hashlib/pbkdf2[test]: ${runtime / 1000} ms');
51+
runtime = HashlibBenchmark(PBKDF2Security.little).measure();
52+
print('hashlib/pbkdf2[little]: ${runtime / 1000} ms');
53+
runtime = HashlibBenchmark(PBKDF2Security.moderate).measure();
54+
print('hashlib/pbkdf2[moderate]: ${runtime / 1000} ms');
55+
runtime = HashlibBenchmark(PBKDF2Security.good).measure();
56+
print('hashlib/pbkdf2[good]: ${runtime / 1000} ms');
57+
runtime = HashlibBenchmark(PBKDF2Security.strong).measure();
58+
print('hashlib/pbkdf2[strong]: ${runtime / 1000} ms');
59+
runtime = HashlibBenchmark(PBKDF2Security.owasp).measure();
60+
print('hashlib/pbkdf2[owasp1]: ${runtime / 1000} ms');
61+
runtime = HashlibBenchmark(PBKDF2Security.owasp2).measure();
62+
print('hashlib/pbkdf2[owasp2]: ${runtime / 1000} ms');
63+
runtime = HashlibBenchmark(PBKDF2Security.owasp3).measure();
64+
print('hashlib/pbkdf2[owasp3]: ${runtime / 1000} ms');
65+
print('');
66+
print('--------- PointyCastle/PBKDF2 ----------');
67+
runtime = PointyCastleBenchmark(PBKDF2Security.test).measure();
68+
print('pc/pbkdf2[test]: ${runtime / 1000} ms');
69+
runtime = PointyCastleBenchmark(PBKDF2Security.little).measure();
70+
print('pc/pbkdf2[little]: ${runtime / 1000} ms');
71+
runtime = PointyCastleBenchmark(PBKDF2Security.moderate).measure();
72+
print('pc/pbkdf2[moderate]: ${runtime / 1000} ms');
73+
runtime = PointyCastleBenchmark(PBKDF2Security.good).measure();
74+
print('pc/pbkdf2[good]: ${runtime / 1000} ms');
75+
runtime = PointyCastleBenchmark(PBKDF2Security.strong).measure();
76+
print('pc/pbkdf2[strong]: ${runtime / 1000} ms');
77+
print('');
7178
}

benchmark/scrypt.dart

+14-22
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import 'dart:math';
55
import 'dart:typed_data';
66

77
import 'package:hashlib/hashlib.dart';
8-
import 'package:pointycastle/export.dart';
98
import 'package:pointycastle/key_derivators/scrypt.dart' as pc;
9+
import 'package:pointycastle/export.dart' show ScryptParameters;
1010

1111
import '_base.dart';
1212

@@ -19,12 +19,13 @@ class HashlibBenchmark extends KDFBenchmarkBase {
1919

2020
@override
2121
void run() {
22-
scrypt(
23-
'long password'.codeUnits,
24-
'secret salt'.codeUnits,
25-
security: security,
26-
dklen: 64,
27-
);
22+
final salt = Uint8List.fromList('secret salt'.codeUnits);
23+
final pass = Uint8List.fromList('long password'.codeUnits);
24+
Scrypt.fromSecurity(
25+
security,
26+
salt: salt,
27+
derivedKeyLength: 64,
28+
).convert(pass);
2829
}
2930
}
3031

@@ -35,21 +36,12 @@ class PointyCastleBenchmark extends KDFBenchmarkBase {
3536

3637
@override
3738
void run() {
38-
var scrypt = pc.Scrypt();
39-
scrypt.init(ScryptParameters(
40-
security.N,
41-
security.r,
42-
security.p,
43-
64,
44-
Uint8List.fromList('secret salt'.codeUnits),
45-
));
46-
var out = Uint8List(64);
47-
scrypt.deriveKey(
48-
Uint8List.fromList('long password'.codeUnits),
49-
0,
50-
out,
51-
0,
52-
);
39+
final salt = Uint8List.fromList('secret salt'.codeUnits);
40+
final pass = Uint8List.fromList('long password'.codeUnits);
41+
final scrypt = pc.Scrypt();
42+
scrypt.init(ScryptParameters(security.N, security.r, security.p, 64, salt));
43+
final out = Uint8List(64);
44+
scrypt.deriveKey(pass, 0, out, 0);
5345
}
5446
}
5547

example/hashlib_example.dart

+7-7
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ void main() {
4242
print('Keccak-512 => ${keccak512.string(text)}');
4343
print('SHAKE-128 => ${shake128.of(20).string(text)}');
4444
print('SHAKE-256 => ${shake256.of(20).string(text)}');
45-
print('BLAKE-2s/256 => ${blake2s256.string(text)}');
46-
print('BLAKE-2b/512 => ${blake2b512.string(text)}');
45+
print('BLAKE2s-256 => ${blake2s256.string(text)}');
46+
print('BLAKE2b-512 => ${blake2b512.string(text)}');
4747
print('SM3] => ${sm3.string(text)}');
4848
print('');
4949

@@ -52,16 +52,16 @@ void main() {
5252
print('HMAC/SHA1 => ${sha1.hmac.byString(text)}');
5353
print('HMAC/SHA256 => ${sha256.hmac.byString(key).string(text)}');
5454
print('HMAC/SHA3-256 => ${HMAC(sha3_256).by(pw).string(text)}');
55-
print("HMAC/BLAKE-2b/256 => ${blake2b512.hmac.by(pw).string(text)}");
55+
print("HMAC/BLAKE2b-256 => ${blake2b512.hmac.by(pw).string(text)}");
5656
print("BLAKE-2b-MAC/256 => ${blake2b256.mac.by(pw).string(text)}");
5757
print("BLAKE-2b-MAC/224 => ${Blake2b(28).mac.by(pw).string(text)}");
5858
print('');
5959

6060
// Examples of PBKDF2 key derivation
61-
print("SHA256/HMAC/PBKDF2 => ${pbkdf2(pw, iv, 100).hex()}");
62-
print("SHA1/HMAC/PBKDF2 => ${sha1.pbkdf2(iv, 100).hex(pw)}");
63-
print("BLAKE-2b/256/HMAC/PBKDF2 => ${blake2b256.pbkdf2(iv, 100).hex(pw)}");
64-
print("BLAKE-2b/256/MAC/PBKDF2 => ${blake2b256.mac.pbkdf2(iv, 100).hex(pw)}");
61+
print("SHA256/HMAC/PBKDF2 => ${pbkdf2(pw, iv).hex()}");
62+
print("BLAKE2b-256/HMAC/PBKDF2 => ${blake2b256.pbkdf2(iv).hex(pw)}");
63+
print("BLAKE2b-256/MAC/PBKDF2 => ${blake2b256.mac.pbkdf2(iv).hex(pw)}");
64+
print("SHA1/HMAC/PBKDF2 => ${sha1.pbkdf2(iv, iterations: 100).hex(pw)}");
6565
print('');
6666

6767
// Examples of OTP generation

0 commit comments

Comments
 (0)