├── README.md
├── RxAppEncryptionProtocol.iml
├── Rx_AES加密日志.png
├── Rx_RSA加密日志.png
├── frida_反特征检测.js
├── hook_art.js
├── hook_registerNative.js
├── js_hook.js
└── src
└── com
└── lang
└── script
├── AES.java
├── AESUtils.java
├── HMACSHA256Util.java
├── HttpURLConnectionExample.java
├── MD5Utils.java
├── RASUtils.java
├── RASUtilsNew.java
└── RSA.java
/README.md:
--------------------------------------------------------------------------------
1 | # app协议逆向破解
2 | ```
3 | 思路:这种app逆向方式比较通用,能够解决大部分app协议加密破解。主要思路是利用frida hook java jdk 中的加密
4 | 函数与方法,打印响应参数分析
5 | ```
6 | ### 逆向步骤
7 | 1. 启动脚步js_hook.js (frida -U -l js_hook.js -f com.lang.testso --no-pause)
8 | * 脚步中包含了hook MD5 AES DES RSA 等一些列加密算法;以及解决app 无法抓包的ssl ping脚步
9 | 2. 启动app点击发送请求,查看响应日志
10 | * AES
11 | 
12 | * RSA
13 | 
14 |
15 | 3. 还原算法,测试代码在com.lang.script下,将打印的16进制转换为byte字节数组,还原加密现场
16 | 4. frida工作中使用总结 https://langgithub.github.io/2019/08/01/frida%E4%BD%BF%E7%94%A8%E6%80%BB%E7%BB%93/
--------------------------------------------------------------------------------
/RxAppEncryptionProtocol.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Rx_AES加密日志.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langgithub/RxAppEncryptionProtocol/d1318490e46c6d067e669e9911467464a1587b66/Rx_AES加密日志.png
--------------------------------------------------------------------------------
/Rx_RSA加密日志.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langgithub/RxAppEncryptionProtocol/d1318490e46c6d067e669e9911467464a1587b66/Rx_RSA加密日志.png
--------------------------------------------------------------------------------
/frida_反特征检测.js:
--------------------------------------------------------------------------------
1 | // js hook jingdong v9.3.0
2 | // frida -U -l jingdong.js -f com.jingdong.app.mall --no-pause
3 |
4 | // frida 反检测 资料: https://bbs.pediy.com/thread-217482.htm
5 | // 1. 改文件名称
6 | // 2. 改端口
7 | // 3. hook系统函数
8 |
9 | // 改端口调用方式
10 | // ./flang -l 0.0.0.0:12345adb
11 | // adb forward tcp:12345 tcp:12345
12 | // frida -H 127.0.0.1:12345 -l jingdong.js -f com.jingdong.app.mall
13 | // %resume 启动
14 |
15 | Interceptor.attach(Module.findExportByName(null, "fopen"), {
16 | onEnter: function(args) {
17 | console.log("fopen Interceptor attached onEnter...");
18 | console.log("fopen param0>>>>>>>" + args[0].readCString());
19 | },
20 | onLeave: function(args) {
21 | console.log("fopen Interceptor attached onLeave...");
22 | }
23 | })
24 |
25 | var is_find_frida = false
26 | Interceptor.attach(Module.findExportByName(null, "strstr"), {
27 | onEnter: function(args) {
28 | // console.log("strstr Interceptor attached onEnter...");
29 | console.log("strstr param0>>>>>>>" + args[0].readCString());
30 | console.log("strstr param1>>>>>>>" + args[1].readCString());
31 | if (args[1].readCString().indexOf("frida")){
32 | is_find_frida = true
33 | }else{
34 | is_find_frida = false
35 | }
36 | },
37 | onLeave: function(retval) {
38 | console.log("strstr Interceptor attached onLeave..." + retval);
39 | if (is_find_frida){
40 | retval.replace(ptr("0x0"))
41 | }
42 | }
43 | })
44 |
--------------------------------------------------------------------------------
/hook_art.js:
--------------------------------------------------------------------------------
1 | var ishook_libart = false;
2 |
3 | function hook_libart() {
4 | if (ishook_libart === true) {
5 | return;
6 | }
7 | var symbols = Module.enumerateSymbolsSync("libart.so");
8 | var addrGetStringUTFChars = null;
9 | var addrNewStringUTF = null;
10 | var addrFindClass = null;
11 | var addrGetMethodID = null;
12 | var addrGetStaticMethodID = null;
13 | var addrGetFieldID = null;
14 | var addrGetStaticFieldID = null;
15 | var addrRegisterNatives = null;
16 | var addrAllocObject = null;
17 | var addrCallObjectMethod = null;
18 | var addrGetObjectClass = null;
19 | var addrReleaseStringUTFChars = null;
20 | for (var i = 0; i < symbols.length; i++) {
21 | var symbol = symbols[i];
22 | if (symbol.name == "_ZN3art3JNI17GetStringUTFCharsEP7_JNIEnvP8_jstringPh") {
23 | addrGetStringUTFChars = symbol.address;
24 | console.log("GetStringUTFChars is at ", symbol.address, symbol.name);
25 | } else if (symbol.name == "_ZN3art3JNI12NewStringUTFEP7_JNIEnvPKc") {
26 | addrNewStringUTF = symbol.address;
27 | console.log("NewStringUTF is at ", symbol.address, symbol.name);
28 | } else if (symbol.name == "_ZN3art3JNI9FindClassEP7_JNIEnvPKc") {
29 | addrFindClass = symbol.address;
30 | console.log("FindClass is at ", symbol.address, symbol.name);
31 | } else if (symbol.name == "_ZN3art3JNI11GetMethodIDEP7_JNIEnvP7_jclassPKcS6_") {
32 | addrGetMethodID = symbol.address;
33 | console.log("GetMethodID is at ", symbol.address, symbol.name);
34 | } else if (symbol.name == "_ZN3art3JNI17GetStaticMethodIDEP7_JNIEnvP7_jclassPKcS6_") {
35 | addrGetStaticMethodID = symbol.address;
36 | console.log("GetStaticMethodID is at ", symbol.address, symbol.name);
37 | } else if (symbol.name == "_ZN3art3JNI10GetFieldIDEP7_JNIEnvP7_jclassPKcS6_") {
38 | addrGetFieldID = symbol.address;
39 | console.log("GetFieldID is at ", symbol.address, symbol.name);
40 | } else if (symbol.name == "_ZN3art3JNI16GetStaticFieldIDEP7_JNIEnvP7_jclassPKcS6_") {
41 | addrGetStaticFieldID = symbol.address;
42 | console.log("GetStaticFieldID is at ", symbol.address, symbol.name);
43 | } else if (symbol.name == "_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi") {
44 | addrRegisterNatives = symbol.address;
45 | console.log("RegisterNatives is at ", symbol.address, symbol.name);
46 | } else if (symbol.name.indexOf("_ZN3art3JNI11AllocObjectEP7_JNIEnvP7_jclass") >= 0) {
47 | addrAllocObject = symbol.address;
48 | console.log("AllocObject is at ", symbol.address, symbol.name);
49 | } else if (symbol.name.indexOf("_ZN3art3JNI16CallObjectMethodEP7_JNIEnvP8_jobjectP10_jmethodIDz") >= 0) {
50 | addrCallObjectMethod = symbol.address;
51 | console.log("CallObjectMethod is at ", symbol.address, symbol.name);
52 | } else if (symbol.name.indexOf("_ZN3art3JNI14GetObjectClassEP7_JNIEnvP8_jobject") >= 0) {
53 | addrGetObjectClass = symbol.address;
54 | console.log("GetObjectClass is at ", symbol.address, symbol.name);
55 | } else if (symbol.name.indexOf("_ZN3art3JNI21ReleaseStringUTFCharsEP7_JNIEnvP8_jstringPKc") >= 0) {
56 | addrReleaseStringUTFChars = symbol.address;
57 | console.log("ReleaseStringUTFChars is at ", symbol.address, symbol.name);
58 | }
59 | }
60 |
61 | if (addrGetStringUTFChars != null) {
62 | Interceptor.attach(addrGetStringUTFChars, {
63 | onEnter: function (args) { },
64 | onLeave: function (retval) {
65 | if (retval != null) {
66 | var bytes = Memory.readCString(retval);
67 | console.log("[GetStringUTFChars] result:" + bytes);
68 | }
69 | }
70 | });
71 | }
72 | if (addrNewStringUTF != null) {
73 | Interceptor.attach(addrNewStringUTF, {
74 | onEnter: function (args) {
75 | if (args[1] != null) {
76 | var string = Memory.readCString(args[1]);
77 | console.log("[NewStringUTF] bytes:" + string);
78 | }
79 | },
80 | onLeave: function (retval) { }
81 | });
82 | }
83 | if (addrFindClass != null) {
84 | Interceptor.attach(addrFindClass, {
85 | onEnter: function (args) {
86 | if (args[1] != null) {
87 | var name = Memory.readCString(args[1]);
88 | console.log("[FindClass] name:" + name);
89 | }
90 | },
91 | onLeave: function (retval) { }
92 | });
93 | }
94 | if (addrGetMethodID != null) {
95 | Interceptor.attach(addrGetMethodID, {
96 | onEnter: function (args) {
97 | if (args[2] != null) {
98 | var name = Memory.readCString(args[2]);
99 | if (args[3] != null) {
100 | var sig = Memory.readCString(args[3]);
101 | console.log("[GetMethodID] name:" + name + ", sig:" + sig);
102 | } else {
103 | console.log("[GetMethodID] name:" + name);
104 | }
105 |
106 | }
107 | },
108 | onLeave: function (retval) { }
109 | });
110 | }
111 | if (addrGetStaticMethodID != null) {
112 | Interceptor.attach(addrGetStaticMethodID, {
113 | onEnter: function (args) {
114 | if (args[2] != null) {
115 | var name = Memory.readCString(args[2]);
116 | if (args[3] != null) {
117 | var sig = Memory.readCString(args[3]);
118 | console.log("[GetStaticMethodID] name:" + name + ", sig:" + sig);
119 | } else {
120 | console.log("[GetStaticMethodID] name:" + name);
121 | }
122 |
123 | }
124 | },
125 | onLeave: function (retval) { }
126 | });
127 | }
128 | if (addrGetFieldID != null) {
129 | Interceptor.attach(addrGetFieldID, {
130 | onEnter: function (args) {
131 | if (args[2] != null) {
132 | var name = Memory.readCString(args[2]);
133 | if (args[3] != null) {
134 | var sig = Memory.readCString(args[3]);
135 | console.log("[GetFieldID] name:" + name + ", sig:" + sig);
136 | } else {
137 | console.log("[GetFieldID] name:" + name);
138 | }
139 |
140 | }
141 | },
142 | onLeave: function (retval) { }
143 | });
144 | }
145 | if (addrGetStaticFieldID != null) {
146 | Interceptor.attach(addrGetStaticFieldID, {
147 | onEnter: function (args) {
148 | if (args[2] != null) {
149 | var name = Memory.readCString(args[2]);
150 | if (args[3] != null) {
151 | var sig = Memory.readCString(args[3]);
152 | console.log("[GetStaticFieldID] name:" + name + ", sig:" + sig);
153 | } else {
154 | console.log("[GetStaticFieldID] name:" + name);
155 | }
156 |
157 | }
158 | },
159 | onLeave: function (retval) { }
160 | });
161 | }
162 |
163 | if (addrRegisterNatives != null) {
164 | Interceptor.attach(addrRegisterNatives, {
165 | onEnter: function (args) {
166 | console.log("[RegisterNatives] method_count:", args[3]);
167 | var env = args[0];
168 | var java_class = args[1];
169 |
170 | var funcAllocObject = new NativeFunction(addrAllocObject, "pointer", ["pointer", "pointer"]);
171 | var funcGetMethodID = new NativeFunction(addrGetMethodID, "pointer", ["pointer", "pointer", "pointer", "pointer"]);
172 | var funcCallObjectMethod = new NativeFunction(addrCallObjectMethod, "pointer", ["pointer", "pointer", "pointer"]);
173 | var funcGetObjectClass = new NativeFunction(addrGetObjectClass, "pointer", ["pointer", "pointer"]);
174 | var funcGetStringUTFChars = new NativeFunction(addrGetStringUTFChars, "pointer", ["pointer", "pointer", "pointer"]);
175 | var funcReleaseStringUTFChars = new NativeFunction(addrReleaseStringUTFChars, "void", ["pointer", "pointer", "pointer"]);
176 |
177 | var clz_obj = funcAllocObject(env, java_class);
178 | var mid_getClass = funcGetMethodID(env, java_class, Memory.allocUtf8String("getClass"), Memory.allocUtf8String("()Ljava/lang/Class;"));
179 | var clz_obj2 = funcCallObjectMethod(env, clz_obj, mid_getClass);
180 | var cls = funcGetObjectClass(env, clz_obj2);
181 | var mid_getName = funcGetMethodID(env, cls, Memory.allocUtf8String("getName"), Memory.allocUtf8String("()Ljava/lang/String;"));
182 | var name_jstring = funcCallObjectMethod(env, clz_obj2, mid_getName);
183 | var name_pchar = funcGetStringUTFChars(env, name_jstring, ptr(0));
184 | var class_name = ptr(name_pchar).readCString();
185 | funcReleaseStringUTFChars(env, name_jstring, name_pchar);
186 |
187 | //console.log(class_name);
188 |
189 | var methods_ptr = ptr(args[2]);
190 |
191 | var method_count = parseInt(args[3]);
192 | for (var i = 0; i < method_count; i++) {
193 | var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));
194 | var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));
195 | var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));
196 |
197 | var name = Memory.readCString(name_ptr);
198 | var sig = Memory.readCString(sig_ptr);
199 | var find_module = Process.findModuleByAddress(fnPtr_ptr);
200 | console.log("[RegisterNatives] java_class:", class_name, "name:", name, "sig:", sig, "fnPtr:", fnPtr_ptr, "module_name:", find_module.name, "module_base:", find_module.base, "offset:", ptr(fnPtr_ptr).sub(find_module.base));
201 |
202 | }
203 | },
204 | onLeave: function (retval) { }
205 | });
206 | }
207 |
208 | ishook_libart = true;
209 | }
210 |
211 | hook_libart();
212 |
--------------------------------------------------------------------------------
/hook_registerNative.js:
--------------------------------------------------------------------------------
1 | var ishook_libart = false;
2 |
3 | function hook_libart() {
4 | if (ishook_libart === true) {
5 | return;
6 | }
7 | var symbols = Module.enumerateSymbolsSync("libart.so");
8 | var addrGetStringUTFChars = null;
9 | var addrNewStringUTF = null;
10 | var addrFindClass = null;
11 | var addrGetMethodID = null;
12 | var addrGetStaticMethodID = null;
13 | var addrGetFieldID = null;
14 | var addrGetStaticFieldID = null;
15 | var addrRegisterNatives = null;
16 | var addrAllocObject = null;
17 | var addrCallObjectMethod = null;
18 | var addrGetObjectClass = null;
19 | var addrReleaseStringUTFChars = null;
20 | for (var i = 0; i < symbols.length; i++) {
21 | var symbol = symbols[i];
22 | if (symbol.name == "_ZN3art3JNI17GetStringUTFCharsEP7_JNIEnvP8_jstringPh") {
23 | addrGetStringUTFChars = symbol.address;
24 | console.log("GetStringUTFChars is at ", symbol.address, symbol.name);
25 | } else if (symbol.name == "_ZN3art3JNI12NewStringUTFEP7_JNIEnvPKc") {
26 | addrNewStringUTF = symbol.address;
27 | console.log("NewStringUTF is at ", symbol.address, symbol.name);
28 | } else if (symbol.name == "_ZN3art3JNI9FindClassEP7_JNIEnvPKc") {
29 | addrFindClass = symbol.address;
30 | console.log("FindClass is at ", symbol.address, symbol.name);
31 | } else if (symbol.name == "_ZN3art3JNI11GetMethodIDEP7_JNIEnvP7_jclassPKcS6_") {
32 | addrGetMethodID = symbol.address;
33 | console.log("GetMethodID is at ", symbol.address, symbol.name);
34 | } else if (symbol.name == "_ZN3art3JNI17GetStaticMethodIDEP7_JNIEnvP7_jclassPKcS6_") {
35 | addrGetStaticMethodID = symbol.address;
36 | console.log("GetStaticMethodID is at ", symbol.address, symbol.name);
37 | } else if (symbol.name == "_ZN3art3JNI10GetFieldIDEP7_JNIEnvP7_jclassPKcS6_") {
38 | addrGetFieldID = symbol.address;
39 | console.log("GetFieldID is at ", symbol.address, symbol.name);
40 | } else if (symbol.name == "_ZN3art3JNI16GetStaticFieldIDEP7_JNIEnvP7_jclassPKcS6_") {
41 | addrGetStaticFieldID = symbol.address;
42 | console.log("GetStaticFieldID is at ", symbol.address, symbol.name);
43 | } else if (symbol.name == "_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi") {
44 | addrRegisterNatives = symbol.address;
45 | console.log("RegisterNatives is at ", symbol.address, symbol.name);
46 | } else if (symbol.name.indexOf("_ZN3art3JNI11AllocObjectEP7_JNIEnvP7_jclass") >= 0) {
47 | addrAllocObject = symbol.address;
48 | console.log("AllocObject is at ", symbol.address, symbol.name);
49 | } else if (symbol.name.indexOf("_ZN3art3JNI16CallObjectMethodEP7_JNIEnvP8_jobjectP10_jmethodIDz") >= 0) {
50 | addrCallObjectMethod = symbol.address;
51 | console.log("CallObjectMethod is at ", symbol.address, symbol.name);
52 | } else if (symbol.name.indexOf("_ZN3art3JNI14GetObjectClassEP7_JNIEnvP8_jobject") >= 0) {
53 | addrGetObjectClass = symbol.address;
54 | console.log("GetObjectClass is at ", symbol.address, symbol.name);
55 | } else if (symbol.name.indexOf("_ZN3art3JNI21ReleaseStringUTFCharsEP7_JNIEnvP8_jstringPKc") >= 0) {
56 | addrReleaseStringUTFChars = symbol.address;
57 | console.log("ReleaseStringUTFChars is at ", symbol.address, symbol.name);
58 | }
59 | }
60 |
61 | if (addrRegisterNatives != null) {
62 | Interceptor.attach(addrRegisterNatives, {
63 | onEnter: function (args) {
64 | console.log("[RegisterNatives] method_count:", args[3]);
65 | var env = args[0];
66 | var java_class = args[1];
67 |
68 | var funcAllocObject = new NativeFunction(addrAllocObject, "pointer", ["pointer", "pointer"]);
69 | var funcGetMethodID = new NativeFunction(addrGetMethodID, "pointer", ["pointer", "pointer", "pointer", "pointer"]);
70 | var funcCallObjectMethod = new NativeFunction(addrCallObjectMethod, "pointer", ["pointer", "pointer", "pointer"]);
71 | var funcGetObjectClass = new NativeFunction(addrGetObjectClass, "pointer", ["pointer", "pointer"]);
72 | var funcGetStringUTFChars = new NativeFunction(addrGetStringUTFChars, "pointer", ["pointer", "pointer", "pointer"]);
73 | var funcReleaseStringUTFChars = new NativeFunction(addrReleaseStringUTFChars, "void", ["pointer", "pointer", "pointer"]);
74 |
75 | var clz_obj = funcAllocObject(env, java_class);
76 | var mid_getClass = funcGetMethodID(env, java_class, Memory.allocUtf8String("getClass"), Memory.allocUtf8String("()Ljava/lang/Class;"));
77 | var clz_obj2 = funcCallObjectMethod(env, clz_obj, mid_getClass);
78 | var cls = funcGetObjectClass(env, clz_obj2);
79 | var mid_getName = funcGetMethodID(env, cls, Memory.allocUtf8String("getName"), Memory.allocUtf8String("()Ljava/lang/String;"));
80 | var name_jstring = funcCallObjectMethod(env, clz_obj2, mid_getName);
81 | var name_pchar = funcGetStringUTFChars(env, name_jstring, ptr(0));
82 | var class_name = ptr(name_pchar).readCString();
83 | funcReleaseStringUTFChars(env, name_jstring, name_pchar);
84 |
85 | //console.log(class_name);
86 |
87 | var methods_ptr = ptr(args[2]);
88 |
89 | var method_count = parseInt(args[3]);
90 | for (var i = 0; i < method_count; i++) {
91 | var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));
92 | var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));
93 | var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));
94 |
95 | var name = Memory.readCString(name_ptr);
96 | var sig = Memory.readCString(sig_ptr);
97 | var find_module = Process.findModuleByAddress(fnPtr_ptr);
98 | console.log("[RegisterNatives] java_class:", class_name, "name:", name, "sig:", sig, "fnPtr:", fnPtr_ptr, "module_name:", find_module.name, "module_base:", find_module.base, "offset:", ptr(fnPtr_ptr).sub(find_module.base));
99 |
100 | }
101 | },
102 | onLeave: function (retval) { }
103 | });
104 | }
105 |
106 | ishook_libart = true;
107 | }
108 |
109 | hook_libart();
--------------------------------------------------------------------------------
/js_hook.js:
--------------------------------------------------------------------------------
1 | // start with:
2 | // frida -U -l pinning.js -f [APP_ID] --no-pause
3 |
4 | console.log("Script loaded successfully 55");
5 | // Uint8Array 代表答应字符串
6 | // ByteArray2Hex 代表转换成16进制
7 |
8 |
9 | //**************************************************************************************************//
10 | //*****************************************MD5加密***************************************************//
11 | //**************************************************************************************************//
12 |
13 |
14 | // MD5
15 | Java.perform(function(){
16 | var MessageDigest= Java.use('java.security.MessageDigest');
17 |
18 | MessageDigest.getInstance.overload('java.lang.String').implementation=function(arg1){
19 | // console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
20 | console.log(arg1);
21 | var ret = this.getInstance(arg1);
22 | return ret;
23 | }
24 |
25 | MessageDigest.update.overload('[B').implementation=function(arg1){
26 | console.log("use update.overload('[B') ");
27 | parseIn(arg1);
28 | var ret = this.update(arg1);
29 | return ret;
30 | }
31 |
32 | MessageDigest.digest.overload().implementation=function(){
33 | console.log('use digest.overload()');
34 | var ret = this.digest();
35 | parseOut(ret);
36 | return ret;
37 | }
38 |
39 | MessageDigest.digest.overload("[B","int","int").implementation=function(buf,offset,len){
40 | console.log('use digest.overload("[B","int","int")');
41 | parseIn(buf);
42 | var ret = this.digest(buf,offset,len);
43 | parseOut(ret);
44 | return ret;
45 | }
46 |
47 | MessageDigest.digest.overload("[B").implementation=function(buf){
48 | console.log('use digest.overload("[B")');
49 | parseIn(buf);
50 | var ret = this.digest(buf);
51 | parseOut(ret);
52 | return ret;
53 | }
54 | });
55 |
56 |
57 |
58 | function parseIn(input){
59 | var Integer= Java.use('java.lang.Integer');
60 | var String= Java.use('java.lang.String');
61 | try{
62 | console.log("original:"+String.$new(input));
63 | }
64 | catch(e){
65 | console.log(parseHex(input));
66 | }
67 | }
68 |
69 | function parseOut(ret){
70 | var Integer= Java.use('java.lang.Integer');
71 | var String= Java.use('java.lang.String');
72 | var result = "";
73 | for(var i = 0;i>>>>>>>>>>>>>> "+ByteArray2Hex(x));
193 | var ret = cipher.doFinal.overload("[B").call(this, x);
194 | // 解密阶段 new String(ret) 为明文
195 | send('{"my_type" : "after_doFinal" , "hashcode" :"' + this.hashCode().toString() + '" }', new Uint8Array(ret));
196 | send("after_doFinal <<<<<<<<<<<<<<<< "+ByteArray2Hex(ret));
197 | return ret;
198 | }
199 |
200 | //
201 | var mac = Java.use("javax.crypto.Mac");
202 | mac.doFinal.overload("[B").implementation = function (x) {
203 | send('{"my_type" : "before_doFinal" , "hashcode" :"' + this.hashCode().toString() + '" }', new Uint8Array(x));
204 | var ret = mac.doFinal.overload("[B").call(this, x);
205 | var hexstr = ByteArray2Hex(ret);
206 | send("after_doFinal HEX: " + hexstr);
207 | send("after_doFinal HEX: " + hexstr.toUpperCase());
208 | return ret;
209 | }
210 |
211 | });
212 |
213 | function Uint8ArrayToString(fileData){
214 | var dataString = "";
215 | for (var i = 0; i < fileData.length; i++) {
216 | dataString += String.fromCharCode(fileData[i]);
217 | }
218 |
219 | return dataString
220 | }
221 |
222 |
223 | function ByteArray2Hex(ret){
224 | var hexstr="";
225 | for (var i=0;i>>0)&0xff;
228 | var n=b.toString(16);
229 | hexstr += ("00" + n).slice(-2)+"";
230 | }
231 | return hexstr;
232 | }
233 |
234 |
235 | //**************************************************************************************************//
236 | //*****************************************ssl ping抓包*********************************************//
237 | //**************************************************************************************************//
238 |
239 |
240 | // hook ssl pinning
241 | Java.perform(function () {
242 | console.log('')
243 | console.log('===')
244 | console.log('* Injecting hooks into common certificate pinning methods *')
245 | console.log('===')
246 |
247 | var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
248 | var SSLContext = Java.use('javax.net.ssl.SSLContext');
249 |
250 | // build fake trust manager
251 | var TrustManager = Java.registerClass({
252 | name: 'com.sensepost.test.TrustManager',
253 | implements: [X509TrustManager],
254 | methods: {
255 | checkClientTrusted: function (chain, authType) {
256 | },
257 | checkServerTrusted: function (chain, authType) {
258 | },
259 | getAcceptedIssuers: function () {
260 | return [];
261 | }
262 | }
263 | });
264 |
265 | // pass our own custom trust manager through when requested
266 | var TrustManagers = [TrustManager.$new()];
267 | var SSLContext_init = SSLContext.init.overload(
268 | '[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom'
269 | );
270 | SSLContext_init.implementation = function (keyManager, trustManager, secureRandom) {
271 | console.log('! Intercepted trustmanager request');
272 | SSLContext_init.call(this, keyManager, TrustManagers, secureRandom);
273 | };
274 |
275 | console.log('* Setup custom trust manager');
276 |
277 | // okhttp3
278 | try {
279 | var CertificatePinner = Java.use('okhttp3.CertificatePinner');
280 | CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function (str) {
281 | console.log('! Intercepted okhttp3: ' + str);
282 | return;
283 | };
284 |
285 | console.log('* Setup okhttp3 pinning')
286 | } catch(err) {
287 | console.log('* Unable to hook into okhttp3 pinner')
288 | }
289 |
290 | // trustkit
291 | try {
292 | var Activity = Java.use("com.datatheorem.android.trustkit.pinning.OkHostnameVerifier");
293 | Activity.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (str) {
294 | console.log('! Intercepted trustkit{1}: ' + str);
295 | return true;
296 | };
297 |
298 | Activity.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (str) {
299 | console.log('! Intercepted trustkit{2}: ' + str);
300 | return true;
301 | };
302 |
303 | console.log('* Setup trustkit pinning')
304 | } catch(err) {
305 | console.log('* Unable to hook into trustkit pinner')
306 | }
307 |
308 | // TrustManagerImpl
309 | try {
310 | var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');
311 | TrustManagerImpl.verifyChain.implementation = function (untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
312 | console.log('! Intercepted TrustManagerImp: ' + host);
313 | return untrustedChain;
314 | }
315 |
316 | console.log('* Setup TrustManagerImpl pinning')
317 | } catch (err) {
318 | console.log('* Unable to hook into TrustManagerImpl')
319 | }
320 |
321 | // Appcelerator
322 | try {
323 | var PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');
324 | PinningTrustManager.checkServerTrusted.implementation = function () {
325 | console.log('! Intercepted Appcelerator');
326 | }
327 |
328 | console.log('* Setup Appcelerator pinning')
329 | } catch (err) {
330 | console.log('* Unable to hook into Appcelerator pinning')
331 | }
332 | });
--------------------------------------------------------------------------------
/src/com/lang/script/AES.java:
--------------------------------------------------------------------------------
1 | package com.lang.script;
2 |
3 | import javax.crypto.Cipher;
4 | import javax.crypto.spec.SecretKeySpec;
5 | import java.io.UnsupportedEncodingException;
6 | import java.security.MessageDigest;
7 | import java.security.NoSuchAlgorithmException;
8 | import java.util.Arrays;
9 | import java.util.Base64;
10 |
11 | /*******************************************************************************
12 | * AES加解密算法
13 | * http://tools.lami.la/jiami/aes
14 | * 说明:AES数据块长度为128位,所以IV长度需要为16个字符(ECB模式不用IV),密钥根据指定密钥位数分别为16、24、32个字符,IV与密钥超过长度则截取,不足则在末尾填充'\0'补足
15 | *******************************************************************************/
16 | public class AES {
17 |
18 | private static SecretKeySpec secretKey;
19 | private static byte[] key;
20 |
21 | public static void setKey(String myKey)
22 | {
23 | MessageDigest sha = null;
24 | try {
25 | key = myKey.getBytes("UTF-8");
26 | sha = MessageDigest.getInstance("SHA-1");
27 | key = sha.digest(key);
28 | key = Arrays.copyOf(key, 16);
29 | secretKey = new SecretKeySpec(key, "AES");
30 | }
31 | catch (NoSuchAlgorithmException e) {
32 | e.printStackTrace();
33 | }
34 | catch (UnsupportedEncodingException e) {
35 | e.printStackTrace();
36 | }
37 | }
38 |
39 | public static String encrypt(String strToEncrypt, String secret)
40 | {
41 | try
42 | {
43 | setKey(secret);
44 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
45 | cipher.init(Cipher.ENCRYPT_MODE, secretKey);
46 | return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
47 | }
48 | catch (Exception e)
49 | {
50 | System.out.println("Error while encrypting: " + e.toString());
51 | }
52 | return null;
53 | }
54 |
55 | public static String decrypt(String strToDecrypt, String secret)
56 | {
57 | try
58 | {
59 | setKey(secret);
60 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
61 | cipher.init(Cipher.DECRYPT_MODE, secretKey);
62 | return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)));
63 | }
64 | catch (Exception e)
65 | {
66 | System.out.println("Error while decrypting: " + e.toString());
67 | }
68 | return null;
69 | }
70 | }
--------------------------------------------------------------------------------
/src/com/lang/script/AESUtils.java:
--------------------------------------------------------------------------------
1 | package com.lang.script;
2 |
3 | import javax.crypto.Cipher;
4 | import javax.crypto.spec.IvParameterSpec;
5 | import javax.crypto.spec.SecretKeySpec;
6 | import java.util.Base64;
7 |
8 |
9 | /*******************************************************************************
10 | * Frida调试逆向AES
11 | *******************************************************************************/
12 | public class AESUtils {
13 |
14 | /**
15 | * 16进制转byte[]
16 | * @param s
17 | * @return
18 | */
19 | public static byte[] hexStringToByteArray(String s) {
20 |
21 | int len = s.length();
22 | byte[] data = new byte[len / 2];
23 | for (int i = 0; i < len; i += 2) {
24 | data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
25 | + Character.digit(s.charAt(i+1), 16));
26 | }
27 | System.out.println("(key不一定可逆)hexStringToByteArray:"+new String(data));
28 | return data;
29 | }
30 |
31 | // 加密
32 | public static String Encrypt(String Src) throws Exception {
33 | String Key = "5565504004055655";
34 | byte[] key = Key.getBytes();
35 | SecretKeySpec keySpec = new SecretKeySpec(hexStringToByteArray("a2f85a04b49048153c9e61f93be968f5"), "AES");
36 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//"算法/模式/补码方式"
37 |
38 | // IvParameterSpec iv = new IvParameterSpec(hexStringToByteArray("0a010b05040f070917030106080c0d5b"));
39 | // cipher.init(Cipher.ENCRYPT_MODE, keySpec,iv);
40 |
41 | cipher.init(Cipher.ENCRYPT_MODE, keySpec);
42 | return Base64.getEncoder().encodeToString(cipher.doFinal(Src.getBytes("UTF-8")));
43 | }
44 |
45 |
46 | // AES/CBC/PKCS5Padding 解密
47 | public static String Decrypt(String Src) throws Exception {
48 | try {
49 | String Key = "5565504004055655";
50 | byte[] key = Key.getBytes("ASCII");
51 | SecretKeySpec keySpec = new SecretKeySpec(hexStringToByteArray("a2f85a04b49048153c9e61f93be968f5"), "AES");
52 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//"算法/模式/补码方式"
53 |
54 | // IvParameterSpec iv = new IvParameterSpec(hexStringToByteArray("33626539303734623433363932616363"));
55 | // cipher.init(Cipher.DECRYPT_MODE, keySpec,iv);
56 |
57 | cipher.init(Cipher.DECRYPT_MODE, keySpec);
58 | return new String(cipher.doFinal(Base64.getDecoder().decode(Src)));
59 | } catch (Exception ex) {
60 | ex.printStackTrace();
61 | return null;
62 | }
63 | }
64 |
65 | /**
66 | *
67 | * @param src
68 | * @return
69 | * @throws Exception
70 | */
71 | public static String HDecrypt(String src) throws Exception {
72 | System.out.println("HDecrypt");
73 | try {
74 | SecretKeySpec keySpec = new SecretKeySpec(hexStringToByteArray("d8ef94301cd8e477562d121342b0457b"), "AES");
75 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//"算法/模式/补码方式"
76 |
77 | IvParameterSpec iv = new IvParameterSpec(hexStringToByteArray("37313865646437643239633038386234"));
78 | cipher.init(Cipher.DECRYPT_MODE, keySpec,iv);
79 |
80 | return new String(cipher.doFinal(hexStringToByteArray(src)));
81 | } catch (Exception ex) {
82 | ex.printStackTrace();
83 | return null;
84 | }
85 | }
86 |
87 |
88 |
89 |
90 | public static void main(String[] args) throws Exception {
91 |
92 |
93 | /*
94 | * 加密用的Key 可以用26个字母和数字组成,最好不要用保留字符,虽然不会错,至于怎么裁决,个人看情况而定
95 | * 此处使用AES-128-CBC加密模式,key需要为16位。
96 | */
97 | // 需要加密的字串
98 | String Src = "howtodoinjava.com";
99 | System.out.println(Src);
100 | // 加密
101 | String enString = AESUtils.Encrypt(Src);
102 | System.out.println("加密后的字串是:" + enString);
103 |
104 |
105 | // 解密
106 | String DeString = AESUtils.Decrypt(enString);
107 | System.out.println("解密后的字串是:" + DeString);
108 |
109 | // 逆向复制
110 | String result=AESUtils.HDecrypt("aef24dbb6e865e821e72a4d6709c717f530e6e5cfd84aba9826ae2685684f5178c7f5e89dad1fd6d59a34d8e052e200d78ba2ffe78b518076d1044082c3eec142c2f0a01e895ac960e8e7472f83052a90dce40bac02572cafa50169aa90c952667e682907de745b51fd84a995d57dfe3dc3f56d5e7a09fe4b58d80ab29c05e177b5edd87732fb4eeb49ed3715ad9b9becc9c769dfb1cf62d3b259666023cac0a60717bb806c8f9038ccda93a82d75924bc8a61e2b180680f2cca6bfdac3aa9b0c99b767e2f980c26f2ce86bb4cdd56fcb1598aefae38ed1f0e9d7c523d953aff784b56c365aae05731aa5a5da506c61da88ee1711f9663b4a3db0897e5a6e56d040321bd4ed4940c09f74fd387a96bb3410986adcab10bff69c5a1d37790ac6f");
111 | System.out.println("解密后的字串是:" + result);
112 |
113 | }
114 | }
--------------------------------------------------------------------------------
/src/com/lang/script/HMACSHA256Util.java:
--------------------------------------------------------------------------------
1 | package com.lang.script;
2 |
3 | import javax.crypto.Mac;
4 | import javax.crypto.spec.SecretKeySpec;
5 |
6 | public class HMACSHA256Util {
7 | // SECRET KEY
8 | private final static String secret_key = "J1r852d15X2jva8cdS97N121H8903097";
9 | /**
10 | * 将加密后的字节数组转换成字符串
11 | *
12 | * @param b 字节数组
13 | * @return 字符串
14 | */
15 | private static String byteArrayToHexString(byte[] b) {
16 | StringBuilder hs = new StringBuilder();
17 | String stmp;
18 | for (int n = 0; b!=null && n < b.length; n++) {
19 | stmp = Integer.toHexString(b[n] & 0XFF);
20 | if (stmp.length() == 1)
21 | hs.append('0');
22 | hs.append(stmp);
23 | }
24 | return hs.toString().toLowerCase();
25 | }
26 | /**
27 | * sha256_HMAC加密
28 | * @param message 消息
29 | * @param secret 秘钥
30 | * @return 加密后字符串
31 | */
32 | public static String sha256_HMAC(String message, String secret) {
33 | String hash = "";
34 | try {
35 | Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
36 | SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
37 | sha256_HMAC.init(secret_key);
38 | byte[] bytes = sha256_HMAC.doFinal(message.getBytes());
39 | hash = byteArrayToHexString(bytes);
40 | System.out.println(hash);
41 | } catch (Exception e) {
42 | System.out.println("Error HmacSHA256 ===========" + e.getMessage());
43 | }
44 | return hash;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/com/lang/script/HttpURLConnectionExample.java:
--------------------------------------------------------------------------------
1 | package com.lang.script;
2 |
3 | import javax.net.ssl.HttpsURLConnection;
4 | import java.io.BufferedReader;
5 | import java.io.DataOutputStream;
6 | import java.io.InputStreamReader;
7 | import java.net.HttpURLConnection;
8 | import java.net.URL;
9 |
10 | public class HttpURLConnectionExample {
11 |
12 | private final String USER_AGENT = "Mozilla/5.0";
13 |
14 | public static void main(String[] args) throws Exception {
15 |
16 | HttpURLConnectionExample http = new HttpURLConnectionExample();
17 |
18 | System.out.println("Testing 1 - Send Http GET request");
19 | http.sendGet();
20 |
21 | System.out.println("\nTesting 2 - Send Http POST request");
22 | http.sendPost();
23 |
24 | }
25 |
26 | // HTTP GET请求
27 | private void sendGet() throws Exception {
28 |
29 | String url = "http://www.google.com/search?q=mkyong";
30 |
31 | URL obj = new URL(url);
32 | HttpURLConnection con = (HttpURLConnection) obj.openConnection();
33 |
34 | //默认值我GET
35 | con.setRequestMethod("GET");
36 |
37 | //添加请求头
38 | con.setRequestProperty("User-Agent", USER_AGENT);
39 |
40 | int responseCode = con.getResponseCode();
41 | System.out.println("\nSending 'GET' request to URL : " + url);
42 | System.out.println("Response Code : " + responseCode);
43 |
44 | BufferedReader in = new BufferedReader(
45 | new InputStreamReader(con.getInputStream()));
46 | String inputLine;
47 | StringBuffer response = new StringBuffer();
48 |
49 | while ((inputLine = in.readLine()) != null) {
50 | response.append(inputLine);
51 | }
52 | in.close();
53 |
54 | //打印结果
55 | System.out.println(response.toString());
56 |
57 | }
58 |
59 | // HTTP POST请求
60 | private void sendPost() throws Exception {
61 |
62 | String url = "https://selfsolve.apple.com/wcResults.do";
63 | URL obj = new URL(url);
64 | HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
65 |
66 | //添加请求头
67 | con.setRequestMethod("POST");
68 | con.setRequestProperty("User-Agent", USER_AGENT);
69 | con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
70 |
71 | String urlParameters = "sn=C02G8416DRJM&cn=&locale=&caller=&num=12345";
72 |
73 | //发送Post请求
74 | con.setDoOutput(true);
75 | DataOutputStream wr = new DataOutputStream(con.getOutputStream());
76 | wr.writeBytes(urlParameters);
77 | wr.flush();
78 | wr.close();
79 |
80 | int responseCode = con.getResponseCode();
81 | System.out.println("\nSending 'POST' request to URL : " + url);
82 | System.out.println("Post parameters : " + urlParameters);
83 | System.out.println("Response Code : " + responseCode);
84 |
85 | BufferedReader in = new BufferedReader(
86 | new InputStreamReader(con.getInputStream()));
87 | String inputLine;
88 | StringBuffer response = new StringBuffer();
89 |
90 | while ((inputLine = in.readLine()) != null) {
91 | response.append(inputLine);
92 | }
93 | in.close();
94 |
95 | //打印结果
96 | System.out.println(response.toString());
97 |
98 | }
99 |
100 | }
--------------------------------------------------------------------------------
/src/com/lang/script/MD5Utils.java:
--------------------------------------------------------------------------------
1 | package com.lang.script;
2 |
3 | import java.security.MessageDigest;
4 | import java.security.NoSuchAlgorithmException;
5 |
6 | /*****************************************************************************************
7 | * MD5加密
8 | *****************************************************************************************/
9 | public class MD5Utils {
10 | private static final char[] HEX_DIGITS = { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102 };
11 |
12 | public static String getMD5String(String str) {
13 | byte[] paramArrayOfByte = str.getBytes();
14 | String result = null;
15 |
16 | try {
17 | //首先进行实例化和初始化
18 | MessageDigest md = MessageDigest.getInstance("MD5");
19 | //得到一个操作系统默认的字节编码格式的字节数组
20 | //对得到的字节数组进行处理
21 | md.update(paramArrayOfByte);
22 | //进行哈希计算并返回结果
23 | byte[] btResult = md.digest();
24 | result = bytesToHex(btResult,0, btResult.length);
25 | } catch (NoSuchAlgorithmException e) {
26 | e.printStackTrace();
27 | }
28 | return result;
29 |
30 | }
31 |
32 | public static String bytesToHex(byte[] bytedata, int starRatingStyle, int encyptBody) {
33 | StringBuilder stringBuilder = new StringBuilder();
34 | for (int i = starRatingStyle; i < starRatingStyle + encyptBody; i++) {
35 | stringBuilder.append(byteToHex(bytedata[i]));
36 | }
37 | return stringBuilder.toString();
38 | }
39 |
40 | public static String byteToHex(byte paramByte)
41 | {
42 | return HEX_DIGITS[((paramByte & 0xF0) >> 4)] + "" + HEX_DIGITS[(paramByte & 0xF)];
43 | }
44 |
45 |
46 |
47 | }
--------------------------------------------------------------------------------
/src/com/lang/script/RASUtils.java:
--------------------------------------------------------------------------------
1 | package com.lang.script;
2 |
3 | import javax.crypto.Cipher;
4 | import java.security.KeyFactory;
5 | import java.security.PrivateKey;
6 | import java.security.PublicKey;
7 | import java.security.spec.PKCS8EncodedKeySpec;
8 | import java.security.spec.X509EncodedKeySpec;
9 | import java.util.Base64;
10 |
11 |
12 | /*******************************************************************************
13 | * frida调试逆向RSA
14 | *******************************************************************************/
15 | public class RASUtils {
16 |
17 |
18 | /**
19 | * 16进制转byte[]
20 | * @param s
21 | * @return
22 | */
23 | public static byte[] hexStringToByteArray(String s) {
24 | int len = s.length();
25 | byte[] data = new byte[len / 2];
26 | for (int i = 0; i < len; i += 2) {
27 | data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
28 | + Character.digit(s.charAt(i+1), 16));
29 | }
30 | System.out.println(new String(data));
31 | return data;
32 | }
33 |
34 | /**
35 | * BASE64 解码
36 | * @param key 需要Base64解码的字符串
37 | * @return 字节数组
38 | */
39 | public static byte[] decryptBase64(String key) {
40 | return Base64.getDecoder().decode(key);
41 | }
42 |
43 | /**
44 | * BASE64 编码
45 | * @param key 需要Base64编码的字节数组
46 | * @return 字符串
47 | */
48 | public static String encryptBase64(byte[] key) {
49 | return new String(Base64.getEncoder().encode(key));
50 | }
51 |
52 | /**
53 | * 确定对方用公钥加密
54 | * @param encryptingStr
55 | * @param publicKeyStr
56 | * @return
57 | */
58 | public static String encryptByPublic(String encryptingStr, String publicKeyStr){
59 | try {
60 | // 将公钥由字符串转为UTF-8格式的字节数组
61 | byte[] publicKeyBytes = hexStringToByteArray(publicKeyStr);
62 | // 获得公钥
63 | X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
64 | // 取得待加密数据
65 | byte[] data = encryptingStr.getBytes("UTF-8");
66 | KeyFactory keyFactory = KeyFactory.getInstance("RSA");
67 | PublicKey publicKey = keyFactory.generatePublic(keySpec);
68 |
69 | System.out.println(keyFactory.getAlgorithm());
70 | // 对数据加密
71 | Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
72 | cipher.init(Cipher.ENCRYPT_MODE, publicKey);
73 | // 返回加密后由Base64编码的加密信息
74 | return encryptBase64(cipher.doFinal(data));
75 | } catch (Exception e) {
76 | e.printStackTrace();
77 | }
78 | return null;
79 | }
80 |
81 | /**
82 | * 确定对方用私钥加密 or 解密
83 | * @param encryptingStr
84 | * @param privateKeyStr
85 | * @return
86 | */
87 | public static String encryptByPrivate(String encryptingStr, String privateKeyStr){
88 | try {
89 | // 将公钥由字符串转为UTF-8格式的字节数组
90 | byte[] publicKeyBytes = hexStringToByteArray(privateKeyStr);
91 | // 获得公钥
92 | PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(publicKeyBytes);
93 | // 取得待加密数据
94 | byte[] data = encryptingStr.getBytes("UTF-8");
95 | KeyFactory keyFactory = KeyFactory.getInstance("RSA");
96 | PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
97 | // 对数据加密
98 | Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
99 | cipher.init(Cipher.ENCRYPT_MODE, privateKey);
100 | // 返回加密后由Base64编码的加密信息
101 | return encryptBase64(cipher.doFinal(data));
102 | } catch (Exception e) {
103 | e.printStackTrace();
104 | }
105 | return null;
106 | }
107 |
108 | /**
109 | * 确定对方用公钥加密 or 解密
110 | * @param encryptedStr
111 | * @param publicKeyStr frida 打印出的key
112 | * @return
113 | */
114 | public static String decryptByPublic(String encryptedStr, String publicKeyStr){
115 | try {
116 | // 对公钥解密
117 | byte[] publicKeyBytes = hexStringToByteArray(publicKeyStr);
118 | // 取得公钥
119 | X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
120 | // 取得待加密数据
121 | KeyFactory factory = KeyFactory.getInstance("RSA");
122 | PublicKey publicKey = factory.generatePublic(keySpec);
123 | // 对数据解密
124 | Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
125 | cipher.init(Cipher.DECRYPT_MODE, publicKey);
126 | // 返回UTF-8编码的解密信息
127 | return new String(cipher.doFinal(hexStringToByteArray(encryptedStr)));
128 | } catch (Exception e) {
129 | e.printStackTrace();
130 | }
131 |
132 | return null;
133 | }
134 |
135 | public static void main(String[] args) throws Exception {
136 | /*
137 | * 加密用的Key 可以用26个字母和数字组成,最好不要用保留字符,虽然不会错,至于怎么裁决,个人看情况而定
138 | * 此处使用AES-128-CBC加密模式,key需要为16位。
139 | */
140 | String Key = "30820122300d06092a864886f70d01010105000382010f003082010a0282010100bbc9efcf4a734e3bb6427c25098f7c727a259ec84ed2ec495d9908307b8840dacea846eae57e869264f55a49dcd8eb34b44a92b483d75b1986b24eee7adc98d440ba1f5558c326b9fb5f7d2820d4d4a546c18c2b550fcd0d1c4c20c61e0fe84cb31e3e2393b7adbe266ccef4ab608414e922982f9ecf123e56ba78d87094348cb2a205abde105ccfce4db720a9ce6388076afc884abc53b0f16974cd8cd74d546dc9bea5e7793e7f66507edd366ef82adf32d65f8db1094728929c438c04b938d5cfe48d6cbcf097fb5fe1e4a31c0d11e6caf8c6b61dc6b514b4387403c212fec12be4286b08de38855528a475363d403c73248305bf6644f9c4a9a799406a4d0203010001";
141 | // 需要加密的字串
142 | String Src = "This is a secret message";
143 | System.out.println(Src);
144 | // 加密
145 | // String enString = RASUtils.encryptByPrivate(Src, Key);
146 | // System.out.println("加密后的字串是:" + enString);
147 |
148 | String encodeBody="79e7825c7dad8dc813118aff2c31122aaac9578a4c0c3bb5ce058d919fa5bd4256f9ea43a38b4e334c78e3bd993be05487d02a3261909d02bebd48a9c6691915b053e700478f33b48cf1a4613f5093daf0e2b897d60090cd8d399cb803eee1d86e5523db27c4cc619b3d170f8673d5cae507498b3a13cb05e1dbd79b23ba84b6255a71b7763042d69b401143b6906e9ecc79803d87e0cad0441d074a12f44acd65e6c0f66a8135d11994b8c45d9356f3e1bbecbdbd6b4852c65fe65f020a2f8b8a29d53f4d8cbe001992d30ac623bea9ee195a38cd0af381dbf8be51a4b5788df578f29f6ba881498dd491f3515ed7b762522fe9a0f7d216a4fdddf51e28d6ed";
149 | String eString = RASUtils.decryptByPublic(encodeBody, Key);
150 | System.out.println("解密后的字串是:" + eString);
151 | }
152 | }
--------------------------------------------------------------------------------
/src/com/lang/script/RASUtilsNew.java:
--------------------------------------------------------------------------------
1 | package com.lang.script;
2 |
3 | import javax.crypto.*;
4 | import java.security.*;
5 | import java.security.spec.X509EncodedKeySpec;
6 | import java.util.Base64;
7 |
8 | /*******************************************************************************
9 | * AES加解密算法
10 | * http://tools.lami.la/jiami/aes
11 | * 说明:AES数据块长度为128位,所以IV长度需要为16个字符(ECB模式不用IV),密钥根据指定密钥位数分别为16、24、32个字符,IV与密钥超过长度则截取,不足则在末尾填充'\0'补足
12 | *******************************************************************************/
13 |
14 |
15 | public class RASUtilsNew {
16 |
17 | public static void encrypt() {
18 |
19 |
20 | try {
21 | KeyGenerator generator = KeyGenerator.getInstance("AES");
22 | generator.init(128); // The AES key size in number of bits
23 | SecretKey secKey = generator.generateKey();
24 |
25 | String plainText = "Please encrypt me urgently...";
26 | Cipher aesCipher = Cipher.getInstance("AES");
27 | aesCipher.init(Cipher.ENCRYPT_MODE, secKey);
28 | byte[] byteCipherText = aesCipher.doFinal(plainText.getBytes());
29 |
30 | KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
31 | kpg.initialize(2048);
32 | KeyPair keyPair = kpg.generateKeyPair();
33 |
34 | PublicKey puKey = keyPair.getPublic();
35 | PrivateKey prKey = keyPair.getPrivate();
36 |
37 | Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
38 | cipher.init(Cipher.PUBLIC_KEY, puKey);
39 | byte[] encryptedKey = cipher.doFinal(secKey.getEncoded()/*Seceret Key From Step 1*/);
40 |
41 | } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
42 | e.printStackTrace();
43 | }
44 |
45 |
46 |
47 | }
48 |
49 | public static byte[] hexStringToByteArray(String s) {
50 | int len = s.length();
51 | byte[] data = new byte[len / 2];
52 | for (int i = 0; i < len; i += 2) {
53 | data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
54 | + Character.digit(s.charAt(i+1), 16));
55 | }
56 | return data;
57 | }
58 |
59 | /**
60 | * BASE64 解码
61 | * @param key 需要Base64解码的字符串
62 | * @return 字节数组
63 | */
64 | public static byte[] decryptBase64(String key) {
65 | return Base64.getDecoder().decode(key);
66 | }
67 |
68 | /**
69 | * BASE64 编码
70 | * @param key 需要Base64编码的字节数组
71 | * @return 字符串
72 | */
73 | public static String encryptBase64(byte[] key) {
74 | return new String(Base64.getEncoder().encode(key));
75 | }
76 |
77 | /**
78 | * 公钥加密
79 | * @param encryptingStr
80 | * @param publicKeyStr
81 | * @return
82 | */
83 | public static String encryptByPublic(String encryptingStr, String publicKeyStr){
84 | try {
85 | // 将公钥由字符串转为UTF-8格式的字节数组
86 | // byte[] publicKeyBytes = decryptBase64(publicKeyStr);
87 | byte[] publicKeyBytes = hexStringToByteArray(publicKeyStr);
88 | // 获得公钥
89 | X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
90 | // 取得待加密数据
91 | byte[] data = encryptingStr.getBytes("UTF-8");
92 | KeyFactory factory;
93 | factory = KeyFactory.getInstance("RSA");
94 | PublicKey publicKey = factory.generatePublic(keySpec);
95 | // 对数据加密
96 | Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
97 | cipher.init(Cipher.ENCRYPT_MODE, publicKey);
98 | // 返回加密后由Base64编码的加密信息
99 | return encryptBase64(cipher.doFinal(data));
100 | } catch (Exception e) {
101 | e.printStackTrace();
102 | }
103 | return null;
104 | }
105 |
106 | /**
107 | * 公钥解密
108 | * @param encryptedStr
109 | * @param publicKeyStr
110 | * @return
111 | */
112 | public static String decryptByPublic(String encryptedStr, String publicKeyStr){
113 | try {
114 | // 对公钥解密
115 | byte[] publicKeyBytes = decryptBase64(publicKeyStr);
116 | // 取得公钥
117 | X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
118 | // 取得待加密数据
119 | byte[] data = decryptBase64(encryptedStr);
120 | KeyFactory factory = KeyFactory.getInstance("RSA");
121 | PublicKey publicKey = factory.generatePublic(keySpec);
122 | // 对数据解密
123 | Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
124 | cipher.init(Cipher.DECRYPT_MODE, publicKey);
125 | // 返回UTF-8编码的解密信息
126 | return new String(cipher.doFinal(data), "UTF-8");
127 | } catch (Exception e) {
128 | e.printStackTrace();
129 | }
130 |
131 | return null;
132 | }
133 |
134 | public static void main(String[] args) throws Exception {
135 | /*
136 | * 加密用的Key 可以用26个字母和数字组成,最好不要用保留字符,虽然不会错,至于怎么裁决,个人看情况而定
137 | * 此处使用AES-128-CBC加密模式,key需要为16位。
138 | */
139 | String Key = "30819f300d06092a864886f70d010101050003818d0030818902818100d65b8500176d70d40b6986cb15c9e6b11835e44744582a176cc4f2cb5a91f792fa3245b69f280825eeba967bc69dd1ee962323daa9cc8493502042c4c2cf87d3ea798015213fd06ea266f2f2c04d467d02e757e6377d1754dfc4b2f8545f3c805131bf02b03373088ba63c5e39674d70886711557699fd472158ddda7bdb17f30203010001";
140 | // 需要加密的字串
141 | String Src = "17611597504";
142 | System.out.println(Src);
143 | // 加密
144 | String enString = RASUtilsNew.encryptByPublic(Src, Key);
145 | System.out.println("加密后的字串是:" + enString);
146 |
147 |
148 |
149 |
150 | }
151 | }
--------------------------------------------------------------------------------
/src/com/lang/script/RSA.java:
--------------------------------------------------------------------------------
1 | package com.lang.script;
2 |
3 | import javax.crypto.Cipher;
4 | import java.io.BufferedWriter;
5 | import java.io.FileWriter;
6 | import java.io.IOException;
7 | import java.nio.charset.Charset;
8 | import java.security.*;
9 | import java.security.interfaces.RSAPrivateKey;
10 | import java.security.interfaces.RSAPublicKey;
11 | import java.security.spec.InvalidKeySpecException;
12 | import java.security.spec.PKCS8EncodedKeySpec;
13 | import java.security.spec.X509EncodedKeySpec;
14 | import java.util.Base64;
15 |
16 | /*******************************************************************************
17 | 加解密:公钥加密,私钥解密
18 | 签名验证:私钥签名,公钥验签
19 | *******************************************************************************/
20 | public class RSA {
21 | public static final String RSA_ALGORITHM = "RSA";
22 | public static final Charset UTF8 = Charset.forName("UTF-8");
23 |
24 | public static void main(String [] args) throws Exception {
25 | // generate public and private keys
26 | KeyPair keyPair = buildKeyPair();
27 | PublicKey publicKey = keyPair.getPublic();
28 | PrivateKey privateKey = keyPair.getPrivate();
29 | RSA.savePrivateKey(privateKey);
30 | RSA.savePublicKey(publicKey);
31 |
32 | // encrypt the message
33 | String encrypted=encrypt(privateKey, "This is a secret message");
34 | System.out.println(encrypted); // <>
35 |
36 | // decrypt the message
37 | System.out.println(decrypt(publicKey, encrypted)); // This is a secret message
38 | }
39 |
40 | public static KeyPair buildKeyPair() throws NoSuchAlgorithmException {
41 | final int keySize = 2048;
42 | KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
43 | keyPairGenerator.initialize(keySize);
44 | return keyPairGenerator.genKeyPair();
45 | }
46 |
47 | public static String encrypt(PrivateKey privateKey, String message) throws Exception {
48 | Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
49 | cipher.init(Cipher.ENCRYPT_MODE, privateKey);
50 | return Base64.getEncoder().encodeToString(cipher.doFinal(message.getBytes(UTF8)));
51 | }
52 |
53 | public static String decrypt(PublicKey publicKey, String encrypted) throws Exception {
54 | Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
55 | cipher.init(Cipher.DECRYPT_MODE, publicKey);
56 | return new String(cipher.doFinal(Base64.getDecoder().decode(encrypted)));
57 | }
58 |
59 | /**
60 | * 从字符串中加载公钥
61 | *
62 | */
63 | public static RSAPublicKey loadPublicKey(String publicKeyStr) throws Exception {
64 | try {
65 | byte[] buffer = base64Decode(publicKeyStr);
66 | KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
67 | X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
68 | return (RSAPublicKey) keyFactory.generatePublic(keySpec);
69 | } catch (NoSuchAlgorithmException e) {
70 | throw new RuntimeException(e);
71 | } catch (InvalidKeySpecException e) {
72 | throw new RuntimeException(e);
73 | }
74 | }
75 |
76 | public static RSAPrivateKey loadPrivateKey(String privateKeyStr) throws Exception {
77 | try {
78 | byte[] buffer = base64Decode(privateKeyStr);
79 | PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
80 | KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
81 | return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
82 | } catch (NoSuchAlgorithmException e) {
83 | throw new RuntimeException(e);
84 | } catch (InvalidKeySpecException e) {
85 | throw new RuntimeException(e);
86 | }
87 | }
88 |
89 | public static void savePublicKey(PublicKey publicKey) throws IOException {
90 | // 得到公钥字符串
91 | String publicKeyString = base64Encode(publicKey.getEncoded());
92 | System.out.println("publicKeyString="+publicKeyString);
93 | FileWriter fw = new FileWriter("publicKey.keystore");
94 | BufferedWriter bw = new BufferedWriter(fw);
95 | bw.write(publicKeyString);
96 | bw.close();
97 | }
98 |
99 | public static void savePrivateKey(PrivateKey privateKey) throws IOException {
100 | // 得到私钥字符串
101 | String privateKeyString = base64Encode(privateKey.getEncoded());
102 | System.out.println("privateKeyString="+privateKeyString);
103 |
104 | BufferedWriter bw = new BufferedWriter(new FileWriter("privateKey.keystore"));
105 | bw.write(privateKeyString);
106 | bw.close();
107 | }
108 |
109 | public static String base64Encode(byte[] data) {
110 | return Base64.getEncoder().encodeToString(data);
111 | }
112 | public static byte[] base64Decode(String data) throws IOException {
113 | return Base64.getDecoder().decode(data);
114 | }
115 | }
--------------------------------------------------------------------------------