盒子
盒子
文章目录
  1. 加密手段
    1. Conceal使用
      1. 在项目的Application的onCreate()函数中初始化
      2. 加密字符串
      3. 解密字符串
      4. 加密文件
      5. 解密文件
    2. SecretKey
      1. 创建一个SecretKeyHelper类
      2. C++实现
        1. 头文件secretkey.h
        2. cpp文件secretkey.cpp
        3. Application.mk文件
        4. Android.mk文件
  2. 代码获取

加密你的App

企业级开发中加密数据一般都少不了,我们在与服务端交互中,发送的参数以及获取的数据都是加密后的,需要客户端与服务端互相加解密
初期我们使用了java提供的Cipher类,加解密效果是达到了,但是缺点也是明显的:太慢。每次加密过程一串不长的Json就将近1秒左右,为此不得不另外再开异步执行加解密,这样繁琐不简洁,整个APP的速度也被拖慢。

加密手段

SqlCipher,Conceal.

SqlCipher主要是数据库加密,此处与我们的场景对应不上,不考虑

Conceal是Facebook出的,时间也不短了,之前只能引入jar和so文件,现在可以直接gradle依赖了

Conceal使用

build.gradle添加依赖

1
2
3
dependencies {
compile 'com.facebook.conceal:conceal:1.1.3@aar'
}

