转载:http://blog.csdn.net/chay_chan/article/details/58605605
源码:https://github.com/Javen205/IJPay
数据传输加密
在开发应用过程中,客户端与服务端经常需要进行数据传输,涉及到重要隐私信息时,开发者自然会想到对其进行加密,即使传输过程中被“有心人”截取,也不会将信息泄露。对于加密算法,相信不少开发者也有所耳闻,比如MD5加密,Base64加密,DES加密,AES加密,RSA加密等等。在这里我主要向大家介绍一下我在开发过程中使用到的加密算法,RSA加密算法+AES加密算法。简单地介绍一下这两种算法吧。
RSA
之所以叫RSA算法,是因为算法的三位发明者RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准,主要的算法原理就不多加介绍,如果对此感兴趣的话,建议去百度一下RSA算法。需要了解的是RSA算法属于非对称加密算法,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。简单的说是“公钥加密,私钥解密;私钥加密,公钥解密”。
AES
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。
为什么要结合使用这两种算法
如果不清楚非对称算法和对称算法,也许你会问,为什么要结合使用这两种算法,单纯使用一种算法不行吗?这就要结合不同的场景和需求了。
客户端传输重要信息给服务端,服务端返回的信息不需加密的情况
客户端传输重要信息给服务端,服务端返回的信息不需加密,例如绑定银行卡的时候,需要传递用户的银行卡号,手机号等重要信息,客户端这边就需要对这些重要信息进行加密,使用RSA公钥加密,服务端使用RSA解密,然后返回一些普通信息,比如状态码code,提示信息msg,提示操作是成功还是失败。这种场景下,仅仅使用RSA加密是可以的。
客户端传输重要信息给服务端,服务端返回的信息需加密的情况
客户端传输重要信息给服务端,服务端返回的信息需加密,例如客户端登录的时候,传递用户名和密码等资料,需要进行加密,服务端验证登录信息后,返回令牌token需要进行加密,客户端解密后保存。此时就需要结合这两种算法了。至于整个流程是怎样的,在下面会慢慢通过例子向你介绍,因为如果一开始就这么多文字类的操作,可能会让读者感到一头雾水。
源码
public class RSAUtils {
/** RSA最大加密明文大小 */
private static final int MAX_ENCRYPT_BLOCK = 117;
/** RSA最大解密密文大小 */
private static final int MAX_DECRYPT_BLOCK = 128;
/** 加密算法RSA */
private static final String KEY_ALGORITHM = "RSA";
/**
* 生成公钥和私钥
*
* @throws Exception
*
*/
public static Map<String, String> getKeys() throws Exception {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
String publicKeyStr = getPublicKeyStr(publicKey);
String privateKeyStr = getPrivateKeyStr(privateKey);
Map<String, String> map = new HashMap<String, String>();
map.put("publicKey", publicKeyStr);
map.put("privateKey", privateKeyStr);
System.out.println("公钥\r\n" + publicKeyStr);
System.out.println("私钥\r\n" + privateKeyStr);
return map;
}
/**
* 使用模和指数生成RSA公钥
* 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
* /None/NoPadding】
*
* @param modulus
* 模
* @param exponent
* 公钥指数
* @return
*/
public static RSAPublicKey getPublicKey(String modulus, String exponent) {
try {
BigInteger b1 = new BigInteger(modulus);
BigInteger b2 = new BigInteger(exponent);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 使用模和指数生成RSA私钥
* 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
* /None/NoPadding】
*
* @param modulus
* 模
* @param exponent
* 指数
* @return
*/
public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {
try {
BigInteger b1 = new BigInteger(modulus);
BigInteger b2 = new BigInteger(exponent);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 公钥加密
* @param data
* @param publicKey
* @return
* @throws Exception
*/
public static String encryptByPublicKey(String data,String publicKey) throws Exception {
byte[] dataByte = data.getBytes();
byte[] keyBytes = Base64Utils.decode(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicK = keyFactory.generatePublic(x509KeySpec);
// 对数据加密
// Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicK);
int inputLen = dataByte.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(dataByte, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(dataByte, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return Base64Utils.encode(encryptedData);
}
/**
* 私钥解密
*
* @param data
* @return
* @throws Exception
*/
public static String decryptByPrivateKey(String data,String privateKey) throws Exception {
byte[] encryptedData = Base64Utils.decode(data);
byte[] keyBytes = Base64Utils.decode(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
// Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateK);
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher
.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher
.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return new String(decryptedData);
}
/**
* 获取模数和密钥
*
* @return
*/
public static Map<String, String> getModulusAndKeys() {
Map<String, String> map = new HashMap<String, String>();
try {
InputStream in = RSAUtils.class
.getResourceAsStream("/rsa.properties");
Properties prop = new Properties();
prop.load(in);
String modulus = prop.getProperty("modulus");
String publicKey = prop.getProperty("publicKey");
String privateKey = prop.getProperty("privateKey");
in.close();
map.put("modulus", modulus);
map.put("publicKey", publicKey);
map.put("privateKey", privateKey);
} catch (IOException e) {
e.printStackTrace();
}
return map;
}
/**
* 从字符串中加载公钥
*
* @param publicKeyStr
* 公钥数据字符串
* @throws Exception
* 加载公钥时产生的异常
*/
public static PublicKey loadPublicKey(String publicKeyStr) throws Exception {
try {
byte[] buffer = Base64Utils.decode(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_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("公钥数据为空");
}
}
/**
* 从字符串中加载私钥<br>
* 加载时使用的是PKCS8EncodedKeySpec(PKCS#8编码的Key指令)。
*
* @param privateKeyStr
* @return
* @throws Exception
*/
public static PrivateKey loadPrivateKey(String privateKeyStr)
throws Exception {
try {
byte[] buffer = Base64Utils.decode(privateKeyStr);
// X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此算法");
} catch (InvalidKeySpecException e) {
throw new Exception("私钥非法");
} catch (NullPointerException e) {
throw new Exception("私钥数据为空");
}
}
public static String getPrivateKeyStr(PrivateKey privateKey)
throws Exception {
return new String(Base64Utils.encode(privateKey.getEncoded()));
}
public static String getPublicKeyStr(PublicKey publicKey) throws Exception {
return new String(Base64Utils.encode(publicKey.getEncoded()));
}
public static void main(String[] args) throws Exception {
Map<String, String> keys = getKeys();
String publicKey = keys.get("publicKey");
String privateKey = keys.get("privateKey");
String content = "我是Javen,I am Javen";
String encrypt = encryptByPublicKey(content, publicKey);
String decrypt = decryptByPrivateKey(encrypt, privateKey);
System.out.println("加密之后:"+encrypt);
System.out.println("解密之后:"+decrypt);
}
}
/**
* AES工具类,密钥必须是16位字符串
*/
public class AESUtils {
/**偏移量,必须是16位字符串*/
private static final String IV_STRING = "16-Bytes--String";
/**
* 默认的密钥
*/
public static final String DEFAULT_KEY = "1bd83b249a414036";
/**
* 产生随机密钥(这里产生密钥必须是16位)
*/
public static String generateKey() {
String key = UUID.randomUUID().toString();
key = key.replace("-", "").substring(0, 16);// 替换掉-号
return key;
}
public static String encryptData(String key, String content) {
byte[] encryptedBytes = new byte[0];
try {
byte[] byteContent = content.getBytes("UTF-8");
// 注意,为了能与 iOS 统一
// 这里的 key 不可以使用 KeyGenerator、SecureRandom、SecretKey 生成
byte[] enCodeFormat = key.getBytes();
SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
byte[] initParam = IV_STRING.getBytes();
IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
// 指定加密的算法、工作模式和填充方式
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
encryptedBytes = cipher.doFinal(byteContent);
// 同样对加密后数据进行 base64 编码
// return Base64.encodeBase64String(encryptedBytes);
return Base64Utils.encode(encryptedBytes);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String decryptData(String key, String content) {
try {
// base64 解码
byte[] encryptedBytes = Base64Utils.decode(content);
// byte[] encryptedBytes = Base64.decodeBase64(content);
byte[] enCodeFormat = key.getBytes();
SecretKeySpec secretKey = new SecretKeySpec(enCodeFormat, "AES");
byte[] initParam = IV_STRING.getBytes();
IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
byte[] result = cipher.doFinal(encryptedBytes);
return new String(result, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
try {
Map<String, String> keys = RSAUtils.getKeys();
String publicKey = keys.get("publicKey");
String privateKey = keys.get("privateKey");
String key = generateKey();
System.out.println("aes密钥:"+key);
String plainText = "I am Javen -By 我是Javen";
plainText = encryptData(key, plainText);
System.out.println("aes加密后: " + plainText );
plainText = decryptData(key, plainText);
System.out.println("aes解密后: " + plainText );
String encrypt = RSAUtils.encryptByPublicKey(key,publicKey);
System.out.println("RSA加密:"+encrypt);
System.out.println("RSA解密:"+RSAUtils.decryptByPrivateKey(encrypt,privateKey));
} catch (Exception e) {
e.printStackTrace();
}
}
}
/** */
/**
* <p>
* BASE64编码解码工具包
* </p>
* <p>
* 依赖javabase64-1.3.1.jar
* </p>
*/
public class Base64Utils {
/** */
/**
* 文件读取缓冲区大小
*/
private static final int CACHE_SIZE = 1024;
/** */
/**
* <p>
* BASE64字符串解码为二进制数据
* </p>
*
* @param base64
* @return
* @throws Exception
*/
public static byte[] decode(String base64) throws Exception {
return Base64.decode(base64.getBytes());
}
public static String decode(byte[] b) {
return new String(Base64.decode(b));
}
/** */
/**
* <p>
* 二进制数据编码为BASE64字符串
* </p>
*
* @param bytes
* @return
* @throws Exception
*/
public static String encode(byte[] bytes) throws Exception {
return new String(Base64.encode(bytes));
}
/** */
/**
* <p>
* 将文件编码为BASE64字符串
* </p>
* <p>
* 大文件慎用,可能会导致内存溢出
* </p>
*
* @param filePath
* 文件绝对路径
* @return
* @throws Exception
*/
public static String encodeFile(String filePath) throws Exception {
byte[] bytes = fileToByte(filePath);
return encode(bytes);
}
/** */
/**
* <p>
* BASE64字符串转回文件
* </p>
*
* @param filePath
* 文件绝对路径
* @param base64
* 编码字符串
* @throws Exception
*/
public static void decodeToFile(String filePath, String base64)
throws Exception {
byte[] bytes = decode(base64);
byteArrayToFile(bytes, filePath);
}
/** */
/**
* <p>
* 文件转换为二进制数组
* </p>
*
* @param filePath
* 文件路径
* @return
* @throws Exception
*/
public static byte[] fileToByte(String filePath) throws Exception {
byte[] data = new byte[0];
File file = new File(filePath);
if (file.exists()) {
FileInputStream in = new FileInputStream(file);
ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
byte[] cache = new byte[CACHE_SIZE];
int nRead = 0;
while ((nRead = in.read(cache)) != -1) {
out.write(cache, 0, nRead);
out.flush();
}
out.close();
in.close();
data = out.toByteArray();
}
return data;
}
/** */
/**
* <p>
* 二进制数据写文件
* </p>
*
* @param bytes
* 二进制数据
* @param filePath
* 文件生成目录
*/
public static void byteArrayToFile(byte[] bytes, String filePath)
throws Exception {
InputStream in = new ByteArrayInputStream(bytes);
File destFile = new File(filePath);
if (!destFile.getParentFile().exists()) {
destFile.getParentFile().mkdirs();
}
destFile.createNewFile();
OutputStream out = new FileOutputStream(destFile);
byte[] cache = new byte[CACHE_SIZE];
int nRead = 0;
while ((nRead = in.read(cache)) != -1) {
out.write(cache, 0, nRead);
out.flush();
}
out.close();
in.close();
}
}
/**
* des加密、解密
*/
public class DESUtils {
// 指定DES加密解密所用的密钥
private static Key key;
/**
* 加密key为空, 默认为类名
*/
public DESUtils() {
setkey(this.getClass().getName());
}
/**
* 设置加密key
*
* @param keyStr
* 加密key值
*/
public DESUtils(String keyStr) {
setkey(keyStr);
}
/**
* 设置加密的校验码
*/
private void setkey(String keyStr) {
try {
// L.cm 2015-01-20 将加密的密匙Base64
// fix Caused by: java.security.InvalidKeyException: Wrong key size
String desKey = Base64.encodeBase64String(keyStr.getBytes("UTF-8"));
DESKeySpec objDesKeySpec = new DESKeySpec(desKey.getBytes("UTF-8"));
SecretKeyFactory objKeyFactory = SecretKeyFactory.getInstance("DES");
key = objKeyFactory.generateSecret(objDesKeySpec);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 对字符串进行DES加密,返回BASE64编码的加密字符串
* @param str
* @return
*/
public final String encryptString(String str) {
byte[] bytes = str.getBytes();
try {
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptStrBytes = cipher.doFinal(bytes);
return Base64.encodeBase64URLSafeString(encryptStrBytes);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 对BASE64编码的加密字符串进行解密,返回解密后的字符串
* @param str
* @return
*/
public final String decryptString(String str) {
try {
byte[] bytes = Base64.decodeBase64(str);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, key);
bytes = cipher.doFinal(bytes);
return new String(bytes);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
String keyStr="9cc9b11a7a0747d4b19d30a324a84dc5";
System.out.println("keyStr:"+keyStr);
DESUtils desUtils=new DESUtils(keyStr);
String sourceStr="12345678";
System.out.println("加密前的Str:"+sourceStr);
String encryptString = desUtils.encryptString(sourceStr);
System.out.println("加密之后:"+encryptString);
String decryptString = desUtils.decryptString(encryptString);
System.out.println("解密之后:"+decryptString);
}
}