2011-08-25 76 views
8

Tôi muốn mã hóa một số dữ liệu trong ứng dụng ruby ​​và sau đó giải mã dữ liệu đó trong ứng dụng nodejs. Tôi đã cố gắng để có được điều này để làm việc và bây giờ tôi chỉ cố gắng để mã hóa cùng một mảnh dữ liệu trong cả hai ngôn ngữ để có được kết quả tương tự nhưng tôi dường như không thể làm điều đó.Mã hóa dữ liệu bằng giải mã ruby ​​bằng nút

//js 
var crypto = require('crypto'); 

var key = crypto.createHash('sha1').update('key').digest('hex'); 
console.log(key); // a62f2225bf70bfaccbc7f1ef2a397836717377de 

var encrypted = ""; 
var cipher = crypto.createCipher('bf-cbc', key); 

encrypted += cipher.update('text'); 
encrypted += cipher.final('hex'); 

console.log(encrypted); //outputs 4eafd5542875bd3c 

Vì vậy, có vẻ như tôi nhận được chuỗi thập lục phân từ mã hóa.

#ruby 
require 'openssl' 
require 'digest/sha1' 
c = OpenSSL::Cipher::Cipher.new("bf-cbc") 
c.encrypt 
# your pass is what is used to encrypt/decrypt 
c.key = key = Digest::SHA1.hexdigest("key") 
p key # a62f2225bf70bfaccbc7f1ef2a397836717377de 
e = c.update("text") 
e << c.final 
p e # 皋?;?? 

Có một số vấn đề về mã hóa mà tôi đang thiếu. Tôi đã cố gắng giải mã base64 nhưng không tạo ra kết quả tương tự như ứng dụng nút. Bất kỳ con trỏ?

CẬP NHẬT: Vì vậy, điều này gần với một người bạn và tôi có thể nhận được: https://gist.github.com/a880ea13d3b65a21a99d. Sheesh, tôi chỉ muốn mã hóa một cái gì đó trong ruby ​​và giải mã nó trong nút.

UPDATE2: Alright, mã trong vấn đề này được tôi rất nhiều con đường đó: https://github.com/joyent/node/issues/1395

+0

Và trong ruby ​​dường 1.8.7 kết quả đầu ra \ 347 \ 232 \ 213 \ 006 \ 250; \ 207 \ 302 trong khi 1,9,2 kết quả đầu ra \ xE7 \ x9A \ x8B \ x06 \ xA8; \ x87 \ xC2 –

Trả lời

0

OK. Tôi muốn cảm ơn tất cả mọi người đã giúp tôi. Về cơ bản, chuỗi này trả lời câu hỏi của tôi: https://github.com/joyent/node/issues/1395. Tôi sẽ đi trước và đăng hai chương trình trong trường hợp bất cứ ai khác phải đi qua rigamarole này. Hãy ghi nhớ điều này không có nghĩa là được bảo mật hardcore, đây là một bước đệm cho mã hóa ruby ​​dữ liệu và nút giải mã nó. Bạn sẽ phải thực hiện thêm các bước để đảm bảo các biện pháp bảo mật cao hơn được thực hiện.

Mã này tọa lạc tại ý chính sau: https://gist.github.com/799d6021890f34734470

Chúng được chạy trên ruby ​​1.9.2p290 và nút 0.4.10

+0

Bạn nên gọi #encrypt hoặC#decrypt trên Mật mã của bạn là hoạt động đầu tiên - xem [tại đây] (http://www.ruby-doc.org /ruby-1.9/classes/OpenSSL/Cipher.html#M006486). – emboss

+0

Tôi nghĩ rằng tôi đang làm điều đó với gửi (chế độ) trên dòng 10 của mã hóa.rb trừ khi tôi không hiểu những gì bạn đang nói correclty –

+0

Rất tiếc, xấu của tôi, bạn nói đúng! Sau đó, quên bình luận của tôi :) – emboss

0

cyphertext của bạn sẽ có một số byte tìm kiếm ngẫu nhiên. Các byte đó có thể được biểu diễn dưới dạng hex, Base64 hoặc theo các cách khác. Có vẻ như mã ruby ​​của bạn xuất ra các byte thô. Tôi đề nghị bạn chuyển đổi các byte thô thành hex để so sánh.

Nhìn vào mã của bạn, bạn cũng nên thay đổi từ Blowfish ("bf") thành AES. Blowfish có kích thước khối 64 bit và bây giờ đã lỗi thời.

Bạn sẽ làm tốt để chỉ định rõ ràng đệm, PKCS7 là phổ biến

+0

Nó là e.unpack ('H *') nhưng tất nhiên các giá trị từ mã hóa nút và ruby mã hóa không bằng –

+0

Nếu vẫn không khớp thì hãy kiểm tra phần đệm mà mỗi phiên bản đang sử dụng. Tốt hơn là chỉ định nó một cách rõ ràng, như tôi đã nói. – rossum

4

Có một số điều tinh tế làm cho điều này không thành công. Điều quan trọng nhất - bạn không chỉ định một IV trong mã của bạn, do đó, một giá trị ngẫu nhiên sẽ được tạo ra cho bạn. Bạn sẽ nhận thấy rằng bạn thậm chí không thể giải mã ciphertext của bạn trong cùng một ngôn ngữ lập trình theo cách này.

