最近研究非对称加密RSA算法,要在native层进行RSA签名,故采用ndk编译openssl的crypto目录下的算法,调用openssl相关函数进行签名。 首先,需要秘密保存私钥,这里在native层读到私钥后由于是在内存中,固需要用到openssl内存相关读取私钥的函数,openssl提供的bio接口读取字符串私钥,在内存中读取私钥有个坑,对私钥的内容是由要求的,私钥必须以字符串”—–BEGIN RSA PRIVATE KEY—– “开始,“ —–END RSA PRIVATE KEY—– ”这个结束,否则openssl相关函数读取不到私钥,直接上代码:
#define PRIVATE_KEY "-----BEGIN RSA PRIVATE KEY-----\n你的私钥\n-----END RSA PRIVATE KEY-----\n" #define IS_VERFY_SIGN false #define IS_LOG_OUT_MSG false std::string rsaSha1Sign(const std::string *src) { unsigned char sign_value[1024]; //保存签名值的数组 unsigned int sign_len; //签名值长度 EVP_MD_CTX mdctx; //摘要算法上下文变量 const char *mess1 = (*src).c_str(); RSA *rsa=NULL; //RSA结构体变量 EVP_PKEY *evpKey=NULL; //EVP KEY结构体变量 int i; #if IS_LOG_OUT_MSG LOGD("正在产生RSA密钥..."); #endif // rsa = RSA_generate_key(1024,RSA_F4,NULL,NULL);//产生一个1024位的RSA密钥//LOGD ("bits: %d\n", BN_num_bits (rsa->n));//返回n的二进制位数!1024! /*************************/ BIO *bio = NULL; if ((bio = BIO_new_mem_buf((void *)PRIVATE_KEY, -1)) == NULL) //从字符串读取RSA私钥 { LOGE("BIO_new_mem_buf failed!\n"); } // rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL); rsa = RSA_new(); PEM_read_bio_RSAPrivateKey(bio,&rsa,0,0); /********************8*****/ if(rsa == NULL) { LOGD("gen rsa err\n"); return NULL; } #if IS_LOG_OUT_MSG LOGD(" 成功.\n"); #endif evpKey = EVP_PKEY_new();//新建一个EVP_PKEY变量 if(evpKey == NULL) { LOGD("EVP_PKEY_new err\n"); RSA_free(rsa); return NULL; } if(EVP_PKEY_set1_RSA(evpKey,rsa) != 1) //保存RSA结构体到EVP_PKEY结构体 { LOGD("EVP_PKEY_set1_RSA err\n"); RSA_free(rsa); EVP_PKEY_free(evpKey); return NULL; } //以下是计算签名代码 EVP_MD_CTX_init(&mdctx);//初始化摘要上下文 if(!EVP_SignInit_ex(&mdctx, EVP_sha1(), NULL))//签名初始化,设置摘要算法,本例为sha1 { LOGD("err\n"); EVP_PKEY_free(evpKey); RSA_free(rsa); return NULL; } if(!EVP_SignUpdate(&mdctx, mess1, strlen(mess1)))//计算签名(摘要)Update { LOGD("err\n"); EVP_PKEY_free(evpKey); RSA_free(rsa); return NULL; } if(!EVP_SignFinal(&mdctx, sign_value, &sign_len, evpKey)) //签名输出 { LOGD("err\n"); EVP_PKEY_free(evpKey); RSA_free(rsa); return NULL; } #if IS_LOG_OUT_MSG LOGD("消息\"%s\"的签名值是: \n",mess1); for(i = 0; i < sign_len; i++) { if(i%16==0) LOGD("\nxH: ",i); LOGD("x ", sign_value[i]); } LOGD("\n"); #endif /*******************************/ std::string msgC; char * t = (char *) sign_value; msgC.assign(t,sign_len); std::string base64 = base64_encodestring(msgC); #if IS_LOG_OUT_MSG LOGD("%s:",base64.c_str()); #endif /********************************/ EVP_MD_CTX_cleanup(&mdctx); #if IS_VERFY_SIGN LOGD("\n正在验证签名...\n"); //以下是验证签名代码 EVP_MD_CTX_init(&mdctx);//初始化摘要上下文 if(!EVP_VerifyInit_ex(&mdctx, EVP_sha1(), NULL))//验证初始化,设置摘要算法,一定要和签名一致。 { LOGD("EVP_VerifyInit_ex err\n"); EVP_PKEY_free(evpKey); RSA_free(rsa); return NULL; } if(!EVP_VerifyUpdate(&mdctx, mess1, strlen(mess1)))//验证签名(摘要)Update { LOGD("err\n"); EVP_PKEY_free(evpKey); RSA_free(rsa); return NULL; } if(!EVP_VerifyFinal(&mdctx,sign_value,sign_len,evpKey))//验证签名 { LOGD("verify err\n"); EVP_PKEY_free(evpKey); RSA_free(rsa); return NULL; } else { LOGD("验证签名正确.\n"); } #endif //释放内存 EVP_PKEY_free(evpKey); RSA_free(rsa); EVP_MD_CTX_cleanup(&mdctx); //删除所有换行符 for (unsigned int j = 0; j < base64.size(); ++j) { if (base64[j] == '\n') { base64.erase(j,1); } } return base64; } std::string base64_encodestring(const std::string &text ){ EVP_ENCODE_CTX ectx; int size = text.size()*2; size = size > 64 ? size : 64; unsigned char* out = (unsigned char*)malloc( size ); int outlen = 0; int tlen = 0; EVP_EncodeInit( &ectx ); EVP_EncodeUpdate( &ectx, out, &outlen, (const unsigned char*)text.c_str(), text.size() ); tlen += outlen; EVP_EncodeFinal( &ectx, out+tlen, &outlen ); tlen += outlen; std::string str( (char*)out, tlen ); free( out ); return str; }这样返回的就是签名值的BASE64字符串,ndk调用范例:
const char * msg_ = "test"; std::string msg ; msg.assign(msg_); std::string signString = rsaSha1Sign(msg); return env->NewStringUTF(signString.c_str());