aws_lc_rs/rsa/encryption/
pkcs1.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0 OR ISC
3
4#![allow(clippy::module_name_repetitions)]
5
6use super::{PrivateDecryptingKey, PublicEncryptingKey};
7use crate::aws_lc::{
8    EVP_PKEY_CTX_set_rsa_padding, EVP_PKEY_decrypt, EVP_PKEY_decrypt_init, EVP_PKEY_encrypt,
9    EVP_PKEY_encrypt_init, EVP_PKEY_CTX, RSA_PKCS1_PADDING,
10};
11use crate::error::Unspecified;
12use crate::fips::indicator_check;
13use crate::ptr::LcPtr;
14use core::fmt::Debug;
15
16/// RSA PKCS1-v1.5 public key for encryption.
17pub struct Pkcs1PublicEncryptingKey {
18    public_key: PublicEncryptingKey,
19}
20
21impl Pkcs1PublicEncryptingKey {
22    /// Constructs an `Pkcs1PublicEncryptingKey` from a `PublicEncryptingKey`.
23    /// # Errors
24    /// * `Unspecified`: Any error that occurs while attempting to construct an RSA-OAEP public key.
25    pub fn new(public_key: PublicEncryptingKey) -> Result<Self, Unspecified> {
26        Ok(Self { public_key })
27    }
28
29    /// Encrypts the contents in `plaintext` and writes the corresponding ciphertext to `ciphertext`.
30    /// Returns the subslice of `ciphertext` containing the ciphertext output.
31    ///
32    /// # Max Plaintext Length
33    /// The provided length of `plaintext` must be at most [`Self::max_plaintext_size`].
34    ///
35    /// # Sizing `output`
36    /// The length of `output` must be greater than or equal to [`Self::ciphertext_size`].
37    ///
38    /// # Errors
39    /// * `Unspecified` for any error that occurs while encrypting `plaintext`.
40    pub fn encrypt<'ciphertext>(
41        &self,
42        plaintext: &[u8],
43        ciphertext: &'ciphertext mut [u8],
44    ) -> Result<&'ciphertext mut [u8], Unspecified> {
45        let mut pkey_ctx = self.public_key.0.create_EVP_PKEY_CTX()?;
46
47        if 1 != unsafe { EVP_PKEY_encrypt_init(*pkey_ctx.as_mut()) } {
48            return Err(Unspecified);
49        }
50
51        configure_pkcs1_crypto_operation(&mut pkey_ctx)?;
52
53        let mut out_len = ciphertext.len();
54
55        if 1 != indicator_check!(unsafe {
56            EVP_PKEY_encrypt(
57                *pkey_ctx.as_mut(),
58                ciphertext.as_mut_ptr(),
59                &mut out_len,
60                plaintext.as_ptr(),
61                plaintext.len(),
62            )
63        }) {
64            return Err(Unspecified);
65        }
66
67        Ok(&mut ciphertext[..out_len])
68    }
69
70    /// Returns the RSA key size in bytes.
71    #[must_use]
72    pub fn key_size_bytes(&self) -> usize {
73        self.public_key.key_size_bytes()
74    }
75
76    /// Returns the RSA key size in bits.
77    #[must_use]
78    pub fn key_size_bits(&self) -> usize {
79        self.public_key.key_size_bits()
80    }
81
82    /// Returns the max plaintext that could be encrypted using this key.
83    #[must_use]
84    pub fn max_plaintext_size(&self) -> usize {
85        const RSA_PKCS1_PADDING_SIZE: usize = 11; // crypto/fipsmodule/rsa/internal.h
86        self.key_size_bytes() - RSA_PKCS1_PADDING_SIZE
87    }
88
89    /// Returns the max ciphertext size that will be output by `Self::encrypt`.
90    #[must_use]
91    pub fn ciphertext_size(&self) -> usize {
92        self.key_size_bytes()
93    }
94}
95
96impl Debug for Pkcs1PublicEncryptingKey {
97    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
98        f.debug_struct("Pkcs1PublicEncryptingKey")
99            .finish_non_exhaustive()
100    }
101}
102
103/// RSA PKCS1-v1.5 private key for decryption.
104pub struct Pkcs1PrivateDecryptingKey {
105    private_key: PrivateDecryptingKey,
106}
107
108impl Pkcs1PrivateDecryptingKey {
109    /// Constructs an `Pkcs1PrivateDecryptingKey` from a `PrivateDecryptingKey`.
110    /// # Errors
111    /// * `Unspecified`: Any error that occurs while attempting to construct an RSA-OAEP public key.
112    pub fn new(private_key: PrivateDecryptingKey) -> Result<Self, Unspecified> {
113        Ok(Self { private_key })
114    }
115
116    /// Decrypts the contents in `ciphertext` and writes the corresponding plaintext to `plaintext`.
117    /// Returns the subslice of `plaintext` containing the plaintext output.
118    ///
119    /// # Max Ciphertext Length
120    /// The provided length of `ciphertext` must be [`Self::key_size_bytes`].
121    ///
122    /// # Sizing `output`
123    /// The length of `output` must be greater than or equal to [`Self::min_output_size`].
124    ///
125    /// # Errors
126    /// * `Unspecified` for any error that occurs while decrypting `ciphertext`.
127    pub fn decrypt<'plaintext>(
128        &self,
129        ciphertext: &[u8],
130        plaintext: &'plaintext mut [u8],
131    ) -> Result<&'plaintext mut [u8], Unspecified> {
132        let mut pkey_ctx = self.private_key.0.create_EVP_PKEY_CTX()?;
133
134        if 1 != unsafe { EVP_PKEY_decrypt_init(*pkey_ctx.as_mut()) } {
135            return Err(Unspecified);
136        }
137
138        configure_pkcs1_crypto_operation(&mut pkey_ctx)?;
139
140        let mut out_len = plaintext.len();
141
142        if 1 != indicator_check!(unsafe {
143            EVP_PKEY_decrypt(
144                *pkey_ctx.as_mut(),
145                plaintext.as_mut_ptr(),
146                &mut out_len,
147                ciphertext.as_ptr(),
148                ciphertext.len(),
149            )
150        }) {
151            return Err(Unspecified);
152        }
153
154        Ok(&mut plaintext[..out_len])
155    }
156
157    /// Returns the RSA key size in bytes.
158    #[must_use]
159    pub fn key_size_bytes(&self) -> usize {
160        self.private_key.key_size_bytes()
161    }
162
163    /// Returns the RSA key size in bits.
164    #[must_use]
165    pub fn key_size_bits(&self) -> usize {
166        self.private_key.key_size_bits()
167    }
168
169    /// Returns the minimum plaintext buffer size required for `Self::decrypt`.
170    #[must_use]
171    pub fn min_output_size(&self) -> usize {
172        self.key_size_bytes()
173    }
174}
175
176impl Debug for Pkcs1PrivateDecryptingKey {
177    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
178        f.debug_struct("Pkcs1PrivateDecryptingKey")
179            .finish_non_exhaustive()
180    }
181}
182
183fn configure_pkcs1_crypto_operation(
184    evp_pkey_ctx: &mut LcPtr<EVP_PKEY_CTX>,
185) -> Result<(), Unspecified> {
186    if 1 != unsafe { EVP_PKEY_CTX_set_rsa_padding(*evp_pkey_ctx.as_mut(), RSA_PKCS1_PADDING) } {
187        return Err(Unspecified);
188    }
189
190    Ok(())
191}