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}