概念
当我们传输一些需要保密性的东西的时候往往需要把数据进行加密以增加它的安全性
密码的常用术语
明文:待加密的信息
密文:经过加密后的明文
加密:明文转换成密文的过程
加密算法:明文转为密文的转换算法
加密密钥:通过加密算法进行加密操作用的密钥
解密:将密文转为明文的过程
解密算法:密文转为明文的算法
解密密钥:通过解密算法进行解密操作用的密钥
密码分析:截获密文者试图通过分析截获的密文从而推断出原来的明文或密钥的过程
主动攻击:攻击者非法入侵密码系统,采用伪造、修改、删除等手段向系统注入假消息进行欺骗。(对密文具有破坏作用)
被动攻击:对一个保密系统采取截获密文并对其进行分析和攻击(对密文没有破坏作用)
密码体制:用明文空间、密文空间、密钥空间、加密算法和解密算法五部分构成。
密码协议:也称安全协议,指以密码学为基础的消息交换的通信协议,目的是在网络环境中提供安全的服务。
密码系统:指用于加密、解密的系统。
柯克霍夫原则:数据的安全基于密钥而不是算法的保密。即系统的安全取决于密钥,对密钥保密,对算法公开。-现代密码学设计的基本原则
密码分类
时间上分:
古典密码:以字符为基本加密单元。
现代密码:以信息块为基本加密单元。
保密内容上分:
密码体制上分:
明文处理上分:
分组密码:指加密时将明文分成固定长度的组,用同一密钥和
算法对每一块加密,输出也是固定长度的密文。多用于网络加
密。
流密码:也称序列密码。指加密时每次加密一位或者一个字节明
文。
散列函数
用来验证数据的完整性。
特点:①长度不受限制
②哈希值容易计算
③散列运算过程不可逆
相关的算法:①消息摘要算法MD5
②SHA–安全散列算法
③MAC–消息认证码算法(MAC–苹果操作系统)
数字签名
主要针对以数字的形式存储的消息进行处理
OSI(Open System Interconnection)
开发式通信系统。网络通信的OSI的七层通信协议(从1到7):物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
TCP/IP安全体系
Java安全组成
JCA(Java Cryptography Architecture):提供基本加密的框架,比如:消息摘要、数字签名
JCE(Java Cryptography Extension):JCA基础上的扩展。如DES、AES、RSA算法
JSSE(Java Secure Socket Extension):提供基于SSL的加密功能,主要用于网络传输
JAAS(Java Authentication and Authentication Service):提供来java平台上用户身份验证的功能。就是基于java开发的系统权限或者安全
相关Java包、类
java.security:消息摘要
javax.crypto:安全消息摘要,消息认证(鉴别)码
java.net.ssl:安全套接字,HttpsURLConnection、SSLContext
第三方Java扩展
有两种支持方案
配置
具体在自己java安装目录下的jdk/jre/lib/security/java.security
这些都是默认的
调用
单向加密
Base64
严格意义上来说它不算一个加解密的算法。但是也把它称为初级的、简单的加解密密算法。
算法的实现
jdk(不建议使用)
private static String src = "java,从入门到放弃";
public static void main(String[] args) throws IOException {
jdkBase64();
}
public static void jdkBase64() throws IOException {
// JDK加密类
BASE64Encoder encoder = new BASE64Encoder();
String result = encoder.encode(src.getBytes());
System.out.println(result);
// JDK解密类
BASE64Decoder decoder = new BASE64Decoder();
String content = new String(decoder.decodeBuffer(result));
System.out.println(content);
}
结果:
奇葩情况:可能会出现编译器无法找到这个类。这个问题就是右键项目进入libraries
点击红线处,添加如图
Commons Codec
public static void commonsCodesBase64() {
byte[] b = Base64.encodeBase64(src.getBytes());
System.out.println(new String(b));
byte[] b1 = Base64.decodeBase64(b);
System.out.println(new String(b1));
}
结果:
Bouncy Castle
public static void bouncyCastleBase64() {
byte[] b = org.bouncycastle.util.encoders.Base64.encode(src.getBytes());
System.out.println(new String(b));
byte[] b1 = org.bouncycastle.util.encoders.Base64.decode(b);
System.out.println(new String(b1));
}
结果:
该算法的应用场景
e-mail、密钥、证书文件
消息摘要算法
其作用验证数据的完整性(下载的文件,可以根据下载文件生成消息摘要跟下载处进行对比来判断文件是否完整),也是数字签名核心算法。下列列举3个算法
MD(Message Digest):消息摘要
生成的消息摘要都是128位摘要信息(MD2、MD4、MD5)
public class TestMD {
private static String src = "java,从入门到放弃";
public static void main(String[] args) {
jdkMD5();
jdkMD2();
bcMD4();
bcMD5();
ccMD5();
ccMD2();
}
public static void jdkMD5() {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] b = md.digest(src.getBytes());
System.out.println("JDKMD5 : "+new String(b));
// JDK的MD5是不完善的,它没有把byte数组转成十六进制,所以我们需要自己写一个十六进制解析或者借助第三方工具
// 这里我用阿帕奇的hex
System.out.println("JDKMD5 : "+Hex.encodeHexString(b));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void jdkMD2() {
try {
MessageDigest md = MessageDigest.getInstance("MD2");
byte[] b = md.digest(src.getBytes());
System.out.println("JDKMD2 : "+new String(b));
// JDK的MD5是不完善的,它没有把byte数组转成十六进制,所以我们需要自己写一个十六进制解析或者借助第三方工具
System.out.println("JDKMD2 : "+Hex.encodeHexString(b));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void bcMD5() {
Digest digest = new MD5Digest();
digest.update(src.getBytes(),0,src.length());
byte[] result = new byte[digest.getDigestSize()];
digest.doFinal(result, 0);
System.out.println("MD5 : "+org.bouncycastle.util.encoders.Hex.toHexString(result));
}
public static void bcMD4(){
Digest digest = new MD4Digest();
digest.update(src.getBytes(),0,src.length());
byte[] result = new byte[digest.getDigestSize()];
digest.doFinal(result, 0);
System.out.println("MD4 : "+org.bouncycastle.util.encoders.Hex.toHexString(result));
}
public static void ccMD5() {
System.out.println("ccMD5 : "+DigestUtils.md5Hex(src.getBytes()));
}
public static void ccMD2() {
System.out.println("ccMD2 : "+DigestUtils.md2Hex(src.getBytes()));
}
//从结果发现其实cc的MD5和cc的MD2只是简化的JDK的操作,也是就解释了为什么cc没有MD4
}
结果:
该算法的应用场景
这个过程是当用户名注册账号的时候把密码进行加密生成十六进制的摘要。而数据库所存的是用户名明文,密码则是密文。
当然有人会问密码是密文怎么登陆
那当然密码去查询之前也需要加密成摘要,相同内容其摘要是相同的
SHA(Secure Hash Algorithm):安全散列算法
与MD5一样固定长度摘要信息,从MD4基础上演变而来。有SHA-1、SHA-2(SHA-224、SHA-256、SHA-384、SHA-512)等五种。
public class TestSHA {
private static String src = "java,从入门到放弃";
public static void main(String[] args) {
jdkSHA1();
bcSHA1();
bcSHA224();
ccSHA1();
}
public static void jdkSHA1(){
try {
MessageDigest md = MessageDigest.getInstance("SHA");
byte[] b= md.digest(src.getBytes());
System.out.println("JDK SHA-1 : "+Hex.encodeHexString(b));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void bcSHA1() {
Digest digest = new SHA1Digest();
digest.update(src.getBytes(),0,src.length());
byte[] result = new byte[digest.getDigestSize()];
digest.doFinal(result, 0);
System.out.println("BC SHA-1 : "+org.bouncycastle.util.encoders.Hex.toHexString(result));
}
public static void bcSHA224() {
Digest digest = new SHA224Digest();
digest.update(src.getBytes(),0,src.length());
byte[] result = new byte[digest.getDigestSize()];
digest.doFinal(result, 0);
System.out.println("BC SHA-224 : "+org.bouncycastle.util.encoders.Hex.toHexString(result));
}
public static void ccSHA1() {
System.out.println("cc SHA-1 : "+DigestUtils.sha1Hex(src.getBytes()));
}
}
结果:
该算法的使用
防止消息被篡改。当接受到的消息经过算法加密后是否与发送方发送的摘要一致,一致则表示信息完整未被篡改。
MAC(Message Authentication Code):消息认证码算法
HMAC(keyed-Hash Message Authentication Code),含有密钥的散列函数算法
是一种含有密钥、散列函数的算法。兼容了MD和SHA两种的特性
融合MD、SHA
– MD系列:HmacMD2、HmacMD4、HmacMD5
–SHA系列:HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384、HmacSHA512
public class TestMAC {
private static String src = "java,从入门到放弃";
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException {
jdkHmacMD5();
bcHmacMD5() ;
}
public static void jdkHmacMD5() throws NoSuchAlgorithmException, InvalidKeyException {
// 初始化密钥工厂
KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5");
// 产生密钥
SecretKey sk = keyGenerator.generateKey();
// 获得密钥
byte[] b = sk.getEncoded();
// 还原密钥
SecretKey rsk = new SecretKeySpec(b,"HmacMD5");
// 实例化MAC
Mac mac = Mac.getInstance(rsk.getAlgorithm());
// 初始化MAC
mac.init(rsk);
// 执行摘要
byte[] result = mac.doFinal(src.getBytes());
System.out.println("JDK hmacMD5 : "+Hex.encodeHexString(result));
}
public static void bcHmacMD5() {
HMac hmac = new HMac(new MD5Digest());
// org.bouncycastle.util.encoders.Hex.decode("aaaaaaaaaa")相当于设置密钥过程
hmac.init(new KeyParameter(org.bouncycastle.util.encoders.Hex.decode("aaaaaaaaaa")));
hmac.update(src.getBytes(),0,src.getBytes().length);
byte[] result = new byte[hmac.getMacSize()];
hmac.doFinal(result, 0);
System.out.println("bc HmacMD5 : "+org.bouncycastle.util.encoders.Hex.toHexString(result));
}
}
结果:
该算法应用场景:
Java对称加密算法
常用的对称加密算法DES(由于长度不够衍生了3DES)、AES、PBE、IDEA。
DES(Data Encryption Standard):数据加密标准
(已经被破解,所以基本没人使用)
public class TestSymmetric {
private static String src = "java,从入门到放弃";
public static void main(String[] args) throws Exception {
jdkDES();
bcDES();
}
public static void jdkDES() throws Exception {
// 生成key
KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
System.out.println(keyGenerator.getProvider());
// 生成56位
keyGenerator.init(56);
SecretKey sk1 = keyGenerator.generateKey();
byte[] bytesKey = sk1.getEncoded();
// key转换
DESKeySpec desKeySpec = new DESKeySpec(bytesKey);
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
Key sk2 = skf.generateSecret(desKeySpec);
//加密
//分别是加密算法、加密模式、填充方式
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
//Cipher.ENCRYPT_MODE 加密模式
cipher.init(Cipher.ENCRYPT_MODE, sk2);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("JDK DES 加密结果: "+Hex.encodeHexString(result));
// 解密操作
// Cipher.DECRYPT_MODE解密模式
cipher.init(Cipher.DECRYPT_MODE,sk2);
result = cipher.doFinal(result);
System.out.println("JDK DES 解密结果: "+new String(result));
}
public static void bcDES() throws Exception {
Security.addProvider(new BouncyCastleProvider());
KeyGenerator keyGenerator = KeyGenerator.getInstance("DES","BC");
System.out.println(keyGenerator.getProvider());
// 生成56位
keyGenerator.init(56);
SecretKey sk1 = keyGenerator.generateKey();
byte[] bytesKey = sk1.getEncoded();
// key转换
DESKeySpec desKeySpec = new DESKeySpec(bytesKey);
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
Key sk2 = skf.generateSecret(desKeySpec);
//加密
//分别是加密算法、加密模式、填充方式
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
//Cipher.ENCRYPT_MODE 加密模式
cipher.init(Cipher.ENCRYPT_MODE, sk2);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("BC DES 加密结果: "+Hex.encodeHexString(result));
// 解密操作
// Cipher.DECRYPT_MODE解密模式
cipher.init(Cipher.DECRYPT_MODE,sk2);
result = cipher.doFinal(result);
System.out.println("BC DES 解密结果: "+new String(result));
}
}
结果:
应用
3重DES
因为DES违反了柯克霍夫原则及安全等问题衍生出来的。
好处:1、密钥长度增强
2、迭代次数提高
public static void jdk3DES() throws Exception {
// 生成key
KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
System.out.println(keyGenerator.getProvider());
keyGenerator.init(168);
SecretKey sk1 = keyGenerator.generateKey();
byte[] bytesKey = sk1.getEncoded();
// key转换
DESedeKeySpec desKeySpec = new DESedeKeySpec(bytesKey);
SecretKeyFactory skf = SecretKeyFactory.getInstance("DESede");
Key sk2 = skf.generateSecret(desKeySpec);
//加密
//分别是加密算法、加密模式、填充方式
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
//Cipher.ENCRYPT_MODE 加密模式
cipher.init(Cipher.ENCRYPT_MODE, sk2);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("JDK 3DES 加密结果: "+Hex.encodeHexString(result));
// 解密操作
// Cipher.DECRYPT_MODE解密模式
cipher.init(Cipher.DECRYPT_MODE,sk2);
result = cipher.doFinal(result);
System.out.println("JDK 3DES 解密结果: "+new String(result));
}
结果:
AES(目前使用最多的对称加密算法)
DES安全有问题,3重DES则效率低下,AES目前为止官方报道并未被破解,AES通常用于移动通信系统加密以及基于SSH协议的软件,如:SSH Client、secureCRT
public class TestAES {
private static String src = "java,从入门到放弃";
public static void main(String[] args) throws Exception {
jdkAES();
}
public static void jdkAES() throws Exception {
//生成key
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
SecretKey sk = keyGenerator.generateKey();
byte[] keyBytes = sk.getEncoded();
//key转换
Key key = new SecretKeySpec(keyBytes, "AES");
//加密
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("JDK AES 加密结果:"+Base64.encodeBase64String(result));
System.out.println("JDK AES 加密结果:"+Hex.encodeHexString(result));
//解密
cipher.init(Cipher.DECRYPT_MODE, key);
result = cipher.doFinal(result);
System.out.println("JDK AES 解密结果:"+new String(result));
}
}
结果:
应用:
PBE算法(Password Based Encryption基于口令的加密)
结合了消息摘要算法和对称加密算法的优点
public class TestPBE {
private static String src = "java,从入门到放弃";
public static void main(String[] args) throws Exception {
jdkPBE();
}
public static void jdkPBE() throws Exception {
//初始化盐,盐就是加密要用的随机数随机条件
SecureRandom random = new SecureRandom();
byte[] salt = random.generateSeed(8);
//口令与密钥
String password = "tiger";
PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBEWITHMD5andDES");
Key key = skf.generateSecret(pbeKeySpec);
//加密
// 参数1为盐,参数2位迭代次数
PBEParameterSpec pbeParameterSpec = new PBEParameterSpec(salt, 100);
Cipher cipher = Cipher.getInstance("PBEWITHMD5andDES");
cipher.init(Cipher.ENCRYPT_MODE, key,pbeParameterSpec);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("jdk pbe 加密 : "+Base64.encodeBase64String(result));
System.out.println("jdk pbe 加密 : "+Hex.encodeHexString(result));
//解密
cipher.init(Cipher.DECRYPT_MODE,key, pbeParameterSpec);
result = cipher.doFinal(result);
System.out.println("jdk pbe 解密 : "+new String(result));
}
}
结果:
应用: