转载请注明出处:https://blog.csdn.net/u011038298/article/details/87921272
1.程序主类
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.EditText;
/**
* 实现方案/思路:
* Android端的加密需要4步:
* 1.随机生成AES密钥
* 2.根据AES秘钥对数据进行加密
* 3.使用RSA公钥加密刚刚生成的AES密钥
* 4.将AES加密过的数据 和 被RSA加密过的AES秘钥 传给服务端
* <p>
* 服务端的解密只需3步:
* 1.获取到客户端传过来的数据
* 2.使用RSA私钥解密从客户端拿到的“被RSA加密过的AES秘钥”
* 3.再使用解密出来的AES秘钥来解密被AES加密过的数据
* <p>
* 这里需要理解的地方:
* 1.RSA是公开秘钥系统的代表,可以通过OpenSSL生成RSA证书,拿到公钥和私钥。
* 2.RSA的公钥用来加密,私钥用来解密。可以这样理解:客户端锁了门,钥匙在服务端那里。
* 3.RSA加/解密速度慢,不适合大量的数据进行加/解密,它是不对称加密方式。
* 4.AES加密速度很快,它是对称密码方式,即加密和解密使用同一个密钥的加密方式。
* <p>
* 理解了以上之后,我们就很容易想到使用RSA+AES相结合的方式,发挥它们共同的优点来实现一种新的数据加密方案
*/
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/**
* 账号密码的输入框
*/
EditText etId = findViewById(R.id.etId);
EditText etPassword = findViewById(R.id.etPassword);
etId.setText("admin");
etPassword.setText("test123456");
// 客户端加密
clientEncryption(etId.getText().toString(), etPassword.getText().toString());
}
/**
* 客户端加密账号和密码,并传值给服务端
* id:账号
* password:密码
*/
private void clientEncryption(String id, String password) {
/**
* 客户端随机生成一个AES秘钥
*/
String key = AESUtils.getRandomKey();
/**
* 经过客户端加密过后的:账号和密码字符串
*/
String encryptId = AESUtils.encrypt(id, key);
String encryptPassword = AESUtils.encrypt(password, key);
/**
* 根据RSA的公钥,先对随机产生的AES秘钥进行加密
*/
String encryptKey = "";
try {
encryptKey = RSAUtils.encryptByPublicKey(key, RSAUtils.loadPublicKey(RSAUtils.rsa_public_key));
} catch (Exception e) {
e.printStackTrace();
}
// 传值给服务端,并且服务端进行解密
serverDecryption(encryptId, encryptPassword, encryptKey);
}
/**
* 服务端解密来自客户端的账号和密码
* encryptId:加密过的账号
* encryptPassword:加密过的密码
* encryptKey:加密过的AES密钥
*/
private void serverDecryption(String encryptId, String encryptPassword, String encryptKey) {
/**
* 根据RSA的私钥进行解密,拿到AES的秘钥
*/
String decryptKey = "";
try {
decryptKey = RSAUtils.decryptByPrivateKey(encryptKey, RSAUtils.loadPrivateKey(RSAUtils.private_key));
} catch (Exception e) {
e.printStackTrace();
}
/**
* 根据AES秘钥对账号和密码进行AES解密,拿到原文
*/
String decryptId = AESUtils.decrypt(encryptId, decryptKey);
String decryptPassword = AESUtils.decrypt(encryptPassword, decryptKey);
Log.i("TAG", "服务端解密出来的数据,账号:" + decryptId + " 密码:" + decryptPassword);
}
}
2.RSA加/解密的工具类
import android.util.Base64;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
public class RSAUtils {
// 使用OpenSSL生成的RSA私钥 (存放于服务端)
public final static String private_key = "MIICXQIBAAKBgQDOwViN4uF/aPIBxwzKytEGiYhQA19srihpYfqPFQSiTGR2N0Hp" +
"igwanfKNk33cyHTBIcAUUnDiScHXptC8RoSgIS7O9iDUzN/TOV1DkDIzuQ8ySpG1" +
"n/4fospFKrNs+j5cXbm8sMMDG9GvnI9svi3wW1+pnrFvXWXjxi0oZ+lkHwIDAQAB" +
"AoGAaK6gRYagIcBi999ubKbv2l18NPbgM8iiEWlYUWWU6Q/AtdIYf0Q0CK38Bw6s" +
"ZULhSn/qHt/247vwd12wxgL2Vqw9JlGVfESMXbOq4juHEXqNdDgC/H/Tx771uLgp" +
"dEIEjVHyXwfbuVd16GKP205FisJP5+Rr13IzkdAYz1WdKOECQQDnQrAqHmrNICOB" +
"DwsF37gnx+gCVhbj+FB0m/y+p6eG0x1VZwcYSf+lH8ac6ktQBOQK2JL5NTOb4arc" +
"oMVyIPY3AkEA5N+OUdX2EqFZV53Ha1/56WRufDUaySq8mM567O6PGEhlFESw+vEE" +
"651AIOUax2qqBrh6feTRwEoorrVzSCUNWQJAHaCBiSPUcusHIWWX9+ytXwtRQdtd" +
"m18Yj5fcTWCVKcSqIWLNmeMBCVqEy12IwHuf63PLgHm8XuAOT62ZHgHzCQJBAMVK" +
"6PYmiL66k7dxbSxkSZwlVRCA/pwW2QioRVLkujlmfqugIyfOiD1LCrLQi+sHSZYN" +
"hJntm9o0kyk3hS7VsdECQQClqdqDmCY0LXGLl4LChtsWvieHhy2QE81kd6zxb5MB" +
"U/387n/UfGD448/nJ19dmDeq+XNIb1nK9cOMvTPb1OYA";
// 使用OpenSSL生成的RSA公钥 (存放于客户端)
public final static String rsa_public_key = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOwViN4uF/aPIBxwzKytEGiYhQ" +
"A19srihpYfqPFQSiTGR2N0HpigwanfKNk33cyHTBIcAUUnDiScHXptC8RoSgIS7O" +
"9iDUzN/TOV1DkDIzuQ8ySpG1n/4fospFKrNs+j5cXbm8sMMDG9GvnI9svi3wW1+p" +
"nrFvXWXjxi0oZ+lkHwIDAQAB";
/**
* 通过公钥加密
*
* @param data
* @param publicKey
* @return
* @throws Exception
*/
public static String encryptByPublicKey(String data, RSAPublicKey publicKey)
throws Exception {
// 模长
int key_len = publicKey.getModulus().bitLength() / 8;
// 加密数据长度 <= 模长-11
String[] array = splitString(data, key_len - 11);
String mi = "";
// 如果明文长度大于模长-11则要分组加密
for (String s : array) {
mi += bcd2Str(encryptByPublicKey(s.getBytes(), publicKey));
}
return mi;
}
/**********************************************************************************************/
private static final String ALGORITHM = "RSA";
private static final String TRANSFORMATION = "RSA";
/**
* 从文件中输入流中加载公钥
*
* @param in 公钥输入流
* @throws Exception 加载公钥时产生的异常
*/
public static RSAPublicKey loadPublicKey(InputStream in) throws Exception {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String readLine = null;
StringBuilder sb = new StringBuilder();
while ((readLine = br.readLine()) != null) {
if (readLine.charAt(0) == '-') {
continue;
} else {
sb.append(readLine);
sb.append('\r');
}
}
return loadPublicKey(sb.toString());
} catch (IOException e) {
throw new Exception("公钥数据流读取错误");
} catch (NullPointerException e) {
throw new Exception("公钥输入流为空");
}
}
/**
* 从字符串中加载公钥
*
* @param publicKeyStr 公钥数据字符串
* @return
* @throws Exception 加载公钥时产生的异常
*/
public static RSAPublicKey loadPublicKey(String publicKeyStr)
throws Exception {
try {
byte[] buffer = Base64.decode(publicKeyStr, Base64.DEFAULT);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此算法");
} catch (InvalidKeySpecException e) {
throw new Exception("公钥非法");
} catch (NullPointerException e) {
throw new Exception("公钥数据为空");
}
}
/**
* 从文件中加载私钥
*
* @param in 私钥输入流
* @return
* @throws Exception
*/
public static RSAPrivateKey loadPrivateKey(InputStream in) throws Exception {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String readLine = null;
StringBuilder sb = new StringBuilder();
while ((readLine = br.readLine()) != null) {
if (readLine.charAt(0) == '-') {
continue;
} else {
sb.append(readLine);
sb.append('\r');
}
}
return loadPrivateKey(sb.toString());
} catch (IOException e) {
throw new Exception("私钥数据读取错误");
} catch (NullPointerException e) {
throw new Exception("私钥输入流为空");
}
}
/**
* 从字符串中加载私钥
*
* @param privateKeyStr 私钥字符串
* @return
* @throws Exception
* @desc
*/
public static RSAPrivateKey loadPrivateKey(String privateKeyStr)
throws Exception {
try {
byte[] buffer = Base64.decode(privateKeyStr, Base64.DEFAULT);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此算法");
} catch (InvalidKeySpecException e) {
throw new Exception("私钥非法");
} catch (NullPointerException e) {
throw new Exception("私钥数据为空");
}
}
/**
* 公钥加密
*
* @param data
* @param publicKey
* @return
* @throws Exception
* @desc
*/
public static byte[] encryptByPublicKey(byte[] data, RSAPublicKey publicKey)
throws Exception {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
/**
* 私钥加密
*
* @param data
* @param privateKey
* @return
* @throws Exception
* @desc
*/
public static byte[] encryptByPrivateKey(byte[] data,
RSAPrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 私钥加密
*
* @param data
* @param privateKey
* @return
* @throws Exception
* @desc
*/
public static String encryptByPrivateKey(String data,
RSAPrivateKey privateKey) throws Exception {
// 模长
int key_len = privateKey.getModulus().bitLength() / 8;
// 加密数据长度 <= 模长-11
String[] datas = splitString(data, key_len - 11);
String mi = "";
// 如果明文长度大于模长-11则要分组加密
for (String s : datas) {
mi += bcd2Str(encryptByPrivateKey(s.getBytes(), privateKey));
}
return mi;
}
/**
* 私钥解密
*
* @param data
* @param privateKey
* @return
* @throws Exception
*/
public static String decryptByPrivateKey(String data,
RSAPrivateKey privateKey) throws Exception {
// 模长
int key_len = privateKey.getModulus().bitLength() / 8;
byte[] bytes = data.getBytes();
byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
// 如果密文长度大于模长则要分组解密
String ming = "";
byte[][] arrays = splitArray(bcd, key_len);
for (byte[] arr : arrays) {
ming += new String(decryptByPrivateKey(arr, privateKey));
}
return ming;
}
/**
* 私钥解密
*
* @param data
* @param privateKey
* @return
* @throws Exception
* @desc
*/
public static byte[] decryptByPrivateKey(byte[] data,
RSAPrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 公钥解密
*
* @param data
* @param publicKey
* @return
* @throws Exception
* @desc
*/
public static String decryptByPublicKey(String data,
RSAPublicKey publicKey) throws Exception {
// 模长
int key_len = publicKey.getModulus().bitLength() / 8;
byte[] bytes = data.getBytes();
byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
// 如果密文长度大于模长则要分组解密
String ming = "";
byte[][] arrays = splitArray(bcd, key_len);
for (byte[] arr : arrays) {
ming += new String(decryptByPublicKey(arr, publicKey));
}
return ming;
}
/**
* 公钥解密
*
* @param data
* @param publicKey
* @return
* @throws Exception
* @desc
*/
public static byte[] decryptByPublicKey(byte[] data,
RSAPublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
/**
* ASCII码转BCD码
*/
private static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) {
byte[] bcd = new byte[asc_len / 2];
int j = 0;
for (int i = 0; i < (asc_len + 1) / 2; i++) {
bcd[i] = asc_to_bcd(ascii[j++]);
bcd[i] = (byte) (((j >= asc_len) ? 0x00 : asc_to_bcd(ascii[j++])) + (bcd[i] << 4));
}
return bcd;
}
private static byte asc_to_bcd(byte asc) {
byte bcd;
if ((asc >= '0') && (asc <= '9'))
bcd = (byte) (asc - '0');
else if ((asc >= 'A') && (asc <= 'F'))
bcd = (byte) (asc - 'A' + 10);
else if ((asc >= 'a') && (asc <= 'f'))
bcd = (byte) (asc - 'a' + 10);
else
bcd = (byte) (asc - 48);
return bcd;
}
/**
* BCD转字符串
*/
private static String bcd2Str(byte[] bytes) {
char temp[] = new char[bytes.length * 2], val;
for (int i = 0; i < bytes.length; i++) {
val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
val = (char) (bytes[i] & 0x0f);
temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
}
return new String(temp);
}
/**
* 拆分字符串
*/
private static String[] splitString(String string, int len) {
int x = string.length() / len;
int y = string.length() % len;
int z = 0;
if (y != 0) {
z = 1;
}
String[] strings = new String[x + z];
String str = "";
for (int i = 0; i < x + z; i++) {
if (i == x + z - 1 && y != 0) {
str = string.substring(i * len, i * len + y);
} else {
str = string.substring(i * len, i * len + len);
}
strings[i] = str;
}
return strings;
}
/**
* 拆分数组
*/
private static byte[][] splitArray(byte[] data, int len) {
int x = data.length / len;
int y = data.length % len;
int z = 0;
if (y != 0) {
z = 1;
}
byte[][] arrays = new byte[x + z][];
byte[] arr;
for (int i = 0; i < x + z; i++) {
arr = new byte[len];
if (i == x + z - 1 && y != 0) {
System.arraycopy(data, i * len, arr, 0, y);
} else {
System.arraycopy(data, i * len, arr, 0, len);
}
arrays[i] = arr;
}
return arrays;
}
}
3.AES加/解密的工具类
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class AESUtils {
/**
* 随机生成一个AES密钥字符串
*
* @return
*/
public static String getRandomKey() {
return byte2hex(generateKey().getEncoded());
}
/**
* 加密数据,通过String类型的密钥加密String
*
* @param content
* @param key
* @return 16进制密文字符串
*/
public static String encrypt(String content, String key) {
byte[] data = null;
try {
data = content.getBytes("UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
data = encrypt(data, new SecretKeySpec(hex2byte(key), "AES").getEncoded());
String result = byte2hex(data);
return result;
}
/**********************************************************************************************/
private static final String CipherMode = "AES/ECB/PKCS5Padding";
/**
* 生成一个AES密钥对象
*
* @return
*/
public static SecretKeySpec generateKey() {
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128, new SecureRandom());
SecretKey secretKey = keyGenerator.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
return key;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
/**
* 加密字节数据
*
* @param content
* @param key
* @return
*/
public static byte[] encrypt(byte[] content, byte[] key) {
try {
Cipher cipher = Cipher.getInstance(CipherMode);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));
byte[] result = cipher.doFinal(content);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 通过byte[]类型的密钥加密String
*
* @param content
* @param key
* @return 16进制密文字符串
*/
public static String encrypt(String content, byte[] key) {
try {
Cipher cipher = Cipher.getInstance(CipherMode);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));
byte[] data = cipher.doFinal(content.getBytes("UTF-8"));
String result = byte2hex(data);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 通过byte[]类型的密钥解密byte[]
*
* @param content
* @param key
* @return
*/
public static byte[] decrypt(byte[] content, byte[] key) {
try {
Cipher cipher = Cipher.getInstance(CipherMode);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"));
byte[] result = cipher.doFinal(content);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 通过String类型的密钥 解密String类型的密文
*
* @param content
* @param key
* @return
*/
public static String decrypt(String content, String key) {
byte[] data = null;
try {
data = hex2byte(content);
} catch (Exception e) {
e.printStackTrace();
}
data = decrypt(data, hex2byte(key));
if (data == null)
return null;
String result = null;
try {
result = new String(data, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
/**
* 通过byte[]类型的密钥 解密String类型的密文
*
* @param content
* @param key
* @return
*/
public static String decrypt(String content, byte[] key) {
try {
Cipher cipher = Cipher.getInstance(CipherMode);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"));
byte[] data = cipher.doFinal(hex2byte(content));
return new String(data, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 字节数组转成16进制字符串
*
* @param b
* @return
*/
public static String byte2hex(byte[] b) { // 一个字节的数,
StringBuffer sb = new StringBuffer(b.length * 2);
String tmp = "";
for (int n = 0; n < b.length; n++) {
// 整数转成十六进制表示
tmp = (Integer.toHexString(b[n] & 0XFF));
if (tmp.length() == 1) {
sb.append("0");
}
sb.append(tmp);
}
return sb.toString().toUpperCase(); // 转成大写
}
/**
* 将hex字符串转换成字节数组
*
* @param inputString
* @return
*/
private static byte[] hex2byte(String inputString) {
if (inputString == null || inputString.length() < 2) {
return new byte[0];
}
inputString = inputString.toLowerCase();
int l = inputString.length() / 2;
byte[] result = new byte[l];
for (int i = 0; i < l; ++i) {
String tmp = inputString.substring(2 * i, 2 * i + 2);
result[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF);
}
return result;
}
}