2011-08-25 21 views
8

Chcę zaszyfrować niektóre dane w aplikacji Ruby, a następnie odszyfrować je w aplikacji nodejs. Próbowałem uruchomić to i teraz próbuję zaszyfrować te same dane w obu językach, aby uzyskać ten sam wynik, ale nie mogę tego zrobić.Szyfrowanie danych za pomocą odszyfrowania ruby ​​za pomocą węzła

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

Wygląda na to, że otrzymałem ciąg szesnastkowy z kodowania.

#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 # 皋?;?? 

Czy jest jakiś problem z kodowaniem, którego mi brakuje. Próbowałem dekodowania base64, ale to nie dało takiego samego wyniku, jak aplikacja węzła. Jakieś wskazówki?

AKTUALIZACJA: To jest tak blisko, jak przyjaciel i mogę uzyskać: https://gist.github.com/a880ea13d3b65a21a99d. Sheesh, chcę tylko zaszyfrować coś w ruby ​​i odszyfrować go w węźle.

Update2: Dobra, kod w tej kwestii staje mi wiele okazji tam: https://github.com/joyent/node/issues/1395

+0

I w Ruby pozornie 1.8.7 wyjść \ 347 \ 232 \ 213 \ 006 \ 250; \ 207 \ 302 podczas gdy 1.9.2 wyprowadza \ xE7 \ x9A \ x8B \ x06 \ xA8; \ x87 \ xC2 –

Odpowiedz

0

OK. Chcę podziękować wszystkim za pomoc. Zasadniczo ten wątek odpowiada na moje pytanie: https://github.com/joyent/node/issues/1395. Zamierzam opublikować dwa programy na wypadek, gdyby ktoś musiał przejść przez ten rigamarole. Pamiętaj, że to nie oznacza, że ​​jesteś hardcorowo bezpieczny, jest to odskocznia do szyfrowania danych przez ruby ​​i odszyfrowania go przez węzeł. Będziesz musiał podjąć więcej kroków, aby upewnić się, że zostały podjęte wyższe środki bezpieczeństwa.

Kod znajduje się w tym GIST: https://gist.github.com/799d6021890f34734470

Zostały one działać na ruby ​​1.9.2p290 i węzła 0.4.10

+0

Powinieneś wywołać #encrypt lub #decrypt na twoim Szyfrowaniu jako pierwszą operację - patrz [tutaj] (http://www.ruby-doc.org /ruby-1.9/classes/OpenSSL/Cipher.html#M006486). – emboss

+0

Myślę, że robię to z wysyłaniem (tryb) na linii 10 encrypt.rb, chyba że nie rozumiem, co mówisz correclty –

+0

Ups, moje złe, masz rację! Więc zapomnij mój komentarz :) – emboss

0

Twoje zaszyfrowane dane będą pewne losowe szukający bajtów. Te bajty mogą być wyrażone jako hex, Base64 lub w inny sposób. Wygląda na to, że twój kod ruby ​​wysyła surowe bajty. Proponuję przekonwertować te surowe bajty na heks, aby dokonać porównania.

Patrząc na swój kod, powinieneś również zmienić Blowfish ("bf") na AES. Blowfish ma 64-bitowy rozmiar bloku i jest już przestarzały.

Można by zrobić dobrze, aby wyraźnie określić wyściółkę, PKCS7 jest powszechne

+0

To jest pakiet e.unpack ("H *"), ale oczywiście wartości z szyfrowania węzła i ruby szyfrowanie nie jest równe –

+0

Jeśli nadal nie pasuje, to sprawdź, które padding używa każda wersja. Lepiej to sprecyzować, jak już powiedziałem. – rossum

4

Istnieje kilka subtelnych rzeczy, które sprawiają, że to zawiedzie. Najważniejszy - nie określasz IV w kodzie, więc losowa wartość zostanie wygenerowana dla ciebie. Zauważylibyście, że w ten sposób nie można nawet odszyfrować swojego zaszyfrowanego tekstu w tym samym języku programowania.

