Skip to content

Commit 933b999

Browse files
committed
Adds SaltedCipher mixin to XChaCha20, XSalsa20, and all AEAD ciphers
1 parent bc0a363 commit 933b999

32 files changed

+988
-367
lines changed

benchmark/chacha20.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class CipherlibBenchmark extends Benchmark {
2323

2424
@override
2525
void run() {
26-
cipher.chacha20(input, key, nonce: nonce);
26+
cipher.ChaCha20(key, nonce).convert(input);
2727
}
2828
}
2929

benchmark/chacha20_poly1305.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class CipherlibBenchmark extends Benchmark {
2323

2424
@override
2525
void run() {
26-
cipher.ChaCha20Poly1305(key: key, nonce: nonce).convert(input);
26+
cipher.ChaCha20Poly1305(key, nonce: nonce).convert(input);
2727
}
2828
}
2929

benchmark/salsa20_poly1305.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class CipherlibBenchmark extends Benchmark {
2121

2222
@override
2323
void run() {
24-
cipher.Salsa20Poly1305(key: key, nonce: nonce).convert(input);
24+
cipher.Salsa20Poly1305(key, nonce: nonce).convert(input);
2525
}
2626
}
2727

example/cipherlib_example.dart

Lines changed: 23 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import 'package:cipherlib/cipherlib.dart';
2+
import 'package:hashlib/hashlib.dart';
23
import 'package:hashlib_codecs/hashlib_codecs.dart';
34

