1、加密概述:

加密就是是以某種特殊的演算法改變原有的資訊資料,使得未授權的使用者即使以獲得了加密的資訊,但因不知解密方式,仍無法瞭解資訊的內容。大體上又分為雙向加密和單向加密。

2、單項加密

2.1、概述:

  單向加密又稱為不可逆加密演算法,在加密過程中不使用金鑰,明文由系統加密成密文,密文無法破解,一般都是採用驗證的方式,具體是:在驗證過程中,重新輸入明文,並經過同樣的加密演算法後,得到相同的密文。單向加密廣泛用於口令加密。

2.2、特點:

(1)對同一訊息反覆執行加密得到相同的密文;

(2)加密演算法生成密文不可預見;

(3)不可逆,一般不能通過密文獲取明文

2.3、類別

2.3.1、MD5加密

2.3.1.1、概述:

  MD5的全稱是Message-Digest Algorithm 5(資訊-摘要演算法),在90年代初由MIT Laboratory for Computer Science和RSA Data Security Inc的Ronald L. Rivest開發出來,經MD2、MD3和MD4發展而來。

  MD5用於確保資訊傳輸完整一致。是計算機廣泛使用的雜湊演算法之一(又譯摘要演算法雜湊演算法),主流程式語言普遍已有MD5實現。將資料(如漢字)運算為另一固定長度值,是雜湊演算法的基礎原理,MD5的前身有MD2、MD3MD4

  MD5的作用是讓大容量資訊在用數字簽名軟體簽署私人金鑰前被"壓縮"成一種保密的格式(就是把一個任意長度的位元組串變換成一定長的十六進位制數字串)。

2.3.1.2、演算法原理:

  對MD5演算法簡要的敘述可以為:MD5以512位分組來處理輸入的資訊,且每一分組又被劃分為16個32位子分組,經過了一系列的處理後,演算法的輸出由四個32位分組組成,將這四個32位分組級聯後將生成一個128位雜湊值。

  在MD5演算法中,首先需要對資訊進行填充,使其位長對512求餘的結果等於448。因此,資訊的位長(Bits Length)將被擴充套件至N*512+448,N為一個非負整數,N可以是零。填充的方法如下,在資訊的後面填充一個1和無數個0,直到滿足上面的條件時才停止用0對資訊的填充。然後,在這個結果後面附加一個以64位二進位制表示的填充前資訊長度。經過這兩步的處理,資訊的位長=N*512+448+64=(N+1)*512,即長度恰好是512的整數倍。這樣做的原因是為滿足後面處理中對資訊長度的要求。

2.3.1.3、java程式碼中使用MD5加密

       /**
* md5計算.
*
* @param datas
* 待計算的資料
* @return 計算結果
*/
public static byte[] md5(byte[] datas) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5");
md.reset();
md.update(datas);
return md.digest();
} catch (Exception e) {
log.error("MD5計算失敗", e);
return null;
}
}

2.3.2、SHA加密

