简体   繁体   中英

Java PBKDF2WithHmacSHA1 issue

I have three apps (.NET, Android, Java). The crypto involved consists of one of the three apps generating a message along with a key, IV, and salt to pass along to the other two. .Net <-> Android works perfectly for both asymmetric and symmetric encryption/decryption, and the key generating functions outputting the same values. The plain vanilla Java version is giving me problems.

The key, iv and salt are generated using a RNG such as

KeyGenerator kg = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
kg.init(len * 8, sr);
return kg.generateKey().getEncoded();

which are then converted to a hex string to be passed along. When I go to do the decryption on Android or Java, I convert the hex representation of the key back into a byte[] and pass it to the SecretKey function shown below.

public void SecretKey(byte[] key) {
    char[] ca = null;
    PBEKeySpec keySpec = null;
    SecretKeyFactory factory = null;

    _secretKey = null;
    try {
            ca = new char[key.length];  
            for (int x = 0; x < key.length; x++) {
                    ca[x] = (char)(key[x]);
            }
            keySpec = new PBEKeySpec(ca, _salt, 1024, 256);
            factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            _secretKey = factory.generateSecret(keySpec);
    .
    .
    .

Now, on the non-Android Java version I can verify that the password and salt are byte for byte identical as the .NET and Android version so there doesn't seem to be a conversion issue. However, the getEncoded() key output is different.

.Net
PW: 228 24 51 237 189 94 87 183 124 144 173 217 195 24 106 199 55 30 74 93 7 206 159 156 245 51 6 131 123 230 255 21 
Salt: 87 241 248 158 129 101 47 36 255 31 30 26 211 50 204 156 
Key: 204 26 176 226 255 40 25 163 60 85 75 208 230 192 214 150 136 5 155 55 228 199 98 36 230 84 210 6 164 113 48 128 

Java:
PW: 228 24 51 237 189 94 87 183 124 144 173 217 195 24 106 199 55 30 74 93 7 206 159 156 245 51 6 131 123 230 255 21 
Salt: 87 -15 -8 -98 -127 101 47 36 -1 31 30 26 -45 50 -52 -100 
Key: -55 6 -4 80 96 9 85 18 72 -43 24 -48 -48 94 17 -113 74 108 -124 -118 -42 -29 -83 -88 -70 11 47 -4 4 -108 11 17 

I'm using JDK1.7.0_45, have the non-restrictive policy files installed, along with BouncyCastle 1.50 set as the preferred provider using both policy and code paths.

On Android, I'm using SpongyCastle and .Net is just using the standard Microsoft CryptAPI.

Any help would be appreciated. Thanks.

The problem stems from the fact that PBKDF2 is designed to be used on passwords (text) not keys (random byte sequences that do not form valid encodings of text).

Following the recommendation in PKCS #5, the first step in key derivation should be conversion of the password text to bytes using UTF-8 encoding. Java does this, and with the particular key given in the post, the encoding is a 48-byte sequence. However, older versions of Android (and perhaps .NET) don't do a UTF-8 encoding; they simply discard all but the lower 8 bits of each character, giving you the 32-byte sequence provided in your post.

The newest Android versions, like Java, perform the character-to-byte conversion using UTF-8, and require use of a different key derivation algorithm to interoperate with old Android versions.

These problems can be avoided by not trying to use PBKDF2 here. It isn't improving security, it makes your code hard to write and read, and it introduces a number of interoperability pitfalls. All for no benefit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM