5

CryptoJS(v 2.3)を使用してWebアプリケーションで文字列を暗号化しており、Pythonのサーバーで文字列を復号化する必要があるため、PyCryptoを使用しています。うまくいかないので、何かが足りないような気がします。

これがJSです:

Crypto.AES.encrypt('1234567890123456', '1234567890123456',
                   {mode: new Crypto.mode.CBC(Crypto.pad.ZeroPadding)})
// output: "wRbCMWcWbDTmgXKCjQ3Pd//aRasZ4mQr57DgTfIvRYE="

Python:

from Crypto.Cipher import AES
import base64
decryptor = AES.new('1234567890123456', AES.MODE_CBC)
decryptor.decrypt(base64.b64decode("wRbCMWcWbDTmgXKCjQ3Pd//aRasZ4mQr57DgTfIvRYE="))
# output: '\xd0\xc2\x1ew\xbb\xf1\xf2\x9a\xb9\xb6\xdc\x15l\xe7\xf3\xfa\xed\xe4\xf5j\x826\xde(m\xdf\xdc_\x9e\xd3\xb1'
4

2 に答える 2

12

これがCryptoJS3.1.2のバージョンです。次のことに常に注意してください(両方の言語で同じものを使用してください)。

  • 動作モード(この場合はCBC)
  • パディング(この場合はゼロパディング。PKCS#7パディングを使用することをお勧めします)
  • キー(同じ導出関数またはクリアキー)
  • エンコーディング(キー、プレーンテキスト、暗号文などの同じエンコーディング)
  • IV(暗号化中に生成され、復号化のために渡されます)

key文字列が引数としてCryptoJS関数に渡される場合、encrypt()その文字列は、暗号化に使用される実際のキーを導出するために使用されます。キー(有効なサイズは16、24、および32バイト)を使用する場合は、それをWordArrayとして渡す必要があります。

CryptoJS暗号化の結果は、OpenSSL形式の暗号文文字列です。そこから実際の暗号文を取得するには、そのciphertextプロパティにアクセスする必要があります。

IVは、意味的に安全であるように、暗号化ごとにランダムである必要があります。そうすれば、攻撃者は、暗号文だけを見たときに、複数回暗号化された同じ平文が実際に同じ平文であるかどうかを判断できません。

以下は私が作った例です。

JavaScript:

var key = CryptoJS.enc.Utf8.parse('1234567890123456'); // TODO change to something with more entropy

function encrypt(msgString, key) {
    // msgString is expected to be Utf8 encoded
    var iv = CryptoJS.lib.WordArray.random(16);
    var encrypted = CryptoJS.AES.encrypt(msgString, key, {
        iv: iv
    });
    return iv.concat(encrypted.ciphertext).toString(CryptoJS.enc.Base64);
}

function decrypt(ciphertextStr, key) {
    var ciphertext = CryptoJS.enc.Base64.parse(ciphertextStr);

    // 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;
    
    // decryption
    var decrypted = CryptoJS.AES.decrypt({ciphertext: ciphertext}, key, {
        iv: iv
    });
    return decrypted.toString(CryptoJS.enc.Utf8);
}

pycryptoを使用したPython2コード:

BLOCK_SIZE = 16
key = b"1234567890123456" # TODO change to something with more entropy

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

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

def encrypt(message, key):
    IV = Random.new().read(BLOCK_SIZE)
    aes = AES.new(key, AES.MODE_CBC, IV)
    return base64.b64encode(IV + aes.encrypt(pad(message)))

def decrypt(encrypted, key):
    encrypted = base64.b64decode(encrypted)
    IV = encrypted[:BLOCK_SIZE]
    aes = AES.new(key, AES.MODE_CBC, IV)
    return unpad(aes.decrypt(encrypted[BLOCK_SIZE:]))

警告: python2とpycryptoはどちらも廃止されているため、python3とpycryptodomeに合うようにコードを調整する必要があることに注意してください。


その他の考慮事項:

パスフレーズをキーにしたいと思われます。パスフレーズは通常人間が読める形式ですが、キーはそうではありません。PBKDF2、bcrypt、scryptなどの機能を備えたパスフレーズからキーを取得できます。

上記のコードは認証がないため、完全に安全ではありません。認証されていない暗号文は、実行可能な攻撃や見過ごされているデータ操作につながる可能性があります。通常、encrypt-then-MACスキームは、HMAC-SHA256などの優れたMAC機能で使用されます。

于 2015-06-23T18:51:17.553 に答える
-2

注:salt、iv、paddingはjsとpythonで同じである必要があります

saltとivの値を生成し、CryptoJS.enc.Utf8.parse()を使用してバイト文字列に変換します

jsファイル

var encrypted = CryptoJS.AES.encrypt(JSON.stringify(json_data), CryptoJS.enc.Utf8.parse(data['salt']) , { iv: CryptoJS.enc.Utf8.parse(data['iv']) , mode: CryptoJS.mode.CBC , padding: CryptoJS.pad.Pkcs7});
en_data = encrypted.ciphertext.toString(CryptoJS.enc.Base64)

この暗号化されたデータをPythonファイルに送信します

Pythonファイル

from Crypto.Util.Padding import pad, unpad

ct = request.POST['encrypted_data']
data = base64.b64decode(ct)
cipher1 = AES.new(salt, AES.MODE_CBC, iv)
pt = unpad(cipher2.decrypt(data), 16)
data = json.loads(pt.decode('utf-8'))
        

pycryptoのpadとupadは、デフォルトでpkcs#7を使用します

ソルトとivの値はバイト文字列である必要があります

于 2020-07-25T05:02:14.697 に答える