2.3.2.1、概述

  其思想是接收一段明文,然後以一種不可逆的方式將它轉換成一段(通常更小)的密文。可以簡單的理解為取一串輸入碼(稱為預對映或資訊),並把他們轉化為長度較短、位數固定的輸出序列的過程。

  安全雜湊演算法SHA(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二進位制位的訊息。

2.3.2.2、原理

  SHA-1是一種資料加密演算法,該演算法的思想是接收一段明文,然後以一種不可逆的方式將它轉換成一段(通常更小)密文,也可以簡單的理解為取一串輸入碼(稱為預對映或資訊),並把它們轉化為長度較短、位數固定的輸出序列即雜湊值(也稱為資訊摘要或資訊認證程式碼)的過程。

  單向雜湊函式的安全性在於其產生雜湊值的操作過程具有較強的單向性。如果在輸入序列中嵌入密碼,那麼任何人在不知道密碼的情況下都不能產生正確的雜湊值,從而保證了其安全性。SHA將輸入流按照每塊512位(64個位元組)進行分塊,併產生20個位元組的被稱為資訊認證程式碼或資訊摘要的輸出。

該演算法輸入報文的長度不限,產生的輸出是一個160位的報文摘要。輸入是按512 位的分組進行處理的。SHA-1是不可逆的、防衝突,並具有良好的雪崩效應。

通過雜湊演算法可實現數字簽名實現,數字簽名的原理是將要傳送的明文通過一種函式運算(Hash)轉換成報文摘要(不同的明文對應不同的報文摘要),報文摘要加密後與明文一起傳送給接受方,接受方將接受的明文產生新的報文摘要與傳送方的發來報文摘要解密比較,比較結果一致表示明文未被改動,如果不一致表示明文已被篡改。

MAC (資訊認證程式碼)就是一個雜湊結果,其中部分輸入資訊是密碼,只有知道這個密碼的參與者才能再次計算和驗證MAC碼的合法性。

2.3.2.3、java中的SHA實現

      /**
* SHA1簽名
* @param paramStr 要加簽的字串
* @return
*/
public static String SHA1(String paramStr) {
MessageDigest alg;
String result = "";
String tmp = "";
try {
alg = MessageDigest.getInstance("SHA-1");
alg.update(paramStr.getBytes());
byte[] bts = alg.digest(); for (int i = 0; i < bts.length; i++) {
tmp = (Integer.toHexString(bts[i] & 0xFF));
if (tmp.length() == 1)
result += "0";
result += tmp;
}
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} return result;
}

  

2.4、SHA與MD5的區別:

(1)對強行攻擊的安全性:最顯著和最重要的區別是:SHA-1的摘要比MD5的摘要長32位。使用強行技術,產生任何一個報文使其摘要等於給定摘要的難度對MD5是是2^128數量級的操作,而對SHA-1則是2^160數量級的操作。這樣,SHA-1對強行攻擊有更大的強度。

(2)對密碼分析的安全性:由於MD5的設計,易受密碼分析的攻擊,SHA-1不易受這樣的攻擊。

3、雙向加密

3.1概述

大體意思是明文加密後形成密文,可以通過演算法還原成明文。

3.2分類

3.2.1對稱加密

3.2.1.1概述

  對稱加密演算法是應用較早的加密演算法,技術成熟。在對稱加密演算法中,資料發信方將明文(原始資料)和加密金鑰(mi yue)一起經過特殊加密演算法處理後,使其變成複雜的加密密文傳送出去。收信方收到密文後,若想解讀原文,則需要使用加密用過的金鑰及相同演算法的逆演算法對密文進行解密,才能使其恢復成可讀明文。在對稱加密演算法中,使用的金鑰只有一個,發收信雙方都使用這個金鑰對資料進行加密和解密,這就要求解密方事先必須知道加密金鑰。

3.2.1.2特點

優點:

    (1)演算法公開,計算量小、加密速度快、加密效率高

缺點:

(1)交易雙方都使用同樣的金鑰,安全性得不到保證

(2)每對使用者每次使用對稱加密演算法時,都需要使用其他人不知道的唯一金鑰,這會使得發收信雙方所擁有的鑰匙數量呈幾何級數增長,金鑰管理成為使用者的負擔。對稱加密演算法在分散式網路系統上使用較為困難,主要是因為金鑰管理困難,使用成本較高。

3.2.1.3常用對稱加密演算法

  基於“對稱金鑰”的加密演算法比較常用的主要有:DES 、 3DES 、AES

(1)DES

概述:

  DES演算法全稱為Data Encryption Standard,即資料加密演算法,它是IBM公司於1975年研究成功並公開發表的。DES演算法的入口引數有三個:Key、Data、Mode。其中Key為8個位元組共64位,是DES演算法的工作金鑰;Data也為8個位元組64位,是要被加密或被解密的資料;Mode為DES的工作方式,有兩種:加密或解密。

演算法原理:

   DES演算法的入口引數有三個:Key、Data、Mode。

  (1)Key為8個位元組共64位,是DES演算法的工作金鑰;

  (2)Data也為8個位元組64位,是要被加密或被解密的資料;

  (3)Mode為DES的工作方式,有兩種:加密或解密。

  DES演算法是這樣工作的:如Mode為加密,則用Key 去把資料Data進行加密, 生成Data的密碼形式(64位)作為DES的輸出結果;如Mode為解密,則用Key去把密碼形式的資料Data解密,還原為Data的明碼形式(64位)作為DES的輸出結果。在通訊網路的兩端,雙方約定一致的Key,在通訊的源點用Key對核心資料進行DES加密,然後以密碼形式在公共通訊網(如電話網)中傳輸到通訊網路的終點,資料到達目的地後,用同樣的Key對密碼資料進行解密,便再現了明碼形式的核心資料。這樣,便保證了核心資料(如PIN、MAC等)在公共通訊網中傳輸的安全性和可靠性。來源:

連結:https://www.zhihu.com/question/36767829/answer/68911532

演算法應用: 

  目前在國內,隨著三金工程尤其是金卡工程的啟動,DES演算法在POS、ATM、磁卡及智慧卡(IC卡)、加油站、高速公路收費站等領域被廣泛應用,以此來實現關鍵資料的保密,如信用卡持卡人的PIN的加密傳輸,IC卡與POS間的雙向認證、金融交易資料包的MAC校驗等,均用到DES演算法。

java程式碼實現:

       /**
* 3DES加密
*
* @param key
* 金鑰資訊
* @param content
* 待加密資訊
* @return
* @throws Exception
*/
public static byte[] encode3DES(byte[] key, byte[] content) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// 不是8的倍數的,補足
if (key.length % 8 != 0) {
int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0);
byte[] temp = new byte[groups * 8];
Arrays.fill(temp, (byte) 0);
System.arraycopy(key, 0, temp, 0, key.length);
key = temp;
}
// 長度為16位,轉換成24位的金鑰
if (key.length == 16) {
byte[] temp = new byte[24];
System.arraycopy(key, 0, temp, 0, key.length);
System.arraycopy(key, 0, temp, key.length, temp.length - key.length);
key = temp;
} // 不是8的倍數的,補足
byte[] srcBytes = content;
if (srcBytes.length % 8 != 0) {
int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0);
srcBytes = new byte[groups * 8];
Arrays.fill(srcBytes, (byte) 0);
System.arraycopy(content, 0, srcBytes, 0, content.length);
} SecretKey deskey = new SecretKeySpec(key, "DESede");
Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, deskey);
byte[] temp = cipher.doFinal(srcBytes);
byte[] tgtBytes = new byte[content.length];
System.arraycopy(temp, 0, tgtBytes, 0, tgtBytes.length);
return tgtBytes;
} /**
* 3DES解密
*
* @param key
* 金鑰
* @param content
* 待解密資訊
* @return
* @throws Exception
*/
public static byte[] decode3DES(byte[] key, byte[] content) throws Exception {
// 不是8的倍數的,補足
if (key.length % 8 != 0) {
int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0);
byte[] temp = new byte[groups * 8];
Arrays.fill(temp, (byte) 0);
System.arraycopy(key, 0, temp, 0, key.length);
key = temp;
}
// 長度為16位,轉換成24位的金鑰
if (key.length == 16) {
byte[] temp = new byte[24];
System.arraycopy(key, 0, temp, 0, key.length);
System.arraycopy(key, 0, temp, key.length, temp.length - key.length);
key = temp;
} // 不是8的倍數的,補足
byte[] srcBytes = content;
if (srcBytes.length % 8 != 0) {
int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0);
srcBytes = new byte[groups * 8];
Arrays.fill(srcBytes, (byte) 0);
System.arraycopy(content, 0, srcBytes, 0, content.length);
} SecretKey deskey = new SecretKeySpec(key, "DESede");
Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, deskey);
byte[] tgtBytes = cipher.doFinal(srcBytes);
return tgtBytes;
} /**
* DES加密
*
* @param key
* 金鑰資訊
* @param content
* 待加密資訊
* @return
* @throws Exception
*/
public static byte[] encodeDES(byte[] key, byte[] content) throws Exception {
// 不是8的倍數的,補足
if (key.length % 8 != 0) {
int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0);
byte[] temp = new byte[groups * 8];
Arrays.fill(temp, (byte) 0);
System.arraycopy(key, 0, temp, 0, key.length);
key = temp;
} // 不是8的倍數的,補足
byte[] srcBytes = content;
if (srcBytes.length % 8 != 0) {
int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0);
srcBytes = new byte[groups * 8];
Arrays.fill(srcBytes, (byte) 0);
System.arraycopy(content, 0, srcBytes, 0, content.length);
} IvParameterSpec iv = new IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 });
SecureRandom sr = new SecureRandom();
DESKeySpec dks = new DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv, sr);
byte[] tgtBytes = cipher.doFinal(srcBytes);
return tgtBytes;
} /**
* DES解密
*
* @param key
* 金鑰資訊
* @param content
* 待加密資訊
* @return
* @throws Exception
*/
public static byte[] decodeDES(byte[] key, byte[] content) throws Exception {
// 不是8的倍數的,補足
if (key.length % 8 != 0) {
int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0);
byte[] temp = new byte[groups * 8];
Arrays.fill(temp, (byte) 0);
System.arraycopy(key, 0, temp, 0, key.length);
key = temp;
}
// 不是8的倍數的,補足
byte[] srcBytes = content;
if (srcBytes.length % 8 != 0) {
int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0);
srcBytes = new byte[groups * 8];
Arrays.fill(srcBytes, (byte) 0);
System.arraycopy(content, 0, srcBytes, 0, content.length);
} IvParameterSpec iv = new IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 });
SecureRandom sr = new SecureRandom();
DESKeySpec dks = new DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv, sr);
byte[] tgtBytes = cipher.doFinal(content);
return tgtBytes;
}

 (2)3DES

