本例中的加密流使用了PBEWithMD5AndDES加密算法,该算法是对称加密算法,加密和解密使用的密钥是一样的。不同的是除了密码之外,还需要“盐”。代码如下:
import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
public class CypherStreamExam {
public static void main(String[] args) {
String infile = "D:\\a.txt";
String outfile = "D:\\a.des";
String password = "This is my key";
byte[] salt = initSalt();
encryptFile(infile, outfile, password, salt);
infile = "D:\\a.des";
outfile = "D:\\a.out";
decryptFile(infile, outfile, password, salt);
}
//产生加密所用的盐
public static byte[] initSalt() {
//实例化安全随机数
SecureRandom random = new SecureRandom();
//产出盐
return random.generateSeed(8);
}
private static void decryptFile(String infile, String outfile, String password, byte[] salt) {
byte[] desKeyData = password.getBytes();
try {
FileInputStream fin = new FileInputStream(infile);
FileOutputStream fout = new FileOutputStream(outfile);
Provider sunJce = new com.sun.crypto.provider.SunJCE();
Security.addProvider(sunJce);
//创建密钥
char[] pbeKeyData = password.toCharArray();
PBEKeySpec pbeKeySpec = new PBEKeySpec(pbeKeyData);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey pbeKey = keyFactory.generateSecret(pbeKeySpec);
PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);
//解密
Cipher pbe = Cipher.getInstance("PBEWithMD5AndDES");
pbe.init(Cipher.DECRYPT_MODE, pbeKey, paramSpec);
CipherOutputStream cout = new CipherOutputStream(fout, pbe);
byte[] input = new byte[64];
int len = 0;
while ((len = fin.read(input)) != -1) {
cout.write(input, 0, len);
}
cout.flush();
cout.close();
fin.close();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
}
private static void encryptFile(String filein, String fileout, String password, byte[] salt) {
byte[] desKeyData = password.getBytes();
try {
FileInputStream fin = new FileInputStream(filein);
FileOutputStream fout = new FileOutputStream(fileout);
Provider sunJce = new com.sun.crypto.provider.SunJCE();
Security.addProvider(sunJce);
//创建密钥
char[] pbeKeyData = password.toCharArray();
PBEKeySpec pbeKeySpec = new PBEKeySpec(pbeKeyData);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey pbeKey = keyFactory.generateSecret(pbeKeySpec);
PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);
//加密
Cipher pbe = Cipher.getInstance("PBEWithMD5AndDES");
pbe.init(Cipher.ENCRYPT_MODE, pbeKey, paramSpec);
CipherOutputStream cout = new CipherOutputStream(fout, pbe);
byte[] input = new byte[64];
int len = 0;
while ((len = fin.read(input)) != -1) {
cout.write(input, 0, len);
}
cout.flush();
cout.close();
fin.close();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
}
}
在真实的应用中,加密方和解密方都知道密码,这个密码一般来说是双方约定的,例如你银行账户密码。如果这个密码被泄露,也不用担心,因为解密还需要“盐”。盐一般来说是由一种随机生成算法生成的,而且生存期很短。例如网上银行使用的U Key就是一种盐生成器,特别是“中国银行”的U Key,在进行转账时直接要求用户输入6位数字的盐。由于网上银行的服务端和客户手中的U Key使用同一种盐生成算法(这个算法当然是保密的,也无从泄露),因此保证了盐不会泄露,从而保证用户进行操作时不会泄密。