1. 前言
The GNU C Library Reference Manual for version 2.35
2. 加密函数
Cryptographic Functions
GNU C 库仅包含一些特殊用途的加密函数:用于密码存储的单向哈希函数,以及对加密随机源(如果操作系统提供)的访问。需要通用加密的程序应该使用专用的加密库,例如 libgcrypt。
许多国家对加密软件的进口、出口、拥有或使用施加了法律限制。我们谴责这些限制,但我们仍然必须警告您,GNU C 库可能会受到这些限制,即使您自己不使用本章中的函数。这些限制因地而异,并且经常更改,因此我们无法提供比此警告更具体的建议。
2.1. 密码存储
Passphrase Storage
有时有必要确保用户被授权使用机器提供的某些服务——例如,以特定用户 ID 登录(请参阅用户和组)。这样做的一种传统方式是让每个用户选择一个秘密密码。然后,系统可以询问自称用户的用户的密码是什么,如果该人提供了正确的密码,则系统可以授予适当的权限。(传统上,这些被称为“密码”,但现在一个单词太容易猜到了。)
处理密码短语的程序必须特别注意不要将密码透露给任何人,无论如何。将它们保存在只能通过特殊权限访问的文件中是不够的。该文件可能通过错误或错误配置“泄露”,系统管理员不应该了解每个人的密码,即使他们出于某种原因必须编辑该文件。为避免这种情况,密码短语还应在存储之前使用单向函数转换为单向哈希。
单向函数很容易计算,但没有已知的方法来计算它的逆。这意味着系统可以通过对密码进行散列并将结果与存储的散列进行比较来轻松检查密码。但是发现某人密码哈希的攻击者只能通过猜测和检查来发现它对应的密码。单向函数旨在使这个过程变得不切实际地缓慢,除了最明显的猜测。(不要使用字典中的单词作为密码。)
GNU C 库为基于 SHA-2-512、SHA-2-256、MD5 和 DES 加密原语的四个单向函数提供了一个接口。新的密码短语应该使用任何一个基于 SHA 的函数进行散列。其他的对于新设置的密码短语来说太弱了,但我们继续支持它们验证旧密码短语。基于 DES 的散列特别弱,因为它忽略了输入的前八个字符以外的所有字符。
函数:char * crypt (const char *phrase, const char *salt)
Preliminary: | MT-Unsafe race:crypt | AS-Unsafe corrupt lock heap dlopen | AC-Unsafe lock mem | See POSIX Safety Concepts.
函数 crypt 将密码字符串、phrase 转换为适合存储在用户数据库中的单向散列。它返回的字符串将完全由可打印的 ASCII 字符组成。它不会包含空格,也不会包含任何字符“:”、“;”、“*”、“!”或“\”。
salt 参数控制使用哪个单向函数,它还确保每个用户的单向函数的输出都是不同的,即使他们具有相同的密码。这使得从大型用户数据库中猜测密码短语变得更加困难。如果没有盐,攻击者可以进行猜测,对其运行一次 crypt,并将结果与所有哈希值进行比较。Salt 迫使攻击者为每个用户单独调用 crypt。
要验证密码短语,请将先前散列的密码短语作为盐传递。要散列一个新的密码以进行存储,请将 salt 设置为由前缀和随机选择的字符序列组成的字符串,如下表所示:
单向函数 前缀 随机序列
SHA-2-512 '$6$' 16 characters
SHA-2-256 '$5$' 16 characters
MD5 '$1$' 8 characters
DES '' 2 characters
在所有情况下,应从字母表 ./0-9A-Za-z 中选择随机字符。
对于除 DES 之外的所有散列函数,短语可以任意长,并且每个字节的所有八位都是有效的。使用 DES,只有短语的前 8 个字符影响输出,每个字节的第 8 位也被忽略。
crypt 可能会失败。一些实现在失败时返回 NULL,而另一些则返回一个无效的散列密码,它以“*”开头,与 salt 不同。在任何一种情况下,都会设置 errno 来指示问题。一些可能的错误代码是:
EINVAL
盐是无效的;既不是以前散列的密码,也不是任何受支持的散列函数的格式良好的新盐。
EPERM
系统配置禁止使用 salt 选择的哈希函数。
ENOMEM
未能分配内部暂存存储。
ENOSYS
EOPNOTSUPP
根本不支持散列密码,或者不支持盐选择的散列函数。GNU C 库不使用这些错误代码,但它们可能会在其他操作系统上遇到。
crypt 对内部临时工作和它返回的字符串使用静态存储。同时从多个线程调用 crypt 是不安全的,并且它返回的字符串将被任何后续对 crypt 的调用覆盖。
crypt 在 X/Open Portability Guide 中指定,几乎所有历史上的 Unix 系统上都有。但是,XPG 没有指定任何单向函数。
crypt 在 unistd.h 中声明。GNU C 库也在 crypt.h 中声明了这个函数。
函数:char * crypt_r (const char *phrase, const char *salt, struct crypt_data *data)
Preliminary: | MT-Safe | AS-Unsafe corrupt lock heap dlopen | AC-Unsafe lock mem | See POSIX Safety Concepts.
函数 crypt_r 是 crypt 的线程安全版本。它不是静态存储,而是使用其数据参数指向的内存来存储临时文件和它返回的字符串。只要在每个线程中使用不同的数据对象,它就可以安全地从多个线程中使用。它返回的字符串仍将被具有相同数据的另一个调用覆盖。
data 必须指向调用者分配的 struct crypt_data 对象。struct crypt_data 的所有字段都是私有的,但在第一次使用这些对象中的一个之前,必须使用 memset 或类似方法将其初始化为全零。之后,它可以在多次调用 crypt_r 时重复使用,而无需再次擦除。struct crypt_data 非常大,所以最好用 malloc 分配,而不是作为局部变量。请参阅为程序数据分配存储空间。
crypt_r 是一个 GNU 扩展。它在 crypt.h 中声明,结构 crypt_data 也是如此。
以下程序显示了如何在第一次输入密码时使用 crypt。它使用 getentropy 使盐尽可能地不可预测;请参阅生成不可预测的字节。
#include <stdio.h><

本文介绍了GNU C Library中关于密码存储的安全实践,包括单向哈希函数、不可预测字节生成和加密随机源的使用。重点讲解了crypt函数及其在存储密码短语和验证过程中的应用,以及如何生成足够的随机数据以增强安全性。
最低0.47元/天 解锁文章
1058

被折叠的 条评论
为什么被折叠?