概述:

  3DES(或稱為Triple DES)是三重資料加密演算法(TDEA,Triple Data Encryption Algorithm)塊密碼的通稱。它相當於是對每個資料塊應用三次DES加密演算法。由於計算機運算能力的增強,原版DES密碼的金鑰長度變得容易被暴力破解;3DES即是設計用來提供一種相對簡單的方法,即通過增加DES的金鑰長度來避免類似的攻擊,而不是設計一種全新的塊密碼演算法

演算法原理:

  3DES(即Triple DES)是DES向AES過渡的加密演算法(1999年,NIST將3-DES指定為過渡的加密標準),加密演算法,其具體實現如下:設Ek()和Dk()代表DES演算法的加密和解密過程,K代表DES演算法使用的金鑰,M代表明文,C代表密文,這樣:
(1)3DES加密過程為:C=Ek3(Dk2(Ek1(M)))
(2)3DES解密過程為:M=Dk1(EK2(Dk3(C)))
java程式碼實現:
 package cn.mars.app.txn.bjyl;

 import java.security.Key;
import java.security.Security; import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec; /**
* 3DES加密
*
* @version 1.0
* @author
*
*/
public class DesUtil { /**
* 金鑰演算法
*/
public static final String KEY_ALGORITHM = "DESede";
public static final String CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding";
private static String strDefaultKey = "national";
private Cipher encryptCipher = null;
private Cipher decryptCipher = null; public DesUtil() throws Exception {
this(strDefaultKey);
} public static String byteArr2HexStr(byte[] arrB) throws Exception {
int iLen = arrB.length;
StringBuffer sb = new StringBuffer(iLen * 2);
for (int i = 0; i < iLen; i++) {
int intTmp = arrB[i];
while (intTmp < 0) {
intTmp = intTmp + 256;
}
if (intTmp < 16) {
sb.append("0");
}
sb.append(Integer.toString(intTmp, 16));
}
return sb.toString();
} public static byte[] hexStr2ByteArr(String strIn) throws Exception {
byte[] arrB = strIn.getBytes();
int iLen = arrB.length;
byte[] arrOut = new byte[iLen / 2];
for (int i = 0; i < iLen; i = i + 2) {
String strTmp = new String(arrB, i, 2);
arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
}
return arrOut;
}
/**
* @param strKey
* @throws Exception
*/
public DesUtil(String strKey) throws Exception {
Security.addProvider(new com.sun.crypto.provider.SunJCE());
Key key = getKey(StringUtil.hexStringToByteArray(strKey));
encryptCipher = Cipher.getInstance("DES/ECB/NoPadding");
encryptCipher.init(Cipher.ENCRYPT_MODE, key);
decryptCipher = Cipher.getInstance("DES/ECB/NoPadding");
decryptCipher.init(Cipher.DECRYPT_MODE, key);
} public byte[] encrypt(byte[] arrB) throws Exception {
return encryptCipher.doFinal(arrB);
} public String encrypt(String strIn) throws Exception {
return byteArr2HexStr(encrypt(strIn.getBytes()));
} public byte[] decrypt(byte[] arrB) throws Exception {
return decryptCipher.doFinal(arrB);
} public String decrypt(String strIn) throws Exception {
return new String(decrypt(hexStr2ByteArr(strIn)));
} private Key getKey(byte[] arrBTmp) throws Exception {
byte[] arrB = new byte[8];
for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
arrB[i] = arrBTmp[i];
}
Key key = new javax.crypto.spec.SecretKeySpec(arrB, "DES");
return key;
} public static String printbytes(String tip, byte[] b) {
String ret = "";
String str;
System.out.println(tip);
for (int i = 0; i < b.length; i++) {
str = Integer.toHexString((int) (b[i] & 0xff));
if (str.length() == 1)
str = "0" + str;
System.out.print(str + " ");
ret = ret + str + " ";
}
return ret;
}
/**
* 加密
* @param data
* @param key
* @return
* @throws Exception
* @author yangxing
* 2014-7-22
*/
public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
Key k = toKey(key);// 還原金鑰
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, k);
return cipher.doFinal(data);
}
/**
* 解密
*
* @param data 待解密資料
* @param key 金鑰
* @return byte[] 解密資料
*/
public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
// 還原金鑰
Key k = toKey(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
// 初始化,設定為解密模式
cipher.init(Cipher.DECRYPT_MODE, k);
// 執行操作
return cipher.doFinal(data);
}
/**
* 轉換金鑰
* @param key 二進位制金鑰
* @return key 金鑰
*/
public static Key toKey(byte[] key) throws Exception {
DESedeKeySpec dks = new DESedeKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
return keyFactory.generateSecret(dks);
} public static void main(String[] args) {
try {
byte[] data = { 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 };
DesUtil des1 = new DesUtil("498F456AC9D9CBA0");
printbytes("data", des1.encrypt(data));
} catch (Exception e) {
e.printStackTrace();
}
}
}

