一。摘要算法html
1》MD5算法(Message Digest Algorithm 5) 能够保证数据传输完整性和一致性 摘要后长度为16字节 摘要信息中不包含原文信息java
全部加密结果不可逆(没法解密) 通常在传送文件时 对源文件进行md5 hash 传送到对方后 检测hash值是否相等 若是相等文件传输正确算法
若是不相等 说明文件被篡改(加入木马)或者未传送完成数据库
其余MD算法 MD2(16字节)数组
public static void main(String[] args) throws NoSuchAlgorithmException { MessageDigest md=MessageDigest.getInstance("MD5") ; String code="hello"; byte[] bt=md.digest(code.getBytes()); System.out.println(bt.length); }2》SHA算法Secure Hash Algorithm(安全hash算法) 安全散列算法(hash函数 将原始信息压缩 返回散列值)能够是SHA-1,SHA1是目前最安全
的摘要算法 摘要的长度为 20字节 安全
其余的SHA 包括 SHA-256(32字节)服务器
public static void main(String[] args) throws NoSuchAlgorithmException { MessageDigest md=MessageDigest.getInstance("SHA") ;//或者SHA-1 SHA1 String code="hello"; byte[] bt=md.digest(code.getBytes()); System.out.println(bt.length); }
二。编码和解码app
1》16进制 编码 计算机系统使用 2进制 为了编写存储方便通常将2进制 转换为16进制字符串 其中base64也是其中相似转换一种 16进制编码和base64都是dom
可逆的 通常用于存储函数
public static byte[] toByte(String src){ ByteArrayOutputStream baos=new ByteArrayOutputStream(); for(int i=0;i<src.length();i=i+2){ char fchar=src.charAt(i); char nchar=src.charAt(i+1); byte srcb=0; if(fchar=='0'){ srcb=Byte.parseByte(nchar+"", 16); }else{ srcb=(byte)(Integer.parseInt(fchar+""+nchar, 16)); } baos.write(srcb); } return baos.toByteArray(); } public static String toHex(byte[] src){ StringBuffer sb=new StringBuffer(); for(byte s:src){ //0XFF表示 8位的 11111111 和它&后 只剩下 8位 其余位都为0 String result=Integer.toHexString(s&0xFF); if(result.length()==1){ result='0'+result; } sb.append(result); } return sb.toString(); }
2》Base64编码 用于将字节数组和字符串互相转换
public static void main(String[] args) throws NoSuchAlgorithmException, IOException { byte[] src="hello".getBytes(); //摘要出来的结果为字节数组 存储到数据库不方便 MessageDigest md=MessageDigest.getInstance("SHA") ; byte[] bt=md.digest(src); //使用base64转换为字符串方便存储 BASE64Encoder base=new BASE64Encoder(); String str=base.encode(bt); System.out.println(str); //还原成字节数组 BASE64Decoder de=new BASE64Decoder(); byte[] bts=de.decodeBuffer(str); System.out.println(bt.length==bts.length); }
三。对称加密
1》DES算法 (Data Encryptin Standard) 是对称加密算法的一种 使用秘钥加解密 秘钥必须是56字节
概念解释:
秘钥 :用于加密和解密的钥匙 秘钥可使用 getEncoded方法 获取byte[] 存储在文件系统中
公钥和私钥:用于非对称加密的钥匙 公钥加密 私钥解密 私钥通常用于解密因此私钥通常存储在密钥库中
口令:通常是自定义的字符串 能够经过口令和盐生成秘钥
/** * 生成56字节的秘钥 */ public static SecretKey genKey(int len) throws NoSuchAlgorithmException{ KeyGenerator kg=KeyGenerator.getInstance("DES"); kg.init(len); return kg.generateKey(); } public static void main(String[] args) throws Exception { //SecretKey sk=new SecretKeySpec(kl.getBytes(), "DES"); SecretKey sk=genKey(57); //---------加密 String password="tiger"; Cipher cipher=Cipher.getInstance("DES"); cipher.init(Cipher.ENCRYPT_MODE, sk); //被加密以后获取的字节数组 byte[] mcontent=cipher.doFinal(password.getBytes()); //---------解密 Cipher cipher1=Cipher.getInstance("DES"); cipher1.init(Cipher.DECRYPT_MODE, sk); System.out.println(new String(cipher1.doFinal(mcontent))); }
2》AES算法 (Advanced Encryptin Standard 高级加密标准) 是对称加密算法一种升级 由于 56位秘钥 在计算机系统性能愈来愈高的前提下 56位很容易被
破解 因此 AES将秘钥的长度提升到128, 192 or 256 必须是这三个数 128默承认以使用 192和256因为美国限制 须要相关受权 不然抛出异常
public static final String AL="AES"; /** * 生成56字节的秘钥 */ public static SecretKey genKey(int len) throws NoSuchAlgorithmException{ KeyGenerator kg=KeyGenerator.getInstance(AL); kg.init(len); return kg.generateKey(); } public static void main(String[] args) throws Exception { //SecretKey sk=new SecretKeySpec(kl.getBytes(), "DES"); SecretKey sk=genKey(128); //---------加密 String password="tiger"; Cipher cipher=Cipher.getInstance(AL); cipher.init(Cipher.ENCRYPT_MODE, sk); //被加密以后获取的字节数组 byte[] mcontent=cipher.doFinal(password.getBytes()); //---------解密 Cipher cipher1=Cipher.getInstance(AL); cipher1.init(Cipher.DECRYPT_MODE, sk); System.out.println(new String(cipher1.doFinal(mcontent))); }
3》PBE算法(Password Base Encryption) 基于自定义口令的加解密算法 定义口令 同时还必须定义 盐和 使用盐混淆的次数
加解密过程当中 该三个参数都必须一致
//盐 用于将明文进行屡次混淆 static byte[] salt = new byte[8]; static Random r = new Random(); static int saltCount=100; static{ r.nextBytes(salt); } public static final String AL="PBEWithMD5AndDES"; /** * 生成自定义口令的秘钥 */ public static SecretKey genKey(String kl) throws Exception{ char[] klChar=kl.toCharArray(); PBEKeySpec pbe=new PBEKeySpec(klChar); SecretKeyFactory skf=SecretKeyFactory.getInstance(AL); return skf.generateSecret(pbe); } /** * 使用口令和盐进行加密 */ public static byte[] encrypt(SecretKey key,byte[] src) throws Exception{ Cipher cipher=Cipher.getInstance(AL); //使用口令 盐(100次混淆) PBEParameterSpec parameter=new PBEParameterSpec(salt, saltCount); cipher.init(Cipher.ENCRYPT_MODE, key,parameter); //被加密以后获取的字节数组 byte[] mcontent=cipher.doFinal(src); return mcontent; } /** * 使用口令和盐进行解密 盐和口令和混淆的次数都必须和加密以前一致 */ public static byte[] decrypt(SecretKey key,byte[] src) throws Exception{ Cipher cipher=Cipher.getInstance(AL); //使用口令 盐(100次混淆) PBEParameterSpec parameter=new PBEParameterSpec(salt, saltCount); cipher.init(Cipher.DECRYPT_MODE, key,parameter); //被加密以后获取的字节数组 byte[] mcontent=cipher.doFinal(src); return mcontent; } public static void main(String[] args) throws Exception { //SecretKey sk=new SecretKeySpec(kl.getBytes(), "DES"); SecretKey sk=genKey("123456"); //---------加密 String password="tiger"; byte[] mw=encrypt(sk, password.getBytes()); //---------解密 System.out.println(new String(decrypt(sk, mw))); }
四。非对称加密
1》DH算法 是一种对称加密到非对称加密的过分算法 使用DH算法生成密钥对 使用对称加密算法获取秘钥后 进行加解密 双方必须都存在公钥和私钥
模型分析
咱们以消息传递模型为例,甲方做为发送者,乙方做为接受者,分述甲乙双方如何构建密钥、交互密钥和加密数据。
首先,甲乙双方须要在收发消息前构建本身的密钥对,如图1所示。
甲乙双方构建密钥须要通过如下几个步骤:
1)由消息发送的一方构建密钥,这里由甲方构建密钥。
2)由构建密钥的一方向对方公布其公钥,这里由甲方向乙方发布公钥。
3)由消息接收的一方经过对方公钥构建自身密钥,这里由乙方使用甲方公钥构建乙方密钥。
4)由消息接收的一方向对方公布其公钥,这里由乙方向甲方公布公钥。
这里要注意的是,乙方构建本身密钥对的时候须要使用甲方公钥做为参数这是很关键的一点,若是缺乏了这一环节则没法确保甲乙双方得到同一个密钥,消息加密更无从谈起。
其次,假设甲乙双方事先约定好了用于数据加密的对称加密算法(如AES算法),并构建本地密钥(即对称加密算法中的密钥),如图2所示。
甲方须要使用本身的私钥和乙方的公钥才能构建本身的本地密钥,乙方须要使用本身的私钥和甲方的公钥才能构建本身的本地密钥。
虽然甲乙双方使用了不一样的密钥来构建本地密钥,可是甲乙两方获得的密钥实际上是一致的,后面的demo能够证实,也正是基于此,甲乙双方才能顺利地进行加密消息的传送。
最后,甲乙双方构建了本地密钥后,可按照基于对称加密算法的消息传递模型完成消息传递。如图4所示。
做为对称加密体制向非对称加密体制的一种过渡,DH算法仅仅比通常的对称加密算法多了密钥对的构建和本地密钥的构建这两项操做,而真正的数据加密/解密操做仍由对称加密算法完成。
测试代码:
public static void main(String[] args) throws Exception { // 生成DH密钥对 KeyPairGenerator kpg=KeyPairGenerator.getInstance("DH"); kpg.initialize(512); KeyPair kp=kpg.generateKeyPair(); PublicKey pk=kp.getPublic(); PrivateKey prk=kp.getPrivate(); //实例化 KeyAgreement keyAgree = KeyAgreement.getInstance("DH"); //初始化 keyAgree.init(prk); keyAgree.doPhase(pk, true); //生成本地密钥 SecretKey secretKey = keyAgree.generateSecret("DES"); //仍是使用对称方式加解密 //使用本地秘钥加密 Cipher cip=Cipher.getInstance("DES"); cip.init(Cipher.ENCRYPT_MODE, secretKey); byte[] mw=cip.doFinal("test".getBytes()); //使用本地秘钥解密 Cipher cip1=Cipher.getInstance("DES"); cip1.init(Cipher.DECRYPT_MODE, secretKey); System.out.println(new String(cip1.doFinal(mw))); }
dh算法过程:
package alao; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.util.Base64; import javax.crypto.Cipher; import javax.crypto.KeyAgreement; import javax.crypto.SecretKey; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; public class DH { public static KeyPair genernateKeyPair() throws NoSuchAlgorithmException { KeyPairGenerator kpg=KeyPairGenerator.getInstance("DH"); kpg.initialize(512); KeyPair kp=kpg.generateKeyPair(); return kp; } public static byte[] encrypt(SecretKey secretKey,byte[] data) throws Exception { // 数据加密 Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, secretKey); return cipher.doFinal(data); } public static byte[] decrypt(SecretKey secretKey,byte[] data) throws Exception { // 数据加密 Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, secretKey); return cipher.doFinal(data); } public static void main(String[] args) throws Exception { //生成A用户的公私钥对 KeyPair apair=genernateKeyPair(); PublicKey apubKey=apair.getPublic(); System.out.println("B接受到A的公钥:"+Base64.getEncoder().encodeToString(apubKey.getEncoded())); //生成B用户的公私钥对 //A和B协商生成对象加密的秘钥过程 //1 A发送公钥给B 模拟获取变量 传送b过程 getEncode获取byte数组后 转换base64 传送 DHParameterSpec dhParameterSpec = ((DHPublicKey)apair.getPublic()).getParams(); KeyPairGenerator kpg=KeyPairGenerator.getInstance("DH"); kpg.initialize(dhParameterSpec);//传入A的公钥 KeyPair bpair=kpg.generateKeyPair(); //2 B经过A的公钥和本身的公私钥 生成秘钥 //实例化 KeyAgreement keyAgree = KeyAgreement.getInstance("DH"); //传入B的私钥和A的公钥 keyAgree.init(bpair.getPrivate()); keyAgree.doPhase(apair.getPublic(), true); //生成本地密钥 SecretKey secretKey = keyAgree.generateSecret("DES"); System.out.println("此时A生成了秘钥:"+Base64.getEncoder().encodeToString(secretKey.getEncoded())); //4 A经过B的公钥和本身的公私钥 生成秘钥 //实例化 keyAgree = KeyAgreement.getInstance("DH"); //传入A的私钥和B的公钥 keyAgree.init(apair.getPrivate()); keyAgree.doPhase(bpair.getPublic(), true); //生成本地密钥 SecretKey secretKey1 = keyAgree.generateSecret("DES"); System.out.println("此时B生成了秘钥:"+Base64.getEncoder().encodeToString(secretKey1.getEncoded())); byte[] bbb=encrypt(secretKey, "hello".getBytes()); System.out.println(new String(decrypt(secretKey1, bbb))); } }
2》RSA算法 目前影响力最大的非对称加密算法 通常公钥对外公开 加密后传送给服务器 服务器使用独有的私钥解密(固然也能够私钥加密 公钥解密 通常不这样 由于谁都有公钥都能解密 加密就没有意义了) 加密的数据在传输过程是 没法破解的 秘钥对初始化大小必须是64的倍数 实际值 只能在512-1024中
public static void main(String[] args) throws Exception { // 生成RSA密钥对 KeyPairGenerator kpg=KeyPairGenerator.getInstance("RSA"); kpg.initialize(512); KeyPair kp=kpg.generateKeyPair(); PublicKey pk=kp.getPublic(); PrivateKey prk=kp.getPrivate(); //公钥加密 Cipher cip=Cipher.getInstance("RSA"); cip.init(Cipher.ENCRYPT_MODE, pk); byte[] mw=cip.doFinal("test".getBytes()); //私钥解密 Cipher cip1=Cipher.getInstance("RSA"); cip1.init(Cipher.DECRYPT_MODE, prk); System.out.println(new String(cip1.doFinal(mw))); }
RSA算法中 通常公钥和私钥都均可以调用getEncoded()转换为byte数组 使用base64编码后 存储在文件中 方便公钥分发 读取文件后须要转换对应
的公钥和私钥的方法为:
/** * 读取公钥字节数组转换为对象 * @throws Exception */ public PublicKey getPub(byte[] bt) throws Exception{ X509EncodedKeySpec x=new X509EncodedKeySpec(bt); KeyFactory fac=KeyFactory.getInstance("RSA"); return fac.generatePublic(x); } /** * 读取私钥字节数组转换为对象 * @throws Exception */ public PrivateKey getPri(byte[] bt) throws Exception{ PKCS8EncodedKeySpec x=new PKCS8EncodedKeySpec(bt); KeyFactory fac=KeyFactory.getInstance("RSA"); return fac.generatePrivate(x); }
五。数据签名(DSA)
签名是非对称加密技术和摘要技术的综合运用用户A将明文和使用私钥加密的明文摘要一块儿发送给用户B 用户B使用公钥解密出摘要 而后使用相同的摘要
算法将明文摘要 将两个摘要字符串比较若是相等 则代表内容没有被篡改
原理实现过程以下
public static void main(String[] args) throws Exception { //获取公钥和私钥 KeyPairGenerator kpg=KeyPairGenerator.getInstance("RSA"); kpg.initialize(512); KeyPair kp=kpg.generateKeyPair(); PublicKey pk=kp.getPublic(); PrivateKey prk=kp.getPrivate(); //使用私钥签名 String message="hello my name is jiaozi"; //返回的byte就能够进行传输 byte[] srcByte=sign(message.getBytes(),prk); //假设这里模拟篡改数据 确定会出现异常 或者检验不经过 srcByte[9]=10; //存在公钥的用户 接受到该srcByte 就能够验证是否被篡改 System.out.println(verify(srcByte,pk)); } /** * 签名过程 */ public static byte[] sign(byte[] content,PrivateKey pk) throws Exception{ //对明文进行摘要 MessageDigest md=MessageDigest.getInstance("MD5"); byte[] zy=md.digest(content); //对摘要进行加密 Cipher cp=Cipher.getInstance("RSA"); cp.init(Cipher.ENCRYPT_MODE, pk); byte[] enZy=cp.doFinal(zy); //要一块儿传送的数据 双方约定好使用Map Map map=new HashMap(); map.put("content", content); map.put("enZy", enZy); //传输过程使用byte数组 这里使用序列化将对象打包转换为字节数组 ByteArrayOutputStream baos=new ByteArrayOutputStream(); ObjectOutputStream oos=new ObjectOutputStream(baos); oos.writeObject(map); oos.close(); return baos.toByteArray(); } /** * 验证签名过程 */ public static boolean verify(byte[] content,PublicKey pk) throws Exception{ //将获取的数据转换为Map ByteArrayInputStream baos=new ByteArrayInputStream(content); ObjectInputStream oos=new ObjectInputStream(baos); Map map=(Map)oos.readObject(); oos.close(); //获取到明文和加密的摘要信息 byte[] srcContent=(byte[])map.get("content"); byte[] enZy=(byte[])map.get("enZy"); //使用相同的摘要算法 将明文摘要 MessageDigest md=MessageDigest.getInstance("MD5"); byte[] contentZy=md.digest(srcContent); //将加密的摘要解密 Cipher cp=Cipher.getInstance("RSA"); cp.init(Cipher.DECRYPT_MODE, pk); byte[] zy=cp.doFinal(enZy); BASE64Encoder bas=new BASE64Encoder(); if(bas.encode(contentZy).equals(bas.encode(zy))){ return true; } return false; }本身实现这个过程略显复杂 java提供了MD5WithRSA和SHA1WithRAS算法直接实现上述过程
public static void main(String[] args) throws Exception { //获取公钥和私钥 KeyPairGenerator kpg=KeyPairGenerator.getInstance("RSA"); kpg.initialize(512); KeyPair kp=kpg.generateKeyPair(); PublicKey pk=kp.getPublic(); PrivateKey prk=kp.getPrivate(); //使用私钥签名 String message="hello my name is jiaozi"; //返回的byte和明文就能够进行传输 byte[] hash=sign(message.getBytes(),prk); //存在公钥的用户 接受到该srcByte 就能够验证是否被篡改 System.out.println(verify(message.getBytes(),hash,pk)); } /** * 签名过程 返回的是加密的摘要 */ public static byte[] sign(byte[] content,PrivateKey pk) throws Exception{ Signature si=Signature.getInstance("MD5WithRSA");//或者使用SHA1WithRSA si.initSign(pk); si.update(content); return si.sign(); } /** * 验证签名过程 content表示原文可能获取原文的hash hash表示sign函数返回的加密摘要 */ public static boolean verify(byte[] content,byte[] hash,PublicKey pk) throws Exception{ Signature si=Signature.getInstance("MD5WithRSA");//或者使用SHA1WithRSA si.initVerify(pk); si.update(content); return si.verify(hash); }