【问题标题】:How can I encrypt SHA512 hash with salt in C and ubuntu?如何在 C 和 ubuntu 中用盐加密 SHA512 哈希?
【发布时间】:2021-02-15 03:26:04
【问题描述】:

我正在尝试用盐加密哈希。

在命令行中,我使用以下命令在影子文件中找到了正确的哈希值。

openssl passwd -6 -salt abcd appple $6$abcd$vIWAp1OzuGuo376cRkZ5DXcgI8KIlnUibsk.iydtfCFqb9okOz.S70Ysu7.qRRg9Me5XwAyTjkZBQJXiIxwpL/

我尝试使用 openssl(How to convert a raw 64-byte binary to Hex or ASCII in C) 在 C 中获取它。

#include <openssl/sha.h>
#include <stdio.h>
#include <string.h>

int main() {
        char data[] = "abcdapple";
        unsigned char hash[SHA512_DIGEST_LENGTH*2+1];
        SHA512((unsigned char *)&data, strlen(data), (unsigned char *)&hash);

        char buffer[SHA512_DIGEST_LENGTH*2+1];
        for(int i =0; i < SHA512_DIGEST_LENGTH; ++i)
                sprintf(&buffer[i*2],"%02x", (unsigned int)hash[i]);
        printf("digest: %s\n", buffer);
        printf("\n");
}

但生成的哈希是 ea1d5a8b11297d20f954a3ab15092d21b733484b2eb9b7226b2b138639f0df30627774945458a774eb279cd83d2e977a2bc5599606d6a9a3b2f075f9b189

我认为我没有很好地使用盐。似乎还有一个根本问题。 我不能用 C 实现加盐的加密程序吗?

【问题讨论】:

  • 你不会“加密”散列,不管有没有盐,首先...
  • @AKX 你的意思是它只是创建一个哈希?
  • 不,你不能只是连接。注意哈希的开头。 $6$abcd$。 6 对应于您的命令中的-6,之后您就有了明文形式的盐。
  • @klutt 如果我可以使用盐计算哈希,我不能在创建哈希之前连接 $6$abcd$ 吗?
  • @Guk 不知道。我刚刚告诉你为什么你的方法不起作用。 :)

标签: c hash sha512


【解决方案1】:

您尝试生成的不是普通的 SHA-512 哈希。它是一个散列密码,使用一种基于 SHA-512 的特殊用途算法openssl passwd 计算此算法,但 OpenSSL 库的 SHA512 函数计算普通 SHA-512。这种特殊用途的算法以及其他几个具有相同功能的算法都记录在 crypt(5) manpage 中。

您可以可能使用来自libcrypt 库的crypt_r 函数(由于历史原因,此库名称不准确;它提供密码哈希算法),使用与openssl passwd 相同的专用算法计算散列密码。在我的电脑上,这个程序打印出你得到的以$6$abcd 开头的相同字符串:

#include <crypt.h>
#include <string.h>
#include <stdio.h>

int main(void)
{
    struct crypt_data cd;
    memset(&cd, 0, sizeof cd);
    puts(crypt_r("appple", "$6$abcd", &cd));
    return 0;
}

注意第二个参数(在我一直链接到的文档中称为“设置字符串”)如何同时包含盐值 abcd 和前缀 $6$(它告诉 crypt_r 使用基于 SHA-512 的哈希)。它以这种方式工作,因此login(1) 可以使用刚刚从 tty 读取的密码作为第一个参数调用crypt_r,并将影子文件中的密码条目作为第二个参数,如果它返回相同的字符串,它将其作为第二个参数,则用户已成功通过身份验证。

像这样编译和运行:

$ gcc -std=gnu11 -O test.c -lcrypt
$ test $(./a.out) = '$6$abcd$vIWAp1OzuGuo376cRkZ5DXcgI8KIlnUibsk.iydtfCFqb9okOz.S70Ysu7.qRRg9Me5XwAyTjkZBQJXiIxwpL/'; echo $?
0

我说可能是因为这个库支持的专用散列算法集因 Unix 而异。如果(且仅当)您可以将字符串$6$abcd$... 放入/etc/shadow 的某个帐户的密码条目中,然后使用密码appple 以该帐户成功登录,那么它应该可以工作。

libcrypt 还可能有一个名为crypt_gensalt_rn 的函数,您可以使用它来生成设置字符串并选择适当的散列算法。这是该功能的演示:

#include <crypt.h>
#include <string.h>
#include <stdio.h>

int main(void)
{
    char setting[CRYPT_GENSALT_OUTPUT_SIZE];
    crypt_gensalt_rn(0, 0, 0, 0, setting, CRYPT_GENSALT_OUTPUT_SIZE);

    struct crypt_data cd;
    memset(&cd, 0, sizeof cd);
    puts(crypt_r("appple", setting, &cd));
    return 0;
}

如果你编译并运行 this 程序,它将打印以$6$abcd开头的字符串;它将打印其他内容,例如

$y$j9T$0aVoGQ/PFN0PHbcYlKZdZ1$05NbMJLbRliM7fmtSAeZoy3OoRsBqETpAZXQpnPey82

每次运行时它打印的内容都会改变,但它输出的每个字符串都可以用作/etc/shadow 条目,允许某人使用密码appple 登录。您可以使用我在 0 处保留的前四个参数来控制它的行为。

(披露:我是 lib(x)crypt 的作者之一。)

【讨论】:

  • 非常感谢!我想我在一定程度上理解了文章的内容。代码已成功运行! (由于 gcc 错误,我将 crypt_r("appple", "$6$abcd") 编辑为 crypt_r("appple", "$6$abcd", &cd))。对我帮助很大!!
  • 糟糕,是的,那是我的错误。
【解决方案2】:

您可以在 GitHub 上找到 openssl passwd 命令(尤其是核心 do_passwd 函数)的源代码:https://github.com/openssl/openssl/blob/8ea761bf40e6578ecd95ec47772ef86a2e4d4607/apps/passwd.c#L795-L874

(非常重要的,290 行)SHA-512 passwd 哈希计算函数位于略高于它的位置,位于 https://github.com/openssl/openssl/blob/8ea761bf40e6578ecd95ec47772ef86a2e4d4607/apps/passwd.c#L509-L793

您最好只从您的应用程序中调用 openssl passwd 作为子进程。

【讨论】:

  • 谢谢!我会看到的。
猜你喜欢
  • 2011-01-09
  • 1970-01-01
  • 2012-11-18
  • 2019-11-28
  • 2011-12-06
  • 2017-03-10
相关资源
最近更新 更多