Skip to content

Commit 6ada120

Browse files
authored
Merge pull request #11 from AaronFeickert/update-pbkdf2
Bump backup version for updated OWASP recommendation
2 parents 011dc9c + 71fe823 commit 6ada120

3 files changed

Lines changed: 36 additions & 26 deletions

File tree

example/pubspec.lock

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ packages:
77
name: async
88
url: "https://pub.dartlang.org"
99
source: hosted
10-
version: "2.8.2"
10+
version: "2.9.0"
1111
boolean_selector:
1212
dependency: transitive
1313
description:
@@ -21,21 +21,14 @@ packages:
2121
name: characters
2222
url: "https://pub.dartlang.org"
2323
source: hosted
24-
version: "1.2.0"
25-
charcode:
26-
dependency: transitive
27-
description:
28-
name: charcode
29-
url: "https://pub.dartlang.org"
30-
source: hosted
31-
version: "1.3.1"
24+
version: "1.2.1"
3225
clock:
3326
dependency: transitive
3427
description:
3528
name: clock
3629
url: "https://pub.dartlang.org"
3730
source: hosted
38-
version: "1.1.0"
31+
version: "1.1.1"
3932
collection:
4033
dependency: transitive
4134
description:
@@ -70,7 +63,7 @@ packages:
7063
name: fake_async
7164
url: "https://pub.dartlang.org"
7265
source: hosted
73-
version: "1.3.0"
66+
version: "1.3.1"
7467
fixnum:
7568
dependency: transitive
7669
description:
@@ -115,28 +108,28 @@ packages:
115108
name: matcher
116109
url: "https://pub.dartlang.org"
117110
source: hosted
118-
version: "0.12.11"
111+
version: "0.12.12"
119112
material_color_utilities:
120113
dependency: transitive
121114
description:
122115
name: material_color_utilities
123116
url: "https://pub.dartlang.org"
124117
source: hosted
125-
version: "0.1.4"
118+
version: "0.1.5"
126119
meta:
127120
dependency: transitive
128121
description:
129122
name: meta
130123
url: "https://pub.dartlang.org"
131124
source: hosted
132-
version: "1.7.0"
125+
version: "1.8.0"
133126
path:
134127
dependency: transitive
135128
description:
136129
name: path
137130
url: "https://pub.dartlang.org"
138131
source: hosted
139-
version: "1.8.1"
132+
version: "1.8.2"
140133
plugin_platform_interface:
141134
dependency: transitive
142135
description:
@@ -162,7 +155,7 @@ packages:
162155
name: source_span
163156
url: "https://pub.dartlang.org"
164157
source: hosted
165-
version: "1.8.2"
158+
version: "1.9.0"
166159
stack_trace:
167160
dependency: transitive
168161
description:
@@ -190,21 +183,21 @@ packages:
190183
name: string_scanner
191184
url: "https://pub.dartlang.org"
192185
source: hosted
193-
version: "1.1.0"
186+
version: "1.1.1"
194187
term_glyph:
195188
dependency: transitive
196189
description:
197190
name: term_glyph
198191
url: "https://pub.dartlang.org"
199192
source: hosted
200-
version: "1.2.0"
193+
version: "1.2.1"
201194
test_api:
202195
dependency: transitive
203196
description:
204197
name: test_api
205198
url: "https://pub.dartlang.org"
206199
source: hosted
207-
version: "0.4.9"
200+
version: "0.4.12"
208201
tuple:
209202
dependency: transitive
210203
description:

