@@ -6,6 +6,7 @@ use crate::low_level::elgamal::{ElGamal, ELGAMAL_LENGTH};
66use derive_more:: { Deref , From } ;
77use rand_core:: { CryptoRng , RngCore } ;
88use serde:: { Deserialize , Deserializer , Serialize , Serializer } ;
9+ use std:: io:: { Error , ErrorKind } ;
910
1011/// A pseudonym (in the background, this is a [`GroupElement`]) that can be used to identify a user
1112/// within a specific context, which can be encrypted, rekeyed and reshuffled.
@@ -196,6 +197,115 @@ pub trait Encryptable {
196197 fn as_bytes ( & self ) -> Option < [ u8 ; 16 ] > {
197198 self . value ( ) . encode_lizard ( )
198199 }
200+
201+ /// Encodes an arbitrary byte array into one or more Encryptables
202+ /// Uses PKCS#7 style padding where the padding byte value equals the number of padding bytes
203+ fn from_bytes_padded ( data : & [ u8 ] ) -> Vec < Self >
204+ where
205+ Self : Sized ,
206+ {
207+ if data. is_empty ( ) {
208+ return vec ! [ ] ;
209+ }
210+
211+ let mut result = Vec :: new ( ) ;
212+
213+ // Process all full blocks, that do not need padding
214+ // Initialize the last block with the padding value
215+ // Copy remaining data if there is any
216+ for i in 0 ..( data. len ( ) / 16 ) {
217+ let start = i * 16 ;
218+ // This is safe, as we know that the slice is 16 bytes long
219+ result. push ( Self :: from_bytes (
220+ & data[ start..start + 16 ] . try_into ( ) . unwrap ( ) ,
221+ ) ) ;
222+ }
223+
224+ let remaining = data. len ( ) % 16 ;
225+ let padding_byte = ( 16 - remaining) as u8 ;
226+
227+ let mut last_block = [ padding_byte; 16 ] ;
228+
229+ if remaining > 0 {
230+ last_block[ ..remaining] . copy_from_slice ( & data[ data. len ( ) - remaining..] ) ;
231+ }
232+
233+ result. push ( Self :: from_bytes ( & last_block) ) ;
234+
235+ result
236+ }
237+
238+ /// Encodes an arbitrary string into one or more Encrtypb
239+ /// Uses PKCS#7 style padding where the padding byte value equals the number of padding bytes
240+ fn from_string_padded ( text : & str ) -> Vec < Self >
241+ where
242+ Self : Sized ,
243+ {
244+ // Convert string to bytes and pass to the byte encoding function
245+ Self :: from_bytes_padded ( text. as_bytes ( ) )
246+ }
247+
248+ /// Decodes encryptables back to the original string
249+ /// Returns an error if the decoded bytes are not valid UTF-8
250+ fn to_string_padded ( encryptables : & [ Self ] ) -> Result < String , Error >
251+ where
252+ Self : Sized ,
253+ {
254+ let bytes = Self :: to_bytes_padded ( encryptables) ?;
255+ String :: from_utf8 ( bytes) . map_err ( |e| Error :: new ( ErrorKind :: InvalidData , e. to_string ( ) ) )
256+ }
257+
258+ /// Decodes encryptables back to the original byte array
259+ fn to_bytes_padded ( encryptables : & [ Self ] ) -> Result < Vec < u8 > , Error >
260+ where
261+ Self : Sized ,
262+ {
263+ if encryptables. is_empty ( ) {
264+ return Err ( Error :: new (
265+ ErrorKind :: InvalidInput ,
266+ "No encryptables provided" ,
267+ ) ) ;
268+ }
269+
270+ let mut result = Vec :: with_capacity ( encryptables. len ( ) * 16 ) ;
271+
272+ // Copy over all blocks except the last one
273+ // Validate padding and copy the data part of the last block
274+ // Copy over all blocks except the last one
275+ for data_point in & encryptables[ ..encryptables. len ( ) - 1 ] {
276+ let block = data_point. as_bytes ( ) . ok_or ( Error :: new (
277+ ErrorKind :: InvalidData ,
278+ "Encryptable conversion to bytes failed" ,
279+ ) ) ?;
280+ result. extend_from_slice ( & block) ;
281+ }
282+
283+ // This is safe, we know that there is at least one element in the slice
284+ let last_block = encryptables. last ( ) . unwrap ( ) . as_bytes ( ) . ok_or ( Error :: new (
285+ ErrorKind :: InvalidData ,
286+ "Last encryptables conversion to bytes failed" ,
287+ ) ) ?;
288+
289+ let padding_byte = last_block[ 15 ] ;
290+
291+ if padding_byte == 0 || padding_byte > 16 {
292+ return Err ( Error :: new ( ErrorKind :: InvalidData , "Invalid padding" ) ) ;
293+ }
294+
295+ if last_block[ 16 - padding_byte as usize ..]
296+ . iter ( )
297+ . any ( |& b| b != padding_byte)
298+ {
299+ return Err ( Error :: new ( ErrorKind :: InvalidData , "Inconsistent padding" ) ) ;
300+ }
301+
302+ // Add the data part of the last block
303+ let data_bytes = 16 - padding_byte as usize ;
304+ result. extend_from_slice ( & last_block[ ..data_bytes] ) ;
305+
306+ Ok ( result)
307+ }
308+
199309 /// Create multiple messages from a byte array.
200310 /// TODO: remove this method, as it cannot handle data that is not a multiple of 16 bytes and padding should generally not belong in this library.
201311 #[ deprecated]
0 commit comments