@@ -161,14 +161,23 @@ static THUMB_NONCE: secretbox::Nonce = secretbox::Nonce([
161161 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 2 ,
162162] ) ;
163163
164+ #[ derive( Clone ) ]
165+ pub struct FileData {
166+ pub file : Vec < u8 > ,
167+ pub thumbnail : Option < Vec < u8 > > ,
168+ }
169+
170+ #[ derive( Clone ) ]
171+ pub struct EncryptedFileData {
172+ pub file : Vec < u8 > ,
173+ pub thumbnail : Option < Vec < u8 > > ,
174+ }
175+
164176/// Encrypt file data and an optional thumbnail using a randomly generated
165177/// symmetric key.
166178///
167179/// Return the encrypted bytes and the key.
168- pub fn encrypt_file_data (
169- file_data : & [ u8 ] ,
170- thumb_data : Option < & [ u8 ] > ,
171- ) -> ( Vec < u8 > , Option < Vec < u8 > > , secretbox:: Key ) {
180+ pub fn encrypt_file_data ( data : & FileData ) -> ( EncryptedFileData , Key ) {
172181 // Make sure to init sodiumoxide library
173182 sodiumoxide:: init ( ) . unwrap ( ) ;
174183
@@ -177,23 +186,48 @@ pub fn encrypt_file_data(
177186
178187 // Encrypt data
179188 // Note: Since we generate a random key, we can safely re-use constant nonces.
180- let encrypted_file = secretbox:: seal ( file_data, & FILE_NONCE , & key) ;
181- let encrypted_thumb = thumb_data. map ( |t| secretbox:: seal ( t, & THUMB_NONCE , & key) ) ;
189+ let file = secretbox:: seal ( & data. file , & FILE_NONCE , & key) ;
190+ let thumbnail = data
191+ . thumbnail
192+ . as_ref ( )
193+ . map ( |t| secretbox:: seal ( t, & THUMB_NONCE , & key) ) ;
182194
183- ( encrypted_file , encrypted_thumb , key)
195+ ( EncryptedFileData { file , thumbnail } , key)
184196}
185197
186- pub fn decrypt_file_data ( encrypted_data : & [ u8 ] , blob_key : & Key ) -> Result < Vec < u8 > , CryptoError > {
187- let decrypted_blob = secretbox:: open ( encrypted_data, & FILE_NONCE , blob_key) ;
188- decrypted_blob. map_err ( |_| CryptoError :: DecryptionFailed )
198+ /// Decrypt file data and optional thumbnail data with the provided symmetric
199+ /// key.
200+ ///
201+ /// Return the decrypted bytes.
202+ pub fn decrypt_file_data (
203+ data : & EncryptedFileData ,
204+ encryption_key : & Key ,
205+ ) -> Result < FileData , CryptoError > {
206+ // Make sure to init sodiumoxide library
207+ sodiumoxide:: init ( ) . unwrap ( ) ;
208+
209+ let file = secretbox:: open ( & data. file , & FILE_NONCE , encryption_key)
210+ . map_err ( |_| CryptoError :: DecryptionFailed ) ?;
211+ let thumbnail = match data. thumbnail . as_ref ( ) {
212+ Some ( t) => {
213+ let decrypted = secretbox:: open ( t, & THUMB_NONCE , encryption_key)
214+ . map_err ( |_| CryptoError :: DecryptionFailed ) ?;
215+ Some ( decrypted)
216+ }
217+ None => None ,
218+ } ;
219+
220+ Ok ( FileData { file, thumbnail } )
189221}
190222
191223#[ cfg( test) ]
192224mod test {
193225 use std:: str:: FromStr ;
194226
195- use crate :: api:: ApiBuilder ;
196- use crate :: types:: { BlobId , MessageType } ;
227+ use crate :: {
228+ api:: ApiBuilder ,
229+ types:: { BlobId , MessageType } ,
230+ } ;
197231 use sodiumoxide:: crypto:: box_:: { self , Nonce , PublicKey , SecretKey } ;
198232
199233 use super :: * ;
@@ -336,23 +370,26 @@ mod test {
336370 fn test_encrypt_file_data ( ) {
337371 let file_data = [ 1 , 2 , 3 , 4 ] ;
338372 let thumb_data = [ 5 , 6 , 7 ] ;
373+ let data = FileData {
374+ file : file_data. to_vec ( ) ,
375+ thumbnail : Some ( thumb_data. to_vec ( ) ) ,
376+ } ;
339377
340378 // Encrypt
341- let ( encrypted_file, encrypted_thumb, key) =
342- encrypt_file_data ( & file_data, Some ( & thumb_data) ) ;
343- let encrypted_thumb = encrypted_thumb. expect ( "Thumbnail missing" ) ;
379+ let ( encrypted, key) = encrypt_file_data ( & data) ;
380+ let encrypted_thumb = encrypted. thumbnail . expect ( "Thumbnail missing" ) ;
344381
345382 // Ensure that encrypted data is different from plaintext data
346- assert_ne ! ( encrypted_file , file_data) ;
383+ assert_ne ! ( encrypted . file , file_data) ;
347384 assert_ne ! ( encrypted_thumb, thumb_data) ;
348- assert_eq ! ( encrypted_file . len( ) , file_data. len( ) + secretbox:: MACBYTES ) ;
385+ assert_eq ! ( encrypted . file . len( ) , file_data. len( ) + secretbox:: MACBYTES ) ;
349386 assert_eq ! (
350387 encrypted_thumb. len( ) ,
351388 thumb_data. len( ) + secretbox:: MACBYTES
352389 ) ;
353390
354391 // Test that data can be decrypted
355- let decrypted_file = secretbox:: open ( & encrypted_file , & FILE_NONCE , & key) . unwrap ( ) ;
392+ let decrypted_file = secretbox:: open ( & encrypted . file , & FILE_NONCE , & key) . unwrap ( ) ;
356393 let decrypted_thumb = secretbox:: open ( & encrypted_thumb, & THUMB_NONCE , & key) . unwrap ( ) ;
357394 assert_eq ! ( decrypted_file, & file_data) ;
358395 assert_eq ! ( decrypted_thumb, & thumb_data) ;
@@ -361,11 +398,41 @@ mod test {
361398 #[ test]
362399 fn test_encrypt_file_data_random_key ( ) {
363400 // Ensure that a different key is generated each time
364- let ( _, _, key1) = encrypt_file_data ( & [ 1 , 2 , 3 ] , None ) ;
365- let ( _, _, key2) = encrypt_file_data ( & [ 1 , 2 , 3 ] , None ) ;
366- let ( _, _, key3) = encrypt_file_data ( & [ 1 , 2 , 3 ] , None ) ;
401+ let ( _, key1) = encrypt_file_data ( & FileData {
402+ file : [ 1 , 2 , 3 ] . to_vec ( ) ,
403+ thumbnail : None ,
404+ } ) ;
405+ let ( _, key2) = encrypt_file_data ( & FileData {
406+ file : [ 1 , 2 , 3 ] . to_vec ( ) ,
407+ thumbnail : None ,
408+ } ) ;
409+ let ( _, key3) = encrypt_file_data ( & FileData {
410+ file : [ 1 , 2 , 3 ] . to_vec ( ) ,
411+ thumbnail : None ,
412+ } ) ;
367413 assert_ne ! ( key1, key2) ;
368414 assert_ne ! ( key2, key3) ;
369415 assert_ne ! ( key1, key3) ;
370416 }
417+
418+ #[ test]
419+ fn test_decrypt_file_data ( ) {
420+ let file_data = [ 1 , 2 , 3 , 4 ] ;
421+ let thumb_data = [ 5 , 6 , 7 ] ;
422+ let data = FileData {
423+ file : file_data. to_vec ( ) ,
424+ thumbnail : Some ( thumb_data. to_vec ( ) ) ,
425+ } ;
426+
427+ // Encrypt
428+ let ( encrypted, key) = encrypt_file_data ( & data) ;
429+ assert_ne ! ( encrypted. file, data. file) ;
430+ assert ! ( encrypted. thumbnail. is_some( ) ) ;
431+ assert_ne ! ( encrypted. thumbnail, data. thumbnail) ;
432+
433+ // Decrypt
434+ let decrypted = decrypt_file_data ( & encrypted, & key) . unwrap ( ) ;
435+ assert_eq ! ( decrypted. file, & file_data) ;
436+ assert_eq ! ( decrypted. thumbnail. unwrap( ) , & thumb_data) ;
437+ }
371438}
0 commit comments