base64ct/alphabet/
shacrypt.rs

1//! `crypt(3)` Base64 encoding for sha* family.
2
3use super::{Alphabet, DecodeStep, EncodeStep};
4
5/// `crypt(3)` Base64 encoding.
6///
7/// This is the standard Base64 encoding used by password hashes for the following schemes:
8/// - MD5-Crypt
9/// - scrypt
10/// - SHA1-Crypt
11/// - SHA256-Crypt
12/// - SHA512-Crypt
13/// - yescrypt
14///
15/// ```text
16/// [.-9]      [A-Z]      [a-z]
17/// 0x2e-0x39, 0x41-0x5a, 0x61-0x7a
18/// ```
19#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
20pub struct Base64ShaCrypt;
21
22impl Alphabet for Base64ShaCrypt {
23    const BASE: u8 = b'.';
24
25    const DECODER: &'static [DecodeStep] = &[
26        DecodeStep::Range(b'.'..=b'9', -45),
27        DecodeStep::Range(b'A'..=b'Z', -52),
28        DecodeStep::Range(b'a'..=b'z', -58),
29    ];
30
31    const ENCODER: &'static [EncodeStep] =
32        &[EncodeStep::Apply(b'9', 7), EncodeStep::Apply(b'Z', 6)];
33
34    const PADDED: bool = false;
35
36    type Unpadded = Self;
37
38    #[inline(always)]
39    fn decode_3bytes(src: &[u8], dst: &mut [u8]) -> i16 {
40        debug_assert_eq!(src.len(), 4);
41        debug_assert!(dst.len() >= 3, "dst too short: {}", dst.len());
42
43        let c0 = Self::decode_6bits(src[0]);
44        let c1 = Self::decode_6bits(src[1]);
45        let c2 = Self::decode_6bits(src[2]);
46        let c3 = Self::decode_6bits(src[3]);
47
48        dst[0] = (c0 | ((c1 & 0x3) << 6)) as u8;
49        dst[1] = ((c1 >> 2) | ((c2 & 0xF) << 4)) as u8;
50        dst[2] = ((c2 >> 4) | (c3 << 2)) as u8;
51
52        ((c0 | c1 | c2 | c3) >> 8) & 1
53    }
54
55    #[inline(always)]
56    fn encode_3bytes(src: &[u8], dst: &mut [u8]) {
57        debug_assert_eq!(src.len(), 3);
58        debug_assert!(dst.len() >= 4, "dst too short: {}", dst.len());
59
60        let b0 = src[0] as i16;
61        let b1 = src[1] as i16;
62        let b2 = src[2] as i16;
63
64        dst[0] = Self::encode_6bits(b0 & 63);
65        dst[1] = Self::encode_6bits(((b1 << 2) | (b0 >> 6)) & 63);
66        dst[2] = Self::encode_6bits(((b2 << 4) | (b1 >> 4)) & 63);
67        dst[3] = Self::encode_6bits(b2 >> 2);
68    }
69}