适应您的评论,这是接近,但不是很使用的盐正确链接到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。
如果您知道所有明文密码,为什么不使用自己的salting + hashing过程,并用新的哈希密码替换旧的密码? – 2012-08-07 11:34:53
不,我不知道所有的密码,只是我的(管理员)用户的密码。我会修改原来的问题,使其更清楚。 – 2012-08-07 12:00:35
啊,好的。链接页面表示Oracle11g将SHA1(密码|| salt)存储在一列中。它不知道盐是什么或它存储在哪里。如果你能找到它,那么实现这个相同的算法应该很容易。有关详细信息,请参阅http://www.petefinnigan.com/weblog/archives/00001097.htm。 – 2012-08-07 12:05:28