2011-08-25 22 views
8

Voglio crittografare alcuni dati in un'app ruby ​​e quindi decodificarli in un'app di nodejs. Ho cercato di farlo funzionare e ora sto solo cercando di crittografare lo stesso pezzo di dati in entrambe le lingue per ottenere lo stesso risultato ma non riesco a farlo.Crittografia dei dati con Ruby Decrittografia con nodo

//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 

Quindi sembra che ottenga una stringa esadecimale dalla codifica.

#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'è qualche tipo di problema di codifica che mi manca. Ho provato a decodificare base64 ma questo non ha prodotto lo stesso risultato dell'app nodo. Qualche indicazione?

AGGIORNAMENTO: Quindi questo è il più vicino di un amico e posso ottenere: https://gist.github.com/a880ea13d3b65a21a99d. Sheesh, voglio solo crittografare qualcosa in ruby ​​e decodificarlo nel nodo.

UPDATE2: Va bene, il codice in questo numero mi fa un sacco di strada lì: https://github.com/joyent/node/issues/1395

+0

E in rubino apparentemente 1.8.7 uscite \ 347 \ 232 \ 213 \ 006 \ 250; \ 207 \ 302 mentre 1.9.2 output \ xE7 \ x9A \ x8B \ x06 \ xA8; \ x87 \ xC2 –

risposta

0

OK. Voglio ringraziare tutti per avermi aiutato. Fondamentalmente questo thread qui risponde alla mia domanda: https://github.com/joyent/node/issues/1395. Ho intenzione di andare avanti e pubblicare i due programmi nel caso in cui qualcun altro debba passare attraverso questa rigamarole. Tieni presente che questo non significa essere sicuri per l'hardcore, questo è un trampolino di lancio per la crittografia dei dati rubati e il nodo che la decifra. Dovrai prendere ulteriori provvedimenti per assicurarti che vengano adottate misure di sicurezza più elevate.

Il codice si trova in questo gist: https://gist.github.com/799d6021890f34734470

Questi sono stati eseguiti su rubino 1.9.2p290 e il nodo 0.4.10

+0

Dovresti chiamare #encrypt o #decrypt sul tuo Cipher come prima operazione - vedi [qui] (http://www.ruby-doc.org) /ruby-1.9/classes/OpenSSL/Cipher.html#M006486). – emboss

+0

Penso di farlo con send (mode) sulla riga 10 di encrypt.rb a meno che non capisco cosa stai dicendo corretti –

+0

Oops, mio ​​male, hai ragione! Quindi dimentica il mio commento :) – emboss

0

tuo testo cifrato saranno alcuni byte in cerca casuali. Questi byte possono essere espressi come hex, Base64 o in altri modi. Sembra che il tuo codice rubino stia emettendo i byte grezzi. Suggerisco di convertire quei byte non elaborati in esadecimale per effettuare il confronto.

Guardando il tuo codice, dovresti anche passare da Blowfish ("bf") ad AES. Blowfish ha una dimensione di blocco di 64 bit ed è ora obsoleto.

Si farebbe bene a specificare esplicitamente imbottitura, PKCS7 è comune

+0

È e.unpack ('H *') ma naturalmente i valori dalla crittografia del nodo e dal rubino la crittografia non è uguale a –

+0

Se il problema persiste, controlla il livello di riempimento di ciascuna versione. Meglio specificarlo esplicitamente, come ho detto. – rossum

4

Ci sono diverse cose sottili che rendono questo sicuro. La più importante: non stai specificando una IV nel tuo codice, quindi verrà generato un valore casuale per te. Si noterà che non è possibile decodificare il testo cifrato nello stesso linguaggio di programmazione in questo modo.

Quindi è necessario fornire un IV esplicito per entrambe le implementazioni. Ma prima vi mostro il codice, un consiglio:

generazione chiave:

Blowfish opera su blocchi di 64 bit, la sua dimensione chiave varia, ma OpenSSL (che attualmente poteri sia cifrario node.js di Ruby e implementazione) utilizza 128 bit per impostazione predefinita, ovvero 16 byte.

Quindi la tua chiave viola due principi: il primo: è semplicemente troppo lungo. È la rappresentazione esadecimale di un hash SHA-1, che è 20 byte * 2 = 40 byte invece di 16. La maggior parte delle volte va bene, perché l'implementazione tronca i valori in modo appropriato, ma è qualcosa che dovresti non dipendere sopra.

Il secondo errore, molto più grave, è che si utilizza la rappresentazione esadecimale anziché i byte non elaborati: grande problema di sicurezza! I caratteri esadecimali non sono affatto casuali, quindi in effetti riducete l'entropia del vostro input a metà della lunghezza (perché i byte sottostanti erano casuali).

Un modo sicuro per generare chiavi casuali sta usando OpenSSL :: caso

key = OpenSSL::Random.random_bytes(cipher_key_len) 

Un terzo errore è quello di mantenere la vostra chiave hard-coded nelle fonti. È una cattiva idea Il minimo da fare è archiviarlo altrove nel file system, dove l'accesso è strettamente limitato. Vedi anche my answer per un'altra domanda.La chiave deve essere archiviata fuori banda e caricata solo dinamicamente all'interno dell'applicazione.

Cipher:

Blowfish invecchia. È ancora considerato ininterrotto nel senso che forzare brutalmente è l'unico modo per romperlo. Ma uno spazio di ricerca di 2^64 non è irraggiungibile per gli aggressori intraprendenti. Quindi dovresti davvero passare ad AES.

Padding:

pastiglie OpenSSL utilizzando PKCS5Padding (noto anche come PKCS7Padding) di default. Ruby beneficia di questo e la mia scommessa è che node.js utilizza anche questo - quindi dovresti essere al sicuro su questo.

Ora alla soluzione di lavoro. Abbiamo bisogno di generare un IV, Blowfish richiede che sia 64 bit - 8 byte. Avrai bisogno di rbytes per ottenere numeri casuali sicuri nel nodo. L'IV può essere hardcoded nelle tue fonti (è informazione pubblica, nessun impatto sulla sicurezza) - ma deve essere lo stesso su entrambi i lati. Dovresti pregenerare un valore e usarlo sia per node.js che per 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'); 

Ora la parte di 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

Generalmente un buon consiglio. Suggerirei, tuttavia, che la crittografia genera un IV e antepone la IV al testo cifrato, in modo che l'output assomigli a "# {iv-raw-bytes} # {ciphertext-raw-bytes}" '. La decrittografia dovrebbe conoscere la dimensione della IV e prendere il primo blocco dell'input di quella dimensione come IV, mentre il resto è cifrato. In questo modo l'IV è casuale su ogni crittografia, come previsto. Si noti che IV non * è * un segreto quando ogni messaggio crittografato ha il proprio IV, quindi è sicuro condividere l'IV per un singolo messaggio al pubblico. L'unico segreto, in questo contesto, è la chiave. – yfeldblum

+0

Questo è un buon modo per farlo, giustizia. Ma è ancora più complicato, quindi tendo a spiegarlo in questo modo .. – emboss

Problemi correlati