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!

Simulate Oracle DES Password Hashing in Java

843811Nov 17 2009 — edited Nov 18 2009
Hi all,

I'm trying to simulate Oracle's password Hashing in Java., because I want to change the authentification-mechanism of an application (currently via Oracle) to an application-build-in authentification.

I used this website as guideline: http://www.sans.org/reading_room/special/?id=oracle_pass&ref=911

But the output is not what I exspected. What's wrong? Any idea?

Expected: 342C0CF1DDCAD9F3
Got:
9gQc62TlB/zI3pN6NNr2CVzALS8g2CNI8JSvMjmoh234MlGJ8FgDIroun4MOgTCvQbDYN1Ww2dRV
cN3vHF1tfbQMJuFZMqBca1N5GLiAbvw=

This is my code:
import java.math.BigInteger;
import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class OracleLikePasswordHasher {
    public static void main(String[] args) {
        System.out.println(new OracleLikePasswordHasher().generateHash("user", "password"));
    }

    public String generateHash(String user, String password) {
        // instructions see http://www.sans.org/reading_room/special/?id=oracle_pass&ref=911
        // 1. Concatenate the username and the password to produce a plaintext string;
        // 2. Convert the plaintext string to uppercase characters;
        // 3. Convert the plaintext string to multi-byte storage format; ASCII characters have the high byte set to 0x00;

        // can I ignore 3. , cause Java uses Unicode?
        String input = (user + password).toUpperCase();
        for (int i = input.length(); i < 80; i++) {
            input += "0";
        }
        try {
            //4.Encrypt the plaintext string (padded with 0s if necessary to the next even block length)
            //using the DES algorithm in cipher block chaining (CBC) mode with a fixed key value of
            //0x0123456789ABCDEF;

            byte[] keyBytes =  new BigInteger("0123456789ABCDEF", 16).toByteArray();
            Cipher cipherA = Cipher.getInstance("DES/CBC/NoPadding");
            SecretKey key = new SecretKeySpec(keyBytes, "DES");

            IvParameterSpec ips = new IvParameterSpec(new byte[] {0,0,0,0,0,0,0,0});
            cipherA.init(Cipher.ENCRYPT_MODE, key, ips);        
            byte[] encryptedBytes = cipherA.doFinal(input.getBytes());    

            //5.Encrypt the plaintext string again with DES-CBC, but using the last block of the output
            //of the previous step (ignoring parity bits) as the encryption key.         
            encryptedBytes = addParity(encryptedBytes);
            Key encryptedKey = new SecretKeySpec(encryptedBytes, "DES");
            Cipher cipherB = Cipher.getInstance("DES/CBC/NoPadding");
            cipherB.init(Cipher.ENCRYPT_MODE, encryptedKey, ips);
            byte[] encryptedPw = cipherB.doFinal(input.getBytes());

            //The last block of the output is converted into a printable string to produce the password hash value.
            return new sun.misc.BASE64Encoder().encode(encryptedPw);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }    

    // copied from http://www.exampledepot.com/egs/javax.crypto/MakeDes.html
    // Takes a 7-byte quantity and returns a valid 8-byte DES key.
    // The input and output bytes are big-endian, where the most significant
    // byte is in element 0.
    private byte[] addParity(byte[] in) {
        byte[] result = new byte[8];

        // Keeps track of the bit position in the result
        int resultIx = 1;

        // Used to keep track of the number of 1 bits in each 7-bit chunk
        int bitCount = 0;

        // Process each of the 56 bits
        for (int i=0; i<56; i++) {
            // Get the bit at bit position i
            boolean bit = (in[6-i/8]&(1<<(i%8))) > 0;

            // If set, set the corresponding bit in the result
            if (bit) {
                result[7-resultIx/8] |= (1<<(resultIx%8))&0xFF;
                bitCount++;
            }

            // Set the parity bit after every 7 bits
            if ((i+1) % 7 == 0) {
                if (bitCount % 2 == 0) {
                    // Set low-order bit (parity bit) if bit count is even
                    result[7-resultIx/8] |= 1;
                }
                resultIx++;
                bitCount = 0;
            }
            resultIx++;
        }
        return result;
    }
} 

Comments

Processing
Locked Post
New comments cannot be posted to this locked post.

Post Details

Locked on Dec 16 2009
Added on Nov 17 2009
2 comments
457 views