JAVA加密方案(AES/RSA/MD5)

JAVA加密方案(AES/RSA/MD5)

  1. 對稱加密和非對稱加密

對稱加密指的就是加密和解密使用同一個祕鑰。對稱加密只有一個祕鑰,作爲私鑰。 
常見的對稱加密算法:DES,AES,3DES等等。

非對稱加密指的是加密和解密使用不同的祕鑰,一把作爲公開的公鑰,另一把作爲私鑰。公鑰加密的信息,只有私鑰才能解密。私鑰加密的信息,只有公鑰才能解密。 
常見的非對稱加密算法:RSA,ECC

對稱加密和非對稱加密不能說誰好誰不好,主要是要看應用場景,如果可以用對稱加密解決的問題,那麼就沒有必要用非對稱進行加密。因爲非對稱加密的開銷一般比較大,例如RSA 1024的安全性,與AES128的安全性是相當的。

 

  1. 對稱加密算法AES

對稱算法以DES和AES爲代表性,其底層原理也有相似之處,都有一個S盒子(可不可以叫做黑盒子),然後通過交換和替換等複雜變換,達到加密的效果。對稱加密算法有個非常重要的特性,就是加密和解密可以互逆。總之呢,算法還是挺複雜的,不過,作爲程序員的我們,可以不去關心這些,我們只要知道,我們可以用他們來做加密。加密的安全性取決於密鑰的長度,密鑰越長,越安全如密鑰長爲128的AES,我們稱之爲AES128,密鑰爲256的AES,我們稱之爲AES256。當前計算機的計算能力下,128的AES基本是安全的,256完全可以放心了。

好了,用java代碼來實現AES加解密吧,這個纔是我們關心的。

加密方法:

public static final String  VIPARA    =  "20179TELIGRR1234";//初始化向量 16位
private static final String DEFAULT_ENCODING = "utf-8";//編碼方式
/**
 * AES加密
 * @param content 待加密的內容
 * @param encryptKey 加密密鑰
 * @return 加密後的byte[]
 * @throws Exception
 */
