@@ -161,14 +161,31 @@ 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+ /// Raw unencrypted bytes of a file and optionally a thumbnail.
165+ ///
166+ /// This struct is used as a parameter type for [`encrypt_file_data`] and
167+ /// returned by [`decrypt_file_data`].
168+ #[ derive( Clone ) ]
169+ pub struct FileData {
170+ pub file : Vec < u8 > ,
171+ pub thumbnail : Option < Vec < u8 > > ,
172+ }
173+
174+ /// Encrypted bytes of a file and optionally a thumbnail.
175+ ///
176+ /// This struct is used as a parameter type for [`decrypt_file_data`] and
177+ /// returned by [`encrypt_file_data`].
178+ #[ derive( Clone ) ]
179+ pub struct EncryptedFileData {
180+ pub file : Vec < u8 > ,
181+ pub thumbnail : Option < Vec < u8 > > ,
182+ }
183+
164184/// Encrypt file data and an optional thumbnail using a randomly generated
165185/// symmetric key.
166186///
167187/// 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 ) {
188+ pub fn encrypt_file_data ( data : & FileData ) -> ( EncryptedFileData , Key ) {
172189 // Make sure to init sodiumoxide library
173190 sodiumoxide:: init ( ) . unwrap ( ) ;
174191
@@ -177,23 +194,48 @@ pub fn encrypt_file_data(
177194
178195 // Encrypt data
179196 // 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) ) ;
197+ let file = secretbox:: seal ( & data. file , & FILE_NONCE , & key) ;
198+ let thumbnail = data
199+ . thumbnail
200+ . as_ref ( )
201+ . map ( |t| secretbox:: seal ( t, & THUMB_NONCE , & key) ) ;
182202
183- ( encrypted_file , encrypted_thumb , key)
203+ ( EncryptedFileData { file , thumbnail } , key)
184204}
185205
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 )
206+ /// Decrypt file data and optional thumbnail data with the provided symmetric
207+ /// key.
208+ ///
209+ /// Return the decrypted bytes.
210+ pub fn decrypt_file_data (
211+ data : & EncryptedFileData ,
212+ encryption_key : & Key ,
213+ ) -> Result < FileData , CryptoError > {
214+ // Make sure to init sodiumoxide library
215+ sodiumoxide:: init ( ) . unwrap ( ) ;
216+
217+ let file = secretbox:: open ( & data. file , & FILE_NONCE , encryption_key)
218+ . map_err ( |_| CryptoError :: DecryptionFailed ) ?;
219+ let thumbnail = match data. thumbnail . as_ref ( ) {
220+ Some ( t) => {
221+ let decrypted = secretbox:: open ( t, & THUMB_NONCE , encryption_key)
222+ . map_err ( |_| CryptoError :: DecryptionFailed ) ?;
223+ Some ( decrypted)
224+ }
225+ None => None ,
226+ } ;
227+
228+ Ok ( FileData { file, thumbnail } )
189229}
190230
191231#[ cfg( test) ]
192232mod test {
193233 use std:: str:: FromStr ;
194234
195- use crate :: api:: ApiBuilder ;
196- use crate :: types:: { BlobId , MessageType } ;
235+ use crate :: {
236+ api:: ApiBuilder ,
237+ types:: { BlobId , MessageType } ,
238+ } ;
197239 use sodiumoxide:: crypto:: box_:: { self , Nonce , PublicKey , SecretKey } ;
198240
199241 use super :: * ;
@@ -336,23 +378,26 @@ mod test {
336378 fn test_encrypt_file_data ( ) {
337379 let file_data = [ 1 , 2 , 3 , 4 ] ;
338380 let thumb_data = [ 5 , 6 , 7 ] ;
381+ let data = FileData {
382+ file : file_data. to_vec ( ) ,
383+ thumbnail : Some ( thumb_data. to_vec ( ) ) ,
384+ } ;
339385
340386 // 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" ) ;
387+ let ( encrypted, key) = encrypt_file_data ( & data) ;
388+ let encrypted_thumb = encrypted. thumbnail . expect ( "Thumbnail missing" ) ;
344389
345390 // Ensure that encrypted data is different from plaintext data
346- assert_ne ! ( encrypted_file , file_data) ;
391+ assert_ne ! ( encrypted . file , file_data) ;
347392 assert_ne ! ( encrypted_thumb, thumb_data) ;
348- assert_eq ! ( encrypted_file . len( ) , file_data. len( ) + secretbox:: MACBYTES ) ;
393+ assert_eq ! ( encrypted . file . len( ) , file_data. len( ) + secretbox:: MACBYTES ) ;
349394 assert_eq ! (
350395 encrypted_thumb. len( ) ,
351396 thumb_data. len( ) + secretbox:: MACBYTES
352397 ) ;
353398
354399 // Test that data can be decrypted
355- let decrypted_file = secretbox:: open ( & encrypted_file , & FILE_NONCE , & key) . unwrap ( ) ;
400+ let decrypted_file = secretbox:: open ( & encrypted . file , & FILE_NONCE , & key) . unwrap ( ) ;
356401 let decrypted_thumb = secretbox:: open ( & encrypted_thumb, & THUMB_NONCE , & key) . unwrap ( ) ;
357402 assert_eq ! ( decrypted_file, & file_data) ;
358403 assert_eq ! ( decrypted_thumb, & thumb_data) ;
@@ -361,11 +406,41 @@ mod test {
361406 #[ test]
362407 fn test_encrypt_file_data_random_key ( ) {
363408 // 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 ) ;
409+ let ( _, key1) = encrypt_file_data ( & FileData {
410+ file : [ 1 , 2 , 3 ] . to_vec ( ) ,
411+ thumbnail : None ,
412+ } ) ;
413+ let ( _, key2) = encrypt_file_data ( & FileData {
414+ file : [ 1 , 2 , 3 ] . to_vec ( ) ,
415+ thumbnail : None ,
416+ } ) ;
417+ let ( _, key3) = encrypt_file_data ( & FileData {
418+ file : [ 1 , 2 , 3 ] . to_vec ( ) ,
419+ thumbnail : None ,
420+ } ) ;
367421 assert_ne ! ( key1, key2) ;
368422 assert_ne ! ( key2, key3) ;
369423 assert_ne ! ( key1, key3) ;
370424 }
425+
426+ #[ test]
427+ fn test_decrypt_file_data ( ) {
428+ let file_data = [ 1 , 2 , 3 , 4 ] ;
429+ let thumb_data = [ 5 , 6 , 7 ] ;
430+ let data = FileData {
431+ file : file_data. to_vec ( ) ,
432+ thumbnail : Some ( thumb_data. to_vec ( ) ) ,
433+ } ;
434+
435+ // Encrypt
436+ let ( encrypted, key) = encrypt_file_data ( & data) ;
437+ assert_ne ! ( encrypted. file, data. file) ;
438+ assert ! ( encrypted. thumbnail. is_some( ) ) ;
439+ assert_ne ! ( encrypted. thumbnail, data. thumbnail) ;
440+
441+ // Decrypt
442+ let decrypted = decrypt_file_data ( & encrypted, & key) . unwrap ( ) ;
443+ assert_eq ! ( decrypted. file, & file_data) ;
444+ assert_eq ! ( decrypted. thumbnail. unwrap( ) , & thumb_data) ;
445+ }
371446}
0 commit comments