在python中加密 - 在Javascript中解密

ben*_*siu 3 javascript python encryption pycrypto cryptojs

我需要简单地加密python中的一些文本,并能够在JavaScrypt中解密.

到目前为止我在python中:

from Crypto import Random
from Crypto.Cipher import AES
import base64

BLOCK_SIZE = 16
key = "1234567890123456" # want to be 16 chars
textToEncrypt = "This is text to encrypt"

def encrypt(message, passphrase):
    # passphrase MUST be 16, 24 or 32 bytes long, how can I do that ?
    IV = Random.new().read(BLOCK_SIZE)
    aes = AES.new(passphrase, AES.MODE_CFB, IV)
    return base64.b64encode(aes.encrypt(message))

def decrypt(encrypted, passphrase):
    IV = Random.new().read(BLOCK_SIZE)
    aes = AES.new(passphrase, AES.MODE_CFB, IV)
    return aes.decrypt(base64.b64decode(encrypted))

print encrypt( textToEncrypt, key )
Run Code Online (Sandbox Code Playgroud)

这是产生文字: ZF9as5JII5TlqcB5tAd4sxPuBXd5TrgE

在JavaScript中:

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
<script>
    var decrypted = CryptoJS.AES.decrypt( "ZF9as5JII5TlqcB5tAd4sxPuBXd5TrgE", "1234567890123456");
    console.log ( decrypted.toString( CryptoJS.enc.Utf8 ) );
</script>
Run Code Online (Sandbox Code Playgroud)

但是它不会产生原始字符串(而是使用空字符串).我做错了什么?

它是专注于AES是一个最好的主意 - 如果我有一些会模糊数据的加密,我会很高兴.

Art*_* B. 12

您的Python代码 CryptoJS代码存在许多问题:

  • 您使用随机IV加密Python中的一些明文.如果要检索该明文,则需要在解密期间使用相同的IV.没有IV,明文就无法恢复.通常,IV只是前置于密文,因为它不必是秘密的.因此,您需要在解密期间读取IV,而不是生成新的IV.

  • 您在CryptoJS(默认)而不是CFB模式中使用CBC模式.模式必须相同.另一个棘手的部分是CFB模式使用段大小进行参数化.PyCrypto默认使用8位段(CFB8),但CryptoJS仅针对128位(CFB128)的固定段实现.由于PyCrypto版本是可变的,您需要更改它.

  • CryptoJS decrypt()函数要求将密文作为OpenSSL格式的字符串或CipherParams对象.由于您没有OpenSSL格式的字符串,因此必须将密文转换为对象.

  • key用于CryptoJS有望成为一个WordArray而不是字符串.

  • 使用相同的填充.如果使用CFB8,PyCrypto不会填充明文,但在使用CFB128时需要填充.CryptoJS默认使用PKCS#7填充,因此您只需要在python中实现该填充.

Python代码(适用于版本2):

def pad(data):
    length = 16 - (len(data) % 16)
    return data + chr(length)*length

def unpad(data):
    return data[:-ord(data[-1])]

def encrypt(message, passphrase):
    IV = Random.new().read(BLOCK_SIZE)
    aes = AES.new(passphrase, AES.MODE_CFB, IV, segment_size=128)
    return base64.b64encode(IV + aes.encrypt(pad(message)))

def decrypt(encrypted, passphrase):
    encrypted = base64.b64decode(encrypted)
    IV = encrypted[:BLOCK_SIZE]
    aes = AES.new(passphrase, AES.MODE_CFB, IV, segment_size=128)
    return unpad(aes.decrypt(encrypted[BLOCK_SIZE:]))
Run Code Online (Sandbox Code Playgroud)

JavaScript代码:

<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/components/mode-cfb-min.js"></script>
<script>
    var base64ciphertextFromPython = "...";
    var ciphertext = CryptoJS.enc.Base64.parse(base64ciphertextFromPython);

    // split iv and ciphertext
    var iv = ciphertext.clone();
    iv.sigBytes = 16;
    iv.clamp();
    ciphertext.words.splice(0, 4); // delete 4 words = 16 bytes
    ciphertext.sigBytes -= 16;

    var key = CryptoJS.enc.Utf8.parse("1234567890123456");

    // decryption
    var decrypted = CryptoJS.AES.decrypt({ciphertext: ciphertext}, key, {
      iv: iv,
      mode: CryptoJS.mode.CFB
    });
    console.log ( decrypted.toString(CryptoJS.enc.Utf8));
</script>
Run Code Online (Sandbox Code Playgroud)

其他考虑:

您似乎想要使用密码作为密钥.密码短语通常是人类可读的,但密钥则不是.您可以使用包含PBKDF2,bcrypt或scrypt等功能的密码来派生密钥.

上面的代码并不完全安全,因为它缺乏身份验证.未经验证的密文可能会导致可行的攻击和未被注意的数据操作.通常,加密然后MAC方案与良好的MAC功能一起使用,例如HMAC-SHA256.


小智 6

(1年后,但我希望这对某人有用)

首先,感谢ArtjomB。您的帖子对我有很大帮助。和OP一样,Python服务器端和Javascript客户端解码也有相同的问题。这是我的解决方案:


Python 3.x(服务器)

我使用专用的PKCS7编码进行填充,为什么?因为我想确保Im使用相同的填充和解码填充,所以这是我在http://programmerin.blogspot.com.co/2011/08/python-padding-with-pkcs7.html找到它的链接。

然后,就像Artjom B.所说的那样,请确保您的段大小,IV大小和AES模式(对我来说是CBC),

这是代码:

def encrypt_val(clear_text):
    master_key = '1234567890123456' 
    encoder = PKCS7Encoder()
    raw = encoder.encode(clear_text)
    iv = Random.new().read( 16 )
    cipher = AES.new( master_key, AES.MODE_CBC, iv, segment_size=128 )
    return base64.b64encode( iv + cipher.encrypt( raw ) ) 
Run Code Online (Sandbox Code Playgroud)

请注意,您不是在base64上将IV和加密数据串联在一起。


Javascript(客户端)

function decryptMsg (data) {
    master_key = '1234567890123456';

    // Decode the base64 data so we can separate iv and crypt text.
    var rawData = atob(data);
    // Split by 16 because my IV size
    var iv = rawData.substring(0, 16);
    var crypttext = rawData.substring(16);

    //Parsers
    crypttext = CryptoJS.enc.Latin1.parse(crypttext);
    iv = CryptoJS.enc.Latin1.parse(iv); 
    key = CryptoJS.enc.Utf8.parse(master_key);

    // Decrypt
    var plaintextArray = CryptoJS.AES.decrypt(
      { ciphertext:  crypttext},
      key,
      {iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7}
    );

    // Can be Utf8 too
    output_plaintext = CryptoJS.enc.Latin1.stringify(plaintextArray);
    console.log("plain text : " + output_plaintext);
}
Run Code Online (Sandbox Code Playgroud)

我的主要问题之一是记住各种编码和解码数据,例如,我不知道客户端的master_key是否要用Utf8解析。