Skip to content

Commit 4ee992e

Browse files
committed
Refactor CipherSink implementation
- Changed CipherSink from an interface to an abstract class, providing default implementations for reset and closed properties. - Updated all cipher algorithms to extend the new CipherSink class, simplifying their implementations. - Removed redundant closed state management from individual cipher sinks. - Adjusted add method to handle range checks and state management consistently across all sinks.
1 parent 00d7209 commit 4ee992e

18 files changed

Lines changed: 166 additions & 504 deletions

CHANGELOG.md

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,6 @@
11
# 0.1.0
22

33
- ![dart support](https://img.shields.io/badge/dart-%3e%3d%202.19.0-39f?logo=dart)
4-
- Bump dependency: hashlib
5-
- Refactor internal files
6-
- Fixes a few security issues:
7-
- AEAD sink reset keeps stale message length state
8-
- AEAD does not re-apply AAD framing after sink reset
9-
- AES-CTR accepts IVs > 16 bytes but silently ignores extra bytes
10-
11-
## 0.0.14
12-
134
- `AES` in ECB, CBC, CTR, CFB, OFB, GCM, XTS, IGE, PCBC modes.
145
- `XChaCha20`, `ChaCha20` cipher with `Poly1305` tag.
156
- `XSalsa20`, `Salsa20` cipher with `Poly1305` tag.

lib/src/algorithms/aead_cipher.dart

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,20 +56,7 @@ class AEADCipherSink<C extends CipherSink, H extends HashDigestSink>
5656
this._aad,
5757
this._verifyMode = false,
5858
]) {
59-
_cipher.reset();
60-
_addAAD();
61-
}
62-
63-
@pragma('vm:prefer-inline')
64-
void _addAAD() {
65-
if (_aad != null) {
66-
_sink.add(_aad!);
67-
// pad with zero
68-
int n = _aad!.length;
69-
if (n & 15 != 0) {
70-
_sink.add(Uint8List(16 - (n & 15)));
71-
}
72-
}
59+
reset(_verifyMode);
7360
}
7461

7562
/// The length of generated hash in bytes
@@ -84,7 +71,14 @@ class AEADCipherSink<C extends CipherSink, H extends HashDigestSink>
8471
_cipher.reset();
8572
_dataLength = 0;
8673
_verifyMode = forVerification;
87-
_addAAD();
74+
if (_aad != null) {
75+
_sink.add(_aad!);
76+
// pad with zero
77+
int n = _aad!.length;
78+
if (n & 15 != 0) {
79+
_sink.add(Uint8List(16 - (n & 15)));
80+
}
81+
}
8882
}
8983

9084
@override
@@ -131,6 +125,11 @@ class AEADCipherSink<C extends CipherSink, H extends HashDigestSink>
131125
return cipher;
132126
}
133127

