为什么PBKDF2 SHA256生成的哈希值在C和java之间不相等

为什么PBKDF2 SHA256生成的哈希值在C和java之间不相等,java,c,sha256,encryption-symmetric,pbkdf2,Java,C,Sha256,Encryption Symmetric,Pbkdf2,我有一个Android客户端和服务器,客户端需要在与服务器通信或处理数据之前验证会话密钥。客户端是Android应用程序,其加密方法是用Java编写的,服务器是用C编写的 我将会话密钥称为“magic token”,magic token由PBKDF2算法在服务器上经过1000次SHA256哈希迭代生成。客户端从服务器获取魔法令牌,客户端本身需要再次重新生成魔法令牌,以便比较获取的令牌和生成的令牌。如果它们相等,则表示会话密钥有效,客户端可以执行进一步的操作 但我的问题是,当我试图使用相同的算法

我有一个Android客户端和服务器,客户端需要在与服务器通信或处理数据之前验证会话密钥。客户端是Android应用程序,其加密方法是用Java编写的,服务器是用C编写的

我将会话密钥称为“magic token”,magic token由PBKDF2算法在服务器上经过1000次SHA256哈希迭代生成。客户端从服务器获取魔法令牌,客户端本身需要再次重新生成魔法令牌,以便比较获取的令牌和生成的令牌。如果它们相等,则表示会话密钥有效,客户端可以执行进一步的操作

但我的问题是,当我试图使用相同的算法生成魔法令牌时,salt,迭代计数与服务器端,生成的哈希值不一样。可能是由于PBKDF2算法或sha256对于不同的平台并不完全相同。我感到很困惑,谁能帮我找出错误的来源

注意,C和Java源代码都是托管在github上的开源项目,如下链接。提前谢谢

C语言风格如下

static unsigned char salt[8] = { 0xda, 0x90, 0x45, 0xc3, 0x06, 0xc7, 0xcc, 0x26 };

    int
seafile_derive_key (const char *data_in, int in_len, int version,
                    unsigned char *key, unsigned char *iv)
{
    if (version == 2) {
        PKCS5_PBKDF2_HMAC (data_in, in_len,
                           salt, sizeof(salt),
                           KEYGEN_ITERATION2,
                           EVP_sha256(),
                           32, key);
        PKCS5_PBKDF2_HMAC ((char *)key, 32,
                           salt, sizeof(salt),
                           10,
                           EVP_sha256(),
                           16, iv);
        return 0;
    } else if (version == 1)
        return EVP_BytesToKey (EVP_aes_128_cbc(), /* cipher mode */
                               EVP_sha1(),        /* message digest */
                               salt,              /* salt */
                               (unsigned char*)data_in,
                               in_len,
                               KEYGEN_ITERATION,   /* iteration times */
                               key, /* the derived key */
                               iv); /* IV, initial vector */
    else
        return EVP_BytesToKey (EVP_aes_128_ecb(), /* cipher mode */
                               EVP_sha1(),        /* message digest */
                               NULL,              /* salt */
                               (unsigned char*)data_in,
                               in_len,
                               3,   /* iteration times */
                               key, /* the derived key */
                               iv); /* IV, initial vector */
}

        void
    seafile_generate_magic (int version, const char *repo_id,
                            const char *passwd, char *magic)
    {
        GString *buf = g_string_new (NULL);
        unsigned char key[32], iv[16];

        /* Compute a "magic" string from repo_id and passwd.
         * This is used to verify the password given by user before decrypting
         * data.
         */
        g_string_append_printf (buf, "%s%s", repo_id, passwd);

        seafile_derive_key (buf->str, buf->len, version, key, iv);

        g_string_free (buf, TRUE);
        rawdata_to_hex (key, magic, 32);
    }
