在ECB模式(electronic codebook mode)中不需要IV,但是也因此会出现相同明文的区块会产生相同密文而很容易被找到规律。所以不安全。
DES是标准的对称加密算法,算法采用的密钥长度可以是8bit或者16bit。加密的结果不一样,因为VI(初始向量)不同。
DES的起始VI是随机的,所以加密结果不同。但是解密过程是相反的,解密到最后一组字节流的时候就得到了VI,这个VI在解密完成后会被舍弃。所以两种实现的加密的结果不同是没有关系的,同样可以解密。
最基本的des加密解密代码:
package com.neusoft.si.simis.ws.faceRecognition.bean;
import java.security.Key;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import org.apache.axis.encoding.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Des {
public static final String ALGORITHM_DES = "DES/CBC/PKCS5Padding";
private static Log log = LogFactory.getLog(Des.class);
/**
* DES算法,加密
*
* @param data
* 待加密字符串
* @param key
* 加密私钥,长度不能够小于8位
* @return 加密后的字节数组,一般结合Base64编码使用
* @throws CryptException
* 异常
*/
public static String encode(String key, String data) throws Exception {
return encode(key, data.getBytes());
}
/**
* DES算法,加密
*
* @param data
* 待加密字符串
* @param key
* 加密私钥,长度不能够小于8位
* @return 加密后的字节数组,一般结合Base64编码使用
* @throws CryptException
* 异常
*/
public static String encode(String key, byte[] data) throws Exception {
try {
DESKeySpec dks = new DESKeySpec(key.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
// key的长度不能够小于8位字节
Key secretKey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance(ALGORITHM_DES);
IvParameterSpec iv = new IvParameterSpec("********".getBytes());
AlgorithmParameterSpec paramSpec = iv;
cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
byte[] bytes = cipher.doFinal(data);
return Base64.encode(bytes);
} catch (Exception e) {
throw new Exception(e);
}
}
/**
* DES算法,解密
*
* @param data
* 待解密字符串
* @param key
* 解密私钥,长度不能够小于8位
* @return 解密后的字节数组
* @throws Exception
* 异常
*/
public static byte[] decode(String key, byte[] data) throws Exception {
try {
SecureRandom sr = new SecureRandom();
DESKeySpec dks = new DESKeySpec(key.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
// key的长度不能够小于8位字节
Key secretKey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance(ALGORITHM_DES);
IvParameterSpec iv = new IvParameterSpec("********".getBytes());
AlgorithmParameterSpec paramSpec = iv;
cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec);
return cipher.doFinal(data);
} catch (Exception e) {
// e.printStackTrace();
throw new Exception(e);
}
}
/**
* 获取编码后的值
*
* @param key
* @param data
* @return
* @throws Exception
* @throws Exception
*/
public static String decodeValue(String key, String data) throws Exception {
byte[] datas;
String value = null;
datas = decode(key, Base64.decode(data));
value = new String(datas);
if (value.equals("")) {
throw new Exception();
}
return value;
}
public static void main(String arg[]){
try {
System.out.println("加密:"+encode("12345678","adfadsfasdf"));
System.out.println("解密:"+decodeValue("12345678","09b+G8cW4Zqirv2eWerRng=="));
} catch (Exception e) {
e.printStackTrace();
}
}
}
des中cbc模式加密解密:
package com.neusoft.des.util;
import java.util.Vector;
public class CbcEn {
private String algorithm;// 算法参数
private String keyStr;// 秘钥字符串
private byte[] seed;// 种子
private byte[] plainText;// 欲加密字符串
private byte[] subText;// 对欲加密字符串的字节数组8字节1截取,存入此字节数组,进行加密
String iv;// 初始种子字符串
public CbcEn(String alg, String keyStr, String iv, byte[] msg) {
algorithm = alg;
this.keyStr = keyStr;
this.iv = iv;
seed = new byte[8];
for (int i = 0; i < 8; i++)
seed[i] = 0;
for (int i = 0; i < 8 & i < iv.length(); i++)
seed[i] = iv.getBytes()[i];
subText = new byte[8];
plainText = msg;
}
// 加密函数
public byte[] CipherMsg() {
byte[] cipherText;// 加密结果存入此字节数组
byte[] subCiper;// 每8字节加密,结果存入此字节数组
Vector<byte[]> cipherVector = new Vector<byte[]>();// 每8位加密结果的字节数组,存入此向量类,最后生成ciperText
int loopTimes;// 判断明文需要执行多少次循环加密
int plainLength = plainText.length;
if (plainLength % 8 > 0) {
loopTimes = plainLength / 8 + 1;
} else
loopTimes = plainLength / 8;
for (int i = 0; i < loopTimes; i++) {
for (int j = 0; j < 8; j++)
subText[j] = 0;
// 取子串
for (int m = 0; m < 8 & i * 8 + m < plainText.length; m++)
subText[m] = plainText[i * 8 + m];
// 子串与种子异或
for (int n = 0; n < 8; n++)
subText[n] ^= seed[n];
subCiper = new DesEn(algorithm, keyStr, subText).CipherMsg();// 对异或结果进行DES加密
cipherVector.add(subCiper);// 暂存子串加密结果
// 种子置为上一次子串的加密结果
for (int k = 0; k < 8 & k < subCiper.length; k++)
seed[k] = subCiper[k];
}
// 合并加密结果
cipherText = new byte[8 * cipherVector.size()];
for (int i = 0; i < cipherVector.size(); i++) {
subText = (byte[]) cipherVector.get(i);
for (int j = i * 8; j < (i + 1) * 8; j++) {
cipherText[j] = subText[j % 8];
}
}
return cipherText;
}
// 解密函数
public byte[] EncipherMsg(byte[] cipherText, String iv, String keyStr) {
byte[] sourceText;// 解密明文存入此字节数组
byte[] subSourceText = new byte[8];// 对密文8字节一截取,存入此字节数组
byte[] subCipherText = new byte[8];// 8字节密文解密结果,存入此字节数组
Vector<byte[]> sourceTextVector = new Vector<byte[]>();// 8字节密文解密结果数组,存入此向量,最后存入sourceText
int loopTimes = cipherText.length / 8;// 解密循环次数
// 种子初始化
for (int i = 0; i < 8; i++)
seed[i] = 0;
for (int i = 0; i < 8 & i < iv.length(); i++)
seed[i] = iv.getBytes()[i];
for (int i = 0; i < loopTimes; i++) {
// 对密文取8字节进行解密
for (int j = 0; j < 8; j++)
subCipherText[j] = cipherText[i * 8 + j];
subSourceText = new DesEn(algorithm, keyStr, null).EncipherMsg(
subCipherText, keyStr);
// 解密结果与种子异或,得8字节明文子串字节数组
for (int m = 0; m < 8; m++)
subSourceText[m] ^= seed[m];
sourceTextVector.add(subSourceText);// 暂存8字节明文子串字节数组
// 种子置为8字节密文子串
for (int k = 0; k < 8 & k < subCipherText.length; k++)
seed[k] = subCipherText[k];
}
// 合并解密结果
sourceText = new byte[loopTimes * 8];
for (int i = 0; i < sourceTextVector.size(); i++) {
subSourceText = (byte[]) sourceTextVector.get(i);
for (int j = i * 8; j < (i + 1) * 8; j++) {
sourceText[j] = subSourceText[j % 8];
}
}
return sourceText;
}
}
cfb模式:
package com.neusoft.des.util;
import java.util.Vector;
public class CfbEn {
private String algorithm;// 算法参数
private String keyStr;// 秘钥字符串
private byte[] seed;// 种子
private byte[] plainText;// 欲加密字符串
private byte subText = 0;// 对欲加密字符串的字符数组每字节1截取,存入进行加密
String iv;// 初始种子字符串
public CfbEn(String alg, String keyStr, String iv, byte[] msg) {
algorithm = alg;
this.keyStr = keyStr;
this.iv = iv;
seed = new byte[8];
for (int i = 0; i < 8; i++)
seed[i] = 0;
for (int i = 0; i < 8 & i < iv.length(); i++)
seed[i] = iv.getBytes()[i];
plainText = msg;
}
// 加密函数
public byte[] CipherMsg() {
byte[] cipherText;// 加密结果存入此字符数组
byte subCipher = 0;// 对每字节加密,结果存入此字节
byte[] seedTemp = new byte[8];// 种子左移1字节,暂存数组
Vector<Byte> cipherVector = new Vector<Byte>();// 暂存加密结果
int loopTimes = plainText.length;// 加密循环次数
for (int i = 0; i < loopTimes; i++) {
subText = plainText[i];
subCipher = (new DesEn(algorithm, keyStr, seed).CipherMsg())[0];// 对seed进行DES加密,取首字节
subCipher ^= subText;// 首字节与欲加密原文字节异或,得加密字节
cipherVector.add(subCipher);
// seed左移一字节,最后一字节存入本次加密结果
for (int j = 0; j < 7; j++)
seedTemp[j] = seed[j + 1];
seedTemp[7] = subCipher;
for (int k = 0; k < 8; k++)
seed[k] = seedTemp[k];
}
// 合并加密结果
cipherText = new byte[cipherVector.size()];
for (int i = 0; i < cipherVector.size(); i++) {
subText = cipherVector.get(i).byteValue();
cipherText[i] = subText;
}
return cipherText;
}
// 解密函数
public byte[] EncipherMsg(byte[] cipherText, String iv, String keyStr) {
byte[] sourceText;// 解密明文存入此字节数组
byte cipherSeed = 0;// 暂存对seed进行DES加密结果的首字节
byte subCipher = 0;// 密文取1字节进行解密
byte[] seedTemp = new byte[8];// 种子左移1字节,暂存数组
Vector<Byte> sourceTextVector = new Vector<Byte>();
int loopTimes = cipherText.length;
for (int i = 0; i < 8; i++)
seed[i] = 0;
for (int i = 0; i < 8 & i < iv.length(); i++)
seed[i] = iv.getBytes()[i];
for (int i = 0; i < loopTimes; i++) {
subCipher = cipherText[i];// 取密文一个字节进行解密
cipherSeed = (new DesEn(algorithm, keyStr, seed).CipherMsg())[0];// 对seed进行DES加密,取首字节
sourceTextVector.add((byte) (subCipher ^ cipherSeed));// 首字节与密文字节异或,得解密字节,暂存
// seed左移1字节,最后一字节存入密文字节
for (int j = 0; j < 7; j++)
seedTemp[j] = seed[j + 1];
seedTemp[7] = subCipher;
for (int k = 0; k < 8; k++)
seed[k] = seedTemp[k];
}
// 合并解密结果
sourceText = new byte[sourceTextVector.size()];
for (int i = 0; i < sourceTextVector.size(); i++) {
sourceText[i] = sourceTextVector.get(i).byteValue();
}
return sourceText;
}
}
ofb模式:
package com.neusoft.des.util;
import java.util.Vector;
public class OfbEn {
private String algorithm;// 算法参数
private String keyStr;// 秘钥字符串
private byte[] seed;// 种子
private byte[] plainText;// 欲加密字符串
private byte subText = 0;// 对欲加密字符串的字符数组每字节1截取,存入进行加密
String iv;// 初始种子字符串
public OfbEn(String alg, String keyStr, String iv, byte[] msg) {
algorithm = alg;
this.keyStr = keyStr;
this.iv = iv;
seed = new byte[8];
for (int i = 0; i < 8; i++)
seed[i] = 0;
for (int i = 0; i < 8 & i < iv.length(); i++)
seed[i] = iv.getBytes()[i];
plainText = msg;
}
// 加密函数
public byte[] CipherMsg() {
byte[] cipherText;// 加密结果存入此字符数组
byte subCipher = 0;// 对每字节加密,结果存入此字节
byte[] seedTemp = new byte[8];// 种子左移1字节,暂存数组
Vector<Byte> cipherVector = new Vector<Byte>();// 暂存加密结果
int loopTimes = plainText.length;// 加密循环次数
for (int i = 0; i < loopTimes; i++) {
subText = plainText[i];
subCipher = (new DesEn(algorithm, keyStr, seed).CipherMsg())[0];// 对seed进行DES加密,取首字节,为加密密文
// seed左移1字节,最后一字节存入密文与明文异或的结果
for (int j = 0; j < 7; j++)
seedTemp[j] = seed[j + 1];
seedTemp[7] = subCipher;
for (int k = 0; k < 8; k++)
seed[k] = seedTemp[k];
subCipher ^= subText;
cipherVector.add(subCipher);
}
// 合并加密结果
cipherText = new byte[cipherVector.size()];
for (int i = 0; i < cipherVector.size(); i++) {
subText = cipherVector.get(i).byteValue();
cipherText[i] = subText;
}
return cipherText;
}
// 解密函数
public byte[] EncipherMsg(byte[] cipherText, String iv, String keyStr) {
byte[] sourceText;// 解密明文存入此字节数组
byte cipherSeed = 0;// 暂存对seed进行DES加密结果的首字节
byte subCipher = 0;// 密文取1字节进行解密
byte[] seedTemp = new byte[8];// 种子左移1字节,暂存数组
Vector<Byte> sourceTextVector = new Vector<Byte>();
int loopTimes = cipherText.length;
for (int i = 0; i < 8; i++)
seed[i] = 0;
for (int i = 0; i < 8 & i < iv.length(); i++)
seed[i] = iv.getBytes()[i];
for (int i = 0; i < loopTimes; i++) {
subCipher = cipherText[i];// 取密文一个字节进行解密
cipherSeed = (new DesEn(algorithm, keyStr, seed).CipherMsg())[0];// 对seed进行DES加密,取首字节
sourceTextVector.add((byte) (subCipher ^ cipherSeed));// 首字节与密文字节异或,得解密字节,暂存
// seed左移1字节,最后一字节存入seed进行DES加密结果的首字节
for (int j = 0; j < 7; j++)
seedTemp[j] = seed[j + 1];
seedTemp[7] = cipherSeed;
for (int k = 0; k < 8; k++)
seed[k] = seedTemp[k];
}
// 合并解密结果
sourceText = new byte[sourceTextVector.size()];
for (int i = 0; i < sourceTextVector.size(); i++) {
sourceText[i] = sourceTextVector.get(i).byteValue();
}
return sourceText;
}
}
各种模式的用法背景和特点后续再表述。