我有一个Oracle数据库。我想用C#加密传入的密码,并将其与存储在内置oracle表sys.user $中的值(特别是“ spare4”列)进行比较。
是否可以这样做?我试图加密密码,但是它没有生成与Oracle数据库表中生成的值相同的输出,因此很明显我缺少Oracle应用的逻辑。有什么想法吗?
据我了解,前40个字符是哈希密码,后20个字符是哈希Salt值。
在Oracle 11g及更高版本中,它使用Salt(不知道Oracle如何生成此密码)并应用密码,然后使用SHA-1对其进行哈希处理以生成S:根据以下博客{部分3 }}和password hashes
这是当前代码:
public static string GenerateSaltedSHA1(string plainTextString, int saltSize)
{
HashAlgorithm algorithm = new SHA1Managed();
var saltBytes = GenerateSalt(saltSize);
var plainTextBytes = Encoding.ASCII.GetBytes(plainTextString);
var plainTextWithSaltBytes = AppendByteArrays(plainTextBytes, saltBytes);
var saltedSHA1Bytes = algorithm.ComputeHash((byte[]) plainTextWithSaltBytes);
var saltedSHA1WithAppendedSaltBytes = AppendByteArrays(saltedSHA1Bytes, saltBytes);
return Convert.ToBase64String(saltedSHA1WithAppendedSaltBytes);
}
private static byte[] GenerateSalt(int saltSize)
{
var rng = new RNGCryptoServiceProvider();
var buff = new byte[saltSize];
rng.GetBytes(buff);
return buff;
}
private static byte[] AppendByteArrays(byte[] byteArray1, byte[] byteArray2)
{
var byteArrayResult =
new byte[byteArray1.Length + byteArray2.Length];
for (var i = 0; i < byteArray1.Length; i++)
byteArrayResult[i] = byteArray1[i];
for (var i = 0; i < byteArray2.Length; i++)
byteArrayResult[byteArray1.Length + i] = byteArray2[i];
return byteArrayResult;
}
我了解在Oracle中DBMS_CRYPTO中有一些函数,例如哈希可用于基于密码等特定类型(例如MD5,SHA-1等)创建哈希。
如果有更好的方法,那么我愿意提出建议。
答案 0 :(得分:0)
如果我的评论不清楚(或不相信),则可以使用下面的SQL语句来完成您要查找的内容。它在12c上运行-但不会发誓它将与所有安全选项一起使用。如果您在int i = methods.get("getLength")("count_length_of_it");
中有一个S:零件,它可能应该可以工作。
var fullCopy = `${data.acf['7yr_full_copy']}`;
根据需要更新数据库的“ MYUSERNAME”和“ MYPASSWORDGUESS”。
基于我在C#中的原始代码,是否有等效的方法在C#中执行以下操作? sys.dbms_crypto.hash(utl_raw.cast_to_raw(trial_password)||强制转换(盐为raw(10)),3)
sys.user$.spare4
与您帖子中的with trial as
(SELECT name,
-- The 1st 20 bytes (40 characters) of the "S" part are the hashed password
substr(substr(spare4,3,60),1,40) hashed_pwd,
-- The last 10 bytes (20 characters) of the "S" part are the plaintext salt
substr(substr(spare4,3,60),-20) salt,
-- I want to know if the password for user MYUSERNAME is "MYPASSWORDGUESS"...
'MYPASSWORDGUESS' trial_password
from sys.user$
where name = 'MYUSERNAME' ),
hashit as (
-- This SELECT adds the salt to our trial password and hashes it.
select name,
trial_password,
hashed_pwd,
salt,
-- The "3" is for the SH1 algorithm
sys.dbms_crypto.hash(
utl_raw.cast_to_raw(trial_password) || cast (salt as raw(10) ),3)
hashed_salted_trial
from trial )
-- If the resulting hash matches what Oracle has stored in spare4, it is good.
SELECT name,
trial_password,
case when hashed_pwd = hashed_salted_trial
then 'Y' ELSE 'N' END password_match
from hashit
;
一样。每个目标都是让您猜测密码并将其转换为字节。
utl_raw.cast_to_raw(trial_password)
在您的帖子中没有等效内容。稍后会对此进行更多介绍。
Encoding.ASCII.GetBytes(plainTextString)
是在Oracle中连接cast(salt as raw(10))
值的方式。它的作用与帖子中的||
相同。
RAW
是在Oracle中生成160位SHA-1哈希的方法。我猜这就是AppendByteArrays
在您的帖子中所做的事情。
因此,您的代码中唯一缺少的是与sys.dbms_crypto.hash(..., 3)
等效的内容。
正如我们所讨论的,您不能为此自己产生盐。您必须使用algorithm.ComputeHash
中编码的盐。那将是该字段“ S:”部分的最后20个字符。看起来像这样:cast(salt as raw(10))
。每两个字符组成一个十六进制的BYTE,它为您提供盐的一个字节。因此,在我的示例中,盐的第一个字节(由“ FA”给出)是15(对于“ F”而言)x16 + 10(对于“ A”而言)= 250。
希望这足以让您在C#中实现逻辑。但是,实际上并不需要这样做,因为盐的输入值只能来自Oracle数据库中的user$.spare4
。既然您还是愿意使用Oracle,那么
FA338B110F78548CCB44
就这样
user$.spare4
,其余工作在C#中完成。您最好还是让Oracle做好自己的事。