Java加密解密全解

1 sha加密

安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。该算法经过加密专家多年来的发展和改进已日益完善,并被广泛使用。该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程。散列函数值可以说是对明文的一种“指纹”或是“摘要”所以对散列值的数字签名就可以视为对此明文的数字签名。

 

(Secure Hash Algorithm,SHA)
是美国国家标准技术研究所发布的国家标准FIPS PUB 180,最新的标准已经于2008年更新到FIPS PUB 180-3。其中规定了SHA-1,SHA-224,SHA-256,SHA-384,和SHA-512这几种 单向散列算法。SHA-1,SHA-224和SHA-256适用于长度不超过2^64二进制位的消息。SHA-384和SHA-512适用于长度不超过2^128二进制位的消息。

散列算法

散列是信息的提炼,通常其长度要比信息小得多,且为一个固定长度。加密性强的散列一定是不可逆的,这就意味着通过散列结果,无法推出任何部分的原始信息。任何输入信息的变化,哪怕仅一位,都将导致散列结果的明显变化,这称之为雪崩效应。散列还应该是防冲突的,即找不出具有相同散列结果的两条信息。具有这些特性的散列结果就可以用于验证信息是否被修改。
单向散列函数一般用于产生 消息摘要,密钥加密等,常见的有:
l MD5(Message Digest Algorithm 5):是RSA数据安全公司开发的一种 单向散列算法
l SHA(Secure Hash Algorithm):可以对任意长度的数据运算生成一个160位的数值;
SHA-1
在1993年,安全散列算法(SHA)由美国国家标准和技术协会(NIST)提出,并作为联邦信息处理标准(FIPS PUB 180)公布;1995年又发布了一个修订版FIPS PUB 180-1,通常称之为SHA-1。SHA-1是基于MD4算法的,并且它的设计在很大程度上是模仿MD4的。现在已成为公认的最安全的散列算法之一,并被广泛使用。

原理

SHA-1是一种 数据加密算法,该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程。
单向散列函数的安全性在于其产生散列值的操作过程具有较强的单向性。如果在输入序列中嵌入密码,那么任何人在不知道密码的情况下都不能产生正确的散列值,从而保证了其安全性。SHA将输入流按照每块512位(64个字节)进行分块,并产生20个字节的被称为信息认证代码或信息摘要的输出。
该算法输入 报文的长度不限,产生的输出是一个160位的 报文摘要。输入是按512 位的分组进行处理的。SHA-1是不可逆的、防冲突,并具有良好的雪崩效应。
通过散列算法可实现 数字签名实现,数字签名的原理是将要传送的明文通过一种函数运算(Hash)转换成报文摘要(不同的明文对应不同的报文摘要),报文摘要加密后与明文一起传送给接受方,接受方将接受的明文产生新的报文摘要与发送方的发来报文摘要解密比较,比较结果一致表示明文未被改动,如果不一致表示明文已被篡改。
MAC (信息认证代码)就是一个散列结果,其中部分输入信息是密码,只有知道这个密码的参与者才能再次计算和验证MAC码的合法性。

SHA-1与MD5的比较

因为二者均由MD4导出,SHA-1和MD5彼此很相似。相应的,他们的强度和其他特性也是相似,但还有以下几点不同:
l 对强行攻击的安全性:最显著和最重要的区别是SHA-1摘要比MD5摘要长32 位。使用强行技术,产生任何一个 报文使其摘要等于给定报摘要的难度对MD5是2^128数量级的操作,而对SHA-1则是2^160数量级的操作。这样,SHA-1对强行攻击有更大的强度。
l 对密码分析的安全性:由于MD5的设计,易受密码分析的攻击,SHA-1显得不易受这样的攻击。
l 速度:在相同的硬件上,SHA-1的运行速度比MD5慢。

 

Java 已经实现了 SHA-256 和 SHA-512 两种 Hash 算法

利用 java.security.MessageDigest 调用已经集成的 Hash 算法

创建 Encrypt 对象,并调用 SHA256 或者 SHA512 并传入要加密的文本信息,分别得到 SHA-256 或 SHA-512 两种被加密的 hash 串。

若要改为 MD5 算法,修改传入参数 strType 为 "MD5" 即可得到 MD5 加密功能。

 