128+
@override
129+
Uint8List $add(List<int> data, int start, int end) {
130+
throw UnimplementedError();
131+
}
132+
134133
@override
135134
Uint8List close() {
136135
final r = add([], true);

lib/src/algorithms/aes_modes/cbc.dart

Lines changed: 11 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import '../aes.dart';
1212
import '../padding.dart';
1313

1414
/// The sink used for encryption by the [AESInCBCModeEncrypt] algorithm.
15-
class AESInCBCModeEncryptSink implements CipherSink {
15+
class AESInCBCModeEncryptSink extends CipherSink {
1616
AESInCBCModeEncryptSink(
1717
this._key,
1818
this._iv,
@@ -22,7 +22,6 @@ class AESInCBCModeEncryptSink implements CipherSink {
2222
}
2323

2424
int _pos = 0;
25-
bool _closed = false;
2625
final Uint8List _iv;
2726
final Uint8List _key;
2827
final Padding _padding;
@@ -32,35 +31,22 @@ class AESInCBCModeEncryptSink implements CipherSink {
3231
late final _block32 = Uint32List.view(_block.buffer);
3332
late final _xkey32 = AESCore.$expandEncryptionKey(_key32);
3433

35-
@override
36-
bool get closed => _closed;
37-
3834
@override
3935
void reset() {
36+
super.reset();
4037
_pos = 0;
41-
_closed = false;
4238
for (int i = 0; i < 16; ++i) {
4339
_block[i] = _iv[i];
4440
}
4541
}
4642

4743
@override
48-
Uint8List add(
49-
List<int> data, [
50-
bool last = false,
51-
int start = 0,
52-
int? end,
53-
]) {
54-
if (_closed) {
55-
throw StateError('The sink is closed');
56-
}
57-
_closed = last;
58-
end ??= data.length;
59-
44+
@pragma('vm:prefer-inline')
45+
Uint8List $add(List<int> data, int start, int end) {
6046
int i, j, p, n;
6147

6248
n = _pos + end - start;
63-
if (last) {
49+
if (closed) {
6450
n += 16 - (n & 15);
6551
}
6652
var output = Uint8List(n);
@@ -78,7 +64,7 @@ class AESInCBCModeEncryptSink implements CipherSink {
7864
}
7965
}
8066

81-
if (last) {
67+
if (closed) {
8268
for (j = _pos; j < 16; ++j) {
8369
_temp[j] = _block[j];
8470
}
@@ -105,14 +91,10 @@ class AESInCBCModeEncryptSink implements CipherSink {
10591
return output.sublist(0, p);
10692
}
10793
}
108-
109-
@override
110-
@pragma('vm:prefer-inline')
111-
Uint8List close() => add([], true);
11294
}
11395

11496
/// The sink used for decryption by the [AESInCBCModeDecrypt] algorithm.
115-
class AESInCBCModeDecryptSink implements CipherSink {
97+
class AESInCBCModeDecryptSink extends CipherSink {
11698
AESInCBCModeDecryptSink(
11799
this._key,
118100
this._iv,
@@ -123,7 +105,6 @@ class AESInCBCModeDecryptSink implements CipherSink {
123105

124106
int _pos = 0;
125107
int _rpos = 0;
126-
bool _closed = false;
127108
final Uint8List _key;
128109
final Uint8List _iv;
129110
final Padding _padding;
@@ -135,31 +116,18 @@ class AESInCBCModeDecryptSink implements CipherSink {
135116
late final _block32 = Uint32List.view(_block.buffer);
136117
late final _xkey32 = AESCore.$expandDecryptionKey(_key32);
137118

138-
@override
139-
bool get closed => _closed;
140-
141119
@override
142120
void reset() {
121+
super.reset();
143122
_pos = 0;
144-
_closed = false;
145123
for (int i = 0; i < 16; ++i) {
146124
_salt[i] = _iv[i];
147125
}
148126
}
149127

150128
@override
151-
Uint8List add(
152-
List<int> data, [
153-
bool last = false,
154-
int start = 0,
155-
int? end,
156-
]) {
157-
if (_closed) {
158-
throw StateError('The sink is closed');
159-
}
160-
_closed = last;
161-
end ??= data.length;
162-
129+
@pragma('vm:prefer-inline')
130+
Uint8List $add(List<int> data, int start, int end) {
163131
int i, j, k, p, n;
164132

165133
n = _rpos + end - start;
@@ -186,7 +154,7 @@ class AESInCBCModeDecryptSink implements CipherSink {
186154
}
187155
}
188156

189-
if (last) {
157+
if (closed) {
190158
if (_rpos == 16) {
191159
for (k = 0; k < 16; ++k) {
192160
output[p++] = _residue[k];
@@ -209,10 +177,6 @@ class AESInCBCModeDecryptSink implements CipherSink {
209177
return output.sublist(0, p);
210178
}
211179
}
212-
213-
@override
214-
@pragma('vm:prefer-inline')
215-
Uint8List close() => add([], true);
216180
}
217181

218182
/// Provides encryption for AES cipher in CBC mode.

lib/src/algorithms/aes_modes/cfb.dart

Lines changed: 8 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import '../aes.dart';
1212
import '../padding.dart';
1313

1414
/// The sink used for encryption by the [AESInCFBModeEncrypt] algorithm.
15-
class AESInCFBModeEncryptSink implements CipherSink {
15+
class AESInCFBModeEncryptSink extends CipherSink {
1616
AESInCFBModeEncryptSink(
1717
this._key,
1818
this._iv,
@@ -22,7 +22,6 @@ class AESInCFBModeEncryptSink implements CipherSink {
2222
}
2323

2424
int _pos = 0;
25-
bool _closed = false;
2625
final Uint8List _key;
2726
final Uint8List _iv;
2827
final int _sbyte;
@@ -32,31 +31,18 @@ class AESInCFBModeEncryptSink implements CipherSink {
3231
late final _block32 = Uint32List.view(_block.buffer);
3332
late final _xkey32 = AESCore.$expandEncryptionKey(_key32);
3433

35-
@override
36-
bool get closed => _closed;
37-
3834
@override
3935
void reset() {
36+
super.reset();
4037
_pos = 0;
41-
_closed = false;
4238
for (int i = 0; i < 16; ++i) {
4339
_salt[i] = _iv[i];
4440
}
4541
}
4642

4743
@override
48-
Uint8List add(
49-
List<int> data, [
50-
bool last = false,
51-
int start = 0,
52-
int? end,
53-
]) {
54-
if (_closed) {
55-
throw StateError('The sink is closed');
56-
}
57-
_closed = last;
58-
end ??= data.length;
59-
44+
@pragma('vm:prefer-inline')
45+
Uint8List $add(List<int> data, int start, int end) {
6046
int i, j, p;
6147
var output = Uint8List(end - start);
6248

@@ -82,14 +68,10 @@ class AESInCFBModeEncryptSink implements CipherSink {
8268

8369
return output;
8470
}
85-
86-
@override
87-
@pragma('vm:prefer-inline')
88-
Uint8List close() => add([], true);
8971
}
9072

9173
/// The sink used for decryption by the [AESInCFBModeDecrypt] algorithm.
92-
class AESInCFBModeDecryptSink implements CipherSink {
74+
class AESInCFBModeDecryptSink extends CipherSink {
9375
AESInCFBModeDecryptSink(
9476
this._key,
9577
this._iv,
@@ -99,7 +81,6 @@ class AESInCFBModeDecryptSink implements CipherSink {
9981
}
10082

10183
int _pos = 0;
102-
bool _closed = false;
10384
final Uint8List _key;
10485
final Uint8List _iv;
10586
late final Uint32List _key32 = Uint32List.view(_key.buffer);
@@ -109,31 +90,18 @@ class AESInCFBModeDecryptSink implements CipherSink {
10990
late final _block32 = Uint32List.view(_block.buffer);
11091
late final _xkey32 = AESCore.$expandEncryptionKey(_key32);
11192

112-
@override
113-
bool get closed => _closed;
114-
11593
@override
11694
void reset() {
95+
super.reset();
11796
_pos = 0;
118-
_closed = false;
11997
for (int i = 0; i < 16; ++i) {
12098
_salt[i] = _iv[i];
12199
}
122100
}
123101

124102
@override
125-
Uint8List add(
126-
List<int> data, [
127-
bool last = false,
128-
int start = 0,
129-
int? end,
130-
]) {
131-
if (_closed) {
132-
throw StateError('The sink is closed');
133-
}
134-
_closed = last;
135-
end ??= data.length;
136-
103+
@pragma('vm:prefer-inline')
104+
Uint8List $add(List<int> data, int start, int end) {
137105
int i, j, p;
138106
p = 0;
139107
j = _pos + 16 - _sbyte;
@@ -158,10 +126,6 @@ class AESInCFBModeDecryptSink implements CipherSink {
158126

159127
return output;
160128
}
161-
162-
@override
163-
@pragma('vm:prefer-inline')
164-
Uint8List close() => add([], true);
165129
}
166130

167131
/// Provides encryption for AES cipher in CFB mode.

lib/src/algorithms/aes_modes/ctr.dart

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ int _swap32(int x) =>
2323

2424
/// The sink used for both encryption and decryption by the
2525
/// [AESInCTRModeCipher] algorithm.
26-
class AESInCTRModeSink implements CipherSink {
26+
class AESInCTRModeSink extends CipherSink {
2727
AESInCTRModeSink(
2828
this._key,
2929
this._iv,
@@ -32,7 +32,6 @@ class AESInCTRModeSink implements CipherSink {
3232
}
3333

3434
int _pos = 0;
35-
bool _closed = false;
3635
final Uint8List _key;
3736
final Uint8List _iv;
3837
late int _s0, _s1, _s2, _s3;
@@ -41,32 +40,19 @@ class AESInCTRModeSink implements CipherSink {
4140
late final _block = Uint8List.view(_block32.buffer);
4241
late final _xkey32 = AESCore.$expandEncryptionKey(_key32);
4342

44-
@override
45-
bool get closed => _closed;
46-
4743
@override
4844
void reset() {
45+
super.reset();
4946
_pos = 0;
50-
_closed = false;
5147
_s0 = (_iv[0] << 24) | (_iv[1] << 16) | (_iv[2] << 8) | (_iv[3]);
5248
_s1 = (_iv[4] << 24) | (_iv[5] << 16) | (_iv[6] << 8) | (_iv[7]);
5349
_s2 = (_iv[8] << 24) | (_iv[9] << 16) | (_iv[10] << 8) | (_iv[11]);
5450
_s3 = (_iv[12] << 24) | (_iv[13] << 16) | (_iv[14] << 8) | (_iv[15]);
5551
}
5652

5753
@override
58-
Uint8List add(
59-
List<int> data, [
60-
bool last = false,
61-
int start = 0,
62-
int? end,
63-
]) {
64-
if (_closed) {
65-
throw StateError('The sink is closed');
66-
}
67-
_closed = last;
68-
end ??= data.length;
69-
54+
@pragma('vm:prefer-inline')
55+
Uint8List $add(List<int> data, int start, int end) {
7056
int i, p;
7157
var output = Uint8List(end - start);
7258

@@ -93,10 +79,6 @@ class AESInCTRModeSink implements CipherSink {
9379

9480
return output;
9581
}
96-
97-
@override
98-
@pragma('vm:prefer-inline')
99-
Uint8List close() => add([], true);
10082
}
10183

10284
/// Provides AES cipher in CTR mode.

0 commit comments

Comments
 (0)