private static String generateMagic(String repoID, String password, int version) throws NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException, SeafException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
    if (version != 1 && version != 2) {
        throw SeafException.unsupportedEncVersion;
    }

    String src = repoID + password;
    char[] salt = {0xda, 0x90, 0x45, 0xc3, 0x06, 0xc7, 0xcc, 0x26};
    final byte[] slt = new String(salt).getBytes("UTF-8");
    // If you use version 1.47 or higher of SpongyCastle, you can invoke PBKDF2WithHmacSHA256 directly.
    // In versions of BC < 1.47, you could not specify SHA256 digest and it defaulted to SHA1.
    // see http://stackoverflow.com/questions/6898801/how-to-include-the-spongy-castle-jar-in-android
    PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA256Digest());
    gen.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(src.toCharArray()), slt, ITERATION_COUNT);
    byte[] keyBytes;

    if (version == 2) {
        keyBytes = ((KeyParameter) gen.generateDerivedMacParameters(KEY_LENGTH * 8)).getKey();
    } else
        keyBytes = ((KeyParameter) gen.generateDerivedMacParameters(16 * 8)).getKey();

    // final SecretKey key = deriveKeyPbkdf2(slt, src, version);
    // final byte[] bytes = key.getEncoded();
    return toHex(keyBytes);
}
可以在上找到C的完整文件

我的java(Android)语言风格如下

static unsigned char salt[8] = { 0xda, 0x90, 0x45, 0xc3, 0x06, 0xc7, 0xcc, 0x26 };

    int
seafile_derive_key (const char *data_in, int in_len, int version,
                    unsigned char *key, unsigned char *iv)
{
    if (version == 2) {
        PKCS5_PBKDF2_HMAC (data_in, in_len,
                           salt, sizeof(salt),
                           KEYGEN_ITERATION2,
                           EVP_sha256(),
                           32, key);
        PKCS5_PBKDF2_HMAC ((char *)key, 32,
                           salt, sizeof(salt),
                           10,
                           EVP_sha256(),
                           16, iv);
        return 0;
    } else if (version == 1)
        return EVP_BytesToKey (EVP_aes_128_cbc(), /* cipher mode */
                               EVP_sha1(),        /* message digest */
                               salt,              /* salt */
                               (unsigned char*)data_in,
                               in_len,
                               KEYGEN_ITERATION,   /* iteration times */
                               key, /* the derived key */
                               iv); /* IV, initial vector */
    else
        return EVP_BytesToKey (EVP_aes_128_ecb(), /* cipher mode */
                               EVP_sha1(),        /* message digest */
                               NULL,              /* salt */
                               (unsigned char*)data_in,
                               in_len,
                               3,   /* iteration times */
                               key, /* the derived key */
                               iv); /* IV, initial vector */
}

        void
    seafile_generate_magic (int version, const char *repo_id,
                            const char *passwd, char *magic)
    {
        GString *buf = g_string_new (NULL);
        unsigned char key[32], iv[16];

        /* Compute a "magic" string from repo_id and passwd.
         * This is used to verify the password given by user before decrypting
         * data.
         */
        g_string_append_printf (buf, "%s%s", repo_id, passwd);

        seafile_derive_key (buf->str, buf->len, version, key, iv);

        g_string_free (buf, TRUE);
        rawdata_to_hex (key, magic, 32);
    }
private static String generateMagic(String repoID, String password, int version) throws NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException, SeafException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
    if (version != 1 && version != 2) {
        throw SeafException.unsupportedEncVersion;
    }

    String src = repoID + password;
    char[] salt = {0xda, 0x90, 0x45, 0xc3, 0x06, 0xc7, 0xcc, 0x26};
    final byte[] slt = new String(salt).getBytes("UTF-8");
    // If you use version 1.47 or higher of SpongyCastle, you can invoke PBKDF2WithHmacSHA256 directly.
    // In versions of BC < 1.47, you could not specify SHA256 digest and it defaulted to SHA1.
    // see http://stackoverflow.com/questions/6898801/how-to-include-the-spongy-castle-jar-in-android
    PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA256Digest());
    gen.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(src.toCharArray()), slt, ITERATION_COUNT);
    byte[] keyBytes;

    if (version == 2) {
        keyBytes = ((KeyParameter) gen.generateDerivedMacParameters(KEY_LENGTH * 8)).getKey();
    } else
        keyBytes = ((KeyParameter) gen.generateDerivedMacParameters(16 * 8)).getKey();

    // final SecretKey key = deriveKeyPbkdf2(slt, src, version);
    // final byte[] bytes = key.getEncoded();
    return toHex(keyBytes);
}

如我所见,我假设您已经找到了答案。如果您找到了问题的答案,您可以将其作为答案发布并接受,如果您想接受。祝贺您找到错误!我不希望我有各种各样的测试向量,这些测试向量已经在几个不同的实现上进行了测试,包括尽可能多的基于标准的测试向量;这可能有助于更全面地验证您的实现。