public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {

    IvParameterSpec zeroIv = new IvParameterSpec(VIPARA.getBytes(DEFAULT_ENCODING));
    SecretKeySpec keySpec = new SecretKeySpec(encryptKey.getBytes(DEFAULT_ENCODING),"AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE,keySpec,zeroIv);
    return cipher.doFinal(content.getBytes(DEFAULT_ENCODING));
}

 

這個加密方法傳入參數是文本內容以及密鑰,注意密鑰長度要爲16byte(與上述的初始化向量是一樣的)。

解密方法類似:

/**
 * AES解密
 * @param encryptBytes 待解密的byte[]
 * @param decryptKey 解密密鑰
 * @return 解密後的String
 * @throws Exception
 */
public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {

    IvParameterSpec zeroIv = new IvParameterSpec(VIPARA.getBytes(DEFAULT_ENCODING));
    SecretKeySpec keySpec = new SecretKeySpec(decryptKey.getBytes(DEFAULT_ENCODING),"AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE,keySpec,zeroIv);
    byte[] decryptBytes = cipher.doFinal(encryptBytes);
    return new String(decryptBytes);
}

上訴加密和解密方法,還是有挺多與密碼學相關的知識的,比如初始化向量,以及加密的CBC模式,不過其實,作爲我們應用層的,可以不去關心這些底層的實現,使用就可以完成我們的目標了。不過,使用舊了,自然而且,我們會好奇,它到底怎麼實現的?它爲什麼就是安全的?到時,我們就可以深入去學習了,希望大家這種好奇來的越早越好。

有了上訴的加密和解密方法,我們就可以來進行加解密了,示例如下:

byte[] data1 = aesEncryptToBytes("DW1234567fddddddddddfffffffffff8","aaaaaaaaaaaaaaaa");
String data1Str = bytesToHexString(data1);
System.out.println("密文:"+data1Str);
String  result1 = aesDecryptByBytes(hexStringToBytes(data1Str),"aaaaaaaaaaaaaaaa");
System.out.println("明文:"+result1);

這上面應用到兩個函數bytesToHexStringhexStringToBytes這個其實不是加解密的環節,而是編解碼的環節了,它們的作用就是把字節轉成16進制數,以及它的逆操作,具體函數如下:

/**
 * 字節數組轉十六進制數
 *
 * @param b
 * @return
 */
public static String bytesToHexString(byte[] b) {
   if(b == null || b.length <= 0){
      return null;
   }
   StringBuilder sb = new StringBuilder(b.length * 2);
   for (int i = 0; i < b.length; i++) {
      sb.append(HEXCHAR[(b[i] & 0xf0) >>> 4]);
      sb.append(HEXCHAR[b[i] & 0x0f]);
   }
   return sb.toString();
}

/**
 * 16進制串字符轉字節
 *  和 bytesToHexString 互逆
 * @param hexString
 * @return
    */
public static byte[] hexStringToBytes(String hexString){
   if(hexString == null || hexString.length() <=  0){
      return null;
   }
   byte[] data = new byte[hexString.length()/2];
   for(int i=0;i< hexString.length();){
      char high = hexString.charAt(i);
      i++;
      char low = hexString.charAt(i);
      data[i/2] = hexToByte(high,low);
      i++;
   }
   return data;
}

 

 

  1. 非對稱加密算法 RSA

非對稱加密算法都有一個數學依據的,比如RSA的數學依據總結起來可以說:兩個質數相乘得到一個合數是很容易的,而兩個大質數相乘得到的大數難以被因式分解。

對於非對稱加密,你首先先要一對密鑰,一個公鑰,用來發布出去的,一個私鑰,只能自己擁有的。基於java的RSA密鑰生成方法如下:

 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");

keyPairGenerator.initialize(1024);// 祕鑰長度爲1024可以改成2048等

KeyPair keyPair = keyPairGenerator.generateKeyPair();

PublicKey publicKey = keyPair.getPublic();//公鑰

PrivateKey privateKey = keyPair.getPrivate();//私鑰

現在公鑰和私鑰都有了,首先我們需要把它們保存起來,可以直接保存爲文件,或者生成字符串等等,下面我把他們保存爲文件

               byte[] publicKeyByte = publicKey.getEncoded();

 byte[] privateKeyByte = privateKey.getEncoded();

   BufferedOutputStream pukout = new BufferedOutputStream(

 new FileOutputStream("src/com/lh/test/publicKey.key"));

 BufferedOutputStream prkout = new BufferedOutputStream(

 new FileOutputStream("src/com/lh/test/privateKey.key"));

 pukout.write(publicKeyByte);

 prkout.write(privateKeyByte);

 pukout.flush();

 prkout.flush();

保存的文件讀出如下:

       BufferedInputStream pukIn = new BufferedInputStream(

new FileInputStream("src/com/lh/test/publicKey.key"));

BufferedInputStream prkIn = new BufferedInputStream(

new FileInputStream("src/com/lh/test/privateKey.key"));

byte[] puKeyByte = new byte[1024];

byte[] prKeyByte = new byte[1024];

pukIn.read(puKeyByte, 0, 1024);

prkIn.read(prKeyByte, 0, 1024);

X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(

puKeyByte);// 公鑰

KeyFactory keyFactory = KeyFactory.getInstance("RSA");

PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(

prKeyByte);// 私鑰

PrivateKey privateKey = keyFactory

.generatePrivate(pkcs8EncodedKeySpec);

現在我們通過文件讀取(或其它途徑)拿到了公鑰和私鑰,我們就可以用來使用了,如果公鑰加密,那麼需要私鑰進行解密,反之亦然。

公鑰加密:

  Cipher cipher = Cipher.getInstance("RSA");

cipher.init(Cipher.ENCRYPT_MODE, publicKey);

byte[] resultbytes = cipher.doFinal(plainBytes);

//plainBytes 要加密的字節數組

私鑰解密:

Cipher cipher = Cipher.getInstance("RSA");

cipher.init(Cipher.DECRYPT_MODE, privateKey);

byte[] deBytes = cipher.doFinal(ciperBytes);

//ciperBytes要解密的字節數組

 

有了byte[],就可以根據上面的hexStringToBytesbytesToHexString方法,進行字節數組與字符串的轉換,便於傳輸。

 

  1. 安全哈希函數MD5

實際開發中,經常可以聽到我們密碼字段是用MD5加密的,其實這種說法是不對的,MD5(安全哈希函數)只是一串數據指紋,只能用來做數據驗證。即,只能單向認證,只能從明文單向計算出MD5值,而不能從MD5值計算出明文。

安全哈希函數常用於驗證信息完整性以及驗證信息等,比如協議的完整性校驗、驗證密碼。

安全哈希函數有MD5/SHA1/SHA2/SHA3,現在推薦使用SHA2/SHA3

Java實現MD5如下

private static final String md5Key = "MD5";
private static final String defaultEncoding = "utf-8";

 

 

/**
 * 以字符串爲輸入輸出的Md5
 * @param dataStr
 * @return
    */
public static String md5Encrypt(String dataStr){
   try {
      MessageDigest md5 = MessageDigest.getInstance(md5Key);
      byte [] data = md5.digest(dataStr.getBytes(defaultEncoding));
      return bytesToHexString(data);
   } catch (Exception e) {
      return null;
   }
}

 

 

發佈了42 篇原創文章 · 獲贊 5 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章