以下为代码:
Rfc2898DeriveBytes.java
package cn.lonecloud.aes;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
/**
* RFC 2898 password derivation compatible with .NET Rfc2898DeriveBytes class.
*/
public class Rfc2898DeriveBytes {
private Mac _hmacSha1;
private byte[] _salt;
private int _iterationCount;
private byte[] _buffer = new byte[20];
private int _bufferStartIndex = 0;
private int _bufferEndIndex = 0;
private int _block = 1;
/**
* Creates new instance.
* @param password The password used to derive the key.
* @param salt The key salt used to derive the key.
* @param iterations The number of iterations for the operation.
* @throws NoSuchAlgorithmException HmacSHA1 algorithm cannot be found.
* @throws InvalidKeyException Salt must be 8 bytes or more. -or- Password cannot be null.
*/
public Rfc2898DeriveBytes(byte[] password, byte[] salt, int iterations) throws NoSuchAlgorithmException, InvalidKeyException {
if ((salt == null) || (salt.length < 8)) { throw new InvalidKeyException("Salt must be 8 bytes or more."); }
if (password == null) { throw new InvalidKeyException("Password cannot be null."); }
this._salt = salt;
this._iterationCount = iterations;
this._hmacSha1 = Mac.getInstance("HmacSHA1");
this._hmacSha1.init(new SecretKeySpec(password, "HmacSHA1"));
}
/**
* Creates new instance.
* @param password The password used to derive the key.
* @param salt The key salt used to derive the key.
* @param iterations The number of iterations for the operation.
* @throws NoSuchAlgorithmException HmacSHA1 algorithm cannot be found.
* @throws InvalidKeyException Salt must be 8 bytes or more. -or- Password cannot be null.
* @throws UnsupportedEncodingException UTF-8 encoding is not supported.
*/
public Rfc2898DeriveBytes(String password, byte[] salt, int iterations) throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
this(password.getBytes("UTF8"), salt, iterations);
}
/**
* Creates new instance.
* @param password The password used to derive the key.
* @param salt The key salt used to derive the key.
* @throws NoSuchAlgorithmException HmacSHA1 algorithm cannot be found.
* @throws InvalidKeyException Salt must be 8 bytes or more. -or- Password cannot be null.
* @throws UnsupportedEncodingException UTF-8 encoding is not supported.
*/
public Rfc2898DeriveBytes(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
this(password, salt, 0x3e8);
}
/**
* Returns a pseudo-random key from a password, salt and iteration count.
* @param count Number of bytes to return.
* @return Byte array.
*/
public byte[] getBytes(int count) {
byte[] result = new byte[count];
int resultOffset = 0;
int bufferCount = this._bufferEndIndex - this._bufferStartIndex;
if (bufferCount > 0) { //if there is some data in buffer
if (count < bufferCount) { //if there is enough data in buffer
System.arraycopy(this._buffer, this._bufferStartIndex, result, 0, count);
this._bufferStartIndex += count;
return result;
}
System.arraycopy(this._buffer, this._bufferStartIndex, result, 0, bufferCount);
this._bufferStartIndex = this._bufferEndIndex = 0;
resultOffset += bufferCount;
}
while (resultOffset < count) {
int needCount = count - resultOffset;
this._buffer = this.func();
if (needCount > 20) { //we one (or more) additional passes
System.arraycopy(this._buffer, 0, result, resultOffset, 20);
resultOffset += 20;
} else {
System.arraycopy(this._buffer, 0, result, resultOffset, needCount);
this._bufferStartIndex = needCount;
this._bufferEndIndex = 20;
return result;
}
}
return result;
}
private byte[] func() {
this._hmacSha1.update(this._salt, 0, this._salt.length);
byte[] tempHash = this._hmacSha1.doFinal(getBytesFromInt(this._block));
this._hmacSha1.reset();
byte[] finalHash = tempHash;
for (int i = 2; i <= this._iterationCount; i++) {
tempHash = this._hmacSha1.doFinal(tempHash);
for (int j = 0; j < 20; j++) {
finalHash[j] = (byte)(finalHash[j] ^ tempHash[j]);
}
}
if (this._block == 2147483647) {
this._block = -2147483648;
} else {
this._block += 1;
}
return finalHash;
}
private static byte[] getBytesFromInt(int i) {
return new byte[] { (byte)(i >>> 24), (byte)(i >>> 16), (byte)(i >>> 8), (byte)i };
}
}
AesSecret.java
package cn.lonecloud.aes;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import org.apache.commons.codec.binary.Base64;
/**
* AES+PBKDF2 加密
* @author lonecloud
*
*/
public class AesSecret {
// region 秘钥对
private static final String saltString = "Wolfy@home";
private static final String pWDString = "home@Wolfy";
/**
* 解密
* @param strSource
* @return
*/
public static byte[] DecryptString(String strSource) {
byte[] result = null;
try {
byte[] encryptBytes = Base64.decodeBase64(strSource.getBytes("UTF-8"));
byte[] salt = saltString.getBytes();
// 提供高级加密标准 (AES) 对称算法的托管实现。
KeyGenerator aes = KeyGenerator.getInstance("AES");
// 通过使用基于 System.Security.Cryptography.HMACSHA1
// 的伪随机数生成器,实现基于密码的密钥派生功能
// (PBKDF2)。
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(pWDString, salt);
// 获取或设置用于对称算法的密钥。
aes.init(128, new SecureRandom(rfc.getBytes(128 / 8)));
// 获取或设置用于对称算法的初始化向量 (IV)。
SecretKey key = aes.generateKey();
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec((rfc.getBytes(128 / 8))));
result = cipher.doFinal(encryptBytes);
} catch (Exception e) {
e.printStackTrace();
}
// 将解密后所得到的流转换为字符串
return result;
}
/**
* 加密
* @param strSource
* @return
*/
public static byte[] EncryptString(String strSource) {
byte[] result = null;
try {
byte[] encryptBytes = strSource.getBytes("UTF-8");
byte[] salt = saltString.getBytes();
// 提供高级加密标准 (AES) 对称算法的托管实现。
// 1.构造密钥生成器,指定为AES算法,不区分大小写
KeyGenerator aes = KeyGenerator.getInstance("AES");
// 通过使用基于 System.Security.Cryptography.HMACSHA1
// 的伪随机数生成器,实现基于密码的密钥派生功能
// (PBKDF2)。
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(pWDString, salt);
// 获取或设置用于对称算法的密钥。
aes.init(128, new SecureRandom(rfc.getBytes(128 / 8)));
// 获取或设置用于对称算法的初始化向量 (IV)。
SecretKey key = aes.generateKey();
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec((rfc.getBytes(128 / 8))));
result = cipher.doFinal(encryptBytes);
} catch (Exception e) {
e.printStackTrace();
}
// 将加密后所得到的流转换为字符串
return result;
}
}
测试类
package cn.lonecloud.aes;
import java.io.UnsupportedEncodingException;
import org.apache.commons.codec.binary.Base64;
import org.junit.Test;
/**
* 测试类
* @author lonecloud
*
*/
public class AesTest {
@Test
public void aes() throws UnsupportedEncodingException {
String content = "";
System.out.println("加密前算法");
byte[] encryptString = AesSecret.EncryptString(content);
System.out.println("加密后字符" + byteToHexString(encryptString));
byte[] encodeBase64 = Base64.encodeBase64(encryptString);
System.out.println("Base64加密后字符" + byteToHexString(encodeBase64));
byte[] decryptString = AesSecret.DecryptString(new String(encodeBase64, "UTf-8"));
System.out.println("解密后的字符串"+new String(decryptString, "UTf-8"));
}
public static String byteToHexString(byte[] bytes) {
StringBuffer sb = new StringBuffer(bytes.length);
String sTemp;
for (int i = 0; i < bytes.length; i++) {
sTemp = Integer.toHexString(0xFF & bytes[i]);
if (sTemp.length() < 2)
sb.append(0);
sb.append(sTemp.toUpperCase());
}
return sb.toString();
}
}