1
- use alloc:: format;
2
- use openssl:: {
3
- cipher:: { Cipher , CipherRef } ,
4
- cipher_ctx:: CipherCtx ,
5
- } ;
6
- use rustls:: {
7
- crypto:: cipher:: { AeadKey , Iv , Nonce } ,
8
- Error ,
9
- } ;
10
-
11
- pub ( crate ) struct MessageCrypter {
12
- pub algo : Algorithm ,
13
- pub key : AeadKey ,
14
- pub iv : Iv ,
15
- }
1
+ use openssl:: cipher:: { Cipher , CipherRef } ;
2
+ use openssl:: cipher_ctx:: CipherCtx ;
3
+ use rustls:: crypto:: cipher:: NONCE_LEN ;
4
+ use rustls:: Error ;
16
5
17
6
#[ derive( Debug , Clone , Copy ) ]
18
7
pub ( crate ) enum Algorithm {
@@ -26,31 +15,30 @@ pub(crate) enum Algorithm {
26
15
pub ( crate ) const TAG_LEN : usize = 16 ;
27
16
28
17
impl Algorithm {
29
- pub ( crate ) fn openssl_cipher ( self ) -> & ' static CipherRef {
18
+ fn openssl_cipher ( self ) -> & ' static CipherRef {
30
19
match self {
31
20
Self :: Aes128Gcm => Cipher :: aes_128_gcm ( ) ,
32
21
Self :: Aes256Gcm => Cipher :: aes_256_gcm ( ) ,
33
22
#[ cfg( chacha) ]
34
23
Self :: ChaCha20Poly1305 => Cipher :: chacha20_poly1305 ( ) ,
35
24
}
36
25
}
37
- }
38
26
39
- impl MessageCrypter {
40
- /// Encrypts the data in place and returns the tag.
27
+ pub ( crate ) fn key_size ( self ) -> usize {
28
+ self . openssl_cipher ( ) . key_length ( )
29
+ }
30
+
31
+ /// Encrypts data in place and returns the tag.
41
32
pub ( crate ) fn encrypt_in_place (
42
- & self ,
43
- sequence_number : u64 ,
33
+ self ,
34
+ key : & [ u8 ] ,
35
+ nonce : & [ u8 ; NONCE_LEN ] ,
44
36
aad : & [ u8 ] ,
45
37
data : & mut [ u8 ] ,
46
38
) -> Result < [ u8 ; TAG_LEN ] , Error > {
47
39
CipherCtx :: new ( )
48
40
. and_then ( |mut ctx| {
49
- ctx. encrypt_init (
50
- Some ( self . algo . openssl_cipher ( ) ) ,
51
- Some ( self . key . as_ref ( ) ) ,
52
- Some ( & Nonce :: new ( & self . iv , sequence_number) . 0 ) ,
53
- ) ?;
41
+ ctx. encrypt_init ( Some ( self . openssl_cipher ( ) ) , Some ( key) , Some ( nonce) ) ?;
54
42
// Providing no output buffer implies input is AAD.
55
43
ctx. cipher_update ( aad, None ) ?;
56
44
// The ciphers are all stream ciphers, so we shound encrypt the same amount of data...
@@ -70,8 +58,9 @@ impl MessageCrypter {
70
58
/// plaintext.
71
59
/// The data is expected to be in the form of [ciphertext, tag].
72
60
pub ( crate ) fn decrypt_in_place (
73
- & self ,
74
- sequence_number : u64 ,
61
+ self ,
62
+ key : & [ u8 ] ,
63
+ nonce : & [ u8 ; NONCE_LEN ] ,
75
64
aad : & [ u8 ] ,
76
65
data : & mut [ u8 ] ,
77
66
) -> Result < usize , Error > {
@@ -84,11 +73,7 @@ impl MessageCrypter {
84
73
85
74
CipherCtx :: new ( )
86
75
. and_then ( |mut ctx| {
87
- ctx. decrypt_init (
88
- Some ( self . algo . openssl_cipher ( ) ) ,
89
- Some ( self . key . as_ref ( ) ) ,
90
- Some ( & Nonce :: new ( & self . iv , sequence_number) . 0 ) ,
91
- ) ?;
76
+ ctx. decrypt_init ( Some ( self . openssl_cipher ( ) ) , Some ( key) , Some ( nonce) ) ?;
92
77
ctx. cipher_update ( aad, None ) ?;
93
78
ctx. set_tag ( tag) ?;
94
79
let count = ctx. cipher_update_inplace ( ciphertext, ciphertext. len ( ) ) ?;
@@ -100,3 +85,130 @@ impl MessageCrypter {
100
85
. map_err ( |e| Error :: General ( format ! ( "OpenSSL error: {e}" ) ) )
101
86
}
102
87
}
88
+
89
+ #[ cfg( test) ]
90
+ mod test {
91
+
92
+ use crate :: test:: schemas:: aead;
93
+ use std:: { fs, path:: PathBuf } ;
94
+
95
+ fn test_aes ( alg : super :: Algorithm ) {
96
+ let path = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) )
97
+ . join ( "src" )
98
+ . join ( "test" )
99
+ . join ( "vectors" )
100
+ . join ( "aes_gcm_test.json" ) ;
101
+ let tests: aead:: AeadTestFile =
102
+ serde_json:: from_str ( & fs:: read_to_string ( path) . unwrap ( ) ) . unwrap ( ) ;
103
+
104
+ for group in tests
105
+ . test_groups
106
+ . unwrap ( )
107
+ . iter ( )
108
+ . filter ( |group| group. key_size . unwrap ( ) == 8 * i64:: try_from ( alg. key_size ( ) ) . unwrap ( ) )
109
+ . filter ( |group| group. iv_size . unwrap ( ) == 96 )
110
+ {
111
+ for test in group. tests . as_ref ( ) . unwrap ( ) {
112
+ dbg ! ( test. tc_id) ;
113
+ let key = test
114
+ . key
115
+ . as_deref ( )
116
+ . map ( |key| hex:: decode ( key) . unwrap ( ) )
117
+ . unwrap ( ) ;
118
+ let iv = test
119
+ . iv
120
+ . as_deref ( )
121
+ . map ( |iv| hex:: decode ( iv) . unwrap ( ) )
122
+ . unwrap ( ) ;
123
+ let aad = test
124
+ . aad
125
+ . as_deref ( )
126
+ . map ( |aad| hex:: decode ( aad) . unwrap ( ) )
127
+ . unwrap ( ) ;
128
+ let msg = test
129
+ . msg
130
+ . as_deref ( )
131
+ . map ( |msg| hex:: decode ( msg) . unwrap ( ) )
132
+ . unwrap ( ) ;
133
+ let ciphertext = test
134
+ . ct
135
+ . as_deref ( )
136
+ . map ( |ct| hex:: decode ( ct) . unwrap ( ) )
137
+ . unwrap ( ) ;
138
+ let tag = test
139
+ . tag
140
+ . as_deref ( )
141
+ . map ( |tag| hex:: decode ( tag) . unwrap ( ) )
142
+ . unwrap ( ) ;
143
+
144
+ let mut iv_bytes = [ 0u8 ; 12 ] ;
145
+ iv_bytes. copy_from_slice ( & iv[ 0 ..12 ] ) ;
146
+
147
+ let mut actual_ciphertext = msg. clone ( ) ;
148
+ let actual_tag = alg
149
+ . encrypt_in_place ( & key, & iv_bytes, & aad, & mut actual_ciphertext)
150
+ . unwrap ( ) ;
151
+
152
+ match test. result . as_ref ( ) . unwrap ( ) {
153
+ aead:: Result :: Invalid => {
154
+ if test
155
+ . flags
156
+ . as_ref ( )
157
+ . unwrap ( )
158
+ . iter ( )
159
+ . any ( |flag| flag == "ModifiedTag" )
160
+ {
161
+ assert_ne ! (
162
+ actual_tag[ ..] ,
163
+ tag[ ..] ,
164
+ "Expected incorrect tag. Id {}: {}" ,
165
+ test. tc_id. unwrap( ) ,
166
+ test. comment. as_deref( ) . unwrap( )
167
+ ) ;
168
+ }
169
+ }
170
+ aead:: Result :: Valid | aead:: Result :: Acceptable => {
171
+ assert_eq ! (
172
+ actual_ciphertext,
173
+ ciphertext,
174
+ "Test case failed {}: {}" ,
175
+ test. tc_id. unwrap( ) ,
176
+ test. comment. as_deref( ) . unwrap( )
177
+ ) ;
178
+ assert_eq ! (
179
+ actual_tag[ ..] ,
180
+ tag[ ..] ,
181
+ "Test case failed {}: {}" ,
182
+ test. tc_id. unwrap( ) ,
183
+ test. comment. as_deref( ) . unwrap( )
184
+ ) ;
185
+ }
186
+ }
187
+
188
+ let mut data = ciphertext. to_vec ( ) ;
189
+ data. extend_from_slice ( & tag) ;
190
+ let res = alg. decrypt_in_place ( & key, & iv_bytes, & aad, & mut data) ;
191
+
192
+ match test. result . as_ref ( ) . unwrap ( ) {
193
+ aead:: Result :: Invalid => {
194
+ assert ! ( res. is_err( ) ) ;
195
+ }
196
+ aead:: Result :: Valid | aead:: Result :: Acceptable => {
197
+ assert_eq ! ( res, Ok ( msg. len( ) ) ) ;
198
+ assert_eq ! ( & data[ ..res. unwrap( ) ] , & msg[ ..] ) ;
199
+ }
200
+ }
201
+ }
202
+ }
203
+ }
204
+
205
+ #[ test]
206
+ fn test_aes_128 ( ) {
207
+ test_aes ( super :: Algorithm :: Aes128Gcm ) ;
208
+ }
209
+
210
+ #[ test]
211
+ fn test_aes_256 ( ) {
212
+ test_aes ( super :: Algorithm :: Aes256Gcm ) ;
213
+ }
214
+ }
0 commit comments