Android中的AES加密解密技术

最近需要在项目中加密数据,首先想到要使用到AES加密技术。在网上找了很多,都是适合Java工程,在Android上无法正常达到预期的解密。花了两天的时间终于找到了可以在Android上顺利实现加密解密的代码,在这里有必要的记录一下。

简介

对于AES的概念,以下摘自维基百科,它是这样解释的:

高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。

其余的就不多说了,以下直接进入主题 …

Android中的用法

以下示例是基于Android的,Java不通用

工具类

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
package com.wt.aes;


import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
* Created by shoewann on 16-9-23.
*/

public class AESUtils {

public static String encrypt(String seed, String cleartext) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}

public static String decrypt(String seed, String encrypted) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}


private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
sr.setSeed(seed);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}


private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}


private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}


private static String toHex(String txt) {
return toHex(txt.getBytes());
}

private static String fromHex(String hex) {
return new String(toByte(hex));
}

private static byte[] toByte(String hexString) {
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();
return result;
}


private static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2 * buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}

private final static String HEX = "0123456789ABCDEF";

private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
}
}

示例调用

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
package com.wt.aes;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

/**
* Created by shoewann on 16-9-23.
*/
public class MainActivity extends AppCompatActivity {

private static final String TAG = "MainActivity";

String content="我是需要加密的数据内容";
String key="com.sina.com";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
Log.d(TAG,"加密前:"+content);
//encrypt (加密)
String encrypt = AESUtils.encrypt(key, content);
Log.d(TAG,"加密后:"+encrypt);
//decrypt (解密)
String decrypt = AESUtils.decrypt(key, encrypt);
Log.d(TAG,"解密后:"+decrypt);
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG,"ERROR:"+e.getMessage());
}
}
}

运行结果,如果是这样:

aes_success.png

根据以上log信息可以看出,数据能在设备上成功被加密和解密出来,说明你当前的调试设备版本在Android 7.0(API 24)以下,你依然可以使用以上的方式来加密解密。

Android N 已弃用Crypto

  • 如果你在Android系统版本是7.0的设备上运行以上代码,结果是这样的:

aes_7.0_error

根据以上的log信息可以看出,在Android 7.0 新版本 Android SDK 不再支持 Crypto,至于详细可以访问http://android-developers.blogspot.com/2016/06/security-crypto-provider-deprecated-in.html
或者
查看之前我翻译提交的这篇文章

以下是,修改过后的工具类:

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
package com.wt.aes;


import java.nio.charset.StandardCharsets;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
* Created by shoewann on 16-9-23.
*/

public class AESUtils {

public static String encrypt(String seed, String cleartext) throws Exception {
byte[] rawKey = deriveKeyInsecurely(seed,32).getEncoded();
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}

public static String decrypt(String seed, String encrypted) throws Exception {
byte[] rawKey = deriveKeyInsecurely(seed,32).getEncoded();
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}

private static SecretKey deriveKeyInsecurely(String password, int
keySizeInBytes) {
byte[] passwordBytes = password.getBytes(StandardCharsets.US_ASCII);
return new SecretKeySpec(
InsecureSHA1PRNGKeyDerivator.deriveInsecureKey(
passwordBytes, keySizeInBytes),
"AES");
}

private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}


private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()]));
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}


private static String toHex(String txt) {
return toHex(txt.getBytes());
}

private static String fromHex(String hex) {
return new String(toByte(hex));
}

private static byte[] toByte(String hexString) {
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();
return result;
}


private static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2 * buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}

private final static String HEX = "0123456789ABCDEF";

private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
}
}

以上的工具类中InsecureSHA1PRNGKeyDerivator这个类,可以在示例代码里找到

通过再次调用以上的工具类中的加密解密的方法,就可以在Android 7.0上成功加密解密出数据:

aes_7.0_success.png

以上是对Anroid 中使用AES及在7.0上使用相关问题,原创不易,如果不足,欢迎指正,谢谢。

0%