lib/stack_wallet_backup.dart

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,29 @@ List<VersionParameters> getAllVersions() {
5252
// Version 1 uses PBKDF2, XChaCha20-Poly1305, and Blake2b
5353
version = 1;
5454
aad = protocol + version.toString();
55-
const int owaspRecommendedPbkdf2Sha512Iterations = 120000; // OWASP recommendation: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2
55+
const int owaspRecommendedPbkdf2Sha512IterationsVersion1 = 120000; // OWASP recommendation: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2
5656
const int pbkdf2SaltLength = 16; // Take that, rainbow tables!
5757
versions.add(VersionParameters(
5858
version,
59-
(passphrase) => _pbkdf2(passphrase, Uint8List.fromList(utf8.encode(aad)), Hmac.sha512(), owaspRecommendedPbkdf2Sha512Iterations, Xchacha20.poly1305Aead().secretKeyLength),
60-
(adk, salt) => _pbkdf2(adk, salt, Hmac.sha512(), owaspRecommendedPbkdf2Sha512Iterations, Xchacha20.poly1305Aead().secretKeyLength),
59+
(passphrase) => _pbkdf2(passphrase, Uint8List.fromList(utf8.encode(aad)), Hmac.sha512(), owaspRecommendedPbkdf2Sha512IterationsVersion1, Xchacha20.poly1305Aead().secretKeyLength),
60+
(adk, salt) => _pbkdf2(adk, salt, Hmac.sha512(), owaspRecommendedPbkdf2Sha512IterationsVersion1, Xchacha20.poly1305Aead().secretKeyLength),
61+
(key, nonce, plaintext) => _xChaCha20Poly1305Encrypt(key, nonce, plaintext, aad),
62+
(key, blob) => _xChaCha20Poly1305Decrypt(key, blob, aad),
63+
(data) => _blake2b(data, aad),
64+
pbkdf2SaltLength,
65+
Xchacha20.poly1305Aead().nonceLength,
66+
Poly1305().macLength,
67+
Blake2b().hashLengthInBytes
68+
));
69+
70+
// Version 2 uses PBKDF2, XChaCha20-Poly1305, and Blake2b
71+
version = 2;
72+
aad = protocol + version.toString();
73+
const int owaspRecommendedPbkdf2Sha512IterationsVersion2 = 210000; // OWASP recommendation: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2
74+
versions.add(VersionParameters(
75+
version,
76+
(passphrase) => _pbkdf2(passphrase, Uint8List.fromList(utf8.encode(aad)), Hmac.sha512(), owaspRecommendedPbkdf2Sha512IterationsVersion2, Xchacha20.poly1305Aead().secretKeyLength),
77+
(adk, salt) => _pbkdf2(adk, salt, Hmac.sha512(), owaspRecommendedPbkdf2Sha512IterationsVersion2, Xchacha20.poly1305Aead().secretKeyLength),
6178
(key, nonce, plaintext) => _xChaCha20Poly1305Encrypt(key, nonce, plaintext, aad),
6279
(key, blob) => _xChaCha20Poly1305Decrypt(key, blob, aad),
6380
(data) => _blake2b(data, aad),

test/stack_wallet_backup_test.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ void main() {
9999

100100
// Compute ADK (this would be stored in the device enclave and, if needed, later retrived for decryption)
101101
// NOTE: The ADK will differ between protocol versions, so the version should be stored with it
102-
final Tuple2<int, Uint8List> adkData = await generateAdk(passphrase);
102+
final Tuple2<int, Uint8List> adkData = await generateAdk(passphrase, version: version);
103103
Uint8List adk = adkData.item2;
104104

105105
// Encrypt
@@ -144,14 +144,14 @@ void main() {
144144
final Uint8List plaintextBytes = Uint8List.fromList(utf8.encode(plaintext));
145145

146146
// Compute ADK
147-
final Tuple2<int, Uint8List> adkData = await generateAdk(passphrase);
147+
final Tuple2<int, Uint8List> adkData = await generateAdk(passphrase, version: version);
148148
Uint8List adk = adkData.item2;
149149

150150
// Encrypt
151151
final Uint8List blob = await encryptWithAdk(adk, plaintextBytes, version: version);
152152

153153
// Compute evil ADK
154-
final Tuple2<int, Uint8List> evilAdkData = await generateAdk(evilPassphrase);
154+
final Tuple2<int, Uint8List> evilAdkData = await generateAdk(evilPassphrase, version: version);
155155
Uint8List evilAdk = evilAdkData.item2;
156156

157157
// Decrypt with an evil ADK
@@ -193,7 +193,7 @@ void main() {
193193
final Uint8List plaintextBytes = Uint8List.fromList(utf8.encode(plaintext));
194194

195195
// Compute ADK
196-
final Tuple2<int, Uint8List> adkData = await generateAdk(passphrase);
196+
final Tuple2<int, Uint8List> adkData = await generateAdk(passphrase, version: version);
197197
Uint8List adk = adkData.item2;
198198

199199
// Encrypt twice to simulate multiple backups; we even use the same plaintext!

0 commit comments

Comments
 (0)