45
void main() {
56
print('----- AES -----');
67
{
78
var plain = 'A not very secret message';
8-
var key = 'abcdefghijklmnopabcdefghijklmnop'.codeUnits;
9-
var iv = 'lka9JLKasljkdPsd'.codeUnits;
9+
var key = randomBytes(32);
10+
var iv = randomBytes(16);
1011
print(' Text: $plain');
1112
print(' Key: ${toHex(key)}');
1213
print(' Nonce: ${toHex(iv)}');
14+
// different modes
1315
print(' ECB: ${toHex(AES(key).ecb().encryptString(plain))}');
1416
print(' CBC: ${toHex(AES(key).cbc(iv).encryptString(plain))}');
1517
print(' CTR: ${toHex(AES(key).ctr(iv).encryptString(plain))}');
@@ -22,49 +24,30 @@ void main() {
2224
}
2325
print('');
2426

25-
print('----- ChaCha20 -----');
27+
print('----- XChaCha20 -----');
2628
{
2729
var text = "Hide me!";
28-
var key = fromHex(
29-
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
30-
var nonce = fromHex("00000000000000004a000000");
31-
var res = chacha20poly1305(toUtf8(text), key, nonce: nonce);
32-
var plain = chacha20(res.data, key, nonce: nonce);
30+
var key = randomBytes(32);
31+
var nonce = randomBytes(24);
32+
// encrypt and sign
33+
var cipher = xchacha20poly1305(
34+
toUtf8(text),
35+
key,
36+
nonce: nonce,
37+
);
38+
// verify and decrypt
39+
var plain = xchacha20poly1305(
40+
cipher.data,
41+
key,
42+
nonce: nonce,
43+
mac: cipher.tag.bytes,
44+
);
3345
print(' Text: $text');
3446
print(' Key: ${toHex(key)}');
3547
print(' Nonce: ${toHex(nonce)}');
36-
print('Cipher: ${toHex(res.data)}');
37-
print(' Tag: ${res.tag.hex()}');
38-
print(' Plain: ${fromUtf8(plain)}');
48+
print('Cipher: ${toHex(cipher.data)}');
49+
print(' Tag: ${cipher.tag.hex()}');
50+
print(' Plain: ${fromUtf8(plain.data)}');
3951
}
4052
print('');
41-
42-
print('----- Salsa20 -----');
43-
{
44-
var text = "Hide me!";
45-
var key = fromHex(
46-
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
47-
var nonce = fromHex("00000000000000004a00000000000000");
48-
var res = salsa20poly1305(toUtf8(text), key, nonce: nonce);
49-
var plain = salsa20(res.data, key, nonce: nonce);
50-
print(' Text: $text');
51-
print(' Key: ${toHex(key)}');
52-
print(' Nonce: ${toHex(nonce)}');
53-
print('Cipher: ${toHex(res.data)}');
54-
print(' Tag: ${res.tag.hex()}');
55-
print(' Plain: ${fromUtf8(plain)}');
56-
57-
print('----- XOR -----');
58-
{
59-
var key = [0x54];
60-
var inp = [0x03, 0xF1];
61-
var cipher = xor(inp, key);
62-
var plain = xor(cipher, key);
63-
print(' Text: ${toBinary(inp)}');
64-
print(' Key: ${toBinary(key)}');
65-
print(' XOR: ${toBinary(cipher)}');
66-
print(' Plain: ${toBinary(plain)}');
67-
}
68-
print('');
69-
}
7053
}

lib/src/algorithms/aead_cipher.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ abstract class AEADCipher<C extends Cipher, M extends MACHashBase>
174174

175175
/// Transforms the [message]. Alias for [sign].
176176
@pragma('vm:prefer-inline')
177-
AEADResult convert(List<int> message) => sign(message);
177+
Uint8List convert(List<int> message, [bool verifyMode = false]) =>
178+
createSink(verifyMode).add(message, true);
178179

179180
/// Signs the [message] with an authentication tag.
180181
AEADResult sign(List<int> message) {
@@ -193,8 +194,9 @@ abstract class AEADCipher<C extends Cipher, M extends MACHashBase>
193194
Stream<Uint8List> bind(
194195
Stream<List<int>> stream, [
195196
Function(HashDigest tag)? onDigest,
197+
bool verifyMode = false,
196198
]) async* {
197-
var sink = createSink();
199+
var sink = createSink(verifyMode);
198200
List<int>? cache;
199201
await for (var data in stream) {
200202
if (cache != null) {
@@ -212,9 +214,10 @@ abstract class AEADCipher<C extends Cipher, M extends MACHashBase>
212214
Stream<int> stream(
213215
Stream<int> stream, [
214216
Function(HashDigest tag)? onDigest,
217+
bool verifyMode = false,
215218
]) async* {
216219
int p = 0;
217-
var sink = createSink();
220+
var sink = createSink(verifyMode);
218221
var chunk = Uint8List(1024);
219222
await for (var x in stream) {
220223
chunk[p++] = x;

lib/src/algorithms/aes/cbc.dart

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33

44
import 'dart:typed_data';
55

6-
import 'package:cipherlib/src/algorithms/padding.dart';
6+
import 'package:cipherlib/src/core/cipher.dart';
77
import 'package:cipherlib/src/core/cipher_sink.dart';
8-
import 'package:cipherlib/src/core/salted_cipher.dart';
8+
import 'package:cipherlib/src/core/collate_cipher.dart';
99
import 'package:hashlib/hashlib.dart' show randomBytes;
1010

11+
import '../padding.dart';
1112
import '_core.dart';
1213

1314
/// The sink used for encryption by the [AESInCBCModeEncrypt] algorithm.
@@ -215,7 +216,7 @@ class AESInCBCModeDecryptSink implements CipherSink {
215216
}
216217

217218
/// Provides encryption for AES cipher in CBC mode.
218-
class AESInCBCModeEncrypt extends SaltedCipher {
219+
class AESInCBCModeEncrypt extends Cipher with SaltedCipher {
219220
@override
220221
String get name => "AES#encrypt/CBC/${padding.name}";
221222

@@ -225,11 +226,14 @@ class AESInCBCModeEncrypt extends SaltedCipher {
225226
/// Padding scheme for the input message
226227
final Padding padding;
227228

229+
@override
230+
final Uint8List iv;
231+
228232
const AESInCBCModeEncrypt(
229233
this.key,
230-
Uint8List iv, [
234+
this.iv, [
231235
this.padding = Padding.pkcs7,
232-
]) : super(iv);
236+
]);
233237

234238
@override
235239
@pragma('vm:prefer-inline')
@@ -238,7 +242,7 @@ class AESInCBCModeEncrypt extends SaltedCipher {
238242
}
239243

240244
/// Provides decryption for AES cipher in CBC mode.
241-
class AESInCBCModeDecrypt extends SaltedCipher {
245+
class AESInCBCModeDecrypt extends Cipher with SaltedCipher {
242246
@override
243247
String get name => "AES#decrypt/CBC/${padding.name}";
244248

@@ -248,11 +252,14 @@ class AESInCBCModeDecrypt extends SaltedCipher {
248252
/// Padding scheme for the output message
249253
final Padding padding;
250254

255+
@override
256+
final Uint8List iv;
257+
251258
const AESInCBCModeDecrypt(
252259
this.key,
253-
Uint8List iv, [
260+
this.iv, [
254261
this.padding = Padding.pkcs7,
255-
]) : super(iv);
262+
]);
256263

257264
@override
258265
@pragma('vm:prefer-inline')
@@ -261,7 +268,7 @@ class AESInCBCModeDecrypt extends SaltedCipher {
261268
}
262269

263270
/// Provides encryption and decryption for AES cipher in CBC mode.
264-
class AESInCBCMode extends SaltedCollateCipher {
271+
class AESInCBCMode extends CollateCipher with SaltedCipher {
265272
@override
266273
String get name => "AES/CBC/${padding.name}";
267274

@@ -276,6 +283,9 @@ class AESInCBCMode extends SaltedCollateCipher {
276283
required this.decryptor,
277284
});
278285

286+
@override
287+
Uint8List get iv => encryptor.iv;
288+
279289
/// Creates AES cipher in CBC mode.
280290
///
281291
/// Parameters:

lib/src/algorithms/aes/cfb.dart

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33

44
import 'dart:typed_data';
55

6-
import 'package:cipherlib/src/algorithms/padding.dart';
6+
import 'package:cipherlib/src/core/cipher.dart';
77
import 'package:cipherlib/src/core/cipher_sink.dart';
8-
import 'package:cipherlib/src/core/salted_cipher.dart';
8+
import 'package:cipherlib/src/core/collate_cipher.dart';
99
import 'package:hashlib/hashlib.dart' show randomBytes;
1010

11+
import '../padding.dart';
1112
import '_core.dart';
1213

1314
/// The sink used for encryption by the [AESInCFBModeEncrypt] algorithm.
@@ -164,7 +165,7 @@ class AESInCFBModeDecryptSink implements CipherSink {
164165
}
165166

166167
/// Provides encryption for AES cipher in CFB mode.
167-
class AESInCFBModeEncrypt extends SaltedCipher {
168+
class AESInCFBModeEncrypt extends Cipher with SaltedCipher {
168169
@override
169170
String get name => "AES#encrypt/CFB/${Padding.none.name}";
170171

@@ -174,11 +175,14 @@ class AESInCFBModeEncrypt extends SaltedCipher {
174175
/// Number of bytes to use per block
175176
final int sbyte;
176177

178+
@override
179+
final Uint8List iv;
180+
177181
const AESInCFBModeEncrypt(
178182
this.key,
179-
Uint8List iv,
183+
this.iv,
180184
this.sbyte,
181-
) : super(iv);
185+
);
182186

183187
@override
184188
@pragma('vm:prefer-inline')
@@ -187,7 +191,7 @@ class AESInCFBModeEncrypt extends SaltedCipher {
187191
}
188192

189193
/// Provides decryption for AES cipher in CFB mode.
190-
class AESInCFBModeDecrypt extends SaltedCipher {
194+
class AESInCFBModeDecrypt extends Cipher with SaltedCipher {
191195
@override
192196
String get name => "AES#decrypt/CFB/${Padding.none.name}";
193197

@@ -197,7 +201,14 @@ class AESInCFBModeDecrypt extends SaltedCipher {
197201
/// Number of bytes to use per block
198202
final int sbyte;
199203

200-
const AESInCFBModeDecrypt(this.key, Uint8List iv, this.sbyte) : super(iv);
204+
@override
205+
final Uint8List iv;
206+
207+
const AESInCFBModeDecrypt(
208+
this.key,
209+
this.iv,
210+
this.sbyte,
211+
);
201212

202213
@override
203214
@pragma('vm:prefer-inline')
@@ -206,7 +217,7 @@ class AESInCFBModeDecrypt extends SaltedCipher {
206217
}
207218

208219
/// Provides encryption and decryption for AES cipher in CFB mode.
209-
class AESInCFBMode extends SaltedCollateCipher {
220+
class AESInCFBMode extends CollateCipher with SaltedCipher {
210221
@override
211222
String get name => "AES/CFB/${Padding.none.name}";
212223

@@ -221,6 +232,9 @@ class AESInCFBMode extends SaltedCollateCipher {
221232
required this.decryptor,
222233
});
223234

235+
@override
236+
Uint8List get iv => encryptor.iv;
237+
224238
/// Creates AES cipher in CFB mode.
225239
///
226240
/// Parameters:

lib/src/algorithms/aes/ctr.dart

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33

44
import 'dart:typed_data';
55

6-
import 'package:cipherlib/src/algorithms/padding.dart';
6+
import 'package:cipherlib/src/core/cipher.dart';
77
import 'package:cipherlib/src/core/cipher_sink.dart';
8-
import 'package:cipherlib/src/core/salted_cipher.dart';
8+
import 'package:cipherlib/src/core/collate_cipher.dart';
99
import 'package:cipherlib/src/utils/nonce.dart';
1010
import 'package:hashlib/hashlib.dart' show randomBytes;
1111

12+
import '../padding.dart';
1213
import '_core.dart';
1314

1415
const int _mask32 = 0xFFFFFFFF;
@@ -99,22 +100,25 @@ class AESInCTRModeSink implements CipherSink {
99100
}
100101

101102
/// Provides AES cipher in CTR mode.
102-
class AESInCTRModeCipher extends SaltedCipher {
103+
class AESInCTRModeCipher extends Cipher with SaltedCipher {
103104
@override
104105
String get name => "AES#cipher/CTR/${Padding.none.name}";
105106

106107
/// Key for the cipher
107108
final Uint8List key;
108109

109-
const AESInCTRModeCipher(this.key, Uint8List iv) : super(iv);
110+
@override
111+
final Uint8List iv;
112+
113+
const AESInCTRModeCipher(this.key, this.iv);
110114

111115
@override
112116
@pragma('vm:prefer-inline')
113117
AESInCTRModeSink createSink() => AESInCTRModeSink(key, iv);
114118
}
115119

116120
/// Provides encryption and decryption for AES cipher in CTR mode.
117-
class AESInCTRMode extends SaltedCollateCipher {
121+
class AESInCTRMode extends CollateCipher with SaltedCipher {
118122
@override
119123
String get name => "AES/CTR/${Padding.none.name}";
120124

@@ -129,6 +133,9 @@ class AESInCTRMode extends SaltedCollateCipher {
129133
required this.decryptor,
130134
});
131135

136+
@override
137+
Uint8List get iv => encryptor.iv;
138+
132139
/// Creates AES cipher in CTR mode.
133140
///
134141
/// The [iv] parameter combines the 64-bit nonce, and 64-bit counter

0 commit comments

Comments
 (0)