rsa keys base64 encoding/decoding

This commit is contained in:
2025-09-29 10:26:45 +05:00
parent 4fda6ae9e8
commit f933d30863
8 changed files with 148 additions and 139 deletions

View File

@@ -2,6 +2,7 @@
#include <assert.h>
#include "bearssl_x509.h"
#include "bearssl_pem.h"
#include "tlibc/base64.h"
// https://crypto.stackexchange.com/questions/3110/impacts-of-not-using-rsa-exponent-of-65537
#define DEFAULT_PUBLIC_EXPONENT 65537
@@ -71,110 +72,88 @@ Result(void) RSA_computePublicKey(const br_rsa_private_key* sk, br_rsa_public_ke
Return RESULT_VOID;
}
Result(void) RSA_serializePrivateKey_RawDER(
const br_rsa_private_key* sk,
NULLABLE(const br_rsa_public_key*) pk,
Array(u8)* out_der)
{
Deferral(32);
br_rsa_compute_pubexp compute_pubexp = br_rsa_i31_compute_pubexp;
br_rsa_compute_privexp compute_privexp = br_rsa_i31_compute_privexp;
br_rsa_public_key pk_computed;
if(pk == NULL){
pk = &pk_computed;
try_void(RSA_computePublicKey(sk, &pk_computed));
Defer(free(pk->n));
}
u32 pubexp_little_endian = compute_pubexp(sk);
if (pubexp_little_endian == 0) {
Return RESULT_ERROR("compute_pubexp", false);
}
size_t privexp_size = compute_privexp(NULL, sk, pubexp_little_endian);
if (privexp_size == 0) {
Return RESULT_ERROR("compute_privexp", false);
}
void* privexp = malloc(privexp_size);
Defer(free(privexp));
if (compute_privexp(privexp, sk, pubexp_little_endian) != privexp_size) {
Return RESULT_ERROR("compute_privexp", false);
}
str RSA_serializePrivateKey_base64(const br_rsa_private_key* sk){
u32 key_buffer_size = BR_RSA_KBUF_PRIV_SIZE(sk->n_bitlen);
u32 key_base64_size = base64_encodedSize(key_buffer_size);
char* serialized_buf = malloc(32 + key_base64_size);
sprintf(serialized_buf, "RSA-Private-%u:", sk->n_bitlen);
u32 offset = strlen(serialized_buf);
offset += base64_encode(sk->p, key_buffer_size, serialized_buf + offset);
serialized_buf[offset] = '\0';
return str_construct(serialized_buf, offset, true);
}
size_t der_size = br_encode_rsa_raw_der(NULL, sk, pk, privexp, privexp_size);
if (der_size == 0) {
Return RESULT_ERROR("br_encode_rsa_raw_der", false);
}
void* der = malloc(der_size);
bool success = false;
Defer(
if(!success)
free(der)
);
if (br_encode_rsa_raw_der(der, sk, pk, privexp, privexp_size) != der_size) {
Return RESULT_ERROR("br_encode_rsa_raw_der", false);
}
str RSA_serializePublicKey_base64(const br_rsa_public_key* pk){
u32 n_bitlen = pk->nlen * 8;
u32 key_buffer_size = BR_RSA_KBUF_PUB_SIZE(n_bitlen);
u32 key_base64_size = base64_encodedSize(key_buffer_size);
char* serialized_buf = malloc(32 + key_base64_size);
sprintf(serialized_buf, "RSA-Public-%u:", n_bitlen);
u32 offset = strlen(serialized_buf);
offset += base64_encode(pk->n, key_buffer_size, serialized_buf + offset);
serialized_buf[offset] = '\0';
return str_construct(serialized_buf, offset, true);
}
success = true;
out_der->data = der;
out_der->size = der_size;
Result(void) RSA_parsePublicKey_base64(const str src, br_rsa_public_key* pk){
Deferral(8);
u32 n_bitlen = 0;
if(sscanf(src.data, "RSA-Public-%u:", &n_bitlen) != 1){
Return RESULT_ERROR("can't parse key size", false);
}
u32 key_buffer_size = BR_RSA_KBUF_PUB_SIZE(n_bitlen);
pk->n = malloc(key_buffer_size);
pk->elen = 4;
pk->nlen = key_buffer_size - 4;
pk->e = pk->n + pk->nlen;
u32 offset = str_seekChar(src, ':', 14) + 1;
if(offset == 0){
Return RESULT_ERROR("missing ':' before key data", false);
}
str key_base64_str = src;
key_base64_str.data += offset;
key_base64_str.size -= offset;
u32 decoded_size = base64_decodedSize(key_base64_str.data, key_base64_str.size);
if(decoded_size != key_buffer_size){
Return RESULT_ERROR_FMT("decoded key size is %u, must be %u", decoded_size, key_buffer_size);
}
decoded_size = base64_decode(key_base64_str.data, key_base64_str.size, pk->n);
if(decoded_size != key_buffer_size){
Return RESULT_ERROR("key decoding failed", false);
}
Return RESULT_VOID;
}
void PEM_encode(Array(u8) src, Array(u8)* dst, cstr label){
u64 encoded_size = br_pem_encode(NULL, src.data, src.size, label, 0);
// br_pem_encode doesn't count '\0' but writes it
*dst = Array_alloc_size(encoded_size + 1);
br_pem_encode(dst->data, src.data, src.size, label, 0);
}
Result(void) RSA_parsePrivateKey_DER(Array(u8) _src, br_rsa_private_key* sk){
Deferral(16);
// private key data will be written in this buffer on success
Array(u8) buf = Array_copy(_src);
bool success = false;
Defer(free(buf.data));
br_skey_decoder_context decoder;
br_skey_decoder_init(&decoder);
br_skey_decoder_push(&decoder, buf.data, buf.size);
i32 errcode = br_skey_decoder_last_error(&decoder);
if (errcode != 0) {
Return RESULT_ERROR_FMT("br_skey_decoder error %i", errcode);
}
i32 parsed_type = br_skey_decoder_key_type(&decoder);
if(parsed_type != BR_KEYTYPE_RSA){
Return RESULT_ERROR_FMT("parsed key has unsupported type %i", parsed_type);
Result(void) RSA_parsePrivateKey_base64(const str src, br_rsa_private_key* sk){
Deferral(8);
u32 n_bitlen = 0;
if(sscanf(src.data, "RSA-Private-%u:", &n_bitlen) != 1){
Return RESULT_ERROR("can't parse key size", false);
}
const br_rsa_private_key* decoded_key = br_skey_decoder_get_rsa(&decoder);
if(decoded_key == NULL){
Return RESULT_ERROR("decoder failed without errors", false);
sk->n_bitlen = n_bitlen;
u32 key_buffer_size = BR_RSA_KBUF_PRIV_SIZE(n_bitlen);
u32 field_len = key_buffer_size / 5;
sk->plen = sk->qlen = sk->dplen = sk->dqlen = sk->iqlen = field_len;
sk->p = malloc(key_buffer_size);
sk->q = sk->p + field_len;
sk->dp = sk->q + field_len;
sk->dq = sk->dp + field_len;
sk->iq = sk->dq + field_len;
u32 offset = str_seekChar(src, ':', 14) + 1;
if(offset == 0){
Return RESULT_ERROR("missing ':' before key data", false);
}
success = true;
memcpy(sk, decoded_key, sizeof(*decoded_key));
// sk fields still point to stack array decoder.key_data
// This code copies the data and adjusts sk fields to point to the copied chunk
Array(u8) key_data_copy = Array_alloc_size(BR_RSA_KBUF_PRIV_SIZE(decoded_key->n_bitlen));
Defer(
if(!success)
free(key_data_copy.data);
);
memcpy(key_data_copy.data, decoder.key_data, key_data_copy.size);
u64 memory_distance = (u64)key_data_copy.data - (u64)(void*)decoder.key_data;
u8** sk_pointer_fields[] = {
&sk->p, &sk->q, &sk->dp, &sk->dq, &sk->iq
};
for(u32 i = 0; i < ARRAY_LEN(sk_pointer_fields); i++){
u8** field_place = sk_pointer_fields[i];
u64 field_value = (u64)*field_place;
field_value += memory_distance;
*field_place = (void*)field_value;
str key_base64_str = src;
key_base64_str.data += offset;
key_base64_str.size -= offset;
u32 decoded_size = base64_decodedSize(key_base64_str.data, key_base64_str.size);
if(decoded_size != key_buffer_size){
Return RESULT_ERROR_FMT("decoded key size is %u, must be %u", decoded_size, key_buffer_size);
}
decoded_size = base64_decode(key_base64_str.data, key_base64_str.size, sk->p);
if(decoded_size != key_buffer_size){
Return RESULT_ERROR("key decoding failed", false);
}
Return RESULT_VOID;
}

View File

@@ -107,24 +107,24 @@ static inline void RSA_destroyPublicKey(br_rsa_public_key* sk){
/// @param pk out public key. WARNING: .n is allocated on heap
Result(void) RSA_computePublicKey(const br_rsa_private_key* sk, br_rsa_public_key* pk);
/// @brief Serialize key in raw DER binary format
/// @param sk the private key
/// @param pk set to NULL to calculate automatically
/// @param out_der out array. WARNING: .data is allocated on heap
Result(void) RSA_serializePrivateKey_RawDER(
const br_rsa_private_key* sk,
NULLABLE(const br_rsa_public_key*) pk,
Array(u8)* out_der);
/// @brief Encode key data in human-readable format
/// @param src some data
/// @return heap-allocated string
str RSA_serializePrivateKey_base64(const br_rsa_private_key* sk);
/// @param src serialized private key format "RSA-Private-%SIZE%:%DATA_BASE64%"
/// @param sk out private key. WARNING: .p is allocated on heap
Result(void) RSA_parsePrivateKey_base64(const str src, br_rsa_private_key* sk);
/// @brief Encode key data in human-readable format
/// @param src some data
/// @param dst out array. WARNING: .data is allocated on heap
/// @param label some string to write at the top of PEM file
void PEM_encode(Array(u8) src, Array(u8)* dst, cstr label);
/// @return heap-allocated string
str RSA_serializePublicKey_base64(const br_rsa_public_key* sk);
/// @param src serialized public key format "RSA-Public-%SIZE%:%DATA_BASE64%"
/// @param sk out public key. WARNING: .p is allocated on heap
Result(void) RSA_parsePublicKey_base64(const str src, br_rsa_public_key* sk);
/// @param src serialized private key in DER format
/// @param sk out private key. WARNING: .p is allocated on heap
Result(void) RSA_parsePrivateKey_DER(Array(u8) src, br_rsa_private_key* sk);
typedef struct EncryptorRSA {
const br_rsa_public_key* pk;