php - c++中的加密和php中的解密有什么问题

标签 php c++ encryption openssl

在这里,我有一个对字符串进行编码的 C++ 程序,我必须在 PHP 中进行解密。我已验证两个程序中的 key 和 iv 相同,但在 openssl_decrypt() 命令中仍然为 false。

    int main(int argc, char** args)
    {
        unsigned char *salt = (unsigned char*)"12345678";                        
        unsigned char *data = (unsigned char*)"123456789123450";                 
        unsigned int count        = 5;                                           
        int dlen                  = strlen((char*)data);                         
        unsigned int ksize        = 16;
        unsigned int vsize        = 12;                                          
        unsigned char *key        = new unsigned char[ksize];                    
        unsigned char *iv         = new unsigned char[vsize];                    

        int ret = EVP_BytesToKey( EVP_aes_128_gcm() , EVP_sha1(), salt, data, dlen, count, key, iv);

        const EVP_CIPHER*     m_cipher = EVP_aes_128_gcm();
        EVP_CIPHER_CTX* m_encode;                                                
        EVP_CIPHER_CTX* m_decode;                                                
        if (!(m_encode = EVP_CIPHER_CTX_new()))                                  
           cout << "ERROR :: In encode Initiallization"<< endl; 

        EVP_EncryptInit_ex(m_encode, m_cipher, NULL, key, iv);

        if (!(m_decode = EVP_CIPHER_CTX_new()))
            cout << "ERROR :: In decode Initiallization"<< endl;
        EVP_DecryptInit_ex(m_decode, m_cipher, NULL, key, iv);
        unsigned char* plain = (unsigned char*)"My Name IS  DON !!!";
        int len  = strlen((char*)plain);
        unsigned char* encData = new unsigned char[len];

        int c_len = len;
        int f_len = 0;
        EVP_EncryptInit_ex(m_encode, NULL, NULL, NULL, NULL);
        EVP_EncryptUpdate(m_encode, encData, &c_len, plain, len);
        EVP_EncryptFinal_ex(m_encode, encData + c_len, &f_len);

        len = c_len + f_len;

        cout << string( encData, encData + len)<< endl;
    }

下面是php解密代码。 “./abc_enc.txt”包含c++代码的加密字符串。正如我上面提到的,我为两个程序获得相同的 key 和 iv,但 openssl_decrypt 函数返回 false。有人能弄清楚是什么错误吗?

    <?
    function EVP_BytesToKey($salt, $password) {
        $ivlen = 12;
        $keylen = 16;
        $iterations = 5;
        $hash = "";
        $hdata = "";
        while(strlen($hash)<$ivlen+$keylen)
        {
            $hdata .= $password.$salt;
            $md_buf = openssl_digest($hdata, 'sha1');
            for ($i = 1; $i < $iterations; $i++) {
                $md_buf = openssl_digest ( hex2bin($md_buf),'sha1');
            }
            $hdata = hex2bin($md_buf);
            $hash.= $hdata;
         }
         return $hash;
    }
    function decrypt($ivHashCiphertext, $password) {
         $method = "aes-128-gcm";
         $salt = "12345678";
         $iterations = 5;
         $ivlen = openssl_cipher_iv_length($method);
         $ciphertext = $ivHashCiphertext;
         $genKeyData = EVP_BytesToKey($salt, $password);
         $keylen = 16;
         $key = substr($genKeyData,0,$keylen);
         $iv  = substr($genKeyData,$keylen,$ivlen);
         //var_dump($key);
         //var_dump($iv);
         $ret = openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv);
         var_dump($ret);
         return $ret;
    }
    $file = './abc_enc.txt';
    $fileData = (file_get_contents($file));
    $encrypted = $fileData;
    $decrypted = decrypt($encrypted, '123456789123450');
    ?>

最佳答案

GCM-mode提供 secret 性和真实性。为了验证真实性,GCM 模式使用身份验证标签并定义了包括在内的长度。标签的 12 和 16 字节。认证强度取决于标签的长度,即标签越长,真实性证明越安全。

但是,在当前的 C++ 代码中,身份验证标记尚未确定!这意味着未使用 GCM 模式的主要功能之一,即身份验证。

虽然在 C++ 中使用 EVP 的解密独立于身份验证(这意味着即使身份验证标签不同也会执行解密),而在 PHP 中使用 openssl_decrypt 的解密只有在身份验证成功,即在 PHP 中,身份验证标记是解密所必需的。因此,必须在 C++ 代码中确定身份验证标记。为此,必须在 EVP_EncryptFinal_ex 调用之后添加以下代码:

unsigned int tsize = 16;
unsigned char *tag = new unsigned char[tsize];
EVP_CIPHER_CTX_ctrl(m_encode, EVP_CTRL_GCM_GET_TAG, tsize, tag);

这里使用了 16 字节的标签大小。此外,必须在 PHP 代码中使用身份验证标记进行解密。这是通过将身份验证标记作为 openssl_decrypt 的第 6 个参数传递来完成的。 -方法:

$ret = openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv, $tag);

只有当用于解密的标签与用于加密的标签匹配时才能进行解密。

对于已发布示例中的数据,C++ 代码生成以下身份验证标记(作为十六进制字符串):

f7c18e8b99587f3063383d68230c0e35

最后,关于使用 OpenSSL 的 AES-GCM 的更详细解释可以在这里找到 encryptiondecryption (包括对身份验证标签的考虑)。

关于php - c++中的加密和php中的解密有什么问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56376819/

相关文章:

php - 我可以在不使用 API 的情况下在 Wordpress 中创建盐键吗?

php - mysql两次离开加入同一个表

php - Laravel Eloquent get where doesn't have, 搜索 wherehas 当不为 null

c++ - 为什么不能 for_each 修改它的仿函数参数?

security - 我应该对密码施加最大长度限制吗?

c# - 使用 Bouncy CaSTLe 在 C# 中加密和使用 AES(EAX 模式)在 Python 中解密的问题

c# - ASP.NET 哈希 PW + 盐混淆

php - 保存从函数 imagecopy 创建的图像

c++ - 按值类成员捕获

c++ - 如何以短时间格式验证输入字符串