移动端越来越火了,我们在开发过程中,总会碰到要和移动端打交道的场景,比如.NET和android或者iOS的打交道。为了让数据交互更安全,我们需要对数据进行加密传输。今天研究了一下,把几种语言的加密都实践了一遍,实现了.NET,java(android),iOS都同一套的加密算法,下面就分享给大家。
AES加密有多种算法模式,下面提供两套模式的可用源码。
加密方式:
- 先将文本AES加密
- 返回Base64转码
解密方式:
- 将数据进行Base64解码
- 进行AES解密
一、CBC(Cipher Block Chaining,加密块链)模式
是一种循环模式,前一个分组的密文和当前分组的明文异或操作后再加密,这样做的目的是增强破解难度.
- 密钥
- 密钥偏移量
java加密AESOperator类:
1 package com.bci.wx.base.util;
2
3 import javax.crypto.Cipher;
4 import javax.crypto.spec.IvParameterSpec;
5 import javax.crypto.spec.SecretKeySpec;
6
7 import sun.misc.BASE64Decoder;
8 import sun.misc.BASE64Encoder;
9
10
11 /**
12 * AES 是一种可逆加密算法,对用户的敏感信息加密处理 对原始数据进行AES加密后,在进行Base64编码转化;
13 */
14 public class AESOperator {
15
16 /*
17 * 加密用的Key 可以用26个字母和数字组成 此处使用AES-128-CBC加密模式,key需要为16位。
18 */
19 private String sKey = "smkldospdosldaaa";//key,可自行修改
20 private String ivParameter = "0392039203920300";//偏移量,可自行修改
21 private static AESOperator instance = null;
22
23 private AESOperator() {
24
25 }
26
27 public static AESOperator getInstance() {
28 if (instance == null)
29 instance = new AESOperator();
30 return instance;
31 }
32
33 public static String Encrypt(String encData ,String secretKey,String vector) throws Exception {
34
35 if(secretKey == null) {
36 return null;
37 }
38 if(secretKey.length() != 16) {
39 return null;
40 }
41 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
42 byte[] raw = secretKey.getBytes();
43 SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
44 IvParameterSpec iv = new IvParameterSpec(vector.getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
45 cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
46 byte[] encrypted = cipher.doFinal(encData.getBytes("utf-8"));
47 return new BASE64Encoder().encode(encrypted);// 此处使用BASE64做转码。
48 }
49
50
51 // 加密
52 public String encrypt(String sSrc) throws Exception {
53 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
54 byte[] raw = sKey.getBytes();
55 SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
56 IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
57 cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
58 byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));
59 return new BASE64Encoder().encode(encrypted);// 此处使用BASE64做转码。
60 }
61
62 // 解密
63 public String decrypt(String sSrc) throws Exception {
64 try {
65 byte[] raw = sKey.getBytes("ASCII");
66 SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
67 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
68 IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());
69 cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
70 byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);// 先用base64解密
71 byte[] original = cipher.doFinal(encrypted1);
72 String originalString = new String(original, "utf-8");
73 return originalString;
74 } catch (Exception ex) {
75 return null;
76 }
77 }
78
79 public String decrypt(String sSrc,String key,String ivs) throws Exception {
80 try {
81 byte[] raw = key.getBytes("ASCII");
82 SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
83 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
84 IvParameterSpec iv = new IvParameterSpec(ivs.getBytes());
85 cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
86 byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);// 先用base64解密
87 byte[] original = cipher.doFinal(encrypted1);
88 String originalString = new String(original, "utf-8");
89 return originalString;
90 } catch (Exception ex) {
91 return null;
92 }
93 }
94
95 public static String encodeBytes(byte[] bytes) {
96 StringBuffer strBuf = new StringBuffer();
97
98 for (int i = 0; i < bytes.length; i++) {
99 strBuf.append((char) (((bytes[i] >> 4) & 0xF) + ((int) 'a')));
100 strBuf.append((char) (((bytes[i]) & 0xF) + ((int) 'a')));
101 }
102
103 return strBuf.toString();
104 }
105
106 public static void main(String[] args) throws Exception {
107 // 需要加密的字串
108 String cSrc = "[{\"request_no\":\"1001\",\"service_code\":\"FS0001\",\"contract_id\":\"100002\",\"order_id\":\"0\",\"phone_id\":\"13913996922\",\"plat_offer_id\":\"100094\",\"channel_id\":\"1\",\"activity_id\":\"100045\"}]";
109
110 // 加密
111 long lStart = System.currentTimeMillis();
112 String enString = AESOperator.getInstance().encrypt(cSrc);
113 System.out.println("加密后的字串是:" + enString);
114
115 long lUseTime = System.currentTimeMillis() - lStart;
116 System.out.println("加密耗时:" + lUseTime + "毫秒");
117 // 解密
118 lStart = System.currentTimeMillis();
119 String DeString = AESOperator.getInstance().decrypt(enString);
120 System.out.println("解密后的字串是:" + DeString);
121 lUseTime = System.currentTimeMillis() - lStart;
122 System.out.println("解密耗时:" + lUseTime + "毫秒");
123 }
124
125 }
Android加密AESOperator类:(以下红色部分是JAVA和安卓代码不同的地方,安卓代码里面和IOS,c#结果一样的加密/解密方法是Encrypt64/Decrypt64)
1 package com.example.demo2;
2
3 import javax.crypto.Cipher;
4 import javax.crypto.spec.IvParameterSpec;
5 import javax.crypto.spec.SecretKeySpec;
6
7 import android.util.Base64;
8
9 public class AESEncrypto {
10 public static byte[] _key = { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97,
11 98, 99, 100, 101, 102 };// 初始化矩阵
12 public static String ivParameter="0392039203920300";
13 // 加密
14 public static String Encrypt64(String sSrc, String sKey) throws Exception {
15 if (sKey == null) {
16 System.out.print("Key为空null");
17 return null;
18 }
19 // 判断Key是否为16位
20 if (sKey.length() != 16) {
21 System.out.print("Key长度不是16位");
22 return null;
23 }
24 byte[] raw = sKey.getBytes();
25 SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
26 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");// "算法/模式/补码方式"
27 IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
28 cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
29 byte[] encrypted = cipher.doFinal(sSrc.getBytes());
30
31 return Base64.encodeToString(encrypted, 0);// 此处使用BASE64做转码功能,同时能起到2次加密的作用。
32 }
33
34 // 解密
35 public static String Decrypt64(String sSrc, String sKey) throws Exception {
36 try {
37 // 判断Key是否正确
38 if (sKey == null) {
39 System.out.print("Key为空null");
40 return null;
41 }
42 // 判断Key是否为16位
43 if (sKey.length() != 16) {
44 System.out.print("Key长度不是16位");
45 return null;
46 }
47 byte[] raw = sKey.getBytes("ASCII");
48 SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
49 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
50 IvParameterSpec iv = new IvParameterSpec(
51 ivParameter.getBytes());
52 cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
53 byte[] encrypted1 = Base64.decode(sSrc, 0);// 先用base64解密
54 try {
55 byte[] original = cipher.doFinal(encrypted1);
56 String originalString = new String(original);
57 return originalString;
58 } catch (Exception e) {
59 System.out.println(e.toString());
60 return null;
61 }
62 } catch (Exception ex) {
63 System.out.println(ex.toString());
64 return null;
65 }
66 }
67
68 public static String Encrypt(String sSrc, String sKey) throws Exception {
69 if (sKey == null) {
70 System.out.print("Key为空null");
71 return null;
72 }
73 // 判断Key是否为16位
74 if (sKey.length() != 16) {
75 System.out.print("Key长度不是16位");
76 return null;
77 }
78 byte[] raw = sKey.getBytes();
79 SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
80 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
81 IvParameterSpec iv = new IvParameterSpec(_key);
82 cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
83 byte[] encrypted = cipher.doFinal(sSrc.getBytes());
84
85 return byte2hex(encrypted).toLowerCase();
86 }
87
88 public static String Decrypt(String sSrc, String sKey) throws Exception {
89 try {
90 // 判断Key是否正确
91 if (sKey == null) {
92 System.out.print("Key为空null");
93 return null;
94 }
95 // 判断Key是否为16位
96 if (sKey.length() != 16) {
97 System.out.print("Key长度不是16位");
98 return null;
99 }
100 byte[] raw = sKey.getBytes("ASCII");
101 SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
102 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
103 IvParameterSpec iv = new IvParameterSpec(_key);
104 cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
105 byte[] encrypted1 = hex2byte(sSrc);
106 try {
107 byte[] original = cipher.doFinal(encrypted1);
108 String originalString = new String(original);
109 return originalString;
110 } catch (Exception e) {
111 System.out.println(e.toString());
112 return null;
113 }
114 } catch (Exception ex) {
115 System.out.println(ex.toString());
116 return null;
117 }
118 }
119
120 public static byte[] hex2byte(String strhex) {
121 if (strhex == null) {
122 return null;
123 }
124 int l = strhex.length();
125 if (l % 2 == 1) {
126 return null;
127 }
128 byte[] b = new byte[l / 2];
129 for (int i = 0; i != l / 2; i++) {
130 b[i] = (byte) Integer.parseInt(strhex.substring(i * 2, i * 2 + 2),
131 16);
132 }
133 return b;
134 }
135
136 public static String byte2hex(byte[] b) {
137 String hs = "";
138 String stmp = "";
139 for (int n = 0; n < b.length; n++) {
140 stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
141 if (stmp.length() == 1) {
142 hs = hs + "0" + stmp;
143 } else {
144 hs = hs + stmp;
145 }
146 }
147 return hs.toUpperCase();
148 }
149
150 }
.NET AES加密解密:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Security.Cryptography;
5 using System.Text;
6 using System.Threading.Tasks;
7
8 namespace AES_Dome
9 {
10 class Program
11 {
12 private static string key = "smkldospdosldaaa";//key,可自行修改
13 private static string iv = "0392039203920300"; //偏移量,可自行修改
14 static void Main(string[] args)
15 {
16 string encrytpData = Encrypt("abc", key, iv);
17 Console.WriteLine(encrytpData);
18
19 string decryptData = Decrypt("5z9WEequVr7qtd+WoxV+Kw==", key, iv);
20 Console.WriteLine(decryptData);
21
22 Console.ReadLine();
23 }
24 public static string Encrypt(string toEncrypt, string key, string iv)
25 {
26 byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
27 byte[] ivArray = UTF8Encoding.UTF8.GetBytes(iv);
28 byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
29
30 RijndaelManaged rDel = new RijndaelManaged();
31 rDel.BlockSize = 128;
32 rDel.KeySize = 256;
33 rDel.FeedbackSize = 128;
34 rDel.Padding = PaddingMode.PKCS7;
35 rDel.Key = keyArray;
36 rDel.IV = ivArray;
37 rDel.Mode = CipherMode.CBC;
38
39 ICryptoTransform cTransform = rDel.CreateEncryptor();
40 byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
41
42 return Convert.ToBase64String(resultArray, 0, resultArray.Length);
43 }
44
45 public static string Decrypt(string toDecrypt, string key, string iv)
46 {
47 byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
48 byte[] ivArray = UTF8Encoding.UTF8.GetBytes(iv);
49 byte[] toEncryptArray = Convert.FromBase64String(toDecrypt);
50
51 // 这里的模式,请保持和上面加密的一样。但源代码里,这个地方并没有修正,虽然也能正确解密。看到博客的朋友,请自行修改。
52 // 这是个人疏忽的地址,感谢@jojoka 的提醒。
53 RijndaelManaged rDel = new RijndaelManaged();
54 //rDel.Key = keyArray;
55 //rDel.IV = ivArray;
56 //rDel.Mode = CipherMode.CBC;
57 //rDel.Padding = PaddingMode.Zeros;
58
59 rDel.BlockSize = 128;
60 rDel.KeySize = 256;
61 rDel.FeedbackSize = 128;
62 rDel.Padding = PaddingMode.PKCS7;
63 rDel.Key = keyArray;
64 rDel.IV = ivArray;
65 rDel.Mode = CipherMode.CBC;
66 ICryptoTransform cTransform = rDel.CreateDecryptor();
67
68 byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
69
70 return UTF8Encoding.UTF8.GetString(resultArray);
71 }
72 }
73 }
二、ECB(Electronic Code Book,电子密码本)模式
是一种基础的加密方式,密文被分割成分组长度相等的块(不足补齐),然后单独一个个加密,一个个输出组成密文。
只需要提供密码即可。