Skip to content

Commit 6d28fba

Browse files
authored
yescrypt: replace Flags with Mode (#696)
As proposed in #694, this replaces the C-derived bitflags with a much simpler `Mode` enum for selecting between the three modes yescrypt offers: classic scrypt, write-once/read-many, and read-write. This eliminates many possible misconfigurations, including trying to use the `YESCRYPT_RW` mode without the appropriate flavor bits set. The flavor bits are now hardcoded. If we reintroduce some fine-grained control over them (we only currently support one flavor, the standard flavor), it would probably be good to map the various possible flavor settings (rounds, gather, simple, sbox) onto enums themselves.
1 parent e22e9c5 commit 6d28fba

File tree

7 files changed

+170
-292
lines changed

7 files changed

+170
-292
lines changed

yescrypt/src/flags.rs

Lines changed: 0 additions & 187 deletions
This file was deleted.

yescrypt/src/lib.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ extern crate alloc;
6060

6161
mod encoding;
6262
mod error;
63-
mod flags;
63+
mod mode;
6464
mod params;
6565
mod pwxform;
6666
mod salsa20;
@@ -69,7 +69,7 @@ mod util;
6969

7070
pub use crate::{
7171
error::{Error, Result},
72-
flags::Flags,
72+
mode::Mode,
7373
params::Params,
7474
};
7575

@@ -173,7 +173,7 @@ pub fn yescrypt_kdf(passwd: &[u8], salt: &[u8], params: &Params, out: &mut [u8])
173173
// Perform conditional pre-hashing
174174
let mut passwd = passwd;
175175
let mut dk = [0u8; 32];
176-
if params.flags.has_rw()
176+
if params.mode.is_rw()
177177
&& params.p >= 1
178178
&& params.n / (params.p as u64) >= 0x100
179179
&& params.n / (params.p as u64) * (params.r as u64) >= 0x20000
@@ -198,11 +198,11 @@ fn yescrypt_kdf_body(
198198
prehash: bool,
199199
out: &mut [u8],
200200
) -> Result<()> {
201-
let flags: Flags = params.flags;
202-
let n: u64 = params.n;
203-
let r: u32 = params.r;
204-
let p: u32 = params.p;
205-
let t: u32 = params.t;
201+
let mode = params.mode;
202+
let n = params.n;
203+
let r = params.r;
204+
let p = params.p;
205+
let t = params.t;
206206

207207
if !((out.len() as u64 <= u32::MAX as u64 * 32)
208208
&& ((r as u64) * (p as u64) < (1 << 30) as u64)
@@ -219,7 +219,7 @@ fn yescrypt_kdf_body(
219219

220220
let mut passwd = passwd;
221221
let mut sha256 = [0u8; 32];
222-
if !flags.is_empty() {
222+
if !mode.is_classic() {
223223
sha256 = util::hmac_sha256(
224224
if prehash {
225225
b"yescrypt-prehash"
@@ -234,13 +234,13 @@ fn yescrypt_kdf_body(
234234
// 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen)
235235
pbkdf2::pbkdf2_hmac::<Sha256>(passwd, salt, 1, util::cast_slice_mut(&mut b));
236236

237-
if !flags.is_empty() {
237+
if !mode.is_classic() {
238238
sha256.copy_from_slice(util::cast_slice(&b[..8]));
239239
passwd = &sha256;
240240
}
241241

242-
if flags.has_rw() {
243-
smix::smix(&mut b, r, n, p, t, flags, &mut v, &mut xy, &mut sha256);
242+
if mode.is_rw() {
243+
smix::smix(&mut b, r, n, p, t, mode, &mut v, &mut xy, &mut sha256);
244244
passwd = &sha256;
245245
} else {
246246
// 2: for i = 0 to p - 1 do
@@ -252,7 +252,7 @@ fn yescrypt_kdf_body(
252252
n,
253253
1,
254254
t,
255-
flags,
255+
mode,
256256
&mut v,
257257
&mut xy,
258258
&mut [],
@@ -261,7 +261,7 @@ fn yescrypt_kdf_body(
261261
}
262262

263263
let mut dk = [0u8; 32];
264-
if !flags.is_empty() && out.len() < 32 {
264+
if !mode.is_classic() && out.len() < 32 {
265265
pbkdf2::pbkdf2_hmac::<Sha256>(passwd, util::cast_slice(&b), 1, &mut dk);
266266
}
267267

@@ -273,8 +273,8 @@ fn yescrypt_kdf_body(
273273
// SCRAM (RFC 5802), so that an extension of SCRAM (with the steps so
274274
// far in place of SCRAM's use of PBKDF2 and with SHA-256 in place of
275275
// SCRAM's use of SHA-1) would be usable with yescrypt hashes.
276-
if !flags.is_empty() && !prehash {
277-
let dkp = if !flags.is_empty() && out.len() < 32 {
276+
if !mode.is_classic() && !prehash {
277+
let dkp = if !mode.is_classic() && out.len() < 32 {
278278
&mut dk
279279
} else {
280280
&mut *out

yescrypt/src/mode.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
//! yescrypt modes.
2+
3+
use crate::{Error, Result};
4+
5+
// Bits which represent the "flavor" of yescrypt when using `Mode::Rw`
6+
const ROUNDS_6: u32 = 0b000001;
7+
const GATHER_4: u32 = 0b000100;
8+
const SIMPLE_2: u32 = 0b001000;
9+
const SBOX_12K: u32 = 0b100000;
10+
11+
// Bits representing the RW "flavor"
12+
// TODO(tarcieri): support other flavors of yescrypt?
13+
const RW_FLAVOR: u32 = 2 | ROUNDS_6 | GATHER_4 | SIMPLE_2 | SBOX_12K;
14+
15+
/// yescrypt modes
16+
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
17+
#[repr(u32)]
18+
pub enum Mode {
19+
/// classic scrypt
20+
Classic = 0,
21+
22+
/// write-once/read-many: conservative enhancement of classic scrypt
23+
Worm = 1,
24+
25+
/// yescrypt’s native mode: read-write
26+
#[default]
27+
Rw = RW_FLAVOR,
28+
}
29+
30+
impl Mode {
31+
/// Is the mode scrypt classic?
32+
pub fn is_classic(self) -> bool {
33+
self == Self::Classic
34+
}
35+
36+
/// Is the mode write-once/read-many?
37+
pub fn is_worm(self) -> bool {
38+
self == Self::Worm
39+
}
40+
41+
/// Is the mode the yescrypt native read-write mode? (default)
42+
pub fn is_rw(self) -> bool {
43+
self == Self::Rw
44+
}
45+
}
46+
47+
impl TryFrom<u32> for Mode {
48+
type Error = Error;
49+
50+
fn try_from(value: u32) -> Result<Self> {
51+
match value {
52+
0 => Ok(Mode::Classic),
53+
1 => Ok(Mode::Worm),
54+
RW_FLAVOR => Ok(Mode::Rw),
55+
_ => Err(Error::Params),
56+
}
57+
}
58+
}
59+
60+
impl From<Mode> for u32 {
61+
fn from(mode: Mode) -> u32 {
62+
mode as u32
63+
}
64+
}
65+
66+
#[cfg(test)]
67+
mod tests {
68+
use super::Mode;
69+
70+
#[test]
71+
fn flavor() {
72+
assert_eq!(0u32, Mode::Classic.into());
73+
assert_eq!(1u32, Mode::Worm.into());
74+
assert_eq!(0b101111u32, Mode::default().into());
75+
}
76+
77+
#[test]
78+
fn try_from() {
79+
assert_eq!(Mode::try_from(0).unwrap(), Mode::Classic);
80+
assert_eq!(Mode::try_from(1).unwrap(), Mode::Worm);
81+
assert_eq!(Mode::try_from(0b101111).unwrap(), Mode::Rw);
82+
}
83+
}

0 commit comments

Comments
 (0)