1. 程式人生 > >分組對稱金鑰加密演算法——DES、3DES(DESede 或 TDES)、AES

分組對稱金鑰加密演算法——DES、3DES(DESede 或 TDES)、AES

一、常用的 "分組對稱金鑰加密演算法" 分為以下3種

(1)DES(Data Encryption Standard,標準加密演算法)

  1977年1月,美國政府頒佈:採納IBM公司設計的方案作為非機密資料的正式資料加密標準(DES Data Encryption Standard) 。

        DES採用了64位的分組長度和56位的金鑰長度,它將64位的輸入經過一系列變換得到64位的輸出。解密則使用了相同的步驟和相同的金鑰。DES的金鑰長度為64位,由於第n*8(n=1,2,…8)是校驗位,因此實際參與加密的長度為56位,金鑰空間含有2^56個金鑰。

(2)3DES(Triple Data Encryption Standard,三重標準加密演算法)

  3DES是DES加密演算法的一種模式,它使用3條64位的金鑰對資料進行三次加密。資料加密標準(DES)是美國的一種由來已久的加密標準,它使用對稱金鑰加密法。

  3DES(即Triple DES)是DES向AES過渡的加密演算法(1999年,NIST將3-DES指定為過渡的加密標準),是DES的一個更安全的變形。它是以DES為基本模組,通過組合分組方法設計出分組加密演算法。

(3)AES(Advantaged Encryption Standard,高階加密演算法)

  AES是下一代的加密演算法標準,速度快,安全級別高。

  AES演算法基於排列和置換運算。排列是對資料重新進行安排,置換是將一個數據單元替換為另一個。

  AES使用幾種不同的方法來執行排列和置換運算。AES是一個迭代的、對稱金鑰分組的密碼,它可以使用128、192和256位金鑰,並且用128位(16位元組)分組加密和解密資料。

  與公共金鑰加密使用金鑰對不同,對稱金鑰加密使用相同的金鑰加密和解密資料。通過分組密碼返回的加密資料的位數與輸入資料相同。迭代加密使用一個迴圈結構,在該迴圈中重複置換和替換輸入資料。

二、安全性 DES < 3DES < AES

三、程式碼實現(Android版)

package com.chy.crypto;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

import android.text.TextUtils;
import android.util.Base64;

//由於加密時會自動填充到8位元組(64bit),那麼在我們進行位元組陣列到字串的轉化過程中,可以把它填補的不可見字元改變了,所以解密時會導致異常,用base64解決
//對稱加密
public class SymmetricalCrypto {
	private static final String CHARSET_NAME = "utf-8";
	private static final String algorithm = "AES";
	/*
	AES/CBC/NoPadding (128)
	AES/CBC/PKCS5Padding (128)
	AES/ECB/NoPadding (128)
	AES/ECB/PKCS5Padding (128)
	DES/CBC/NoPadding (56)
	DES/CBC/PKCS5Padding (56)
	DES/ECB/NoPadding (56)
	DES/ECB/PKCS5Padding (56)

	(DESede實際上是3-DES)
	DESede/CBC/NoPadding (168)
	DESede/CBC/PKCS5Padding (168)
	DESede/ECB/NoPadding (168)
	DESede/ECB/PKCS5Padding (168)
	*/
	private static final String transformation = "AES/ECB/PKCS7Padding";

	public static String encrypt(String content, String password) {
		if(TextUtils.isEmpty(content) || TextUtils.isEmpty(password)) {
			return null;
		}
		String result = null;
		try {
			SecretKeySpec key = new SecretKeySpec(getPaddingPwd(password), algorithm);
			Cipher cipher = Cipher.getInstance(transformation);
			cipher.init(Cipher.ENCRYPT_MODE, key);
			byte[] byteContent = content.getBytes(CHARSET_NAME);
			byte[] encryptContent = cipher.doFinal(byteContent);
			byte[] base64Content = Base64.encode(encryptContent, Base64.DEFAULT);
			result = new String(base64Content, Charset.forName(CHARSET_NAME));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return result;
	}

	public static String decrypt(String content, String password) {
		if(TextUtils.isEmpty(content) || TextUtils.isEmpty(password)) {
			return null;
		}
		String result = null;
		try {
			SecretKeySpec key = new SecretKeySpec(getPaddingPwd(password), algorithm);
			Cipher cipher = Cipher.getInstance(transformation);
			cipher.init(Cipher.DECRYPT_MODE, key);
			byte[] base64Content = content.getBytes(Charset.forName(CHARSET_NAME));
			byte[] encryptContent = Base64.decode(base64Content, Base64.DEFAULT);
			byte[] byteResult = cipher.doFinal(encryptContent, 0, encryptContent.length);
			result = new String(byteResult, CHARSET_NAME);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return result;
	}

	private static byte[] getPaddingPwd(String password) throws UnsupportedEncodingException {
		// 密碼必須是16byte的整數倍
		byte[] src = password.getBytes(CHARSET_NAME);
		int left = src.length % 16;
		if (left != 0) {
			byte[] dest = new byte[src.length + 16 - left];
			// 目標陣列中所有元素的值置0
			Arrays.fill(dest, (byte) 0);
			System.arraycopy(src, 0, dest, 0, src.length);
			return dest;
		}
		return src;
	}
}