In recent projects, RSA algorithm needs to be implemented by C language. Here, I implement it by Mbedtls library.
1. Download Mbedtls
First, we put the Mbedtls code into the project, and the related transmission gates are as follows:
Official download address of Mbedtls
The official website is slow download abroad, so the Mbedtls code used in this article is also attached. The portal is as follows:
Mbedtls encryption and decryption tool code
2. Import Mbedtls header file
Here, we introduce the header file of Mbedtls into CMakeLists.txt in the project. The code is as follows:
# for debug # add_compile_options(-g) project("device-authentication") cmake_minimum_required(VERSION 3.5) INCLUDE_DIRECTORIES( ../include/ ../../src/net/mbedtls/include ../../src/smalgo/sms4/include ) SET(my_src_crypto ../../src/net/mbedtls/library/aes.c ../../src/net/mbedtls/library/aesni.c ../../src/net/mbedtls/library/base64.c ../../src/net/mbedtls/library/rsa.c ../../src/net/mbedtls/library/rsa_internal.c ../../src/net/mbedtls/library/entropy.c ../../src/net/mbedtls/library/entropy_poll.c ../../src/net/mbedtls/library/bignum.c ../../src/net/mbedtls/library/sha1.c ../../src/net/mbedtls/library/sha256.c ../../src/net/mbedtls/library/sha512.c ../../src/net/mbedtls/library/md.c ../../src/net/mbedtls/library/md5.c ../../src/net/mbedtls/library/md_wrap.c ../../src/net/mbedtls/library/ripemd160.c ../../src/net/mbedtls/library/platform_util.c ../../src/net/mbedtls/library/oid.c ../../src/net/mbedtls/library/timing.c ../../src/net/mbedtls/library/net_sockets.c ../../src/smalgo/sms4/cbc128.c ../../src/smalgo/sms4/sms4_cbc.c ../../src/smalgo/sms4/sms4_common.c ../../src/smalgo/sms4/sms4_enc.c ../../src/smalgo/sms4/sms4_setkey.c ) SET(my_src_crypto_dbg ../../src/net/mbedtls/library/ctr_drbg.c ) SET(SRC_LIST_ENCRYPT_BIN oem_porting.c sdk_porting.c authref.c test.c ${my_src_crypto} ${my_src_crypto_dbg} ) SET(SRC_LIST_DECRYPT_LIB oem_porting.c sdk_porting.c authref.c auth.c ${my_src_crypto} ${my_src_crypto_dbg} ) #SET(SRC_LIST_AUTH_DEV # oem_porting.c # sdk_porting.c # authref.c # ${my_src_crypto} # ${my_src_crypto_dbg} #) add_definitions(-fPIC) #ADD_LIBRARY(authd STATIC ${SRC_LIST_AUTH_DEV}) ADD_LIBRARY(authoal STATIC ${SRC_LIST_DECRYPT_LIB}) ADD_EXECUTABLE(eaidkAuth ${SRC_LIST_ENCRYPT_BIN})
The project structure is as follows:
After the introduction, we can start to write RSA code.
3. RSA coding
The code of authref.h header file is as follows:
#ifndef __AUTHREF_H__ #define __AUTHREF_H__ #include <assert.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #undef DEBUG #Define RSA key size 1024 / / the number of digits of the RSA public key #define EXPONENT 65537 #define BUFFER_SIZE 1024 #define RSA_KEY_LEN 256 #define AES_KEY_DEC_LEN 8 #define LICENSE_DEC_LEN 64 typedef struct __rsa { uint8_t buf[BUFFER_SIZE*8]; uint8_t* rsa_n; uint8_t* rsa_e; uint8_t* rsa_d; uint8_t* rsa_p; uint8_t* rsa_q; uint8_t* rsa_dp; uint8_t* rsa_dq; uint8_t* rsa_qp; uint32_t n_len; uint32_t e_len; uint32_t d_len; uint32_t p_len; uint32_t q_len; uint32_t dp_len; uint32_t dq_len; uint32_t qp_len; }T_rsa; void generate_rsa(T_rsa* r); void init_rsa_keys(T_rsa* rsa); void rsa_encrypt( const T_rsa *r, const unsigned char* plaintext, unsigned int plaintext_size, unsigned char *ciphertext, size_t *ciphertext_size); void rsa_decrypt( const T_rsa *r, const unsigned char* ciphertext, //unsigned int ciphertext_size, unsigned char *plaintext, size_t *plaintext_size); #ifdef __cplusplus } #endif #endif //__AUTHREF_H__
The authref.c code is as follows:
#include "authref.h" #include "mbedtls/entropy.h" #include "mbedtls/ctr_drbg.h" #include "mbedtls/rsa.h" #Define RSA key size 1024 / / the number of digits of the RSA public key #define EXPONENT 65537 #define BUFFER_SIZE 1024 #define RSA_KEY_LEN 256 #define AES_KEY_DEC_LEN 8 #define LICENSE_DEC_LEN 64 void generate_rsa(T_rsa* r) { mbedtls_rsa_context rsa; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_entropy_init(&entropy); mbedtls_ctr_drbg_init(&ctr_drbg); mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0); mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0); mbedtls_rsa_gen_key(&rsa, mbedtls_ctr_drbg_random, &ctr_drbg, RSA_KEY_SIZE, EXPONENT); mbedtls_mpi_write_binary(&rsa.N, r->rsa_n, BUFFER_SIZE); mbedtls_mpi_write_binary(&rsa.E, r->rsa_e, BUFFER_SIZE); mbedtls_mpi_write_binary(&rsa.D, r->rsa_d, BUFFER_SIZE); mbedtls_mpi_write_binary(&rsa.P, r->rsa_p, BUFFER_SIZE); mbedtls_mpi_write_binary(&rsa.Q, r->rsa_q, BUFFER_SIZE); mbedtls_mpi_write_binary(&rsa.DP, r->rsa_dp, BUFFER_SIZE); mbedtls_mpi_write_binary(&rsa.DQ, r->rsa_dq, BUFFER_SIZE); mbedtls_mpi_write_binary(&rsa.QP, r->rsa_qp, BUFFER_SIZE); mbedtls_rsa_free(&rsa); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); } void init_rsa_keys(T_rsa *rsa) { memset(rsa->buf, 0, BUFFER_SIZE * 8); rsa->rsa_n = &rsa->buf[BUFFER_SIZE * 0]; rsa->rsa_e = &rsa->buf[BUFFER_SIZE * 1]; rsa->rsa_d = &rsa->buf[BUFFER_SIZE * 2]; rsa->rsa_p = &rsa->buf[BUFFER_SIZE * 3]; rsa->rsa_q = &rsa->buf[BUFFER_SIZE * 4]; rsa->rsa_dp = &rsa->buf[BUFFER_SIZE * 5]; rsa->rsa_dq = &rsa->buf[BUFFER_SIZE * 6]; rsa->rsa_qp = &rsa->buf[BUFFER_SIZE * 7]; rsa->n_len = BUFFER_SIZE; rsa->e_len = BUFFER_SIZE; rsa->d_len = BUFFER_SIZE; rsa->p_len = BUFFER_SIZE; rsa->q_len = BUFFER_SIZE; rsa->dp_len = BUFFER_SIZE; rsa->dq_len = BUFFER_SIZE; rsa->qp_len = BUFFER_SIZE; } // encryption void rsa_encrypt( const T_rsa *r, const unsigned char *plaintext, unsigned int plaintext_size, unsigned char *ciphertext, size_t *ciphertext_size) { mbedtls_rsa_context rsa; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; int rett = 0; mbedtls_entropy_init(&entropy); //assert(mbedtls_ctr_drbg_init(&ctr_drbg, mbedtls_entropy_func, &entropy, nullptr, 0) == 0); mbedtls_ctr_drbg_init(&ctr_drbg); assert(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0) == 0); mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0); assert(mbedtls_mpi_read_binary(&rsa.N, r->rsa_n, BUFFER_SIZE) == 0); assert(mbedtls_mpi_read_binary(&rsa.E, r->rsa_e, BUFFER_SIZE) == 0); *ciphertext_size = rsa.len = (mbedtls_mpi_bitlen(&rsa.N) + 7) >> 3; //assert(mbedtls_rsa_pkcs1_encrypt(&rsa, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, plaintext_size, plaintext, ciphertext) == 0); rett = mbedtls_rsa_pkcs1_encrypt(&rsa, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, plaintext_size, plaintext, ciphertext); assert(rett == 0); mbedtls_rsa_free(&rsa); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); } // Decrypt void rsa_decrypt( const T_rsa *r, const unsigned char *ciphertext, //unsigned int ciphertext_size, unsigned char *plaintext, size_t *plaintext_size) { mbedtls_rsa_context rsa; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_entropy_init(&entropy); //assert(mbedtls_ctr_drbg_init(&ctr_drbg, mbedtls_entropy_func, &entropy, nullptr, 0) == 0); mbedtls_ctr_drbg_init(&ctr_drbg); assert(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0) == 0); mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0); assert(mbedtls_mpi_read_binary(&rsa.N, r->rsa_n, BUFFER_SIZE) == 0); assert(mbedtls_mpi_read_binary(&rsa.E, r->rsa_e, BUFFER_SIZE) == 0); assert(mbedtls_mpi_read_binary(&rsa.D, r->rsa_d, BUFFER_SIZE) == 0); assert(mbedtls_mpi_read_binary(&rsa.P, r->rsa_p, BUFFER_SIZE) == 0); assert(mbedtls_mpi_read_binary(&rsa.Q, r->rsa_q, BUFFER_SIZE) == 0); assert(mbedtls_mpi_read_binary(&rsa.DP, r->rsa_dp, BUFFER_SIZE) == 0); assert(mbedtls_mpi_read_binary(&rsa.DQ, r->rsa_dq, BUFFER_SIZE) == 0); assert(mbedtls_mpi_read_binary(&rsa.QP, r->rsa_qp, BUFFER_SIZE) == 0); rsa.len = (mbedtls_mpi_bitlen(&rsa.N) + 7) >> 3; assert(mbedtls_rsa_pkcs1_decrypt(&rsa, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PRIVATE, plaintext_size, ciphertext, plaintext, *plaintext_size) == 0); mbedtls_rsa_free(&rsa); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); } int do_ras_encrypt(authhandle *hdl, uint8_t contract_id[CONTRACTID_LEN], uint8_t user_id[USERID_LEN], uint8_t uid[FINAL_UID_LEN]) { T_rsa r; uint8_t uid_local[UID_LEN]; uint8_t ciphertext[SN_LEN]; size_t ciphertext_len = SN_LEN; GenRawUID(hdl, contract_id, user_id, uid_local); //encryp UID init_rsa_keys(&r); if (hdl->callback_func.GetServerPublicKey) { hdl->callback_func.GetServerPublicKey(r.buf); } else { GetServerPublicKey(hdl, r.buf); //load 2048 bytes for public key } rsa_encrypt(&r, uid_local, UID_LEN, ciphertext, &ciphertext_len); //printf("ciphertext_len: %ld\n", ciphertext_len); //copy SWID #if 0 int i; printf("CipherUID: "); for(i = 0; i < FINAL_UID_LEN; ++i){ printf("%02x, ", uid[i]); } printf("\n"); #endif return 0; //OK }
The pseudo code to generate the RSA public private key is as follows:
T_rsa r; uint8_t pub_key[2048] = { 0 }; uint8_t prv_key[8192] = { 0 }; init_rsa_keys(&r); generate_rsa(&r); //1. public key memcpy(pub_key, r.buf, 2048); //2. private key memcpy(prv_key, r.buf, 8192);
RSA encryption code is as follows:
int do_ras_encrypt(authhandle *hdl, uint8_t contract_id[CONTRACTID_LEN], uint8_t user_id[USERID_LEN], uint8_t uid[FINAL_UID_LEN]) { T_rsa r; uint8_t uid_local[UID_LEN]; uint8_t ciphertext[SN_LEN]; size_t ciphertext_len = SN_LEN; //encryp UID init_rsa_keys(&r); if (hdl->callback_func.GetServerPublicKey) { hdl->callback_func.GetServerPublicKey(r.buf); } else { GetServerPublicKey(hdl, r.buf); //load 2048 bytes for public key } rsa_encrypt(&r, uid_local, UID_LEN, ciphertext, &ciphertext_len); //printf("ciphertext_len: %ld\n", ciphertext_len); //copy SWID #if 0 int i; printf("CipherUID: "); for(i = 0; i < FINAL_UID_LEN; ++i){ printf("%02x, ", uid[i]); } printf("\n"); #endif return 0; //OK }
The decryption code is as follows:
static int SetServerPrivateKey(T_rsa *r, uint8_t *prv_key) { memcpy(r->buf, prv_key, 8192); //memset(&r->buf[0], 0, 1024-128); //memset(&r->buf[1024], 0, 1024-4); //memset(&r->buf[2048], 0, 1024-128); //memset(&r->buf[3072], 0, 1024-64); //memset(&r->buf[4096], 0, 1024-64); //memset(&r->buf[5120], 0, 1024-64); //memset(&r->buf[6144], 0, 1024-64); //memset(&r->buf[7168], 0, 1024-64); return 0; //OK } JNIEXPORT jbyteArray JNICALL Java_com_openailab_oascloud_security_jni_cloud_CloudAuthJNI_decrypUidOnServer (JNIEnv *env, jobject obj, jstring uidEnc, jbyteArray privateKey) { uint8_t *uid_enc = (*env)->GetStringUTFChars(env, uidEnc, NULL); uint8_t *private_key = (*env)->GetByteArrayElements(env, privateKey, NULL); jbyteArray ret = NULL; T_rsa r; uint8_t plaintext[UID_LEN]; size_t plaintext_len = 256; uint8_t UID_Recover[SN_LEN]; uint8_t uid_enc_c[FINAL_UID_LEN]; init_rsa_keys(&r); SetServerPrivateKey(&r, private_key); hex2array(uid_enc, FINAL_UID_LEN * 2, uid_enc_c); recover(&uid_enc_c[FINAL_UID_LEN - SN_LEN], UID_Recover, SN_LEN); rsa_decrypt(&r, UID_Recover, plaintext, &plaintext_len); /*printf("plaintext=\n"); for (size_t i = 0; i < UID_LEN; i++) { if (i > 0 && i % 16 == 0) { printf("\n"); } printf("%02x,", plaintext[i]); } printf("\n");*/ ret = (*env)->NewByteArray(env, UID_LEN); (*env)->SetByteArrayRegion(env, ret, 0, UID_LEN, (jbyte*)plaintext); (*env)->ReleaseByteArrayElements(env, privateKey, private_key, 0); (*env)->ReleaseStringUTFChars(env, uidEnc, uid_enc); return ret; }
This C language RSA encryption and decryption on the end of the introduction.