24#include <openssl/objects.h>
25#include <openssl/bn.h>
27#include <freerdp/config.h>
30#include <winpr/assert.h>
32#include <freerdp/log.h>
33#include <freerdp/crypto/crypto.h>
36#include "privatekey.h"
38#define TAG FREERDP_TAG("crypto")
40static SSIZE_T crypto_rsa_common(
const BYTE* input,
size_t length, UINT32 key_length,
41 const BYTE* modulus,
const BYTE* exponent,
size_t exponent_size,
42 BYTE* output,
size_t out_length)
44 BN_CTX* ctx =
nullptr;
45 int output_length = -1;
46 BYTE* input_reverse =
nullptr;
47 BYTE* modulus_reverse =
nullptr;
48 BYTE* exponent_reverse =
nullptr;
49 BIGNUM* mod =
nullptr;
50 BIGNUM* exp =
nullptr;
53 size_t bufferSize = 0;
55 if (!input || !modulus || !exponent || !output)
58 if (exponent_size > INT_MAX / 2)
61 if (key_length >= INT_MAX / 2 - exponent_size)
64 bufferSize = 2ULL * key_length + exponent_size;
65 if (length > bufferSize)
68 input_reverse = (BYTE*)calloc(bufferSize, 1);
73 modulus_reverse = input_reverse + key_length;
74 exponent_reverse = modulus_reverse + key_length;
75 memmove(modulus_reverse, modulus, key_length);
76 crypto_reverse(modulus_reverse, key_length);
77 memmove(exponent_reverse, exponent, exponent_size);
78 crypto_reverse(exponent_reverse, exponent_size);
79 memmove(input_reverse, input, length);
80 crypto_reverse(input_reverse, length);
82 if (!(ctx = BN_CTX_new()))
85 if (!(mod = BN_new()))
88 if (!(exp = BN_new()))
97 if (!BN_bin2bn(modulus_reverse, (
int)key_length, mod))
100 if (!BN_bin2bn(exponent_reverse, (
int)exponent_size, exp))
102 if (!BN_bin2bn(input_reverse, (
int)length, x))
104 if (BN_mod_exp(y, x, exp, mod, ctx) != 1)
107 const int len = BN_num_bytes(y);
108 if ((len < 0) || (WINPR_ASSERTING_INT_CAST(
size_t, len) > out_length))
110 output_length = BN_bn2bin(y, output);
112 if (output_length < 0)
114 crypto_reverse(output, WINPR_ASSERTING_INT_CAST(
size_t, output_length));
116 if ((
size_t)output_length < key_length)
118 size_t diff = key_length - WINPR_ASSERTING_INT_CAST(
size_t, output_length);
119 if ((
size_t)output_length + diff > out_length)
120 diff = out_length - (size_t)output_length;
121 memset(output + output_length, 0, diff);
131 return output_length;
134static SSIZE_T crypto_rsa_public(
const BYTE* input,
size_t length,
const rdpCertInfo* cert,
135 BYTE* output,
size_t output_length)
138 return crypto_rsa_common(input, length, cert->ModulusLength, cert->Modulus, cert->exponent,
139 sizeof(cert->exponent), output, output_length);
142static SSIZE_T crypto_rsa_private(
const BYTE* input,
size_t length,
const rdpPrivateKey* key,
143 BYTE* output,
size_t output_length)
146 const rdpCertInfo* info = freerdp_key_get_info(key);
149 size_t PrivateExponentLength = 0;
150 const BYTE* PrivateExponent = freerdp_key_get_exponent(key, &PrivateExponentLength);
151 return crypto_rsa_common(input, length, info->ModulusLength, info->Modulus, PrivateExponent,
152 PrivateExponentLength, output, output_length);
155SSIZE_T crypto_rsa_public_encrypt(
const BYTE* input,
size_t length,
const rdpCertInfo* cert,
156 BYTE* output,
size_t output_length)
158 return crypto_rsa_public(input, length, cert, output, output_length);
161SSIZE_T crypto_rsa_public_decrypt(
const BYTE* input,
size_t length,
const rdpCertInfo* cert,
162 BYTE* output,
size_t output_length)
164 return crypto_rsa_public(input, length, cert, output, output_length);
167SSIZE_T crypto_rsa_private_encrypt(
const BYTE* input,
size_t length,
const rdpPrivateKey* key,
168 BYTE* output,
size_t output_length)
170 return crypto_rsa_private(input, length, key, output, output_length);
173SSIZE_T crypto_rsa_private_decrypt(
const BYTE* input,
size_t length,
const rdpPrivateKey* key,
174 BYTE* output,
size_t output_length)
176 return crypto_rsa_private(input, length, key, output, output_length);
179void crypto_reverse(BYTE* data,
size_t length)
184 for (
size_t i = 0, j = length - 1; i < j; i++, j--)
186 const BYTE temp = data[i];
192char* crypto_read_pem(
const char* WINPR_RESTRICT filename,
size_t* WINPR_RESTRICT plength)
197 WINPR_ASSERT(filename);
202 fp = winpr_fopen(filename,
"r");
207 const int rs = _fseeki64(fp, 0, SEEK_END);
213 const int64_t size = _ftelli64(fp);
218 const int rc = _fseeki64(fp, 0, SEEK_SET);
223 pem = calloc(WINPR_ASSERTING_INT_CAST(
size_t, size) + 1,
sizeof(
char));
228 const size_t fr = fread(pem, (
size_t)size, 1, fp);
234 *plength = strnlen(pem, WINPR_ASSERTING_INT_CAST(
size_t, size));
241 char buffer[8192] = WINPR_C_ARRAY_INIT;
242 WLog_WARN(TAG,
"Failed to read PEM from file '%s' [%s]", filename,
243 winpr_strerror(errno, buffer,
sizeof(buffer)));
251BOOL crypto_write_pem(
const char* WINPR_RESTRICT filename,
const char* WINPR_RESTRICT pem,
254 WINPR_ASSERT(filename);
255 WINPR_ASSERT(pem || (length == 0));
257 WINPR_ASSERT(filename);
260 const size_t size = strnlen(pem, length) + 1;
262 FILE* fp = winpr_fopen(filename,
"w");
265 rc = fwrite(pem, 1, size, fp);
270 char buffer[8192] = WINPR_C_ARRAY_INIT;
271 WLog_WARN(TAG,
"Failed to write PEM [%" PRIuz
"] to file '%s' [%s]", length, filename,
272 winpr_strerror(errno, buffer,
sizeof(buffer)));