[java]  view plain  copy
 
  1. /** 
  2.  * @file Encrypt.java 
  3.  * @date 2016年8月5日 
  4.  * @version 3.4.1 
  5.  * 
  6.  * Copyright (c) 2013 Sihua Tech, Inc. All Rights Reserved. 
  7.  */  
  8. package encrypt;  
  9.    
  10. /** 
  11.  *  
  12.  * 
  13.  * @author chengjian.he 
  14.  * @version  3.4, 2016年8月5日 上午10:05:37  
  15.  * @since    
  16.  */  
  17.   
  18. import java.security.MessageDigest;  
  19. import java.security.NoSuchAlgorithmException;  
  20.   
  21. public class Encrypt  
  22. {  
  23.   
  24.   /** 
  25.    * 传入文本内容,返回 SHA-256 串 
  26.    *  
  27.    * @param strText 
  28.    * @return 
  29.    */  
  30.   public String SHA256(final String strText)  
  31.   {  
  32.     return SHA(strText, "SHA-256");  
  33.   }  
  34.   
  35.   /** 
  36.    * 传入文本内容,返回 SHA-512 串 
  37.    *  
  38.    * @param strText 
  39.    * @return 
  40.    */  
  41.   public String SHA512(final String strText)  
  42.   {  
  43.     return SHA(strText, "SHA-512");  
  44.   }  
  45.   
  46.   /** 
  47.    * 字符串 SHA 加密 
  48.    *  
  49.    * @param strSourceText 
  50.    * @return 
  51.    */  
  52.   private String SHA(final String strText, final String strType)  
  53.   {  
  54.     // 返回值  
  55.     String strResult = null;  
  56.   
  57.     // 是否是有效字符串  
  58.     if (strText != null && strText.length() > 0)  
  59.     {  
  60.       try  
  61.       {  
  62.         // SHA 加密开始  
  63.         // 创建加密对象 并傳入加密類型  
  64.         MessageDigest messageDigest = MessageDigest.getInstance(strType);  
  65.         // 传入要加密的字符串  
  66.         messageDigest.update(strText.getBytes());  
  67.         // 得到 byte 類型结果  
  68.         byte byteBuffer[] = messageDigest.digest();  
  69.   
  70.         // 將 byte 轉換爲 string  
  71.         StringBuffer strHexString = new StringBuffer();  
  72.         // 遍歷 byte buffer  
  73.         for (int i = 0; i < byteBuffer.length; i++)  
  74.         {  
  75.           String hex = Integer.toHexString(0xff & byteBuffer[i]);  
  76.           if (hex.length() == 1)  
  77.           {  
  78.             strHexString.append('0');  
  79.           }  
  80.           strHexString.append(hex);  
  81.         }  
  82.         // 得到返回結果  
  83.         strResult = strHexString.toString();  
  84.       }  
  85.       catch (NoSuchAlgorithmException e)  
  86.       {  
  87.         e.printStackTrace();  
  88.       }  
  89.     }  
  90.   
  91.     return strResult;  
  92.   }  
  93.     
  94.   public static void main(String args[]){  
  95.       Encrypt ey = new Encrypt();  
  96.       System.out.println(ey.SHA("ILoveYou""MD5"));//62accaf23ac9a73c0b28765b7dfaf75a  
  97.   }  
  98. }  



 

2 Base64

Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的详细规范。Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在Java Persistence系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码具有不可读性,即所编码的数据不会被人用肉眼所直接看到。

 

