将传入凭据与Oracle哈希密码进行比较

时间:2018-10-11 13:45:32

标签: c# oracle hash

我有一个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等)创建哈希。

如果有更好的方法,那么我愿意提出建议。

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做好自己的事。