(3)AES

概述:
  高階加密標準(英語:Advanced Encryption Standard,縮寫:AES),在密碼學中又稱Rijndael加密法,是美國聯邦政府採用的一種區塊加密標準。這個標準用來替代原先的DES,已經被多方分析且廣為全世界所使用。經過五年的甄選流程,高階加密標準由美國國家標準與技術研究院(NIST)於2001年11月26日釋出於FIPS PUB 197,並在2002年5月26日成為有效的標準。2006年,高階加密標準已然成為對稱金鑰加密中最流行的演算法之一。
原理:
  AES加密過程涉及到4種操作:位元組替代(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)和輪金鑰加(AddRoundKey)。解密過程分別為對應的逆操作。由於每一步操作都是可逆的,按照相反的順序進行解密即可恢復明文。加解密中每輪的金鑰分別由初始金鑰擴充套件得到。演算法中16位元組的明文、密文和輪金鑰都以一個4x4的矩陣表示。

java程式碼實現:

 package cn.mars.app.txn.wanglian;

 import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security; import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; import cfca.util.Base64; /**
* java實現AES256加密解密
* @author xiaoqiang
*
*/ public class AES256Util { public static byte[] encrypt(String content, String password) {
try {
// "AES":請求的金鑰演算法的標準名稱
KeyGenerator kgen = KeyGenerator.getInstance("AES");
// 256:金鑰生成引數;securerandom:金鑰生成器的隨機源
SecureRandom securerandom = new SecureRandom(tohash256Deal(password));
kgen.init(256, securerandom);
// 生成祕密(對稱)金鑰
SecretKey secretKey = kgen.generateKey();
// 返回基本編碼格式的金鑰
byte[] enCodeFormat = secretKey.getEncoded();
// 根據給定的位元組陣列構造一個金鑰。enCodeFormat:金鑰內容;"AES":與給定的金鑰內容相關聯的金鑰演算法的名稱
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
// 將提供程式新增到下一個可用位置
Security.addProvider(new BouncyCastleProvider());
// 建立一個實現指定轉換的 Cipher物件,該轉換由指定的提供程式提供。
// "AES/ECB/PKCS7Padding":轉換的名稱;"BC":提供程式的名稱
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC"); cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] byteContent = content.getBytes("utf-8");
byte[] cryptograph = cipher.doFinal(byteContent);
byte[] encode = Base64.encode(cryptograph); return encode;
} catch (Exception e) {
e.printStackTrace();
}
return null;
} public static String decrypt(byte[] cryptograph, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom securerandom = new SecureRandom(tohash256Deal(password));
kgen.init(256, securerandom);
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); cipher.init(Cipher.DECRYPT_MODE, key);
byte[] content = cipher.doFinal(Base64.decode(cryptograph));
return new String(content);
} catch (Exception e) {
e.printStackTrace();
}
return null;
} public static String parseByte2HexStr(byte buf[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
} /*
* private static byte[] parseHexStr2Byte(String hexStr) { if
* (hexStr.length() < 1) return null; byte[] result = new
* byte[hexStr.length()/2]; for (int i = 0;i< hexStr.length()/2; i++) { int
* high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16); int low =
* Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16); result[i] = (byte)
* (high * 16 + low); } return result; }
*/ private static byte[] tohash256Deal(String datastr) {
try {
MessageDigest digester = MessageDigest.getInstance("SHA-256");
digester.update(datastr.getBytes());
byte[] hex = digester.digest();
return hex;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e.getMessage());
}
} /**
* 生成隨機金鑰
*
* @param size
* 位數
* @return
*/
public static String generateRandomKey(int size) {
StringBuilder key = new StringBuilder();
String chars = "0123456789ABCDEF";
for (int i = 0; i < size; i++) {
int index = (int) (Math.random() * (chars.length() - 1));
key.append(chars.charAt(index));
}
return key.toString();
} public static void main(String[] args) { String content = "123456";
String password = generateRandomKey(32);
System.out.println("明文:" + content);
System.out.println("key:" + password); byte[] encryptResult = AES256Util.encrypt(content, password);
System.out.println(encryptResult);
System.out.println("密文:" + AES256Util.parseByte2HexStr(encryptResult)); String decryptResult = AES256Util.decrypt(encryptResult, password);
System.out.println("解密:" + decryptResult);
}
}

