2012-05-11 70 views
9

Tôi đang cố gắng mã hóa một số nội dung bằng Python và giải mã nó trong ứng dụng nodejs.Mã hóa và giải mã bằng python và nodejs

Tôi đang cố gắng để có được hai triển khai AES để làm việc cùng nhau mặc dù. Đây là nơi tôi đang ở.

Trong nút:

var crypto = require('crypto'); 

var password = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; 
var input = 'hello world'; 

var encrypt = function (input, password, callback) { 
    var m = crypto.createHash('md5'); 
    m.update(password) 
    var key = m.digest('hex'); 

    m = crypto.createHash('md5'); 
    m.update(password + key) 
    var iv = m.digest('hex'); 

    // add padding 
    while (input.length % 16 !== 0) { 
     input += ' '; 
    } 

    var data = new Buffer(input, 'utf8').toString('binary'); 

    var cipher = crypto.createCipheriv('aes-256-cbc', key, iv.slice(0,16)); 
    var encrypted = cipher.update(data, 'binary') + cipher.final('binary'); 
    var encoded = new Buffer(encrypted, 'binary').toString('base64'); 

    callback(encoded); 
}; 

var decrypt = function (input, password, callback) { 
    // Convert urlsafe base64 to normal base64 
    var input = input.replace('-', '+').replace('/', '_'); 
    // Convert from base64 to binary string 
    var edata = new Buffer(input, 'base64').toString('binary') 

    // Create key from password 
    var m = crypto.createHash('md5'); 
    m.update(password) 
    var key = m.digest('hex'); 

    // Create iv from password and key 
    m = crypto.createHash('md5'); 
    m.update(password + key) 
    var iv = m.digest('hex'); 

    // Decipher encrypted data 
    var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv.slice(0,16)); 
    var decrypted = decipher.update(edata, 'binary') + decipher.final('binary'); 
    var plaintext = new Buffer(decrypted, 'binary').toString('utf8'); 

    callback(plaintext); 
}; 

encrypt(input, password, function (encoded) { 
    console.log(encoded); 
    decrypt(encoded, password, function (output) { 
     console.log(output); 
    }); 
}); 

này tạo ra kết quả:

BXSGjDAYKeXlaRXVVJGuREKTPiiXeam8W9e96Nknt3E= 
hello world 

Trong python

from Crypto.Cipher import AES 
from hashlib import md5 
import base64 

password = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 
input = 'hello world' 

def _encrypt(data, nonce, password): 
    m = md5() 
    m.update(password) 
    key = m.hexdigest() 

    m = md5() 
    m.update(password + key) 
    iv = m.hexdigest() 

    # pad to 16 bytes 
    data = data + " " * (16 - len(data) % 16) 

    aes = AES.new(key, AES.MODE_CBC, iv[:16]) 

    encrypted = aes.encrypt(data) 
    return base64.urlsafe_b64encode(encrypted) 

def _decrypt(edata, nonce, password): 
    edata = base64.urlsafe_b64decode(edata) 

    m = md5() 
    m.update(password) 
    key = m.hexdigest() 

    m = md5() 
    m.update(password + key) 
    iv = m.hexdigest() 

    aes = AES.new(key, AES.MODE_CBC, iv[:16]) 
    return aes.decrypt(edata) 

output = _encrypt(input, "", password) 
print(output) 
plaintext = _decrypt(output, "", password) 
print(plaintext) 

này tạo ra sản lượng

BXSGjDAYKeXlaRXVVJGuRA== 
hello world 

Rõ ràng chúng rất gần, nhưng nút có vẻ là đệm đầu ra với một cái gì đó. Bất kỳ ý tưởng làm thế nào tôi có thể có được hai để tương thích?

+0

1) Bạn có thực sự cần mã hóa mật khẩu dựa, thay vì sử dụng một chìa khóa ngẫu nhiên? 2) Nếu bạn làm thế, không sử dụng hàm băm đơn lặp. Sử dụng hàm muối và các hàm dẫn xuất khóa chậm, chẳng hạn như PBKDF2, bcrypt hoặc scrypt. – CodesInChaos

+0

3) Bạn không sử dụng chính xác IV. Nó phải là một giá trị ngẫu nhiên mới cho mỗi tin nhắn. Nó cũng phải có cùng kích thước với kích thước khối và không phải là một nửa kích thước khối, như trong ví dụ của bạn. – CodesInChaos

+0

Cảm ơn @CodeInChaos đây là mẫu mã vì vậy tôi đã đơn giản hóa một số trong số đó. Mật khẩu được tạo ra bằng cách sử dụng PBKDF2, và IV sẽ được ngẫu nhiên trong sản xuất. – dave

Trả lời

18

OK, tôi đã tìm ra, nút sử dụng OpenSSL sử dụng PKCS5 để làm đệm. PyCrypto không xử lý padding vì vậy tôi đã làm nó bản thân mình chỉ cần thêm '' trong cả hai.

Nếu tôi thêm PKCS5 đệm vào mã python và loại bỏ phần đệm trong mã nút, nó hoạt động.

