views:

653

answers:

4

I have been studying Oracle's mechanism for authenticating against a 10g database. Although it is less documented than its 9i counterpart, I have still managed to find many of its details on various web sites and blogs. One piece remains a mystery, however. Before I mention what is missing, let me explain what is known about the protocol in pseudo code:

// CLIENT SIDE PSEUDO CODE

user = "SCOTT"
password = "TIGER"
password_hash = oracle_password_hash(user, password)

// 1. Client provides user name to server
send(user)

// 2. Server responds with its encrypted AUTH_SESSKEY, 
//    a randomly generated number associated with the current session
encrypted_server_AUTH_SESSKEY = receive_AUTH_SESSKEY() // 32 bytes

decrypted_server_AUTH_SESSKEY = aes_decrypt(
    encrypted_input => encrypted_server_AUTH_SESSKEY,
    decryption_key  => password_hash
)

// 3. Client generates its own AUTH_SESSKEY for this session
unencrypted_client_AUTH_SESSKEY = generate_random_AUTH_SESSKEY() // 32 bytes

encrypted_client_AUTH_SESSKEY = aes_encrypt(
    unencrypted_input => unencrypted_client_AUTH_SESSKEY,
    encryption_key    => password_hash
)

// 4. Client combines the two AUTH_SESSKEYs using a known Oracle-specific algorithm
combined_AUTH_SESSKEYs = oracle_combine(decrypted_server_AUTH_SESSKEY, unencrypted_client_AUTH_SESSKEY)

// 5. Client builds AUTH_PASSWORD
unencrypted_AUTH_PASSWORD = byte[32]
unencrypted_AUTH_PASSWORD[0 .. 16] = ??? // THIS IS THE PROBLEM
unencrypted_AUTH_PASSWORD[16 .. 16 + len(password)] = password
unencrypted_AUTH_PASSWORD[16 + len(password) .. ] = PKCS#7 padding

// 6. Client encrypts the AUTH_PASSWORD data using the combined AUTH_SESSKEYs as the encryption key
encrypted_AUTH_PASSWORD = aes_encrypt(
    unencrypted_input => unencrypted_AUTH_PASSWORD,
    encryption_key    => combined_AUTH_SESSKEYs
)

// 7. Client transmits its encrypted AUTH_SESSKEY and AUTH_PASSWORD to server for verification
send(encrypted_client_AUTH_SESSKEY, encrypted_AUTH_PASSWORD)

What does the Oracle client put in the lower 16 bytes of the AUTH_PASSWORD value in step 5?

Almost all documentation I have found cares only about obtaining the plain text password contained within, paying little attention to these first bytes. I have tried looking at the JDBC driver, but it appears that even the 10g version avoids this authentication scheme by requesting that the server revert back to an older scheme (which happens to be much better understood). An excellent C program demonstrates the decryption of AUTH_PASSWORD.

Can anyone point me in the right direction?

A: 

I have determined that the 16 bytes immediately before the plain text password are randomly generated (for the curious, take a look at the ztvo5pe function exported by the oran10.dll library - you will see two successive calls to ztcen, the first call fills it in).

I originally posted the question because I was writing a small program to connect to an Oracle database without the use of Oracle's JDBC driver. I was finding that the database was rejecting my 32-byte AUTH_PASSWORD. I assumed that it was rejected because I had put an incorrect value in these first 16 bytes. I was wrong. It appears that these do not have any effect on whether or not a user authenticates.

Rather, it turns out that the database was rejecting my AUTH_PASSWORD because of the trailing bytes that come immediately after the plain text password. I naively padded the buffer with zeroes. It should have been padded according to the PKCS #7 specification.

Adam Paynter
A: 

If the password length < 16, the first 16 bytes are random data, then the password, the padding data are char of (16 – strlen(password)). The Oracle server can accept my AUTH_PASSWORD. If the password length >= 16, I don’t know how to do it. I filled the first 16 bytes with random data, but the server reject my data. I want to know: are you sure the padding data is according to the PKCS#7 specification.

As you already know, the first 16 bytes are random. The next 16 bytes are the password and its padding. This only works if the password is 15 bytes or less (because you need the 16th byte for padding). If the password is 16 bytes or more, you must use 32 bytes for the password and its padding. Therefore, the first 16 bytes would be random and the next 32 bytes would be the password and its padding.
Adam Paynter
I am confident that it is PKCS#7. It is simpler than it sounds: http://en.wikipedia.org/wiki/Padding_%28cryptography%29
Adam Paynter
A: 

In your Third step: unencrypted_client_AUTH_SESSKEY = generate_random_AUTH_SESSKEY(). I want to know how to generate the unencrypted_client_AUTH_SESSKEY? Is the random data will be OK?

Yes - as long as the random key is cryptographically random (which is much more random than any pseudo-random generator generates), then you should be fine.
Jonathan Leffler
Thank you for your answer, Could you tell me how to generate the unencrypted_client_AUTH_SESSKEY? I tryed but not success.
A: 

In your Third step: unencrypted_client_AUTH_SESSKEY = generate_random_AUTH_SESSKEY(). I want to know how to generate the unencrypted_client_AUTH_SESSKEY? I filled the 32 bytes are randomly generated, but the server rejected it. I think there is some relations between the unencrypted_client_AUTH_SESSKEY and the unencrypted_server_AUTH_SESSKEY, Can anyone point me in the right direction?

They should be unrelated. What do you mean when you say "but the server rejected it"?
Adam Paynter
I did a proxy of oracle,so I can get the server data and client data. I got the client AUTH_SESSKEY and decrypted it, then encrypt it and got the same client AUTH_SESSKEY.I generated my own AUTH_PASSWORD and send to the server , the server accepted it. But if I change the decrypted_client_AUTH_SESSKEY and encrypted it to get the client AUTH_SESSKEY and AUTH_PASSWORD, the server rejected it. So I think they should be related. If the decrypted client AUTH_SESSKEY is random, any data will be OK, and my encrypt method si right, why the server reject it?
I am not sure. If you're just writing a proxy, feel free to continue using the AUTH_SESSKEY sent from the client.
Adam Paynter
FYI: You are asking questions via the "Your Answer" text box. They are all showing up as "answers" to my question. I get notified when new answers (your questions) are added, but not when we begin commenting on your question (answer). If you want to be sure I get notified, you can try asking questions via comments on either my original question or my answer. That way, StackOverflow will let me know when you comment.
Adam Paynter