easyssl 0.50.142aaef
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 size_t realEncryptedDataPartSize = 0;
244 int currentPartSize = std::min(message.length() - index, maxEncryptedSize - getPandingSize(_padding)) ;
245 if (EVP_PKEY_encrypt(ctx,
246 reinterpret_cast<unsigned char*>(encryptedDataPart.data()),
247 &realEncryptedDataPartSize,
248 reinterpret_cast<const unsigned char*>(&(message.constData()[index])),
249 currentPartSize) <= 0) {
250
252 EVP_PKEY_CTX_free(ctx);
253 EVP_PKEY_free(rsaPublicKey);
254 return {};
255 }
256
257 encryptedData += encryptedDataPart.left(realEncryptedDataPartSize);
258 index += currentPartSize;
259 }
260
261 EVP_PKEY_CTX_free(ctx);
262 EVP_PKEY_free(rsaPublicKey);
263 return encryptedData;
264}
265
266RSASSL::RSAPadding RSASSL::padding() const {
267 return _padding;
268}
269
270void RSASSL::setPadding(RSAPadding newPadding) {
271 _padding = newPadding;
272}
273
274int RSASSL::getRawOpenSSLPandingValue(RSAPadding panding) {
275 switch (panding) {
276 case NO_PADDING: return RSA_NO_PADDING;
277 case PKCS1_OAEP_PADDING: return RSA_PKCS1_OAEP_PADDING;
278 case PKCS1_PADDING: return RSA_PKCS1_PADDING;
279
280 default:
281 return 0;
282 }
283}
284
285int RSASSL::getPandingSize(RSAPadding panding) {
286 switch (panding) {
287 case PKCS1_OAEP_PADDING: return 42;
288 case PKCS1_PADDING: return 11;
289
290 default:
291 return 0;
292 }
293}
294
295RSASSL::RSABits RSASSL::bits() const {
296 return _bits;
297}
298
299void RSASSL::setBits(RSABits newBits) {
300 _bits = newBits;
301}
302
303}
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:295
void setBits(RSABits newBits)
setBits sets new value of the rsa key generator.
Definition rsassl.cpp:299
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:266
void setPadding(RSAPadding newPadding)
setPadding This method sets new mode for encryption pendong.
Definition rsassl.cpp:270
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