From 39454f69c4f112aab63598e2a75ca59b46d0d452 Mon Sep 17 00:00:00 2001 From: JeremyTubongbanua Date: Mon, 23 Sep 2024 18:46:49 +0000 Subject: [PATCH 1/9] feat: pkcs1 generation working --- packages/atchops/include/atchops/rsa_key.h | 8 ++ packages/atchops/src/rsa.c | 6 - packages/atchops/src/rsa_key.c | 158 ++++++++++++++++++++- packages/atchops/tests/test_rsa_generate.c | 27 ++++ 4 files changed, 190 insertions(+), 9 deletions(-) create mode 100644 packages/atchops/tests/test_rsa_generate.c diff --git a/packages/atchops/include/atchops/rsa_key.h b/packages/atchops/include/atchops/rsa_key.h index c41894a4..35ad5b46 100644 --- a/packages/atchops/include/atchops/rsa_key.h +++ b/packages/atchops/include/atchops/rsa_key.h @@ -45,6 +45,14 @@ int atchops_rsa_key_public_key_clone(const atchops_rsa_key_public_key *src, atch */ int atchops_rsa_key_private_key_clone(const atchops_rsa_key_private_key *src, atchops_rsa_key_private_key *dst); +/** + * @brief Generate a new RSA 2048 key pair (public and private) + * + * @param public_key the public key struct to populate, assumed to be allocated and initialized. initialized via atchops_rsa_key_public_key_init + * @param private_key the private key struct to populate, assumed to be allocated and initialized. initialized via atchops_rsa_key_private_key_init + */ +int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa_key_private_key *private_key); + /** * @brief Populate a public key struct from a base64 string * diff --git a/packages/atchops/src/rsa.c b/packages/atchops/src/rsa.c index b1199dee..628f89c9 100644 --- a/packages/atchops/src/rsa.c +++ b/packages/atchops/src/rsa.c @@ -407,9 +407,3 @@ exit: { return ret; } } - -int atchops_rsa_generate(atchops_rsa_key_public_key *public_key, atchops_rsa_key_private_key *private_key, - const unsigned int key_size) { - // TODO maybe also introduce `enum atchops_rsa_key_size` ? - return 1; // TODO: implement -} diff --git a/packages/atchops/src/rsa_key.c b/packages/atchops/src/rsa_key.c index 45d52347..197dfb1b 100644 --- a/packages/atchops/src/rsa_key.c +++ b/packages/atchops/src/rsa_key.c @@ -1,5 +1,6 @@ #include "atchops/rsa_key.h" #include "atchops/base64.h" +#include "atchops/constants.h" #include "atchops/mbedtls.h" #include #include @@ -177,6 +178,155 @@ int atchops_rsa_key_private_key_clone(const atchops_rsa_key_private_key *src, at exit: { return ret; } } +int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa_key_private_key *private_key) { + int ret = 1; + + /* + * 1. Validate arguments + */ + if (public_key == NULL) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "public_key is null\n"); + return ret; + } + + if (private_key == NULL) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "private_key is null\n"); + return ret; + } + + /* + * 2. Variables + */ + mbedtls_entropy_context entropy; + mbedtls_entropy_init(&entropy); + + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ctr_drbg_init(&ctr_drbg); + + mbedtls_pk_context pk; + mbedtls_pk_init(&pk); + + const size_t public_key_base64_size = 1024; // 1024 bytes is sufficient size for a 2048 bit RSA key base64 encoded + char public_key_base64[public_key_base64_size]; + memset(public_key_base64, 0, sizeof(char) * public_key_base64_size); + + const size_t private_key_base64_size = 2048; // 2048 bytes is sufficient size for a 2048 bit RSA key base64 encoded + char private_key_base64[private_key_base64_size]; + memset(private_key_base64, 0, sizeof(char) * private_key_base64_size); + + const size_t temp_buf_size = 8192; + unsigned char temp_buf[temp_buf_size]; // temporary buffer for formatting purposes + + /* + * 3. Seed RNG + */ + if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + (const unsigned char *)ATCHOPS_RNG_PERSONALIZATION, + strlen(ATCHOPS_RNG_PERSONALIZATION))) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to seed random number generator\n"); + goto exit; + } + + /* + * 4. Use MbedTLS to generate RSA key pair + */ + if ((ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA))) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to setup RSA key\n"); + goto exit; + } + + if ((ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(pk), mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to generate RSA key\n"); + goto exit; + } + + /* + * 5. Write to public_key_base64 buffer + */ + memset(temp_buf, 0, sizeof(temp_buf)); + if ((ret = mbedtls_pk_write_pubkey_pem(&pk, temp_buf, temp_buf_size)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to write public key\n"); + goto exit; + } + // log temp buf + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "temp_buf: %s\n", temp_buf); + + size_t public_key_base64_len = 0; + char *begin = strstr((char *)temp_buf, "-----BEGIN PUBLIC KEY-----"); + char *end = strstr((char *)temp_buf, "-----END PUBLIC KEY-----"); + if (begin != NULL && end != NULL) { + // Move begin pointer to start of base64 content + begin += strlen("-----BEGIN PUBLIC KEY-----"); + while (*begin == '\n' || *begin == '\r' || *begin == ' ') + begin++; // Skip newlines, carriage returns, and spaces + + // Copy base64 content + for (char *src = begin, *dest = public_key_base64; src < end; ++src) { + if (*src != '\n' && *src != '\r') { // Skip newlines and carriage returns + *dest++ = *src; + public_key_base64_len++; + } + } + } + + /* + * 6. Write to private_key_base64 buffer + */ + memset(temp_buf, 0, sizeof(temp_buf)); + if ((ret = mbedtls_pk_write_key_pem(&pk, temp_buf, temp_buf_size)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to write private key\n"); + goto exit; + } + // log temp buf + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "temp_buf: %s\n", temp_buf); + + size_t private_key_base64_len = 0; + begin = strstr((char *)temp_buf, "-----BEGIN RSA PRIVATE KEY-----"); + end = strstr((char *)temp_buf, "-----END RSA PRIVATE KEY-----"); + if (begin != NULL && end != NULL) { + // Move begin pointer to start of base64 content + begin += strlen("-----BEGIN RSA PRIVATE KEY-----"); + while (*begin == '\n' || *begin == '\r' || *begin == ' ') + begin++; // Skip newlines, carriage returns, and spaces + + // Copy base64 content + for (char *src = begin, *dest = private_key_base64; src < end; ++src) { + if (*src != '\n' && *src != '\r') { // Skip newlines and carriage returns + *dest++ = *src; + private_key_base64_len++; + } + } + } + + /* + * 7. Populate the atchops_rsa_key_public_key and atchops_rsa_key_private_key structs + */ + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "Public Key (%lu): %s\n", public_key_base64_len, public_key_base64); + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "Private Key (%lu): %s\n", private_key_base64_len, + private_key_base64); + + if ((ret = atchops_rsa_key_populate_public_key(public_key, (const char *)public_key_base64, public_key_base64_len)) != + 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to populate public key\n"); + goto exit; + } + + if ((ret = atchops_rsa_key_populate_private_key(private_key, (const char *)private_key_base64, + private_key_base64_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to populate private key\n"); + goto exit; + } + +exit: { + mbedtls_pk_free(&pk); + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + return ret; +} +} + int atchops_rsa_key_populate_public_key(atchops_rsa_key_public_key *public_key, const char *public_key_base64, const size_t public_key_base64_len) { int ret = 1; @@ -395,7 +545,8 @@ exit: { } bool atchops_rsa_key_is_public_key_populated(const atchops_rsa_key_public_key *public_key) { - return atchops_rsa_key_public_key_is_n_initialized(public_key) && atchops_rsa_key_public_key_is_e_initialized(public_key); + return atchops_rsa_key_public_key_is_n_initialized(public_key) && + atchops_rsa_key_public_key_is_e_initialized(public_key); } bool atchops_rsa_key_is_private_key_populated(const atchops_rsa_key_private_key *private_key) { @@ -1058,7 +1209,8 @@ bool atchops_rsa_key_private_key_is_q_initialized(const atchops_rsa_key_private_ return private_key->q._is_value_initialized; } -void atchops_rsa_key_private_key_set_q_initialized(atchops_rsa_key_private_key *private_key, const bool is_initialized) { +void atchops_rsa_key_private_key_set_q_initialized(atchops_rsa_key_private_key *private_key, + const bool is_initialized) { /* * 1. Validate arguments */ @@ -1074,7 +1226,7 @@ void atchops_rsa_key_private_key_set_q_initialized(atchops_rsa_key_private_key * } int atchops_rsa_key_private_key_set_q(atchops_rsa_key_private_key *private_key, const unsigned char *q, - const size_t q_len) { + const size_t q_len) { int ret = 1; /* diff --git a/packages/atchops/tests/test_rsa_generate.c b/packages/atchops/tests/test_rsa_generate.c new file mode 100644 index 00000000..66549aed --- /dev/null +++ b/packages/atchops/tests/test_rsa_generate.c @@ -0,0 +1,27 @@ + +#include +#include + +int main() { + + int ret = 1; + + atlogger_set_logging_level(ATLOGGER_LOGGING_LEVEL_DEBUG); + + atchops_rsa_key_public_key public_key; + atchops_rsa_key_public_key_init(&public_key); + + atchops_rsa_key_private_key private_key; + atchops_rsa_key_private_key_init(&private_key); + + if ((ret = atchops_rsa_key_generate(&public_key, &private_key)) != 0) { + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to generate RSA key pair\n"); + goto exit; + } + +exit: { + atchops_rsa_key_public_key_free(&public_key); + atchops_rsa_key_private_key_free(&private_key); + return ret; +} +} \ No newline at end of file From eb6de5902c060dbd72f47044ed045fa8459245b7 Mon Sep 17 00:00:00 2001 From: JeremyTubongbanua Date: Mon, 23 Sep 2024 19:10:34 +0000 Subject: [PATCH 2/9] wip: --- packages/atchops/src/rsa_key.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/packages/atchops/src/rsa_key.c b/packages/atchops/src/rsa_key.c index 197dfb1b..9e4cb809 100644 --- a/packages/atchops/src/rsa_key.c +++ b/packages/atchops/src/rsa_key.c @@ -251,20 +251,19 @@ int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa goto exit; } // log temp buf - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "temp_buf: %s\n", temp_buf); + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "temp_buf (public key): %s\n", temp_buf); size_t public_key_base64_len = 0; char *begin = strstr((char *)temp_buf, "-----BEGIN PUBLIC KEY-----"); char *end = strstr((char *)temp_buf, "-----END PUBLIC KEY-----"); if (begin != NULL && end != NULL) { - // Move begin pointer to start of base64 content + begin += strlen("-----BEGIN PUBLIC KEY-----"); while (*begin == '\n' || *begin == '\r' || *begin == ' ') - begin++; // Skip newlines, carriage returns, and spaces + begin++; - // Copy base64 content for (char *src = begin, *dest = public_key_base64; src < end; ++src) { - if (*src != '\n' && *src != '\r') { // Skip newlines and carriage returns + if (*src != '\n' && *src != '\r') { *dest++ = *src; public_key_base64_len++; } @@ -272,28 +271,26 @@ int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa } /* - * 6. Write to private_key_base64 buffer + * 6. Write to private_key_base64 buffer (PKCS#8 format) */ memset(temp_buf, 0, sizeof(temp_buf)); if ((ret = mbedtls_pk_write_key_pem(&pk, temp_buf, temp_buf_size)) != 0) { - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to write private key\n"); + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to write private key (PKCS#8 format)\n"); goto exit; } // log temp buf - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "temp_buf: %s\n", temp_buf); + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "temp_buf (private key): %s\n", temp_buf); size_t private_key_base64_len = 0; begin = strstr((char *)temp_buf, "-----BEGIN RSA PRIVATE KEY-----"); end = strstr((char *)temp_buf, "-----END RSA PRIVATE KEY-----"); if (begin != NULL && end != NULL) { - // Move begin pointer to start of base64 content begin += strlen("-----BEGIN RSA PRIVATE KEY-----"); while (*begin == '\n' || *begin == '\r' || *begin == ' ') - begin++; // Skip newlines, carriage returns, and spaces + begin++; - // Copy base64 content for (char *src = begin, *dest = private_key_base64; src < end; ++src) { - if (*src != '\n' && *src != '\r') { // Skip newlines and carriage returns + if (*src != '\n' && *src != '\r') { *dest++ = *src; private_key_base64_len++; } From 1b8e1f0b3c7cf9bf685ea8ea0b23f09e0eed3f60 Mon Sep 17 00:00:00 2001 From: JeremyTubongbanua Date: Mon, 23 Sep 2024 21:24:14 +0000 Subject: [PATCH 3/9] chore: Remove debug logs --- packages/atchops/src/rsa_key.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/atchops/src/rsa_key.c b/packages/atchops/src/rsa_key.c index 9e4cb809..8930da39 100644 --- a/packages/atchops/src/rsa_key.c +++ b/packages/atchops/src/rsa_key.c @@ -250,8 +250,6 @@ int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to write public key\n"); goto exit; } - // log temp buf - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "temp_buf (public key): %s\n", temp_buf); size_t public_key_base64_len = 0; char *begin = strstr((char *)temp_buf, "-----BEGIN PUBLIC KEY-----"); @@ -278,8 +276,6 @@ int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to write private key (PKCS#8 format)\n"); goto exit; } - // log temp buf - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "temp_buf (private key): %s\n", temp_buf); size_t private_key_base64_len = 0; begin = strstr((char *)temp_buf, "-----BEGIN RSA PRIVATE KEY-----"); @@ -300,9 +296,6 @@ int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa /* * 7. Populate the atchops_rsa_key_public_key and atchops_rsa_key_private_key structs */ - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "Public Key (%lu): %s\n", public_key_base64_len, public_key_base64); - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "Private Key (%lu): %s\n", private_key_base64_len, - private_key_base64); if ((ret = atchops_rsa_key_populate_public_key(public_key, (const char *)public_key_base64, public_key_base64_len)) != 0) { From 5c43ccb11164c9d827158974f35970cc6f2cd082 Mon Sep 17 00:00:00 2001 From: JeremyTubongbanua Date: Thu, 26 Sep 2024 16:30:14 +0000 Subject: [PATCH 4/9] feat: YAY generate working --- packages/atchops/src/rsa_key.c | 90 +++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/packages/atchops/src/rsa_key.c b/packages/atchops/src/rsa_key.c index 8930da39..7f0593ae 100644 --- a/packages/atchops/src/rsa_key.c +++ b/packages/atchops/src/rsa_key.c @@ -216,6 +216,10 @@ int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa char private_key_base64[private_key_base64_size]; memset(private_key_base64, 0, sizeof(char) * private_key_base64_size); + unsigned char *private_key_non_base64 = NULL; + unsigned char *private_key_pkcs8 = NULL; + char *private_key_pkcs8_base64 = NULL; + const size_t temp_buf_size = 8192; unsigned char temp_buf[temp_buf_size]; // temporary buffer for formatting purposes @@ -293,6 +297,78 @@ int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa } } + const size_t private_key_non_base64_size = atchops_base64_decoded_size(private_key_base64_len); + private_key_non_base64 = (unsigned char *)malloc(private_key_non_base64_size); + if(private_key_non_base64 == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to allocate memory for private_key_non_base64\n"); + goto exit; + } + + size_t private_key_non_base64_len = 0; + if((ret = atchops_base64_decode((const unsigned char *)private_key_base64, private_key_base64_len, private_key_non_base64, + private_key_non_base64_size, &private_key_non_base64_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to decode private key\n"); + goto exit; + } + + const size_t private_key_pkcs8_size = private_key_non_base64_len + 22; + private_key_pkcs8 = (unsigned char *)malloc(private_key_pkcs8_size); + if(private_key_pkcs8 == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to allocate memory for private_key_pkcs8\n"); + goto exit; + } + memset(private_key_pkcs8, 0, sizeof(unsigned char) * private_key_pkcs8_size); + // PrivateKeyInfo SEQUENCE (3 elements) + private_key_pkcs8[0] = 0x30; // constructed sequence tag + private_key_pkcs8[1] = 0x82; // 8 --> 1000 0000 (1 in MSB means that it is long form) and 2 --> 0010 0000 (the next 2 bytes are the length of data) + private_key_pkcs8[2] = (unsigned char)((private_key_pkcs8_size >> 8) & 0xFF); + private_key_pkcs8[3] = (unsigned char)(private_key_pkcs8_size & 0xFF); + + // version INTEGER 0 + private_key_pkcs8[4] = 0x02; // integer tag + private_key_pkcs8[5] = 0x01; // length of data + private_key_pkcs8[6] = 0x00; // data + + // private key algorithm identifier + private_key_pkcs8[7] = 0x30; // constructed sequence tag + private_key_pkcs8[8] = 0x0D; // there are 2 elements in the sequence + private_key_pkcs8[9] = 0x06; + private_key_pkcs8[10] = 0x09; + private_key_pkcs8[11] = 0x2A; + private_key_pkcs8[12] = 0x86; + private_key_pkcs8[13] = 0x48; + private_key_pkcs8[14] = 0x86; + private_key_pkcs8[15] = 0xF7; + private_key_pkcs8[16] = 0x0D; + private_key_pkcs8[17] = 0x01; + private_key_pkcs8[18] = 0x01; + private_key_pkcs8[19] = 0x01; + private_key_pkcs8[20] = 0x05; + private_key_pkcs8[21] = 0x00; + + // PrivateKey OCTET STRING + private_key_pkcs8[22] = 0x04; // octet string tag + private_key_pkcs8[23] = 0x82; // 8 --> 1000 0000 (1 in MSB means that it is long form) and 2 --> 0010 0000 (the next 2 bytes are the length of data) + private_key_pkcs8[24] = (unsigned char)((private_key_non_base64_len >> 8) & 0xFF); // length of data + private_key_pkcs8[25] = (unsigned char)(private_key_non_base64_len & 0xFF); // length of data + + memcpy(private_key_pkcs8 + 26, private_key_non_base64, private_key_non_base64_len); + + const size_t private_key_base64_pkcs8_size = atchops_base64_encoded_size(private_key_non_base64_len); + private_key_pkcs8_base64 = (char *)malloc(private_key_base64_pkcs8_size); + if(private_key_pkcs8_base64 == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to allocate memory for private_key_pkcs8_base64\n"); + goto exit; + } + memset(private_key_pkcs8_base64, 0, sizeof(char) * private_key_base64_pkcs8_size); + + size_t private_key_base64_pkcs8_len = 0; + if ((ret = atchops_base64_encode(private_key_pkcs8, 26 + private_key_non_base64_len, private_key_pkcs8_base64, + private_key_base64_pkcs8_size, &private_key_base64_pkcs8_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to encode private key\n"); + goto exit; + } + /* * 7. Populate the atchops_rsa_key_public_key and atchops_rsa_key_private_key structs */ @@ -303,8 +379,8 @@ int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa goto exit; } - if ((ret = atchops_rsa_key_populate_private_key(private_key, (const char *)private_key_base64, - private_key_base64_len)) != 0) { + if ((ret = atchops_rsa_key_populate_private_key(private_key, (const char *)private_key_pkcs8_base64, + private_key_base64_pkcs8_len)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to populate private key\n"); goto exit; } @@ -313,6 +389,15 @@ exit: { mbedtls_pk_free(&pk); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); + if(private_key_non_base64 != NULL) { + free(private_key_non_base64); + } + if(private_key_pkcs8_base64 != NULL) { + free(private_key_pkcs8_base64); + } + if(private_key_pkcs8 != NULL) { + free(private_key_pkcs8); + } return ret; } } @@ -471,6 +556,7 @@ int atchops_rsa_key_populate_private_key(atchops_rsa_key_private_key *private_ke } p = p + lengthread2; + size_t lengthread3 = 0; if ((ret = mbedtls_asn1_get_tag(&p, end, &lengthread3, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to get tag 3\n"); From 912b3fe94bf0965a8bbeebee504dd5465e1c99ad Mon Sep 17 00:00:00 2001 From: JeremyTubongbanua Date: Thu, 26 Sep 2024 16:32:33 +0000 Subject: [PATCH 5/9] chore: logging in test --- packages/atchops/tests/test_rsa_generate.c | 51 ++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/packages/atchops/tests/test_rsa_generate.c b/packages/atchops/tests/test_rsa_generate.c index 66549aed..1b29a9dd 100644 --- a/packages/atchops/tests/test_rsa_generate.c +++ b/packages/atchops/tests/test_rsa_generate.c @@ -19,6 +19,57 @@ int main() { goto exit; } + // log the public key + if (atchops_rsa_key_is_public_key_populated(&public_key)) { + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "Public Key:\n"); + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "N: "); + for (size_t i = 0; i < public_key.n.len; i++) { + printf("%02x ", public_key.n.value[i]); + } + printf("\n"); + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "E: "); + for (size_t i = 0; i < public_key.e.len; i++) { + printf("%02x ", public_key.e.value[i]); + } + printf("\n"); + } else { + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_ERROR, "Public key is not populated\n"); + goto exit; + } + + // log the private key + if (atchops_rsa_key_is_private_key_populated(&private_key)) { + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "Private Key:\n"); + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "N: "); + for (size_t i = 0; i < private_key.n.len; i++) { + printf("%02x ", private_key.n.value[i]); + } + printf("\n"); + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "E: "); + for (size_t i = 0; i < private_key.e.len; i++) { + printf("%02x ", private_key.e.value[i]); + } + printf("\n"); + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "D: "); + for (size_t i = 0; i < private_key.d.len; i++) { + printf("%02x ", private_key.d.value[i]); + } + printf("\n"); + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "P: "); + for (size_t i = 0; i < private_key.p.len; i++) { + printf("%02x ", private_key.p.value[i]); + } + printf("\n"); + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "Q: "); + for (size_t i = 0; i < private_key.q.len; i++) { + printf("%02x ", private_key.q.value[i]); + } + printf("\n"); + } else { + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_ERROR, "Private key is not populated\n"); + goto exit; + } + exit: { atchops_rsa_key_public_key_free(&public_key); atchops_rsa_key_private_key_free(&private_key); From eab2c50ea6a4cfdf5186f5bac99685ee7c4a6a28 Mon Sep 17 00:00:00 2001 From: JeremyTubongbanua Date: Thu, 26 Sep 2024 16:36:57 +0000 Subject: [PATCH 6/9] chore: edit buffer sizes, misc changes, and comments --- packages/atchops/src/rsa_key.c | 55 ++++++++++++++++------------------ 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/packages/atchops/src/rsa_key.c b/packages/atchops/src/rsa_key.c index 7f0593ae..b2e76211 100644 --- a/packages/atchops/src/rsa_key.c +++ b/packages/atchops/src/rsa_key.c @@ -9,8 +9,6 @@ #define TAG "rsa_key" -#define BASE64_DECODED_KEY_BUFFER_SIZE 8192 // the max buffer size of a decoded RSA key - void atchops_rsa_key_public_key_init(atchops_rsa_key_public_key *public_key) { /* * 1. Validate arguments @@ -216,12 +214,14 @@ int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa char private_key_base64[private_key_base64_size]; memset(private_key_base64, 0, sizeof(char) * private_key_base64_size); - unsigned char *private_key_non_base64 = NULL; - unsigned char *private_key_pkcs8 = NULL; - char *private_key_pkcs8_base64 = NULL; + unsigned char *private_key_non_base64 = + NULL; // holds the raw bytes of the 9 element SEQUENCE of the numbers (0, N, E, D, P, Q, DP, DQ, QP), free later + + unsigned char *private_key_pkcs8 = NULL; // buffer for building the pkcs_8 formatted private key, free later + char *private_key_pkcs8_base64 = NULL; // to hold the base64-encoded pkcs 8 formatted private key, free later - const size_t temp_buf_size = 8192; - unsigned char temp_buf[temp_buf_size]; // temporary buffer for formatting purposes + const size_t temp_buf_size = 4096; // sufficient to hold a private RSA Key in format ----BEGIN .... + unsigned char temp_buf[temp_buf_size]; /* * 3. Seed RNG @@ -275,7 +275,7 @@ int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa /* * 6. Write to private_key_base64 buffer (PKCS#8 format) */ - memset(temp_buf, 0, sizeof(temp_buf)); + memset(temp_buf, 0, sizeof(unsigned char) * temp_buf_size); if ((ret = mbedtls_pk_write_key_pem(&pk, temp_buf, temp_buf_size)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to write private key (PKCS#8 format)\n"); goto exit; @@ -299,28 +299,31 @@ int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa const size_t private_key_non_base64_size = atchops_base64_decoded_size(private_key_base64_len); private_key_non_base64 = (unsigned char *)malloc(private_key_non_base64_size); - if(private_key_non_base64 == NULL) { + if (private_key_non_base64 == NULL) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to allocate memory for private_key_non_base64\n"); goto exit; } size_t private_key_non_base64_len = 0; - if((ret = atchops_base64_decode((const unsigned char *)private_key_base64, private_key_base64_len, private_key_non_base64, - private_key_non_base64_size, &private_key_non_base64_len)) != 0) { + if ((ret = atchops_base64_decode((const unsigned char *)private_key_base64, private_key_base64_len, + private_key_non_base64, private_key_non_base64_size, &private_key_non_base64_len)) != + 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to decode private key\n"); goto exit; } const size_t private_key_pkcs8_size = private_key_non_base64_len + 22; private_key_pkcs8 = (unsigned char *)malloc(private_key_pkcs8_size); - if(private_key_pkcs8 == NULL) { + if (private_key_pkcs8 == NULL) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to allocate memory for private_key_pkcs8\n"); goto exit; } memset(private_key_pkcs8, 0, sizeof(unsigned char) * private_key_pkcs8_size); + // PrivateKeyInfo SEQUENCE (3 elements) private_key_pkcs8[0] = 0x30; // constructed sequence tag - private_key_pkcs8[1] = 0x82; // 8 --> 1000 0000 (1 in MSB means that it is long form) and 2 --> 0010 0000 (the next 2 bytes are the length of data) + private_key_pkcs8[1] = 0x82; // 8 --> 1000 0000 (1 in MSB means that it is long form) and 2 --> 0010 0000 (the next 2 + // bytes are the length of data) private_key_pkcs8[2] = (unsigned char)((private_key_pkcs8_size >> 8) & 0xFF); private_key_pkcs8[3] = (unsigned char)(private_key_pkcs8_size & 0xFF); @@ -348,15 +351,16 @@ int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa // PrivateKey OCTET STRING private_key_pkcs8[22] = 0x04; // octet string tag - private_key_pkcs8[23] = 0x82; // 8 --> 1000 0000 (1 in MSB means that it is long form) and 2 --> 0010 0000 (the next 2 bytes are the length of data) + private_key_pkcs8[23] = 0x82; // 8 --> 1000 0000 (1 in MSB means that it is long form) and 2 --> 0010 0000 (the next 2 + // bytes are the length of data) private_key_pkcs8[24] = (unsigned char)((private_key_non_base64_len >> 8) & 0xFF); // length of data - private_key_pkcs8[25] = (unsigned char)(private_key_non_base64_len & 0xFF); // length of data + private_key_pkcs8[25] = (unsigned char)(private_key_non_base64_len & 0xFF); // length of data memcpy(private_key_pkcs8 + 26, private_key_non_base64, private_key_non_base64_len); const size_t private_key_base64_pkcs8_size = atchops_base64_encoded_size(private_key_non_base64_len); private_key_pkcs8_base64 = (char *)malloc(private_key_base64_pkcs8_size); - if(private_key_pkcs8_base64 == NULL) { + if (private_key_pkcs8_base64 == NULL) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to allocate memory for private_key_pkcs8_base64\n"); goto exit; } @@ -364,7 +368,7 @@ int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa size_t private_key_base64_pkcs8_len = 0; if ((ret = atchops_base64_encode(private_key_pkcs8, 26 + private_key_non_base64_len, private_key_pkcs8_base64, - private_key_base64_pkcs8_size, &private_key_base64_pkcs8_len)) != 0) { + private_key_base64_pkcs8_size, &private_key_base64_pkcs8_len)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to encode private key\n"); goto exit; } @@ -389,15 +393,9 @@ exit: { mbedtls_pk_free(&pk); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); - if(private_key_non_base64 != NULL) { - free(private_key_non_base64); - } - if(private_key_pkcs8_base64 != NULL) { - free(private_key_pkcs8_base64); - } - if(private_key_pkcs8 != NULL) { - free(private_key_pkcs8); - } + free(private_key_non_base64); + free(private_key_pkcs8_base64); + free(private_key_pkcs8); return ret; } } @@ -432,7 +430,7 @@ int atchops_rsa_key_populate_public_key(atchops_rsa_key_public_key *public_key, */ mbedtls_asn1_sequence *seq = NULL; // free later - const size_t dst_size = BASE64_DECODED_KEY_BUFFER_SIZE; + const size_t dst_size = 2048; // sufficient size for a 2048 bit RSA key unsigned char dst[dst_size]; memset(dst, 0, sizeof(unsigned char) * dst_size); size_t dst_len = 0; @@ -530,7 +528,7 @@ int atchops_rsa_key_populate_private_key(atchops_rsa_key_private_key *private_ke */ mbedtls_asn1_sequence *seq = NULL; // free later - const size_t dst_size = BASE64_DECODED_KEY_BUFFER_SIZE; + const size_t dst_size = 4096; // sufficient size for a 2048 bit RSA private key unsigned char dst[dst_size]; memset(dst, 0, sizeof(unsigned char) * dst_size); size_t dst_len = 0; @@ -556,7 +554,6 @@ int atchops_rsa_key_populate_private_key(atchops_rsa_key_private_key *private_ke } p = p + lengthread2; - size_t lengthread3 = 0; if ((ret = mbedtls_asn1_get_tag(&p, end, &lengthread3, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to get tag 3\n"); From 24031466100a062f27fd2859ce5604a431b3f644 Mon Sep 17 00:00:00 2001 From: JeremyTubongbanua Date: Thu, 26 Sep 2024 16:40:18 +0000 Subject: [PATCH 7/9] chore: add a PKCS 8 formated key frmo C SDK --- packages/atchops/tests/test_rsadecrypt.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/atchops/tests/test_rsadecrypt.c b/packages/atchops/tests/test_rsadecrypt.c index ba95b16d..66c983e9 100644 --- a/packages/atchops/tests/test_rsadecrypt.c +++ b/packages/atchops/tests/test_rsadecrypt.c @@ -1,9 +1,14 @@ #include "atchops/rsa.h" +#include #include #include #include -#include +// a pkcs8 formatted key in base64 from C SDK generation +// #define PRIVATEKEYBASE64 +// "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzn72C2fNOzP3Uwy3gkSQiYPQalzMIJnyM51amjYzsaP20CNo5y2NQV6Nx1bwcpn1MBoPx4AK26hD7d9ijjOS2lU5glPiSf0ZA68e24zi7NsyRgvD1jhYH2H8coNc7eRlukfy/7BbJsf2H33CBcjLPXEdp46kdABqP6iudbXzG33HQKGnfjaaQWWHePdNU3T1btTQJ8Mv+sH+caJ6DdRu95ZdKuoiVip7qHCZ2jlNHn46BJjSL9r2MiYF2i4G/pkdmSVvC15xnp/x13f+GDKIMAerj62I0UyGasTJQlfEn1wYBNlghKlIyyMSsFpv9Ugi/R06gK3GGTaeL7kZmNQ8JAgMBAAECggEAESCVKGnxyjy/o07tC/Gq+WA3RmXOZuOMkr7oQz9SBaTJNCZ38HTVRm7k1dDke/LgFaS1ZhXPDHPrJJ871/RyRnqcG5d40Dc0krIou+aUnT1PajyLD076CMt661bmzvPwGdvvtrkjPx4qp48FokIqWB1bbdxYXryIy9ovSHaNJEU3IYpuUA0BW3798rshwQK1UlrK0BdStfXPpmN7sCdbymb4atJynFqoZph0BobC4hXgXaxSeNhY5pIGfuQd97etFq9v3sFcn6ZjwDJzRormff4E7TbRHQ9Yl2b0tb1kz2cpUFqAr7ap32Re6LZ8TD32GVTRYVriFAn6v2OmwuXU5QKBgQDdgLiBEE07RUqwLPNR8CmnIiJxopxMld7lJFWcwNOE4fxsOZzLnz2Xwl21f/Xyo33RxAMNuW9PvqIoTfVRT0AfnDINp4GU7GlvFdtWWQ7kJLAAqklzEyU/57g9s3m34fpzIOOTxABucUGgfonfm2EdJ07FdEUoGIUaNvONAVJhiwKBgQDPmVFat8PIOcvRiO+KMgHHQmBdGR6NiAOOvpJ93OOMN6+JInNXKxiE1Iv8agw20hCtOx9LewgoACw12UqSHC+4BJHasjTUrrKiklmdDMjFSC9XrZ6PuTpugu/wM6h4fhwf3K9PEVx1mDlAZoSfwhQ4MGkqKbewqvGw9S7oz5Q8OwKBgQCmcFuzd2lhGR8XJJ+tOTZDRQ32r0ac8ZysN9Iw2F/YIOtI8z2Tb9ObXkyF3mIT8a/QWGYnAOjYVhmJCZNFhrRbTEX8JprjKYXMF/NZfdAHtF2gElTgqEk8LMUvb9YNSzujGNqIpSXh1y6GB69YG2wsuOWiz0xL5ajWWuZFVPHvIwKBgDrbuEIlOeAJ6uyki22+Ed0Bx7p9hbkQ6BlPlM8UkntNynnyB4ueT1xRusK8+muMkWfcDFplLoHQ0rgNvGPClBDzUrsTrYDjawhGwBuT5VRxy+Jq+jq7hIKSox6SNuC6uJScCCQ9wt4gY5MLvexhpUPtDdQDce4n+VB3o24kdF3DAoGAc4q30FsexTKZNMUekkDm3ZYdGCYoRDF5+A2JOSTqlSKubb1dfSxGPvBe55dSfO1G0yR7Z8rZcG0+6gdv6tqi+ndRVyVApGuetMK7jhiuyzYEv9dJWdvVBg5T7+ElaKUxzAEapEaLvVplg8XBjq3c1BwFFj08T+6LXd3gy1eu92g=" + +// a pkcs8 formatted key in base64 from Dart SDK generation #define PRIVATEKEYBASE64 \ "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCDc/" \ "uZ5+pmDYY1A+IQdiKeZNhRxttbYCv1aLksIP+5Fk1GJAnKlsBBum+" \ @@ -69,7 +74,5 @@ int main() { goto ret; -ret: { - return ret; -} +ret: { return ret; } } From a5819c518c566bf569c4bb2fd56def58f394f412 Mon Sep 17 00:00:00 2001 From: JeremyTubongbanua Date: Thu, 26 Sep 2024 16:43:49 +0000 Subject: [PATCH 8/9] test: improve test_rsa_generate --- packages/atchops/tests/test_rsa_generate.c | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/packages/atchops/tests/test_rsa_generate.c b/packages/atchops/tests/test_rsa_generate.c index 1b29a9dd..621a2cdb 100644 --- a/packages/atchops/tests/test_rsa_generate.c +++ b/packages/atchops/tests/test_rsa_generate.c @@ -1,7 +1,10 @@ #include +#include #include +#define PLAINTEXT "Hello, World!" + int main() { int ret = 1; @@ -14,6 +17,14 @@ int main() { atchops_rsa_key_private_key private_key; atchops_rsa_key_private_key_init(&private_key); + const size_t ciphertext_size = 256; + unsigned char ciphertext[ciphertext_size]; + memset(ciphertext, 0, sizeof(unsigned char) * ciphertext_size); + + const size_t plaintext_size = 256; + unsigned char plaintext[plaintext_size]; + memset(plaintext, 0, sizeof(unsigned char) * plaintext_size); + if ((ret = atchops_rsa_key_generate(&public_key, &private_key)) != 0) { atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to generate RSA key pair\n"); goto exit; @@ -70,6 +81,40 @@ int main() { goto exit; } + // use the public key to encrypt something + // use the private key to decrypt it + + if((ret = atchops_rsa_encrypt(&public_key, (const unsigned char *)PLAINTEXT, strlen(PLAINTEXT), ciphertext)) != 0) { + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to encrypt plaintext\n"); + goto exit; + } + + // log the ciphertext + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "Ciphertext: "); + for (size_t i = 0; i < ciphertext_size; i++) { + printf("%02x ", ciphertext[i]); + } + + size_t plaintext_len = 0; + if((ret = atchops_rsa_decrypt(&private_key, ciphertext, ciphertext_size, plaintext, plaintext_size, &plaintext_len)) != 0) { + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to decrypt ciphertext\n"); + goto exit; + } + + // log the plaintext + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_INFO, "Plaintext: "); + for (size_t i = 0; i < plaintext_len; i++) { + printf("%c", plaintext[i]); + } + printf("\n"); + + // check if plaintext is equal to PLAINTEXT + if (strncmp((const char *)plaintext, PLAINTEXT, strlen(PLAINTEXT)) != 0) { + atlogger_log("test_rsa_generate", ATLOGGER_LOGGING_LEVEL_ERROR, "Plaintext does not match original\n"); + goto exit; + } + + exit: { atchops_rsa_key_public_key_free(&public_key); atchops_rsa_key_private_key_free(&private_key); From d0cbe62296954648df0d20e6559f2623e7b7c524 Mon Sep 17 00:00:00 2001 From: JeremyTubongbanua Date: Thu, 26 Sep 2024 17:05:17 +0000 Subject: [PATCH 9/9] docs: --- packages/atchops/src/rsa_key.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/atchops/src/rsa_key.c b/packages/atchops/src/rsa_key.c index b2e76211..8ff64c9d 100644 --- a/packages/atchops/src/rsa_key.c +++ b/packages/atchops/src/rsa_key.c @@ -319,7 +319,9 @@ int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa goto exit; } memset(private_key_pkcs8, 0, sizeof(unsigned char) * private_key_pkcs8_size); - + + + // https://lapo.it/asn1js/ use this to debug // PrivateKeyInfo SEQUENCE (3 elements) private_key_pkcs8[0] = 0x30; // constructed sequence tag private_key_pkcs8[1] = 0x82; // 8 --> 1000 0000 (1 in MSB means that it is long form) and 2 --> 0010 0000 (the next 2