我有一个Android客户端和服务器,客户端需要在与服务器通信或处理数据之前验证会话密钥。客户端是Android应用程序,其加密方法是用Java编写的,服务器是用C语言编写的。
我将会话密钥称为"魔术令牌",并且魔术令牌由PBKDF2算法生成,在服务器上具有1000次SHA256哈希迭代。客户端从服务器获取魔术令牌,客户端本身需要再次重新生成魔术令牌,以便比较获取的令牌和生成的令牌。如果它们相等,则表示会话密钥有效,客户端可以进一步操作。
但我的问题是当我尝试使用相同的算法生成魔术令牌,盐,服务器端的迭代计数时,生成的哈希值不一样。也许它由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);
}
可以在github
上找到C的完整文件和我的java(Android)语言风格如下
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);
}
可以在github
上找到Java的完整文件最后,我发现了错误,它是由char [] salt引起的,
是正确的byte[] salt = {(byte) 0xda, (byte) 0x90, (byte) 0x45, (byte) 0xc3, (byte) 0x06, (byte) 0xc7, (byte) 0xcc, (byte) 0x26};