这里主要是openssl常用的编码Base64, 摘要算法MD5,对称加密AES, 非对称加密RSA与Java互通
一: openssl交叉编译
openssl源码下载, NDK下载
这里下载的openssl版本是1.1.0f, NDK版本是21, Ubuntu18,解压openssl代码包执行 config或者Configure可以查看编译时的附加参数列表, NDK如何编译,在developer NDK文档中都有详细介绍,也有编译时的示例脚本,要编译的第三库也一般会提供config, configure相关编译参数文件,./执行即可查看
就是根据下载的NDK包配置好编译时对应的CC(编译C代码)/CXX(编译C++),在NDK21时都已经采用clang(弃用了gcc)和SYSROOT等路径,openssl1.1.0f是纯C写的只要配置CC就行,这里编译的shell脚本在项目源码中,已经编译了arm64-v8a和armeabi-v7a的包
二:openssl与java互相加解密
openssl中文手册,这里只介绍C++与JAVA相互编解,加解密时的注意点
1:Base64
android已经提供好android.util.Base64类, 编解码时注意byte[]转换编码格式一致即可
const char *data = env->GetStringUTFChars(_data, JNI_FALSE);
//GetStringUTFChars 与java代码data.getBytes(UTF8)对应编码一致即可
Base64.encode(data.getBytes(UTF8))
2:MD5
同样在byte[]转换时统一编码格式,摘要算法后的byte[]统一转16进制及统一大小写即可
std::string MD5Code::md5(const char *src, size_t src_len) {
unsigned char md[16];
MD5((unsigned char *) src, src_len, md);
char md5str[33]{0}; //MD5结果 32 + \0
for (int i = 0; i < 16; i++) {
sprintf(md5str, "%s%02x", md5str, md[i]);
}
return md5str;
}
3:AES
加密模式如ECB,CBC,填充方式一致即可如PKCS5Padding,ZEROPading,加密后的byte[]转换base64时的编码也要一致 (如下openssl部分填充方式代码)
void Padding::padding(std::string &src, int alignSize, PaddingModel mode) {
int remainder = src.length() % alignSize;
int paddingSize = (remainder == 0) ? alignSize : (alignSize - remainder);
switch (mode) {
case PKCS5OR7:
src.append(paddingSize, paddingSize);
break;
case ZERO:
default:
src.append(paddingSize, 0);
break;
}
}
4: RSA (一般用加密AES需要的KEY)
openssl的公私钥采用的是PEM格式,JAVA采用的是DER格式,openssl生成的PEM格式的公私钥通过bouncycastlel转换成DER格式及生成密钥时的长度一致即可, 加解密时的填充方式如(PKCS1Padding)一致
如部分转换PEM成DER格式公钥代码
public static PublicKey getFromPemPublicKey(String public_key) throws Exception {
byte[] keyBytes = new sun.misc.BASE64Decoder().decodeBuffer(public_key);
ASN1InputStream in = new ASN1InputStream(keyBytes);
DERObject obj = in.readObject();
RSAPublicKeyStructure pStruct = RSAPublicKeyStructure.getInstance(obj);
RSAPublicKeySpec spec = new RSAPublicKeySpec(pStruct.getModulus(), pStruct.getPublicExponent());
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(spec);
}
测试如
最后是源码地址