├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── wtuadn │ │ └── demo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── wtuadn │ │ │ └── demo │ │ │ └── MainActivity.java │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── wtuadn │ └── demo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── CMakeLists.txt ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── cpp │ ├── aes.c │ ├── aes.h │ ├── base64.c │ ├── base64.h │ ├── jni_tool.cpp │ ├── md5.cpp │ └── md5.h │ └── java │ └── com │ └── wtuadn │ └── jnitool │ └── JNITool.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JNITool 2 | NDK实现的工具库,支持AES的ECB和CBC加解密(支持emoji),MD5加盐 3 | 4 | AES基于[tiny-AES128-C](https://github.com/kokke/tiny-AES128-C)扩展,根据key长度自动选择AES128、AES192、AES256 5 | 6 | 默认采用PKCS7Padding填充(和PKCS5Padding一样),加密后进行一次Base64 7 | 8 | 应用包名和签名的hash code放在native层,使用前会进行签名检验,防二次打包 9 | 10 | JNITool.java : 11 | ```java 12 | public static native String pwdMD5(String str); 13 | public static String encrypt(String str); 14 | public static String decrypt(String str); 15 | ``` 16 | 17 | aes.c : 18 | ```c 19 | char *AES_ECB_PKCS7_Encrypt(const char *in, const uint8_t *key); 20 | char *AES_ECB_PKCS7_Decrypt(const char *in, const uint8_t *key); 21 | char *AES_CBC_PKCS7_Encrypt(const char *in, const uint8_t *key, const uint8_t *iv); 22 | char *AES_CBC_PKCS7_Decrypt(const char *in, const uint8_t *key, const uint8_t *iv); 23 | ``` 24 | 25 | 使用前记得修改jni_tool.cpp的以下内容: 26 | ```c++ 27 | static const char *app_packageName = "com.wtuadn.demo"; 28 | static const int app_signature_hash_code = -827662039; 29 | static const uint8_t AES_KEY[] = "xS544RXNm0P4JVLHIEsTqJNzDbZhiLjr"; 30 | static const uint8_t AES_IV[] = "KXTUDEdBs9zGlvy7"; 31 | static const string PWD_MD5_KEY = "4J9lKuR2c8OuDPBAniEy5USFQdSM0An4"; 32 | ``` 33 | **app_signature_hash_code**获取方法见demo 34 | 35 | ## Tips 36 | 如果只用到ECB或者CBC算法,可以把aes.h头文件里没用到的定义注释掉,减小生成的so文件体积 37 | ```c 38 | #ifndef CBC 39 | #define CBC 1 40 | #endif 41 | 42 | #ifndef ECB 43 | #define ECB 1 44 | #endif 45 | ``` 46 | 47 | ### 鸣谢 48 | > [tiny-AES128-C](https://github.com/kokke/tiny-AES128-C)、[AESJniEncrypt](https://github.com/weizongwei5/AESJniEncrypt)、[MD5](https://github.com/JieweiWei/md5) 49 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | buildToolsVersion "26.0.2" 6 | defaultConfig { 7 | applicationId "com.wtuadn.demo" 8 | minSdkVersion 14 9 | targetSdkVersion 26 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile project(':library') 25 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 26 | exclude group: 'com.android.support', module: 'support-annotations' 27 | }) 28 | compile 'com.android.support:appcompat-v7:26.1.0' 29 | testCompile 'junit:junit:4.12' 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\workspace\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/wtuadn/demo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.wtuadn.demo; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.assertEquals; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.wtuadn.demo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/wtuadn/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.wtuadn.demo; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.util.Log; 6 | 7 | import com.wtuadn.jnitool.JNITool; 8 | 9 | 10 | public class MainActivity extends AppCompatActivity { 11 | private static final String TAG = "jnidemo"; 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_main); 17 | 18 | Log.e(TAG, "signature:" + JNITool.getSignature(this)); 19 | 20 | String originalStr = "123"; 21 | String encrypt = JNITool.encrypt(originalStr); 22 | Log.e(TAG, "原字符串:" + originalStr); 23 | Log.e(TAG, "AES ECB PKCS7Padding 加密:" + encrypt); 24 | Log.e(TAG, "AES ECB PKCS7Padding 解密:" + JNITool.decrypt(encrypt)); 25 | 26 | String pwdStr = "pwd123456"; 27 | Log.e(TAG, "password: " + pwdStr); 28 | Log.e(TAG, "md5再加salt: " + JNITool.pwdMD5(pwdStr)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wtuadn/JNITool/9b4b381e4ca29b697caa79a0d55ee89a8a6c4a71/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wtuadn/JNITool/9b4b381e4ca29b697caa79a0d55ee89a8a6c4a71/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #00000000 4 | #ffffff 5 | #000000 6 | #fe642d 7 | #ff0000 8 | #cccccc 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | JNITool Demo 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/test/java/com/wtuadn/demo/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.wtuadn.demo; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | google() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.0.1' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | google() 19 | } 20 | } 21 | 22 | task clean(type: Delete) { 23 | delete rootProject.buildDir 24 | } 25 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wtuadn/JNITool/9b4b381e4ca29b697caa79a0d55ee89a8a6c4a71/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Mar 08 10:09:51 CST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For more information about using CMake with Android Studio, read the 2 | # documentation: https://d.android.com/studio/projects/add-native-code.html 3 | 4 | # Sets the minimum version of CMake required to build the native library. 5 | 6 | cmake_minimum_required(VERSION 3.4.1) 7 | 8 | # Creates and names a library, sets it as either STATIC 9 | # or SHARED, and provides the relative paths to its source code. 10 | # You can define multiple libraries, and CMake builds them for you. 11 | # Gradle automatically packages shared libraries with your APK. 12 | 13 | add_library( # Sets the name of the library. 14 | jni_tool 15 | 16 | # Sets the library as a shared library. 17 | SHARED 18 | 19 | # Provides a relative path to your source file(s). 20 | src/main/cpp/jni_tool.cpp 21 | src/main/cpp/md5.cpp 22 | src/main/cpp/aes.c 23 | src/main/cpp/base64.c) 24 | 25 | # Searches for a specified prebuilt library and stores the path as a 26 | # variable. Because CMake includes system libraries in the search path by 27 | # default, you only need to specify the name of the public NDK library 28 | # you want to add. CMake verifies that the library exists before 29 | # completing its build. 30 | 31 | # find_library( # Sets the name of the path variable. 32 | # log-lib 33 | # # Specifies the name of the NDK library that 34 | # # you want CMake to locate. 35 | # log ) 36 | 37 | # Specifies libraries CMake should link to your target library. You 38 | # can link multiple libraries, such as libraries you define in this 39 | # build script, prebuilt third-party libraries, or system libraries. 40 | 41 | # target_link_libraries( # Specifies the target library. 42 | # jni_tool 43 | # # Links the target library to the log library 44 | # # included in the NDK. 45 | # ${log-lib} ) -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 26 5 | buildToolsVersion "26.0.2" 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 26 10 | 11 | externalNativeBuild { 12 | cmake { 13 | cppFlags "-std=c++11" 14 | } 15 | } 16 | } 17 | 18 | externalNativeBuild { 19 | cmake { 20 | path "CMakeLists.txt" 21 | } 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /library/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\wtuadn\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /library/src/main/cpp/aes.c: -------------------------------------------------------------------------------- 1 | /*****************************************************************************/ 2 | /* Includes: */ 3 | /*****************************************************************************/ 4 | #include "aes.h" 5 | 6 | 7 | /*****************************************************************************/ 8 | /* Defines: */ 9 | /*****************************************************************************/ 10 | // The number of columns comprising a state in AES. This is a constant in AES. Value=4 11 | #define Nb 4 12 | // aes BLOCK SIZE. Value=16 13 | #define BLOCK_SIZE 16 14 | 15 | // jcallan@github points out that declaring Multiply as a function 16 | // reduces code size considerably with the Keil ARM compiler. 17 | // See this link for more information: https://github.com/kokke/tiny-AES128-C/pull/3 18 | #ifndef MULTIPLY_AS_A_FUNCTION 19 | #define MULTIPLY_AS_A_FUNCTION 0 20 | #endif 21 | 22 | 23 | /*****************************************************************************/ 24 | /* Private variables: */ 25 | /*****************************************************************************/ 26 | // state - array holding the intermediate results during decryption. 27 | typedef uint8_t state_t[4][4]; 28 | static state_t *state; 29 | 30 | // The array that stores the round keys. 31 | static uint8_t RoundKey[240]; 32 | 33 | // The Key input to the AES Program 34 | static const uint8_t *Key; 35 | 36 | // The number of 32 bit words in a key. 37 | static char Nk;//4 for aes 128 38 | // The number of rounds in AES Cipher. 39 | static char Nr;//10 for aes 128 40 | // Key length in bytes [128 bit]. 41 | static char KEYLEN;//16 for aes 128 42 | 43 | #if defined(CBC) && CBC 44 | // Initial Vector used only for CBC mode 45 | static uint8_t *Iv; 46 | #endif 47 | 48 | // The lookup-tables are marked const so they can be placed in read-only storage instead of RAM 49 | // The numbers below can be computed dynamically trading ROM for RAM - 50 | // This can be useful in (embedded) bootloader applications, where ROM is often limited. 51 | static const uint8_t sbox[256] = { 52 | //0 1 2 3 4 5 6 7 8 9 A B C D E F 53 | 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 54 | 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 55 | 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 56 | 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 57 | 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 58 | 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 59 | 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 60 | 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 61 | 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 62 | 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 63 | 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 64 | 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 65 | 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 66 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 67 | 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 68 | 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}; 69 | 70 | static const uint8_t rsbox[256] = 71 | {0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 72 | 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 73 | 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 74 | 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 75 | 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 76 | 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 77 | 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 78 | 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 79 | 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 80 | 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 81 | 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 82 | 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 83 | 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 84 | 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 85 | 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 86 | 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d}; 87 | 88 | 89 | // The round constant word array, Rcon[i], contains the values given by 90 | // x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) 91 | // Note that i starts at 1, not 0). 92 | static const uint8_t Rcon[15] = { 93 | 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d}; 94 | 95 | 96 | /*****************************************************************************/ 97 | /* Private functions: */ 98 | /*****************************************************************************/ 99 | static uint8_t getSBoxValue(uint8_t num) { 100 | return sbox[num]; 101 | } 102 | 103 | static uint8_t getSBoxInvert(uint8_t num) { 104 | return rsbox[num]; 105 | } 106 | 107 | // This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. 108 | static void KeyExpansion(void) { 109 | uint32_t i, j, k; 110 | uint8_t tempa[4]; // Used for the column/row operations 111 | 112 | Nk = KEYLEN / 4; 113 | Nr = 6 + Nk; 114 | 115 | // The first round key is the key itself. 116 | for (i = 0; i < Nk; ++i) { 117 | RoundKey[(i * 4) + 0] = Key[(i * 4) + 0]; 118 | RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; 119 | RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; 120 | RoundKey[(i * 4) + 3] = Key[(i * 4) + 3]; 121 | } 122 | 123 | // All other round keys are found from the previous round keys. 124 | for (; (i < (Nb * (Nr + 1))); ++i) { 125 | for (j = 0; j < 4; ++j) { 126 | tempa[j] = RoundKey[(i - 1) * 4 + j]; 127 | } 128 | if (i % Nk == 0) { 129 | // This function rotates the 4 bytes in a word to the left once. 130 | // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] 131 | 132 | // Function RotWord() 133 | { 134 | k = tempa[0]; 135 | tempa[0] = tempa[1]; 136 | tempa[1] = tempa[2]; 137 | tempa[2] = tempa[3]; 138 | tempa[3] = k; 139 | } 140 | 141 | // SubWord() is a function that takes a four-byte input word and 142 | // applies the S-box to each of the four bytes to produce an output word. 143 | 144 | // Function Subword() 145 | { 146 | tempa[0] = getSBoxValue(tempa[0]); 147 | tempa[1] = getSBoxValue(tempa[1]); 148 | tempa[2] = getSBoxValue(tempa[2]); 149 | tempa[3] = getSBoxValue(tempa[3]); 150 | } 151 | 152 | tempa[0] = tempa[0] ^ Rcon[i / Nk]; 153 | } else if (Nk > 6 && i % Nk == 4) { 154 | // Function Subword() 155 | { 156 | tempa[0] = getSBoxValue(tempa[0]); 157 | tempa[1] = getSBoxValue(tempa[1]); 158 | tempa[2] = getSBoxValue(tempa[2]); 159 | tempa[3] = getSBoxValue(tempa[3]); 160 | } 161 | } 162 | RoundKey[i * 4 + 0] = RoundKey[(i - Nk) * 4 + 0] ^ tempa[0]; 163 | RoundKey[i * 4 + 1] = RoundKey[(i - Nk) * 4 + 1] ^ tempa[1]; 164 | RoundKey[i * 4 + 2] = RoundKey[(i - Nk) * 4 + 2] ^ tempa[2]; 165 | RoundKey[i * 4 + 3] = RoundKey[(i - Nk) * 4 + 3] ^ tempa[3]; 166 | } 167 | } 168 | 169 | // This function adds the round key to state. 170 | // The round key is added to the state by an XOR function. 171 | static void AddRoundKey(uint8_t round) { 172 | uint8_t i, j; 173 | for (i = 0; i < 4; ++i) { 174 | for (j = 0; j < 4; ++j) { 175 | (*state)[i][j] ^= RoundKey[round * Nb * 4 + i * Nb + j]; 176 | } 177 | } 178 | } 179 | 180 | // The SubBytes Function Substitutes the values in the 181 | // state matrix with values in an S-box. 182 | static void SubBytes(void) { 183 | uint8_t i, j; 184 | for (i = 0; i < 4; ++i) { 185 | for (j = 0; j < 4; ++j) { 186 | (*state)[j][i] = getSBoxValue((*state)[j][i]); 187 | } 188 | } 189 | } 190 | 191 | // The ShiftRows() function shifts the rows in the state to the left. 192 | // Each row is shifted with different offset. 193 | // Offset = Row number. So the first row is not shifted. 194 | static void ShiftRows(void) { 195 | uint8_t temp; 196 | 197 | // Rotate first row 1 columns to left 198 | temp = (*state)[0][1]; 199 | (*state)[0][1] = (*state)[1][1]; 200 | (*state)[1][1] = (*state)[2][1]; 201 | (*state)[2][1] = (*state)[3][1]; 202 | (*state)[3][1] = temp; 203 | 204 | // Rotate second row 2 columns to left 205 | temp = (*state)[0][2]; 206 | (*state)[0][2] = (*state)[2][2]; 207 | (*state)[2][2] = temp; 208 | 209 | temp = (*state)[1][2]; 210 | (*state)[1][2] = (*state)[3][2]; 211 | (*state)[3][2] = temp; 212 | 213 | // Rotate third row 3 columns to left 214 | temp = (*state)[0][3]; 215 | (*state)[0][3] = (*state)[3][3]; 216 | (*state)[3][3] = (*state)[2][3]; 217 | (*state)[2][3] = (*state)[1][3]; 218 | (*state)[1][3] = temp; 219 | } 220 | 221 | static uint8_t xtime(uint8_t x) { 222 | return ((x << 1) ^ (((x >> 7) & 1) * 0x1b)); 223 | } 224 | 225 | // MixColumns function mixes the columns of the state matrix 226 | static void MixColumns(void) { 227 | uint8_t i; 228 | uint8_t Tmp, Tm, t; 229 | for (i = 0; i < 4; ++i) { 230 | t = (*state)[i][0]; 231 | Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3]; 232 | Tm = (*state)[i][0] ^ (*state)[i][1]; 233 | Tm = xtime(Tm); 234 | (*state)[i][0] ^= Tm ^ Tmp; 235 | Tm = (*state)[i][1] ^ (*state)[i][2]; 236 | Tm = xtime(Tm); 237 | (*state)[i][1] ^= Tm ^ Tmp; 238 | Tm = (*state)[i][2] ^ (*state)[i][3]; 239 | Tm = xtime(Tm); 240 | (*state)[i][2] ^= Tm ^ Tmp; 241 | Tm = (*state)[i][3] ^ t; 242 | Tm = xtime(Tm); 243 | (*state)[i][3] ^= Tm ^ Tmp; 244 | } 245 | } 246 | 247 | // Multiply is used to multiply numbers in the field GF(2^8) 248 | #if MULTIPLY_AS_A_FUNCTION 249 | static uint8_t Multiply(uint8_t x, uint8_t y) 250 | { 251 | return (((y & 1) * x) ^ 252 | ((y>>1 & 1) * xtime(x)) ^ 253 | ((y>>2 & 1) * xtime(xtime(x))) ^ 254 | ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ 255 | ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); 256 | } 257 | #else 258 | #define Multiply(x, y) \ 259 | ( ((y & 1) * x) ^ \ 260 | ((y>>1 & 1) * xtime(x)) ^ \ 261 | ((y>>2 & 1) * xtime(xtime(x))) ^ \ 262 | ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \ 263 | ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \ 264 | 265 | #endif 266 | 267 | // MixColumns function mixes the columns of the state matrix. 268 | // The method used to multiply may be difficult to understand for the inexperienced. 269 | // Please use the references to gain more information. 270 | static void InvMixColumns(void) { 271 | int i; 272 | uint8_t a, b, c, d; 273 | for (i = 0; i < 4; ++i) { 274 | a = (*state)[i][0]; 275 | b = (*state)[i][1]; 276 | c = (*state)[i][2]; 277 | d = (*state)[i][3]; 278 | 279 | (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); 280 | (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); 281 | (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); 282 | (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); 283 | } 284 | } 285 | 286 | 287 | // The SubBytes Function Substitutes the values in the 288 | // state matrix with values in an S-box. 289 | static void InvSubBytes(void) { 290 | uint8_t i, j; 291 | for (i = 0; i < 4; ++i) { 292 | for (j = 0; j < 4; ++j) { 293 | (*state)[j][i] = getSBoxInvert((*state)[j][i]); 294 | } 295 | } 296 | } 297 | 298 | static void InvShiftRows(void) { 299 | uint8_t temp; 300 | 301 | // Rotate first row 1 columns to right 302 | temp = (*state)[3][1]; 303 | (*state)[3][1] = (*state)[2][1]; 304 | (*state)[2][1] = (*state)[1][1]; 305 | (*state)[1][1] = (*state)[0][1]; 306 | (*state)[0][1] = temp; 307 | 308 | // Rotate second row 2 columns to right 309 | temp = (*state)[0][2]; 310 | (*state)[0][2] = (*state)[2][2]; 311 | (*state)[2][2] = temp; 312 | 313 | temp = (*state)[1][2]; 314 | (*state)[1][2] = (*state)[3][2]; 315 | (*state)[3][2] = temp; 316 | 317 | // Rotate third row 3 columns to right 318 | temp = (*state)[0][3]; 319 | (*state)[0][3] = (*state)[1][3]; 320 | (*state)[1][3] = (*state)[2][3]; 321 | (*state)[2][3] = (*state)[3][3]; 322 | (*state)[3][3] = temp; 323 | } 324 | 325 | 326 | // Cipher is the main function that encrypts the PlainText. 327 | static void Cipher(void) { 328 | uint8_t round = 0; 329 | 330 | // Add the First round key to the state before starting the rounds. 331 | AddRoundKey(0); 332 | 333 | // There will be Nr rounds. 334 | // The first Nr-1 rounds are identical. 335 | // These Nr-1 rounds are executed in the loop below. 336 | for (round = 1; round < Nr; ++round) { 337 | SubBytes(); 338 | ShiftRows(); 339 | MixColumns(); 340 | AddRoundKey(round); 341 | } 342 | 343 | // The last round is given below. 344 | // The MixColumns function is not here in the last round. 345 | SubBytes(); 346 | ShiftRows(); 347 | AddRoundKey(Nr); 348 | } 349 | 350 | static void InvCipher(void) { 351 | uint8_t round = 0; 352 | 353 | // Add the First round key to the state before starting the rounds. 354 | AddRoundKey(Nr); 355 | 356 | // There will be Nr rounds. 357 | // The first Nr-1 rounds are identical. 358 | // These Nr-1 rounds are executed in the loop below. 359 | for (round = Nr - 1; round > 0; round--) { 360 | InvShiftRows(); 361 | InvSubBytes(); 362 | AddRoundKey(round); 363 | InvMixColumns(); 364 | } 365 | 366 | // The last round is given below. 367 | // The MixColumns function is not here in the last round. 368 | InvShiftRows(); 369 | InvSubBytes(); 370 | AddRoundKey(0); 371 | } 372 | 373 | static void BlockCopy(uint8_t *output, const uint8_t *input) { 374 | uint8_t i; 375 | for (i = 0; i < BLOCK_SIZE; ++i) { 376 | output[i] = input[i]; 377 | } 378 | } 379 | 380 | 381 | 382 | /*****************************************************************************/ 383 | /* Public functions: */ 384 | /*****************************************************************************/ 385 | 386 | static inline int *findPaddingIndex(uint8_t *str, size_t length) { 387 | static int result[] = {-1, -1}, i, k; 388 | for (i = 0; i < length; ++i) { 389 | char c = str[length - i]; 390 | if ('\0' != c) { 391 | result[0] = i; 392 | for (k = 0; k < BLOCK_SIZE; ++k) { 393 | if (HEX[k] == c) { 394 | if (0 == k) { 395 | k = BLOCK_SIZE; 396 | } 397 | result[1] = k; 398 | return result; 399 | } 400 | } 401 | return result; 402 | } 403 | } 404 | } 405 | 406 | static inline uint8_t *getPKCS7PaddingInput(const char *in) { 407 | int inLength = (int) strlen(in);//输入的长度 408 | int remainder = inLength % BLOCK_SIZE; 409 | uint8_t *paddingInput; 410 | int group = inLength / BLOCK_SIZE; 411 | int size = BLOCK_SIZE * (group + 1); 412 | paddingInput = (uint8_t *) malloc(size + 1); 413 | 414 | int dif = size - inLength; 415 | for (int i = 0; i < size; i++) { 416 | if (i < inLength) { 417 | paddingInput[i] = in[i]; 418 | } else { 419 | if (remainder == 0) { 420 | //刚好是16倍数,就填充16个16 421 | paddingInput[i] = HEX[0]; 422 | } else { //如果不足16位 少多少位就补几个几 如:少4为就补4个4 以此类推 423 | paddingInput[i] = HEX[dif]; 424 | } 425 | } 426 | } 427 | paddingInput[size] = '\0'; 428 | return paddingInput; 429 | } 430 | 431 | static inline void removePKCS7Padding(uint8_t *out, const size_t inputLength) { 432 | int *result = findPaddingIndex(out, inputLength - 1); 433 | int offSetIndex = result[0]; 434 | int lastChar = result[1]; 435 | //检查是不是padding的字符,然后去掉 436 | const size_t noZeroIndex = inputLength - offSetIndex; 437 | if (lastChar >= 0 && offSetIndex >= 0) { 438 | int success = 1; 439 | for (int i = 0; i < lastChar; ++i) { 440 | size_t index = noZeroIndex - lastChar + i; 441 | if (!HEX[lastChar] == out[index]) { 442 | success = 0; 443 | } 444 | } 445 | if (1 == success) { 446 | out[noZeroIndex - lastChar] = '\0'; 447 | memset(out + noZeroIndex - lastChar + 1, 0, lastChar - 1); 448 | } 449 | } else { 450 | out[noZeroIndex] = '\0'; 451 | } 452 | } 453 | 454 | #if defined(ECB) && ECB 455 | 456 | 457 | static inline void AES_ECB_encrypt(const uint8_t *input, const uint8_t *key, uint8_t *output) { 458 | // Copy input to output, and work in-memory on output 459 | BlockCopy(output, input); 460 | state = (state_t *) output; 461 | 462 | if (Key != key) { 463 | Key = key; 464 | KeyExpansion(); 465 | } 466 | 467 | // The next function call encrypts the PlainText with the Key using AES algorithm. 468 | Cipher(); 469 | } 470 | 471 | static inline void AES_ECB_decrypt(const uint8_t *input, const uint8_t *key, uint8_t *output) { 472 | // Copy input to output, and work in-memory on output 473 | BlockCopy(output, input); 474 | state = (state_t *) output; 475 | 476 | if (Key != key) { 477 | Key = key; 478 | KeyExpansion(); 479 | } 480 | 481 | InvCipher(); 482 | } 483 | 484 | /** 485 | * 不定长加密,pkcs7padding,根据密钥长度自动选择128、192、256算法 486 | */ 487 | char *AES_ECB_PKCS7_Encrypt(const char *in, const uint8_t *key) { 488 | KEYLEN = strlen(key); 489 | uint8_t *paddingInput = getPKCS7PaddingInput(in); 490 | int paddingInputLengt = strlen(paddingInput); 491 | int count = paddingInputLengt / BLOCK_SIZE; 492 | //开始分段加密 493 | char *out = (char *) malloc(paddingInputLengt); 494 | for (int i = 0; i < count; ++i) { 495 | AES_ECB_encrypt(paddingInput + i * BLOCK_SIZE, key, out + i * BLOCK_SIZE); 496 | } 497 | char *base64En = b64_encode(out, paddingInputLengt); 498 | free(paddingInput); 499 | free(out); 500 | return base64En; 501 | } 502 | 503 | /** 504 | * 不定长解密,pkcs7padding,根据密钥长度自动选择128、192、256算法 505 | */ 506 | char *AES_ECB_PKCS7_Decrypt(const char *in, const uint8_t *key) { 507 | KEYLEN = strlen(key); 508 | size_t len = strlen(in); 509 | uint8_t *inputDesBase64 = b64_decode(in, len); 510 | const size_t inputLength = (len / 4) * 3; 511 | uint8_t *out = malloc(inputLength); 512 | memset(out, 0, inputLength); 513 | size_t count = inputLength / BLOCK_SIZE; 514 | if (count <= 0) { 515 | count = 1; 516 | } 517 | for (size_t i = 0; i < count; ++i) { 518 | AES_ECB_decrypt(inputDesBase64 + i * BLOCK_SIZE, key, out + i * BLOCK_SIZE); 519 | } 520 | 521 | removePKCS7Padding(out, inputLength); 522 | free(inputDesBase64); 523 | return (char *) out; 524 | } 525 | 526 | #endif // #if defined(ECB) && ECB 527 | 528 | 529 | #if defined(CBC) && CBC 530 | 531 | 532 | static void XorWithIv(uint8_t *buf) { 533 | uint8_t i; 534 | for (i = 0; i < BLOCK_SIZE; ++i) { 535 | buf[i] ^= Iv[i]; 536 | } 537 | } 538 | 539 | void AES_CBC_encrypt(uint8_t *output, uint8_t *input, uint32_t length, const uint8_t *key, const uint8_t *iv) { 540 | uintptr_t i; 541 | uint8_t remainders = length % BLOCK_SIZE; /* Remaining bytes in the last non-full block */ 542 | 543 | BlockCopy(output, input); 544 | state = (state_t *) output; 545 | 546 | // Skip the key expansion if key is passed as 0 547 | if (0 != key) { 548 | Key = key; 549 | KeyExpansion(); 550 | } 551 | 552 | if (iv != 0) { 553 | Iv = (uint8_t *) iv; 554 | } 555 | 556 | for (i = 0; i < length; i += BLOCK_SIZE) { 557 | XorWithIv(input); 558 | BlockCopy(output, input); 559 | state = (state_t *) output; 560 | Cipher(); 561 | Iv = output; 562 | input += BLOCK_SIZE; 563 | output += BLOCK_SIZE; 564 | } 565 | 566 | if (remainders) { 567 | BlockCopy(output, input); 568 | memset(output + remainders, 0, BLOCK_SIZE - remainders); /* add 0-padding */ 569 | state = (state_t *) output; 570 | Cipher(); 571 | } 572 | } 573 | 574 | void AES_CBC_decrypt(uint8_t *output, uint8_t *input, uint32_t length, const uint8_t *key, const uint8_t *iv) { 575 | uintptr_t i; 576 | uint8_t remainders = length % BLOCK_SIZE; /* Remaining bytes in the last non-full block */ 577 | 578 | BlockCopy(output, input); 579 | state = (state_t *) output; 580 | 581 | // Skip the key expansion if key is passed as 0 582 | if (0 != key) { 583 | Key = key; 584 | KeyExpansion(); 585 | } 586 | 587 | // If iv is passed as 0, we continue to encrypt without re-setting the Iv 588 | if (iv != 0) { 589 | Iv = (uint8_t *) iv; 590 | } 591 | 592 | for (i = 0; i < length; i += BLOCK_SIZE) { 593 | BlockCopy(output, input); 594 | state = (state_t *) output; 595 | InvCipher(); 596 | XorWithIv(output); 597 | Iv = input; 598 | input += BLOCK_SIZE; 599 | output += BLOCK_SIZE; 600 | } 601 | 602 | if (remainders) { 603 | BlockCopy(output, input); 604 | memset(output + remainders, 0, BLOCK_SIZE - remainders); /* add 0-padding */ 605 | state = (state_t *) output; 606 | InvCipher(); 607 | } 608 | } 609 | 610 | /** 611 | * 不定长加密,pkcs7padding,根据密钥长度自动选择128、192、256算法 612 | */ 613 | char *AES_CBC_PKCS7_Encrypt(const char *in, const uint8_t *key, const uint8_t *iv) { 614 | KEYLEN = strlen(key); 615 | uint8_t *paddingInput = getPKCS7PaddingInput(in); 616 | int paddingInputLengt = strlen(paddingInput); 617 | char *out = (char *) malloc(paddingInputLengt); 618 | AES_CBC_encrypt(out, paddingInput, paddingInputLengt, key, iv); 619 | char *base64En = b64_encode(out, paddingInputLengt); 620 | free(paddingInput); 621 | free(out); 622 | return base64En; 623 | } 624 | 625 | /** 626 | * 不定长解密,pkcs7padding,根据密钥长度自动选择128、192、256算法 627 | */ 628 | char *AES_CBC_PKCS7_Decrypt(const char *in, const uint8_t *key, const uint8_t *iv) { 629 | KEYLEN = strlen(key); 630 | size_t len = strlen(in); 631 | uint8_t *inputDesBase64 = b64_decode(in, len); 632 | const size_t inputLength = (len / 4) * 3 / BLOCK_SIZE * BLOCK_SIZE; 633 | uint8_t *out = malloc(inputLength); 634 | memset(out, 0, inputLength); 635 | AES_CBC_decrypt(out, inputDesBase64, inputLength, key, iv); 636 | 637 | removePKCS7Padding(out, inputLength); 638 | free(inputDesBase64); 639 | return (char *) out; 640 | } 641 | 642 | #endif // #if defined(CBC) && CBC -------------------------------------------------------------------------------- /library/src/main/cpp/aes.h: -------------------------------------------------------------------------------- 1 | #ifndef _AES_H_ 2 | #define _AES_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "base64.h" 8 | 9 | 10 | // #define the macros below to 1/0 to enable/disable the mode of operation. 11 | // 12 | // CBC enables AES128 encryption in CBC-mode of operation and handles 0-padding. 13 | // ECB enables the basic ECB 16-byte block algorithm. Both can be enabled simultaneously. 14 | 15 | // The #ifndef-guard allows it to be configured before #include'ing or at compile time. 16 | #ifndef CBC 17 | #define CBC 1 18 | #endif 19 | 20 | #ifndef ECB 21 | #define ECB 1 22 | #endif 23 | 24 | 25 | static const unsigned char HEX[16]={0x10,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #if defined(ECB) && ECB 32 | 33 | char* AES_ECB_PKCS7_Encrypt(const char *in, const uint8_t *key); 34 | char* AES_ECB_PKCS7_Decrypt(const char *in, const uint8_t *key); 35 | 36 | #endif // #if defined(ECB) && ECB 37 | 38 | 39 | #if defined(CBC) && CBC 40 | 41 | char *AES_CBC_PKCS7_Encrypt(const char *in, const uint8_t *key, const uint8_t *iv); 42 | char *AES_CBC_PKCS7_Decrypt(const char *in, const uint8_t *key, const uint8_t *iv); 43 | 44 | #endif // #if defined(CBC) && CBC 45 | 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif //_AES_H_ 52 | -------------------------------------------------------------------------------- /library/src/main/cpp/base64.c: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * `encode.c' - b64 4 | * 5 | * copyright (c) 2014 joseph werle 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "base64.h" 12 | 13 | 14 | 15 | char * 16 | b64_encode (const unsigned char *src, size_t len) { 17 | int i = 0; 18 | int j = 0; 19 | char *enc = NULL; 20 | size_t size = 0; 21 | unsigned char buf[4]; 22 | unsigned char tmp[3]; 23 | 24 | // alloc 25 | enc = (char *) malloc(0); 26 | if (NULL == enc) { return NULL; } 27 | 28 | // parse until end of source 29 | while (len--) { 30 | // read up to 3 bytes at a time into `tmp' 31 | tmp[i++] = *(src++); 32 | 33 | // if 3 bytes read then encode into `buf' 34 | if (3 == i) { 35 | buf[0] = (tmp[0] & 0xfc) >> 2; 36 | buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4); 37 | buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6); 38 | buf[3] = tmp[2] & 0x3f; 39 | 40 | // allocate 4 new byts for `enc` and 41 | // then translate each encoded buffer 42 | // part by index from the base 64 index table 43 | // into `enc' unsigned char array 44 | enc = (char *) realloc(enc, size + 4); 45 | for (i = 0; i < 4; ++i) { 46 | enc[size++] = b64_table[buf[i]]; 47 | } 48 | 49 | // reset index 50 | i = 0; 51 | } 52 | } 53 | 54 | // remainder 55 | if (i > 0) { 56 | // fill `tmp' with `\0' at most 3 times 57 | for (j = i; j < 3; ++j) { 58 | tmp[j] = '\0'; 59 | } 60 | 61 | // perform same codec as above 62 | buf[0] = (tmp[0] & 0xfc) >> 2; 63 | buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4); 64 | buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6); 65 | buf[3] = tmp[2] & 0x3f; 66 | 67 | // perform same write to `enc` with new allocation 68 | for (j = 0; (j < i + 1); ++j) { 69 | enc = (char *) realloc(enc, size + 1); 70 | enc[size++] = b64_table[buf[j]]; 71 | } 72 | 73 | // while there is still a remainder 74 | // append `=' to `enc' 75 | while ((i++ < 3)) { 76 | enc = (char *) realloc(enc, size + 1); 77 | enc[size++] = '='; 78 | } 79 | } 80 | 81 | // Make sure we have enough space to add '\0' character at end. 82 | enc = (char *) realloc(enc, size + 1); 83 | enc[size] = '\0'; 84 | 85 | return enc; 86 | } 87 | 88 | 89 | unsigned char * 90 | b64_decode(const char *src, size_t len) { 91 | return b64_decode_ex(src, len, NULL); 92 | } 93 | 94 | unsigned char * 95 | b64_decode_ex(const char *src, size_t len, size_t *decsize) { 96 | int i = 0; 97 | int j = 0; 98 | int l = 0; 99 | size_t size = 0; 100 | unsigned char *dec = NULL; 101 | unsigned char buf[3]; 102 | unsigned char tmp[4]; 103 | 104 | // alloc 105 | dec = (unsigned char *) malloc(0); 106 | if (NULL == dec) { return NULL; } 107 | 108 | // parse until end of source 109 | while (len--) { 110 | // break if char is `=' or not base64 char 111 | if ('=' == src[j]) { break; } 112 | if (!(isalnum(src[j]) || '+' == src[j] || '/' == src[j])) { break; } 113 | 114 | // read up to 4 bytes at a time into `tmp' 115 | tmp[i++] = src[j++]; 116 | 117 | // if 4 bytes read then decode into `buf' 118 | if (4 == i) { 119 | // translate values in `tmp' from table 120 | for (i = 0; i < 4; ++i) { 121 | // find translation char in `b64_table' 122 | for (l = 0; l < 64; ++l) { 123 | if (tmp[i] == b64_table[l]) { 124 | tmp[i] = l; 125 | break; 126 | } 127 | } 128 | } 129 | 130 | // decode 131 | buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4); 132 | buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2); 133 | buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3]; 134 | 135 | // write decoded buffer to `dec' 136 | dec = (unsigned char *) realloc(dec, size + 3); 137 | for (i = 0; i < 3; ++i) { 138 | dec[size++] = buf[i]; 139 | } 140 | 141 | // reset 142 | i = 0; 143 | } 144 | } 145 | 146 | // remainder 147 | if (i > 0) { 148 | // fill `tmp' with `\0' at most 4 times 149 | for (j = i; j < 4; ++j) { 150 | tmp[j] = '\0'; 151 | } 152 | 153 | // translate remainder 154 | for (j = 0; j < 4; ++j) { 155 | // find translation char in `b64_table' 156 | for (l = 0; l < 64; ++l) { 157 | if (tmp[j] == b64_table[l]) { 158 | tmp[j] = l; 159 | break; 160 | } 161 | } 162 | } 163 | 164 | // decode remainder 165 | buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4); 166 | buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2); 167 | buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3]; 168 | 169 | // write remainer decoded buffer to `dec' 170 | dec = (unsigned char *) realloc(dec, size + (i - 1)); 171 | for (j = 0; (j < i - 1); ++j) { 172 | dec[size++] = buf[j]; 173 | } 174 | } 175 | 176 | // Make sure we have enough space to add '\0' character at end. 177 | dec = (unsigned char *) realloc(dec, size + 1); 178 | dec[size] = '\0'; 179 | 180 | // Return back the size of decoded string if demanded. 181 | if (decsize != NULL) *decsize = size; 182 | 183 | return dec; 184 | } 185 | -------------------------------------------------------------------------------- /library/src/main/cpp/base64.h: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * `b64.h' - b64 4 | * 5 | * copyright (c) 2014 joseph werle 6 | */ 7 | 8 | #ifndef B64_H 9 | #define B64_H 1 10 | 11 | /** 12 | * Base64 index table. 13 | */ 14 | 15 | static const char b64_table[] = { 16 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 17 | 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 18 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 19 | 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 20 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 21 | 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 22 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', 23 | '4', '5', '6', '7', '8', '9', '+', '/' 24 | }; 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | /** 31 | * Encode `unsigned char *' source with `size_t' size. 32 | * Returns a `char *' base64 encoded string. 33 | */ 34 | 35 | char * 36 | b64_encode (const unsigned char *, size_t); 37 | 38 | /** 39 | * Dencode `char *' source with `size_t' size. 40 | * Returns a `unsigned char *' base64 decoded string. 41 | */ 42 | unsigned char * 43 | b64_decode (const char *, size_t); 44 | 45 | /** 46 | * Dencode `char *' source with `size_t' size. 47 | * Returns a `unsigned char *' base64 decoded string + size of decoded string. 48 | */ 49 | unsigned char * 50 | b64_decode_ex (const char *, size_t, size_t *); 51 | 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /library/src/main/cpp/jni_tool.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "aes.h" 4 | #include "md5.h" 5 | //#include 6 | 7 | static const char *app_packageName = "com.wtuadn.demo"; 8 | static const int app_signature_hash_code = 1967296062; 9 | static const uint8_t AES_KEY[] = "xS544RXNm0P4JVLHIEsTqJNzDbZhiLjr"; 10 | static const uint8_t AES_IV[] = "KXTUDEdBs9zGlvy7"; 11 | static const string PWD_MD5_KEY = "4J9lKuR2c8OuDPBAniEy5USFQdSM0An4"; 12 | 13 | static jobject getApplication(JNIEnv *env) { 14 | jobject application = NULL; 15 | jclass activity_thread_clz = env->FindClass("android/app/ActivityThread"); 16 | if (activity_thread_clz != NULL) { 17 | jmethodID currentApplication = env->GetStaticMethodID( 18 | activity_thread_clz, "currentApplication", "()Landroid/app/Application;"); 19 | if (currentApplication != NULL) { 20 | application = env->CallStaticObjectMethod(activity_thread_clz, currentApplication); 21 | } 22 | } 23 | return application; 24 | } 25 | 26 | static bool checkSignature(JNIEnv *env) { 27 | jobject context = getApplication(env); 28 | //Context的类 29 | jclass context_clazz = env->GetObjectClass(context); 30 | // 得到 getPackageManager 方法的 ID 31 | jmethodID methodID_getPackageManager = env->GetMethodID(context_clazz, "getPackageManager", 32 | "()Landroid/content/pm/PackageManager;"); 33 | // 获得PackageManager对象 34 | jobject packageManager = env->CallObjectMethod(context, methodID_getPackageManager); 35 | // 获得 PackageManager 类 36 | jclass pm_clazz = env->GetObjectClass(packageManager); 37 | // 得到 getPackageInfo 方法的 ID 38 | jmethodID methodID_pm = env->GetMethodID(pm_clazz, "getPackageInfo", 39 | "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;"); 40 | // 得到 getPackageName 方法的 ID 41 | jmethodID methodID_pack = env->GetMethodID(context_clazz, 42 | "getPackageName", "()Ljava/lang/String;"); 43 | // 获得当前应用的包名 44 | jstring application_package = (jstring) env->CallObjectMethod(context, methodID_pack); 45 | const char *package_name = env->GetStringUTFChars(application_package, 0); 46 | // 获得PackageInfo 47 | jobject packageInfo = env->CallObjectMethod(packageManager, methodID_pm, application_package, 64); 48 | jclass packageinfo_clazz = env->GetObjectClass(packageInfo); 49 | jfieldID fieldID_signatures = env->GetFieldID(packageinfo_clazz, 50 | "signatures", "[Landroid/content/pm/Signature;"); 51 | jobjectArray signature_arr = (jobjectArray) env->GetObjectField(packageInfo, fieldID_signatures); 52 | //Signature数组中取出第一个元素 53 | jobject signature = env->GetObjectArrayElement(signature_arr, 0); 54 | //读signature的hashcode 55 | jclass signature_clazz = env->GetObjectClass(signature); 56 | jmethodID methodID_hashcode = env->GetMethodID(signature_clazz, "hashCode", "()I"); 57 | jint hashCode = env->CallIntMethod(signature, methodID_hashcode); 58 | 59 | if (strcmp(package_name, app_packageName) != 0) { 60 | exit(-1); 61 | } 62 | if (hashCode != app_signature_hash_code) { 63 | exit(-2); 64 | } 65 | return true; 66 | } 67 | 68 | jint JNI_OnLoad(JavaVM *vm, void *reserved) { 69 | JNIEnv *env = NULL; 70 | if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { 71 | return JNI_ERR; 72 | } 73 | if (checkSignature(env)) { 74 | return JNI_VERSION_1_6; 75 | } 76 | return JNI_ERR; 77 | } 78 | 79 | extern "C" 80 | JNIEXPORT jstring JNICALL 81 | Java_com_wtuadn_jnitool_JNITool_jniencrypt(JNIEnv *env, jclass type, jbyteArray jbArr) { 82 | 83 | char *str = NULL; 84 | jsize alen = env->GetArrayLength(jbArr); 85 | jbyte *ba = env->GetByteArrayElements(jbArr, JNI_FALSE); 86 | str = (char *) malloc(alen + 1); 87 | memcpy(str, ba, alen); 88 | str[alen] = '\0'; 89 | env->ReleaseByteArrayElements(jbArr, ba, 0); 90 | 91 | char *result = AES_ECB_PKCS7_Encrypt(str, AES_KEY);//AES ECB PKCS7Padding加密 92 | // char *result = AES_CBC_PKCS7_Encrypt(str, AES_KEY, AES_IV);//AES CBC PKCS7Padding加密 93 | return env->NewStringUTF(result); 94 | } 95 | 96 | extern "C" 97 | JNIEXPORT jbyteArray JNICALL 98 | Java_com_wtuadn_jnitool_JNITool_jnidecrypt(JNIEnv *env, jclass type, jstring out_str) { 99 | 100 | const char *str = env->GetStringUTFChars(out_str, 0); 101 | char *result = AES_ECB_PKCS7_Decrypt(str, AES_KEY);//AES ECB PKCS7Padding解密 102 | // char *result = AES_CBC_PKCS7_Decrypt(str, AES_KEY, AES_IV);//AES CBC PKCS7Padding解密 103 | env->ReleaseStringUTFChars(out_str, str); 104 | 105 | jsize len = (jsize) strlen(result); 106 | jbyteArray jbArr = env->NewByteArray(len); 107 | env->SetByteArrayRegion(jbArr, 0, len, (jbyte *) result); 108 | return jbArr; 109 | } 110 | 111 | extern "C" 112 | JNIEXPORT jstring JNICALL 113 | Java_com_wtuadn_jnitool_JNITool_pwdMD5(JNIEnv *env, jclass type, jstring out_str) { 114 | 115 | const char *str = env->GetStringUTFChars(out_str, 0); 116 | string result = MD5(MD5(PWD_MD5_KEY + string(str)).toStr()).toStr();//加盐后进行两次md5 117 | env->ReleaseStringUTFChars(out_str, str); 118 | return env->NewStringUTF(("###" + result).data());//最后再加三个# 119 | } 120 | 121 | 122 | -------------------------------------------------------------------------------- /library/src/main/cpp/md5.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file md5.cpp 3 | * @The implement of md5. 4 | * @author Jiewei Wei 5 | * @mail weijieweijerry@163.com 6 | * @github https://github.com/JieweiWei 7 | * @data Oct 19 2014 8 | * 9 | */ 10 | 11 | #include "md5.h" 12 | 13 | /* Define the static member of MD5. */ 14 | const byte MD5::PADDING[64] = { 0x80 }; 15 | const char MD5::HEX_NUMBERS[16] = { 16 | '0', '1', '2', '3', 17 | '4', '5', '6', '7', 18 | '8', '9', 'a', 'b', 19 | 'c', 'd', 'e', 'f' 20 | }; 21 | 22 | /** 23 | * @Construct a MD5 object with a string. 24 | * 25 | * @param {message} the message will be transformed. 26 | * 27 | */ 28 | MD5::MD5(const string& message) { 29 | finished = false; 30 | /* Reset number of bits. */ 31 | count[0] = count[1] = 0; 32 | /* Initialization constants. */ 33 | state[0] = 0x67452301; 34 | state[1] = 0xefcdab89; 35 | state[2] = 0x98badcfe; 36 | state[3] = 0x10325476; 37 | 38 | /* Initialization the object according to message. */ 39 | init((const byte*)message.c_str(), message.length()); 40 | } 41 | 42 | /** 43 | * @Generate md5 digest. 44 | * 45 | * @return the message-digest. 46 | * 47 | */ 48 | const byte* MD5::getDigest() { 49 | if (!finished) { 50 | finished = true; 51 | 52 | byte bits[8]; 53 | bit32 oldState[4]; 54 | bit32 oldCount[2]; 55 | bit32 index, padLen; 56 | 57 | /* Save current state and count. */ 58 | memcpy(oldState, state, 16); 59 | memcpy(oldCount, count, 8); 60 | 61 | /* Save number of bits */ 62 | encode(count, bits, 8); 63 | 64 | /* Pad out to 56 mod 64. */ 65 | index = (bit32)((count[0] >> 3) & 0x3f); 66 | padLen = (index < 56) ? (56 - index) : (120 - index); 67 | init(PADDING, padLen); 68 | 69 | /* Append length (before padding) */ 70 | init(bits, 8); 71 | 72 | /* Store state in digest */ 73 | encode(state, digest, 16); 74 | 75 | /* Restore current state and count. */ 76 | memcpy(state, oldState, 16); 77 | memcpy(count, oldCount, 8); 78 | } 79 | return digest; 80 | } 81 | 82 | /** 83 | * @Initialization the md5 object, processing another message block, 84 | * and updating the context. 85 | * 86 | * @param {input} the input message. 87 | * 88 | * @param {len} the number btye of message. 89 | * 90 | */ 91 | void MD5::init(const byte* input, size_t len) { 92 | 93 | bit32 i, index, partLen; 94 | 95 | finished = false; 96 | 97 | /* Compute number of bytes mod 64 */ 98 | index = (bit32)((count[0] >> 3) & 0x3f); 99 | 100 | /* update number of bits */ 101 | if ((count[0] += ((bit32)len << 3)) < ((bit32)len << 3)) { 102 | ++count[1]; 103 | } 104 | count[1] += ((bit32)len >> 29); 105 | 106 | partLen = 64 - index; 107 | 108 | /* transform as many times as possible. */ 109 | if (len >= partLen) { 110 | 111 | memcpy(&buffer[index], input, partLen); 112 | transform(buffer); 113 | 114 | for (i = partLen; i + 63 < len; i += 64) { 115 | transform(&input[i]); 116 | } 117 | index = 0; 118 | 119 | } else { 120 | i = 0; 121 | } 122 | 123 | /* Buffer remaining input */ 124 | memcpy(&buffer[index], &input[i], len - i); 125 | } 126 | 127 | /** 128 | * @MD5 basic transformation. Transforms state based on block. 129 | * 130 | * @param {block} the message block. 131 | */ 132 | void MD5::transform(const byte block[64]) { 133 | 134 | bit32 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; 135 | 136 | decode(block, x, 64); 137 | 138 | /* Round 1 */ 139 | FF (a, b, c, d, x[ 0], s11, 0xd76aa478); 140 | FF (d, a, b, c, x[ 1], s12, 0xe8c7b756); 141 | FF (c, d, a, b, x[ 2], s13, 0x242070db); 142 | FF (b, c, d, a, x[ 3], s14, 0xc1bdceee); 143 | FF (a, b, c, d, x[ 4], s11, 0xf57c0faf); 144 | FF (d, a, b, c, x[ 5], s12, 0x4787c62a); 145 | FF (c, d, a, b, x[ 6], s13, 0xa8304613); 146 | FF (b, c, d, a, x[ 7], s14, 0xfd469501); 147 | FF (a, b, c, d, x[ 8], s11, 0x698098d8); 148 | FF (d, a, b, c, x[ 9], s12, 0x8b44f7af); 149 | FF (c, d, a, b, x[10], s13, 0xffff5bb1); 150 | FF (b, c, d, a, x[11], s14, 0x895cd7be); 151 | FF (a, b, c, d, x[12], s11, 0x6b901122); 152 | FF (d, a, b, c, x[13], s12, 0xfd987193); 153 | FF (c, d, a, b, x[14], s13, 0xa679438e); 154 | FF (b, c, d, a, x[15], s14, 0x49b40821); 155 | 156 | /* Round 2 */ 157 | GG (a, b, c, d, x[ 1], s21, 0xf61e2562); 158 | GG (d, a, b, c, x[ 6], s22, 0xc040b340); 159 | GG (c, d, a, b, x[11], s23, 0x265e5a51); 160 | GG (b, c, d, a, x[ 0], s24, 0xe9b6c7aa); 161 | GG (a, b, c, d, x[ 5], s21, 0xd62f105d); 162 | GG (d, a, b, c, x[10], s22, 0x2441453); 163 | GG (c, d, a, b, x[15], s23, 0xd8a1e681); 164 | GG (b, c, d, a, x[ 4], s24, 0xe7d3fbc8); 165 | GG (a, b, c, d, x[ 9], s21, 0x21e1cde6); 166 | GG (d, a, b, c, x[14], s22, 0xc33707d6); 167 | GG (c, d, a, b, x[ 3], s23, 0xf4d50d87); 168 | GG (b, c, d, a, x[ 8], s24, 0x455a14ed); 169 | GG (a, b, c, d, x[13], s21, 0xa9e3e905); 170 | GG (d, a, b, c, x[ 2], s22, 0xfcefa3f8); 171 | GG (c, d, a, b, x[ 7], s23, 0x676f02d9); 172 | GG (b, c, d, a, x[12], s24, 0x8d2a4c8a); 173 | 174 | /* Round 3 */ 175 | HH (a, b, c, d, x[ 5], s31, 0xfffa3942); 176 | HH (d, a, b, c, x[ 8], s32, 0x8771f681); 177 | HH (c, d, a, b, x[11], s33, 0x6d9d6122); 178 | HH (b, c, d, a, x[14], s34, 0xfde5380c); 179 | HH (a, b, c, d, x[ 1], s31, 0xa4beea44); 180 | HH (d, a, b, c, x[ 4], s32, 0x4bdecfa9); 181 | HH (c, d, a, b, x[ 7], s33, 0xf6bb4b60); 182 | HH (b, c, d, a, x[10], s34, 0xbebfbc70); 183 | HH (a, b, c, d, x[13], s31, 0x289b7ec6); 184 | HH (d, a, b, c, x[ 0], s32, 0xeaa127fa); 185 | HH (c, d, a, b, x[ 3], s33, 0xd4ef3085); 186 | HH (b, c, d, a, x[ 6], s34, 0x4881d05); 187 | HH (a, b, c, d, x[ 9], s31, 0xd9d4d039); 188 | HH (d, a, b, c, x[12], s32, 0xe6db99e5); 189 | HH (c, d, a, b, x[15], s33, 0x1fa27cf8); 190 | HH (b, c, d, a, x[ 2], s34, 0xc4ac5665); 191 | 192 | /* Round 4 */ 193 | II (a, b, c, d, x[ 0], s41, 0xf4292244); 194 | II (d, a, b, c, x[ 7], s42, 0x432aff97); 195 | II (c, d, a, b, x[14], s43, 0xab9423a7); 196 | II (b, c, d, a, x[ 5], s44, 0xfc93a039); 197 | II (a, b, c, d, x[12], s41, 0x655b59c3); 198 | II (d, a, b, c, x[ 3], s42, 0x8f0ccc92); 199 | II (c, d, a, b, x[10], s43, 0xffeff47d); 200 | II (b, c, d, a, x[ 1], s44, 0x85845dd1); 201 | II (a, b, c, d, x[ 8], s41, 0x6fa87e4f); 202 | II (d, a, b, c, x[15], s42, 0xfe2ce6e0); 203 | II (c, d, a, b, x[ 6], s43, 0xa3014314); 204 | II (b, c, d, a, x[13], s44, 0x4e0811a1); 205 | II (a, b, c, d, x[ 4], s41, 0xf7537e82); 206 | II (d, a, b, c, x[11], s42, 0xbd3af235); 207 | II (c, d, a, b, x[ 2], s43, 0x2ad7d2bb); 208 | II (b, c, d, a, x[ 9], s44, 0xeb86d391); 209 | 210 | state[0] += a; 211 | state[1] += b; 212 | state[2] += c; 213 | state[3] += d; 214 | } 215 | 216 | /** 217 | * @Encodes input (unsigned long) into output (byte). 218 | * 219 | * @param {input} usigned long. 220 | * 221 | * @param {output} byte. 222 | * 223 | * @param {length} the length of input. 224 | * 225 | */ 226 | void MD5::encode(const bit32* input, byte* output, size_t length) { 227 | 228 | for (size_t i = 0, j = 0; j < length; ++i, j += 4) { 229 | output[j]= (byte)(input[i] & 0xff); 230 | output[j + 1] = (byte)((input[i] >> 8) & 0xff); 231 | output[j + 2] = (byte)((input[i] >> 16) & 0xff); 232 | output[j + 3] = (byte)((input[i] >> 24) & 0xff); 233 | } 234 | } 235 | 236 | /** 237 | * @Decodes input (byte) into output (usigned long). 238 | * 239 | * @param {input} bytes. 240 | * 241 | * @param {output} unsigned long. 242 | * 243 | * @param {length} the length of input. 244 | * 245 | */ 246 | void MD5::decode(const byte* input, bit32* output, size_t length) { 247 | for (size_t i = 0, j = 0; j < length; ++i, j += 4) { 248 | output[i] = ((bit32)input[j]) | (((bit32)input[j + 1]) << 8) | 249 | (((bit32)input[j + 2]) << 16) | (((bit32)input[j + 3]) << 24); 250 | } 251 | } 252 | 253 | 254 | /** 255 | * @Convert digest to string value. 256 | * 257 | * @return the hex string of digest. 258 | * 259 | */ 260 | string MD5::toStr() { 261 | const byte* digest_ = getDigest(); 262 | string str; 263 | str.reserve(16 << 1); 264 | for (size_t i = 0; i < 16; ++i) { 265 | int t = digest_[i]; 266 | int a = t / 16; 267 | int b = t % 16; 268 | str.append(1, HEX_NUMBERS[a]); 269 | str.append(1, HEX_NUMBERS[b]); 270 | } 271 | return str; 272 | } 273 | -------------------------------------------------------------------------------- /library/src/main/cpp/md5.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file md5.h 3 | * @The header file of md5. 4 | * @author Jiewei Wei 5 | * @mail weijieweijerry@163.com 6 | * @github https://github.com/JieweiWei 7 | * @data Oct 19 2014 8 | * 9 | */ 10 | 11 | #ifndef MD5_H 12 | #define MD5_H 13 | 14 | /* Parameters of MD5. */ 15 | #define s11 7 16 | #define s12 12 17 | #define s13 17 18 | #define s14 22 19 | #define s21 5 20 | #define s22 9 21 | #define s23 14 22 | #define s24 20 23 | #define s31 4 24 | #define s32 11 25 | #define s33 16 26 | #define s34 23 27 | #define s41 6 28 | #define s42 10 29 | #define s43 15 30 | #define s44 21 31 | 32 | /** 33 | * @Basic MD5 functions. 34 | * 35 | * @param there bit32. 36 | * 37 | * @return one bit32. 38 | */ 39 | #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) 40 | #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) 41 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 42 | #define I(x, y, z) ((y) ^ ((x) | (~z))) 43 | 44 | /** 45 | * @Rotate Left. 46 | * 47 | * @param {num} the raw number. 48 | * 49 | * @param {n} rotate left n. 50 | * 51 | * @return the number after rotated left. 52 | */ 53 | #define ROTATELEFT(num, n) (((num) << (n)) | ((num) >> (32-(n)))) 54 | 55 | /** 56 | * @Transformations for rounds 1, 2, 3, and 4. 57 | */ 58 | #define FF(a, b, c, d, x, s, ac) { \ 59 | (a) += F ((b), (c), (d)) + (x) + ac; \ 60 | (a) = ROTATELEFT ((a), (s)); \ 61 | (a) += (b); \ 62 | } 63 | #define GG(a, b, c, d, x, s, ac) { \ 64 | (a) += G ((b), (c), (d)) + (x) + ac; \ 65 | (a) = ROTATELEFT ((a), (s)); \ 66 | (a) += (b); \ 67 | } 68 | #define HH(a, b, c, d, x, s, ac) { \ 69 | (a) += H ((b), (c), (d)) + (x) + ac; \ 70 | (a) = ROTATELEFT ((a), (s)); \ 71 | (a) += (b); \ 72 | } 73 | #define II(a, b, c, d, x, s, ac) { \ 74 | (a) += I ((b), (c), (d)) + (x) + ac; \ 75 | (a) = ROTATELEFT ((a), (s)); \ 76 | (a) += (b); \ 77 | } 78 | 79 | #include 80 | #include 81 | 82 | using std::string; 83 | 84 | /* Define of btye.*/ 85 | typedef unsigned char byte; 86 | /* Define of byte. */ 87 | typedef unsigned int bit32; 88 | 89 | class MD5 { 90 | public: 91 | /* Construct a MD5 object with a string. */ 92 | MD5(const string& message); 93 | 94 | /* Generate md5 digest. */ 95 | const byte* getDigest(); 96 | 97 | /* Convert digest to string value */ 98 | string toStr(); 99 | 100 | private: 101 | /* Initialization the md5 object, processing another message block, 102 | * and updating the context.*/ 103 | void init(const byte* input, size_t len); 104 | 105 | /* MD5 basic transformation. Transforms state based on block. */ 106 | void transform(const byte block[64]); 107 | 108 | /* Encodes input (usigned long) into output (byte). */ 109 | void encode(const bit32* input, byte* output, size_t length); 110 | 111 | /* Decodes input (byte) into output (usigned long). */ 112 | void decode(const byte* input, bit32* output, size_t length); 113 | 114 | private: 115 | /* Flag for mark whether calculate finished. */ 116 | bool finished; 117 | 118 | /* state (ABCD). */ 119 | bit32 state[4]; 120 | 121 | /* number of bits, low-order word first. */ 122 | bit32 count[2]; 123 | 124 | /* input buffer. */ 125 | byte buffer[64]; 126 | 127 | /* message digest. */ 128 | byte digest[16]; 129 | 130 | /* padding for calculate. */ 131 | static const byte PADDING[64]; 132 | 133 | /* Hex numbers. */ 134 | static const char HEX_NUMBERS[16]; 135 | }; 136 | 137 | #endif // MD5_H 138 | -------------------------------------------------------------------------------- /library/src/main/java/com/wtuadn/jnitool/JNITool.java: -------------------------------------------------------------------------------- 1 | package com.wtuadn.jnitool; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | import android.content.pm.Signature; 7 | 8 | /** 9 | * Created by wtuadn on 2017/3/9. 10 | */ 11 | 12 | public class JNITool { 13 | static { 14 | System.loadLibrary("jni_tool"); 15 | } 16 | 17 | private static native String jniencrypt(byte[] bytes); 18 | 19 | private static native byte[] jnidecrypt(String str); 20 | 21 | public static native String pwdMD5(String str); 22 | 23 | public static String encrypt(String str) { 24 | return jniencrypt(str.getBytes()); 25 | } 26 | 27 | public static String decrypt(String str) { 28 | return new String(jnidecrypt(str)); 29 | } 30 | 31 | //获取签名 32 | public static int getSignature(Context context) { 33 | try { 34 | PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); 35 | 36 | Signature sign = packageInfo.signatures[0]; 37 | return sign.hashCode(); 38 | } 39 | catch (Exception e) { 40 | e.printStackTrace(); 41 | } 42 | return -1; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':library' 2 | --------------------------------------------------------------------------------