然而,标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的“/”和“+”字符变为形如“%XX”的形式,而这些“%”号在存入数据库时还需要再进行转换,因为ANSI SQL中已将“%”号用作通配符。
为解决此问题,可采用一种用于URL的改进Base64编码,它不仅在末尾填充'='号,并将标准Base64中的“+”和“/”分别改成了“-”和“_”,这样就免去了在URL编解码和数据库存储时所要作的转换,避免了编码信息长度在此过程中的增加,并统一了数据库、表单等处对象 标识符的格式。
另有一种用于正则表达式的改进Base64变种,它将“+”和“/”改成了“!”和“-”,因为“+”,“*”以及前面在IRCu中用到的“[”和“]”在正则表达式中都可能具有特殊含义。
此外还有一些变种,它们将“+/”改为“_-”或“._”(用作编程语言中的标识符名称)或“.-”(用于XML中的Nmtoken)甚至“_:”(用于XML中的Name)。
其他应用
Mozilla Thunderbird和Evolution用Base64来保密电子邮件密码
Base64 也会经常用作一个简单的“加密”来保护某些数据,而真正的加密通常都比较繁琐。
垃圾讯息传播者用Base64来避过反垃圾邮件工具,因为那些工具通常都不会翻译Base64的讯息。
在LDIF档案,Base64用作编码字串。
[java]  view plain  copy
 
  1. /** 
  2.  * @file Base64.java 
  3.  * @date 2016年8月5日 
  4.  * @version 3.4.1 
  5.  * 
  6.  * Copyright (c) 2013 Sihua Tech, Inc. All Rights Reserved. 
  7.  */  
  8. package encrypt;  
  9.   
  10. import java.io.UnsupportedEncodingException;  
  11.   
  12. import Decoder.BASE64Decoder;  
  13. import Decoder.BASE64Encoder;  
  14.   
  15. /** 
  16.  *  
  17.  * 
  18.  * @author chengjian.he 
  19.  * @version  3.4, 2016年8月5日 上午10:32:23  
  20.  * @since   Yeexun 3.4 
  21.  */  
  22.   
  23. public class Base64 {  
  24.     // 加密  
  25.     public String getBase64(String str) {  
  26.         byte[] b = null;  
  27.         String s = null;  
  28.         try {  
  29.             b = str.getBytes("utf-8");  
  30.         } catch (UnsupportedEncodingException e) {  
  31.             e.printStackTrace();  
  32.         }  
  33.         if (b != null) {  
  34.             s = new BASE64Encoder().encode(b);  
  35.         }  
  36.         return s;  
  37.     }  
  38.   
  39.     // 解密  
  40.     public String getFromBase64(String s) {  
  41.         byte[] b = null;  
  42.         String result = null;  
  43.         if (s != null) {  
  44.             BASE64Decoder decoder = new BASE64Decoder();  
  45.             try {  
  46.                 b = decoder.decodeBuffer(s);  
  47.                 result = new String(b, "utf-8");  
  48.             } catch (Exception e) {  
  49.                 e.printStackTrace();  
  50.             }  
  51.         }  
  52.         return result;  
  53.     }  
  54.       
  55.     public static void main(String args[]){  
  56.         Base64 b6 = new Base64();  
  57.         System.out.println(b6.getBase64("ILoveYou"));  
  58.         System.out.println(b6.getFromBase64(b6.getBase64("ILoveYou")));  
  59.     }  
  60. }  
[java]  view plain  copy
 
  1. SUxvdmVZb3U=  
  2. ILoveYou  

 

3 Base64Encoder

一直以来Base64的加密解密都是使用sun.misc包下的BASE64EncoderBASE64Decodersun.misc.BASE64Encoder/BASE64Decoder类。这人个类是sun公司的内部方法,并没有在java api中公开过,不属于JDK标准库范畴,但在JDK中包含了该类,可以直接使用。

 

[java]  view plain  copy
 
  1. /** 
  2.  * @file Base64Encoder.java 
  3.  * @date 2016年8月5日 
  4.  * @version 3.4.1 
  5.  * 
  6.  * Copyright (c) 2013 Sihua Tech, Inc. All Rights Reserved. 
  7.  */  
  8. package encrypt;  
  9.    
  10. /** 
  11.  *  
  12.  * 
  13.  * @author chengjian.he 
  14.  * @version  3.4, 2016年8月5日 上午10:44:22  
  15.  * @since   Yeexun 3.4 
  16.  */  
  17. public class Base64Encoder {  
  18.     public static String getBASE64(String s) {    
  19.         if (s == null)    
  20.             return null;    
  21.         return (new sun.misc.BASE64Encoder()).encode(s.getBytes());    
  22.     }    
  23.     // 将 BASE64 编码的字符串 s 进行解码   解密  
  24.     public static String getFromBASE64(String s) {    
  25.         if (s == null)    
  26.             return null;    
  27.         sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();    
  28.         try {    
  29.             byte[] b = decoder.decodeBuffer(s);    
  30.             return new String(b);    
  31.         } catch (Exception e) {    
  32.             return null;    
  33.         }    
  34.     }    
  35.     public static String mTOa(Object ming){  
  36.         return Base64Encoder.getBASE64(Base64Encoder.getBASE64(Base64Encoder.getBASE64((String)ming)));  
  37.     }  
  38.     public static String aTOm(String an){  
  39.         return Base64Encoder.getFromBASE64(Base64Encoder.getFromBASE64(Base64Encoder.getFromBASE64(an)));  
  40.     }  
  41.     public static void main(String[] args) {  
  42.         String a = mTOa("100000.89".toString());  
  43.           System.out.println(a);//加密  
  44.           System.out.println(aTOm(a));//解密  
  45.     }  
  46. }  



 

 

