使用OpenSSL进行加密时的结果不同

时间:2017-08-24 07:54:14

标签: linux encryption openssl cryptography

当我尝试使用OpenSSL

进行加密时,我遇到了一个奇怪的情况

详细说明:

  • 我尝试使用" Hello World加密文件!"
  • 密码(字符串):" testtesttesttest"
  • 密码(HEX):74657374746573747465737474657374

加密文件的终端命令:

  • 用于纯文本密码

    • openssl aes-128-cbc -e -a -nosalt -iv [some vector] -k [password] -in [input file] -out [output file]

    • openssl aes-128-cbc -e -a -nosalt -iv [some vector] -pass pass:[password] -in [input file] -out [output file]

  • 对于HEX格式的密码

    • openssl aes-128-cbc -e -a -nosalt -iv [some vector] -K [HEX password] -in [input file] -out [output file]

所以命令的唯一区别是一个使用纯文本密码而另一个使用相同的密码但是采用HEX格式。所以在我看来,加密的结果应该是一样的。但Base64输出实际上是不同的。

也许有人知道并且暗示这可能是什么情况?

另一种情况,现在我开发了一个加密Blackberry手机上的文件的小应用程序,我希望它可以与PC上提供的其他加密软件如OpenSSL兼容。因此,我的应用程序的Base64输出与OpenSSL使用给定密码生成的输出不同。

示例代码如下所示:

String testKey = "testtesttesttest"; (example)

byte[] aesKeyAsBytes = testKey.getBytes();

AESKey aesKey = new AESKey(aesKeyAsBytes);

AESEncryptorEngine engine = new AESEncryptorEngine(aesKey);

CBCEncryptorEngine cengine=new CBCEncryptorEngine(engine, new InitializationVector(_initVector));

PKCS5FormatterEngine fengine = new PKCS5FormatterEngine(cengine);

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

BlockEncryptor cryptoStream = new BlockEncryptor(fengine, outputStream);

cryptoStream.write(plainText, 0, numOfPlainTextBytes);

cryptoStream.close();

byte[] cipherText = outputStream.toByteArray();

outputStream.close();

return cipherText;

2 个答案:

答案 0 :(得分:2)

我使用以下输入作为此方案的测试数据:

Key (Hex): 01010101010101010101010101010101
IV  (Hex): 02020202020202020202020202020202
Plaintext: Hello, World!

在OpenSSL中使用以上命令并使用以下命令:

openssl aes-128-cbc -K 01010101010101010101010101010101 -iv 02020202020202020202020202020202 -e -a -in in.txt -out out-openssl.txt

给我一​​个结果:

wT6aF/PXrGhxEwyX6mNfXA==

使用C#System.Security.Cryptography命名空间,它具有我们可以测试的原始AES实现,我使用了以下代码:

using (AesManaged aes = new AesManaged())
{
    aes.KeySize = 128;
    aes.Padding = PaddingMode.PKCS7;

    aes.Key = new byte[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
    aes.IV = new byte[] { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };

    byte[] plaintext = Encoding.UTF8.GetBytes("Hello, World!");
    ICryptoTransform t = aes.CreateEncryptor();
    byte[] ciphertext = t.TransformFinalBlock(plaintext, 0, plaintext.Length);

    Console.WriteLine(Convert.ToBase64String(ciphertext));
}

生成完全相同的base64结果:

wT6aF/PXrGhxEwyX6mNfXA==

这表明如果您希望完全按照提供的方式使用密钥(例如带有大写K的-K标志),则上面的OpenSSL命令是正确的。

正如我在评论中提到的,OpenSSL 确实在以明文形式提供密码时使用KDF,详见this answer

答案 1 :(得分:1)

应该出现在任何Unixy系统上的enc的手册页(有时在1ssl之类的修改过的部分下)or current release on the web

-k password

    the password to derive the key from. This is for compatibility with 
    previous versions of OpenSSL. Superseded by the -pass argument.

-kfile filename

    read the password to derive the key from the first line of 
    filename. This is for compatibility with previous versions of 
    OpenSSL. Superseded by the -pass argument.

-K key

    the actual key to use: this must be represented as a string 
    comprised only of hex digits. If only the key is specified, the IV ...

您是否发现密钥来自'(密码)之间的任何差异'和'实际的关键'?

PS:由于-K没有进行密钥派生,因此与salt -nosalt -salt -S相关的参数对它没有影响并被忽略。