MySQL AES_ENCRYPT 密钥长度

信息安全 加密 密码学 密钥管理 mysql pycrypto
2021-08-17 22:28:00

AES_ENCRYPT使用 128 位长的密钥来加密数据,但 MySQL 如何处理更长或更短的密钥?我发现 PyCrypto 实例建议通过使用 MD5、SHA-1、SHA-2 等哈希来转换密钥,然后使用生成的密钥进行加密。它如何与 MySQL 一起工作?

4个回答

MySQL 5.5 不处理其他密钥大小。http://dev.mysql.com/doc/refman/5.5/en/encryption-functions.html所述:

AES_ENCRYPT() 和 AES_DECRYPT() 启用使用官方 AES(高级加密标准)算法(以前称为“Rijndael”)对数据进行加密和解密。使用 128 位密钥长度编码,但您可以通过修改源将其扩展到 256 位。我们选择了 128 位,因为它速度更快,并且对于大多数用途来说足够安全。

我从未尝试将更大的密钥传递给 MySQL,但我猜它会产生错误或截断为 128 位。

我不确定 MD5 是否使用它的完整 codomain,因为我找不到任何证据证明 MD5 是 surjection。因此,我假设您将less 通过使用 MD5 哈希来获得安全性,因为您减少了密钥的可能值集。这仍然是非常主观的。

就较小的密钥而言,我想0x1 == 0x00...01它仍然是有效的密钥。

顺便说一句,我不明白你为什么不生成给定大小的密钥。如果您有一些限制(您想重用已经存在的密钥,...),请告诉我们。

抱歉,后来我从RubyForum发现了

“该算法只是创建一个 16 字节缓冲区设置为全零,然后遍历您提供的字符串的所有字符,并在两个值之间使用按位异或进行赋值。如果我们迭代直到我们到达 16 字节缓冲区的末尾,我们只是从头开始做 ^=。对于短于 16 个字符的字符串,我们在字符串的末尾停止。

  bzero((char*) rkey,AES_KEY_LENGTH/8);      /* Set initial key  */

  for (ptr= rkey, sptr= key; sptr < key_end; ptr++,sptr++)
  {
    if (ptr == rkey_end)
      ptr= rkey;  /*  Just loop over tmp_key until we used all key */
    *ptr^= (uint8) *sptr;
  }

在 Ruby 中看起来像这样

def mysql_key2(key)
   final_key = "\0" * 16
   key.length.times do |i|
     final_key[i%16] ^= key[i]
   end
   final_key
end

我将它应用于python:

finalKey = b'\0'*16
key = b'mySecretKey'
for i, c in enumerate(key) :
  finalKey[i%16] ^= key[i]

不要使用重复的密码可能是明智的,"MySQL=insecure! MySQL=insecure! "因为它会使生成的密钥归零。

默认情况下,这些函数使用 128 位密钥长度实现 AES。从 MySQL 5.7.4 开始,可以使用 196 或 256 位的密钥长度,如下所述。密钥长度是性能和安全性之间的权衡。加密函数

我必须在 PHP 中执行此操作。您需要按照@joecks 的描述执行 XOR,并删除任何小于 16 字节的加密数据的填充,如下所述:http://forums.devnetwork.net/viewtopic.php?f=34&t= 97082

工作代码:

<?php
    $key = 'SomeSecretKeyThatCanBeLongerThan16Bytes';
    $encodedString = [fetched from DB];

    $finalKey = array_fill(0, 16, 0);
    foreach (unpack('C*', $key) as $i => $char)
    {
        $finalKey[($i-1)%16] = $finalKey[($i-1)%16] ^ $char;
    }

    $dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, implode(array_map("chr", $finalKey)), $encodedString, MCRYPT_MODE_ECB, '');
    return rtrim($dec, ((ord(substr($dec, strlen($dec) - 1, 1)) >= 0 and ord(substr($dec, strlen($dec) - 1, 1 ) ) <= 16 ) ? chr(ord(substr($dec, strlen($dec ) - 1, 1))): null) );