4 RSA

 

 

RSA 公钥 加密算法是1977年由 罗纳德·李维斯特(Ron Rivest)、 阿迪·萨莫尔(Adi Shamir)和 伦纳德·阿德曼(Leonard Adleman)一起提出的。1987年首次公布,当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。
RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥 数据加密标准
今天只有短的RSA钥匙才可能被强力方式解破。到2008年为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。但在 分布式计算量子计算机理论日趋成熟的今天,RSA加密安全性受到了挑战。
RSA算法基于一个十分简单的数论事实:将两个大质数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

缺点

编辑
1)产生密钥很麻烦,受到素数产生技术的限制,因而难以做到一次一密。
2)安全性,RSA的安全性依赖于大数的因子分解,但并没有从理论上证明破译RSA的难度与大数分解难度等价,而且密码学界多数人士倾向于因子分解不是NP问题。现今,人们已能分解140多个十进制位的大素数,这就要求使用更长的密钥,速度更慢;另外,人们正在积极寻找攻击RSA的方法,如选择密文攻击,一般攻击者是将某一信息作一下伪装(Blind),让拥有私钥的实体签署。然后,经过计算就可得到它所想要的信息。实际上,攻击利用的都是同一个弱点,即存在这样一个事实:乘幂保留了输入的乘法结构:
(XM)d = Xd *Md mod n
前面已经提到,这个固有的问题来自于公钥密码系统的最有用的特征--每个人都能使用公钥。但从算法上无法解决这一问题,主要措施有两条:一条是采用好的公钥协议,保证工作过程中实体不对其他实体任意产生的信息解密,不对自己一无所知的信息签名;另一条是决不对陌生人送来的随机文档签名,签名时首先使用One-Way Hash Function对文档作HASH处理,或同时使用不同的签名算法。除了利用公共模数,人们还尝试一些利用解密指数或φ(n)等等攻击.
3)速度太慢,由于RSA 的分组长度太大,为保证安全性,n 至少也要 600 bits以上,使运算代价很高,尤其是速度较慢,较对称密码算法慢几个数量级;且随着大数分解技术的发展,这个长度还在增加,不利于数据格式的标准化。SET(Secure Electronic Transaction)协议中要求CA采用2048比特长的密钥,其他实体使用1024比特的密钥。为了速度问题,人们广泛使用单, 公钥密码结合使用的方法,优缺点互补:单钥密码加密速度快,人们用它来加密较长的文件,然后用RSA来给文件密钥加密,极好的解决了单钥密码的密钥分发问题。
 
