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