3.2.2非對稱加密

3.2.2.1概述

  1976年,美國學者Dime和Henman為解決資訊公開傳送和金鑰管理問題,提出一種新的金鑰交換協議,允許在不安全的媒體上的通訊雙方交換資訊,安全地達成一致的金鑰,這就是“公開金鑰系統”。
  與對稱加密演算法不同,非對稱加密演算法需要兩個金鑰公開金鑰(publickey)和私有金鑰(privatekey)。公開金鑰與私有金鑰是一對,如果用公開金鑰對資料進行加密,只有用對應的私有金鑰才能解密;如果用私有金鑰對資料進行加密,那麼只有用對應的公開金鑰才能解密。因為加密和解密使用的是兩個不同的金鑰,所以這種演算法叫作非對稱加密演算法
3.2.2.2工作流程
  如下圖所示,甲乙之間使用非對稱加密的方式完成了重要資訊的安全傳輸。
  
  非對稱加密工作過程簡要示意圖
  1、乙方生成一對金鑰(公鑰和私鑰)並將公鑰向其它方公開。
  2、得到該公鑰的甲方使用該金鑰對機密資訊進行加密後再發送給乙方。
  3、乙方再用自己儲存的另一把專用金鑰(私鑰)對加密後的資訊進行解密。乙方只能用其專用金鑰(私鑰)解密由對應的公鑰加密後的資訊。
  在傳輸過程中,即使攻擊者截獲了傳輸的密文,並得到了乙的公鑰,也無法破解密文,因為只有乙的私鑰才能解密密文。
  同樣,如果乙要回復加密資訊給甲,那麼需要甲先公佈甲的公鑰給乙用於加密,甲自己儲存甲的私鑰用於解密。
