├── .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 |
--------------------------------------------------------------------------------