【问题标题】:Converting C# AES encryption function to PHP将 C# AES 加密函数转换为 PHP
【发布时间】:2019-02-13 17:44:51
【问题描述】:

我正在尝试将 C# 加密函数转换为 php,但我怀疑存在编码问题或 IV 生成不正确。

这是用于向 API 发送加密文本,我目前尝试强制使用 utf8,但 base64 编码的字符串总是与我运行 C# 函数时不同。我似乎也找不到在 C# 中生成 IV 的确切方式。

遗憾的是,我无法更改 API 的解密方式,我不得不以这种方式对其进行加密。

C# 函数

public void EncryptStringToBytes(string plaintext) {
            string key = DateTime.UtcNow.ToShortDateString();
            HashAlgorithm algorithm = SHA256.Create();
            byte[] bytekey = algorithm.ComputeHash(Encoding.UTF8.GetBytes(key));

            using (Aes myAes = Aes.Create()) {
                myAes.Key = bytekey;
                // Encrypt the string to an array of bytes.
                byte[] encrypted = null;

                // Create a decrytor to perform the stream transform.
                ICryptoTransform encryptor = myAes.CreateEncryptor(myAes.Key, myAes.IV);

                // Create the streams used for encryption.
                using (MemoryStream msEncrypt = new MemoryStream()) {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) {
                             //Write all data to the stream.
                             swEncrypt.Write(plaintext);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
                 Console.WriteLine(Convert.ToBase64String(encrypted)); 
                 Console.WriteLine(Convert.ToBase64String(myAes.IV));
            }
        }

PHP 函数

date_default_timezone_set("UTC");

function encrypt($string) {
  // Generate key based on current time
  $secret_key = utf8_encode(date('Y-m-d'));
  // Hash the key with SHA256
  $key = hash('sha256', $secret_key);
  // Use AES 128 w/ CBC as encryption method
  $encrypt_method = "AES-128-CBC";
  // Get cipher length based on encryption method
  $cypher_length = openssl_cipher_iv_length($encrypt_method);
  // Generate IV -- possible issue
  $iv = openssl_random_pseudo_bytes($cypher_length);
  // Encrypt input string with the given method, key and IV
  $output = openssl_encrypt($string, $encrypt_method, $key, OPENSSL_RAW_DATA , $iv);

  $debug_info = [ 'date' => $secret_key, 'key' => $key, 'method' => $encrypt_method, 'cypher_len' => $cypher_length, 'iv' => $iv, 'output' => $output];
  return [base64_encode($output), base64_encode($iv), $debug_info];
}

【问题讨论】:

  • 您指定 AES-128-CBC 作为 php 中的方法,我发现 C# 默认使用 AES-256。
  • 生成加密安全的伪随机字节php.net/manual/en/function.random-bytes.php
  • 由于 SHA256 的输出是 256 位,因此您想要 AES-256-CBC,而不是 128。(您也确实想要更好的 KDF 和密钥生成器,但这是另一个问题)
  • 我现在感觉自己像个白痴,问题是我有你说的 128 而不是 256 并且在发送数据时我是 base64_encoding 它,然后用 SoapClient 发送它显然已经 base64_encodes

标签: c# php aes


【解决方案1】:

感谢 bartonjs,我找到了解决方案,我不得不使用 AES-256-CBC 而不是 128。此外,我在散列时没有使用原始输出,这也改变了结果,因为我正在发送加密数据和 IV通过使用 SoapClient 的 php-soap 我不必使用 base64_encode,因为 SoapClient 已经为我做到了。

工作代码如下:

    function encrypt($string, $debug = false) {
        $method = 'aes-256-cbc';
        $secret_key = date('Y-m-d', time());
        $key = hash('SHA256', $secret_key, true);
        $cypher_length = openssl_cipher_iv_length($method);
        $iv = random_bytes($cypher_length);
        $output = openssl_encrypt($string, $method, $key, OPENSSL_RAW_DATA, $iv);
        $debug_info = [ 'date' => $secret_key, 'date_utf8' => utf8_encode($secret_key), 'key' => utf8_encode($key), 'method' => $method, 'cypher_len' => $cypher_length, 'iv' => base64_encode($iv), 'output' => base64_encode($output)];

        if($debug){
            return [$output, $iv, $debug_info];
        }
        return [$output, $iv];
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-11
    • 1970-01-01
    • 1970-01-01
    • 2018-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多