对于.NET和Java Rfc2898DeriveBytes产生不同的价值观 [英] Rfc2898DeriveBytes for .NET and Java generate different values

查看:352
本文介绍了对于.NET和Java Rfc2898DeriveBytes产生不同的价值观的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用Android的Java和.NET C#框架Rfc2898DeriveBytes生成加密和解密过程中的关键。

I'm trying to use Rfc2898DeriveBytes for Android Java and .NET C# framework to generate key for encryption and decryption process.

问题是,尽管该输入值一样,我越来越在.NET和Java不同的密钥。

The problem is in spite of that the input values are same, I'm getting different keys in .NET and Java.

.NET code:

.NET code:

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的code(在Android应用程序中使用):

Java Code (used in an android application):

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的德code方法:

Java Decode Method:

String decodeUTF8(byte[] bytes) {
    private final Charset UTF8_CHARSET = Charset.forName("UTF-8");
    return new String(bytes, UTF8_CHARSET);
}

Rfc2898DeriveBytes java类:

Rfc2898DeriveBytes java class:

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 };
    }

}

编辑:

我也将其转换为十六进制,但得到不同的值也。

I also convert it to Hex, but getting different values also.

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方法:

Java method:

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);
}

我在做什么错:(?

What I'm doing wrong :( ?

推荐答案

我重新解决这个问题,下面code生成.NET和Java对我相同的值。

I re-solved the issue, the following code generate same values for me in .NET and Java.

.NET code:

.NET code:

private void btnKey_Click(object sender, EventArgs e)
{
    byte[] salt = new byte[] { 172, 137, 25, 56, 156, 100, 136, 211, 84, 67, 96, 10, 24, 111, 112, 137, 3 };
    int iterations = 1024;
    var rfc2898 = new System.Security.Cryptography.Rfc2898DeriveBytes("_sOme*ShaREd*SecreT", salt, iterations);
    byte[] key = rfc2898.GetBytes(16);
    String keyB64 = Convert.ToBase64String(key);
    txtRfc2898DeriveBytes.Text = keyB64;
}

Java的code:

Java code:

String password = "_sOme*ShaREd*SecreT";
byte[] salta = new byte[]{-84, -119, 25, 56, -100, 100, -120, -45, 84, 67, 96, 10, 24, 111, 112, -119, 3};
SecretKeyFactory factory = null;
try {
    factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
} catch (NoSuchAlgorithmException e2) {
    e2.printStackTrace();
}
KeySpec spec = new PBEKeySpec(password.toCharArray(), salta, 1024, 128);
SecretKey tmp = null;
try {
    tmp = factory.generateSecret(spec);
} catch (InvalidKeySpecException e2) {
    e2.printStackTrace();
}
SecretKeySpec secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Log.i("The secret Key: " , Base64.encodeToString(secret.getEncoded(), 0 ));

这篇关于对于.NET和Java Rfc2898DeriveBytes产生不同的价值观的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