2

我有一个使用 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 的奇怪之处的情况下让它工作,然后使事情复杂化。

4

3 回答 3

6

我对 mcrypt 没有运气,但 openssl 似乎可以更好地使用 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)

于 2013-05-18T20:16:37.750 回答
5

查看 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。

于 2012-08-29T23:12:13.377 回答
0
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-25T04:48:40.107 回答