3.2.2.3優缺點:
  (1)優點:非對稱加密與對稱加密相比,其安全性更好:對稱加密的通訊雙方使用相同的祕鑰,如果一方的祕鑰遭洩露,那麼整個通訊就會被破解。而非對稱加密使用一對祕鑰,一個用來加密,一個用來解密,而且公鑰是公開的,祕鑰是自己儲存的,不需要像對稱加密那樣在通訊之前要先同步祕鑰。
  (2)缺點:非對稱加密的缺點是加密和解密花費時間長、速度慢,只適合對少量資料進行加密。
3.2.2.4常用非對稱加密演算法:
  在非對稱加密中使用的主要演算法有:RSAElgamal、揹包演算法、Rabin、D-H、ECC(橢圓曲線加密演算法)等,其中RSA是最常用的。
(1)RSA加密演算法
概述:
  RSA是目前最有影響力和最常用的公鑰加密演算法,它能夠抵抗到目前為止已知的絕大多數密碼攻擊,已被ISO推薦為公鑰資料加密標準
  RSA公開金鑰密碼體制。所謂的公開金鑰密碼體制就是使用不同的加密金鑰與解密金鑰,是一種“由已知加密金鑰推匯出解密金鑰在計算上是不可行的”密碼體制。
  在公開金鑰密碼體制中,加密金鑰(即公開金鑰)PK是公開資訊,而解密金鑰(即祕密金鑰)SK是需要保密的。加密演算法E和解密演算法D也都是公開的。雖然解密金鑰SK是由公開金鑰PK決定的,但卻不能根據PK計算出SK。

  正是基於這種理論,1978年出現了著名的RSA演算法,它通常是先生成一對RSA 金鑰,其中之一是保密金鑰,由使用者儲存;另一個為公開金鑰,可對外公開,甚至可在網路伺服器中註冊。為提高保密強度,RSA金鑰至少為500位長,一般推薦使用1024位。這就使加密的計算量很大。為減少計算量,在傳送資訊時,常採用傳統加密方法與公開金鑰加密方法相結合的方式,即資訊採用改進的DES或IDEA對話金鑰加密,然後使用RSA金鑰加密對話金鑰和資訊摘要。對方收到資訊後,用不同的金鑰解密並可核對資訊摘要。