为了使用方面,我封装成了一个类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
package net.robinx.lib.encrypt.conceal;
import android.content.Context;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import com.facebook.android.crypto.keychain.AndroidConceal;
import com.facebook.android.crypto.keychain.SharedPrefsBackedKeyChain;
import com.facebook.crypto.Crypto;
import com.facebook.crypto.CryptoConfig;
import com.facebook.crypto.Entity;
import com.facebook.crypto.exception.CryptoInitializationException;
import com.facebook.crypto.exception.KeyChainException;
import net.robinx.lib.encrypt.SecretKeyHelper;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
/**
* Created by Robin on 2016/11/16 10:27.
*/
public enum ConcealHelper {
INSTANCE;
private ConcealHelper() {
}
private static final String DEFAULT_ENCODE = "utf-8";
public static final String PREFIX_E = "encrypt_", PREFIX_D = "decrypt_";
private static SharedPrefsBackedKeyChain msp;
private static Crypto mCrypto;
private static Entity mEntity;
public static void init(Context context) {
if (null == mCrypto) {
msp = new SharedPrefsBackedKeyChain(context, CryptoConfig.KEY_256);
mCrypto = AndroidConceal.get().createDefaultCrypto(msp);
String secretKey = SecretKeyHelper.getSecretKey(context);
mEntity = Entity.create(secretKey);
}
}
/**
* 加密字节数组
*
* @param plainBytes 原始字节数组
* @return 密文字节数组
*/
public static byte[] encryptByte(byte[] plainBytes) {
if (!mCrypto.isAvailable()) {
Log.e("system.out", "encryptByte error: mCrypto is unavailable");
return null;
}
if (null == plainBytes || plainBytes.length <= 0) {
Log.e("system.out", "encryptByte error: plainBytes is null or length <= 0");
return null;
}
try {
byte[] result = mCrypto.encrypt(plainBytes, mEntity);
if (null == result || result.length == 0) {
Log.e("system.out", "encryptByte error: result is null or length <= 0");
return null;
}
return result;
} catch (KeyChainException e) {
e.printStackTrace();
} catch (CryptoInitializationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 解密字节数组
*
* @param encryptBytes 密文字节数组
* @return 原始字节数组
*/
public static byte[] decryptByte(byte[] encryptBytes) {
if (!mCrypto.isAvailable()) {
Log.e("system.out", "decryptByte error: mCrypto is unavailable");
return null;
}
if (null == encryptBytes || encryptBytes.length <= 0) {
Log.e("system.out", "decryptByte error: encryptBytes is null or length <= 0");
return null;
}
try {
byte[] result = mCrypto.decrypt(encryptBytes, mEntity);
if (null == result || result.length == 0) {
Log.e("system.out", "decryptByte error: result is null or length <= 0");
return null;
}
return result;
} catch (KeyChainException e) {
e.printStackTrace();
} catch (CryptoInitializationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 加密字符串
*
* @param plainText 原始字符串
* @return 加密后字符串
*/
public static String encryptString(String plainText) {
if (TextUtils.isEmpty(plainText)) {
Log.e("system.out", "encryptString error: plainText is empty");
return null;
}
try {
byte[] plainTextBytes = plainText.getBytes(DEFAULT_ENCODE);
byte[] result = encryptByte(plainTextBytes);
if (null == result || result.length <= 0) {
Log.e("system.out", "encryptString error: encrypt result is null or length <= 0");
return null;
}
String encryptText = Base64.encodeToString(result, Base64.DEFAULT);
return encryptText;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* 解密字符串
* @param encryptText 密文
* @return 原始字符串
*/
public static String decryptString(String encryptText) {
if (TextUtils.isEmpty(encryptText)) {
Log.e("system.out", "decryptString error: encryptText is empty");
return null;
}
byte[] encryptTextBytes = Base64.decode(encryptText, Base64.DEFAULT);
byte[] data = decryptByte(encryptTextBytes);
if (null == data || data.length <= 0) {
Log.e("system.out", "decryptString error: decrypt result is null or length <= 0");
return null;
}
try {
String plainText = new String(data, DEFAULT_ENCODE);
return plainText;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* 加密文件
*
* @param file 源文件
* @return 加密文件,文件名:encrypt_xxx
*/
public static File encryptFile(File file) {
if (!mCrypto.isAvailable()) {
return null;
}
if (null == file) {
return null;
}
String originFilePath = file.getAbsolutePath();
String encryptFilePath = String.format("%s%s%s%s", file.getParent(), File.separator, PREFIX_E, file.getName());
File encryptFile = new File(encryptFilePath);
if (encryptFile.exists()) {
encryptFile.deleteOnExit();
}
try {
FileInputStream sourceFile = new FileInputStream(originFilePath);
OutputStream fileOS = new BufferedOutputStream(new FileOutputStream(encryptFile));
OutputStream out = mCrypto.getCipherOutputStream(fileOS, mEntity);
int read = 0;
byte[] buffer = new byte[1024];
while ((read = sourceFile.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
out.flush();
fileOS.flush();
out.close();
fileOS.close();
sourceFile.close();
return encryptFile;
} catch (IOException e) {
e.printStackTrace();
} catch (CryptoInitializationException e) {
e.printStackTrace();
} catch (KeyChainException e) {
e.printStackTrace();
}
return null;
}
/**
* 解密文件
* @param file 源文件(加密后的)
* @return 解密文件,文件名:decrypt_xxx
*/
public static File decryptFile(File file) {
if (!mCrypto.isAvailable()) {
return null;
}
if (null == file) {
return null;
}
String fileName = file.getName();
fileName = fileName.substring(PREFIX_E.length(), fileName.length());
String originFilePath = file.getAbsolutePath();
String decryptFilePath = String.format("%s%s%s%s", file.getParent(), File.separator, PREFIX_D, fileName);
File decryptFile = new File(decryptFilePath);
if (decryptFile.exists()) {
decryptFile.deleteOnExit();
}
try {
FileInputStream fileInputStream = new FileInputStream(originFilePath);
InputStream inputStream = mCrypto.getCipherInputStream(fileInputStream, mEntity);
OutputStream out = new BufferedOutputStream(new FileOutputStream(decryptFile));
int read = 0;
byte[] buffer = new byte[1024];
while ((read = inputStream.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
out.flush();
out.close();
inputStream.close();
fileInputStream.close();
return decryptFile;
} catch (IOException e) {
e.printStackTrace();
} catch (CryptoInitializationException e) {
e.printStackTrace();
} catch (KeyChainException e) {
e.printStackTrace();
}
return null;
}
}

在项目的Application的onCreate()函数中初始化

1
2
3
4
5
6
7
8
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
ConcealHelper.init(this);
}
}

加密字符串

1
String encryptText = ConcealHelper.encryptString(jsonStr);

解密字符串

1
String originalText = ConcealHelper.decryptString(encryptText);

中间我们还加了一层Base64编码,因为Conceal的加解密都是针对byte[],使用Base64对其编码,转换为字符串

测试发现很长的一串Json,每次加密时间基本在10 ms以内,解密时间与加密差不多,可以说是飞快了。

加密文件

1
2
File originalFile = new File("/sdcard/1.gif");
File encryptFile = ConcealHelper.encryptFile(originalFile);

解密文件

1
File decryptFile = ConcealHelper.decryptFile(encryptFile);

SecretKey

在上面的初始化函数中,有个获取secret的操作

1
String secretKey = SecretKeyHelper.getSecretKey(context);

这个Key是我们的重点,就是我们所说的密钥,实际上就是一串字符串,保存在sd卡不安全,我们可以通过jni,每次从so文件获取,因为相比较而言,so破解少一些,难一点。

创建一个SecretKeyHelper类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package net.robinx.lib.encrypt;
import android.content.Context;
public class SecretKeyHelper {
static {
System.loadLibrary("secretkey");
}
private static String sSecretKeyText;
public static String getSecretKey(Context con){
if (sSecretKeyText ==null) {
sSecretKeyText =createSecretKey(con);
}
return sSecretKeyText;
}
private static native String createSecretKey(Context con);
}

C++实现

创建native方法createSecretKey由C++实现

头文件secretkey.h
1
2
3
4
5
6
7
8
9
10
11
#include <jni.h>
#define UTF_8 "UTF-8"
#ifdef __cplusplus
extern "C" {
jstring Java_net_robinx_lib_encrypt_SecretKeyHelper_createSecretKey(JNIEnv *, jobject,jobject);
}
#endif
cpp文件secretkey.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
#include <string>
#include <stdio.h>
#include "secretkey.h"
#include <android/log.h>
#define LOG_TAG "robin_jni" // 自定义的LOG的标识
#define LOGOPEN 1 //日志开关,1为开,其它为关
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG ,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__)
//char* to jstring
jstring toString(JNIEnv* env, jbyteArray byteArray) {
jclass string_cls = env->FindClass("java/lang/String");
jmethodID new_string_mid = env->GetMethodID(string_cls, "<init>",
"([BLjava/lang/String;)V");
return reinterpret_cast<jstring>(env->NewObject(string_cls, new_string_mid,
byteArray, env->NewStringUTF(UTF_8)));
}
jbyteArray toBytes(JNIEnv* env, const char* bytes) {
jclass string_cls = env->FindClass("java/lang/String");
jmethodID get_bytes_mid = env->GetMethodID(string_cls, "getBytes",
"(Ljava/lang/String;)[B");
return reinterpret_cast<jbyteArray>(env->CallObjectMethod(
env->NewStringUTF(bytes), get_bytes_mid, env->NewStringUTF(UTF_8)));
}
jbyteArray toBytes(JNIEnv* env, jstring string) {
jclass string_cls = env->FindClass("java/lang/String");
jmethodID get_bytes_mid = env->GetMethodID(string_cls, "getBytes",
"(Ljava/lang/String;)[B");
return reinterpret_cast<jbyteArray>(env->CallObjectMethod(string,
get_bytes_mid, env->NewStringUTF(UTF_8)));
}
jbyteArray getDigestedBytes(JNIEnv* env, jbyteArray complex_bytes) {
static jobject satic_message_digest_obj = __null;
jclass message_digest_cls = env->FindClass("java/security/MessageDigest");
jmethodID get_instance_mid = env->GetStaticMethodID(message_digest_cls,
"getInstance", "(Ljava/lang/String;)Ljava/security/MessageDigest;");
if (satic_message_digest_obj == __null) {
jobject local_message_digest_obj = env->CallStaticObjectMethod(
message_digest_cls, get_instance_mid, env->NewStringUTF("MD5"));
satic_message_digest_obj = env->NewGlobalRef(local_message_digest_obj);
env->DeleteLocalRef(local_message_digest_obj);
}
jmethodID digest_mid = env->GetMethodID(message_digest_cls, "digest",
"([B)[B");
env->DeleteLocalRef(message_digest_cls);
return reinterpret_cast<jbyteArray>(env->CallObjectMethod(
satic_message_digest_obj, digest_mid, complex_bytes));
}
jstring toHex(JNIEnv* env, jbyteArray digested_bytes) {
jclass big_integer_cls = env->FindClass("java/math/BigInteger");
jmethodID new_big_integer_mid = env->GetMethodID(big_integer_cls, "<init>",
"(I[B)V");
jobject big_integer_obj = env->NewObject(big_integer_cls,
new_big_integer_mid, 1, digested_bytes);
env->DeleteLocalRef(digested_bytes);
jmethodID to_String_mid = env->GetMethodID(big_integer_cls, "toString",
"(I)Ljava/lang/String;");
env->DeleteLocalRef(big_integer_cls);
return reinterpret_cast<jstring>(env->CallObjectMethod(big_integer_obj,
to_String_mid, 16));
}
jstring getMD5(JNIEnv* env, jstring jInfo) {
jbyteArray digested_bytes = getDigestedBytes(env, toBytes(env, jInfo));
return toHex(env, digested_bytes);
}
jstring getAppendedString(JNIEnv* env, jobject thiz, jstring s1, jstring s2) {
const char *s1x = (env)->GetStringUTFChars(s1, NULL);
const char *s2x = (env)->GetStringUTFChars(s2, NULL);
char *sall = new char[strlen(s1x) + strlen(s2x) + 1];
strcpy(sall, s1x);
strcat(sall, s2x);
jstring retval = (env)->NewStringUTF(sall);
(env)->ReleaseStringUTFChars(s1, s1x);
(env)->ReleaseStringUTFChars(s2, s2x);
free(sall);
return retval;
}
jobject getInstance(JNIEnv* env, jclass obj_class) {
jmethodID construction_id = env->GetMethodID(obj_class, "<init>", "()V");
jobject obj = env->NewObject(obj_class, construction_id);
return obj;
}
//获取deviceid
jstring getDeviceID(JNIEnv *env, jobject thiz, jobject mContext) {
jclass cls_context = (env)->FindClass("android/content/Context");
if (cls_context == 0) {
return (env)->NewStringUTF("unknown");
}
jmethodID getSystemService = (env)->GetMethodID(cls_context,
"getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
if (getSystemService == 0) {
return (env)->NewStringUTF("unknown");
}
jfieldID TELEPHONY_SERVICE = (env)->GetStaticFieldID(cls_context,
"TELEPHONY_SERVICE", "Ljava/lang/String;");
if (TELEPHONY_SERVICE == 0) {
return (env)->NewStringUTF("unknown");
}
jobject str = (env)->GetStaticObjectField(cls_context, TELEPHONY_SERVICE);
jobject telephonymanager = (env)->CallObjectMethod(mContext,
getSystemService, str);
if (telephonymanager == 0) {
return (env)->NewStringUTF("unknown");
}
jclass cls_tm = (env)->FindClass("android/telephony/TelephonyManager");
if (cls_tm == 0) {
return (env)->NewStringUTF("unknown");
}
jmethodID getDeviceId = (env)->GetMethodID(cls_tm, "getDeviceId",
"()Ljava/lang/String;");
if (getDeviceId == 0) {
return (env)->NewStringUTF("unknown");
}
jobject deviceid = (env)->CallObjectMethod(telephonymanager, getDeviceId);
return (jstring) deviceid;
}
//获取SerialNumber
jstring getSerialNumber(JNIEnv *env, jobject thiz, jobject mContext) {
jclass cls_tm = (env)->FindClass("android/os/SystemProperties");
if (cls_tm == 0) {
return (env)->NewStringUTF("unknown");
}
jmethodID getDeviceId = (env)->GetStaticMethodID(cls_tm, "get",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
if (getDeviceId == 0) {
return (env)->NewStringUTF("unknown");
}
jstring param1 = (env)->NewStringUTF("ro.serialno");
jstring param2 = (env)->NewStringUTF("unknown");
jobject deviceid = (env)->CallStaticObjectMethod(cls_tm, getDeviceId,
param1, param2);
return (jstring) deviceid;
}
jstring jint2jstring(JNIEnv *env, jint first) {
char buf[64]; // assumed large enough to cope with result
sprintf(buf, "%d", first); // error checking omitted
return env->NewStringUTF( buf);
}
//获取公钥
jstring getPublicKey(JNIEnv* env, jobject thiz,jobject context) {
jclass context_cls = env->GetObjectClass(context);
jmethodID get_package_manager_mid = env->GetMethodID(context_cls,
"getPackageManager", "()Landroid/content/pm/PackageManager;");
jmethodID get_package_name_mid = env->GetMethodID(context_cls,
"getPackageName", "()Ljava/lang/String;");
env->DeleteLocalRef(context_cls);
jobject pm_obj = env->CallObjectMethod(context, get_package_manager_mid);
jclass pm_cls = env->FindClass("android/content/pm/PackageManager");
jmethodID get_package_info_mid = env->GetMethodID(pm_cls, "getPackageInfo",
"(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
jstring package_name = reinterpret_cast<jstring>(env->CallObjectMethod(
context, get_package_name_mid));
jfieldID flag_fid = env->GetStaticFieldID(pm_cls, "GET_SIGNATURES", "I");
jint flag = env->GetStaticIntField(pm_cls, flag_fid);
env->DeleteLocalRef(pm_cls);
jobject pi_obj = env->CallObjectMethod(pm_obj, get_package_info_mid,
package_name, flag);
env->DeleteLocalRef(package_name);
jclass pi_cls = env->FindClass("android/content/pm/PackageInfo");
jfieldID signatures_fid = env->GetFieldID(pi_cls, "signatures",
"[Landroid/content/pm/Signature;");
env->DeleteLocalRef(pi_cls);
jobject sig_obj = env->GetObjectField(pi_obj, signatures_fid);
env->DeleteLocalRef(pi_obj);
jobjectArray sigs = reinterpret_cast<jobjectArray>(sig_obj);
jclass signature_cls = env->FindClass("android/content/pm/Signature");
jmethodID to_byte_array_mid = env->GetMethodID(signature_cls, "toByteArray",
"()[B");
jbyteArray sig_bytes = reinterpret_cast<jbyteArray>(env->CallObjectMethod(
env->GetObjectArrayElement(sigs, 0), to_byte_array_mid));
jclass certificate_factory_cls = env->FindClass(
"java/security/cert/CertificateFactory");
jmethodID get_certificate_instance_mid = env->GetStaticMethodID(
certificate_factory_cls, "getInstance",
"(Ljava/lang/String;)Ljava/security/cert/CertificateFactory;");
jobject certificate_factory_obj = env->CallStaticObjectMethod(
certificate_factory_cls, get_certificate_instance_mid,
env->NewStringUTF("X509"));
jmethodID generate_certificate_mid = env->GetMethodID(
certificate_factory_cls, "generateCertificate",
"(Ljava/io/InputStream;)Ljava/security/cert/Certificate;");
env->DeleteLocalRef(certificate_factory_cls);
jclass certificate_cls = env->FindClass("java/security/cert/Certificate");
jclass byte_input_stream_cls = env->FindClass(
"java/io/ByteArrayInputStream");
jmethodID new_sig_bytes_is_mid = env->GetMethodID(byte_input_stream_cls,
"<init>", "([B)V");
jobject sig_bytes_is = env->NewObject(byte_input_stream_cls,
new_sig_bytes_is_mid, sig_bytes);
env->DeleteLocalRef(sig_bytes);
env->DeleteLocalRef(byte_input_stream_cls);
jobject cert = env->CallObjectMethod(certificate_factory_obj,
generate_certificate_mid, sig_bytes_is);
env->DeleteLocalRef(sig_bytes_is);
env->DeleteLocalRef(certificate_factory_obj);
jmethodID get_pubic_key_mid = env->GetMethodID(certificate_cls,
"getPublicKey", "()Ljava/security/PublicKey;");
env->DeleteLocalRef(certificate_cls);
jobject publicKey = env->CallObjectMethod(cert, get_pubic_key_mid);
jclass publicKey_cls = env->GetObjectClass(publicKey);
jmethodID toString_mid = env->GetMethodID(publicKey_cls,"toString", "()Ljava/lang/String;");
jstring publicKey_str = static_cast<jstring>(env->CallObjectMethod(publicKey,toString_mid));
env->DeleteLocalRef(cert);
env->DeleteLocalRef(publicKey_cls);
env->DeleteLocalRef(publicKey);
jclass string_cls = env->GetObjectClass(publicKey_str);
jmethodID indexOf_mid = env->GetMethodID(string_cls,"indexOf", "(Ljava/lang/String;)I");
jstring param = env->NewStringUTF("modulus");
jint aa = env->CallIntMethod(publicKey_str,indexOf_mid,param);
jstring param2 = env->NewStringUTF("publicExponent");
jint bb = env->CallIntMethod(publicKey_str,indexOf_mid,param2);
jmethodID substring_mid = env->GetMethodID(string_cls,"substring", "(II)Ljava/lang/String;");
jstring publicKey2_str = static_cast<jstring>(env->CallObjectMethod(publicKey_str,substring_mid,aa+8,bb-1));
return publicKey2_str;
}
//获取签名
jstring getSignatures(JNIEnv* env, jobject thizz,
jobject thiz) {
jclass native_clazz = env->GetObjectClass(thiz);
// 得到 getPackageManager 方法的 ID
jmethodID methodID_func = env->GetMethodID(native_clazz,
"getPackageManager", "()Landroid/content/pm/PackageManager;");
// 获得应用包的管理器
jobject package_manager = env->CallObjectMethod(thiz, methodID_func);
// 获得 PackageManager 类
jclass pm_clazz = env->GetObjectClass(package_manager);
// 得到 getPackageInfo 方法的 ID
jmethodID methodID_pm = env->GetMethodID(pm_clazz, "getPackageInfo",
"(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
//获取包名
jmethodID methodID_packagename = env->GetMethodID(native_clazz,
"getPackageName", "()Ljava/lang/String;");
jstring name_str = static_cast<jstring>(env->CallObjectMethod(thiz,
methodID_packagename));
// 获得应用包的信息
jobject package_info = env->CallObjectMethod(package_manager, methodID_pm,
name_str, 64); //env->NewStringUTF("com.example.contasdf")
// 获得 PackageInfo 类
jclass pi_clazz = env->GetObjectClass(package_info);
// 获得签名数组属性的 ID
jfieldID fieldID_signatures = env->GetFieldID(pi_clazz, "signatures",
"[Landroid/content/pm/Signature;");
// 得到签名数组,待修改
jobject signatur = env->GetObjectField(package_info, fieldID_signatures);
jobjectArray signatures = reinterpret_cast<jobjectArray>(signatur);
// 得到签名
jobject signature = env->GetObjectArrayElement(signatures, 0);
// 获得 Signature 类,待修改
jclass s_clazz = env->GetObjectClass(signature);
// 得到 hashCode 方法的 ID
jmethodID methodID_hc = env->GetMethodID(s_clazz, "hashCode", "()I");
// 获得应用包的管理器,待修改
int hash_code = env->CallIntMethod(signature, methodID_hc);
char str[100];
sprintf(str, "%u", hash_code);
jstring sign = env->NewStringUTF(str);
return sign;
}
jstring getPackageName(JNIEnv* env, jobject thizz,jobject thiz) {
jclass native_clazz = env->GetObjectClass(thiz);
// 得到 getPackageManager 方法的 ID
jmethodID methodID_func = env->GetMethodID(native_clazz,
"getPackageManager", "()Landroid/content/pm/PackageManager;");
// 获得应用包的管理器
jobject package_manager = env->CallObjectMethod(thiz, methodID_func);
// 获得 PackageManager 类
jclass pm_clazz = env->GetObjectClass(package_manager);
// 得到 getPackageInfo 方法的 ID
jmethodID methodID_pm = env->GetMethodID(pm_clazz, "getPackageInfo",
"(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
//获取包名
jmethodID methodID_packagename = env->GetMethodID(native_clazz,
"getPackageName", "()Ljava/lang/String;");
jstring name_str = static_cast<jstring>(env->CallObjectMethod(thiz,
methodID_packagename));
return name_str;
}
char* jstringTostring(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
}
jstring Java_net_robinx_lib_encrypt_SecretKeyHelper_createSecretKey(JNIEnv* env, jobject thizz,
jobject thiz) {
jstring imei = getAppendedString(env, thizz, getDeviceID(env, thizz, thiz),getSerialNumber(env, thizz, thiz));
if (LOGOPEN == 1){
LOGD("imei = %s",jstringTostring(env,imei));
}
jstring sign = getPublicKey(env, thizz, thiz);
if (LOGOPEN == 1){
LOGD("sign = %s",jstringTostring(env,sign));
}
jstring imei_sign = getAppendedString(env, thizz, imei, sign);
if (LOGOPEN == 1){
LOGD("imei_sign = %s",jstringTostring(env,imei_sign));
}
jstring package = getPackageName(env, thizz, thiz);
if (LOGOPEN == 1){
LOGD("package = %s",jstringTostring(env,package));
}
jstring imei_sign_package = getAppendedString(env, thizz, imei_sign,package);
if (LOGOPEN == 1){
LOGD("imei_sign_package = %s",jstringTostring(env,imei_sign_package));
}
imei_sign_package = getAppendedString(env, thizz, imei_sign_package, imei);
if (LOGOPEN == 1){
LOGD("imei_sign_package2 = %s",jstringTostring(env,imei_sign_package));
}
imei_sign_package = getAppendedString(env, thizz, imei_sign_package, sign);
if (LOGOPEN == 1){
LOGD("imei_sign_package3 = %s",jstringTostring(env,imei_sign_package));
}
jstring secretKey = getMD5(env, imei_sign_package);
if (LOGOPEN == 1){
LOGD("secretKey = %s",jstringTostring(env,secretKey));
}
return secretKey;
}
Application.mk文件
1
2
3
4
5
APP_STL := stlport_static
APP_ABI := all
APP_PLATFORM:= android-22
APP_OPTIM := release
Android.mk文件
1
2
3
4
5
6
7
8
9
10
11
LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:=secretkey
LOCAL_SRC_FILES:=secretkey.cpp secretkey.h
LOCAL_LDLIBS :=-llog
include $(BUILD_SHARED_LIBRARY)

最终返回imei(手机IMEI)+sign(签名)+package(包名)+imei(手机IMEI)+sign(签名)的MD5结果,你可以修改cpp末尾位置,自己组合,穿插添加其他的字符串
做到唯一性

这样整个加密流程就完毕了,用起来很方便

代码获取

https://github.com/robinxdroid/Encrypt

转载请指明出处RobinBlog:http://robinx.net/2016/11/30/加密你的App/