C#:使用来自 /etc/shadow 的 linux 用户的 salt 验证密码哈希 (SHA512)

Posted

技术标签:

【中文标题】C#:使用来自 /etc/shadow 的 linux 用户的 salt 验证密码哈希 (SHA512)【英文标题】:C#: Verify password hash (SHA512) with salt for linux user from /etc/shadow 【发布时间】:2020-07-04 18:54:00 【问题描述】:

我想使用本机 C# 代码 (.NET Core) 验证 Linux 用户的用户凭据(名称和密码)。 Linux 系统上的用户凭据通常存储在文件中:/etc/shadow

例如,名为“csharp”且密码为“1337”的用户在文件/etc/shadow中有以下条目:

string entry = "csharp:$6$qVnvjWpk$DOUTmbC9ROZ6s1h0hCZTYWLFfVeUWDbz8f0EUFPEJEC2UKQV0gRiIfoGpnaA.8i4RCcrGpOEHEd9xrAUDpo3Y/:18337:0:99999:7:::"

第一个“:”之前的字符串是用户名 => entry.Split(":")[0] (csharp)

第一个“$”之后的字符是哈希方法 => entry.Split("$")[1] (6 = SHA256)。可能的方法是:MD5 => 1; SHA256 => 5; SHA512 => 6

第二个“$”之后的字符串是盐(或哈希?)=> entry.Split("$")[2] (qVnvjWpk)

在 Linux 系统上使用“openssl passwd -6 -salt qVnvjWpk 1337”程序openssl时,它会给我以下输出: <pre>$6$qVnvjWpk$DOUTmbC9ROZ6s1h0hCZTYWLFfVeUWDbz8f0EUFPEJEC2UKQV0gRiIfoGpnaA.8i4RCcrGpOEHEd9xrAUDpo3Y/</pre>

如您所见,openssl 输出是 /etc/shadow 条目的一部分:

entry.Split(":")[1] == openssl_output

但是如何使用原生 csharp 代码而不使用程序 openssl 来完成呢?

我有以下方法可以做到这一点。

CheckCredentials("csharp", "1337");
public static bool CheckCredentials(string username, string password) 

    string[] shadow = File.ReadAllLines("/etc/shadow");

    foreach(string entry in shadow) 
        // entry = csharp:$6$qVnvjWpk$DOUTmbC9ROZ6s1h0hCZTYWLFfVeUWDbz8f0EUFPEJEC2UKQV0gRiIfoGpnaA.8i4RCcrGpOEHEd9xrAUDpo3Y/:18337:0:99999:7:::
        if(entry.Split(":")[0] == username) 

            // hash = 6f0ac65fe01188660aad900bfe16c566ebf0e56c0a7d4a15bd831049108de80bd3a2fbf1a8b91662433a40458ec208a207cab073f190bd65b889e95e4fca8e09
            // $6 => SHA512 
            string hash = HashSHA512(password);

            // salt = qVnvjWpk
            string salt = entry.Split("$")[2];

            // >>> how to check now the given password "1337"? <<< 

            break; 
        

        throw new Exception($"User 'username' was not found");

    

    return false;


public static string HashSHA512(string input)

    SHA512Managed crypt = new SHA512Managed();
    StringBuilder hash = new StringBuilder();
    byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(input));

    foreach (byte append in crypto)
    
        hash.Append(append.ToString("x2"));
    
    return hash.ToString();

【问题讨论】:

您找到解决方案了吗?我需要做同样的事情,使用新应用程序验证旧数据库中的密码。好像是extremely complicated。我最好为此找到一个库。 【参考方案1】:

确实很复杂。我发现了一些实现original specificationin C#的代码。它是 SHA-512 支持的 extended。然后我为它制作了some more changes,现在我可以自己使用它了。 Here's the code.(这个答案真的没什么好说的了……)

【讨论】:

以上是关于C#:使用来自 /etc/shadow 的 linux 用户的 salt 验证密码哈希 (SHA512)的主要内容,如果未能解决你的问题,请参考以下文章

/etc/shadow,/etc/passwd,/etc/shadow,/etc/passwd文件的内容解释

/etc/shadow文件详解

/etc/shadow保存用户的啥信息?

/etc/shadow

2021-09-16--Linux-shadow文件

/etc/shadow