[java]  view plain  copy
 
  1. /** 
  2.  * @file RSATool.java 
  3.  * @date 2016年8月5日 
  4.  * @version 3.4.1 
  5.  * 
  6.  * Copyright (c) 2013 Sihua Tech, Inc. All Rights Reserved. 
  7.  */  
  8. package encrypt;  
  9.    
  10. /** 
  11.  *  
  12.  * 
  13.  * @author chengjian.he 
  14.  * @version  3.4, 2016年8月5日 上午10:51:35  
  15.  * @since   Yeexun 3.4 
  16.  */  
  17. import java.io.FileInputStream;  
  18. import java.io.FileNotFoundException;  
  19. import java.io.FileOutputStream;  
  20. import java.io.IOException;  
  21. import java.io.ObjectInputStream;  
  22. import java.io.ObjectOutputStream;  
  23. import java.security.Key;  
  24. import java.security.KeyPair;  
  25. import java.security.KeyPairGenerator;  
  26. import java.security.NoSuchAlgorithmException;  
  27. import java.security.interfaces.RSAPrivateKey;  
  28. import java.security.interfaces.RSAPublicKey;  
  29.   
  30. import javax.crypto.Cipher;  
  31. import javax.crypto.NoSuchPaddingException;  
  32.   
  33. public class RSATool {  
  34.   
  35.     public static void makekeyfile(String pubkeyfile, String privatekeyfile)  
  36.             throws NoSuchAlgorithmException, FileNotFoundException, IOException {  
  37.         // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象  
  38.         KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");  
  39.         // 初始化密钥对生成器,密钥大小为1024位  
  40.         keyPairGen.initialize(1024);  
  41.         // 生成一个密钥对,保存在keyPair中  
  42.         KeyPair keyPair = keyPairGen.generateKeyPair();  
  43.   
  44.         // 得到私钥  
  45.         RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();  
  46.   
  47.         // 得到公钥  
  48.         RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  
  49.   
  50.         // 生成私钥  
  51.         ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(  
  52.                 privatekeyfile));  
  53.         oos.writeObject(privateKey);  
  54.         oos.flush();  
  55.         oos.close();  
  56.   
  57.         oos = new ObjectOutputStream(new FileOutputStream(pubkeyfile));  
  58.         oos.writeObject(publicKey);  
  59.         oos.flush();  
  60.         oos.close();  
  61.   
  62.         System.out.println("make file ok!");  
  63.     }  
  64.   
  65.     /** 
  66.      *  
  67.      * @param k 
  68.      * @param data 
  69.      * @param encrypt 
  70.      *            1 加密 0解密 
  71.      * @return 
  72.      * @throws NoSuchPaddingException 
  73.      * @throws Exception 
  74.      */  
  75.     public static byte[] handleData(Key k, byte[] data, int encrypt)  
  76.             throws Exception {  
  77.   
  78.         if (k != null) {  
  79.   
  80.             Cipher cipher = Cipher.getInstance("RSA");  
  81.   
  82.             if (encrypt == 1) {  
  83.                 cipher.init(Cipher.ENCRYPT_MODE, k);  
  84.                 byte[] resultBytes = cipher.doFinal(data);  
  85.                 return resultBytes;  
  86.             } else if (encrypt == 0) {  
  87.                 cipher.init(Cipher.DECRYPT_MODE, k);  
  88.                 byte[] resultBytes = cipher.doFinal(data);  
  89.                 return resultBytes;  
  90.             } else {  
  91.                 System.out.println("参数必须为: 1 加密 0解密");  
  92.             }  
  93.         }  
  94.         return null;  
  95.     }  
  96.   
  97.     public static void main(String[] args) throws Exception {  
  98.   
  99.         String pubfile = "d:/temp/pub.key";  
  100.         String prifile = "d:/temp/pri.key";  
  101.   
  102.          makekeyfile(pubfile, prifile);  
  103.   
  104.         ObjectInputStream ois = new ObjectInputStream(new FileInputStream(pubfile));  
  105.         RSAPublicKey pubkey = (RSAPublicKey) ois.readObject();  
  106.         ois.close();  
  107.   
  108.         ois = new ObjectInputStream(new FileInputStream(prifile));  
  109.         RSAPrivateKey prikey = (RSAPrivateKey) ois.readObject();  
  110.         ois.close();  
  111.   
  112.         // 使用公钥加密  
  113.         String msg = "~O(∩_∩)O哈哈~";  
  114.         String enc = "UTF-8";  
  115.   
  116.         // 使用公钥加密私钥解密  
  117.         System.out.println("原文: " + msg);  
  118.         byte[] result = handleData(pubkey, msg.getBytes(enc), 1);  
  119.         System.out.println("加密: " + new String(result, enc));  
  120.         byte[] deresult = handleData(prikey, result, 0);  
  121.         System.out.println("解密: " + new String(deresult, enc));  
  122.   
  123.         msg = "嚯嚯";  
  124.         // 使用私钥加密公钥解密  
  125.         System.out.println("原文: " + msg);  
  126.         byte[] result2 = handleData(prikey, msg.getBytes(enc), 1);  
  127.         System.out.println("加密: " + new String(result2, enc));  
  128.         byte[] deresult2 = handleData(pubkey, result2, 0);  
  129.         System.out.println("解密: " + new String(deresult2, enc));  
  130.   
  131.     }  
  132. }  
