@@ -37,56 +37,6 @@ impl<J> PrivateJar<J> {
37
37
PrivateJar { parent, key : key. encryption ( ) . try_into ( ) . expect ( "enc key len" ) }
38
38
}
39
39
40
- /// Encrypts the cookie's value with authenticated encryption providing
41
- /// confidentiality, integrity, and authenticity.
42
- fn encrypt_cookie ( & self , cookie : & mut Cookie ) {
43
- // Create a vec to hold the [nonce | cookie value | tag].
44
- let cookie_val = cookie. value ( ) . as_bytes ( ) ;
45
- let mut data = vec ! [ 0 ; NONCE_LEN + cookie_val. len( ) + TAG_LEN ] ;
46
-
47
- // Split data into three: nonce, input/output, tag. Copy input.
48
- let ( nonce, in_out) = data. split_at_mut ( NONCE_LEN ) ;
49
- let ( in_out, tag) = in_out. split_at_mut ( cookie_val. len ( ) ) ;
50
- in_out. copy_from_slice ( cookie_val) ;
51
-
52
- // Fill nonce piece with random data.
53
- let mut rng = self :: rand:: thread_rng ( ) ;
54
- rng. try_fill_bytes ( nonce) . expect ( "couldn't random fill nonce" ) ;
55
- let nonce = GenericArray :: clone_from_slice ( nonce) ;
56
-
57
- // Perform the actual sealing operation, using the cookie's name as
58
- // associated data to prevent value swapping.
59
- let aad = cookie. name ( ) . as_bytes ( ) ;
60
- let aead = Aes256Gcm :: new ( GenericArray :: from_slice ( & self . key ) ) ;
61
- let aad_tag = aead. encrypt_in_place_detached ( & nonce, aad, in_out)
62
- . expect ( "encryption failure!" ) ;
63
-
64
- // Copy the tag into the tag piece.
65
- tag. copy_from_slice ( & aad_tag) ;
66
-
67
- // Base64 encode [nonce | encrypted value | tag].
68
- cookie. set_value ( base64:: encode ( & data) ) ;
69
- }
70
-
71
- /// Given a sealed value `str` and a key name `name`, where the nonce is
72
- /// prepended to the original value and then both are Base64 encoded,
73
- /// verifies and decrypts the sealed value and returns it. If there's a
74
- /// problem, returns an `Err` with a string describing the issue.
75
- fn unseal ( & self , name : & str , value : & str ) -> Result < String , & ' static str > {
76
- let data = base64:: decode ( value) . map_err ( |_| "bad base64 value" ) ?;
77
- if data. len ( ) <= NONCE_LEN {
78
- return Err ( "length of decoded data is <= NONCE_LEN" ) ;
79
- }
80
-
81
- let ( nonce, cipher) = data. split_at ( NONCE_LEN ) ;
82
- let payload = Payload { msg : cipher, aad : name. as_bytes ( ) } ;
83
-
84
- let aead = Aes256Gcm :: new ( GenericArray :: from_slice ( & self . key ) ) ;
85
- aead. decrypt ( GenericArray :: from_slice ( nonce) , payload)
86
- . map_err ( |_| "invalid key/nonce/value: bad seal" )
87
- . and_then ( |s| String :: from_utf8 ( s) . map_err ( |_| "bad unsealed utf8" ) )
88
- }
89
-
90
40
/// Authenticates and decrypts `cookie`, returning the plaintext version if
91
41
/// decryption succeeds or `None` otherwise. Authenticatation and decryption
92
42
/// _always_ succeeds if `cookie` was generated by a `PrivateJar` with the
@@ -112,13 +62,8 @@ impl<J> PrivateJar<J> {
112
62
/// let plain = Cookie::new("plaintext", "hello");
113
63
/// assert!(jar.private(&key).decrypt(plain).is_none());
114
64
/// ```
115
- pub fn decrypt ( & self , mut cookie : Cookie < ' static > ) -> Option < Cookie < ' static > > {
116
- if let Ok ( value) = self . unseal ( cookie. name ( ) , cookie. value ( ) ) {
117
- cookie. set_value ( value) ;
118
- return Some ( cookie) ;
119
- }
120
-
121
- None
65
+ pub fn decrypt ( & self , cookie : Cookie < ' static > ) -> Option < Cookie < ' static > > {
66
+ decrypt_cookie ( & cookie, & self . key )
122
67
}
123
68
}
124
69
@@ -143,7 +88,7 @@ impl<J: Borrow<CookieJar>> PrivateJar<J> {
143
88
/// assert_eq!(private_jar.get("name").unwrap().value(), "value");
144
89
/// ```
145
90
pub fn get ( & self , name : & str ) -> Option < Cookie < ' static > > {
146
- self . parent . borrow ( ) . get ( name) . and_then ( |c| self . decrypt ( c . clone ( ) ) )
91
+ self . parent . borrow ( ) . get ( name) . and_then ( |c| decrypt_cookie ( c , & self . key ) )
147
92
}
148
93
}
149
94
@@ -166,7 +111,7 @@ impl<J: BorrowMut<CookieJar>> PrivateJar<J> {
166
111
/// ```
167
112
pub fn add < C : Into < Cookie < ' static > > > ( & mut self , cookie : C ) {
168
113
let mut cookie = cookie. into ( ) ;
169
- self . encrypt_cookie ( & mut cookie) ;
114
+ encrypt_cookie ( & mut cookie, & self . key ) ;
170
115
self . parent . borrow_mut ( ) . add ( cookie) ;
171
116
}
172
117
@@ -194,7 +139,7 @@ impl<J: BorrowMut<CookieJar>> PrivateJar<J> {
194
139
/// ```
195
140
pub fn add_original < C : Into < Cookie < ' static > > > ( & mut self , cookie : C ) {
196
141
let mut cookie = cookie. into ( ) ;
197
- self . encrypt_cookie ( & mut cookie) ;
142
+ encrypt_cookie ( & mut cookie, & self . key ) ;
198
143
self . parent . borrow_mut ( ) . add_original ( cookie) ;
199
144
}
200
145
@@ -226,6 +171,67 @@ impl<J: BorrowMut<CookieJar>> PrivateJar<J> {
226
171
}
227
172
}
228
173
174
+ /// Encrypts `cookie` in-place using authenticated encryption with the provided
175
+ /// key `key`.
176
+ pub ( crate ) fn encrypt_cookie ( cookie : & mut Cookie < ' static > , key : & [ u8 ] ) {
177
+ // Create a vec to hold the [nonce | cookie value | tag].
178
+ let cookie_val = cookie. value ( ) . as_bytes ( ) ;
179
+ let mut data = vec ! [ 0 ; NONCE_LEN + cookie_val. len( ) + TAG_LEN ] ;
180
+
181
+ // Split data into three: nonce, input/output, tag. Copy input.
182
+ let ( nonce, in_out) = data. split_at_mut ( NONCE_LEN ) ;
183
+ let ( in_out, tag) = in_out. split_at_mut ( cookie_val. len ( ) ) ;
184
+ in_out. copy_from_slice ( cookie_val) ;
185
+
186
+ // Fill nonce piece with random data.
187
+ let mut rng = rand:: thread_rng ( ) ;
188
+ rng. try_fill_bytes ( nonce) . expect ( "couldn't random fill nonce" ) ;
189
+ let nonce = GenericArray :: clone_from_slice ( nonce) ;
190
+
191
+ // Perform the actual sealing operation, using the cookie's name as
192
+ // associated data to prevent value swapping.
193
+ let aad = cookie. name ( ) . as_bytes ( ) ;
194
+ let aead = Aes256Gcm :: new ( GenericArray :: from_slice ( key) ) ;
195
+ let aad_tag = aead. encrypt_in_place_detached ( & nonce, aad, in_out)
196
+ . expect ( "encryption failure!" ) ;
197
+
198
+ // Copy the tag into the tag piece.
199
+ tag. copy_from_slice ( & aad_tag) ;
200
+
201
+ // Base64 encode [nonce | encrypted value | tag].
202
+ let new_value = base64:: encode ( & data) ;
203
+
204
+ // Return encrypted cookie.
205
+ cookie. set_value ( new_value) ;
206
+ }
207
+
208
+ /// Authenticates and decrypts `cookie` using the provided key `key` and returns
209
+ /// the plaintext version if decryption succeeds, otherwise `None`.
210
+ pub ( crate ) fn decrypt_cookie < ' a > ( cookie : & Cookie < ' a > , key : & [ u8 ] ) -> Option < Cookie < ' static > > {
211
+ if let Ok ( value) = decrypt_cookie_impl ( cookie, key) {
212
+ let mut cookie = cookie. clone ( ) . into_owned ( ) ;
213
+ cookie. set_value ( value) ;
214
+ return Some ( cookie) ;
215
+ }
216
+
217
+ None
218
+ }
219
+
220
+ fn decrypt_cookie_impl < ' a > ( cookie : & Cookie < ' a > , key : & [ u8 ] ) -> Result < String , & ' static str > {
221
+ let data = base64:: decode ( cookie. value ( ) ) . map_err ( |_| "bad base64 value" ) ?;
222
+ if data. len ( ) <= NONCE_LEN {
223
+ return Err ( "length of decoded data is <= NONCE_LEN" ) ;
224
+ }
225
+
226
+ let ( nonce, cipher) = data. split_at ( NONCE_LEN ) ;
227
+ let payload = Payload { msg : cipher, aad : cookie. name ( ) . as_bytes ( ) } ;
228
+
229
+ let aead = Aes256Gcm :: new ( GenericArray :: from_slice ( key) ) ;
230
+ aead. decrypt ( GenericArray :: from_slice ( nonce) , payload)
231
+ . map_err ( |_| "invalid key/nonce/value: bad seal" )
232
+ . and_then ( |s| String :: from_utf8 ( s) . map_err ( |_| "bad unsealed utf8" ) )
233
+ }
234
+
229
235
#[ cfg( test) ]
230
236
mod test {
231
237
use crate :: { CookieJar , Cookie , Key } ;
0 commit comments