pkcs7_encrypt.c
Go to the documentation of this file.
1 /**
2  * @file pkcs7_encrypt.c
3  * @brief PKCS #7 message encryption
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.5.2
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/crypto.h"
36 #include "pkcs7/pkcs7_format.h"
37 #include "pkcs7/pkcs7_encrypt.h"
39 #include "cipher_modes/cbc.h"
40 #include "pkix/x509_key_parse.h"
41 #include "debug.h"
42 
43 //Check crypto library configuration
44 #if (PKCS7_SUPPORT == ENABLED)
45 
46 
47 /**
48  * @brief Encrypt enveloped-data content
49  * @param[in] prngAlgo PRNG algorithm
50  * @param[in] prngContext Pointer to the PRNG context
51  * @param[in] recipientCertInfo Recipient's certificate
52  * @param[in] contentEncrAlgo Content encryption algorithm
53  * @param[in] plaintext Pointer to the message to be encrypted
54  * @param[in] plaintextLen Length of the message, in bytes
55  * @param[out] output Buffer where to format the ASN.1 structure
56  * @param[out] written Length of the resulting ASN.1 structure
57  * @return Error code
58  **/
59 
60 error_t pkcs7EncryptEnvelopedData(const PrngAlgo *prngAlgo, void *prngContext,
61  const X509CertInfo *recipientCertInfo,
62  const Pkcs7ContentEncrAlgo *contentEncrAlgo, const uint8_t *plaintext,
63  size_t plaintextLen, uint8_t *output, size_t *written)
64 {
65  error_t error;
66  Pkcs7EnvelopedData envelopedData;
67  const CipherAlgo *cipherAlgo;
68  uint8_t iv[16];
69 
70  //Retrieve cipher algorithm
71  cipherAlgo = pkcs7GetCipherAlgo(contentEncrAlgo->oid.value,
72  contentEncrAlgo->oid.length);
73  //Invalid cipher algorithm?
74  if(cipherAlgo == NULL)
76 
77  //Generate a random initialization vector
78  error = prngAlgo->read(prngContext, iv, cipherAlgo->blockSize);
79  //Any error to report?
80  if(error)
81  return error;
82 
83  //Clear EnvelopedData structure
84  osMemset(&envelopedData, 0, sizeof(Pkcs7EnvelopedData));
85 
86  //version is the syntax version number
87  envelopedData.version = PKCS7_VERSION_0;
88 
89  //recipientInfos is a collection of per-recipient information
90  envelopedData.recipientInfos.numRecipientInfos = 1,
92  envelopedData.recipientInfos.recipientInfos[0].issuerAndSerialNumber.name.raw = recipientCertInfo->tbsCert.issuer.raw;
96 
97  //encryptedContentInfo is the encrypted content information
99  envelopedData.encryptedContentInfo.contentType.length = sizeof(PKCS7_DATA_OID);
100  envelopedData.encryptedContentInfo.contentEncrAlgo.oid.value = contentEncrAlgo->oid.value;
101  envelopedData.encryptedContentInfo.contentEncrAlgo.oid.length = contentEncrAlgo->oid.length;
103  envelopedData.encryptedContentInfo.contentEncrAlgo.iv.length = cipherAlgo->blockSize;
104 
105  //Format enveloped-data content
106  error = pkcs7FormatEnvelopedData(prngAlgo, prngContext, recipientCertInfo,
107  &envelopedData, plaintext, plaintextLen, output, written);
108 
109  //Return status code
110  return error;
111 }
112 
113 
114 /**
115  * @brief Perform key encryption
116  * @param[in] prngAlgo PRNG algorithm
117  * @param[in] prngContext Pointer to the PRNG context
118  * @param[in] recipientCertInfo Recipient's certificate
119  * @param[in] plaintext Pointer to the key to be encrypted
120  * @param[in] plaintextLen Length of the key, in bytes
121  * @param[out] ciphertext Ciphertext resulting from the encryption operation
122  * @param[out] ciphertextLen Length of the resulting ciphertext
123  * @return Error code
124  **/
125 
126 error_t pkcs7EncryptKey(const PrngAlgo *prngAlgo, void *prngContext,
127  const X509CertInfo *recipientCertInfo, const uint8_t *plaintext,
128  size_t plaintextLen, uint8_t *ciphertext, size_t *ciphertextLen)
129 {
130 #if (PKCS7_RSA_SUPPORT == ENABLED && RSA_SUPPORT == ENABLED)
131  error_t error;
132  RsaPublicKey rsaPublicKey;
133 
134  //Initialize RSA public key
135  rsaInitPublicKey(&rsaPublicKey);
136 
137  //Import the RSA public key
138  error = x509ImportRsaPublicKey(&rsaPublicKey,
139  &recipientCertInfo->tbsCert.subjectPublicKeyInfo);
140 
141  //Check status code
142  if(!error)
143  {
144  //If the output parameter is NULL, then the function calculates the
145  //length of the ciphertext without copying any data
146  if(ciphertext != NULL)
147  {
148  //Perform RSA encryption
149  error = rsaesPkcs1v15Encrypt(prngAlgo, prngContext, &rsaPublicKey,
150  plaintext, plaintextLen, ciphertext, ciphertextLen);
151  }
152  else
153  {
154  //Length of the resulting ciphertext
155  *ciphertextLen = mpiGetByteLength(&rsaPublicKey.n);
156  }
157  }
158 
159  //Release previously allocated resources
160  rsaFreePublicKey(&rsaPublicKey);
161 
162  //Return status code
163  return error;
164 #else
165  //Not implemented
166  return ERROR_NOT_IMPLEMENTED;
167 #endif
168 }
169 
170 
171 /**
172  * @brief Perform data encryption
173  * @param[in] encryptedContentInfo Pointer to the encryptedContentInfo structure
174  * @param[in] key Pointer to the encryption key
175  * @param[in] keyLen Length of the encryption key, in bytes
176  * @param[in] plaintext Pointer to the plaintext data to be encrypted
177  * @param[in] plaintextLen Length of the plaintext, in bytes
178  * @param[out] ciphertext Ciphertext resulting from the encryption operation
179  * @param[out] ciphertextLen Length of the resulting ciphertext
180  * @return Error code
181  **/
182 
184  const uint8_t *key, size_t keyLen, const uint8_t *plaintext,
185  size_t plaintextLen, uint8_t *ciphertext, size_t *ciphertextLen)
186 {
187  error_t error;
188  size_t i;
189  size_t n;
190  size_t ivLen;
191  size_t paddingLen;
192  uint8_t iv[MAX_CIPHER_BLOCK_SIZE];
193  const CipherAlgo *cipherAlgo;
194  CipherContext cipherContext;
195 
196  //Retrieve cipher algorithm
197  cipherAlgo = pkcs7GetCipherAlgo(encryptedContentInfo->contentEncrAlgo.oid.value,
198  encryptedContentInfo->contentEncrAlgo.oid.length);
199  //Invalid cipher algorithm?
200  if(cipherAlgo == NULL)
202 
203  //Obtain the key length in octets
204  n = pkcs7GetKeyLength(encryptedContentInfo->contentEncrAlgo.oid.value,
205  encryptedContentInfo->contentEncrAlgo.oid.length);
206  //Invalid key length?
207  if(n == 0)
209 
210  //Check the length of the encryption key
211  if(keyLen != n)
213 
214  //Retrieve the length of the initialization vector
215  ivLen = encryptedContentInfo->contentEncrAlgo.iv.length;
216 
217  //Check the length of the initialization vector
218  if(ivLen != cipherAlgo->blockSize)
220 
221  //Copy the initialization vector
222  osMemcpy(iv, encryptedContentInfo->contentEncrAlgo.iv.value, ivLen);
223 
224  //Load encryption key
225  error = cipherAlgo->init(&cipherContext, key, keyLen);
226  //Any error to report?
227  if(error)
228  return error;
229 
230  //Get the actual amount of bytes in the last block
231  paddingLen = plaintextLen % cipherAlgo->blockSize;
232 
233  //Determine the length of the padding string
234  if(paddingLen > 0)
235  {
236  paddingLen = cipherAlgo->blockSize - paddingLen;
237  }
238 
239  //If the output parameter is NULL, then the function calculates the length
240  //of the resulting ciphertext without performing encryption
241  if(ciphertext != NULL)
242  {
243  //Copy the data to encrypt
244  osMemmove(ciphertext, plaintext, plaintextLen);
245 
246  //The content must be padded to a multiple of the block size
247  for(i = 0; i <= paddingLen; i++)
248  {
249  ciphertext[plaintextLen + i] = (uint8_t) paddingLen;
250  }
251 
252  //Perform CBC encryption
253  error = cbcEncrypt(cipherAlgo, &cipherContext, iv, ciphertext, ciphertext,
254  plaintextLen + paddingLen);
255  //Any error to report?
256  if(error)
257  return error;
258  }
259 
260  //Return the length of the ciphertext
261  *ciphertextLen = plaintextLen + paddingLen;
262 
263  //Successful processing
264  return NO_ERROR;
265 }
266 
267 #endif
void rsaFreePublicKey(RsaPublicKey *key)
Release an RSA public key.
Definition: rsa.c:113
error_t pkcs7FormatEnvelopedData(const PrngAlgo *prngAlgo, void *prngContext, const X509CertInfo *recipientCertInfo, const Pkcs7EnvelopedData *envelopedData, const uint8_t *plaintext, size_t plaintextLen, uint8_t *output, size_t *written)
Format enveloped-data content.
Definition: pkcs7_format.c:349
X509TbsCertificate tbsCert
Definition: x509_common.h:1121
X509SerialNumber serialNumber
Definition: pkcs7_common.h:216
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
#define PrngAlgo
Definition: crypto.h:980
@ ERROR_DECRYPTION_FAILED
Definition: error.h:243
__weak_func error_t cbcEncrypt(const CipherAlgo *cipher, void *context, uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
CBC encryption.
Definition: cbc.c:61
Collection of AEAD algorithms.
Generic cipher algorithm context.
X509OctetString contentType
Definition: pkcs7_common.h:340
size_t blockSize
Definition: crypto.h:1115
X509OctetString iv
Definition: pkcs7_common.h:330
const CipherAlgo * pkcs7GetCipherAlgo(const uint8_t *oid, size_t length)
Get the cipher algorithm that matches the specified OID.
Definition: pkcs7_common.c:215
Mpi n
Modulus.
Definition: rsa.h:58
Content encryption algorithm.
Definition: pkcs7_common.h:328
error_t pkcs7EncryptData(const Pkcs7EncryptedContentInfo *encryptedContentInfo, const uint8_t *key, size_t keyLen, const uint8_t *plaintext, size_t plaintextLen, uint8_t *ciphertext, size_t *ciphertextLen)
Perform data encryption.
#define MAX_CIPHER_BLOCK_SIZE
CipherAlgoInit init
Definition: crypto.h:1116
error_t pkcs7EncryptKey(const PrngAlgo *prngAlgo, void *prngContext, const X509CertInfo *recipientCertInfo, const uint8_t *plaintext, size_t plaintextLen, uint8_t *ciphertext, size_t *ciphertextLen)
Perform key encryption.
Pkcs7RecipientInfos recipientInfos
Definition: pkcs7_common.h:368
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
X.509 certificate.
Definition: x509_common.h:1119
error_t
Error codes.
Definition: error.h:43
Encrypted content information.
Definition: pkcs7_common.h:339
error_t rsaesPkcs1v15Encrypt(const PrngAlgo *prngAlgo, void *prngContext, const RsaPublicKey *key, const uint8_t *message, size_t messageLen, uint8_t *ciphertext, size_t *ciphertextLen)
RSAES-PKCS1-v1_5 encryption operation.
Definition: rsa.c:409
@ PKCS7_VERSION_0
v0
Definition: pkcs7_common.h:165
X509AlgoId keyEncryptionAlgo
Definition: pkcs7_common.h:295
RSA public key.
Definition: rsa.h:57
X509OctetString oid
Definition: x509_common.h:775
uint_t pkcs7GetKeyLength(const uint8_t *oid, size_t length)
Get the encryption key length to be used for PBES2 operation.
Definition: pkcs7_common.c:270
General definitions for cryptographic algorithms.
X509SerialNumber serialNumber
Definition: x509_common.h:1104
uint8_t iv[]
Definition: ike.h:1626
Pkcs7EncryptedContentInfo encryptedContentInfo
Definition: pkcs7_common.h:369
Cipher Block Chaining (CBC) mode.
const uint8_t RSA_ENCRYPTION_OID[9]
Definition: rsa.c:54
Pkcs7ContentEncrAlgo contentEncrAlgo
Definition: pkcs7_common.h:341
PKCS #7 message encryption.
const uint8_t PKCS7_DATA_OID[9]
Definition: pkcs7_common.c:50
X509OctetString oid
Definition: pkcs7_common.h:329
@ ERROR_UNSUPPORTED_CIPHER_ALGO
Definition: error.h:129
error_t x509ImportRsaPublicKey(RsaPublicKey *publicKey, const X509SubjectPublicKeyInfo *publicKeyInfo)
Import an RSA public key.
uint8_t n
Pkcs7RecipientInfo recipientInfos[PKCS7_MAX_RECIPIENT_INFOS]
Definition: pkcs7_common.h:308
Common interface for encryption algorithms.
Definition: crypto.h:1111
const uint8_t * value
Definition: x509_common.h:702
Parsing of ASN.1 encoded keys.
PKCS #7 message formatting.
#define osMemset(p, value, length)
Definition: os_port.h:138
X509SubjectPublicKeyInfo subjectPublicKeyInfo
Definition: x509_common.h:1109
Pkcs7IssuerAndSerialNumber issuerAndSerialNumber
Definition: pkcs7_common.h:294
Enveloped data content.
Definition: pkcs7_common.h:366
X509OctetString raw
Definition: x509_common.h:724
@ NO_ERROR
Success.
Definition: error.h:44
error_t pkcs7EncryptEnvelopedData(const PrngAlgo *prngAlgo, void *prngContext, const X509CertInfo *recipientCertInfo, const Pkcs7ContentEncrAlgo *contentEncrAlgo, const uint8_t *plaintext, size_t plaintextLen, uint8_t *output, size_t *written)
Encrypt enveloped-data content.
Definition: pkcs7_encrypt.c:60
Debugging facilities.
#define osMemmove(dest, src, length)
Definition: os_port.h:150
void rsaInitPublicKey(RsaPublicKey *key)
Initialize an RSA public key.
Definition: rsa.c:100
uint_t mpiGetByteLength(const Mpi *a)
Get the actual length in bytes.
Definition: mpi.c:215