2009-06-23 10 views
33

Sarebbe più che interessante per me capire quale tecnica viene utilizzata qui per mantenere dati sensibili poiché ho bisogno di implementare una soluzione simile. Ecco una configurazione di connessione campione e il frammento di esportato risultante:Qualcuno sa quale tecnica di crittografia viene utilizzata da JDeveloper/SQL Developer per mantenere le credenziali?

Oracle SQL Developer Connections http://i44.tinypic.com/2lcwpkg.gif

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

Qualche consiglio sarebbe molto apprezzato.

risposta

41

Per i curiosi, che cosa si sta effettivamente vedere è il segreto chiave concatenata con la password crittografata. Ad esempio, ho provato criptare la password "SAILBOAT" utilizzando:

DatabaseProviderHelper.goingOut("SAILBOAT") 

In questo caso particolare, il risultato è stato:

 
0527C290B40C41D71139B5E7A4446E94D7678359087249A463 

Il primo byte è costante:

 
05 

L' i successivi 8 byte rappresentano la chiave segreta generata in modo casuale (per il codice DES):

 
27C290B40C41D711 

I restanti byte sono la password crittografata:

 
39B5E7A4446E94D7678359087249A463 

Pertanto, per decifrare la password, è sufficiente utilizzare questo:

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

Questo codice ha decodificato molte delle mie password memorizzate, grazie! – Jason

+1

@ Jason: Prego! Sono felice di aiutare. Ho trovato questa indagine particolarmente interessante. :) –

+1

Qualcuno dovrebbe riscriverlo in Javascript in modo da poter decifrare le password online (senza doverlo caricare ovviamente!) – MasterScrat

1

Non lo so, ma non sarei sorpreso se fosse DBMS_OBFUSCATION_TOOLKIT essere qualcosa di usato in questo modo:

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

Tony interessante! Grazie mille per il contributo! –

+1

Ne dubito. Per utilizzare DBMS_OBFUSCATION_TOOLKIT, è necessario essere già connessi al database. Quindi, come potrebbe il client accedere al database quando ha bisogno del database per recuperare la password?!? –

+0

Mi hai portato lì! –

2

La lunghezza del hash è 50 caratteri esadecimali, che si trova a 200 bit così, può essere l'hash della password con un sale, preceduto dal sale, come:

salt | hash(salt | password) 

dove | significa concatenazione.

Solo speculazioni però. La mia ipotesi sarebbe un sale di 40 bit e un hash SHA-1, dal momento che SHA-1 produce hash di 160 bit.

Sarebbe utile fornire alcuni dati di test di input/output da controllare!

+0

Grazie per il commento Peter! I dati di autenticazione che ho usato per l'esempio sono semplicemente "username" e "password". –

3

Non ne sono sicuro, ma ho sempre pensato che gli hash non possono essere decifrati, solo rispetto ad un altro hash. MD5 genera un hash. La password salvata nello sviluppatore SQL deve essere decrittografata e inviata al server. Quindi le procedure DES3Encrypt e DES3Decrypt nel pacchetto dbms_obfuscation_toolkit sono una scommessa migliore. Ma il decrypt dovrebbe essere chiamato prima di connettersi a un database, quindi è probabilmente un pacchetto di crittografia Java con metodi DES.

+0

Grazie per la risposta Robert! –

-3

FYI la password 'apps_ro' crittografa come:

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

Questo non risponde alla domanda. – Amit

10

Si noti che la password hash di Tim di cui sopra non è per "apps_ro" - presumibilmente ha tagliato e incollato da posto sbagliato ... non voglio postare la vera password nel caso in cui sia qualcosa che non vuole condividere!

Ho avuto un problema simile, tentando di archiviare centralmente le credenziali db (per i database non protetti!) E quindi esportando i file xml dello sviluppatore sql. Non ho idea di cosa sia l'algoritmo, tuttavia non è necessario conoscere l'algoritmo, poiché è possibile chiamare l'API java Oracle da soli. Se si dispone di SQLDeveloper, basta afferrare i file Jar giusti:

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

Allora o caricarli nel vostro app Java, o usare qualcosa come JRuby come faccio io:

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

Nota che l'algoritmo, qualsiasi cosa è, ha un fattore casuale, quindi la stessa password utilizzata due volte può produrre due diverse stringhe esadecimali.

+0

Grazie mille per il contributo kornelissietsma! –

+0

Questa è un'ottima soluzione, ma si noti che le posizioni dei jar sono state leggermente modificate in sqldeveloper 3. Uso questo codice jython (Oracle spedisce jython con quasi tutto ...): 'importa sys; sys.path.append (r'C: \ sqldeveloper \ sqldeveloper \ estensioni \ oracle.datamodeler \ lib \ ojmisc.jar '); sys.path.append (r'C: \ sqldeveloper \ moduli \ oracle.adf.model_11.1.1 \ db-ca.jar '); da oracle.jdevimpl.db.adapter.DatabaseProviderHelper import goingOut as criptare; da oracle.jdevimpl.db.adapter.DatabaseProviderHelper import comingin as decrypt' –

4

Lo stesso codice come kornelissietsma ha dato, ma scritto in 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(); 
    } 
} 

può essere eseguito come segue:

# 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

Questa soluzione funziona grande per me ... Copiato da: 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); 
     } 
    } 
} 
+2

Non è la mia risposta con un metodo 'main'? L'articolo non dà credito. :( –

+0

ops! Scusa Adam, non l'ho visto, quindi grazie per la risposta! – Topera

+0

Non devi essere affatto dispiaciuto, sono solo un po 'rattristato dal fatto che il mio codice sia stato utilizzato senza credito –

2

Ecco un frammento di pitone se un yone è intersted. È una traduzione dell'esempio Adam Paynter's sopra. Esso utilizza 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

Dato è troppo vecchio e funziona solo con la versione 2.x, ma non ora. perché Oracle SQL Developer ha modificato l'algoritmo di crittografia nella versione 3.xe 4.x.

versione 3

password vengono memorizzate nel file criptati connections.xml in quei luoghi:

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 

versione 4

password vengono memorizzate criptate nei collegamenti di cui sopra. file xml ma la chiave di crittografia utilizza un valore unico della macchina db.system.id nelle preferenze del prodotto.file xml accessibili qui:

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 

per decriptare file di ultima crittografato è possibile utilizzare Show me password estensione per SQL Developer. O decifrare il file con SQL Developer password decryptor

Problemi correlati