easyssl 0.87.745ff01
EasySSL is base back end library for your c++ Qt projects.
rsassl.cpp
Go to the documentation of this file.
1//#
2//# Copyright (C) 2021-2025 QuasarApp.
3//# Distributed under the GPLv3 software license, see the accompanying
4//# Everyone is permitted to copy and distribute verbatim copies
5//# of this license document, but changing it is not allowed.
6//#
7
8
9#include "rsassl.h"
10#include "qcryptographichash.h"
11#include <openssl/bn.h>
12#include <openssl/evp.h>
13#include <openssl/pem.h>
14#include <openssl/rsa.h>
15#include <easysslutils.h>
16#include <QDebug>
17
18namespace EasySSL {
19
20RSASSL::RSASSL(RSAPadding padding) {
22}
23
24void *RSASSL::makeRawKeys() const {
25
26 EVP_PKEY *pkey = nullptr;
27 EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name(nullptr, "RSA", nullptr);
28 EVP_PKEY_keygen_init(pctx);
29
30 if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, _bits) <= 0) {
32 };
33
34 EVP_PKEY_generate(pctx, &pkey);
35 EVP_PKEY_CTX_free(pctx);
36
37 return pkey;
38}
39
43
44QSsl::KeyAlgorithm RSASSL::keyAlgorithm() const {
45 return QSsl::KeyAlgorithm::Rsa;
46}
47
48QByteArray RSASSL::signMessage(const QByteArray &inputData, const QByteArray &key) const {
49 QByteArray signature;
50
51 auto pkey = EasySSLUtils::byteArrayToBio(key);
52 auto rsaPrivateKey = PEM_read_bio_PrivateKey(pkey, nullptr, nullptr, nullptr);
53 BIO_free(pkey);
54
55 if (!rsaPrivateKey) {
56 qCritical() << "Error reading private key";
58 return {};
59 }
60
61 EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
62 if (mdctx == nullptr) {
63 return {};
64 }
65
66 // Initialize the signing operation
67 if (EVP_DigestSignInit(mdctx, nullptr, EVP_sha256(), nullptr, rsaPrivateKey) != 1) {
69 EVP_MD_CTX_free(mdctx);
70 return {};
71 }
72
73 auto hash = QCryptographicHash::hash(inputData,
74 QCryptographicHash::Sha256);
75
76 // Provide the message to be signed
77 if (EVP_DigestSignUpdate(mdctx, hash.data(), hash.size()) != 1) {
79 EVP_MD_CTX_free(mdctx);
80 return {};
81 }
82
83 size_t signatureLength = EVP_PKEY_size(rsaPrivateKey);
84 signature.resize(signatureLength);
85
86 // Perform the final signing operation and obtain the signature
87 if (EVP_DigestSignFinal(mdctx, reinterpret_cast<unsigned char*>(signature.data()), &signatureLength) != 1) {
89 EVP_MD_CTX_free(mdctx);
90 return {};
91 }
92
93 signature.resize(signatureLength);
94
95 EVP_MD_CTX_free(mdctx);
96 return signature;
97}
98
99bool RSASSL::checkSign(const QByteArray &inputData, const QByteArray &signature, const QByteArray &key) const {
100 EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
101 if (mdctx == nullptr) {
102 return false;
103 }
104
105 auto pkey = EasySSLUtils::byteArrayToBio(key);
106 auto rsaPublickKey = PEM_read_bio_PUBKEY(pkey, nullptr, nullptr, nullptr);
107 BIO_free(pkey);
108
109 // Initialize the verification operation
110 if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, rsaPublickKey) != 1) {
112 EVP_MD_CTX_free(mdctx);
113 return false;
114 }
115
116 auto hash = QCryptographicHash::hash(inputData,
117 QCryptographicHash::Sha256);
118
119 // Provide the message to be verified
120 if (EVP_DigestVerifyUpdate(mdctx, hash.data(), hash.size()) != 1) {
122 EVP_MD_CTX_free(mdctx);
123 return false;
124 }
125
126 // Perform the signature verification
127 int verificationResult = EVP_DigestVerifyFinal(mdctx,
128 reinterpret_cast<const unsigned char*>(signature.data()),
129 signature.length());
130
131 EVP_MD_CTX_free(mdctx);
132
133 return verificationResult == 1;
134}
135
136QByteArray RSASSL::decrypt(const QByteArray &message, const QByteArray &key) {
137
138 auto pkey = EasySSLUtils::byteArrayToBio(key);
139 auto rsaPrivateKey = PEM_read_bio_PrivateKey(pkey, nullptr, nullptr, nullptr);
140 BIO_free(pkey);
141
142 if (!rsaPrivateKey) {
143 qCritical() << "Error reading private key";
145 return {};
146 }
147
148 const long long maxDencryptedSize = EVP_PKEY_size(rsaPrivateKey);
149 if (message.length() % maxDencryptedSize) {
150 qCritical() << "Error wrong encrypted data size.";
151 qCritical() << "Your key requir size multiple " << maxDencryptedSize;
152
153 return {};
154 }
155
156
157 EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(rsaPrivateKey, nullptr);
158 if (ctx == nullptr) {
159 EVP_PKEY_free(rsaPrivateKey);
160 return {};
161 }
162
163 if (EVP_PKEY_decrypt_init(ctx) <= 0) {
165
166 EVP_PKEY_CTX_free(ctx);
167 EVP_PKEY_free(rsaPrivateKey);
168 return {};
169 }
170
171 if (EVP_PKEY_CTX_set_rsa_padding(ctx, getRawOpenSSLPandingValue(_padding)) <= 0) {
173 EVP_PKEY_CTX_free(ctx);
174 EVP_PKEY_free(rsaPrivateKey);
175 return {};
176 }
177
178 QByteArray decryptedData;
179
180 for (int index = 0; index < message.size(); index += maxDencryptedSize) {
181
182 QByteArray decryptedDataPart(maxDencryptedSize, 0);
183 size_t realDecryptedDataPartSize = maxDencryptedSize; // must be equals or large of private key size.
184 if (EVP_PKEY_decrypt(ctx,
185 reinterpret_cast<unsigned char*>(decryptedDataPart.data()),
186 &realDecryptedDataPartSize,
187 reinterpret_cast<const unsigned char*>(&(message.constData()[index])),
188 maxDencryptedSize) <= 0) {
189
191 EVP_PKEY_CTX_free(ctx);
192 EVP_PKEY_free(rsaPrivateKey);
193 return {};
194 }
195
196 decryptedData += decryptedDataPart.left(realDecryptedDataPartSize);
197 }
198
199 EVP_PKEY_CTX_free(ctx);
200 EVP_PKEY_free(rsaPrivateKey);
201 return decryptedData;
202
203}
204
205QByteArray RSASSL::encrypt(const QByteArray &message, const QByteArray &key) {
206 auto pkey = EasySSLUtils::byteArrayToBio(key);
207 auto rsaPublicKey = PEM_read_bio_PUBKEY(pkey, nullptr, nullptr, nullptr);
208 BIO_free(pkey);
209
210 if (!rsaPublicKey) {
211 qCritical() << "Error reading public key";
213 return {};
214 }
215
216 EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(rsaPublicKey, nullptr);
217 if (ctx == nullptr) {
219 EVP_PKEY_free(rsaPublicKey);
220 return {};
221 }
222
223 if (EVP_PKEY_encrypt_init(ctx) <= 0) {
225 EVP_PKEY_CTX_free(ctx);
226 EVP_PKEY_free(rsaPublicKey);
227 return {};
228 }
229
230 if (EVP_PKEY_CTX_set_rsa_padding(ctx, getRawOpenSSLPandingValue(_padding)) <= 0) {
232 EVP_PKEY_CTX_free(ctx);
233 EVP_PKEY_free(rsaPublicKey);
234 return {};
235 }
236
237 const long long maxEncryptedSize = EVP_PKEY_size(rsaPublicKey);
238 QByteArray encryptedData;
239
240 for (int index = 0; index < message.size();) {
241
242 QByteArray encryptedDataPart(maxEncryptedSize, 0);
243 // EVP_PKEY_encrypt() uses *realEncryptedDataPartSize as the size of the
244 // output buffer on input (and as the actual size on output). OpenSSL >= 3.6
245 // validates it and fails with "rsa_encrypt: output buffer too small" when
246 // it is smaller than the key size, so it must be the buffer size, not 0.
247 size_t realEncryptedDataPartSize = maxEncryptedSize;
248 int currentPartSize = std::min(message.length() - index, maxEncryptedSize - getPandingSize(_padding)) ;
249 if (EVP_PKEY_encrypt(ctx,
250 reinterpret_cast<unsigned char*>(encryptedDataPart.data()),
251 &realEncryptedDataPartSize,
252 reinterpret_cast<const unsigned char*>(&(message.constData()[index])),
253 currentPartSize) <= 0) {
254
256 EVP_PKEY_CTX_free(ctx);
257 EVP_PKEY_free(rsaPublicKey);
258 return {};
259 }
260
261 encryptedData += encryptedDataPart.left(realEncryptedDataPartSize);
262 index += currentPartSize;
263 }
264
265 EVP_PKEY_CTX_free(ctx);
266 EVP_PKEY_free(rsaPublicKey);
267 return encryptedData;
268}
269
270RSASSL::RSAPadding RSASSL::padding() const {
271 return _padding;
272}
273
274void RSASSL::setPadding(RSAPadding newPadding) {
275 _padding = newPadding;
276}
277
278int RSASSL::getRawOpenSSLPandingValue(RSAPadding panding) {
279 switch (panding) {
280 case NO_PADDING: return RSA_NO_PADDING;
281 case PKCS1_OAEP_PADDING: return RSA_PKCS1_OAEP_PADDING;
282 case PKCS1_PADDING: return RSA_PKCS1_PADDING;
283
284 default:
285 return 0;
286 }
287}
288
289int RSASSL::getPandingSize(RSAPadding panding) {
290 switch (panding) {
291 case PKCS1_OAEP_PADDING: return 42;
292 case PKCS1_PADDING: return 11;
293
294 default:
295 return 0;
296 }
297}
298
299RSASSL::RSABits RSASSL::bits() const {
300 return _bits;
301}
302
303void RSASSL::setBits(RSABits newBits) {
304 _bits = newBits;
305}
306
307}
static BIO * byteArrayToBio(const QByteArray &byteArray)
byteArrayToBio This method creates the BIO struct from the Qt QByteArray object.
static void printlastOpenSSlError()
printlastOpenSSlError This method prints the latest ssl error message.
Features
The Features enum this is list of the supported description features.
Definition icrypto.h:29
@ Encryption
Encryption and decryption data.
Definition icrypto.h:33
@ Signing
Signin and check sign of the data.
Definition icrypto.h:31
Features supportedFeatures() const override
supportedFeatures This method should return supported featurs of the current encryption algorithm
Definition rsassl.cpp:40
void * makeRawKeys() const override
makeKeys This method generate the public and private keys of the ECDSA.
Definition rsassl.cpp:24
RSABits bits() const
bits return cuurrent rsa keys size mode. Using oly for generate keys.
Definition rsassl.cpp:299
void setBits(RSABits newBits)
setBits sets new value of the rsa key generator.
Definition rsassl.cpp:303
QByteArray decrypt(const QByteArray &message, const QByteArray &key) override
decrypt This method has empty implementation.
Definition rsassl.cpp:136
QByteArray signMessage(const QByteArray &inputData, const QByteArray &key) const override
signMessage This method should be sign the message using the key.
Definition rsassl.cpp:48
QSsl::KeyAlgorithm keyAlgorithm() const override
keyAlgorithm This method should be return Qt Key algorithm (needed for generate cetrificates....
Definition rsassl.cpp:44
RSAPadding padding() const
padding This is mode of pending data before icnription.
Definition rsassl.cpp:270
void setPadding(RSAPadding newPadding)
setPadding This method sets new mode for encryption pendong.
Definition rsassl.cpp:274
QByteArray encrypt(const QByteArray &message, const QByteArray &key) override
encrypt This method has empty implementation.
Definition rsassl.cpp:205
RSASSL(RSAPadding padding=PKCS1_OAEP_PADDING)
Definition rsassl.cpp:20
bool checkSign(const QByteArray &inputData, const QByteArray &signature, const QByteArray &key) const override
checkSign This method should be check signature of the message using the key.
Definition rsassl.cpp:99