2012-08-07 99 views
1

我有一個基於使用Oracle 11g的Java/Spring的Web應用程序。目前,用戶在登錄時直接通過系統表SYS.USER$通過用戶名/密碼進行認證。將Oracle身份驗證遷移到表

這必須改變,所以我們創建了一個(常規)新表來存儲所有用戶數據。我們將所有現有的密碼插入到新創建的表中。然而,密碼似乎要加密/散列在於通過真實this site

一個實例描述的方式:一旦用戶輸入XXXXX,所述數據庫存儲07E4898C06DEF253

我想使用新(常規)表中存儲的舊密碼執行認證。我的問題是我不知道如何驗證現有的密碼,因爲我不知道它們是如何被哈希/加密的。

我玩過ora_hashdbms_obfuscation_toolkit.DESDecrypt,但沒有一個給我一個正確的結果。我知道我的用戶的密碼是正確的,我可以看到Oracle爲此產生的值,但我無法再現Oracle通常「處理」密碼數據的方式。

有沒有辦法解決這個問題,而無需重置所有密碼?

+1

如果您知道所有明文密碼,爲什麼不使用自己的salting + hashing過程,並用新的哈希密碼替換舊的密碼? – 2012-08-07 11:34:53

+0

不,我不知道所有的密碼,只是我的(管理員)用戶的密碼。我會修改原來的問題,使其更清楚。 – 2012-08-07 12:00:35

+0

啊,好的。鏈接頁面表示Oracle11g將SHA1(密碼|| salt)存儲在一列中。它不知道鹽是什麼或它存儲在哪裏。如果你能找到它,那麼實現這個相同的算法應該很容易。有關詳細信息,請參閱http://www.petefinnigan.com/weblog/archives/00001097.htm。 – 2012-08-07 12:05:28

回答

1

適應您的評論,這是接近,但不是很使用的鹽正確鏈接到Java實現:

import java.security.MessageDigest; 
import java.util.Formatter; 

class Main{ 

    public static String calculateHash(String password) throws Exception{ 
     MessageDigest crypt = MessageDigest.getInstance("SHA-1"); 

     String encodedPassword = "S:71752CE0530476A8B2E0DD218AE59CB71B211D7E1DB70EE23BFB23BDFD48"; 

     // Convert password to bytes 
     byte[] bPassword = password.getBytes("UTF-8"); 

     // Get salt from encoded password 
     String salt = encodedPassword.substring(42, 62); 
     System.out.println("Salt is " + salt); 

     // Convert salt from hex back to bytes 
     // based on http://stackoverflow.com/a/140861/266304 
     int len = salt.length(); 
     byte[] bSalt = new byte[len/2]; 
     for (int i = 0; i < len; i += 2) { 
      bSalt[i/2] = (byte) ((Character.digit(salt.charAt(i), 16) << 4) 
       + Character.digit(salt.charAt(i+1), 16)); 
     } 

     // Add converted salt to password bytes 
     // based on http://stackoverflow.com/a/80503/266304 
     byte[] bData = new byte[bPassword.length + bSalt.length]; 
     System.arraycopy(bPassword, 0, bData, 0, bPassword.length); 
     System.arraycopy(bSalt, 0, bData, bPassword.length, bSalt.length); 

     // Hash the final byte array 
     crypt.update(bData); 
     byte bHash[] = crypt.digest(); 

     Formatter formatter = new Formatter(); 
     for (byte b : bHash) 
     { 
      formatter.format("%02x", b); 
     } 

     System.out.println("Expected  " + encodedPassword.substring(2,42)); 

     return formatter.toString().toUpperCase(); 
    } 

    public static void main(String[] args) throws Exception { 
     System.out.println("The result is " + calculateHash("ZK3002")); 
    } 
} 

其中給出輸出:

Salt is 1DB70EE23BFB23BDFD48 
Expected  71752CE0530476A8B2E0DD218AE59CB71B211D7E 
The result is 71752CE0530476A8B2E0DD218AE59CB71B211D7E 

的PL/SQL版本涉及一些轉換; dbms_crypto.hash()需要RAW參數,因此您必須將明文密碼轉換爲RAW,然後連接已提取的salt(已經是十六進制)。 (在Pete Finnigan博客的PL/SQL版本中,您可能會注意到他有一個明確的hextoraw調用,所以我簡化了一下)。因此,對於您的示例,傳遞給dbms_crypto.hash的參數應該是ZK3002的十六進制(正常,未加工)等效,即5A4B33303032,其中十六進制的鹽級聯到該值;所以5A4B333030321DB70EE23BFB23BDFD48

對於Java版本,您傳遞一個字節數組,但這意味着您需要將從存儲密碼中提取的鹽從十六進制中轉換回來,然後再將它加到密碼上;並且由於它不太可能具有有用的字符串表示形式,所以不妨將它直接放入字節數組中。因此,將密碼轉換爲字節數組,將鹽轉換爲字節數組,並將兩個數組粘在一起。然後這成爲您傳遞給MessageDigest的值。

您可以將生成的散列與Oracle散列版本進行比較,跳過初始S:和嵌入的salt。

+0

所以沒有其他方法比蠻力找到他的密碼。不感到驚訝。 – 2012-08-08 10:42:24

+0

@MatinKh - 我不認爲他特別想要對它們進行散列(當然這是不可能的,沒有暴力強制它們),只是想通過Oracle散列值進行驗證。我可能會考慮只在用戶第一次登錄時執行此操作,然後以非Oracle方式(也許是'bcrypt',但不管)來重新密碼並將其存儲以備將來使用。取決於爲什麼它可能會首先改變。 – 2012-08-08 10:54:47

+0

是的,我現在明白了。從這個問題中我得到了這種感覺,他正在尋找解密這些加密密碼的方法。 (如果有人給了他答案,這會讓我感到驚訝) – 2012-08-08 11:05:01