用PHP加密,用Python或openssl命令行解密


Encrypt in PHP and decrypt in Python or openssl command line

我接管的数据库中的许多数据包含加密字段。用于加密数据的方法是以下PHP代码:

<?php
$text = "test 1234'ntest 2345'ntest 3456'ntest 4567";
$key = "0123456789abcdefghijklmnopqrstuv";
$enc = openssl_encrypt($text, "AES-256-CBC", $key);
echo "Raw: " . $text . "'n";
echo "Key: " . $key . "'n";
echo "Key (Hex) " . bin2hex($key) . "'n";
echo $enc;
echo "'n";
?>

当我运行代码时,我得到以下输出,包括关于空初始化向量(iv)的警告,我必须忽略它,因为整个DB数据都是以这种方式加密的(我完全知道这不应该这样做)。

Warning: openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended in /tmp/cp3_encdec/enc2.php on line 5
Raw: test 1234
test 2345
test 3456
test 4567
Key: 0123456789abcdefghijklmnopqrstuv
Key (Hex) 303132333435363738396162636465666768696a6b6c6d6e6f70717273747576
uPNXdo2K0Gvy/+MW0YFR7utFsrNDAp8yYaDxT352W3lPKNOkNMg+l3eFKEi0zeze

使用php openssl_decrypt($encrypted, "AES-256-CBC", $key)解密给我完整的输出。Php手册并没有详细说明当这些值为空时,如何使用填充和iv进行加密。

接下来,我尝试使用openssl命令在命令行上解密:

echo "uPNXdo2K0Gvy/+MW0YFR7utFsrNDAp8yYaDxT352W3lPKNOkNMg+l3eFKEi0zeze" | openssl aes-256-cbc -d -a -K 303132333435363738396162636465666768696a6b6c6d6e6f70717273747576 -iv 0

可以正常工作并返回初始输入:

test 1234
test 2345
test 3456
test 4567

尝试在Python中使用以下代码解密会导致错误的解密:

import base64
from Crypto.Cipher import AES 
PAD = u''0000' 
def decrypt(enc, key):
    decobj = AES.new(key, AES.MODE_ECB)
    data = decobj.decrypt(base64.b64decode(enc))
    data = data.rstrip(PAD.encode())
    print(str(data))
key = "0123456789abcdefghijklmnopqrstuv"
decrypt("uPNXdo2K0Gvy/+MW0YFR7utFsrNDAp8yYaDxT352W3lPKNOkNMg+l3eFKEi0zeze", key)

结果,前16字节可读,其余部分不可读:

b'test 1234'ntest 2'x8b'xc7b|'xf9'xef'xa3'x1f'xd2'xcc'xd7#'xe7'x8b%'x8b'x981'x92'x87v4'xa8;h'xa9'xf8Fw'x7fRp'

修改我的输入以包含更多的数据也会破坏使用openssl命令的解密:

Raw: [system] test:1234
[system] test:2345
[database] test:3456
[unknown] test:4567
Key: 0123456789abcdefghijklmnopqrstuv
Key (Hex) 303132333435363738396162636465666768696a6b6c6d6e6f70717273747576
9KWsGGLa1/g3f36kUJJ/oHNiEnIDorZULwR8pXZHwJhul2XsdZLwLN8jMptP9fcWgY42oTq7RTm+/8CKPiGFPWrY/3neLvf8UNedsVuKRlc=
Openssl命令行:
echo "9KWsGGLa1/g3f36kUJJ/oHNiEnIDorZULwR8pXZHwJhul2XsdZLwLN8jMptP9fcWgY42oTq7RTm+/8CKPiGFPWrY/3neLvf8UNedsVuKRlc=" | openssl aes-256-cbc -d -a -K 303132333435363738396162636465666768696a6b6c6d6e6f70717273747576 -iv 0
bad decrypt
15143:error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length:/BuildRoot/Library/Caches/com.apple.xbs/Sources/OpenSSL098/OpenSSL098-64/src/crypto/evp/evp_enc.c:323:

同样使用上面的Python代码将导致前16字节可读,但其余部分不可读:

b'[system] test:12'xc7'x91'xa6C'x11'xa3'xa4'x8cR'x12#'x84$'xf7'x0c'xd4IP!F6'xa8'xed0Np'x1d'xc7'x174'xa5'xc5N'xe3'x00'x9f'x01'xa8'xc3'x18'xea'x158'xc0:'x9b'x9cx'xee'xf9X'xfc'x1a'xcf J'xca'xc5'xf4'xbf'x08'x16'x8f<'

如果使用php openssl_decrypt works:

<?php
$text = "9KWsGGLa1/g3f36kUJJ/oHNiEnIDorZULwR8pXZHwJhul2XsdZLwLN8jMptP9fcWgY42oTq7RTm+/8CKPiGFPWrY/3neLvf8UNedsVuKRlc=";
$key = "0123456789abcdefghijklmnopqrstuv";
$dec = openssl_decrypt($text, "AES-256-CBC", $key);
echo $dec;
echo "'n";
?>
[system] test:1234
[system] test:2345
[database] test:3456
[unknown] test:4567

有人有一个想法如何php加密数据,我想这是一个填充问题,但我不确定,我是开放的任何帮助在这个主题

我对我的Python代码做了一些修改,似乎解决了这个问题:

import base64
from Crypto.Cipher import AES 
IV = 16 * ''x00'
def decrypt(enc, key):
    decobj = AES.new(key, AES.MODE_CBC, IV)
    data = decobj.decrypt(base64.b64decode(enc))
    print(str(data.decode()))
key = "0123456789abcdefghijklmnopqrstuv"
decrypt("uPNXdo2K0Gvy/+MW0YFR7utFsrNDAp8yYaDxT352W3lPKNOkNMg+l3eFKEi0zeze", key)

在命令行中我还没有找到解决方案

使用块解码的示例,我的PHP工作替代方案openssl_private_decrypt

Сreate私钥:

openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen-bits 1024

Сreate公钥:

openssl rsa -pubout -in private.pem -out public.pem

您可能需要创建以-----开头的RSA密钥文件BEGIN RSA PRIVATE key -----:

openssl rsa -in private.pem -out private_rsa.pem

Python3代码:

   from cryptography.hazmat.primitives import serialization
   from cryptography.hazmat.primitives.asymmetric import padding
   import zlib
   file = open('private_rsa.pem', 'rb')
   priv_key = file.read()
   file.close()
   encryptedString=''' YOUR ENCRYPTED STRING '''
   private_key = serialization.load_pem_private_key(priv_key, password=None, backend=default_backend())
   chunk_size = math.ceil(1024/8)
   offset = 0
   decrypted = bytearray()
   while offset < len(encryptedString):
       decrypted += private_key.decrypt(encryptedString[offset: offset + chunk_size], padding.PKCS1v15())
       offset += chunk_size
   result = zlib.decompress(decrypted)
   print(result)