Musisz więc podać jednoznacznie IV dla obu implementacji. Ale zanim pokażę Ci kod, kilka rad:

Key generacja:

Blowfish działa na 64 bitowych bloków, jego rozmiar klucza różna, ale OpenSSL (który obecnie uprawnienia zarówno szyfr Ruby i node.js' implementacja) domyślnie używa 128 bitów, czyli 16 bajtów.

Twój klucz narusza dwie zasady - pierwszą: po prostu jest za długa. Jest to szesnastkowa reprezentacja skrótu SHA-1, która wynosi 20 bajtów * 2 = 40 bajtów zamiast 16. W większości przypadków jest to w porządku, ponieważ implementacja obcina odpowiednio wartości, ale to jest coś, co powinno być , a nie zależne. na.

Drugi błąd, znacznie surowszy, polega na tym, że zamiast surowych bajtów używa się reprezentacji w postaci heksadecymalnej: duży problem bezpieczeństwa! Znaki szesnastkowe nie są wcale losowe, więc w efekcie redukujesz entropię danych wejściowych do połowy długości (ponieważ bazowe bajty były losowe).

bezpieczny sposób do generowania kluczy losowych używa OpenSSL :: Losowa

key = OpenSSL::Random.random_bytes(cipher_key_len) 

Trzeci błąd jest, aby zachować swój klucz zakodowany w źródłach. To zły pomysł. Należy przynajmniej przechowywać go w innym miejscu w systemie plików, gdzie dostęp jest ściśle ograniczony. Zobacz także my answer na kolejne pytanie.Klucz powinien być przechowywany poza pasmem i ładowany dynamicznie w aplikacji.

Cipher:

Blowfish starzeje. Nadal jest uważany za nieprzerwany w tym sensie, że brutalne wymuszanie go jest jedynym sposobem na jego złamanie. Ale przestrzeń wyszukiwania o rozmiarze 2^64 nie jest poza zasięgiem zaradnych atakujących. Powinieneś więc przejść do AES.

Dopełnienie:

klocki OpenSSL wykorzystujące PKCS5Padding (znany również jako PKCS7Padding) domyślnie. Ruby czerpie z tego zyski, a mój zakład, node.js, również to wykorzystuje - więc powinieneś być na to bezpieczny.

Teraz do rozwiązania roboczego. Musimy wygenerować IV, Blowfish wymaga 64-bitowego - 8 bajtów. Będziesz potrzebował rbytes, aby uzyskać bezpieczne liczby losowe w węźle. IV może być zakodowana na stałe w twoich źródłach (to informacja publiczna, bez wpływu na bezpieczeństwo) - ale musi być taka sama po obu stronach. Powinieneś wstępnie wygenerować wartość i użyć jej zarówno dla node.js, jak i 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'); 

Teraz części 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

Ogólnie dobra rada. Sugerowałbym jednak, że szyfrowanie generuje IV i dodaje IV do zaszyfrowanego tekstu, tak że wynik wygląda jak "# {iv-raw-bytes} # {ciphertext-raw-bytes}" '. Odszyfrowanie powinno znać rozmiar IV i wziąć pierwszy blok danych wejściowych o tej wielkości jako IV, a reszta to szyfrogram. W ten sposób IV jest losowy na każdym szyfrowaniu, zgodnie z przeznaczeniem. Zauważ, że IV jest * nie * tajemnicą, gdy każda zaszyfrowana wiadomość ma swoją własną IV, więc bezpieczne jest dzielenie się IV dla pojedynczej wiadomości dla publiczności. Jedynym sekretem w tym kontekście jest klucz. – yfeldblum

+0

To dobry sposób na zrobienie tego, Sprawiedliwość. Ale jest to jeszcze bardziej skomplikowane, więc zaczynam wyjaśniać to w ten sposób. – emboss

Powiązane problemy