@@ -81,7 +81,7 @@ use cipher::{
8181 Block , BlockSizeUser , IvSizeUser , KeyIvInit , KeySizeUser , StreamCipherClosure ,
8282 StreamCipherCore , StreamCipherCoreWrapper , StreamCipherSeekCore ,
8383 array:: { Array , ArraySize , typenum:: Unsigned } ,
84- consts:: { U4 , U6 , U8 , U10 , U24 , U32 , U64 } ,
84+ consts:: { U4 , U6 , U8 , U10 , U16 , U24 , U32 , U64 } ,
8585} ;
8686use core:: marker:: PhantomData ;
8787
@@ -105,8 +105,19 @@ pub type Salsa12 = StreamCipherCoreWrapper<SalsaCore<U6, U32>>;
105105/// (20 rounds; **recommended**)
106106pub type Salsa20 = StreamCipherCoreWrapper < SalsaCore < U10 , U32 > > ;
107107
108+ /// Salsa20/20 stream cipher, using 16-byte keys (*not recommended*)
109+ ///
110+ /// # ⚠️ Security warning
111+ ///
112+ /// Using Salsa20 with keys shorter than 32 bytes is
113+ /// [**explicitly discouraged** by its creator][0]. It is included for
114+ /// compatibility with systems that use these weaker keys.
115+ ///
116+ /// [0]: https://cr.yp.to/snuffle/keysizes.pdf
117+ pub type Salsa20_16 = StreamCipherCoreWrapper < SalsaCore < U10 , U16 > > ;
118+
108119/// Key type used by all Salsa variants and [`XSalsa20`].
109- pub type Key < KeySize > = Array < u8 , KeySize > ;
120+ pub type Key < KeySize = U32 > = Array < u8 , KeySize > ;
110121
111122/// Nonce type used by all Salsa variants.
112123pub type Nonce = Array < u8 , U8 > ;
@@ -117,8 +128,11 @@ pub type XNonce = Array<u8, U24>;
117128/// Number of 32-bit words in the Salsa20 state
118129const STATE_WORDS : usize = 16 ;
119130
120- /// State initialization constant ("expand 32-byte k")
121- const CONSTANTS : [ u32 ; 4 ] = [ 0x6170_7865 , 0x3320_646e , 0x7962_2d32 , 0x6b20_6574 ] ;
131+ /// State initialization constant for 32-byte keys ("expand 32-byte k")
132+ const CONSTANTS_32 : [ u32 ; 4 ] = [ 0x6170_7865 , 0x3320_646e , 0x7962_2d32 , 0x6b20_6574 ] ;
133+
134+ /// State initialization constant for 16-byte keys ("expand 16-byte k")
135+ const CONSTANTS_16 : [ u32 ; 4 ] = [ 0x6170_7865 , 0x3120_646e , 0x7962_2d36 , 0x6b20_6574 ] ;
122136
123137/// The Salsa20 core function.
124138pub struct SalsaCore < R : Unsigned , KeySize = U32 > {
@@ -159,31 +173,84 @@ impl<R: Unsigned, KeySize> BlockSizeUser for SalsaCore<R, KeySize> {
159173 type BlockSize = U64 ;
160174}
161175
162- impl < R : Unsigned > KeyIvInit for SalsaCore < R , U32 >
163- {
176+ impl < R : Unsigned > KeyIvInit for SalsaCore < R , U16 > {
177+ /// Create a new Salsa core using a _weaker_ 16-byte key.
178+ ///
179+ /// # ⚠️ Security warning
180+ ///
181+ /// Using Salsa20 with keys shorter than 32 bytes is
182+ /// [**explicitly discouraged** by its creator][0]. It is included for
183+ /// compatibility with systems that use these weaker keys.
184+ ///
185+ /// [0]: https://cr.yp.to/snuffle/keysizes.pdf
186+ fn new ( key : & Key < U16 > , iv : & Nonce ) -> Self {
187+ let mut state = [ 0u32 ; STATE_WORDS ] ;
188+ state[ 0 ] = CONSTANTS_16 [ 0 ] ;
189+
190+ for ( i, chunk) in key. chunks ( 4 ) . enumerate ( ) {
191+ state[ 1 + i] = u32:: from_le_bytes ( chunk. try_into ( ) . unwrap ( ) ) ;
192+ }
193+
194+ state[ 5 ] = CONSTANTS_16 [ 1 ] ;
195+
196+ for ( i, chunk) in iv. chunks ( 4 ) . enumerate ( ) {
197+ state[ 6 + i] = u32:: from_le_bytes ( chunk. try_into ( ) . unwrap ( ) ) ;
198+ }
199+
200+ state[ 8 ] = 0 ;
201+ state[ 9 ] = 0 ;
202+ state[ 10 ] = CONSTANTS_16 [ 2 ] ;
203+
204+ for ( i, chunk) in key. chunks ( 4 ) . enumerate ( ) {
205+ state[ 11 + i] = u32:: from_le_bytes ( chunk. try_into ( ) . unwrap ( ) ) ;
206+ }
207+
208+ state[ 15 ] = CONSTANTS_16 [ 3 ] ;
209+
210+ cfg_if ! {
211+ if #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ] {
212+ state = [
213+ state[ 0 ] , state[ 5 ] , state[ 10 ] , state[ 15 ] ,
214+ state[ 4 ] , state[ 9 ] , state[ 14 ] , state[ 3 ] ,
215+ state[ 8 ] , state[ 13 ] , state[ 2 ] , state[ 7 ] ,
216+ state[ 12 ] , state[ 1 ] , state[ 6 ] , state[ 11 ] ,
217+ ] ;
218+ }
219+ }
220+
221+ Self {
222+ state,
223+ rounds : PhantomData ,
224+ key_size : PhantomData ,
225+ }
226+ }
227+ }
228+
229+ impl < R : Unsigned > KeyIvInit for SalsaCore < R , U32 > {
230+ /// Create a new Salsa core using a 32-byte key.
164231 fn new ( key : & Key < U32 > , iv : & Nonce ) -> Self {
165232 let mut state = [ 0u32 ; STATE_WORDS ] ;
166- state[ 0 ] = CONSTANTS [ 0 ] ;
233+ state[ 0 ] = CONSTANTS_32 [ 0 ] ;
167234
168235 for ( i, chunk) in key[ ..16 ] . chunks ( 4 ) . enumerate ( ) {
169236 state[ 1 + i] = u32:: from_le_bytes ( chunk. try_into ( ) . unwrap ( ) ) ;
170237 }
171238
172- state[ 5 ] = CONSTANTS [ 1 ] ;
239+ state[ 5 ] = CONSTANTS_32 [ 1 ] ;
173240
174241 for ( i, chunk) in iv. chunks ( 4 ) . enumerate ( ) {
175242 state[ 6 + i] = u32:: from_le_bytes ( chunk. try_into ( ) . unwrap ( ) ) ;
176243 }
177244
178245 state[ 8 ] = 0 ;
179246 state[ 9 ] = 0 ;
180- state[ 10 ] = CONSTANTS [ 2 ] ;
247+ state[ 10 ] = CONSTANTS_32 [ 2 ] ;
181248
182249 for ( i, chunk) in key[ 16 ..] . chunks ( 4 ) . enumerate ( ) {
183250 state[ 11 + i] = u32:: from_le_bytes ( chunk. try_into ( ) . unwrap ( ) ) ;
184251 }
185252
186- state[ 15 ] = CONSTANTS [ 3 ] ;
253+ state[ 15 ] = CONSTANTS_32 [ 3 ] ;
187254
188255 cfg_if ! {
189256 if #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ] {
0 commit comments