个人博客地址:https://blog.yookingh.cn
该文章地址:https://blog.yookingh.cn/dev/201216-gmssl.html
简述
GmSSL是一个开源的密码工具箱,支持SM2/SM3/SM4/SM9/ZUC等国密(国家商用密码)算法、SM2国密数字证书及基于SM2证书的SSL/TLS安全通信协议,支持国密硬件密码设备,提供符合国密规范的编程接口与命令行工具,可以用于构建PKI/CA、安全通信、数据加密等符合国密标准的安全应用。
GmSSL项目是OpenSSL项目的分支,并与OpenSSL保持接口兼容。因此GmSSL可以替代应用中的OpenSSL组件,并使应用自动具备基于国密的安全能力。GmSSL项目采用对商业应用友好的类BSD开源许可证,开源且可以用于闭源的商业应用。
GmSSL项目由北京大学关志副研究员的密码学研究组开发维护,项目源码托管于GitHub。自2014年发布以来,GmSSL已经在多个项目和产品中获得部署与应用,并获得2015年度“一铭杯”中国Linux软件大赛二等奖(年度最高奖项)与开源中国密码类推荐项目。GmSSL项目的核心目标是通过开源的密码技术推动国内网络空间安全建设。
安装
编译环境参考OpenSSL的编译和使用
# 安装 目录 - yooking@ubuntu:~/Downloads/gmssl$
wget https://github.com/guanzhi/GmSSL/archive/master.zip
unzip master.zip
编译
-
生成Makefile文件
./config
生成Makefile文件# 目录 - yooking@ubuntu:~/Downloads/gmssl/GmSSL-master$ # 使用./执行config生成Makefile文件 ./config # 报错,信息如下 Operating system: x86_64-whatever-linux2 "glob" is not exported by the File::Glob module Can't continue after import errors at ./Configure line 18. BEGIN failed--compilation aborted at ./Configure line 18. "glob" is not exported by the File::Glob module Can't continue after import errors at ./Configure line 18. BEGIN failed--compilation aborted at ./Configure line 18. This system (linux-x86_64) is not supported. See file INSTALL for details.
打开
Configure
文件,修改line 18gedit Configure #line 18原始内容如下 use if $^O ne "VMS", 'File::Glob' => qw/glob/; #修改为 use if $^O ne "VMS", 'File::Glob' => qw/:glob/;
重新执行
./config
./config # 再次报错,信息如下 Something wrong with this line: Program fragment delivered error ``"glob" is not exported by the File::Glob module at /home/yooking/Downloads/gmssl/GmSSL-master/test/build.info at ./Configure line 1644.
修改对应文件
test/build.info
gedit test/build.info # build.info文件中发现 use if $^O ne "VMS", 'File::Glob' => qw/glob/; # 同样进行修改 use if $^O ne "VMS", 'File::Glob' => qw/:glob/;
再次执行
./config
即可生成Makefile文件 -
编写编译脚本(参考官方文档)(修改自Github开源项目)
下载开源项目,并根据提示进行了对应的修改,修改请看注释
#No
运行前先执行
# 请使用你的NDK路径 export ANDROID_NDK=/home/yooking/Public/android/android-sdk/ndk/android-ndk-r21d
_shared.sh
文件#!/bin/bash TOOLS_ROOT=`pwd` #1 这里使用的 ndk是r21d r21d 不具备 mips 和mips64 ARCHS=("android" "android-armeabi" "android64-aarch64" "android-x86" "android64") # "android-mips" "android-mips64" ABIS=("armeabi" "armeabi-v7a" "arm64-v8a" "x86" "x86_64" ) # "mips" "mips64" # Default to API 21 for it is the minimum requirement for 64 bit archs. #2 编译64位需要使用21或以上Anddroid-Api ANDROID_API=${ANDROID_API:-21} NDK=${ANDROID_NDK} configure() { ARCH=$1; OUT=$2; CLANG=${3:-""}; #3 记住这里,很占空间,github项目上并没有对这个进行删除,这里我们会在后续进行删除 TOOLCHAIN_ROOT=${TOOLS_ROOT}/${OUT}-android-toolchain if [ "$ARCH" == "android" ]; then export ARCH_FLAGS="-mthumb" export ARCH_LINK="" export TOOL="arm-linux-androideabi" NDK_FLAGS="--arch=arm" elif [ "$ARCH" == "android-armeabi" ]; then export ARCH_FLAGS="-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -mfpu=neon" export ARCH_LINK="-march=armv7-a -Wl,--fix-cortex-a8" export TOOL="arm-linux-androideabi" NDK_FLAGS="--arch=arm" elif [ "$ARCH" == "android64-aarch64" ]; then export ARCH_FLAGS="" export ARCH_LINK="" export TOOL="aarch64-linux-android" NDK_FLAGS="--arch=arm64" elif [ "$ARCH" == "android-x86" ]; then export ARCH_FLAGS="-march=i686 -mtune=intel -msse3 -mfpmath=sse -m32" export ARCH_LINK="" export TOOL="i686-linux-android" NDK_FLAGS="--arch=x86" elif [ "$ARCH" == "android64" ]; then export ARCH_FLAGS="-march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel" export ARCH_LINK="" export TOOL="x86_64-linux-android" NDK_FLAGS="--arch=x86_64" elif [ "$ARCH" == "android-mips" ]; then export ARCH_FLAGS="" export ARCH_LINK="" export TOOL="mipsel-linux-android" NDK_FLAGS="--arch=mips" elif [ "$ARCH" == "android-mips64" ]; then export ARCH="linux64-mips64" export ARCH_FLAGS="" export ARCH_LINK="" export TOOL="mips64el-linux-android" NDK_FLAGS="--arch=mips64" fi; [ -d ${TOOLCHAIN_ROOT} ] || python $NDK/build/tools/make_standalone_toolchain.py \ --api ${ANDROID_API} \ --stl libc++ \ --install-dir=${TOOLCHAIN_ROOT} \ $NDK_FLAGS export TOOLCHAIN_PATH=${TOOLCHAIN_ROOT}/bin export NDK_TOOLCHAIN_BASENAME=${TOOLCHAIN_PATH}/${TOOL} export SYSROOT=${TOOLCHAIN_ROOT}/sysroot export CROSS_SYSROOT=$SYSROOT if [ -z "${CLANG}" ]; then export CC=${NDK_TOOLCHAIN_BASENAME}-gcc export CXX=${NDK_TOOLCHAIN_BASENAME}-g++ else export CC=${TOOLCHAIN_PATH}/clang export CXX=${TOOLCHAIN_PATH}/clang++ fi; export LINK=${CXX} export LD=${NDK_TOOLCHAIN_BASENAME}-ld export AR=${NDK_TOOLCHAIN_BASENAME}-ar export RANLIB=${NDK_TOOLCHAIN_BASENAME}-ranlib export STRIP=${NDK_TOOLCHAIN_BASENAME}-strip export CPPFLAGS=${CPPFLAGS:-""} export LIBS=${LIBS:-""} export CFLAGS="${ARCH_FLAGS} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" export CXXFLAGS="${CFLAGS} -std=c++11 -frtti -fexceptions" export LDFLAGS="${ARCH_LINK}" echo "**********************************************" echo "use ANDROID_API=${ANDROID_API}" echo "use NDK=${NDK}" echo "export ARCH=${ARCH}" echo "export NDK_TOOLCHAIN_BASENAME=${NDK_TOOLCHAIN_BASENAME}" echo "export SYSROOT=${SYSROOT}" echo "export CC=${CC}" echo "export CXX=${CXX}" echo "export LINK=${LINK}" echo "export LD=${LD}" echo "export AR=${AR}" echo "export RANLIB=${RANLIB}" echo "export STRIP=${STRIP}" echo "export CPPFLAGS=${CPPFLAGS}" echo "export CFLAGS=${CFLAGS}" echo "export CXXFLAGS=${CXXFLAGS}" echo "export LDFLAGS=${LDFLAGS}" echo "export LIBS=${LIBS}" echo "**********************************************" }
build-gmssl4android.sh
文件#!/bin/bash # # Copyright 2016 leenjewel # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -u source ./_shared.sh # Setup architectures, library name and other vars + cleanup from previous runs LIB_NAME="GmSSL-master" LIB_DEST_DIR=${TOOLS_ROOT}/libs [ -d ${LIB_DEST_DIR} ] && rm -rf ${LIB_DEST_DIR} #4 这里判断了master.zip压缩包是否存在,如果不存在则下载最新的包,这里建议修改为判断解压后的文件夹是否存在,如果不存在才去重新下载,原因后续解释,例如[-f "GmSSL-master"] || wget https://github.com/guanzhi/GmSSL/archive/master.zip; [ -f "master.zip" ] || wget https://github.com/guanzhi/GmSSL/archive/master.zip; # Unarchive library, then configure and make for specified architectures configure_make() { ARCH=$1; ABI=$2; rm -rf "${LIB_NAME}" #5 这里建议修改为 #5 if[![-f "GmSSL-master"]];then #5 unzip -o "master.zip" #5 fi unzip -o "master.zip" pushd "${LIB_NAME}" configure $* #support openssl-1.0.x if [[ $LIB_NAME != "GmSSL-master" ]]; then if [[ $ARCH == "android-armeabi" ]]; then ARCH="android-armv7" elif [[ $ARCH == "android64" ]]; then ARCH="linux-x86_64 shared no-ssl2 no-ssl3 no-hw " elif [[ "$ARCH" == "android64-aarch64" ]]; then ARCH="android shared no-ssl2 no-ssl3 no-hw " fi fi echo "use android api:${ANDROID_API}" ./Configure $ARCH \ --prefix=${LIB_DEST_DIR}/${ABI} \ --with-zlib-include=$SYSROOT/usr/include \ --with-zlib-lib=$SYSROOT/usr/lib \ zlib \ no-asm \ no-shared \ no-unit-test\ no-serpent PATH=$TOOLCHAIN_PATH:$PATH if make -j4; then make install OUTPUT_ROOT=${TOOLS_ROOT}/../output/android/gmssl-${ABI} [ -d ${OUTPUT_ROOT}/include ] || mkdir -p ${OUTPUT_ROOT}/include cp -r ${LIB_DEST_DIR}/${ABI}/include/openssl ${OUTPUT_ROOT}/include [ -d ${OUTPUT_ROOT}/lib ] || mkdir -p ${OUTPUT_ROOT}/lib cp ${LIB_DEST_DIR}/${ABI}/lib/libcrypto.a ${OUTPUT_ROOT}/lib cp ${LIB_DEST_DIR}/${ABI}/lib/libssl.a ${OUTPUT_ROOT}/lib fi; popd } for ((i=0; i < ${#ARCHS[@]}; i++)) do if [[ $# -eq 0 ]] || [[ "$1" == "${ARCHS[i]}" ]]; then # Do not build 64 bit arch if ANDROID_API is less than 21 which is # the minimum supported API level for 64 bit. [[ ${ANDROID_API} < 21 ]] && ( echo "${ABIS[i]}" | grep 64 > /dev/null ) && continue; configure_make "${ARCHS[i]}" "${ABIS[i]}" fi #6 每次循环体结束,删除后缀为 -android-toolchain的文件,防止占用存储空间过大 rm -rf ${TOOLS_ROOT}/*-android-toolchain done
这里解释下注释
#4
的理由:
该Github开源项目已三年没有更新了,或许旧版本可以正常使用,但新版本中确实要修改Configure
和test/build.info
两个文件后才可以正常使用,因此在下载完毕master包后,需要对zip压缩包内的两个文件进行修改,后续解压后该代码才可正常执行。修改参考1.生成Makefile文件
如果参照#4
和#5
的修改建议,则可以修改解压后的GmSSL-master
内的对应文件。
引用
配置
Android Studio - gradle:3.5.2
ndk - android-ndk-r21d新建一个Native C++项目
将脚本生成的.a文件放在
app/libs/
下(必须,否则会报错)将CMakeLists.txt文件移动到
app/
下-
修改
app/buidl.gradle
android { defaultConfig { externalNativeBuild { cmake { cppFlags "-frtti -fexceptions -lz" } ndk { abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' } } } externalNativeBuild { cmake { path "CMakeLists.txt" } } }
-
修改
CMakeLists.txt
# For more information about using CMake with Android Studio, read the # documentation: https://d.android.com/studio/projects/add-native-code.html # Sets the minimum version of CMake required to build the native library. cmake_minimum_required(VERSION 3.4.1) # Creates and names a library, sets it as either STATIC # or SHARED, and provides the relative paths to its source code. # You can define multiple libraries, and CMake builds them for you. # Gradle automatically packages shared libraries with your APK. add_library( # Sets the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). src/main/cpp/native-lib.cpp src/main/cpp/utils.cpp ) #引用头文件目录 include_directories( src/main/cpp/include/) include_directories(src/main/cpp) add_library(crypto STATIC IMPORTED) set_target_properties(crypto PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libcrypto.a) # Searches for a specified prebuilt library and stores the path as a # variable. Because CMake includes system libraries in the search path by # default, you only need to specify the name of the public NDK library # you want to add. CMake verifies that the library exists before # completing its build. find_library( # Sets the name of the path variable. log-lib # Specifies the name of the NDK library that # you want CMake to locate. log ) # Specifies libraries CMake should link to your target library. You # can link multiple libraries, such as libraries you define in this # build script, prebuilt third-party libraries, or system libraries. target_link_libraries( # Specifies the target library. native-lib crypto # Links the target library to the log library # included in the NDK. ${log-lib} )
将
e_os.h
文件和openssl
文件夹移动到app/src/main/cpp/include
中将
crypto
文件夹移动到app/src/main/cpp
中
使用
-
utils.h
#ifndef MYAPPLICATION2_UTILS_H #define MYAPPLICATION2_UTILS_H unsigned char *hex2bin(const char *data, int size, int *outlen); char *bin2hex(unsigned char *data, int size); int b64_op(const unsigned char *in, int in_len, char *out, int out_len, int op); /*存储文件*/ int writeBufToFile(char *file, char *buf); /*读取文件*/ int readBufFromFile(char *file, char *buf); int initEcKey(EC_KEY *ec_key,char * path); #endif //MYAPPLICATION2_UTILS_H
-
utils.cpp
#include <openssl/bio.h> #include <openssl/evp.h> #include <fcntl.h> #include <e_os.h> #include <string> #include <openssl/ec.h> #include <crypto/ec/ec_lcl.h> #include "utils.h" unsigned char *hex2bin(const char *data, int size, int *outlen) { int i = 0; int len = 0; char char1 = '\0'; char char2 = '\0'; unsigned char value = 0; unsigned char *out = NULL; if (size % 2 != 0) { return NULL; } len = size / 2; out = (unsigned char *) malloc(len * sizeof(char) + 1); if (out == NULL) { return NULL; } while (i < len) { char1 = *data; if (char1 >= '0' && char1 <= '9') { value = (char1 - '0') << 4; } else if (char1 >= 'a' && char1 <= 'f') { value = (char1 - 'a' + 10) << 4; } else if (char1 >= 'A' && char1 <= 'F') { value = (char1 - 'A' + 10) << 4; } else { free(out); return NULL; } data++; char2 = *data; if (char2 >= '0' && char2 <= '9') { value |= char2 - '0'; } else if (char2 >= 'a' && char2 <= 'f') { value |= char2 - 'a' + 10; } else if (char2 >= 'A' && char2 <= 'F') { value |= char2 - 'A' + 10; } else { free(out); return NULL; } data++; *(out + i++) = value; } *(out + i) = '\0'; if (outlen != NULL) { *outlen = i; } return out; } char *bin2hex(unsigned char *data, int size) { int i = 0; int v = 0; char *p = NULL; char *buf = NULL; char base_char = 'A'; buf = p = (char *) malloc(size * 2 + 1); for (i = 0; i < size; i++) { v = data[i] >> 4; *p++ = v < 10 ? v + '0' : v - 10 + base_char; v = data[i] & 0x0f; *p++ = v < 10 ? v + '0' : v - 10 + base_char; } *p = '\0'; return buf; } int b64_op(const unsigned char *in, int in_len, char *out, int out_len, int op) { int ret = 0; BIO *b64 = BIO_new(BIO_f_base64()); BIO *bio = BIO_new(BIO_s_mem()); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); BIO_push(b64, bio); if (op == 0) { ret = BIO_write(b64, in, in_len); BIO_flush(b64); if (ret > 0) { ret = BIO_read(bio, out, out_len); } } else { ret = BIO_write(bio, in, in_len); BIO_flush(bio); if (ret) { ret = BIO_read(b64, out, out_len); } } BIO_free(b64); return ret; } int writeBufToFile(char *file, char *buf) { int fd = open(file, O_CREAT | O_RDWR, 0666); if (fd == -1) return -1; int offset = write(fd, buf, 1024); if (offset == 0) return -2; close(fd); return 0; } int readBufFromFile(char *file, char *buf) { int fd = open(file, O_CREAT | O_RDWR, 0666); if (fd == -1) return -1; int offset = read(fd, buf, 1024); if (offset == 0) return -2; close(fd); return 0; }
-
native-lib.cpp
#include <jni.h> #include <string> #include <malloc.h> #include <openssl/ec.h> #include <openssl/evp.h> #include <openssl/sm2.h> #include <openssl/sms4.h> #include <crypto/ec/ec_lcl.h> #include <openssl/aes.h> #include <crypto/sm2/sm2_lcl.h> #include "utils.h" #include <syslog.h> #include <openssl/pem.h> using std::string; char *path; //获取sm2的密钥 EC_KEY *getEcKey() { std::string p1 = path; p1.append("/private"); std::string p2 = path; p2.append("/public"); char *privateChar = (char *) malloc(1024); memset(privateChar, 0, 1024); readBufFromFile((char *) p1.c_str(), privateChar); char *publicChar = (char *) malloc(1024); memset(publicChar, 0, 1024); readBufFromFile((char *) p2.c_str(), publicChar); EC_KEY *ec_key; ec_key = EC_KEY_new_by_curve_name(NID_sm2p256v1); BN_CTX *ctx1 = BN_CTX_new(); EC_POINT *pubkey_point = EC_POINT_hex2point(ec_key->group, publicChar, NULL, ctx1); int iret = EC_KEY_set_public_key(ec_key, pubkey_point); BIGNUM *bn_prikey = BN_new(); iret = BN_hex2bn(&bn_prikey, privateChar); iret = EC_KEY_set_private_key(ec_key, bn_prikey); p1.clear(); p2.clear(); free(publicChar); free(privateChar); BN_free(bn_prikey); EC_POINT_free(pubkey_point); return ec_key; } extern "C" JNIEXPORT jbyteArray JNICALL Java_com_yooking_gmssldemo_MainActivity_aesEnc(JNIEnv *env, jobject instance, jbyteArray in_, jint length, jbyteArray key_) { jbyte *in = env->GetByteArrayElements(in_, NULL); jbyte *key = env->GetByteArrayElements(key_, NULL); int pading = AES_BLOCK_SIZE - length % AES_BLOCK_SIZE; int block = length / AES_BLOCK_SIZE; int endLen = AES_BLOCK_SIZE - pading; unsigned char *p = (unsigned char *) malloc(AES_BLOCK_SIZE + 1); memset(p, 0, AES_BLOCK_SIZE + 1); memset(p + endLen, pading, (size_t) pading); memcpy(p, in + block * AES_BLOCK_SIZE, (size_t) endLen); AES_KEY aes_key; AES_set_encrypt_key((const unsigned char *) key, 16 * 8, &aes_key); unsigned char *out = (unsigned char *) malloc((size_t) (length + pading + 1)); memset(out, 0, (size_t) (length + pading + 1)); for (int i = 0; i < block; i++) { AES_encrypt((const unsigned char *) (in + (i * AES_BLOCK_SIZE)), out + i * AES_BLOCK_SIZE, &aes_key); } AES_encrypt(p, out + block * AES_BLOCK_SIZE, &aes_key); jbyteArray array = env->NewByteArray(length + pading); env->SetByteArrayRegion(array, 0, length + pading, (const jbyte *) out); free(p); free(out); env->ReleaseByteArrayElements(in_, in, 0); env->ReleaseByteArrayElements(key_, key, 0); return array; } extern "C" JNIEXPORT jbyteArray JNICALL Java_com_yooking_gmssldemo_MainActivity_aesDec(JNIEnv *env, jobject instance, jbyteArray in_, jint length, jbyteArray key_) { jbyte *in = env->GetByteArrayElements(in_, NULL); jbyte *key = env->GetByteArrayElements(key_, NULL); AES_KEY aes_key; AES_set_decrypt_key((const unsigned char *) key, 16 * 8, &aes_key); unsigned char *out = (unsigned char *) malloc(length); memset(out, 0, length); for (int i = 0; i < length / 16; i++) { AES_decrypt((const unsigned char *) (in + (i * AES_BLOCK_SIZE)), out + i * AES_BLOCK_SIZE, &aes_key); } //去补位 int padinglen = out[length - 1]; memset(out + length - padinglen, 0, padinglen); jbyteArray array = env->NewByteArray(length - padinglen); env->SetByteArrayRegion(array, 0, length - padinglen, (const jbyte *) out); free(out); env->ReleaseByteArrayElements(in_, in, 0); env->ReleaseByteArrayElements(key_, key, 0); return array; } extern "C" JNIEXPORT jbyteArray JNICALL Java_com_yooking_gmssldemo_MainActivity_sha1(JNIEnv *env, jobject instance, jbyteArray in_, jint length) { jbyte *in = env->GetByteArrayElements(in_, NULL); unsigned char *sha1Msg = (unsigned char *) malloc(SHA_DIGEST_LENGTH + 1); memset(sha1Msg, 0, SHA_DIGEST_LENGTH + 1); SHA1((const unsigned char *) in, length, sha1Msg); jbyteArray array = env->NewByteArray(SHA_DIGEST_LENGTH); env->SetByteArrayRegion(array, 0, SHA_DIGEST_LENGTH, (const jbyte *) sha1Msg); free(sha1Msg); env->ReleaseByteArrayElements(in_, in, 0); return array; } extern "C" JNIEXPORT jint JNICALL Java_com_yooking_gmssldemo_MainActivity_genSM2KeyPairs(JNIEnv *env, jobject instance, jstring path_) { const char *p = env->GetStringUTFChars(path_, JNI_FALSE); int pLen = env->GetStringUTFLength(path_); path = (char *) malloc(pLen + 1); memset(path, 0, pLen + 1); memcpy(path, p, pLen); std::string p1 = path; p1.append("/private"); std::string p2 = path; p2.append("/public"); EC_KEY *ec_key = EC_KEY_new(); ec_key = EC_KEY_new_by_curve_name(NID_sm2p256v1); EC_KEY_generate_key(ec_key); const EC_POINT *point = EC_KEY_get0_public_key(ec_key); char *publicChar = EC_POINT_point2hex(EC_KEY_get0_group(ec_key), point, POINT_CONVERSION_UNCOMPRESSED, BN_CTX_new()); const BIGNUM *privateKey = EC_KEY_get0_private_key(ec_key); char *privateChar = BN_bn2hex(privateKey); int iRet = writeBufToFile((char *) p1.c_str(), privateChar); iRet = writeBufToFile((char *) p2.c_str(), publicChar); EC_KEY_free(ec_key); return 0; } extern "C" JNIEXPORT jbyteArray JNICALL Java_com_yooking_gmssldemo_MainActivity_sm3(JNIEnv *env, jobject instance, jbyteArray in_, jint length) { jbyte *in = env->GetByteArrayElements(in_, NULL); unsigned char *sm3Msg = (unsigned char *) malloc(SM3_DIGEST_LENGTH + 1); memset(sm3Msg, 0, SM3_DIGEST_LENGTH + 1); sm3((const unsigned char *) in, length, sm3Msg); jbyteArray array = env->NewByteArray(SM3_DIGEST_LENGTH); env->SetByteArrayRegion(array, 0, SM3_DIGEST_LENGTH, (const jbyte *) sm3Msg); free(sm3Msg); env->ReleaseByteArrayElements(in_, in, 0); return array; } extern "C" JNIEXPORT jbyteArray JNICALL Java_com_yooking_gmssldemo_MainActivity_sm4Enc(JNIEnv *env, jobject instance, jbyteArray in_, jint length, jbyteArray key_) { jbyte *in = env->GetByteArrayElements(in_, NULL); jbyte *key = env->GetByteArrayElements(key_, NULL); int pading = SMS4_KEY_LENGTH - length % SMS4_KEY_LENGTH; int block = length / SMS4_KEY_LENGTH; int endLen = SMS4_KEY_LENGTH - pading; unsigned char *p = (unsigned char *) malloc(SMS4_KEY_LENGTH + 1); memset(p, 0, SMS4_KEY_LENGTH + 1); memset(p + endLen, pading, (size_t) pading); memcpy(p, in + block * SMS4_KEY_LENGTH, (size_t) endLen); sms4_key_t sms4EncKey; sms4_set_encrypt_key(&sms4EncKey, (const unsigned char *) key); unsigned char *out = (unsigned char *) malloc((size_t) (length + pading + 1)); memset(out, 0, (size_t) (length + pading + 1)); for (int i = 0; i < block; i++) { sms4_encrypt((const unsigned char *) (in + (i * 16)), out + i * 16, &sms4EncKey); } sms4_encrypt(p, out + block * 16, &sms4EncKey); jbyteArray array = env->NewByteArray(length + pading); env->SetByteArrayRegion(array, 0, length + pading, (const jbyte *) out); free(p); free(out); env->ReleaseByteArrayElements(in_, in, 0); env->ReleaseByteArrayElements(key_, key, 0); return array; } extern "C" JNIEXPORT jbyteArray JNICALL Java_com_yooking_gmssldemo_MainActivity_sm4Dec(JNIEnv *env, jobject instance, jbyteArray in_, jint length, jbyteArray key_) { jbyte *in = env->GetByteArrayElements(in_, NULL); jbyte *key = env->GetByteArrayElements(key_, NULL); sms4_key_t sms4DecKey; sms4_set_decrypt_key(&sms4DecKey, (const unsigned char *) key); unsigned char *out = (unsigned char *) malloc(length); memset(out, 0, length); for (int i = 0; i < length / 16; i++) { sms4_decrypt((const unsigned char *) (in + (i * 16)), out + i * 16, &sms4DecKey); } //去补位 int padinglen = out[length - 1]; memset(out + length - padinglen, 0, padinglen); jbyteArray array = env->NewByteArray(length - padinglen); env->SetByteArrayRegion(array, 0, length - padinglen, (const jbyte *) out); free(out); env->ReleaseByteArrayElements(in_, in, 0); env->ReleaseByteArrayElements(key_, key, 0); return array; } extern "C" JNIEXPORT jbyteArray JNICALL Java_com_yooking_gmssldemo_MainActivity_sm2Enc(JNIEnv *env, jobject instance, jbyteArray in_, jint length) { jbyte *in = env->GetByteArrayElements(in_, NULL); int iRet = 0; EC_KEY *ec_key = getEcKey(); size_t sm2EncLen = SM2_MAX_PLAINTEXT_LENGTH; unsigned char *sm2EncMsg = (unsigned char *) malloc(SM2_MAX_PLAINTEXT_LENGTH); memset(sm2EncMsg, 0, SM2_MAX_PLAINTEXT_LENGTH); iRet = SM2_encrypt(NID_sm3, (const unsigned char *) in, (size_t) length, sm2EncMsg, &sm2EncLen, ec_key); if (!iRet) { ERR_load_ERR_strings(); ERR_load_crypto_strings(); unsigned long ulErr = ERR_get_error(); // 获取错误号 const char *pTmp = ERR_reason_error_string(ulErr); puts(pTmp); } jbyteArray array = env->NewByteArray(sm2EncLen); env->SetByteArrayRegion(array, 0, sm2EncLen, (const jbyte *) sm2EncMsg); free(sm2EncMsg); EC_KEY_free(ec_key); env->ReleaseByteArrayElements(in_, in, 0); return array; } extern "C" JNIEXPORT jbyteArray JNICALL Java_com_yooking_gmssldemo_MainActivity_sm2Dec(JNIEnv *env, jobject instance, jbyteArray in_, jint length) { jbyte *in = env->GetByteArrayElements(in_, NULL); int iRet = 0; EC_KEY *ec_key = getEcKey(); size_t sm2DecLen = 0; iRet = SM2_decrypt(NID_sm3, (const unsigned char *) in, (size_t) length, NULL, &sm2DecLen, ec_key); unsigned char *sm2DecMsg = (unsigned char *) malloc(sm2DecLen + 1); memset(sm2DecMsg, 0, sm2DecLen); iRet = SM2_decrypt(NID_sm3, (const unsigned char *) in, (size_t) length, sm2DecMsg, &sm2DecLen, ec_key); jbyteArray array = env->NewByteArray(sm2DecLen); env->SetByteArrayRegion(array, 0, sm2DecLen, (const jbyte *) sm2DecMsg); free(sm2DecMsg); EC_KEY_free(ec_key); env->ReleaseByteArrayElements(in_, in, 0); return array; } extern "C" JNIEXPORT jbyteArray JNICALL Java_com_yooking_gmssldemo_MainActivity_sm2Sign(JNIEnv *env, jobject instance, jbyteArray in_, jint length) { jbyte *in = env->GetByteArrayElements(in_, NULL); int iret = -1; EC_KEY *ec_key = getEcKey(); size_t zlen = 0; iret = SM2_compute_message_digest(EVP_sm3(), EVP_sm3(), (const unsigned char *) in, length, SM2_DEFAULT_ID_GMT09, SM2_DEFAULT_ID_LENGTH, NULL, &zlen, ec_key); if (!iret) { return NULL; } unsigned char *z = (unsigned char *) malloc(zlen + 1); memset(z, 0, zlen + 1); iret = SM2_compute_message_digest(EVP_sm3(), EVP_sm3(), (const unsigned char *) in, length, SM2_DEFAULT_ID_GMT09, SM2_DEFAULT_ID_LENGTH, z, &zlen, ec_key); if (!iret) { return NULL; } unsigned int signLen = 0; iret = SM2_sign(NID_sm3, z, zlen, NULL, &signLen, ec_key); if (!iret) { return NULL; } unsigned char *signMsg = (unsigned char *) malloc(signLen + 1); memset(signMsg, 0, signLen + 1); iret = SM2_sign(NID_sm3, z, zlen, signMsg, &signLen, ec_key); if (!iret) { return NULL; } jbyteArray array = env->NewByteArray(signLen); env->SetByteArrayRegion(array, 0, signLen, (const jbyte *) signMsg); free(signMsg); free(z); EC_KEY_free(ec_key); env->ReleaseByteArrayElements(in_, in, 0); return array; } extern "C" JNIEXPORT jint JNICALL Java_com_yooking_gmssldemo_MainActivity_sm2Verify(JNIEnv *env, jobject instance, jbyteArray in_, jint length, jbyteArray sign_, jint signLen) { jbyte *in = env->GetByteArrayElements(in_, NULL); jbyte *sign = env->GetByteArrayElements(sign_, NULL); int iret = -1; EC_KEY *ec_key = getEcKey(); size_t zlen = 0; iret = SM2_compute_message_digest(EVP_sm3(), EVP_sm3(), (const unsigned char *) in, length, SM2_DEFAULT_ID_GMT09, SM2_DEFAULT_ID_LENGTH, NULL, &zlen, ec_key); unsigned char *z = (unsigned char *) malloc(zlen + 1); memset(z, 0, zlen + 1); iret = SM2_compute_message_digest(EVP_sm3(), EVP_sm3(), (const unsigned char *) in, length, SM2_DEFAULT_ID_GMT09, SM2_DEFAULT_ID_LENGTH, z, &zlen, ec_key); if (!iret) { return -2; } iret = SM2_verify(NID_sm3, z, zlen, (const unsigned char *) sign, signLen, ec_key); free(z); EC_KEY_free(ec_key); env->ReleaseByteArrayElements(in_, in, 0); env->ReleaseByteArrayElements(sign_, sign, 0); return iret; } extern "C" JNIEXPORT jbyteArray JNICALL Java_com_yooking_gmssldemo_MainActivity_rsaEnc(JNIEnv *env, jobject instance, jbyteArray keys_, jbyteArray src_) { // LOGI("RSA->非对称密码算法,也就是说该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密"); jbyte *keys = env->GetByteArrayElements(keys_, NULL); jbyte *src = env->GetByteArrayElements(src_, NULL); jsize src_Len = env->GetArrayLength(src_); int ret = 0, src_flen = 0, cipherText_offset = 0, desText_len = 0, src_offset = 0; RSA *rsa = NULL; BIO *keybio = NULL; // LOGI("RSA->从字符串读取RSA公钥"); keybio = BIO_new_mem_buf(keys, -1); // LOGI("RSA->从bio结构中得到RSA结构"); rsa = PEM_read_bio_RSA_PUBKEY(keybio, NULL, NULL, NULL); // LOGI("RSA->释放BIO"); BIO_free_all(keybio); int flen = RSA_size(rsa); desText_len = flen * (src_Len / (flen - 11) + 1); unsigned char *srcOrigin = (unsigned char *) malloc(src_Len); unsigned char *cipherText = (unsigned char *) malloc(flen); unsigned char *desText = (unsigned char *) malloc(desText_len); memset(desText, 0, desText_len); memset(srcOrigin, 0, src_Len); memcpy(srcOrigin, src, src_Len); // LOGI("RSA->进行公钥加密操作"); //RSA_PKCS1_PADDING最大加密长度:128-11;RSA_NO_PADDING最大加密长度:128 for (int i = 0; i <= src_Len / (flen - 11); i++) { src_flen = (i == src_Len / (flen - 11)) ? src_Len % (flen - 11) : flen - 11; if (src_flen == 0) { break; } memset(cipherText, 0, flen); ret = RSA_public_encrypt(src_flen, srcOrigin + src_offset, cipherText, rsa, RSA_PKCS1_PADDING); memcpy(desText + cipherText_offset, cipherText, ret); cipherText_offset += ret; src_offset += src_flen; } RSA_free(rsa); // LOGI("RSA->CRYPTO_cleanup_all_ex_data"); CRYPTO_cleanup_all_ex_data(); // LOGI("RSA->从jni释放数据指针"); env->ReleaseByteArrayElements(keys_, keys, 0); env->ReleaseByteArrayElements(src_, src, 0); jbyteArray cipher = env->NewByteArray(cipherText_offset); // LOGI("RSA->在堆中分配ByteArray数组对象成功,将拷贝数据到数组中"); env->SetByteArrayRegion(cipher, 0, cipherText_offset, (jbyte *) desText); // LOGI("RSA->释放内存"); free(srcOrigin); free(cipherText); free(desText); return cipher; } extern "C" JNIEXPORT jbyteArray JNICALL Java_com_yooking_gmssldemo_MainActivity_rsaDes(JNIEnv *env, jobject instance, jbyteArray keys_, jbyteArray src_) { // LOGI("RSA->非对称密码算法,也就是说该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密"); jbyte *keys = env->GetByteArrayElements(keys_, NULL); jbyte *src = env->GetByteArrayElements(src_, NULL); jsize src_Len = env->GetArrayLength(src_); int ret = 0, src_flen = 0, plaintext_offset = 0, descText_len = 0, src_offset = 0; RSA *rsa = NULL; BIO *keybio = NULL; // LOGI("RSA->从字符串读取RSA私钥"); keybio = BIO_new_mem_buf(keys, -1); // LOGI("RSA->从bio结构中得到RSA结构"); rsa = PEM_read_bio_RSAPrivateKey(keybio, NULL, NULL, NULL); // LOGI("RSA->释放BIO"); BIO_free_all(keybio); int flen = RSA_size(rsa); descText_len = (flen - 11) * (src_Len / flen + 1); unsigned char *srcOrigin = (unsigned char *) malloc(src_Len); unsigned char *plaintext = (unsigned char *) malloc(flen - 11); unsigned char *desText = (unsigned char *) malloc(descText_len); memset(desText, 0, descText_len); memset(srcOrigin, 0, src_Len); memcpy(srcOrigin, src, src_Len); // LOGI("RSA->进行私钥解密操作"); //一次性解密数据最大字节数RSA_size for (int i = 0; i <= src_Len / flen; i++) { src_flen = (i == src_Len / flen) ? src_Len % flen : flen; if (src_flen == 0) { break; } memset(plaintext, 0, flen - 11); ret = RSA_private_decrypt(src_flen, srcOrigin + src_offset, plaintext, rsa, RSA_PKCS1_PADDING); memcpy(desText + plaintext_offset, plaintext, ret); plaintext_offset += ret; src_offset += src_flen; } RSA_free(rsa); // LOGI("RSA->CRYPTO_cleanup_all_ex_data"); CRYPTO_cleanup_all_ex_data(); // LOGI("RSA->从jni释放数据指针"); env->ReleaseByteArrayElements(keys_, keys, 0); env->ReleaseByteArrayElements(src_, src, 0); jbyteArray cipher = env->NewByteArray(plaintext_offset); // LOGI("RSA->在堆中分配ByteArray数组对象成功,将拷贝数据到数组中"); env->SetByteArrayRegion(cipher, 0, plaintext_offset, (jbyte *) desText); // LOGI("RSA->释放内存"); free(srcOrigin); free(plaintext); free(desText); return cipher; } extern "C" JNIEXPORT jbyteArray JNICALL Java_com_yooking_gmssldemo_MainActivity_rsaSign(JNIEnv *env, jobject instance, jbyteArray keys_, jbyteArray src_) { // LOGI("RSA->非对称密码算法,也就是说该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密"); jbyte *keys = env->GetByteArrayElements(keys_, NULL); jbyte *src = env->GetByteArrayElements(src_, NULL); jsize src_Len = env->GetArrayLength(src_); unsigned int siglen = 0; unsigned char digest[SHA_DIGEST_LENGTH]; RSA *rsa = NULL; BIO *keybio = NULL; // LOGI("RSA->从字符串读取RSA公钥"); keybio = BIO_new_mem_buf(keys, -1); // LOGI("RSA->从bio结构中得到RSA结构"); rsa = PEM_read_bio_RSAPrivateKey(keybio, NULL, NULL, NULL); // LOGI("RSA->释放BIO"); BIO_free_all(keybio); unsigned char *sign = (unsigned char *) malloc(129); memset(sign, 0, 129); SHA1((const unsigned char *) src, src_Len, digest); RSA_sign(NID_sha1, digest, SHA_DIGEST_LENGTH, sign, &siglen, rsa); RSA_free(rsa); // LOGI("RSA->CRYPTO_cleanup_all_ex_data"); CRYPTO_cleanup_all_ex_data(); // LOGI("RSA->从jni释放数据指针"); env->ReleaseByteArrayElements(keys_, keys, 0); env->ReleaseByteArrayElements(src_, src, 0); jbyteArray cipher = env->NewByteArray(siglen); // LOGI("RSA->在堆中分配ByteArray数组对象成功,将拷贝数据到数组中"); env->SetByteArrayRegion(cipher, 0, siglen, (jbyte *) sign); // LOGI("RSA->释放内存"); free(sign); return cipher; } extern "C" JNIEXPORT jint JNICALL Java_com_yooking_gmssldemo_MainActivity_rsaVerify(JNIEnv *env, jobject instance, jbyteArray keys_, jbyteArray src_, jbyteArray sign_) { // LOGI("RSA->非对称密码算法,也就是说该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密"); jbyte *keys = env->GetByteArrayElements(keys_, NULL); jbyte *src = env->GetByteArrayElements(src_, NULL); jbyte *sign = env->GetByteArrayElements(sign_, NULL); jsize src_Len = env->GetArrayLength(src_); jsize siglen = env->GetArrayLength(sign_); int ret; unsigned char digest[SHA_DIGEST_LENGTH]; RSA *rsa = NULL; BIO *keybio = NULL; // LOGI("RSA->从字符串读取RSA公钥"); keybio = BIO_new_mem_buf(keys, -1); // LOGI("RSA->从bio结构中得到RSA结构"); rsa = PEM_read_bio_RSA_PUBKEY(keybio, NULL, NULL, NULL); // LOGI("RSA->释放BIO"); BIO_free_all(keybio); SHA1((const unsigned char *) src, src_Len, digest); ret = RSA_verify(NID_sha1, digest, SHA_DIGEST_LENGTH, (const unsigned char *) sign, siglen, rsa); RSA_free(rsa); // LOGI("RSA->CRYPTO_cleanup_all_ex_data"); CRYPTO_cleanup_all_ex_data(); // LOGI("RSA->从jni释放数据指针"); env->ReleaseByteArrayElements(keys_, keys, 0); env->ReleaseByteArrayElements(src_, src, 0); env->ReleaseByteArrayElements(sign_, sign, 0); return ret; }