Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does anybody know what encrypting technique is JDeveloper/SQL Developer using to persist credentials?

I'd be more than interesting for me to understand which technique is being used here to persist sensible data since I'm needing to implement a similar solution. Here's a sample connection configuration and the resulting exported snippet:

Oracle SQL Developer Connections

<?xml version = '1.0' encoding = 'UTF-8'?>
    <References xmlns="http://xmlns.oracle.com/adf/jndi">
        <Reference name="My Connection" className="oracle.jdeveloper.db.adapter.DatabaseProvider" xmlns="">
        <Factory className="oracle.jdeveloper.db.adapter.DatabaseProviderFactory"/>
        <RefAddresses>
            <StringRefAddr addrType="user">
                <Contents>username</Contents>
            </StringRefAddr>
            <StringRefAddr addrType="password">
                <Contents>054D4844D8549C0DB78EE1A98FE4E085B8A484D20A81F7DCF8</Contents>
            </StringRefAddr>
        <SKIPPED />
        </RefAddresses>
    </Reference>
</References>

Any advice would be really appreciated.

like image 393
Nano Taboada Avatar asked Jun 23 '09 13:06

Nano Taboada


3 Answers

For the curious, what you're actually seeing is the secret key concatenated with the encrypted password. For example, I tried encrypting the password "SAILBOAT" using:

DatabaseProviderHelper.goingOut("SAILBOAT") 

In this particular instance, the result was:

 0527C290B40C41D71139B5E7A4446E94D7678359087249A463 

The first byte is constant:

 05 

The next 8 bytes represent the randomly generated secret key (for the DES cipher):

 27C290B40C41D711 

The remaining bytes are the encrypted password:

 39B5E7A4446E94D7678359087249A463 

Therefore, to decrypt the password, you simply use this:

public static byte[] decryptPassword(byte[] result) throws GeneralSecurityException {     byte constant = result[0];     if (constant != 5) {         throw new IllegalArgumentException();     }      byte[] secretKey = new byte[8];     System.arraycopy(result, 1, secretKey, 0, 8);      byte[] encryptedPassword = new byte[result.length - 9];     System.arraycopy(result, 9, encryptedPassword, 0, encryptedPassword.length);      byte[] iv = new byte[8];     for (int i = 0; i < iv.length; i++) {         iv[i] = 0;     }      Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");     cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secretKey, "DES"), new IvParameterSpec(iv));     return cipher.doFinal(encryptedPassword); } 
like image 194
Adam Paynter Avatar answered Oct 21 '22 09:10

Adam Paynter


Note that Tim's password hash above is not for "apps_ro" - presumably he cut and pasted from the wrong place... I won't post the real password in case it's something he doesn't want shared!

I had a similar problem, trying to store my db credentials centrally (for non-secure databases!) and then exporting sql developer xml files. I have no idea what the algorithm is - however, you don't really need to know the algorithm, as you can just call the Oracle java API yourself. If you have SQLDeveloper, just grab the right Jar files:

cp /Applications/SQLDeveloper.App/Contents/Resources/sqldeveloper/BC4J/lib/db-ca.jar . cp /Applications/SQLDeveloper.App/Contents/Resources/sqldeveloper/jlib/ojmisc.jar . 

Then either load them in your Java app, or use something like JRuby as I do:

$jirb > require 'java' > require 'ojmisc.jar' > require 'db-ca.jar' > Java::oracle.jdevimpl.db.adapter.DatabaseProviderHelper.goingOut("password")      => "059D45F5EB78C99875F6F6E3C3F66F71352B0EB4668D7DEBF8"  > Java::oracle.jdevimpl.db.adapter.DatabaseProviderHelper.goingOut("password")  => "055CBB58B69B477714239157A1F95FDDD6E5B453BEB69E5D49"  > Java::oracle.jdevimpl.db.adapter.DatabaseProviderHelper.comingIn("059D45F5EB78C99875F6F6E3C3F66F71352B0EB4668D7DEBF8")  => "password"  > Java::oracle.jdevimpl.db.adapter.DatabaseProviderHelper.comingIn("055CBB58B69B477714239157A1F95FDDD6E5B453BEB69E5D49")  => "password"  

Note that the algorithm, whatever it is, has a random factor so the same password used twice can produce two different hex strings.

like image 24
Korny Avatar answered Oct 21 '22 11:10

Korny


This solution works great for me... Copied from: http://www.mischiefblog.com/?p=912

import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;

/**
 * Decrypt passwords stored in Oracle SQL Developer. This is intended for
 * password recovery.
 * 
 * Passwords are stored in
 * ~/.sqldeveloper/system2.1.1.64.39/o.jdeveloper.db.connection
 * .11.1.1.2.36.55.30/connections.xml
 */
public class Decrypt {
    public static byte[] decryptPassword(byte[] result)
            throws GeneralSecurityException {
        byte constant = result[0];
        if (constant != (byte) 5) {
            throw new IllegalArgumentException();
        }

        byte[] secretKey = new byte[8];
        System.arraycopy(result, 1, secretKey, 0, 8);

        byte[] encryptedPassword = new byte[result.length - 9];
        System.arraycopy(result, 9, encryptedPassword, 0,
                encryptedPassword.length);

        byte[] iv = new byte[8];
        for (int i = 0; i < iv.length; i++) {
            iv[i] = 0;
        }

        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secretKey, "DES"),
                new IvParameterSpec(iv));
        return cipher.doFinal(encryptedPassword);
    }

    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("Usage:  java Decrypt <password>");
            System.exit(1);
        }

        if (args[0].length() % 2 != 0) {
            System.err
                    .println("Password must consist of hex pairs.  Length is odd (not even).");
            System.exit(2);
        }

        byte[] secret = new byte[args[0].length() / 2];
        for (int i = 0; i < args[0].length(); i += 2) {
            String pair = args[0].substring(i, i + 2);
            secret[i / 2] = (byte) (Integer.parseInt(pair, 16));
        }

        try {
            System.out.println(new String(decryptPassword(secret)));
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
            System.exit(3);
        }
    }
}
like image 44
Topera Avatar answered Oct 21 '22 09:10

Topera