Java 有人知道 JDeveloper/SQL Developer 使用什么加密技术来保存凭据吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1032721/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 22:28:52  来源:igfitidea点击:

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

javaoracleoracle-sqldeveloperjdeveloper

提问by Nano Taboada

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

Oracle SQL 开发人员连接

<?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.

任何建议将不胜感激。

采纳答案by Adam Paynter

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:

出于好奇,您实际看到的是与加密密码连接的密钥。例如,我尝试使用以下方法加密密码“SAILBOAT”:

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):

接下来的 8 个字节代表随机生成的密钥(用于 DES 密码):

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);
}

回答by Tony Andrews

I don't know, but I wouldn't be surprised if it was DBMS_OBFUSCATION_TOOLKITbeing used something like this:

我不知道,但如果DBMS_OBFUSCATION_TOOLKIT被使用这样的东西,我不会感到惊讶:

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

回答by Peter

The length of the hash is 50 hex characters, which is 200 bits, so it may be the the hash of the password with a salt, prepended with the salt, like:

散列的长度是 50 个十六进制字符,也就是 200 位,所以它可能是带盐的密码散列,加上盐,例如:

salt | hash(salt | password)

where | means concatenation.

哪里| 表示串联。

Just speculation though. My guess would be a 40-bit salt and a SHA-1 hash, since SHA-1 produces 160-bit hashes.

不过也只是猜测。我的猜测是 40 位盐和 SHA-1 哈希,因为 SHA-1 产生 160 位哈希。

Would be helpful to provide some input/output test data to check against!

提供一些输入/输出测试数据来检查会很有帮助!

回答by Rob van Laarhoven

I'm not sure about this but I always thought hashes can't be decrypted, only compared to another hash. MD5 generates a hash. The saved password in SQL Developer needs to be decrypted and send to the server. So the DES3Encrypt and DES3Decrypt procedures in dbms_obfuscation_toolkit package are a better bet. But the decrypt should be called before connecting to a database, so it's probably a Java crypto package with DES methods.

我对此不确定,但我一直认为散列无法解密,只能与另一个散列进行比较。MD5 生成散列。SQL Developer 中保存的密码需要解密并发送到服务器。所以 dbms_obfuscation_toolkit 包中的 DES3Encrypt 和 DES3Decrypt 过程是更好的选择。但是应该在连接到数据库之前调用解密,所以它可能是一个带有 DES 方法的 Java 加密包。

回答by Tim

FYI the password 'apps_ro' encrypts as:

仅供参考,密码“apps_ro”加密为:

     <StringRefAddr addrType="password">
        <Contents>051DC8A88C574538CC4AEE32D326E9480659C06CEC271EA6D7</Contents>
     </StringRefAddr>

回答by Korny

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!

请注意,上面 Tim 的密码哈希不适用于“apps_ro”——大概是他从错误的地方剪切和粘贴的……我不会发布真实的密码,以防他不想分享!

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:

我有一个类似的问题,试图集中存储我的数据库凭据(对于非安全数据库!),然后导出 sql developer xml 文件。我不知道算法是什么 - 但是,您实际上不需要知道算法,因为您可以自己调用 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 .

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

然后要么将它们加载到您的 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" 

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

请注意,无论算法是什么,都有一个随机因素,因此两次使用相同的密码会产生两个不同的十六进制字符串。

回答by maximusin9

The same code as kornelissietsma has given, but written on java:

与 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();
    }   
}

Can be executed as following:

可以执行如下:

# 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

回答by Topera

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

这个解决方案对我很有用......复制自: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);
        }
    }
}

回答by Madhu

Here's a python snippet if anyone is intersted. It's a translation of Adam Paynter'sexample above. It uses pyDes

如果有人感兴趣,这里有一个 python 片段。这是上面Adam Paynter示例的翻译。它使用pyDes

import os
import pyDes

import binascii

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

    cipherText = '%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:])

回答by Jakub Jirutka

Methods described in other answers unfortunately doesn't work in SQL Developer 4.x. There's extension that works on both 3.x and 4.x versions and it's very easy to use:

不幸的是,其他答案中描述的方法在 SQL Developer 4.x 中不起作用。有适用于 3.x 和 4.x 版本的扩展,并且非常易于使用:

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

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