如何解密 PL/SQL 中使用 PHP 加密的字符串?

How to decrypt a string in PL/SQL that is encrypted using PHP?

我不熟悉加密和解密技术。我需要解密从 PHP 服务器收到的 PL/SQL 中的响应。加密方式为AES128 CBC。

PHP代码

$clear_text = "Secret Message";
$str        = "0962774221568619";
$key        = "0962774221568619";

$iv = str_pad($iv, 16, "[=12=]");
$encrypt_text = openssl_encrypt($clear_text, "AES-128-CBC", $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($encrypt_text);

echo $data;

以上代码加密后的字符串为:87UMyOAog3rlmzorneakjA==

现在我想解密PL/SQL中的这个字符串。在解密之前,首先我尝试通过在 PL/SQL 中复制 PHP 代码来加密相同的消息,如下所示。

使用PL/SQL

加密
DECLARE
   input_string       VARCHAR2 (200) :=  'Secret Message';
   output_string      VARCHAR2 (200);
   encrypted_raw      RAW (2000);             -- stores encrypted binary text
   decrypted_raw      RAW (2000);             -- stores decrypted binary text
   encrypted_string   VARCHAR2(1000);        
   num_key_bytes      NUMBER := 128/8;        -- key length 256 bits (32 bytes)
   key_bytes_raw      RAW (32);               -- stores 256-bit encryption key
   encryption_type    PLS_INTEGER :=          -- total encryption type
                            DBMS_CRYPTO.ENCRYPT_AES128
                          + DBMS_CRYPTO.CHAIN_CBC
                          + DBMS_CRYPTO.PAD_PKCS5;

   iv_raw             RAW (16);

BEGIN
   key_bytes_raw := UTL_I18N.STRING_TO_RAW ('0962774221568619',  'UTF8');
   iv_raw        := UTL_I18N.STRING_TO_RAW ('0962774221568619',  'UTF8');
   
   encrypted_raw := DBMS_CRYPTO.ENCRYPT
      (
         src => UTL_I18N.STRING_TO_RAW (input_string,  'UTF8'),
         typ => encryption_type,
         key => key_bytes_raw,
         iv  => iv_raw
      );

    DBMS_OUTPUT.PUT_LINE ('encrypted_raw: ' || encrypted_raw);    
    
    encrypted_string:= utl_raw.cast_to_varchar2(UTL_ENCODE.BASE64_ENCODE(encrypted_raw));
    
    DBMS_OUTPUT.PUT_LINE ('encrypted_string: ' || encrypted_string);
END;

输出

encrypted_raw: 0C36016A23FE45D8C62C50615336E5C6

encrypted_string:DDYBaiP+RdjGLFBhUzblxg=

这里我从PHP和PL/SQL得到了不同的加密字符串。我不确定,但似乎 PL/SQL 中的 PHP 代码复制对我来说不正确。

使用下面的代码,我可以解密从 PL/SQL.

加密的字符串
DECLARE
   output_string      VARCHAR2 (200);
   encrypted_raw      RAW (2000);             -- stores encrypted binary text
   decrypted_raw      RAW (2000);             -- stores decrypted binary text
   num_key_bytes      NUMBER := 128/8;        -- key length 256 bits (32 bytes)
   key_bytes_raw      RAW (32);               -- stores 256-bit encryption key
   encryption_type    PLS_INTEGER :=          -- total encryption type
                            DBMS_CRYPTO.ENCRYPT_AES128
                          + DBMS_CRYPTO.CHAIN_CBC
                          + DBMS_CRYPTO.PAD_PKCS5;

   iv_raw             RAW (16);

BEGIN
   encrypted_raw := '0C36016A23FE45D8C62C50615336E5C6'; 
   key_bytes_raw := UTL_I18N.STRING_TO_RAW ('0962774221568619',  'UTF8');
   iv_raw        := UTL_I18N.STRING_TO_RAW ('0962774221568619',  'UTF8');
   
     decrypted_raw := DBMS_CRYPTO.DECRYPT
      (
         src => encrypted_raw,
         typ => encryption_type,
         key => key_bytes_raw,
         iv  => iv_raw
      );

   output_string := UTL_I18N.RAW_TO_CHAR (decrypted_raw, 'AL32UTF8');

   DBMS_OUTPUT.PUT_LINE ('Decrypted string: ' || output_string);
END;

输出:秘密消息

这很好,但我在解密从 PHP 加密的字符串时面临挑战。

更新

我忘记在用于加密字符串的 PHP 代码中分配 IV 值。感谢@topaco 和@BartoszOlchowik 指出这个错误。

更新代码

PHP

$clear_text = "Secret Message";
$iv         = "0962774221568619";
$key        = "0962774221568619";

$iv = str_pad($iv, 16, "[=15=]");
$encrypt_text = openssl_encrypt($clear_text, "AES-128-CBC", $key, OPENSSL_RAW_DATA, $iv);
$data = base64_encode($encrypt_text);

echo $data;

加密字符串:DDYBaiP+RdjGLFBhUzblxg==

PL/SQL

DECLARE
   encrypted_string   VARCHAR2(1000):= 'DDYBaiP+RdjGLFBhUzblxg=='; -- Encrypted string from php
   output_string      VARCHAR2 (200);
   encrypted_raw      RAW (2000);             -- stores encrypted binary text
   decrypted_raw      RAW (2000);             -- stores decrypted binary text
          
   num_key_bytes      NUMBER := 128/8;        -- key length 256 bits (32 bytes)
   key_bytes_raw      RAW (32);               -- stores 256-bit encryption key
   encryption_type    PLS_INTEGER :=          -- total encryption type
                            DBMS_CRYPTO.ENCRYPT_AES128
                          + DBMS_CRYPTO.CHAIN_CBC
                          + DBMS_CRYPTO.PAD_PKCS5;

   iv_raw             RAW (16);

BEGIN
   key_bytes_raw := UTL_I18N.STRING_TO_RAW ('0962774221568619',  'UTF8');
   iv_raw        := UTL_I18N.STRING_TO_RAW ('0962774221568619',  'UTF8');
    
   --convert base64 encrypted string from php to raw
   encrypted_raw:= UTL_ENCODE.BASE64_DECODE(utl_raw.cast_to_raw(encrypted_string));
   
   decrypted_raw := DBMS_CRYPTO.DECRYPT
                    ( src => encrypted_raw,
                      typ => encryption_type,
                      key => key_bytes_raw,
                      iv  => iv_raw );
                      
   output_string := UTL_I18N.RAW_TO_CHAR (decrypted_raw, 'AL32UTF8');
   DBMS_OUTPUT.PUT_LINE ('Decrypted string: ' || output_string);    
END;

输出:解密后的字符串:Secret Message

您必须声明相同的加密数据才能正确解密。

在您的 PLSQL 代码中,IV 变量的值与 PHP 中声明的 IV 不同,因此您将无法解密 PLSQL 中的数据,您使用不同的 IV 在 PHP.

在 PLSQL 中使用与 PHP 中相同的 IV 值将解决问题。