黑马程序员技术交流社区
标题: [黑马程序员杭州]Java中的数据传输安全策略 [打印本页]
作者: 小江哥 时间: 2017-11-12 23:17
标题: [黑马程序员杭州]Java中的数据传输安全策略
本帖最后由 小江哥 于 2017-11-12 23:17 编辑
1. 引言
1.0 在开发中面临的数据安全问题:
1.数据存储安全
2.数据传输安全(本节我们探究的内容)
1.1 密码学中的常见概念:
ü 明文:指待加密信息
ü 密文:指经过加密后的明文
ü 加签:主要用来验证数据有没有被篡改
ü 加盐:在明文中加入一些无关字符后再进行不可逆加密(例如MD5)
附:MD5加密后的数据是不可逆的,目前的解密策略都是基于碰撞机制进行,本质上并不算是真正的解密
1.2 加解密策略:
l 对称加密:加密和解密使用同一个秘钥
l 非对称加密:加密使用公钥(public key),解密使用私钥(private key),公钥和私钥是一对
2. 对称加密—AES
对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key)。
对称加密通常使用的是相对较小的密钥,一般小于256 bit。因为密钥越大,加密越强,但加密与解密的过程越慢。如果你只用1 bit来做这个密钥,那黑客们可以先试着用0来解密,不行的话就再用1解;但如果你的密钥有1 MB大,黑客们可能永远也无法破解,但加密和解密的过程要花费很长的时间。
3. 非对称加密—RSA
非对称加密为数据的加密与解密提供了一个非常安全的方法,它使用了一对密钥,公钥(public key)和私钥(private key)。私钥只能由一方安全保管,不能外泄,而公钥则可以发给任何请求它的人。非对称加密使用这对密钥中的一个进行加密,而解密则需要另一个密钥。比如,你向银行请求公钥,银行将公钥发给你,你使用公钥对消息加密,那么只有私钥的持有人--银行才能对你的消息解密。与对称加密不同的是,银行不需要将私钥通过网络发送出去,因此安全性大大提高。
4. 总结
a. 对称加密与解密使用的是同样的密钥,所以速度快,但由于需要将密钥在网络传输,所以安全性不高。
b. 非对称加密使用了一对密钥,公钥与私钥,所以安全性高,但加密与解密速度慢。
c. 解决的办法是将对称加密的密钥使用非对称加密的公钥进行加密,然后发送出去,接收方使用私钥进行解密得到对称加密的密钥,然后双方可以使用对称加密来进行沟通。
5. 个人建议
Ø 信息量较少的数据使用RSA
Ø 信息量较大的数据使用AES
6. 案例代码
Maven依赖:
<dependencies>
<!-- security -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.cryptonode.jncryptor</groupId>
<artifactId>jncryptor</artifactId>
<version>1.2.0</version>
</dependency>
<!-- CryptoException-->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcmail-jdk14</artifactId>
<version>1.51</version>
</dependency>
</dependencies>
AES工具类:
public class AESUtil {
public static JNCryptor cryptor = newAES256JNCryptor(100);
/**
* 加密
*
* @param plaintext
* @param password
* @return
* @throwsCryptoException
*/
public static StringencryptData(String plaintext, String password) throwsCryptoException {
byte[] ciphertext = null;
try {
ciphertext = cryptor.encryptData(plaintext.getBytes(),password.toCharArray());
} catch(CryptorException e) {
throw newCryptoException("Failed to encrypt data by AES", e);
}
return Hex.encodeHexString(ciphertext);
}
/**
* 解密
*
* @param data
* @param password
* @return
* @throwsCryptoException
*/
public static StringdecryptData(String data, String password) throwsCryptoException {
if(StringUtils.isEmpty(data)) {
throw newCryptoException("Decryption error", newIllegalArgumentException("Data is empty"));
}
if(StringUtils.isEmpty(password)) {
throw newCryptoException("Decryption error", newIllegalArgumentException("Key is empty"));
}
byte[] plaintext = null;
try {
plaintext = cryptor.decryptData(Hex.decodeHex(data.toCharArray()),password.toCharArray());
} catch(DecoderException e) {
throw newCryptoException("Decryption error", e);
} catch(CryptorException e) {
throw newCryptoException("Decryption error", e);
}
return new String(plaintext);
}
public static voidmain(String[] args) throwsDecoderException {
// 1.定义原始数据
byte[] plaintext = ("欢迎来到黑马程序员!").getBytes();
// 2.定义key
String password = "CdFzeUoOvGptXwkR";
try {
// 3.加密数据
byte[] ciphertext = cryptor.encryptData(plaintext, password.toCharArray());
String cString = Hex.encodeHexString(ciphertext);
// 4.打印加密后的数据
System.out.println(cString);
// 5.解密数据
byte[] s = cryptor.decryptData(Hex.decodeHex(cString.toCharArray()),password.toCharArray());
// 6.打印解密后的数据
System.out.println(new String(s));
} catch(CryptorException e) {
e.printStackTrace();
}
}
}
RSA工具类:
public class RSAUtil {
// String to hold name of the encryption algorithm.
public static final String ALGORITHM = "RSA";
// String to hold name of the public key file.
private static String PUBLIC_KEY_FILE = "public.txt";
// String to hold name of the public key file.
private static String PRIVATE_KEY_FILE = "private.txt";
public static PublicKey publicKey;
public static PrivateKey privateKey;
/**
* Encrypt the plain text using public key.
*
* @param text
* @param key
* @return
* @throws CryptoException
*/
public static byte[]encrypt(String text, PublicKey key) throws CryptoException {
byte[] cipherText = null;
try {
// get an RSA cipher object
final Cipher cipher = Cipher.getInstance(ALGORITHM);
// encrypt the text using the public key
cipher.init(Cipher.ENCRYPT_MODE, key);
cipherText = cipher.doFinal(text.getBytes());
}catch (Exception e) {
throw newCryptoException("Failed to encrypt data byRSA", e);
}
return cipherText;
}
/**
* Decrypt text using private key.
*
* @param text
* @param key
* @return
* @throws CryptoException
*/
public static Stringdecrypt(byte[] text, PrivateKey key) throws CryptoException {
byte[] dectyptedText = null;
try {
// get an RSA cipher object
final Cipher cipher = Cipher.getInstance(ALGORITHM);
// decrypt the text using the private key
cipher.init(Cipher.DECRYPT_MODE, key);
dectyptedText = cipher.doFinal(text);
}catch (Exception e) {
throw newCryptoException("Failed to decrypt data byRSA", e);
}
return new String(dectyptedText);
}
public static void init() throws IOException {
InputStreaminputStream01 = RSAUtil.class.getClassLoader().getResourceAsStream(PUBLIC_KEY_FILE);
ObjectInputStreampublicIns = null;
InputStreaminputStream02 = RSAUtil.class.getClassLoader().getResourceAsStream(PRIVATE_KEY_FILE);
ObjectInputStreamprivateIns = null;
try {
publicIns = newObjectInputStream(inputStream01);
privateIns = newObjectInputStream(inputStream02);
publicKey =(PublicKey) publicIns.readObject();
privateKey =(PrivateKey) privateIns.readObject();
}catch (IOException e) {
System.out.println(e.getMessage());
}catch (ClassNotFoundException f) {
System.out.println(f.getMessage());
}finally {
privateIns.close();
publicIns.close();
}
}
public static void main(String[] args) throws IOException {
// 1.加载公钥,私钥文件
init();
// 2.定义原始内容
final String originalText = "woaiheimawoaijava";
byte[] encryptText = null;
StringdecryptText = null;
try {
// 3.加密数据
encryptText = encrypt(originalText, publicKey);
// 4.解密数据
decryptText = decrypt(encryptText, privateKey);
}catch (CryptoException e) {
e.printStackTrace();
}
// 5.打印原始数据,加密后的数据,解密后的数据
System.out.println("Original: " + originalText);
System.out.println("Encrypted: " + encryptText);
System.out.println("Decrypted: " + decryptText);
}
}
注意:
在使用AES工具类的时候,会出现如下错误:
org.cryptonode.jncryptor.CryptorException: Caught InvalidKeyException. Do you have unlimited strength jurisdictionfiles installed?
atorg.cryptonode.jncryptor.AES256JNCryptor.encryptData(AES256JNCryptor.java:494)
atorg.cryptonode.jncryptor.AES256JNCryptor.encryptData(AES256JNCryptor.java:345)
atorg.cryptonode.jncryptor.AES256JNCryptor.encryptData(AES256JNCryptor.java:361)
atcom.itheima.security.AESUtil.main(AESUtil.java:20)
Caused by: java.security.InvalidKeyException: Illegal key size
atjavax.crypto.Cipher.checkCryptoPerm(Cipher.java:1024)
atjavax.crypto.Cipher.implInit(Cipher.java:790)
atjavax.crypto.Cipher.chooseProvider(Cipher.java:849)
atjavax.crypto.Cipher.init(Cipher.java:1348)
atjavax.crypto.Cipher.init(Cipher.java:1282)
atorg.cryptonode.jncryptor.AES256JNCryptor.encryptData(AES256JNCryptor.java:481)
...3 more
问题由来:
因为密钥长度是受限制的,不能超过128位,而我们使用的是256位,java运行时环境读到的是受限的policy文件,文件位于${java_home}/jre/lib/security下,这种限制是由于美国对出口软件的控制
解决方案:
在JDK官网下载JCE无限制权限策略文件,下列分别为JDK7和JDK8的JCE无限制权限策略文件下载地址:
解锁限制:解压下载好的UnlimitedJCEPolicy文件,里面有两个jar包:
将这两个jar包拷贝到jdk/jre/lib/security文件夹下,覆盖原有文件即可
期待与同学们下次再见~
作者: fanbuer 时间: 2017-11-12 23:20
这更新速度,都赶上我的学习速度了……点赞
作者: gy_yt 时间: 2017-11-12 23:21
啸哥666,每日一学
作者: 小江哥 时间: 2017-11-12 23:21
不进则退,紧跟时代步伐
作者: 咸鱼666 时间: 2017-11-12 23:22
牛,真是6
作者: 猫先森 时间: 2017-11-12 23:27
66666666666
作者: 许言 时间: 2017-11-12 23:35
顶顶顶顶顶
作者: wxz_hm 时间: 2017-11-12 23:37
厉害了。顶顶顶
作者: nhm 时间: 2017-11-13 15:32
大佬666666666
作者: 从此学好 时间: 2017-11-13 15:34
强无敌,每次都能学到东西,666
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |