Skip to Main Content

Java Security

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Java version of MS CryptDeriveKey()

843811Jan 27 2007 — edited Jan 29 2007
I've been trying to build a Java equivalent of the MS Crypto API function 'CryptDeriveKey', and am almost, but not quite there.

My goal is to come up with a Java decryption routine that can take a string of encrypted text, combine it with a hashed keyword, and decrypt it using 3DES.

For short encrypted text strings, my routine works, but for longer ones, something goes awry.

I would welcome any ideas on how to make this work.

This matches
Value:	'doggie'	Encrypted:  	4C62984923E42106

Value:	'doggie'	MS Encrypted:	4C62984923E42106
This doesn't, but the first dozen or so bytes *do* match.
Value:	'SomeTextToEncrypt'	Encrypted:  	A5EF6FD341C71C8DA5E348710846491B12559380E11B077D
Value:	'SomeTextToEncrypt'	MS Encrypted:	A5EF6FD341C71C8D67626FAC996568F84CB6EA02E8FCF9DF
The on-line documentation for CryptDeriveKey() describes the function as follows:


Let n be the required derived key length in bytes. The derived key is the first n bytes of the hash value after the hash computation has been completed by
CryptDeriveKey. If the required key length is longer than the hash value, the key is derived as follows:

1. Form a 64-byte buffer by repeating the constant 0x36 64 times. Let k be the length of the hash value that is represented by the input parameter hBaseData. Set the first k bytes of the buffer to the result of an XOR operation of the first k bytes of the buffer with the hash value that is represented by the
input parameter hBaseData.

2. Form a 64-byte buffer by repeating the constant 0x5C 64 times. Set the first k bytes of the buffer to the result of an XOR operation of the first k bytes of
the buffer with the hash value that is represented by the input parameter hBaseData.

3. Hash the result of step 1 by using the same hash algorithm as that used to compute the hash value that is represented by the hBaseData parameter.

4. Hash the result of step 2 by using the same hash algorithm as that used to compute the hash value that is represented by the hBaseData parameter.

5. Concatenate the result of step 3 with the result of step 4.

6. Use the first n bytes of the result of step 5 as the derived key.


Here's my Java version of the function, based on my understanding of the above paragraphs.
public static byte[] CryptDeriveKey( byte[] hBaseData, String hashAlgorithm, int requiredLength ) {

    int keyLength = hBaseData.length;

    byte[] derivedKey = new byte[requiredLength];    
        
    if ( keyLength >= requiredLength ) {
            
        for(int i=0; i<requiredLength; i++) {
        
            derivedKey[i] = hBaseData;
}

return derivedKey;
}

byte[] buff1 = new byte[64];
byte[] buff2 = new byte[64];

Arrays.fill(buff1, (byte) 0x36);
Arrays.fill(buff2, (byte) 0x5C);

for (int i = 0; i < keyLength; i++) {

buff1[i] ^= hBaseData[i];
buff2[i] ^= hBaseData[i];

}

try {

MessageDigest md = MessageDigest.getInstance( hashAlgorithm );

md.reset();

// use the named algorithm to hash those buffers
byte[] result1 = md.digest(buff1);

md.reset();

byte[] result2 = md.digest(buff2);

for (int i = 0; i < requiredLength; i++) {

if(i < result1.length)
derivedKey[i] = result1[i];
else
derivedKey[i] = result2[i - result1.length];

}

} catch ( NoSuchAlgorithmException nsae ) { }

return derivedKey;

}

Here's a code snippet, showing the use of the CryptDeriveKey() function. (The hex() function simply returns a hex string of the byte[] array, and I'm fairly certain it's not the problem)
try {

    String textToEncrypt = "SomeTextToEncrypt";

    // First, use SHA1 to create a hashed byte array of some password data
    
    String keyWord = "Quetzacoatl";

    String hashAlg = "SHA1";
        
    MessageDigest md = MessageDigest.getInstance( hashAlg );
    
    md.reset();
    md.update( keyWord.getBytes() );
    
    byte[] hashKey = md.digest();
    
    
    // param1 = source bytes
    // param2 = name of source data's hash algorithm
    // param3 = required length of derived key
    
    byte[] derivedKey = CryptDeriveKey( hashKey, hashAlg, 24 );

    SecretKey key = new SecretKeySpec(derivedKey, "DESede");

    Cipher cipher = Cipher.getInstance("DESede");
                
    cipher.init(Cipher.ENCRYPT_MODE, key);
        
    byte[] result = cipher.doFinal(source);
    
    String sEncrypted = hex( result );
            
    System.out.println("Encrypted: " + sEncrypted);
   
    } catch ( ... ) { ... }

 
Message was edited by: Mark_S
Mark_S
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Feb 26 2007
Added on Jan 27 2007
4 comments
1,148 views