RSA演算法是第一個能同時用於加密和數字簽名的演算法,也易於理解和操作。RSA是被研究得最廣泛的公鑰演算法,從提出到現今的三十多年裡,經歷了各種攻擊的考驗,逐漸為人們接受,普遍認為是目前最優秀的公鑰方案之一。
加密過程:
  (1)使用者A和使用者B通訊,為了保證資訊保安,使用RSA加密;
  (2)使用者A生成一對公司鑰,保留私鑰,提供公鑰給B使用者;A傳送資訊給B,使用生成的私鑰進行加密;
  (3)使用者B接收使用者A加密後的資訊,使用A提供的公鑰進行解密
java程式碼實現:
 package cn.mars.app.txn.zjyl;

 import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map; import javax.crypto.Cipher; /**
* Rsa工具類
*
* @author ThinkPad
*
*/
public abstract class RsaUtils {
/**
* 生成公鑰私鑰對,使用預設模長1024。
*
* @return Object[] : 0:公鑰( RSAPublicKey ),1:私鑰( RSAPrivateKey )
*/ private static final int DEFAULT_KEY_LEN = 2048; public static Map<String, String> genKeyPair() {
return genKeyPair(DEFAULT_KEY_LEN); } /**
* 指定模長生成公私鑰對
*
* @param modulus
* @return
*/
public static Map<String, String> genKeyPair(int modulus) {
KeyPairGenerator keyPairGen;
try {
keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(modulus);
KeyPair keyPair = keyPairGen.generateKeyPair(); Map<String, String> keyMaps = new HashMap<String, String>();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
keyMaps.put("publicKey", new String(Base64.encode(publicKey.getEncoded())));
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
keyMaps.put("privateKey", new String(Base64.encode(privateKey.getEncoded()))); return keyMaps;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
} /**
* 公鑰加密
*
* @param publicKeyBytes
* @param data
* @param modulus
* 公鑰模長,範圍512-2048。
* @return
*/
public static byte[] encryptByPublicKey(byte[] publicKeyBytes, byte[] data, int modulus) {
try {
// RSA最大加密明文大小
int maxEncryptBlock = modulus / 8 - 11; X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
Key publicK = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicK);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
while (inputLen - offSet > 0) {
if (inputLen - offSet > maxEncryptBlock) {
cache = cipher.doFinal(data, offSet, maxEncryptBlock);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * maxEncryptBlock;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
} catch (Exception e) {
throw new RuntimeException(e);
} } /**
* 公鑰加密,金鑰模長使用預設長度1024。
*
* @param publicKeyBytes
* 公鑰RSAPublicKey getEncoded()
* @param data
* 要加密的位元組陣列
*/
public static byte[] encryptByPublicKey(byte[] publicKeyBytes, byte[] data) {
return encryptByPublicKey(publicKeyBytes, data, DEFAULT_KEY_LEN);
} /**
* 公鑰解密
*
* @param publicKeyBytes
* 公鑰RSAPublicKey getEncoded()
* @param encryptedData
* 被(私鑰)加密過的位元組陣列
* @param modulus
* 模長,範圍512-2048
* @return
*/
public static byte[] decryptByPublicKey(byte[] publicKeyBytes, byte[] encryptedData, int modulus) {
// RSA最大解密密文大小
int maxDecryptBlock = modulus / 8;
try {
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
Key publicK = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicK);
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 對資料分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > maxDecryptBlock) {
cache = cipher.doFinal(encryptedData, offSet, maxDecryptBlock);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * maxDecryptBlock;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
} catch (Exception e) {
throw new RuntimeException(e);
}
} /**
* 公鑰解密,預設模長1024
*
* @param publicKeyBytes
* 公鑰RSAPublicKey getEncoded()
* @param encryptedData
* 被(私鑰)加密過的位元組陣列
*/
public static byte[] decryptByPublicKey(byte[] publicKeyBytes, byte[] encryptedData) {
return decryptByPublicKey(publicKeyBytes, encryptedData, DEFAULT_KEY_LEN);
} /**
* 私鑰加密
*
* @param privateKeyBytes
* 私鑰RSAPrivateKey getEncoded()
* @param data
* 要加密的位元組陣列
* @param modulus
* 模長,範圍512-2048。
*/
public static byte[] encryptByPrivateKey(byte[] privateKeyBytes, byte[] data, int modulus) {
try {
// RSA最大加密明文大小
int maxEncryptBlock = modulus / 8 - 11; PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateK);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
while (inputLen - offSet > 0) {
if (inputLen - offSet > maxEncryptBlock) {
cache = cipher.doFinal(data, offSet, maxEncryptBlock);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * maxEncryptBlock;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
} catch (Exception e) {
throw new RuntimeException(e);
}
} /**
* 私鑰加密,預設模長1024。
*
* @param privateKeyBytes
* 私鑰RSAPrivateKey getEncoded()
* @param data
* 要加密的位元組陣列
*/
public static byte[] encryptByPrivateKey(byte[] privateKeyBytes, byte[] data) {
return encryptByPrivateKey(privateKeyBytes, data, DEFAULT_KEY_LEN);
} /**
* 私鑰解密
*
* @param privateKeyBytes
* 私鑰RSAPrivateKey getEncoded()
* @param encryptedData
* 被(公鑰)加密過的位元組陣列
* @param modulus
* 模長,範圍512-2048
*/
public static byte[] decryptByPrivateKey(byte[] privateKeyBytes, byte[] encryptedData, int modulus) {
try {
// RSA最大解密密文大小
int maxDecryptBlock = modulus / 8; PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateK);
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
while (inputLen - offSet > 0) {
if (inputLen - offSet > maxDecryptBlock) {
cache = cipher.doFinal(encryptedData, offSet, maxDecryptBlock);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * maxDecryptBlock;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
} catch (Exception e) {
throw new RuntimeException(e);
}
} /**
* 私鑰解密,預設模長1024。
*
* @param privateKeyBytes
* 私鑰RSAPrivateKey getEncoded()
* @param encryptedData
* 被(公鑰)加密過的位元組陣列
*/
public static byte[] decryptByPrivateKey(byte[] privateKeyBytes, byte[] encryptedData) {
return decryptByPrivateKey(privateKeyBytes, encryptedData, DEFAULT_KEY_LEN);
} public static void main(String[] args) {
genKeyPair();
}
}

  此文只是簡單介紹了java常用的加減密演算法,之後文章會對每種演算法做具體說明。