我需要简单地加密python中的一些文本,并能够在JavaScrypt中解密。
到目前为止我已经在python中了:
function plus(a, b) {
return (a + b);
}
function minus(a, b) {
return (a - b);
}
function multiply(a, b) {
return (a * b);
}
function divide(a, b) {
return (a / b);
}
function calc() {
var x = parseFloat( document.getElementById("operator1").value );
var y = document.getElementById("operatorx").value;
var z = parseFloat( document.getElementById("operator2").value );
switch (y) {
case '0':
w = plus(x, z);
break;
case '1':
w = minus(x, z);
break;
case '2':
w = multiply(x, z);
break;
case '3':
w = divide(x, z);
break;
default:
w = "Don't really know..";
}
document.getElementById("result").value = w;
}
这是生成文字: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 )
:
ZF9as5JII5TlqcB5tAd4sxPuBXd5TrgE
然而它不会产生原始字符串(而是使用空字符串)。 我做错了什么?
专注于AES是一个最好的想法 - 如果我有某种加密会模糊数据,我会很高兴。
答案 0 :(得分:10)
您的Python代码和 CryptoJS代码存在许多问题:
您使用随机IV加密Python中的某些明文。如果要检索该明文,则需要在解密期间使用相同的IV 。没有IV,明文就无法恢复。通常,IV只是在密文之前,因为它不必是秘密的。因此,您需要在解密期间阅读IV,而不是生成新的。
您在CryptoJS(默认)中使用CBC模式而不是CFB模式。模式必须相同。另一个棘手的部分是CFB模式使用段大小进行参数化。 PyCrypto默认使用8位段(CFB8),但CryptoJS仅针对128位(CFB128)的固定段实现。由于PyCrypto版本是可变的,您需要更改它。
CryptoJS decrypt()
函数要求将密文作为OpenSSL格式的字符串或CipherParams对象。由于您没有OpenSSL格式的字符串,因此必须将密文转换为对象。
CryptoJS的key
应该是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:]))
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>
其他注意事项:
您似乎想要使用密码作为密钥。密码短语通常是人类可读的,但密钥则不是。您可以使用密码短语从PBKDF2,bcrypt或scrypt等函数派生密钥。
上面的代码并不完全安全,因为它缺乏身份验证。未经验证的密文可能会导致可行的攻击和未被注意的数据操作。通常,加密然后MAC方案采用良好的MAC功能,如HMAC-SHA256。
答案 1 :(得分:5)
(1年后但我希望这适用于某人)
首先,感谢Artjom B.你的帖子对我很有帮助。和OP一样,我有同样的问题Python服务器端口和Javascript客户端解码。这是我的解决方案:
Python 3.x (服务器)
我使用了一个明确的 PKCS7 编码进行填充,为什么?因为我想确保我使用相同的填充内容和解码,这是我找到它的链接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 ) )
请注意,您在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);
}
我的一个主要问题是记住所有类型的编码和解码数据,例如,我不知道客户端的master_key是要用Utf8进行解析。
答案 2 :(得分:0)
///第一个pip安装pycryptodome-(pycrypto已过时并出现问题) // pip安装pkcs7
from Crypto import Random
from Crypto.Cipher import AES
import base64
from pkcs7 import PKCS7Encoder
from app_settings.views import retrieve_settings # my custom settings
app_secrets = retrieve_settings(file_name='secrets');
def encrypt_data(text_data):
#limit to 16 bytes because my encryption key was too long
#yours could just be 'abcdefghwhatever'
encryption_key = app_secrets['ENCRYPTION_KEY'][:16];
#convert to bytes. same as bytes(encryption_key, 'utf-8')
encryption_key = str.encode(encryption_key);
#pad
encoder = PKCS7Encoder();
raw = encoder.encode(text_data) # Padding
iv = Random.new().read(AES.block_size ) #AES.block_size defaults to 16
# no need to set segment_size=BLAH
cipher = AES.new( encryption_key, AES.MODE_CBC, iv )
encrypted_text = base64.b64encode( iv + cipher.encrypt( str.encode(raw) ) )
return encrypted_text;