我正在尝试使用 Rfc2898DeriveBytes for Android Java 和 .NET C# 框架来生成加密和解密过程的密钥。
问题是尽管输入值相同,但我在 .NET 和 Java 中得到了不同的键。
.NET 代码:
private void btnRfc2898DeriveBytes_Click(object sender, EventArgs e)
{
byte[] salt = new byte[] { 19, 3, 24, 18, 14, 42, 57, 23 };
Rfc2898DeriveBytes keyGenerator = null;
keyGenerator = new Rfc2898DeriveBytes("somestring", salt, 1000);
txtRfc2898DeriveBytes.Text = System.Text.Encoding.UTF8.GetString(keyGenerator.GetBytes(16));
}
Java 代码(用于 android 应用程序):
byte[] salt = new byte[] { 19, 3, 24, 18, 14, 42, 57, 23 };
Rfc2898DeriveBytes keyGenerator = null;
try {
keyGenerator = new Rfc2898DeriveBytes("somestring", salt, 1000);
} catch (InvalidKeyException e1) {
e1.printStackTrace();
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Log.i("key = ", decodeUTF8(keyGenerator.getBytes(16)));
Java解码方法:
String decodeUTF8(byte[] bytes) {
private final Charset UTF8_CHARSET = Charset.forName("UTF-8");
return new String(bytes, UTF8_CHARSET);
}
Rfc2898DeriveBytes java 类:
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 };
}
}
编辑:
我也将它转换为十六进制,但也得到不同的值。
C#函数:
public static String encode(byte[] data)
{
char[] lookup = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
int i = 0, p = 2, l = data.Length;
char[] c = new char[l * 2 + 2];
byte d; c[0] = '0'; c[1] = 'x';
while (i < l)
{
d = data[i++];
c[p++] = lookup[d / 0x10];
c[p++] = lookup[d % 0x10];
}
return new string(c, 0, c.Length);
}
Java方法:
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
int v;
for ( int j = 0; j < bytes.length; j++ ) {
v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
我做错了什么:(?