Vì vậy, bạn cần cung cấp IV rõ ràng cho cả hai triển khai. Nhưng trước khi tôi cho bạn thấy mã, một số lời khuyên:

hệ chính:

Blowfish hoạt động trên các khối 64 bit, kích thước quan trọng của nó thay đổi, nhưng OpenSSL (hiện quyền hạn cả mật mã Ruby và Node.js' triển khai) sử dụng 128 bit theo mặc định, đó là 16 byte.

Vì vậy, khóa của bạn vi phạm hai nguyên tắc - đầu tiên: quá dài. Đó là biểu diễn hex của hàm băm SHA-1, là 20 byte * 2 = 40 byte thay vì 16. Phần lớn thời gian này là tốt, bởi vì việc triển khai cắt bớt các giá trị một cách thích hợp, nhưng đó là điều bạn nên không phụ thuộc trên.

Lỗi thứ hai, nghiêm trọng hơn nhiều, là bạn sử dụng biểu diễn hex thay vì byte thô: vấn đề bảo mật lớn! Ký tự hex không phải là ngẫu nhiên chút nào, do đó, trong thực tế bạn giảm entropy của đầu vào của bạn xuống một nửa chiều dài (vì các byte cơ bản là ngẫu nhiên).

Một cách an toàn để tạo ra các phím ngẫu nhiên được sử dụng OpenSSL :: Random

key = OpenSSL::Random.random_bytes(cipher_key_len) 

Một sai lầm thứ ba là để giữ chìa khóa của bạn mã hóa cứng trong nguồn. Đó là một ý tưởng tồi. Ít nhất bạn nên làm là lưu trữ nó ở nơi khác trên hệ thống tập tin, nơi truy cập bị hạn chế chặt chẽ. Xem thêm my answer cho một câu hỏi khác.Khóa phải được lưu trữ ngoài băng và chỉ được tải động trong ứng dụng.

Cipher:

Blowfish già đi. Nó vẫn được coi là không gián đoạn trong ý nghĩa rằng brute-buộc nó là cách duy nhất để phá vỡ nó. Nhưng không gian tìm kiếm của 2^64 không nằm ngoài tầm với của những kẻ tấn công tài nguyên. Vì vậy, bạn thực sự nên chuyển sang AES.

Padding:

miếng đệm OpenSSL sử dụng PKCS5Padding (còn gọi là PKCS7Padding) theo mặc định. Ruby lợi nhuận từ điều này và đặt cược của tôi là node.js sử dụng này, quá - vì vậy bạn nên được an toàn về điều này.

Bây giờ đến giải pháp làm việc. Chúng ta cần tạo ra một IV, Blowfish yêu cầu nó phải là 64 bit - 8 byte. Bạn sẽ cần rbyte để có được số ngẫu nhiên an toàn trong nút. IV có thể được mã hóa cứng trong nguồn của bạn (thông tin công khai, không có tác động bảo mật) - nhưng nó phải giống nhau ở cả hai bên. Bạn nên pregenerate một giá trị và sử dụng nó cho cả hai node.js và Ruby.

/*node.js*/ 

var rbytes = require('rbytes'); 
var iv = rbytes.randomBytes(8); 

/*see advice above - this should be out-of-band*/ 
var key = rbytes.randomBytes(16); 
var encrypted = ""; 
var cipher = crypto.createCipheriv('bf-cbc', key, iv); 

encrypted += cipher.update('text'); 
encrypted += cipher.final('hex'); 

Bây giờ là phần Ruby:

require 'openssl' 

c = OpenSSL::Cipher::Cipher.new("bf-cbc") 
c.encrypt 
# should be out-of-band again 
c.key = OpenSSL::Random.random_bytes(16) 
# may be public but has to be the same for Ruby and node 
iv = OpenSSL::Random.random_bytes(8) 
c.iv = iv 
e = c.update("text") 
e << c.final 
puts e.unpack('H*')[0] 
+0

Nói chung là lời khuyên tốt. Tuy nhiên, tôi sẽ đề nghị rằng việc mã hóa tạo ra một IV và thêm IV vào bản mã, do đó đầu ra trông giống như "# {iv-raw-bytes} # {ciphertext-raw-bytes}" '. Giải mã phải biết kích thước của IV và lấy khối đầu tiên của đầu vào có kích thước đó là IV với phần còn lại là bản mã. Bằng cách đó IV là ngẫu nhiên trên mỗi mã hóa, như dự định. Lưu ý rằng IV là * không * một bí mật khi mỗi thông điệp được mã hóa có IV riêng của nó, vì vậy an toàn để chia sẻ IV cho một thông điệp duy nhất cho công chúng. Bí mật duy nhất, trong bối cảnh này, là chìa khóa. – yfeldblum

+0

Đó là một cách hay để làm điều đó, Công lý. Nhưng nó thậm chí còn phức tạp hơn, vì vậy tôi có xu hướng bắt đầu giải thích nó theo cách này .. – emboss

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