【问题标题】:EVP_CIPHER_CTX_set_key_length accepts bad sizes for blowfishEVP_CIPHER_CTX_set_key_length 接受河豚的错误尺寸
【发布时间】:2017-01-26 05:02:46
【问题描述】:

当我尝试通过EVP_CIPHER_CTX_set_key_lengthEVP_aes_128_cbc 信封的密钥长度设置为58 时,我收到以下错误:

3073369856:error:0607A082:digital envelope routines:EVP_CIPHER_CTX_set_key_length:invalid key length:crypto/evp/evp_enc.c:557:

这是有道理的,因为 EVP_aes_128_cbc 仅支持 128 位或 16 字节的密钥大小。

对我来说没有意义的是,当我为 EVP_bf_cbc 做同样的事情时,我根本没有收到任何错误。

根据wikipedia's entry on Blowfish,最大位大小为 448 位或 56 字节,小于 58。此外,引用http://etutorials.org/Programming/secure+programming/Chapter+5.+Symmetric+Encryption/5.18+Using+Variable+Key-Length+Ciphers+in+OpenSSL/,“OpenSSL 对密钥大小设置了 256 位的硬性限制 ”。

我的代码:

#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/crypto.h>
#include <string.h>
void handleErrors(void);
int main (void)
{
  unsigned char *key = (unsigned char *)"0123456789012345678901234567890123456789012345678901234567";
  unsigned char *iv = (unsigned char *)"01234567";
  unsigned char *plaintext = (unsigned char *)"xxxxxxxx";
  unsigned char ciphertext[128];
  int plaintext_len = strlen((char *)plaintext);
  int len;
  EVP_CIPHER_CTX *ctx;
  ERR_load_crypto_strings();
  OpenSSL_add_all_algorithms();
  OPENSSL_config(NULL);
  if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
  if (!EVP_EncryptInit_ex(ctx, EVP_bf_cbc(), NULL, NULL, NULL)) handleErrors();
  if (!EVP_CIPHER_CTX_set_key_length(ctx, 58)) handleErrors();
  if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
  if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) handleErrors();
  if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
  EVP_CIPHER_CTX_free(ctx);
}
void handleErrors(void)
{
  ERR_print_errors_fp(stderr);
  abort();
}

EVP_bf_cbc 替换为EVP_aes_128_cbc 以重现错误。如果我在EVP_EncryptInit_ex(与EVP_aes_128_cbc)中遇到错误,我不会感到惊讶,因为 iv 不等于块大小,但代码在此之前中止,无论如何,所以它似乎有点没有实际意义我。

【问题讨论】:

  • 这可能是 OpenSSL 中的验证问题。我猜这个库在内部将密钥设置为 56 字节。也许你应该把它放在 OpenSSL 邮件列表中。

标签: c openssl


【解决方案1】:

使用EVP_CIPHER_CTX_set_key_length() 仅在密码具有可变密钥长度的情况下有用(Blowfish 就是这种情况)。该函数对提供的密钥长度进行一些有限的验证。如果密码具有固定长度的密钥,那么它将检查提供的密钥长度是否与固定长度相同。否则会返回错误。

如果使用带有可变长度密钥的密码,那么它只会检查密钥长度是否为正。否则,您可以设置任何您喜欢的值。这并没有真正的区别,因为当 Blowfish 开始使用它时,它会检查密钥长度是否正常,如果太长则使用减小的长度:

static int bf_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
                       const unsigned char *iv, int enc)
{
    BF_set_key(&data(ctx)->ks, EVP_CIPHER_CTX_key_length(ctx), key);
    return 1;
}
...
void BF_set_key(BF_KEY *key, int len, const unsigned char *data)
#ifdef OPENSSL_FIPS
{
    fips_cipher_abort(BLOWFISH);
    private_BF_set_key(key, len, data);
}

void private_BF_set_key(BF_KEY *key, int len, const unsigned char *data)
#endif
{
    int i;
    BF_LONG *p, ri, in[2];
    const unsigned char *d, *end;

    memcpy(key, &bf_init, sizeof(BF_KEY));
    p = key->P;

    if (len > ((BF_ROUNDS + 2) * 4))
        len = (BF_ROUNDS + 2) * 4;

这里 BF_ROUNDS == 16,因此最大密钥长度为 72 字节(576 位)。我对Blowfish不是特别熟悉,所以我不知道为什么这个和你上面提到的448位之间存在差异。

编辑: 啊,差异可能是由于这个(来自维基百科): “因为 P 数组的长度为 576 位,并且在初始化期间密钥字节通过所有这些 576 位进行异或运算,所以许多实现支持高达 576 位的密钥大小。”

【讨论】:

  • "这里BF_ROUNDS == 16,所以最大密钥长度为72字节(576位)。我对Blowfish不是特别熟悉,所以不知道为什么会出现这样的差异这和你上面提到的 448 位" - Schneier 说它的 448 位;见The Blowfish Encryption Algorithm。也许算法有更新。
  • 我刚刚尝试将 100 传递给 EVP_CIPHER_CTX_set_key_length()EVP_bf_cbc。没有收到任何错误。查看您发布的代码 sn-p 并不奇怪 - 如果大小太大并且它是可变长度密码,它看起来只是默默地调整它的大小。似乎它应该改为给出错误。哦,好吧..
猜你喜欢
  • 2016-07-22
  • 2019-09-20
  • 2019-02-21
  • 1970-01-01
  • 2013-01-04
  • 1970-01-01
  • 1970-01-01
  • 2020-05-31
  • 2019-08-29
相关资源
最近更新 更多