Skip to main content

mcf/
base64.rs

1//! Base64 encoding variants.
2
3#![cfg(feature = "base64")]
4
5use base64ct::{
6    Base64Bcrypt, Base64Pbkdf2, Base64ShaCrypt, Base64Unpadded as B64, Encoding as _,
7    Error as B64Error,
8};
9
10#[cfg(feature = "alloc")]
11use alloc::{string::String, vec::Vec};
12
13/// Base64 encoding variants used in various MCF encodings.
14#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
15#[non_exhaustive]
16pub enum Base64 {
17    /// "B64" encoding: standard Base64 without padding, as used by the PHC string format.
18    ///
19    /// ```text
20    /// [A-Z]      [a-z]      [0-9]      +     /
21    /// 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
22    /// ```
23    /// <https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md#b64>
24    B64,
25
26    /// bcrypt encoding.
27    ///
28    /// ```text
29    /// ./         [A-Z]      [a-z]      [0-9]
30    /// 0x2e-0x2f, 0x41-0x5a, 0x61-0x7a, 0x30-0x39
31    /// ```
32    Bcrypt,
33
34    /// `crypt(3)` Base64 encoding.
35    ///
36    /// Used by the following schemes:
37    /// - MD5-Crypt
38    /// - scrypt
39    /// - SHA1-Crypt
40    /// - SHA256-Crypt
41    /// - SHA512-Crypt
42    /// - yescrypt
43    ///
44    /// ```text
45    /// [.-9]      [A-Z]      [a-z]
46    /// 0x2e-0x39, 0x41-0x5a, 0x61-0x7a
47    /// ```
48    Crypt,
49
50    /// PBKDF2 Base64 encoding.
51    ///
52    /// This is a variant of the unpadded standard Base64 with `.` in place of `+`:
53    ///
54    /// ```text
55    /// [A-Z]      [a-z]      [0-9]      .     /
56    /// 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2e, 0x2f
57    /// ```
58    Pbkdf2,
59}
60
61impl Base64 {
62    /// Decode a Base64 string into the provided destination buffer.
63    pub fn decode(self, src: impl AsRef<[u8]>, dst: &mut [u8]) -> Result<&[u8], B64Error> {
64        match self {
65            Self::B64 => B64::decode(src, dst),
66            Self::Bcrypt => Base64Bcrypt::decode(src, dst),
67            Self::Crypt => Base64ShaCrypt::decode(src, dst),
68            Self::Pbkdf2 => Base64Pbkdf2::decode(src, dst),
69        }
70    }
71
72    /// Decode a Base64 string into a byte vector.
73    #[cfg(feature = "alloc")]
74    pub fn decode_vec(self, input: &str) -> Result<Vec<u8>, B64Error> {
75        match self {
76            Self::B64 => B64::decode_vec(input),
77            Self::Bcrypt => Base64Bcrypt::decode_vec(input),
78            Self::Crypt => Base64ShaCrypt::decode_vec(input),
79            Self::Pbkdf2 => Base64Pbkdf2::decode_vec(input),
80        }
81    }
82
83    /// Encode the input byte slice as Base64.
84    ///
85    /// Writes the result into the provided destination slice, returning an
86    /// ASCII-encoded Base64 string value.
87    pub fn encode<'a>(self, src: &[u8], dst: &'a mut [u8]) -> Result<&'a str, B64Error> {
88        match self {
89            Self::B64 => B64::encode(src, dst),
90            Self::Bcrypt => Base64Bcrypt::encode(src, dst),
91            Self::Crypt => Base64ShaCrypt::encode(src, dst),
92            Self::Pbkdf2 => Base64Pbkdf2::encode(src, dst),
93        }
94        .map_err(Into::into)
95    }
96
97    /// Encode input byte slice into a [`String`] containing Base64.
98    ///
99    /// # Panics
100    /// If `input` length is greater than `usize::MAX/4`.
101    #[cfg(feature = "alloc")]
102    pub fn encode_string(self, input: &[u8]) -> String {
103        match self {
104            Self::B64 => B64::encode_string(input),
105            Self::Bcrypt => Base64Bcrypt::encode_string(input),
106            Self::Crypt => Base64ShaCrypt::encode_string(input),
107            Self::Pbkdf2 => Base64Pbkdf2::encode_string(input),
108        }
109    }
110
111    /// Get the length of Base64 produced by encoding the given bytes.
112    pub fn encoded_len(self, bytes: &[u8]) -> usize {
113        match self {
114            Self::B64 => B64::encoded_len(bytes),
115            Self::Bcrypt => Base64Bcrypt::encoded_len(bytes),
116            Self::Crypt => Base64ShaCrypt::encoded_len(bytes),
117            Self::Pbkdf2 => Base64Pbkdf2::encoded_len(bytes),
118        }
119    }
120}