[java]  view plain  copy
 
  1. make file ok!  
  2. 原文: ~O(∩_∩)O哈哈~  
  3. 加密: �A N�ډB�����ym��r�C��ʇ�������U  

5 AES对称加密

加密技术可以分为对称与非对称两种.

对称加密,解密,即加密与解密用的是同一把秘钥,常用的对称加密技术有DES,AES等

而非对称技术,加密与解密用的是不同的秘钥,常用的非对称加密技术有RSA等

 

为什么要有非对称加密,解密技术呢

假设这样一种场景A要发送一段消息给B,但是又不想以明文发送,所以就需要对消息进行加密.如果采用对称加密技术,那么加密与解密用的是同一把秘钥.除非B事先就知道A的秘钥,并且保存好.这样才可以解密A发来的消息.

由于对称技术只有一把秘钥,所以秘钥的管理是一个很麻烦的问题.而非对称技术的诞生就解决了这个问题.非对称加密与解密使用的是不同的秘钥,并且秘钥对是一一对应的,即用A的私钥加密的密文只有用A的公钥才能解密.

这样的话,每个人都有两把秘钥,私钥和公钥,私钥是只有自己才知道的,不能告诉别人,而公钥是公开的,大家都可以知道.这样,当A想要发送消息给B的时候,只需要用B的公钥对消息进行加密就可以了,由于B的私钥只有B才拥有,所以A用B的公钥加密的消息只有B才能解开.而B想更换自己的秘要时也很方便,只须把公钥告诉大家就可以了.

那么,既然非对称加密如此之好,对称加密就没有存在的必要了啊,其实不然,由于非对称加密算法的开销很大,所以如果直接以非对称技术来加密发送的消息效率会很差.那么怎么办呢?解决的办法也很简单,就是把对称加密技术与非对称加密技术结合起来使用.

还是这个例子:A要发送一个消息给B.

一,A先生成一个对称秘钥,这个秘钥可以是随机生成的,

二,A用B的公钥加密第一步生成的这个对称秘钥

三,A把加密过的对称秘钥发给B

四,A用第一步生成的这个对称秘钥加密实际要发的消息

五,A把用对称秘钥加密的消息发给B

对于B

他先收到A发来的对称秘钥,这个秘钥是用B的公钥加密过的,所以B需要用自己的私钥来解密这个秘钥

然后B又收到A发来的密文,这时候用刚才解密出来的秘钥来解密密文

 

这样子的整个过程既保证了安全,又保证了效率.

 

接下来是Java实现:

我这个Java实现使用的是AES的对称加密和RSA的非对称加密(DES的对称加密实现方法和AES的是一样的,但是由于DES算法本身有缺陷,容易被破解,所以现在多用其升级版AES对称加密)

 

