4

I have a Android client and Server, the client needs to validate the session key before communication or processing data with the server. The client was Android app and its encryption method was wrote in Java, the server`s was wrote in C.

I call the session key as "magic token", and the magic token is generated by PBKDF2 algorithm with 1000 iterations of SHA256 hash on server. The client fetch the magic token from server and the client itself needs to regenerate the magic token again in order to compare the fetched one and generated one. if they are equal, means the session key is valid and the client can go further operations.

But my problem is when I trying to generate the magic token using the same algorithm, salt, iteration count with server side, the generated hash value are not the same. Maybe it caused by PBKDF2 algorithm or sha256 are not exactly same for different platforms. I feel really confused and anyone can help me find out where the error comes from?

NOTE, both C and Java source code are open sourced project hosted on github as linked below. Thanks in advance.

C language style as below

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

the complete file for C can be found on github

and my java (Android) language style as below

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

the complete file for Java can be found on github

EDIT

Finally, I found the error, it was caused by char[] salt, the correct one as

byte[] salt = {(byte) 0xda, (byte) 0x90, (byte) 0x45, (byte) 0xc3, (byte) 0x06, (byte) 0xc7, (byte) 0xcc, (byte) 0x26};
Logan Guo
  • 865
  • 4
  • 17
  • 35
  • 1
    As I see EDIT, I assume that you have found the answer. If you have found the answer to your question, you could post it as an answer and accept it, if you want to accept. – a3.14_Infinity Feb 18 '16 at 04:37
  • Congratulations on finding your error! I would not that at [my Github repository](https://github.com/Anti-weakpasswords/PBKDF2-Test-Vectors) I have a wide variety of test vectors which have been tested on several different implementations, and include as many standards-based test vectors as I can find; this may help more fully validate your implementation. – Anti-weakpasswords Feb 18 '16 at 07:07

0 Answers0