【问题标题】:Crypto++ to PHP mcrypt not workingCrypto++ 到 PHP mcrypt 不起作用
【发布时间】:2012-08-24 15:20:22
【问题描述】:

我有一个使用 Crypto++ 将加密数据发送到 PHP 站点的 C++ 应用程序。但是,当数据到达 PHP 端时,它并没有正确解密数据。

C++ / Crypto++ 代码:

char stupidKey[AES::MAX_KEYLENGTH] = "thisisastupidkeythisisastupidke";

ECB_Mode<AES>::Encryption aes((byte *)stupidKey, AES::MAX_KEYLENGTH);

std::string cypher;
StringSource(aData, true, new StreamTransformationFilter(aes, new StringSink( cypher ))); 
StringSource(cypher, true, new Base64Encoder( new StringSink(aOutput) ));

PHP 代码:

define('CRYPT_SECRET', 'thisisastupidkeythisisastupidke');

$postData = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, 
                CRYPT_SECRET, base64_decode($_POST['request']), 
                MCRYPT_MODE_ECB);

注意:我知道 ECB 是一个糟糕的加密模式选择,但我想先让它在没有 IV 的额外怪异的情况下工作,然后再使事情复杂化。

【问题讨论】:

    标签: php c++ mcrypt crypto++


    【解决方案1】:

    我在使用 mcrypt 时运气不佳,但 openssl 似乎更适合使用 Crypto++。

    这里是 Crypto++ 代码:

    #include <iostream>
    #include <cryptopp/aes.h>
    #include <cryptopp/modes.h>
    #include <cryptopp/base64.h>
    
    std::string encrypt(const std::string& str_in, const std::string& key, const std::string& iv)
    {
        std::string str_out;
        CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption encryption((byte*)key.c_str(), key.length(), (byte*)iv.c_str());
    
        CryptoPP::StringSource encryptor(str_in, true, 
            new CryptoPP::StreamTransformationFilter(encryption, 
                new CryptoPP::Base64Encoder(
                    new CryptoPP::StringSink(str_out),
                    false // do not append a newline
                )
            )
        );
        return str_out;
    }
    
    std::string decrypt(const std::string& str_in, const std::string& key, const std::string& iv)
    {
        std::string str_out;
    
        CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption decryption((byte*)key.c_str(), key.length(), (byte*)iv.c_str());
    
        CryptoPP::StringSource decryptor(str_in, true, 
            new CryptoPP::Base64Decoder(
                new CryptoPP::StreamTransformationFilter(decryption, 
                    new CryptoPP::StringSink(str_out)
                )
            )
        );
        return str_out;
    }
    
    int main(int argc, char *argv[])
    {
        std::string str = "Hello, world!";
        std::string key = "01234567891234560123456789123456"; // 32 bytes
        std::string iv  = "0123456789123456"; // 16 bytes
        std::string str_encrypted = encrypt(str, key, iv);
        std::string str_decrypted = decrypt(str_encrypted, key, iv);
        std::cout << "str_encrypted: " << str_encrypted << std::endl;
        std::cout << "str_decrypted: " << str_decrypted << std::endl;
    }
    

    这里是 PHP 代码:

    <?php
        $string = 'Hello, world!';
        $key = '01234567891234560123456789123456'; // 32 bytes
        $iv  = '0123456789123456'; // 16 bytes
        $method = 'aes-256-cfb';
        $encrypted = base64_encode( openssl_encrypt ($string, $method, $key, true, $iv));
        $decrypted = openssl_decrypt( base64_decode($encrypted), $method, $key, true, $iv);
        echo "encrypted: $encrypted<br/>";
        echo "decrypted: $decrypted<br/>";
    ?>
    

    这里是 Crypto++ 的输出:

    str_encrypted: pF1gsk+GolfeTSYnEQ==
    str_decrypted: Hello, world!
    

    ...和 ​​PHP 输出:

    encrypted: pF1gsk+GolfeTSYnEQ==
    decrypted: Hello, world!
    

    不要忘记将 key 和 iv 更改为一些更智能的值 :o)

    【讨论】:

    • 我必须添加#include 来编译你的cpp!很好的例子,我花了 2 天时间才找到它,哈哈!
    • 谢谢你,@gcphost!我现在已将包含添加到上面的代码中。
    【解决方案2】:

    查看 PHP 手册(http://php.net/manual/en/function.mcrypt-decrypt.php),MCRYPT_RIJNDAEL_256 与 AES_256 不同。第一条评论提供了一些帮助:http://www.php.net/manual/en/function.mcrypt-decrypt.php#105985

    注意,MCRYPT_RIJNDAEL_256 不等同于 AES_256。

    使用 openssl 从 AES 解密 RIJNDAEL 的方法是使用 MCRYPT_RIJNDAEL_128 并在使用以下函数加密之前填充要加密的字符串:

    <?php 
    function pkcs5_pad ($text, $blocksize) { 
        $pad = $blocksize - (strlen($text) % $blocksize); 
        return $text . str_repeat(chr($pad), $pad); 
    } 
    ?> 
    

    在解密时,AES_256 或 AES_128 等的选择取决于加密时使用的密钥大小。就我而言,它是一个 128 位密钥,所以我使用了 AES_128。

    【讨论】:

      【解决方案3】:
      Client Side using ECB - DES_EDE3
      ==================================
      
      #include "cryptlib.h"
      #include "modes.h"
      #include "des.h"
      #include "base64.h" <-- any base64 encoder/decoder i found the usage of crypto++ base64 class a bit hard to use since you have to know how many byte are taken to encode a byte in base 64...
      #include "hex.h"
      
      // Encode the data using the handy Crypto++ base64 encoder. Base64 uses
      // 3 characters to store 2 characters.
      const int BUFFER_LENGTH = 255;
      byte plaintext[BUFFER_LENGTH];
      byte ciphertext[BUFFER_LENGTH];
      byte newciphertext[BUFFER_LENGTH];
      byte decrypted[BUFFER_LENGTH];
      
      CryptoPP::Base64Encoder base64Encoder;
      CBase64Coding base64Coder;
      CString MySensitiveDataUncrypted;
      CString MySensitiveData;
      
      // Set up the same key and IV
      const int KEY_LENGTH = 24;
      const int BLOCK_SIZE = CryptoPP::DES::BLOCKSIZE;
      byte key[KEY_LENGTH], iv[CryptoPP::DES::BLOCKSIZE];
      memset( key, 0, KEY_LENGTH);
      memcpy( key, "012345678901234567890123", KEY_LENGTH );
      memset( iv, 0, CryptoPP::DES::BLOCKSIZE);
      memcpy( iv, "01234567", CryptoPP::DES::BLOCKSIZE );
      memset( plaintext, 0, BUFFER_LENGTH);
      memset( ciphertext, 0, BUFFER_LENGTH);
      memset( newciphertext, 0, BUFFER_LENGTH);
      strcpy((char*)plaintext,MySensitiveDataUncrypted.GetBuffer(0));
      // now encrypt
      CryptoPP::ECB_Mode::Encryption ecbEncryption(key, sizeof(key));
      ecbEncryption.ProcessString(newciphertext, plaintext, BUFFER_LENGTH);
      // your own base64 encoder/decoder
      base64Coder.Encode((char *)newciphertext,BUFFER_LENGTH,(char *)ciphertext);
      MySensitiveData.Format(_T("%s"),ciphertext);
      
      // MySensitiveData can now be send over http
      
      
      Server Side in PHP using ECB - DES_EDE3
      =========================================
      
      // $MyBase64EncodedSecretString will receive/store the encrypted string which will also be base64Encoded for HTTP protocol convenience
      
      $key = "012345678901234567890123";
      $iv = "01234567";
      
      // Set up an "encryption" descriptor. This is basically just an object that
      // encapsulates the encryption algorithm. 'tripledes' is the name of the
      // algorithm, which is simply the DES algorithm done three times back to
      // back. 'ecb' describes how to encrypt different blocks. See, DES
      // actually only encrypts 8-byte blocks at a time. To encrypt more than 8
      // bytes of data, you break the data up into 8-byte chunks (padding the
      // last chunk with NULL, if need be), and then encrypt each block
      // individually. Now, ECB (which stands for "Electronic Code Book", for
      // whatever that's worth) means that each 8-byte block is encrypted
      // independently. This has pros and cons that I don't care to discuss.
      // The other option is CBC ("Cipher Block Chaining") which links the blocks,
      // such as by XORing each block with the encrypted result of the previous
      // block. Security geeks probably really get excited about this, but for my
      // needs, I don't really care.
      $td = mcrypt_module_open( 'tripledes', '', 'ecb', '' );
      mcrypt_generic_init( $td, $key, $iv );
      
      // Grab some interesting data from the descriptor.
      // $maxKeySize = 24, meaning 24 bytes
      // $maxIVSize = 8, meaning 8 bytes
      $maxKeySize = mcrypt_enc_get_key_size( $td );
      $maxIVSize = mcrypt_enc_get_iv_size( $td );
      //echo "maxKeySize=$maxKeySize, maxIVSize=$maxIVSize\n";
      
      // let's decrypt it and verify the result. Because DES pads
      // the end of the original block with NULL bytes, let's trim those off to
      // create the final result.
      $MyEncodedSecretString = base64_decode( $MyBase64EncodedSecretString );
      $MyDecodedString = rtrim( mdecrypt_generic( $td, $MyEncodedSecretString ), "\0" );
      
      // And finally, clean up the encryption object
      mcrypt_generic_deinit($td);
      mcrypt_module_close($td);
      
      
      Client Side Stronger Encryption using RSA
      =========================================
      
      First you will need to generate a public/private key pair using crypto++ keygen console application then your client code should be something like
      
      // Client Side Using RSA
      #include "cryptlib.h"
      #include "rsa.h"
      #include "hex.h"
      #include "randpool.h"
      #include "filesource.h"
      
      CString MyNotverySecretStringInMemory;
      CString MySensitiveData;
      char pubFilename[128];
      char seed[1024], message[1024];
      
      // MAX = 19999991
      strcpy(seed,"12345");
      
      CString tmpPath;
      TCHAR appPath[MAX_PATH];
      ::GetModuleFileName(NULL,appPath,MAX_PATH);
      
      tmpPath = appPath;
      tmpPath = tmpPath.Left(tmpPath.ReverseFind('\\')+1);
      tmpPath += "public.key"; // 1024 key length for higher security.
      
      strcpy(pubFilename,tmpPath.GetBuffer(0));
      strcpy(message,MyNotverySecretStringInMemory.GetBuffer(0));
      CryptoPP::FileSource pubFile(pubFilename, true, new CryptoPP::HexDecoder);
      CryptoPP::RSAES_OAEP_SHA_Encryptor pub(pubFile);
      CryptoPP::RandomPool randPool;
      randPool.IncorporateEntropy((byte *)seed, strlen(seed));
      std::string result;
      CryptoPP::StringSource(message, true, new CryptoPP::PK_EncryptorFilter(randPool, pub, new CryptoPP::HexEncoder(new CryptoPP::StringSink(result))));
      MySensitiveData.Format(_T("%s"),result.c_str());
      

      【讨论】:

        猜你喜欢
        • 2013-01-20
        • 2014-06-06
        • 2014-09-12
        • 2012-01-28
        • 2011-11-13
        • 2014-02-06
        • 2015-12-03
        • 2014-08-14
        • 2011-05-02
        相关资源
        最近更新 更多