Cryptographic Storage Cheat Sheet / 加密存储速查表¶
Introduction / 介绍¶
This article provides a simple model to follow when implementing solutions to protect data at rest.
本文提供了一个简单的模型,用于实现保护静态数据的解决方案时遵循。
Passwords should not be stored using reversible encryption - secure password hashing algorithms should be used instead. The Password Storage Cheat Sheet contains further guidance on storing passwords.
不应使用可逆加密来存储密码 - 应该使用安全的密码散列算法。密码存储速查表包含了关于存储密码的进一步指导。
Architectural Design / 架构设计¶
The first step in designing any application is to consider the overall architecture of the system, as this will have a huge impact on the technical implementation.
设计任何应用程序的第一步是考虑系统的整体架构,因为这将对技术实现产生巨大影响。
This process should begin with considering the threat model of the application (i.e, who you are trying to protect that data against).
这个过程应该从考虑应用程序的威胁模型开始(即,你试图保护数据免受哪些人的攻击)。
The use of dedicated secret or key management systems can provide an additional layer of security protection, as well as making the management of secrets significantly easier - however it comes at the cost of additional complexity and administrative overhead - so may not be feasible for all applications. Note that many cloud environments provide these services, so these should be taken advantage of where possible. The Secrets Management Cheat Sheet contains further guidance on this topic.
使用专门的密钥或密钥管理系统可以提供额外的安全保护层,同时显著简化密钥管理 - 然而,这也带来了额外的复杂性和管理开销 - 因此,可能不是所有应用程序都可行。请注意,许多云环境提供这些服务,因此应尽可能利用这些服务。密钥管理速查表包含了关于此主题的进一步指导。
Where to Perform Encryption / 在哪里执行加密¶
Encryption can be performed on a number of levels in the application stack, such as:
加密可以在应用堆栈的多个层级上执行,例如:
- At the application level.
中文:在应用层。 - At the database level (e.g, SQL Server TDE)
中文:数据库层面的批准(例如,SQL Server TDE) - At the filesystem level (e.g, BitLocker or LUKS)
中文:在文件系统层(例如,BitLocker 或 LUKS) - At the hardware level (e.g, encrypted RAID cards or SSDs)
中文:在硬件层(例如,加密 RAID 卡或 SSDs)
Which layer(s) are most appropriate will depend on the threat model. For example, hardware level encryption is effective at protecting against the physical theft of the server, but will provide no protection if an attacker is able to compromise the server remotely.
最合适的层取决于威胁模型。例如,硬件层加密可以有效保护服务器免受物理盗窃,但如果攻击者能够远程入侵服务器,则将提供不了任何保护。
Minimize the Storage of Sensitive Information / 最小化敏感信息的存储¶
The best way to protect sensitive information is to not store it in the first place. Although this applies to all kinds of information, it is most often applicable to credit card details, as they are highly desirable for attackers, and PCI DSS has such stringent requirements for how they must be stored. Wherever possible, the storage of sensitive information should be avoided.
保护敏感信息的最佳方式是首先不存储它。尽管这适用于所有类型的信息,但它最常适用于信用卡详情,因为攻击者非常渴望这些信息,PCI DSS 对其存储有严格的要求。 wherever possible,应尽量避免存储敏感信息。
Algorithms / 算法¶
For symmetric encryption AES with a key that's at least 128 bits (ideally 256 bits) and a secure mode should be used as the preferred algorithm.
对于对称加密,应使用至少 128位(理想情况下 256位)密钥和安全的模式的 AES 作为首选算法。
For public-key encryption, use a maintained library implementing an established hybrid encryption scheme, such as Hybrid Public Key Encryption (HPKE), which combines key establishment, key derivation, and authenticated symmetric encryption. X25519 on Curve25519 is a key-agreement primitive; it does not encrypt stored data by itself. Select an appropriate HPKE authentication mode if sender authentication is required; the base mode does not authenticate the sender. HPKE gives only limited replay protection, within a single context. If an attacker could resend a ciphertext, add your own replay check, such as a unique message ID the recipient tracks.
对于公钥加密,使用维护良好的库实现已建立的混合加密方案,例如[混合公钥加密(HPKE)](https://www.rfc-editor.org/rfc/rfc9180.html#section-4),该方案结合了密钥建立、密钥派生和认证对称加密。X25519在Curve25519上 是一种密钥协商原语;它本身并不加密存储的数据。如果需要发送方认证,选择适当的HPKE认证模式;基本模式不认证发送方。HPKE在单个上下文中只提供有限的重放保护。如果攻击者可以重发密文,请添加自己的重放检查,例如接收方跟踪的唯一消息ID。
If RSA must be used, ensure that the key is at least 2048 bits.
如果必须使用 RSA,请确保密钥至少为 2048位。
Post-Quantum Consideration / 后量子考虑¶
RSA and ECC-based public-key cryptography (including Curve25519) are not post-quantum secure. A future cryptographically relevant quantum computer could break them, which matters for data that must remain confidential over long periods.
基于RSA和ECC的公钥密码学(包括Curve25519)不是后量子安全的。未来的具有密码学相关性的量子计算机可能会破解它们,这对于必须长期保持机密性的数据来说很重要。
Where post-quantum key establishment is required, use a supported protocol or library integration of a standardized mechanism such as ML-KEM (NIST FIPS 203), typically in a hybrid construction alongside a classical algorithm during migration. ML-KEM establishes a shared secret for symmetric encryption; it does not replace AES for encrypting stored data. Include the public-key protection of stored encryption keys in the migration plan.
在需要后量子密钥建立的地方,使用支持的协议或库集成标准机制,例如ML-KEM(NIST FIPS 203),通常在迁移期间与经典算法混合构造。ML-KEM为对称加密建立共享密钥;它不替代AES用于加密存储数据。在迁移计划中包括存储加密密钥的公钥保护。
For migration guidance, see the Post-Quantum Cryptography Cheat Sheet.
有关迁移指南,请参阅后量子密码学速查表。
When selecting cryptographic algorithms for a specific use case, consider:
在选择特定用例的加密算法时,请考虑:
- Key size.
中文:密钥大小 - Known attacks and weaknesses of the algorithm.
中文:算法的已知攻击和弱点 - Maturity of the algorithm.
中文:算法的成熟度 - Approval by third parties such as NIST's algorithmic validation program.
中文:第三方批准,如 NIST 的算法验证计划。 - Performance (both for encryption and decryption).
中文:性能(包括加密和解密) - Quality of the libraries available.
中文:可用库的质量 - Portability of the algorithm (i.e, how widely supported is it).
中文:算法的可移植性(即其支持范围)
In some cases there may be regulatory requirements that limit the algorithms that can be used, such as FIPS 140-3 or PCI DSS.
在某些情况下,可能存在监管要求限制可使用的算法,例如FIPS 140-3或PCI DSS
Custom Algorithms / 自定义算法¶
Don't do this.
不要这样做。
Cipher Modes / 加密模式¶
There are various modes that can be used to allow block ciphers (such as AES) to encrypt arbitrary amounts of data, in the same way that a stream cipher would. These modes have different security and performance characteristics, and a full discussion of them is outside the scope of this cheat sheet. Some of the modes have requirements to generate secure initialization vectors (IVs) and other attributes, but these should be handled automatically by the library.
有各种模式,可以使用这些模式来允许块加密(如AES)加密任意数量的数据,就像流加密一样。这些模式具有不同的安全性和性能特征,对这些模式的全面讨论超出了本速查表的范畴。一些模式需要生成安全的初始化向量(IV)和其他属性,但这些应该由库自动处理。
Where available, authenticated modes should always be used. These provide guarantees of the integrity and authenticity of the data, as well as confidentiality. The most commonly used authenticated modes are GCM and CCM, which should be used as a first preference.
在可用的情况下,应始终使用认证模式。这些模式提供了数据完整性和真实性的保证,以及机密性。最常用的认证模式是GCM和CCM,应优先使用。
If GCM or CCM are not available, then CTR mode or CBC mode should be used. As these do not provide any guarantees about the authenticity of the data, separate authentication should be implemented, such as using the Encrypt-then-MAC technique. Care needs to be taken when using this method with variable length messages
如果GCM或CCM不可用,则应使用CTR模式或CBC模式。由于这些模式不提供关于数据真实性的任何保证,因此应实现单独的认证,例如使用加密后MAC技术。在使用此方法时,需要注意可变长度消息的情况。
ECB should not be used outside of very specific circumstances.
Random Padding / 随机填充¶
For RSA encryption, use a maintained library's RSAES-OAEP (Optimal Asymmetric Encryption Padding) implementation, as specified in RFC 8017, Section 7.1. OAEP uses randomized encoding and mask generation functions; simply prepending random bytes to the message is not a substitute. Do not use RSA without an encryption padding scheme.
对于RSA加密,使用维护良好的库的RSAES-OAEP(最优非对称加密填充)实现,如RFC 8017,第7.1节中指定。OAEP使用随机编码和掩码生成函数;简单地在消息前添加随机字节不是替代方案。不要在没有加密填充方案的情况下使用RSA。
Secure Random Number Generation¶
Random numbers (or strings) are needed for various security critical functionality, such as generating encryption keys, IVs, session IDs, CSRF tokens or password reset tokens. As such, it is important that these are generated securely, and that it is not possible for an attacker to guess and predict them.
It is generally not possible for computers to generate truly random numbers (without special hardware), so most systems and languages provide two different types of randomness.
Pseudo-Random Number Generators (PRNG) provide low-quality randomness that are much faster, and can be used for non-security related functionality (such as ordering results on a page, or randomizing UI elements). However, they must not be used for anything security critical, as it is often possible for attackers to guess or predict the output.
Cryptographically Secure Pseudo-Random Number Generators (CSPRNG) are designed to produce a much higher quality of randomness (more strictly, a greater amount of entropy), making them safe to use for security-sensitive functionality. However, they are slower and more CPU intensive, can end up blocking in some circumstances when large amounts of random data are requested. As such, if large amounts of non-security related randomness are needed, they may not be appropriate.
The table below shows the recommended algorithms for each language, as well as insecure functions that should not be used.
| Language / 语言 | Unsafe Functions / 不安全函数 | Cryptographically Secure Functions / 密码学安全函数 |
|---|---|---|
| C | random(), rand() |
getrandom(2) |
| Java | Math.random(), StrictMath.random(), java.util.Random, java.util.SplittableRandom, java.util.concurrent.ThreadLocalRandom |
java.security.SecureRandom, java.util.UUID.randomUUID() |
| PHP | array_rand(), lcg_value(), mt_rand(), rand(), uniqid() |
Random\Engine\Secure in PHP 8.2, random_bytes(), random_int() in PHP 7, openssl_random_pseudo_bytes() in PHP 5 Random\Engine\Secure 在 PHP 8.2 中, random_bytes(), random_int() 在 PHP 7 中, openssl_random_pseudo_bytes() 在 PHP 5 中 |
| .NET/C# | Random() |
RandomNumberGenerator 随机数生成器 |
| Objective-C | Subclasses of GKRandomSource, rand(), random()GKRandomSource 的子类,rand(),random() |
SecRandomCopyBytes, the arc4random family on current Apple platformsSecRandomCopyBytes,当前苹果平台上的 arc4random 系列 |
| Python | random() |
secrets() |
| Ruby | rand(), Random |
SecureRandom |
| Go | rand using math/rand packagerand 使用 math/rand 包 |
crypto.rand package |
| Rust | rand::prng::XorShiftRng |
rand::prng::chacha::ChaChaRng and the rest of the Rust library CSPRNGs. rand::prng::chacha::ChaChaRng 以及 Rust 库中的其余部分 CSPRNGs. |
| Node.js | Math.random() |
crypto.randomBytes(), crypto.randomInt(), crypto.randomUUID() |
UUIDs and GUIDs¶
Universally unique identifiers (UUIDs or GUIDs) are sometimes used as a quick way to generate random strings. Although they can provide a reasonable source of randomness, this will depend on the type or version of the UUID that is created.
通用唯一标识符(UUID或GUID)有时被用作生成随机字符串的快捷方式。尽管它们可以提供合理的随机源,但这将取决于创建的UUID的类型或版本(https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions)。
Specifically, version 1 UUIDs are comprised of a high precision timestamp and the MAC address of the system that generated them, so are not random (although they may be hard to guess, given the timestamp is to the nearest 100ns). Type 4 UUIDs are randomly generated, although whether this is done using a CSPRNG will depend on the implementation. Unless this is known to be secure in the specific language or framework, the randomness of UUIDs should not be relied upon.
具体来说,版本1的UUID由高精度时间戳和生成它们的系统的MAC地址组成,因此不是随机的(尽管由于时间戳精确到最近的100ns,它们可能很难猜测)。类型4的UUID是随机生成的,但这是否使用CSPRNG(密码学安全的伪随机数生成器)取决于实现。除非已知在特定的语言或框架中是安全的,否则不应依赖于UUID的随机性。
Defense in Depth / 深度防御¶
Applications should be designed to still be secure even if cryptographic controls fail. Any information that is stored in an encrypted form should also be protected by additional layers of security. Application should also not rely on the security of encrypted URL parameters, and should enforce strong access control to prevent unauthorized access to information.
应用程序应该设计成即使在加密控制失败的情况下也能保持安全。以加密形式存储的任何信息也应通过额外的安全层进行保护。应用程序还不应依赖于加密URL参数的安全性,并应实施强大的访问控制以防止未经授权访问信息。
Key Management / 密钥管理¶
Processes / 流程¶
Formal processes should be implemented (and tested) to cover all aspects of key management, including:
应实施(并测试)正式流程以涵盖密钥管理的所有方面,包括:
- Generating and storing new keys.
中文:生成和存储新密钥。 - Distributing keys to the required parties.
中文:将密钥分发给相关方。 - Deploying keys to application servers.
中文:将密钥部署到应用服务器上。 - Rotating and decommissioning old keys
中文:轮换和退役旧密钥
Key Generation / 密钥生成¶
Keys should be randomly generated using a cryptographically secure function, such as those discussed in the Secure Random Number Generation section. Keys should not be based on common words or phrases, or on "random" characters generated by mashing the keyboard.
密钥应使用加密安全的函数随机生成,例如在安全随机数生成部分中讨论的。密钥不应基于常见单词或短语,或基于通过按键组合产生的“随机”字符。
Where multiple keys are used (such as data separate data-encrypting and key-encrypting keys), they should be fully independent from each other.
在多个密钥被使用的情况下(例如,数据分离的数据加密密钥和密钥加密密钥),它们应彼此完全独立。
Key Lifetimes and Rotation / 密钥生命周期和轮换¶
Encryption keys should be changed (or rotated) based on a number of different criteria:
加密密钥应根据多个不同标准进行更改(或轮换):
- If the previous key is known (or suspected) to have been compromised.
中文:如果知道(或怀疑)之前的密钥已被泄露。- This could also be caused by a someone who had access to the key leaving the organization.
中文:这也可能是由于某个曾经有权访问密钥的人离开组织所导致的。
- This could also be caused by a someone who had access to the key leaving the organization.
- After a specified period of time has elapsed (known as the cryptoperiod).
中文:在经过一段指定的时间后(称为密钥周期)。- There are many factors that could affect what an appropriate cryptoperiod is, including the size of the key, the sensitivity of the data, and the threat model of the system. See section 5.3 of NIST SP 800-57 Part 1 Rev. 5 for further guidance.
中文:有许多因素可能影响适当的密钥周期,包括密钥大小、数据的敏感性和系统的威胁模型。参见NIST SP 800-57 第1部分修订版5的第5.3节以获取进一步指导。
- There are many factors that could affect what an appropriate cryptoperiod is, including the size of the key, the sensitivity of the data, and the threat model of the system. See section 5.3 of NIST SP 800-57 Part 1 Rev. 5 for further guidance.
- Before reaching the usage limits of the selected encryption mode.
中文:在达到所选加密模式的用量限制之前。- Enforce the mode's limits on message size, encryption operations, and initialization vector (IV) uniqueness across all instances sharing the key. Block size alone does not determine a safe data-volume limit. For example, AES-GCM has separate requirements for input lengths and IV construction in NIST SP 800-38D, Sections 5.2.1.1 and 8. See Key Management: Cryptoperiods and Rotation for usage-based rotation guidance.
中文:强制实施模式对消息大小、加密操作和初始化向量(IV)唯一性的限制,适用于所有共享密钥的实例。仅块大小本身并不能确定安全的数据量限制。例如,AES-GCM在NIST SP 800-38D,第5.2.1.1节和第8节中对输入长度和IV构造有单独的要求。参见密钥管理:密钥周期和轮换以获取基于使用的轮换指导。
- Enforce the mode's limits on message size, encryption operations, and initialization vector (IV) uniqueness across all instances sharing the key. Block size alone does not determine a safe data-volume limit. For example, AES-GCM has separate requirements for input lengths and IV construction in NIST SP 800-38D, Sections 5.2.1.1 and 8. See Key Management: Cryptoperiods and Rotation for usage-based rotation guidance.
- If there is a significant change to the security provided by the algorithm (such as a new attack being announced).
中文:如果算法提供的安全性发生了重大变化(例如宣布了一种新的攻击)。
Once one of these criteria have been met, a new key should be generated and used for encrypting any new data. There are two main approaches for how existing data that was encrypted with the old key(s) should be handled:
一旦满足这些标准之一,就应该生成一个新的密钥,并用于加密任何新的数据。对于使用旧密钥加密的现有数据应该如何处理,主要有两种方法:
- Decrypting it and re-encrypting it with the new key.
中文:将其解密并使用新密钥重新加密。 - Marking each item with the ID of the key that was used to encrypt it, and storing multiple keys to allow the old data to be decrypted.
中文:在每个项目上标记用于加密它的密钥的ID,并存储多个密钥以允许解密旧数据。
The first option should generally be preferred, as it greatly simplifies both the application code and key management processes; however, it may not always be feasible. Note that old keys should generally be stored for a certain period after they have been retired, in case old backups of copies of the data need to be decrypted.
通常应首选第一种方法,因为它极大地简化了应用程序代码和密钥管理流程;然而,这可能并不总是可行的。请注意,旧密钥在退役后通常应存储一段时间,以防需要解密旧备份或数据副本。
It is important that the code and processes required to rotate a key are in place before they are required, so that keys can be quickly rotated in the event of a compromise. Additionally, processes should also be implemented to allow the encryption algorithm or library to be changed, in case a new vulnerability is found in the algorithm or implementation.
在需要之前,确保旋转密钥所需的代码和流程已经就绪非常重要,以便在发生泄露事件时能够快速旋转密钥。此外,还应实施流程,以便在发现算法或实现中存在新的漏洞时,可以更改加密算法或库。
Key Storage / 密钥存储¶
Securely storing cryptographic keys is one of the hardest problems to solve, as the application always needs to have some level of access to the keys in order to decrypt the data. While it may not be possible to fully protect the keys from an attacker who has fully compromised the application, a number of steps can be taken to make it harder for them to obtain the keys.
安全存储加密密钥是解决难度最大的问题之一,因为应用程序始终需要以某种程度访问密钥以解密数据。虽然可能无法完全保护密钥免受完全泄露应用程序的攻击者,但可以采取一些步骤使攻击者更难获取密钥。
Where available, the secure storage mechanisms provided by the operating system, framework or cloud service provider should be used. These include:
在可用的情况下,应使用操作系统、框架或云服务提供商提供的安全存储机制。这包括:
- A physical Hardware Security Module (HSM).
中文:物理硬件安全模块(HSM)。 - A virtual HSM.
中文:虚拟HSM。 - Key vaults such as Amazon KMS or Azure Key Vault.
中文:如Amazon KMS或Azure Key Vault之类的密钥库。 - An external secrets management service such as Conjur or HashiCorp Vault.
中文:如Conjur或HashiCorp Vault之类的外部密钥管理服务。 - Secure storage APIs provided by the ProtectedData class in the .NET framework.
中文:由.NET框架中ProtectedData类提供的安全存储API。
There are many advantages to using these types of secure storage over simply putting keys in configuration files. The specifics of these will vary depending on the solution used, but they include:
与简单地将密钥放入配置文件相比,使用这些类型的存储有许多优势。具体细节将根据所使用的解决方案而有所不同,但包括:
- Central management of keys, especially in containerised environments.
中文:密钥的集中管理,尤其是在容器化环境中。 - Easy key rotation and replacement.
中文:易于密钥轮换和替换。 - Secure key generation.
中文:安全生成密钥。 - Simplifying compliance with regulatory standards such as FIPS 140 or PCI DSS.
中文:简化符合FIPS 140或PCI DSS等监管标准。 - Making it harder for an attacker to export or steal keys.
中文:使攻击者更难导出或窃取密钥。
In some cases none of these will be available, such as in a shared hosting environment, meaning that it is not possible to obtain a high degree of protection for any encryption keys. However, the following basic rules can still be followed:
在某些情况下,这些措施可能都无法实施,例如在共享托管环境中,这意味着无法为任何加密密钥获得高程度的保护。然而,以下基本规则仍然可以遵循:
- Do not hard-code keys into the application source code.
中文:不要将密钥硬编码到应用程序源代码中。 - Do not check keys into version control systems.
中文:不要将密钥检查到版本控制系统中。 - Protect the configuration files containing the keys with restrictive permissions.
中文:使用限制性权限保护包含密钥的配置文件。 - Avoid storing keys in environment variables, as these can be accidentally exposed through functions such as phpinfo() or through the
/proc/self/environfile.
中文:避免在环境变量中存储密钥,因为这些可以通过如phpinfo()之类的函数或通过/proc/self/environ文件意外暴露。
The Secrets Management Cheat Sheet provides more details on securely storing secrets.
秘密管理速查表提供了关于安全存储秘密的更多细节。
Separation of Keys and Data / 密钥与数据的分离¶
Where possible, encryption keys should be stored in a separate location from encrypted data. For example, if the data is stored in a database, the keys should be stored in the filesystem. This means that if an attacker only has access to one of these (for example through directory traversal or SQL injection), they cannot access both the keys and the data.
在可能的情况下,加密密钥应存储在与加密数据不同的位置。例如,如果数据存储在数据库中,密钥应存储在文件系统中。这意味着如果攻击者只能访问其中之一(例如通过目录遍历或SQL注入),他们无法同时访问密钥和数据。
Depending on the architecture of the environment, it may be possible to store the keys and data on separate systems, which would provide a greater degree of isolation.
根据环境的架构,可能可以将密钥和数据存储在不同的系统上,这将提供更大的隔离度。
Encrypting Stored Keys / 存储密钥的加密¶
Where possible, encryption keys should themselves be stored in an encrypted form. At least two separate keys are required for this:
在可能的情况下,加密密钥本身应以加密形式存储。为此至少需要两个独立的密钥:
- The Data Encryption Key (DEK) is used to encrypt the data.
中文:数据加密密钥(DEK)用于加密数据。 - The Key Encryption Key (KEK) is used to encrypt the DEK.
中文:密钥加密密钥(KEK)用于加密DEK。
For this to be effective, the KEK must be stored separately from the DEK. The encrypted DEK can be stored with the data, but will only be usable if an attacker is able to also obtain the KEK, which is stored on another system.
为了有效,密钥封装密钥(KEK)必须与数据加密密钥(DEK)分开存储。加密的DEK可以与数据一起存储,但只有在攻击者能够同时获取KEK(存储在另一个系统上)的情况下才能使用。
The KEK should also be at least as strong as the DEK. The envelope encryption guidance from Google contains further details on how to manage DEKs and KEKs.
KEK的强度也应至少与DEK相同。谷歌的信封加密指南包含了关于如何管理DEK和KEK的更多详细信息。
In simpler application architectures (such as shared hosting environments) where the KEK and DEK cannot be stored separately, there is limited value to this approach, as an attacker is likely to be able to obtain both of the keys at the same time. However, it can provide an additional barrier to unskilled attackers.
在简单的应用程序架构(如共享托管环境)中,由于KEK和DEK无法分开存储,这种方法的价值有限,因为攻击者很可能会同时获取这两个密钥。然而,它可以为无技能的攻击者提供额外的障碍。
A key derivation function (KDF) could be used to generate a KEK from user-supplied input (such a passphrase), which would then be used to encrypt a randomly generated DEK. This allows the KEK to be easily changed (when the user changes their passphrase), without needing to re-encrypt the data (as the DEK remains the same).
可以使用密钥派生函数(KDF)从用户提供的输入(如密码短语)生成KEK,然后使用它来加密随机生成的DEK。这允许KEK容易地更改(当用户更改他们的密码短语时),而无需重新加密数据(因为DEK保持不变)。
References / 参考¶
- NIST SP 800-57 Part 1 Rev. 5: Recommendation for Key Management) (NIST SP 800-57 第1部分 第5版:密钥管理推荐)
- NIST FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard) (NIST FIPS 203:基于模块格的密钥封装机制标准)
- NIST: Post-Quantum Cryptography FAQ) (NIST:后量子密码学常见问题解答)