Vì vậy, mã làm việc được cập nhật. Node:

var crypto = require('crypto'); 

var password = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; 
var input = 'hello world'; 

var encrypt = function (input, password, callback) { 
    var m = crypto.createHash('md5'); 
    m.update(password) 
    var key = m.digest('hex'); 

    m = crypto.createHash('md5'); 
    m.update(password + key) 
    var iv = m.digest('hex'); 

    var data = new Buffer(input, 'utf8').toString('binary'); 

    var cipher = crypto.createCipheriv('aes-256-cbc', key, iv.slice(0,16)); 

    // UPDATE: crypto changed in v0.10 
    // https://github.com/joyent/node/wiki/Api-changes-between-v0.8-and-v0.10 
    var nodev = process.version.match(/^v(\d+)\.(\d+)/); 
    var encrypted; 

    if(nodev[1] === '0' && parseInt(nodev[2]) < 10) { 
     encrypted = cipher.update(data, 'binary') + cipher.final('binary'); 
    } else { 
     encrypted = cipher.update(data, 'utf8', 'binary') + cipher.final('binary'); 
    } 

    var encoded = new Buffer(encrypted, 'binary').toString('base64'); 

    callback(encoded); 
}; 

var decrypt = function (input, password, callback) { 
    // Convert urlsafe base64 to normal base64 
    var input = input.replace(/\-/g, '+').replace(/_/g, '/'); 
    // Convert from base64 to binary string 
    var edata = new Buffer(input, 'base64').toString('binary') 

    // Create key from password 
    var m = crypto.createHash('md5'); 
    m.update(password) 
    var key = m.digest('hex'); 

    // Create iv from password and key 
    m = crypto.createHash('md5'); 
    m.update(password + key) 
    var iv = m.digest('hex'); 

    // Decipher encrypted data 
    var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv.slice(0,16)); 

    // UPDATE: crypto changed in v0.10 
    // https://github.com/joyent/node/wiki/Api-changes-between-v0.8-and-v0.10 
    var nodev = process.version.match(/^v(\d+)\.(\d+)/); 
    var decrypted, plaintext; 

    if(nodev[1] === '0' && parseInt(nodev[2]) < 10) { 
     decrypted = decipher.update(edata, 'binary') + decipher.final('binary');  
     plaintext = new Buffer(decrypted, 'binary').toString('utf8'); 
    } else { 
     plaintext = (decipher.update(edata, 'binary', 'utf8') + decipher.final('utf8')); 
    } 

    callback(plaintext); 
}; 

encrypt(input, password, function (encoded) { 
    console.log(encoded); 
    decrypt(encoded, password, function (output) { 
     console.log(output); 
    }); 
}); 

Python:

from Crypto.Cipher import AES 
from hashlib import md5 
import base64 


password = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 
input = 'hello world' 

BLOCK_SIZE = 16 

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

def unpad (padded): 
    pad = ord(padded[-1]) 
    return padded[:-pad] 

def _encrypt(data, nonce, password): 
    m = md5() 
    m.update(password) 
    key = m.hexdigest() 

    m = md5() 
    m.update(password + key) 
    iv = m.hexdigest() 

    data = pad(data) 

    aes = AES.new(key, AES.MODE_CBC, iv[:16]) 

    encrypted = aes.encrypt(data) 
    return base64.urlsafe_b64encode(encrypted) 

def _decrypt(edata, nonce, password): 
    edata = base64.urlsafe_b64decode(edata) 

    m = md5() 
    m.update(password) 
    key = m.hexdigest() 

    m = md5() 
    m.update(password + key) 
    iv = m.hexdigest() 

    aes = AES.new(key, AES.MODE_CBC, iv[:16]) 
    return unpad(aes.decrypt(edata)) 

output = _encrypt(input, "", password) 
print(output) 
plaintext = _decrypt(output, "", password) 
print("'" + plaintext + "'") 
+2

Có một lỗi nhỏ trong hàm giải mã Node.js của bạn. Nó sẽ không xử lý nhiều '-' hoặc nhiều'/'. Ngoài ra, trong giải mã, bạn cần phải thay thế '_' bằng'/', không phải là cách khác. Bạn chỉ có thể thay thế dòng đó bằng: 'var input = input.replace (/ \ -/g, '+'). Thay thế (/ _/g, '/'); ' – Itay

+0

Cảm ơn, tôi đã sửa nó trong câu trả lời ngay bây giờ – dave

+0

Cảm ơn bạn rất nhiều cho các ví dụ. Tôi đã nhận được lỗi "độ dài khối cuối cùng sai" với đầu vào phức tạp và tôi đã tìm thấy bản cập nhật được mô tả trong [bài đăng SO này] (http://stackoverflow.com/questions/21292142/decyrpting-aes256-with-node-js- return-wrong-final-block-length # 21292538) đã giải quyết được vấn đề của tôi. Tôi đã áp dụng các thay đổi ở trên. –

Các vấn đề liên quan