Кто-нибудь знает, какую технику шифрования использует JDeveloper / SQL Developer для сохранения учетных данных? - PullRequest
37 голосов
/ 23 июня 2009

Мне было бы более интересно понять, какой метод используется здесь для сохранения разумных данных, поскольку мне нужно реализовать подобное решение. Вот пример конфигурации соединения и полученный экспортированный фрагмент:

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>

Любой совет был бы очень признателен.

Ответы [ 11 ]

46 голосов
/ 24 июня 2010

Любопытно, что на самом деле вы видите секретный ключ, соединенный с зашифрованным паролем. Например, я попытался зашифровать пароль «Парусник», используя:

DatabaseProviderHelper.goingOut("SAILBOAT")

В данном конкретном случае результат был:

0527C290B40C41D71139B5E7A4446E94D7678359087249A463

Первый байт является константой:

05

Следующие 8 байтов представляют случайно сгенерированный секретный ключ (для шифра DES):

27C290B40C41D711

Остальные байты являются зашифрованным паролем:

39B5E7A4446E94D7678359087249A463

Поэтому, чтобы расшифровать пароль, вы просто используете это:

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);
}
11 голосов
/ 04 марта 2010

Обратите внимание, что хэш пароля Тима выше не для "apps_ro" - предположительно, он вырезал и вставил не из того места ... Я не буду публиковать реальный пароль, если он не хочет делиться!

У меня была похожая проблема: я пытался централизованно хранить свои учетные данные в БД (для незащищенных баз данных!), А затем экспортировал XML-файлы sql developer. Я понятия не имею, что такое алгоритм - однако вам не нужно знать алгоритм, так как вы можете просто вызвать Oracle Java API самостоятельно. Если у вас есть SQLDeveloper, просто возьмите нужные файлы Jar:

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

Затем либо загрузите их в свое Java-приложение, либо используйте что-то вроде JRuby, как я:

$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" 

Обратите внимание, что алгоритм, каким бы он ни был, имеет случайный множитель, поэтому один и тот же пароль, использованный дважды, может создать две разные шестнадцатеричные строки.

8 голосов
/ 20 января 2011

Это решение прекрасно работает для меня ... Скопировано из: 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);
        }
    }
}
6 голосов
/ 21 апреля 2016

Данное решение слишком старое и работает только с версией 2.x, но не сейчас. потому что Oracle SQL Developer, изменил алгоритм шифрования в версиях 3.x и 4.x.

Версия 3

Пароли хранятся в зашифрованном виде в файле connections.xml в следующих местах:

Windows: C:\Users\<USER>\AppData\Roaming\SQL Developer\system<VERSION>\o.jdeveloper.db.connection.<VERSION>\connections.xml
Linux: ~/.sqldeveloper/system<VERSION>/o.jdeveloper.db.connection.<VERSION>/connections.xml

Версия 4

Пароли хранятся в зашифрованном виде в вышеупомянутом файле connections.xml, но ключ шифрования использует уникальное для компьютера значение db.system.id в файле product-preferences.xml, доступном здесь:

Windows: C:\Users\<USER>\AppData\Roaming\SQL Developer\system<VERSION>\o.sqldeveloper.<VERSION>\product-preferences.xml
Linux: ~/.sqldeveloper/system<VERSION>/o.sqldeveloper.<VERSION>/product-preferences.xml

Для расшифровки последнего зашифрованного файла вы можете использовать Показать мне пароль * Расширение 1019 * для SQL Developer. Или расшифруйте файл с помощью Расшифровщик пароля разработчика SQL

5 голосов
/ 09 марта 2015

Методы, описанные в других ответах, к сожалению, не работают в SQL Developer 4.x. Существует расширение, которое работает в версиях 3.x и 4.x, и его очень легко использовать:

https://github.com/tomecode/show-me-password-sqldev-jdev

5 голосов
/ 24 июня 2010

Тот же код, который дал kornelissietsma, но написанный на Java:

import oracle.jdevimpl.db.adapter.DatabaseProviderHelper;

class Decode {
    String pass = ""; 

    public Decode() {
        pass = DatabaseProviderHelper.comingIn("HASH");
        System.out.println(pass);
    }   

    public static void main(String[] args){
        new Decode();
    }   
}

Может быть выполнено следующим образом:

# javac -classpath .:/full/path/to/sqldeveloper/BC4J/lib/db-ca.jar:/full/path/to/sqldeveloper/jlib/ojmisc.jar sqldeveloper_hash_decode.java
# java -classpath .:/full/path/to/sqldeveloper/BC4J/lib/db-ca.jar:/full/path/to/sqldeveloper/jlib/ojmisc.jar Decode
4 голосов
/ 24 июня 2009

Я не уверен в этом, но я всегда думал, что хэши не могут быть расшифрованы, только по сравнению с другим хэшем. MD5 генерирует хэш. Сохраненный пароль в SQL Developer необходимо расшифровать и отправить на сервер. Поэтому процедуры DES3Encrypt и DES3Decrypt в пакете dbms_obfuscation_toolkit являются лучшим выбором. Но дешифрование следует вызывать перед подключением к базе данных, так что, вероятно, это криптопакет Java с методами DES.

2 голосов
/ 02 августа 2013

Вот фрагмент кода на Python, если кто-нибудь заинтересовался. Это перевод примера Адама Пайнтера выше. Он использует pyDes

import os
import pyDes

import binascii

if __name__ == '__main__':
    # Encrypt example
    zero = '\0\0\0\0\0\0\0\0'
    key = os.urandom(8)
    plainText = 'open sesame'
    cipher = pyDes.des(key, mode=pyDes.CBC, IV=zero, padmode=pyDes.PAD_PKCS5)

    cipherText = '\5%s%s' % (key, cipher.encrypt(plainText))
    cipherHex = binascii.hexlify(cipherText)

    # This is what SQLDeveloper stores in XML
    print cipherHex

    # Decrypt above
    cipherText = binascii.unhexlify(cipherHex)
    assert cipherHex[0:2] == '05'
    key = cipherText[1:1+8]
    cipher = pyDes.des(key, mode=pyDes.CBC, IV=zero, padmode=pyDes.PAD_PKCS5)
    print cipher.decrypt(cipherText[1+8:])
1 голос
/ 23 июня 2009

Длина хеша равна 50 шестнадцатеричным символам, что составляет 200 бит, поэтому это может быть хеш пароля с солью, с добавлением соли, например:

salt | hash(salt | password)

где | означает конкатенацию.

Только предположения. Я предполагаю, что это будет 40-битная соль и хэш SHA-1, поскольку SHA-1 создает 160-битные хеш-коды.

Было бы полезно предоставить некоторые тестовые данные ввода / вывода для проверки!

1 голос
/ 23 июня 2009

Не знаю, но я не удивлюсь, если бы DBMS_OBFUSCATION_TOOLKIT использовалось примерно так:

l_hash := dbms_obfuscation_toolkit.md5(input_string=>:username||:password);
...