多谢网友反馈,修复bug
最新的代码连接:http://download.csdn.net/download/gao1040841994/9934340
鉴于之前c 代码用eclispe 编译,不太方便,现在已经 是 studio时代,重新写了一份demo,供大家参考。
开发工具:Android studio
库: openssl
编译环境: mac os
jni开发语言:C++
包含加密种类:RSA 3DES AES MD5 BASE64
此次基于android studio 的CmakeList 方式编译。
不会的话,可以看看这位大神的博客,写的很详细
http://blog.csdn.net/wzzfeitian/article/details/40963457/
还有不少示例,看懂了就没问题了。
gradle 配置:
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.0"
defaultConfig {
applicationId "demo.rsa.gkbn.rsademo"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags "-std=c++11 -frtti -fexceptions"
abiFilters "armeabi"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.0.0'
testCompile 'junit:junit:4.12'
}
CmakeList 文件配置:
cmake_minimum_required(VERSION 3.4.1)
#导入头文件路径
INCLUDE_DIRECTORIES(
src/main/cpp/openssllib/include/openssl/
)
#链接库文件路径(.a .so 文件)
LINK_DIRECTORIES(src/main/cpp/openssllib/)
#编译源代码
ADD_LIBRARY(native SHARED src/main/cpp/native-lib.cpp src/main/cpp/MyRSA.cpp src/main/cpp/MyBASE64.cpp src/main/cpp/My3DES.cpp src/main/cpp/MyMD5.cpp src/main/cpp/MyAES.cpp)
#链接Android 日志库文件
find_library( log-lib log)
#编译.so 文件
TARGET_LINK_LIBRARIES( native libcrypto.a libssl.a ${log-lib}) # 链接动态库
native文件:
#include
#include
#include "MyRSA.h"
#include
#include
#include "MyBASE64.h"
#include "My3DES.h"
#include "MyMD5.h"
#include "Log.h"
#include "MyAES.h"
extern "C" {
__attribute ((visibility ("default")))
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) //这是JNI_OnLoad的声明,必须按照这样的方式声明
{
return JNI_VERSION_1_4; //这里很重要,必须返回版本,否则加载会失败。
}
__attribute ((visibility ("default")))
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
// __android_log_print(ANDROID_LOG_ERROR, "tag", "library was unload");
}
/**
* base64加密
*/
__attribute ((visibility ("default")))
JNIEXPORT jstring JNICALL
Java_demo_rsa_gkbn_rsademo_JniDemo_encryptBase64(JNIEnv *env, jobject instance, jstring msg_) {
const char *msg = env->GetStringUTFChars(msg_, 0);
std::string msgC;
msgC.assign(msg);
std::string base64 = MyBASE64::base64_encodestring(msgC);
env->ReleaseStringUTFChars(msg_, msg);
return env->NewStringUTF(base64.c_str());
}
/**
* base64 解密
*/
__attribute ((visibility ("default")))
JNIEXPORT jstring JNICALL
Java_demo_rsa_gkbn_rsademo_JniDemo_decryptBase64(JNIEnv *env, jobject instance, jstring msg_) {
const char *msg = env->GetStringUTFChars(msg_, 0);
std::string msgC;
msgC.assign(msg);
std::string base64 = MyBASE64::base64_decodestring(msgC);
env->ReleaseStringUTFChars(msg_, msg);
return env->NewStringUTF(base64.c_str());
}
/**
* MD5加密算法
*/
__attribute ((visibility ("default")))
JNIEXPORT jstring JNICALL
Java_demo_rsa_gkbn_rsademo_JniDemo_MD5(JNIEnv *env, jobject instance, jstring msg_) {
const char *msg = env->GetStringUTFChars(msg_, 0);
std::string msgC;
msgC.assign(msg);
std::string f = MyMD5::encryptMD5(msgC);
env->ReleaseStringUTFChars(msg_, msg);
return env->NewStringUTF(f.c_str());
}
/**
* AES加密算法
*/
__attribute ((visibility ("default")))
JNIEXPORT jstring JNICALL
Java_demo_rsa_gkbn_rsademo_JniDemo_encodeAES(JNIEnv *env, jobject instance, jstring msg_) {
const char *msg = env->GetStringUTFChars(msg_, 0);
std::string msgC;
msgC.assign(msg);
std::string aes = MyAES::encodeAES("1234567812345678", msgC);//密码长度必须大于16 位
std::string base64 = MyBASE64::base64_encodestring(aes);
env->ReleaseStringUTFChars(msg_, msg);
return env->NewStringUTF(base64.c_str());
}
/**
* AES解密算法
*/
__attribute ((visibility ("default")))
JNIEXPORT jstring JNICALL
Java_demo_rsa_gkbn_rsademo_JniDemo_decodeAES(JNIEnv *env, jobject instance, jstring msg_) {
const char *msg = env->GetStringUTFChars(msg_, 0);
std::string msgC;
msgC.assign(msg);
int length;
std::string base64 = MyBASE64::base64_decodestring(msgC);
std::string aes = MyAES::decodeAES("1234567812345678", base64);
env->ReleaseStringUTFChars(msg_, msg);
return env->NewStringUTF(aes.c_str());
}
/**
* DES加密算法
*/
__attribute ((visibility ("default")))
JNIEXPORT jstring JNICALL
Java_demo_rsa_gkbn_rsademo_JniDemo_encryptDES(JNIEnv *env, jobject instance, jstring msg_) {
const char *msg = env->GetStringUTFChars(msg_, 0);
std::string msgC;
msgC.assign(msg);
int length;
std::string key = "12345678";
std::string des = My3DES::encryptDES(msgC, key, &length);
std::string base64 = MyBASE64::base64_encodestring(des);
env->ReleaseStringUTFChars(msg_, msg);
return env->NewStringUTF(base64.c_str());
}
/**
*
* DES解密算法
*/
__attribute ((visibility ("default")))
JNIEXPORT jstring JNICALL
Java_demo_rsa_gkbn_rsademo_JniDemo_decryptDES(JNIEnv *env, jobject instance, jstring msg_) {
const char *msg = env->GetStringUTFChars(msg_, 0);
std::string msgC;
msgC.assign(msg);
std::string key = "12345678";
int length;
std::string base64 = MyBASE64::base64_decodestring(msgC);
std::string des = My3DES::decryptDES(base64, key, base64.length());
env->ReleaseStringUTFChars(msg_, msg);
return env->NewStringUTF(des.c_str());
}
/**
* RSA解密算法
*/
__attribute ((visibility ("default")))
JNIEXPORT jstring JNICALL
Java_demo_rsa_gkbn_rsademo_JniDemo_decryptRSA(JNIEnv *env, jobject instance, jstring msg_) {
const char *msg = env->GetStringUTFChars(msg_, 0);
std::string msgC;
msgC.assign(msg);
std::string base64 = MyBASE64::base64_decodestring(msgC);
std::string rsa = MyRSA::decryptRSA(base64);
env->ReleaseStringUTFChars(msg_, msg);
return env->NewStringUTF(rsa.c_str());
}
/**
* RSA 加密算法
*/
__attribute ((visibility ("default")))
JNIEXPORT jstring JNICALL
Java_demo_rsa_gkbn_rsademo_JniDemo_encryptRSA(JNIEnv *env, jobject instance, jstring msg_) {
const char *msg = env->GetStringUTFChars(msg_, 0);
std::string msgC;
msgC.assign(msg);
std::string rsa = MyRSA::encryptRSA(msgC, NULL);
std::string base64 = MyBASE64::base64_encodestring(rsa);
env->ReleaseStringUTFChars(msg_, msg);
return env->NewStringUTF(base64.c_str());
}
}
此工程是楼主花了几天心血完成。其他代码太多,请下载demo自行查看,顺便送点积分吧。
工程demo 地址:
http://download.csdn.net/detail/gao1040841994/9705385
客户端:使用公钥,加密动态生成的3DES秘钥,用3des秘钥加密报文。拼接报文
服务器:使用私钥,解密到3des秘钥后,用3des秘钥加密报文并返回,改秘钥加密的数据给客户端
java 代码
private byte[] bkey;
// java 动态层生成的 3des 秘钥的 二进制数据,
如果你的项目 3des 秘钥是写死的 ,那恭喜你,直接在c 代码里面写死
static {
System.loadLibrary("demo");
}
public native String Encrypt( byte[] deskey,String msg,);
public native int Decrypt(String src, byte[] deskey);
public ConnectionTask(byte[] bkey2){
KeyGenerator kg = KeyGenerator.getInstance("DESede");
kg.init(168);
//生成秘密密钥
SecretKey secretKey = kg.generateKey();
//获得密钥的二进制编码形式
bkey=secretKey.getEncoded();
}
C 语言代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define TAG "myDemo-jni" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型
#define PUBLIC_EXPONENT RSA_F4 //默认不用改
//RSA 质子 可以用公钥的 密文代替,请自行查阅,或使用公钥 得出质子 替换这个值
#define MODULUS "9c847aae8aa567d36af169dbed35f42f9568d137067b30a204476897020e7d88914d1c03a671c62be4a05fbd645bd358b2ff38ad2e5166003414eb7b155301d1f6cacaa54260261073e1c02947379614e6b6123e5b35af50dc675f1c673565906cc4acb967976e209bad50d24ab38b6822198644de43874e4fb92714f6fd677d"
# ifdef __cplusplus
extern "C" {
# endif
//隐藏符号表 ,加大反编译难度
__attribute ((visibility ("default")))
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void *reserved) //这是JNI_OnLoad的声明,必须按照这样的方式声明
{
return JNI_VERSION_1_4; //这里很重要,必须返回版本,否则加载会失败。
}
__attribute ((visibility ("default")))
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved)
{
// __android_log_print(ANDROID_LOG_ERROR, "tag", "library was unload");
}
/**
* 字符串左补位函数 (超长会自动截断)
* @dest 原字符串
* @src 填充字符
* @len 总长度
* return 补位后字符串
*/
char *Lzero(char *dest,char *src,int len){
static char res[1024];
memset(res,0x00,sizeof(res));
int dlen=strlen(dest);
if(dlen>=len){
memcpy(res, dest,len);
}
else{
int blen=0;
while(blen<(len-dlen)){
res[blen]=src[0];
blen++;
}
memcpy(res+len-dlen,dest,dlen);
}
return (res);
}
/**
* 字符串右补位函数 (超长会自动截断)
* @dest 原字符串
* @src 填充字符
* @len 总长度
* return 补位后字符串
*/
char *Rzero(char *dest, char *src, int len) {
static char res[1024];
memset(res, 0x00, sizeof(res));
int dlen = strlen(dest);
if (dlen >= len) {
memcpy(res, dest, len);
} else {
memcpy(res, dest, dlen);
while (dlen < len) {
res[dlen] = src[0];
dlen++;
}
}
return (res);
}
unsigned char * encryptDES(const char *data, char *k,int *lenreturn);
unsigned char * decryptDES(const char *data, int data_len, char *k);
//jstring to char*
char* jstringTostring(JNIEnv* env, jstring jstr) {
char* rtn = NULL;
jclass clsstring = (*env)->FindClass(env, "java/lang/String");
jstring strencode = (*env)->NewStringUTF(env, "utf-8");
jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes",
"(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid,
strencode);
jsize alen = (*env)->GetArrayLength(env, barr);
jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);
if (alen > 0) {
rtn = (char*) malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
(*env)->ReleaseByteArrayElements(env, barr, ba, 0);
return rtn;
}
/**
*BASE64 解码
*/
static void openssl_base64_decode(char *encoded_bytes,
unsigned char **decoded_bytes, int *decoded_length) {
BIO *bioMem, *b64;
size_t buffer_length;
bioMem = BIO_new_mem_buf((void *) encoded_bytes, -1);
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bioMem = BIO_push(b64, bioMem);
buffer_length = BIO_get_mem_data(bioMem, NULL);
*decoded_bytes = malloc(buffer_length);
if (decoded_bytes == NULL) {
BIO_free_all(bioMem);
*decoded_length = 0;
return;
}
*decoded_length = BIO_read(bioMem, *decoded_bytes, buffer_length);
BIO_free_all(bioMem);
}
/* Return NULL if failed, REMEMBER to free() BASE64 加密*/
static char *openssl_base64_encode(unsigned char *decoded_bytes,
size_t decoded_length) {
int x;
BIO *bioMem, *b64;
BUF_MEM *bufPtr;
char *buff = NULL;
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bioMem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bioMem);
BIO_write(b64, decoded_bytes, decoded_length);
x = BIO_flush(b64);
if (x < 1)
goto END;
BIO_get_mem_ptr(b64, &bufPtr);
buff = (char *) malloc(bufPtr->length + 1);
if (buff == NULL)
goto END;
memcpy(buff, bufPtr->data, bufPtr->length);
buff[bufPtr->length] = 0;
END: BIO_free_all(b64);
return buff;
}
// demo请求格式: BASE64(RSA(3DES密钥))| BASE64(3DES(报文原文)) 仿httpS原理 实现
__attribute ((visibility ("default")))
jstring Java_com_example_demojiami_ConnectionTask_Encrypt(JNIEnv *env,
jclass obj, jbyteArray Deskey, jstring msg ) {
jsize i4PlaintTextLen = (*env)->GetArrayLength(env, Deskey);
jbyte * pKey = (jbyte*) (*env)->GetByteArrayElements(env, Deskey, 0);
int ret, flen;
BIGNUM *bnn, *bne;
bnn = BN_new();
bne = BN_new();
BN_hex2bn(&bnn, MODULUS);
BN_set_word(bne, PUBLIC_EXPONENT);
RSA *r = RSA_new();
r->n = bnn;
r->e = bne;
RSA_print_fp(stdout, r, 5);
flen = RSA_size(r);
static char cipherText[129];
memset(cipherText, 0x00, sizeof(cipherText));
unsigned char *pCipherText = cipherText;
char * gkbna= Rzero( (unsigned char *) pKey,"000",128);
ret = RSA_public_encrypt(flen-11 ,gkbna, pCipherText, r,
RSA_PKCS1_PADDING);
RSA_free(r);
//***************************************************************************************************************
// BASE64(RSA(3DES密钥))
char *two = openssl_base64_encode(pCipherText,128);
// LOGE("two=%s", two);
//*********************************************************************************RSA***
// 第二段内容
unsigned char *cipher;
unsigned char *pmsg = jstringTostring(env, msg);
int lenadd=strlen(pmsg)%8;
char *des= Rzero(pmsg,"\0",strlen(pmsg)+(8-lenadd));
int lenth;
cipher = encryptDES(pmsg, (char *) pKey,&lenth);
if(pmsg!=NULL){
free(pmsg);
pmsg=NULL;
}
if(cipher==NULL) return (*env)->NewStringUTF(env, "null");
(*env)->ReleaseByteArrayElements(env, Deskey, pKey, 0);
char *three = openssl_base64_encode(cipher, lenth);
char * line = "|";
char *result = malloc(
strlen(two) + strlen(line)
+ strlen(three) + 1); //+1 for the zero-terminator
strcat(result, two);
strcat(result, line);
strcat(result, three);
two = NULL;
three = NULL;
cipher = NULL;
three = NULL;
line = NULL;
pmsg = NULL;
machid = NULL;
return (*env)->NewStringUTF(env, result);
}
//解密方法
__attribute ((visibility ("default")))
jstring Java_com_example_demojiami_ConnectionTask_Decrypt(JNIEnv *env, jclass thiz,
jstring msg, jbyteArray key ) {
jbyte * pKey = (jbyte*) (*env)->GetByteArrayElements(env, key, 0);
if (!pKey ) {
return (*env)->NewStringUTF(env, "null");
}
unsigned char *pmsg = jstringTostring(env, msg);
unsigned char *decode;
int lenth;
openssl_base64_decode(pmsg,&decode, &lenth);
char *result = decryptDES(decode, lenth,(char *)pKey );
(*env)->ReleaseByteArrayElements(env, key, pKey, 0);
decode=NULL;
if(pmsg!=NULL){
free(pmsg);
pmsg=NULL;
}
if(result!=NULL){
return (*env)->NewStringUTF(env, result);
}
return (*env)->NewStringUTF(env, "null");
}
unsigned char * encryptDES(const char *data, char *key, int * lenreturn) {
int docontinue = 1;
// char *data = "gubojun"; /* 明文 */
int data_len;
int data_rest;
unsigned char ch;
unsigned char *src = NULL; /* 补齐后的明文 */
unsigned char *dst = NULL; /* 解密后的明文 */
int len;
unsigned char tmp[8];
unsigned char in[8];
unsigned char out[8];
// char *k = "12345678"; /* 原始密钥 */
int key_len;
#define LEN_OF_KEY 24
// unsigned char key[LEN_OF_KEY]; /* 补齐后的密钥 */
unsigned char block_key[9];
DES_key_schedule ks, ks2, ks3;
/* 构造补齐后的密钥 */
//key_len = strlen(k);
// LOGE("key_len=%d", key_len);
// memcpy(key, k, key_len);
// memset(key + key_len, 0x00, LEN_OF_KEY - key_len);
/* 分析补齐明文所需空间及补齐填充数据 */
data_len = strlen(data);
data_rest = data_len % 8;
len = data_len + (8 - data_rest);
ch = 8 - data_rest;
src = (unsigned char *) malloc(len);
dst = (unsigned char *) malloc(len);
if (NULL == src || NULL == dst) {
docontinue = 0;
}
if (docontinue) {
int count;
int i;
/* 构造补齐后的加密内容 */
memset(src, 0, len);
memcpy(src, data, data_len);
memset(src + data_len, ch, 8 - data_rest);
/* 密钥置换 */
memset(block_key, 0, sizeof(block_key));
memcpy(block_key, key + 0, 8);
DES_set_key_unchecked((const_DES_cblock*) block_key, &ks);
memcpy(block_key, key + 8, 8);
DES_set_key_unchecked((const_DES_cblock*) block_key, &ks2);
memcpy(block_key, key + 16, 8);
DES_set_key_unchecked((const_DES_cblock*) block_key, &ks3);
/* 循环加密/解密,每8字节一次 */
count = len / 8;
for (i = 0; i < count; i++) {
memset(tmp, 0, 8);
memset(in, 0, 8);
memset(out, 0, 8);
memcpy(tmp, src + 8 * i, 8);
/* 加密 */
//
// DES_ecb_encrypt((const_DES_cblock*) tmp, (DES_cblock*) in,
// &schedule, DES_ENCRYPT);
DES_ecb3_encrypt((const_DES_cblock*) tmp, (DES_cblock*) in, &ks,
&ks2, &ks3,
DES_ENCRYPT);
/* 解密 */
// DES_ecb3_encrypt((const_DES_cblock*) in, (DES_cblock*) out, &ks,
// &ks2, &ks3, DES_DECRYPT);
/* 将解密的内容拷贝到解密后的明文 */
// memcpy(dst + 8 * i, out, 8);
memcpy(dst + 8 * i, in, 8);
}
}
*lenreturn = len;
if (NULL != src) {
free(src);
src = NULL;
}
if (NULL != dst) {
return dst;
}
return NULL;
}
unsigned char * decryptDES(const char *data, int data_len, char *key) {
int docontinue = 1;
// char *data = "gubojun"; /* 明文 */
// int data_len;
int data_rest;
unsigned char ch;
unsigned char *src = NULL; /* 补齐后的明文 */
unsigned char *dst = NULL; /* 解密后的明文 */
int len;
unsigned char tmp[8];
unsigned char in[8];
unsigned char out[8];
//char *k = "12345678"; /* 原始密钥 */
// int key_len;
//#define LEN_OF_KEY 24
// unsigned char key[LEN_OF_KEY]; /* 补齐后的密钥 */
unsigned char block_key[9];
DES_key_schedule ks, ks2, ks3;
/* 构造补齐后的密钥 */
// key_len = strlen(k);
// memcpy(key, k, key_len);
// memset(key + key_len, 0x00, LEN_OF_KEY - key_len);
/* 分析补齐明文所需空间及补齐填充数据 */
data_rest = data_len % 8;
len = data_len;
src = (unsigned char *) malloc(len);
dst = (unsigned char *) malloc(len);
if (NULL == src || NULL == dst) {
docontinue = 0;
}
if (docontinue) {
int count;
int i;
/* 构造补齐后的加密内容 */
memset(src, 0, len);
memcpy(src, data, data_len);
/* 密钥置换 */
memset(block_key, 0, sizeof(block_key));
memcpy(block_key, key + 0, 8);
DES_set_key_unchecked((const_DES_cblock*) block_key, &ks);
memcpy(block_key, key + 8, 8);
DES_set_key_unchecked((const_DES_cblock*) block_key, &ks2);
memcpy(block_key, key + 16, 8);
DES_set_key_unchecked((const_DES_cblock*) block_key, &ks3);
/* 循环加密/解密,每8字节一次 */
count = len / 8;
for (i = 0; i < count; i++) {
memset(tmp, 0, 8);
memset(out, 0, 8);
memcpy(tmp, src + 8 * i, 8);
/* 加密 */
// DES_ecb3_encrypt((const_DES_cblock*) tmp, (DES_cblock*) in, &ks,
// &ks2, &ks3, DES_ENCRYPT);
/* 解密 */
DES_ecb3_encrypt((const_DES_cblock*) tmp, (DES_cblock*) out, &ks,
&ks2, &ks3,
DES_DECRYPT);
/* 将解密的内容拷贝到解密后的明文 */
memcpy(dst + 8 * i, out, 8);
}
for (i = 0; i < len; i++) {
if (*(dst + i) < 9) {
*(dst + i) = 0;
break;
}
}
}
if (NULL != src) {
free(src);
src = NULL;
}
if (NULL != dst) {
return dst;
}
return NULL;
}
# ifdef __cplusplus
}
# endif
附demo代码地址:http://download.csdn.net/detail/gao1040841994/9630750