简体   繁体   中英

OpenSSL inconsistency in C++ and PHP

I'm trying to write a piece of code for encrypting/decrypting data (eg passwords) which will be stored in DB. The goal is that data can be used in C++, PHP and Java. The problem is I'm not getting same encrypted data in C++ and PHP (I'm not dealing with Java jet). C++ code:

void CSSLtestDlg::TryIt()
{
    CString msg, tmp;

    /* A 256 bit key */
    unsigned char *key = (unsigned char *)"01234567890123456789012345678901";
    /* A 128 bit IV */
    unsigned char *iv = (unsigned char *)"01234567890123456";
    /* Message to be encrypted */
    unsigned char *plaintext = (unsigned char *)"Some_plain_text";

    msg = "Original text is: Some_plain_text";

    /* Buffer for ciphertext. Ensure the buffer is long enough for the
    * ciphertext which may be longer than the plaintext, dependant on the
    * algorithm and mode
    */
    unsigned char ciphertext[128];

    /* Buffer for the decrypted text */
    unsigned char decryptedtext[128];

    int decryptedtext_len, ciphertext_len;
    /* Initialise the library */
    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();
    OPENSSL_config(NULL);

    /* Encrypt the plaintext */
    ciphertext_len = encryptIt (plaintext, strlen ((char *)plaintext), 
        key, iv, ciphertext);

    ciphertext[ciphertext_len] = '\0';

    tmp.Format("\nEncrypted text (in HEX) is: %s", StrToHex(ciphertext));
    msg += tmp;

    /* Decrypt the ciphertext */
    decryptedtext_len = decryptIt(ciphertext, ciphertext_len, 
        key, iv, decryptedtext);

    /* Add a NULL terminator. We are expecting printable text */
    decryptedtext[decryptedtext_len] = '\0';

    tmp.Format("\nDecrypted text is: %s", decryptedtext);
    msg += tmp;

    AfxMessageBox(msg);

    /* Clean up */
    EVP_cleanup();
    ERR_free_strings();
}

int CSSLtestDlg::encryptIt(unsigned char *plaintext, int plaintext_len, 
 unsigned char *key,  unsigned char *iv, unsigned char *ciphertext)
{
  EVP_CIPHER_CTX *ctx;

  int len;

  int ciphertext_len;

  /* Create and initialise the context */
  if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();

  /* Initialise the encryption operation. IMPORTANT - ensure you use a key
   * and IV size appropriate for your cipher
   * In this example we are using 256 bit AES (i.e. a 256 bit key). The
   * IV size for *most* modes is the same as the block size. For AES this
   * is 128 bits */
  if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
    handleErrors();

  /* Provide the message to be encrypted, and obtain the encrypted output.
   * EVP_EncryptUpdate can be called multiple times if necessary
   */
  if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
    handleErrors();
  ciphertext_len = len;

  /* Finalise the encryption. Further ciphertext bytes may be written at
   * this stage.
   */
  if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
  ciphertext_len += len;

  /* Clean up */
  EVP_CIPHER_CTX_free(ctx);

  return ciphertext_len;
}

int CSSLtestDlg::decryptIt(unsigned char *ciphertext, int ciphertext_len, 
unsigned char *key, unsigned char *iv, unsigned char *plaintext)
{
  EVP_CIPHER_CTX *ctx;

  int len;

  int plaintext_len;

  /* Create and initialise the context */
  if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();

  /* Initialise the decryption operation. IMPORTANT - ensure you use a key
   * and IV size appropriate for your cipher
   * In this example we are using 256 bit AES (i.e. a 256 bit key). The
   * IV size for *most* modes is the same as the block size. For AES this
   * is 128 bits */
  if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
    handleErrors();

  /* Provide the message to be decrypted, and obtain the plaintext output.
   * EVP_DecryptUpdate can be called multiple times if necessary
   */
  if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
    handleErrors();
  plaintext_len = len;

  /* Finalise the decryption. Further plaintext bytes may be written at
   * this stage.
   */
  if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();
  plaintext_len += len;

  /* Clean up */
  EVP_CIPHER_CTX_free(ctx);

  return plaintext_len;
}

Result:

Original text is: Some_plain_text
Encrypted text (in HEX) is: 39D35A2E6EF8F8E36F3BC1FD8B6B32
Decrypted text is: Some_plain_text

PHP code:

$key = "01234567890123456789012345678901";
$iv = "01234567890123456";
$msg = "Some_plain_text";

if(function_exists('openssl_encrypt'))
{
    echo("Original text is:" . $msg . "<br>");
    $encrypted_msg = openssl_encrypt($msg, "aes-256-cbc", $key, OPENSSL_RAW_DATA, $iv);
    if ($encrypted_msg == FALSE)
        $log->logDebug("openssl_encrypt error!");
    else
    {
        echo("Encrypted text (in HEX) is:" . strToHex($encrypted_msg) . "<br>");
        $decrypted_msg = openssl_decrypt($encrypted_msg, "aes-256-cbc", $key, OPENSSL_RAW_DATA , $iv);
        echo("Decrypted text is:" . $decrypted_msg . "<br>");
    }
}
else echo("openssl_encrypt doesn't exists!<br>");

function strToHex($string)
{
    $hex = '';
    for ($i=0; $i<strlen($string); $i++)
    {
        $ord = ord($string[$i]);
        $hexCode = dechex($ord);
        $hex .= substr('0'.$hexCode, -2);
    }
    return strToUpper($hex);
}

Result:

Original text is:Some_plain_text
Encrypted text (in HEX) is:39D35A2E6EF8F8E36F3BC1FD8B06B302
Decrypted text is:Some_plain_text

So I'm getting 39D35A2E6EF8F8E36F3BC1FD8B6 B32 (C++) opposite to 39D35A2E6EF8F8E36F3BC1FD8B06 B302 (PHP). In the end a HEX data is going to be stored in DB and retrieved later on. Thanks in advance for all the help and sorry for my bad language.

So the problem was in C++ code in StrToHex() function (which I forget to post in original question) so here it is:

CString StrToHex(unsigned char* str)
{       
    CString tmp;
    CString csHexString;    
    int nCount = strlen((char *)str);            
    for( int nIdx =0; nIdx < nCount; nIdx++ )      
    {          
        int n = str[nIdx];
        //tmp.Format( _T("%X"), n ); --> this is wrong
        tmp.Format( _T("%02X"), n ); // --> this is OK
        csHexString += tmp;      
    }   
    return csHexString;
}

There's also another extra 0 in the second output (B6/B06). Those are probably the only low bytes in the output, and you have different format settings.

If you show your C++ StrToHex it's probably a simple format string fix, like %x to %0x.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM