1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
6 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
7)]
8#![forbid(unsafe_code)]
9
10#[cfg(all(feature = "alloc", feature = "pbes2"))]
22extern crate alloc;
23
24mod error;
25
26pub mod pbes1;
27pub mod pbes2;
28
29pub use crate::error::{Error, Result};
30pub use der::{self, asn1::ObjectIdentifier};
31pub use spki::AlgorithmIdentifierRef;
32
33use der::{
34 Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, Writer,
35};
36
37#[cfg(feature = "pbes2")]
38pub use scrypt;
39
40#[cfg(all(feature = "alloc", feature = "pbes2"))]
41use alloc::vec::Vec;
42
43#[derive(Clone, Debug, Eq, PartialEq)]
53#[non_exhaustive]
54#[allow(clippy::large_enum_variant)]
55pub enum EncryptionScheme {
56 Pbes1(pbes1::Algorithm),
60
61 Pbes2(pbes2::Parameters),
65}
66
67impl EncryptionScheme {
68 #[cfg(all(feature = "pbes2", feature = "getrandom"))]
74 #[must_use]
75 #[track_caller]
76 pub fn generate() -> Self {
77 Self::Pbes2(pbes2::Parameters::generate())
78 }
79
80 #[cfg(all(feature = "alloc", feature = "pbes2"))]
88 pub fn decrypt(&self, password: impl AsRef<[u8]>, ciphertext: &[u8]) -> Result<Vec<u8>> {
89 match self {
90 Self::Pbes2(params) => params.decrypt(password, ciphertext),
91 Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
92 }
93 }
94
95 #[cfg(feature = "pbes2")]
103 pub fn decrypt_in_place<'a>(
104 &self,
105 password: impl AsRef<[u8]>,
106 buffer: &'a mut [u8],
107 ) -> Result<&'a [u8]> {
108 match self {
109 Self::Pbes2(params) => params.decrypt_in_place(password, buffer),
110 Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
111 }
112 }
113
114 #[cfg(all(feature = "alloc", feature = "pbes2"))]
121 pub fn encrypt(&self, password: impl AsRef<[u8]>, plaintext: &[u8]) -> Result<Vec<u8>> {
122 match self {
123 Self::Pbes2(params) => params.encrypt(password, plaintext),
124 Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
125 }
126 }
127
128 #[cfg(feature = "pbes2")]
136 pub fn encrypt_in_place<'a>(
137 &self,
138 password: impl AsRef<[u8]>,
139 buffer: &'a mut [u8],
140 pos: usize,
141 ) -> Result<&'a [u8]> {
142 match self {
143 Self::Pbes2(params) => params.encrypt_in_place(password, buffer, pos),
144 Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
145 }
146 }
147
148 #[must_use]
150 pub fn oid(&self) -> ObjectIdentifier {
151 match self {
152 Self::Pbes1(params) => params.oid(),
153 Self::Pbes2(_) => pbes2::PBES2_OID,
154 }
155 }
156
157 #[must_use]
159 pub fn pbes1(&self) -> Option<&pbes1::Algorithm> {
160 match self {
161 Self::Pbes1(alg) => Some(alg),
162 _ => None,
163 }
164 }
165
166 #[must_use]
168 pub fn pbes2(&self) -> Option<&pbes2::Parameters> {
169 match self {
170 Self::Pbes2(params) => Some(params),
171 _ => None,
172 }
173 }
174}
175
176impl<'a> DecodeValue<'a> for EncryptionScheme {
177 type Error = der::Error;
178
179 fn decode_value<R: Reader<'a>>(decoder: &mut R, header: Header) -> der::Result<Self> {
180 AlgorithmIdentifierRef::decode_value(decoder, header)?.try_into()
181 }
182}
183
184impl EncodeValue for EncryptionScheme {
185 fn value_len(&self) -> der::Result<Length> {
186 match self {
187 Self::Pbes1(pbes1) => pbes1.oid().encoded_len()? + pbes1.parameters.encoded_len()?,
188 Self::Pbes2(pbes2) => pbes2::PBES2_OID.encoded_len()? + pbes2.encoded_len()?,
189 }
190 }
191
192 fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
193 match self {
194 Self::Pbes1(pbes1) => {
195 pbes1.oid().encode(writer)?;
196 pbes1.parameters.encode(writer)?;
197 }
198 Self::Pbes2(pbes2) => {
199 pbes2::PBES2_OID.encode(writer)?;
200 pbes2.encode(writer)?;
201 }
202 }
203
204 Ok(())
205 }
206}
207
208impl Sequence<'_> for EncryptionScheme {}
209
210impl From<pbes1::Algorithm> for EncryptionScheme {
211 fn from(alg: pbes1::Algorithm) -> EncryptionScheme {
212 Self::Pbes1(alg)
213 }
214}
215
216impl From<pbes2::Parameters> for EncryptionScheme {
217 fn from(params: pbes2::Parameters) -> EncryptionScheme {
218 Self::Pbes2(params)
219 }
220}
221
222impl TryFrom<AlgorithmIdentifierRef<'_>> for EncryptionScheme {
223 type Error = der::Error;
224
225 fn try_from(alg: AlgorithmIdentifierRef<'_>) -> der::Result<EncryptionScheme> {
226 if alg.oid == pbes2::PBES2_OID {
227 match alg.parameters {
228 Some(params) => pbes2::Parameters::try_from(params).map(Into::into),
229 None => Err(Tag::OctetString.value_error().into()),
230 }
231 } else {
232 pbes1::Algorithm::try_from(alg).map(Into::into)
233 }
234 }
235}
236
237impl TryFrom<&[u8]> for EncryptionScheme {
238 type Error = der::Error;
239
240 fn try_from(bytes: &[u8]) -> der::Result<EncryptionScheme> {
241 AlgorithmIdentifierRef::from_der(bytes)?.try_into()
242 }
243}