@@ -79,7 +79,7 @@ use cipher::{
7979 Block , BlockSizeUser , IvSizeUser , KeyIvInit , KeySizeUser , StreamCipherClosure ,
8080 StreamCipherCore , StreamCipherCoreWrapper , StreamCipherSeekCore ,
8181 array:: { Array , ArraySize , typenum:: Unsigned } ,
82- consts:: { U4 , U6 , U8 , U10 , U24 , U32 , U64 } ,
82+ consts:: { U4 , U6 , U8 , U10 , U16 , U24 , U32 , U64 } ,
8383} ;
8484use core:: marker:: PhantomData ;
8585
@@ -103,8 +103,19 @@ pub type Salsa12 = StreamCipherCoreWrapper<SalsaCore<U6, U32>>;
103103/// (20 rounds; **recommended**)
104104pub type Salsa20 = StreamCipherCoreWrapper < SalsaCore < U10 , U32 > > ;
105105
106+ /// Salsa20/20 stream cipher, using 16-byte keys (*not recommended*)
107+ ///
108+ /// # ⚠️ Security warning
109+ ///
110+ /// Using Salsa20 with keys shorter than 32 bytes is
111+ /// [**explicitly discouraged** by its creator][0]. It is included for
112+ /// compatibility with systems that use these weaker keys.
113+ ///
114+ /// [0]: https://cr.yp.to/snuffle/keysizes.pdf
115+ pub type Salsa20_16 = StreamCipherCoreWrapper < SalsaCore < U10 , U16 > > ;
116+
106117/// Key type used by all Salsa variants and [`XSalsa20`].
107- pub type Key < KeySize > = Array < u8 , KeySize > ;
118+ pub type Key < KeySize = U32 > = Array < u8 , KeySize > ;
108119
109120/// Nonce type used by all Salsa variants.
110121pub type Nonce = Array < u8 , U8 > ;
@@ -115,8 +126,11 @@ pub type XNonce = Array<u8, U24>;
115126/// Number of 32-bit words in the Salsa20 state
116127const STATE_WORDS : usize = 16 ;
117128
118- /// State initialization constant ("expand 32-byte k")
119- const CONSTANTS : [ u32 ; 4 ] = [ 0x6170_7865 , 0x3320_646e , 0x7962_2d32 , 0x6b20_6574 ] ;
129+ /// State initialization constant for 32-byte keys ("expand 32-byte k")
130+ const CONSTANTS_32 : [ u32 ; 4 ] = [ 0x6170_7865 , 0x3320_646e , 0x7962_2d32 , 0x6b20_6574 ] ;
131+
132+ /// State initialization constant for 16-byte keys ("expand 16-byte k")
133+ const CONSTANTS_16 : [ u32 ; 4 ] = [ 0x6170_7865 , 0x3120_646e , 0x7962_2d36 , 0x6b20_6574 ] ;
120134
121135/// The Salsa20 core function.
122136pub struct SalsaCore < R : Unsigned , KeySize = U32 > {
@@ -157,31 +171,84 @@ impl<R: Unsigned, KeySize> BlockSizeUser for SalsaCore<R, KeySize> {
157171 type BlockSize = U64 ;
158172}
159173
160- impl < R : Unsigned > KeyIvInit for SalsaCore < R , U32 >
161- {
174+ impl < R : Unsigned > KeyIvInit for SalsaCore < R , U16 > {
175+ /// Create a new Salsa core using a _weaker_ 16-byte key.
176+ ///
177+ /// # ⚠️ Security warning
178+ ///
179+ /// Using Salsa20 with keys shorter than 32 bytes is
180+ /// [**explicitly discouraged** by its creator][0]. It is included for
181+ /// compatibility with systems that use these weaker keys.
182+ ///
183+ /// [0]: https://cr.yp.to/snuffle/keysizes.pdf
184+ fn new ( key : & Key < U16 > , iv : & Nonce ) -> Self {
185+ let mut state = [ 0u32 ; STATE_WORDS ] ;
186+ state[ 0 ] = CONSTANTS_16 [ 0 ] ;
187+
188+ for ( i, chunk) in key. chunks ( 4 ) . enumerate ( ) {
189+ state[ 1 + i] = u32:: from_le_bytes ( chunk. try_into ( ) . unwrap ( ) ) ;
190+ }
191+
192+ state[ 5 ] = CONSTANTS_16 [ 1 ] ;
193+
194+ for ( i, chunk) in iv. chunks ( 4 ) . enumerate ( ) {
195+ state[ 6 + i] = u32:: from_le_bytes ( chunk. try_into ( ) . unwrap ( ) ) ;
196+ }
197+
198+ state[ 8 ] = 0 ;
199+ state[ 9 ] = 0 ;
200+ state[ 10 ] = CONSTANTS_16 [ 2 ] ;
201+
202+ for ( i, chunk) in key. chunks ( 4 ) . enumerate ( ) {
203+ state[ 11 + i] = u32:: from_le_bytes ( chunk. try_into ( ) . unwrap ( ) ) ;
204+ }
205+
206+ state[ 15 ] = CONSTANTS_16 [ 3 ] ;
207+
208+ cfg_if ! {
209+ if #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ] {
210+ state = [
211+ state[ 0 ] , state[ 5 ] , state[ 10 ] , state[ 15 ] ,
212+ state[ 4 ] , state[ 9 ] , state[ 14 ] , state[ 3 ] ,
213+ state[ 8 ] , state[ 13 ] , state[ 2 ] , state[ 7 ] ,
214+ state[ 12 ] , state[ 1 ] , state[ 6 ] , state[ 11 ] ,
215+ ] ;
216+ }
217+ }
218+
219+ Self {
220+ state,
221+ rounds : PhantomData ,
222+ key_size : PhantomData ,
223+ }
224+ }
225+ }
226+
227+ impl < R : Unsigned > KeyIvInit for SalsaCore < R , U32 > {
228+ /// Create a new Salsa core using a 32-byte key.
162229 fn new ( key : & Key < U32 > , iv : & Nonce ) -> Self {
163230 let mut state = [ 0u32 ; STATE_WORDS ] ;
164- state[ 0 ] = CONSTANTS [ 0 ] ;
231+ state[ 0 ] = CONSTANTS_32 [ 0 ] ;
165232
166233 for ( i, chunk) in key[ ..16 ] . chunks ( 4 ) . enumerate ( ) {
167234 state[ 1 + i] = u32:: from_le_bytes ( chunk. try_into ( ) . unwrap ( ) ) ;
168235 }
169236
170- state[ 5 ] = CONSTANTS [ 1 ] ;
237+ state[ 5 ] = CONSTANTS_32 [ 1 ] ;
171238
172239 for ( i, chunk) in iv. chunks ( 4 ) . enumerate ( ) {
173240 state[ 6 + i] = u32:: from_le_bytes ( chunk. try_into ( ) . unwrap ( ) ) ;
174241 }
175242
176243 state[ 8 ] = 0 ;
177244 state[ 9 ] = 0 ;
178- state[ 10 ] = CONSTANTS [ 2 ] ;
245+ state[ 10 ] = CONSTANTS_32 [ 2 ] ;
179246
180247 for ( i, chunk) in key[ 16 ..] . chunks ( 4 ) . enumerate ( ) {
181248 state[ 11 + i] = u32:: from_le_bytes ( chunk. try_into ( ) . unwrap ( ) ) ;
182249 }
183250
184- state[ 15 ] = CONSTANTS [ 3 ] ;
251+ state[ 15 ] = CONSTANTS_32 [ 3 ] ;
185252
186253 Self {
187254 state,
0 commit comments