【问题标题】:Which data format do I need to decrypt data stored in MySQL DB?我需要哪种数据格式来解密存储在 MySQL DB 中的数据?
【发布时间】:2018-11-17 00:48:12
【问题描述】:

我正在使用 PHP 7.1,正在研究加密/解密主题。我使用这个函数来编码/解码(基于 PHP 的official doc):

$key = openssl_random_pseudo_bytes(16);

function encryptName($plaintext) {
  global $key;
  // $plaintext - string which must be encrypted

  $ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
  $iv = openssl_random_pseudo_bytes($ivlen);

  $ciphertext_raw = openssl_encrypt($plaintext, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
  $hmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true);
  $ciphertext = base64_encode( $iv.$hmac.$ciphertext_raw );
  return $ciphertext;
}

 function decryptName($ciphertext) {
    global $key;
    // $ciphertext - encrypted string

    $c = base64_decode($ciphertext);
    $ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
    $iv = substr($c, 0, $ivlen);

    $hmac = substr($c, $ivlen, $sha2len=32);
    $ciphertext_raw = substr($c, $ivlen+$sha2len);

    $original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, 
    $options=OPENSSL_RAW_DATA, $iv); // | OPENSSL_ZERO_PADDING
    $calcmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true);

    if (hash_equals($hmac, $calcmac)) {
      //echo $original_plaintext."\n";
    }
    echo openssl_error_string();
    return $original_plaintext;  
}

当我 enc/dec strig "MyTestPhrase" 时,这两个函数都运行良好。但是当我加密数据然后将其写入 MySQL 表时,解密失败并出现以下错误代码:

error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length

我的$original_plaintext 等于bool(false)

我是这样想的。 AES 适用于块。解密的字符串必须适合阻止长度:解密数据的大小必须是 16 的倍数。如果不是,我们必须激活 PHP 选项,用 0es 填充它。

猜测这个问题可能与 MySQL 数据格式和加密字符串长度有关,但无法捕捉到。

请帮我解决上面发布的问题。

【问题讨论】:

  • 只是为了排除这一点。发送到 db 后,您使用的是与加密相同的密钥进行解密吗?
  • 根据Encryption and Compression Functions,您需要将列设置为键入`VARBINARY`或BLOB。你这样做了吗?
  • 他不应该那样做。他从加密函数中将其作为base64返回。否则很好。
  • @wayneOS,是的,两个都试过了
  • @Joseph_J,是的,我愿意

标签: php mysql encryption aes


【解决方案1】:

所以在我的示例中,我使用 pseudo_bytes 创建了一个 base64_encoded 字符串。这样你的密钥是不变的。您可以创建自己的密钥,但对于这个 ex,我们将使用这个。 LoPCPKd8iDxHvb8mATzhhg==

接下来我们将键定义为常量。这可以在脚本顶部或 conf.php 文件中完成。

接下来,我们将在您需要密钥的任何地方使用常量值。

像这样:

define("MYKEY_", base64_decode('LoPCPKd8iDxHvb8mATzhhg=='));

function encryptName($plaintext) {

  $ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
  $iv = openssl_random_pseudo_bytes($ivlen);

  $ciphertext_raw = openssl_encrypt($plaintext, $cipher, MYKEY_, $options=OPENSSL_RAW_DATA, $iv);
  $hmac = hash_hmac('sha256', $ciphertext_raw, MYKEY_, $as_binary=true);
  $ciphertext = base64_encode( $iv.$hmac.$ciphertext_raw );
  return $ciphertext;
}

 function decryptName($ciphertext) {

    $c = base64_decode($ciphertext);
    $ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
    $iv = substr($c, 0, $ivlen);

    $hmac = substr($c, $ivlen, $sha2len=32);
    $ciphertext_raw = substr($c, $ivlen+$sha2len);

    $original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, MYKEY_,
    $options=OPENSSL_RAW_DATA, $iv); // | OPENSSL_ZERO_PADDING
    $calcmac = hash_hmac('sha256', $ciphertext_raw, MYKEY_, $as_binary=true);

    if (hash_equals($hmac, $calcmac)) {
      //echo $original_plaintext."\n";
    }

    echo openssl_error_string();
    return $original_plaintext;
}

【讨论】:

  • 完美!非常感谢!问题是脚本在每次启动时都会生成一个新密钥。 MySQL的数据格式应该是text,默认长度。
  • 如果你做一些像名字或短句 tinytext(255 最大长度)这样的事情应该可以。但对于更大的东西,我会做文字。您甚至可能无法设置文本的长度,但默认值就可以了。如果你真的关心长度,你也可以做 varchar 并设置长度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 2016-11-08
  • 1970-01-01
  • 2022-01-08
  • 1970-01-01
  • 2018-04-10
  • 2021-11-19
相关资源
最近更新 更多