1#![no_std]
2#![cfg_attr(docsrs, feature(doc_auto_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#![warn(
10 clippy::mod_module_files,
11 clippy::unwrap_used,
12 missing_docs,
13 rust_2018_idioms,
14 unused_lifetimes,
15 unused_qualifications
16)]
17
18#[cfg(all(feature = "alloc", feature = "pbes2"))]
27extern crate alloc;
28
29mod error;
30
31pub mod pbes1;
32pub mod pbes2;
33
34pub use crate::error::{Error, Result};
35pub use der::{self, asn1::ObjectIdentifier};
36pub use spki::AlgorithmIdentifierRef;
37
38use der::{
39 Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, Writer,
40};
41
42#[cfg(feature = "pbes2")]
43pub use scrypt;
44
45#[cfg(all(feature = "alloc", feature = "pbes2"))]
46use alloc::vec::Vec;
47
48#[derive(Clone, Debug, Eq, PartialEq)]
50#[non_exhaustive]
51#[allow(clippy::large_enum_variant)]
52pub enum EncryptionScheme<'a> {
53 Pbes1(pbes1::Algorithm),
57
58 Pbes2(pbes2::Parameters<'a>),
62}
63
64impl<'a> EncryptionScheme<'a> {
65 #[cfg(all(feature = "alloc", feature = "pbes2"))]
68 pub fn decrypt(&self, password: impl AsRef<[u8]>, ciphertext: &[u8]) -> Result<Vec<u8>> {
69 match self {
70 Self::Pbes2(params) => params.decrypt(password, ciphertext),
71 Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
72 }
73 }
74
75 #[cfg(feature = "pbes2")]
82 pub fn decrypt_in_place<'b>(
83 &self,
84 password: impl AsRef<[u8]>,
85 buffer: &'b mut [u8],
86 ) -> Result<&'b [u8]> {
87 match self {
88 Self::Pbes2(params) => params.decrypt_in_place(password, buffer),
89 Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
90 }
91 }
92
93 #[cfg(all(feature = "alloc", feature = "pbes2"))]
96 pub fn encrypt(&self, password: impl AsRef<[u8]>, plaintext: &[u8]) -> Result<Vec<u8>> {
97 match self {
98 Self::Pbes2(params) => params.encrypt(password, plaintext),
99 Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
100 }
101 }
102
103 #[cfg(feature = "pbes2")]
106 pub fn encrypt_in_place<'b>(
107 &self,
108 password: impl AsRef<[u8]>,
109 buffer: &'b mut [u8],
110 pos: usize,
111 ) -> Result<&'b [u8]> {
112 match self {
113 Self::Pbes2(params) => params.encrypt_in_place(password, buffer, pos),
114 Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport),
115 }
116 }
117
118 pub fn oid(&self) -> ObjectIdentifier {
120 match self {
121 Self::Pbes1(params) => params.oid(),
122 Self::Pbes2(_) => pbes2::PBES2_OID,
123 }
124 }
125
126 pub fn pbes1(&self) -> Option<&pbes1::Algorithm> {
128 match self {
129 Self::Pbes1(alg) => Some(alg),
130 _ => None,
131 }
132 }
133
134 pub fn pbes2(&self) -> Option<&pbes2::Parameters<'a>> {
136 match self {
137 Self::Pbes2(params) => Some(params),
138 _ => None,
139 }
140 }
141}
142
143impl<'a> DecodeValue<'a> for EncryptionScheme<'a> {
144 fn decode_value<R: Reader<'a>>(decoder: &mut R, header: Header) -> der::Result<Self> {
145 AlgorithmIdentifierRef::decode_value(decoder, header)?.try_into()
146 }
147}
148
149impl EncodeValue for EncryptionScheme<'_> {
150 fn value_len(&self) -> der::Result<Length> {
151 match self {
152 Self::Pbes1(pbes1) => pbes1.oid().encoded_len()? + pbes1.parameters.encoded_len()?,
153 Self::Pbes2(pbes2) => pbes2::PBES2_OID.encoded_len()? + pbes2.encoded_len()?,
154 }
155 }
156
157 fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
158 match self {
159 Self::Pbes1(pbes1) => {
160 pbes1.oid().encode(writer)?;
161 pbes1.parameters.encode(writer)?;
162 }
163 Self::Pbes2(pbes2) => {
164 pbes2::PBES2_OID.encode(writer)?;
165 pbes2.encode(writer)?;
166 }
167 }
168
169 Ok(())
170 }
171}
172
173impl<'a> Sequence<'a> for EncryptionScheme<'a> {}
174
175impl<'a> From<pbes1::Algorithm> for EncryptionScheme<'a> {
176 fn from(alg: pbes1::Algorithm) -> EncryptionScheme<'a> {
177 Self::Pbes1(alg)
178 }
179}
180
181impl<'a> From<pbes2::Parameters<'a>> for EncryptionScheme<'a> {
182 fn from(params: pbes2::Parameters<'a>) -> EncryptionScheme<'a> {
183 Self::Pbes2(params)
184 }
185}
186
187impl<'a> TryFrom<AlgorithmIdentifierRef<'a>> for EncryptionScheme<'a> {
188 type Error = der::Error;
189
190 fn try_from(alg: AlgorithmIdentifierRef<'a>) -> der::Result<EncryptionScheme<'_>> {
191 if alg.oid == pbes2::PBES2_OID {
192 match alg.parameters {
193 Some(params) => pbes2::Parameters::try_from(params).map(Into::into),
194 None => Err(Tag::OctetString.value_error()),
195 }
196 } else {
197 pbes1::Algorithm::try_from(alg).map(Into::into)
198 }
199 }
200}
201
202impl<'a> TryFrom<&'a [u8]> for EncryptionScheme<'a> {
203 type Error = der::Error;
204
205 fn try_from(bytes: &'a [u8]) -> der::Result<EncryptionScheme<'a>> {
206 AlgorithmIdentifierRef::from_der(bytes)?.try_into()
207 }
208}