[java]  view plain  copy
 
  1. /** 
  2.  * @file AES.java 
  3.  * @date 2016年8月5日 
  4.  * @version 3.4.1 
  5.  * 
  6.  * Copyright (c) 2013 Sihua Tech, Inc. All Rights Reserved. 
  7.  */  
  8. package encrypt;  
  9.    
  10. import java.io.File;  
  11. import java.io.FileInputStream;  
  12. import java.io.FileOutputStream;  
  13. /** 
  14.  *  
  15.  * 
  16.  * @author chengjian.he 
  17.  * @version  3.4, 2016年8月5日 上午11:35:13  
  18.  * @since   Yeexun 3.4 
  19.  */  
  20. import java.io.IOException;  
  21. import java.io.InputStream;  
  22. import java.io.ObjectInputStream;  
  23. import java.io.OutputStream;  
  24. import java.security.InvalidKeyException;  
  25. import java.security.Key;  
  26. import java.security.NoSuchAlgorithmException;  
  27. import java.security.SecureRandom;  
  28. import java.security.interfaces.RSAPrivateKey;  
  29. import java.security.interfaces.RSAPublicKey;  
  30.   
  31. import javax.crypto.BadPaddingException;  
  32. import javax.crypto.Cipher;  
  33. import javax.crypto.IllegalBlockSizeException;  
  34. import javax.crypto.KeyGenerator;  
  35. import javax.crypto.NoSuchPaddingException;  
  36. import javax.crypto.ShortBufferException;  
  37.   
  38. public class AES {  
  39.       
  40.     private Key key;  
  41.       
  42.     /** 
  43.      * 生成AES对称秘钥 
  44.      * @throws NoSuchAlgorithmException 
  45.      */  
  46.     public void generateKey() throws NoSuchAlgorithmException {  
  47.         KeyGenerator keygen = KeyGenerator.getInstance("AES");  
  48.         SecureRandom random = new SecureRandom();  
  49.         keygen.init(random);  
  50.         this.key = keygen.generateKey();  
  51.     }  
  52.       
  53.       
  54.     /** 
  55.      * 加密 
  56.      * @param in 
  57.      * @param out 
  58.      * @throws InvalidKeyException 
  59.      * @throws ShortBufferException 
  60.      * @throws IllegalBlockSizeException 
  61.      * @throws BadPaddingException 
  62.      * @throws NoSuchAlgorithmException 
  63.      * @throws NoSuchPaddingException 
  64.      * @throws IOException 
  65.      */  
  66.     public void encrypt(InputStream in, OutputStream out) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException {  
  67.         this.crypt(in, out, Cipher.ENCRYPT_MODE);  
  68.     }  
  69.       
  70.     /** 
  71.      * 解密 
  72.      * @param in 
  73.      * @param out 
  74.      * @throws InvalidKeyException 
  75.      * @throws ShortBufferException 
  76.      * @throws IllegalBlockSizeException 
  77.      * @throws BadPaddingException 
  78.      * @throws NoSuchAlgorithmException 
  79.      * @throws NoSuchPaddingException 
  80.      * @throws IOException 
  81.      */  
  82.     public void decrypt(InputStream in, OutputStream out) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException {  
  83.         this.crypt(in, out, Cipher.DECRYPT_MODE);  
  84.     }  
  85.   
  86.     /** 
  87.      * 实际的加密解密过程 
  88.      * @param in 
  89.      * @param out 
  90.      * @param mode 
  91.      * @throws IOException 
  92.      * @throws ShortBufferException 
  93.      * @throws IllegalBlockSizeException 
  94.      * @throws BadPaddingException 
  95.      * @throws NoSuchAlgorithmException 
  96.      * @throws NoSuchPaddingException 
  97.      * @throws InvalidKeyException 
  98.      */  
  99.     public void crypt(InputStream in, OutputStream out, int mode) throws IOException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {  
  100.         Cipher cipher = Cipher.getInstance("AES");  
  101.         cipher.init(mode, this.key);  
  102.           
  103.         int blockSize = cipher.getBlockSize();  
  104.         int outputSize = cipher.getOutputSize(blockSize);  
  105.         byte[] inBytes = new byte[blockSize];  
  106.         byte[] outBytes = new byte[outputSize];  
  107.           
  108.         int inLength = 0;  
  109.         boolean more = true;  
  110.         while (more) {  
  111.             inLength = in.read(inBytes);  
  112.             if (inLength == blockSize) {  
  113.                 int outLength = cipher.update(inBytes, 0, blockSize, outBytes);  
  114.                 out.write(outBytes, 0, outLength);  
  115.             } else {  
  116.                 more = false;  
  117.             }  
  118.         }  
  119.         if (inLength > 0)  
  120.             outBytes = cipher.doFinal(inBytes, 0, inLength);  
  121.         else  
  122.             outBytes = cipher.doFinal();  
  123.         out.write(outBytes);  
  124.         out.flush();  
  125.     }  
  126.   
  127.     public void setKey(Key key) {  
  128.         this.key = key;  
  129.     }  
  130.   
  131.     public Key getKey() {  
  132.         return key;  
  133.     }  
  134.       
  135.     public static void main(String[] args) throws Exception {  
  136.         AES aes = new AES();  
  137.         aes.generateKey();  
  138.         File file = new File("D:/aa.jpg");    
  139.         FileInputStream in = new FileInputStream(file);   
  140.         File file1 = new File("D:/temp/pub.key");    
  141.         FileOutputStream out = new FileOutputStream(file1);    
  142.         aes.encrypt(in, out);  
  143.         aes.decrypt(in, out);  
  144.     }  
  145.   
  146. }  

猜你喜欢

转载自kingding.iteye.com/blog/2391878