I am trying to do some RSA encryption using the mbedtls library on specifically the PK API on an esp32 using the Arduino framework and PlatformIO. I can succesfully encrypt 20 bytes at a time (that is inputArray[21]). But anymore than that, and I receive the 0x4080 error code RSA - Bad input parameters to function.
According to their documentation, I should be able to (given I am using a 2048 bit key) to encrypt at the very least 200 bytes at a time.
Command prompt when running the code:
___________________PROGRAM_START_________________________
Seeding the random number generator...
Initializing key context...
Generating the private key...
ABCDEFGHIJKLMNOPQRSTUV
Error encrypting
-16512
��������@�������������
���������������������
This is my RSACryptographer object:
//
// Created by DripTooHard on 15-04-2023.
//
#include "Cryptographer.h"
class Cryptographer{
protected:
mbedtls_ctr_drbg_context CTR_ctx;
public:
Cryptographer(){
}
virtual ~Cryptographer(){}
//TODO: Add PEMformatter
virtual int encrypt(unsigned char * inputArray, size_t inputLen, unsigned char * outputArray, size_t outSize, size_t * outLen) = 0;
virtual int decrypt(unsigned char * inputArray, size_t inputLen, unsigned char * outputArray,size_t outSize, size_t * outLen) = 0;
virtual int generate_key() = 0;
virtual int validate_key() = 0;
int generate_CTRX_context(){
mbedtls_ctr_drbg_free(&CTR_ctx);
mbedtls_entropy_context entropy; //Used to seed the drbg
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&this->CTR_ctx);
Serial.println("Seeding the random number generator...");
int ret = (mbedtls_ctr_drbg_seed(&this->CTR_ctx, mbedtls_entropy_func, &entropy, NULL, 0)) != 0;
if (ret)
{
Serial.print("Error in seeding the random number generator\nmbedtls_ctr_drbg_seed returned: ");
Serial.print(ret);
return RSABooleanFalse;
//ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret);
}
return 0;
};
mbedtls_ctr_drbg_context get_CTRX_context(){
return CTR_ctx;
}
};
class RSACryptographer : public Cryptographer{
protected:
mbedtls_pk_context RSA_ctx;
public:
RSACryptographer()
{
}
~RSACryptographer(
){}
/**
*
* @param inputArray : The array which we would like to do our encryption/decryption on
* @param inputLen
* @param outputArray
* @param outLen : The length of the result (not the size of the outputArray)
* @param isEncryption : 0 if we're decrypting, 1 if we're encrypting
* @return 0 if succesfull, otherwise a specified error code
*/
int use_key(unsigned char * inputArray, size_t inputLen, unsigned char * outputArray,size_t outSize, size_t * outLen, int isEncryption){
int res;
//The input is larger than what our encryption algorithm can handle
if(inputLen>RSA_MAX_INPUT_LEN){
Serial.print("ERROR: INPUT: \n");
println_unsignedString(inputArray,inputLen,CHR);
Serial.print("EXCEEDS MAX ENCRYPTION INPUT LEN: ");
Serial.print(RSA_MAX_INPUT_LEN);
return RSA_ERR_INPUT_EXCEEDS_MAX_LEN;
}
if(isEncryption) {
res = mbedtls_pk_encrypt(&this->RSA_ctx, inputArray, inputLen, outputArray, outLen,
outSize, mbedtls_ctr_drbg_random, &this->CTR_ctx);
}
else{
res = mbedtls_pk_decrypt(&this->RSA_ctx, inputArray,inputLen, outputArray, outLen, outSize ,mbedtls_ctr_drbg_random,&this->CTR_ctx);
}
//If our output is larger than the array
if(*outLen>outSize){
Serial.println("ERROR: Output length exceeds size of the outputArray");
Serial.println(*outLen);
Serial.println(outSize);
return RSA_ERR_OUTPUT_EXCEEDS_OUTPUT_ARRAY_LEN;
}
return res;
}
int encrypt(unsigned char * inputArray, size_t inputLen, unsigned char * outputArray,size_t outSize, size_t * outLen){
return use_key(inputArray, inputLen, outputArray, outSize, outLen, 1);
}
int decrypt(unsigned char * inputArray, size_t inputLen, unsigned char * outputArray,size_t outSize, size_t * outLen) {
return use_key(inputArray, inputLen, outputArray, outSize, outLen, 0);
}
int generate_key(){
mbedtls_pk_init(&RSA_ctx);
int ret = mbedtls_pk_setup(&RSA_ctx, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
Serial.println("Initializing key context...");
ESP_LOGI(TAG_MAIN, "Initializing key context...");
if (ret != 0)
{
ESP_LOGE(TAG_WORDS, "mbedtls_pk_info_from_type returned %d", ret);
return RSABooleanFalse;
}
Serial.println("Generating the private key...");
ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(RSA_ctx), mbedtls_ctr_drbg_random, &CTR_ctx, pubKeyLen, RSAPubKeyEXPONENT);
if (ret != 0)
{
ESP_LOGE(TAG_WORDS, "mbedtls_rsa_gen_key returned %d", ret);
return RSABooleanFalse;
}
return 0;
}
int validate_key(){
return mbedtls_pk_check_pair(&this->RSA_ctx,&this->RSA_ctx);
}
mbedtls_pk_context get_RSA_context(){
return this->RSA_ctx;
}
};
And the code I am running/main:
#include <esp_spiffs.h>
#include "Arduino.h"
#include "Cryptography/CryptographicSettings.cpp"
#include "Cryptography/RSAEncryption.h"
#include "esp_dsp.h"
#include "SPIFFS.h"
#include "Flash/CustomSPIFFS.h"
#include "Flash/FileManager.cpp"
#include "Flash/FileManager.h"
#include "FS.h"
#include "sha/sha_parallel_engine.h"
#include "TinyGPSPlus-master/src/TinyGPS++.h"
#include "stddef.h"
#include "Utility.h"
#include "Cryptography/Cryptographer.h"
#include "Cryptography/Cryptographer.cpp"
#include "HardwareMacros.h"
static const char* TAG_main = "Main";
const char * RSAPubKeyPath = "/RSAPubKey";
const char * RSAPrivKeyPath = "RSAPrivKey";
unsigned char PEMKeyBuffer[256];
unsigned char pubKey[pubKeyLen];
unsigned char a[2] = "a";
unsigned char outputBuf[SHA256_OUTPUT_BUFFERLEN];
unsigned char ID[IDLen];
unsigned char outputBufDecrypt[SHA256_OUTPUT_BUFFERLEN];
/**
* Finds the size of an RSA key formatted in PEM format
*
* \arg PEMBUFFER: An unsigned char containing the PEM file in the format
* {PEM_EMPTY_PLACEHOLDER,...,PEM_EMPTY_PLACEHOLDER,PEMFILE....,\0}
* Where PEM_EMPTY_PLACEHOLDER indicates that the value is not a part of the actual PEM file.
*
* Notice, that there can be nothing inbetween the start of the PEMFILE and the end of the array.
*
* \return
* The size of the PEMFILE or PEM_ERR_NO_PEM_FILE if there is no PEM file
*/
int findStartingIndexPEMFile(unsigned char * PEMBuffer,size_t sizeOfBuffer){
for(int i = 0; i<sizeOfBuffer;i++){
unsigned char c = PEMBuffer[i];
//We've reached the end of the array without encountering anything but PEM_EMPTY_PLACEHOLDERS
if(c == '\0'){
return PEM_ERR_NO_PEM_FILE;
}
if(c != PEM_EMPTY_PLACEHOLDER){
return i;
}
}
return PEM_ERR_NO_PEM_FILE;
}
void setup(){
Serial.begin(9600);
int res = 0;
Serial.println("___________________PROGRAM_START_________________________"); //We get a lot of fluffer at the start of the program
//SPIFFS
FileManager * spiff = new SPIFFSFileManager();
auto * rsaCryptographer = new RSACryptographer();
if(rsaCryptographer->generate_CTRX_context() != 0){
Serial.println("Error generating CTR");
}
if(rsaCryptographer->generate_key() != 0){
Serial.println("Error");
}
if(rsaCryptographer->validate_key() != 0){
Serial.println("Error");
}
unsigned char inputArray[22];
unsigned char outputArray[4000];
size_t oLen;
fill_alphanumeric_unsignedString(inputArray,sizeof(inputArray));
println_unsignedString(inputArray,sizeof(inputArray),CHR);
res = rsaCryptographer->encrypt(inputArray,sizeof(inputArray),outputArray,sizeof(outputArray),&oLen);
if(res != 0){
Serial.println("Error encrypting");
Serial.println(res);
}
println_unsignedString(outputArray,sizeof(inputArray),CHR);
//fill_alphanumeric_unsignedString(outputArray,sizeof(outputArray));
rsaCryptographer->decrypt(outputArray,oLen,outputArray,sizeof(outputArray),&oLen);
//mbedtls_pk_encrypt(&key,(const unsigned char *)inputArray,sizeof(inputArray),outputArray,&oLen,sizeof(outputArray),mbedtls_ctr_drbg_random,&ctr_drbg);
println_unsignedString(outputArray,oLen,CHR);
};
void loop(){
};
CryptographicSettings file:
//
// Created by DripTooHard on 03-04-2023.
//
//Truth values for our RSA functions
//They're defined as such, because the mbedtls libraries define 0 as success
#define RSABooleanTrue 0
#define RSABooleanFalse 1
//RSA related
#define RSAPubKeyEXPONENT 65537
#define pubKeyLen 256 //2048 bits
#define RSA_MAX_INPUT_LEN 245 //245 bytes
//RSA related errors
#define RSA_ERR_INPUT_EXCEEDS_MAX_LEN -69
#define RSA_ERR_OUTPUT_EXCEEDS_OUTPUT_ARRAY_LEN -68
//Identification/Network related
#define IDLen 20 //How many of the chars we take from the hash
//If we iterate over a PEM file and it's "7"
#define PEM_EMPTY_PLACEHOLDER 7
#define PEM_ERR_NO_PEM_FILE -69
//Hashing related
#define SHA256_OUTPUT_BUFFERLEN 32 //256 bits
Ps. This is some messy code, because we're just building the objects one at a time. No need to help me with structuring the code or messy stuff like linking a .cpp file ;)
At first I thought this was a problem with the size of the output array, but after having set it to 4k bytes, I am fairly certain, this must not be the case. Unless I am using some very weird padding scheme.