【问题标题】:Does anybody know what encrypting technique is JDeveloper/SQL Developer using to persist credentials?有人知道 JDeveloper/SQL Developer 使用什么加密技术来保存凭据吗?
【发布时间】:2010-11-05 04:28:05
【问题描述】:

如果我需要实施类似的解决方案,我会非常感兴趣地了解这里使用哪种技术来保存敏感数据。这是一个示例连接配置和导出的 sn-p:

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

任何建议将不胜感激。

【问题讨论】:

    标签: java oracle oracle-sqldeveloper jdeveloper


    【解决方案1】:

    给定的解决方案太旧了,只适用于 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文件中,但加密密钥使用product-preferences.xml文件中的机器唯一值db.system.id:

    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
    

    要解密最新的加密文件,您可以使用 SQL Developer 的 Show me password 扩展名。或者用SQL Developer password decryptor解密文件

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

        如果有人感兴趣,这里有一个 python sn-p。 这是上面Adam Paynter's 示例的翻译。 它使用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:])
        

        【讨论】:

          【解决方案4】:

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

          【讨论】:

          • 这不是我用main 方法的答案吗?这篇文章没有给出任何信用。 :(
          • 操作!对不起亚当,我没看到。所以,谢谢你的回答!
          • 您完全不必感到抱歉。我有点难过我的代码在没有信用的情况下被使用。
          • export xpath="//References/Reference/RefAddresses/StringRefAddr[@addrType='user' or @addrType='password']/Contents/text()"
          • 不幸的是,这不再适用于 SQL Developer 4.x。
          【解决方案5】:

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

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

          【讨论】:

          • @Jason:不客气!我很乐意提供帮助。我发现这项调查特别有趣。 :)
          • 有人应该用Javascript重写这个,这样我们就可以在线解密密码(当然不需要上传它!)
          【解决方案6】:

          与 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
          

          【讨论】:

            【解决方案7】:

            请注意,上面 Tim 的密码散列不适用于“apps_ro” - 可能是他从错误的位置剪切和粘贴...我不会发布真正的密码,以防他不想共享!

            我遇到了类似的问题,试图集中存储我的 db 凭据(对于非安全数据库!),然后导出 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 .
            

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

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

            【讨论】:

            • 非常感谢 kornelissietsma 的贡献!
            • 这是一个很好的解决方案,但请注意 sqldeveloper 3 中的 jar 位置略有变化。我使用这个 jython 代码(Oracle 提供 jython 几乎所有东西......):import sys; sys.path.append(r'C:\sqldeveloper\sqldeveloper\extensions\oracle.datamodeler\lib\ojmisc.jar'); sys.path.append(r'C:\sqldeveloper\modules\oracle.adf.model_11.1.1\db-ca.jar'); from oracle.jdevimpl.db.adapter.DatabaseProviderHelper import goingOut as encrypt; from oracle.jdevimpl.db.adapter.DatabaseProviderHelper import comingIn as decrypt
            【解决方案8】:

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

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

            【讨论】:

            • 这不能回答问题。
            【解决方案9】:

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

            【讨论】:

            • 谢谢罗伯特的回答!
            【解决方案10】:

            哈希的长度是50个十六进制字符,也就是200位,所以它可能是密码的哈希加盐,前面加盐,比如:

            salt | hash(salt | password)
            

            在哪里 |表示串联。

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

            将有助于提供一些输入/输出测试数据进行检查!

            【讨论】:

            • 感谢彼得的评论!我用于示例的身份验证数据只是“用户名”和“密码”。
            【解决方案11】:

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

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

            【讨论】:

            • 有趣的托尼!非常感谢您的贡献!
            • 我对此表示怀疑。要使用 DBMS_OBFUSCATION_TOOLKIT,您必须已经连接到数据库。那么客户端在需要数据库找回密码的时候怎么登录数据库呢?!?
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-05-27
            • 1970-01-01
            • 2018-11-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-07-22
            相关资源
            最近更新 更多