OpenSSL

密码学和SSL/TLS工具包

passphrase-encoding

名称

passphrase-encoding - OpenSSL的不同部分如何处理密码字符编码

描述

在现代世界中,各种字符编码的存在使得密码的处理变得越来越复杂。本手册页试图概述OpenSSL库的不同部分目前如何解决此问题。

一般情况

作为一般规则,OpenSSL库不会以任何特殊方式处理密码,并信任应用程序或用户选择合适的字符集并在受影响对象的整个生命周期内坚持使用该字符集。这意味着,对于使用ISO-8859-1编码的密码加密的对象,需要使用ISO-8859-1编码的密码对其进行解密。使用错误的编码预计会导致解密失败。

PKCS#12

在密码编码方面,PKCS#12略有不同。该标准规定密码应编码为ASN.1 BMPString,它由基本多语言平面上的代码点组成,以大端序(UCS-2 BE)编码。

OpenSSL尝试以以下方式之一适应此要求

  1. 将接收到的密码视为UTF-8编码,并尝试将其重新编码为UTF-16(对于字符U+0000到U+D7FF和U+E000到U+FFFF,这与UCS-2相同,但对于任何其他字符都会扩展),或者如果失败,则继续执行步骤2。

  2. 假设密码以ASCII或ISO-8859-1编码,并有机会在每个字节前添加一个零字节以获得字符的UCS-2编码,然后将其存储为BMPString。

    请注意,由于没有检查您的区域设置,因此这可能会产生与其他字符集(例如除ISO-8859-1之外的任何ISO-8859-X编码(或对于Windows,CP 1252,除了0x80-0x9F范围内额外的“图形”字符))的原始密码字符不对应的UCS-2/UTF-16字符。

1.1.0之前的OpenSSL版本仅执行变体2,这就是OpenSSL仍然这样做的原因,以便能够读取使用旧版本创建的文件。

需要注意的是,这种方法并非完全没有错误。

以ISO-8859-2编码的密码很可能具有诸如0xC3 0xAF之类的序列(在ISO-8859-2编码中,它是两个字符“带短音符的拉丁大写字母A”和“带点符号的拉丁大写字母Z”),但会被误解为完全有效的UTF-8编码代码点U+00EF(带分音符的拉丁小写字母I)如果密码不包含任何无效的UTF-8内容。包含此类字节序列的密码在OpenSSL 1.1.0及更高版本中与1.1.0之前的OpenSSL版本相比会产生不同的结果。

0x00 0xC3 0x00 0xAF                    # OpenSSL older than 1.1.0
0x00 0xEF                              # OpenSSL 1.1.0 and newer

同样,任何以UTF-8编码并提供给1.1.0之前的OpenSSL的内容都被误解为ISO-8859-1序列。

OSSL_STORE

ossl_store(7)充当访问各种对象的通用接口,这些对象可能受密码、PIN或其他内容保护。此API规定密码应以UTF-8编码,任何其他密码编码可能会产生未定义的结果。此API依赖于应用程序确保UTF-8编码,并且不检查情况是否如此,因此它获取的内容也将传递给底层加载程序。

建议

本节假设您知道用于加密的密码是什么,但它可能以与您当前输入方法使用的字符编码不同的字符编码进行编码。例如,密码可能是在您的默认编码为ISO-8859-1(即“naïve”导致字节序列0x6E 0x61 0xEF 0x76 0x65)时使用的,而您现在处于默认编码为UTF-8的环境中(即“naïve”导致字节序列0x6E 0x61 0xC3 0xAF 0x76 0x65)。无论何时提及您应该使用某种字符编码,都应理解您在输入密码时将输入方法更改为使用提到的编码,或者使用一些合适的工具将密码从您的默认编码转换为目标编码。

另请注意,以下子部分讨论的是人类可读的密码。这对于PKCS#12对象尤其相关,因为在这些对象中假设使用了人类可读的密码。对于其他对象,使用任何字节序列(例如来自/dev/urandom的已保存字节序列)都是合法的,这使得任何字符编码讨论都变得无关紧要;在这种情况下,只需使用相同的字节序列即可。

创建新对象

对于创建新的密码保护对象,请确保密码使用UTF-8编码。这在大多数现代Unix系统上是默认设置,但在其他平台上可能需要一些操作。特别是对于Windows,设置环境变量OPENSSL_WIN32_UTF8将使在[Windows]控制台提示符下输入的任何内容转换为UTF-8(命令行和单独提示的密码)。

打开现有对象

对于打开密码保护的对象,如果您知道用于加密密码的字符编码是什么,请确保再次使用相同的编码。

对于打开密码保护的对象,如果使用的字符编码未知,或者生成应用程序未知,请尝试以下操作之一

  1. 尝试使用您当前环境的字符编码中的密码。它可能恰好是正确的字节序列。

  2. 将密码转换为UTF-8,然后尝试使用结果。特别是对于PKCS#12,这应该可以打开根据规范创建的任何对象。

  3. 执行一个简单的(即纯数学的)ISO-8859-1到UTF-8转换,然后尝试使用结果。这与之前的尝试不同,因为ISO-8859-1直接映射到U+0000到U+00FF,而其他非UTF-8字符集则不映射。

    这也可以处理在1.1.0之前的OpenSSL中使用UTF-8编码字符串的情况。(例如,ï在UTF-8中编码为0xC3 0xAF,在以简单方式重新编码时将变为0xC3 0x83 0xC2 0xAF。然后,转换为BMPString将产生0x00 0xC3 0x00 0xA4 0x00 0x00,这是1.1.0之前的OpenSSL使用的错误/不符合规范的编码。)

参见

evp(7)ossl_store(7)EVP_BytesToKey(3)EVP_DecryptInit(3)PEM_do_header(3)PKCS12_parse(3)PKCS12_newpass(3)d2i_PKCS8PrivateKey_bio(3)

版权所有 2018-2021 OpenSSL 项目作者。保留所有权利。

根据 Apache 许可证 2.0(“许可证”)获得许可。除非符合许可证,否则您不得使用此文件。您可以在源代码分发版中的LICENSE文件中或在https://www.openssl.org/source/license.html中获得副本。