Skryptowy kombajn kryptograficzny – kryptosystem z błyskawicznym czasem realizacji

cryptologist_resizeW celu zabezpieczenia danych przesyłanych przez sieć, trzeba dostarczyć im choćby minimum ochrony środkami i metodami rodem z kryptografii. Poufność osiągamy rzecz jasna szyfrowaniem, zaś wykrywalność wszelkiego rodzaju przypadków dezintegracji danych, czyli nieuprawnionych zmian ich treści, gwarantuje nam weryfikacja kryptograficznych sum kontrolnych przez strony bezpiecznej wymiany danych. Jedną i drugą funkcjonalność daje się technicznie osiągnąć różnymi metodami. Na przykład szyfrować można symetrycznie lub asymetrycznie, zaś kontrolę integralności zdolne są zapewnić nam na przykład choćby kody HMAC, zaszyfrowane skróty (hasze) komunikatu lub po prostu podpis elektroniczny. Na cokolwiek się zdecydujemy, mając do dyspozycji język skryptowy, taki jak chociażby Ruby, choć może być też Python, Perl czy Tcl, jesteśmy w stanie niemal błyskawicznie opracować potężne, w pełni użyteczne narzędzia. Ich zaletą będzie przede wszystkim niezależność od systemu operacyjnego i pełna przenośność kodu. Identyczny kod będzie poprawnie działał na Windows, Linux, Solaris, AIX, HP-UX czy MacOS. Moc tego rodzaju narzędzi tkwi ponadto w możliwości ich dalszego rozwoju i – co za tym idzie – łatwej implementacji dodatkowych funkcji, i to dokładnie takich, jakich potrzebujemy. Wreszcie, narzędzia te są dostęne kompletnie za darmo – kosztują tylko nieco czasu i wysiłku niezbędnego do ich opracowania (zazwyczaj mniej niż się nam wydaje :-)). To jedyny koszt.

Dokładnie tego rodzaju narzędziem jest skrypt, stanowiący kanwę dla tego artykułu. Skrypt oferuje do dyspozycji użytkownika bardzo silny kryptosystem, a w nim funkcje enkrypcji i dekrypcji symetrycznej z użyciem niemal wszelkich dostępnych algorytmów, najważniejsze funkcje skrótu oraz kryptograficzne sumy kontrolne HMAC (Hashing Message Authentication Codes).

Szyfrowanie/deszyfrowanie zaimplementowane w skrypcie oparte jest o standard PKCS#5. Jest to szyfrowanie bazujące na hasłach, na podstawie których wyliczane są właściwe klucze kryptograficzne. Dlaczego wybrałem PKCS#5, zamiast szyfrowania opartego bezpośrednio na kluczach? Odpowiedź jest prosta – bo bezpieczne przekazanie hasła, oddzielnym kanałem, osobie uczestniczącej w wymianie szyfrowanych informacji jest mimo wszystko prostsze niż dostarczenie jej klucza.

Skrypt został wyposażony w graficzny interfejs użytkownika oparty na bibliotece GTK2. Poszczególne elementy kryptosystemu dostępne są z poziomu GUI w ramach jego czterech zakładek: (1) szyfrowanie, (2) deszyfrowanie, (3) haszowanie, (4) wyliczanie HMAC.

Skrypt działa na wyróżnionym (zaznaczonym kursorem) bloku tekstu w oknie wejścia/wyjścia lub, jeśli nie dojdzie do takowego zaznaczenia, to na całość tekstu w oknie.

Możliwe jest wykonanie szeregu operacji na tym samym lub na różnych blokach tekstu. Każda kolejna z nich powoduje w rezultacie dopisanie wyników na koniec tekstu w oknie wejścia/wyjścia. Okno to jest oczywiście w pełni przewijalne (w pionie i w poziomie) oraz obsługuje wszystkie operacje kopiowania i wklejania tekstu z zewnątrz lub pomiędzy zakładkami.

Łatwe jest na przykład przeprowadzenie wielokrotnego szyfrowania tego samego bloku tekstu, różnymi algorytmami enkrypcji w poszczególnych rundach procesu.

Zakładka „Encrypion” prezentuje się następująco:

crypto_tool-01

Proszę zwrócić uwagę na dostępność wszystkich oferowanych przez bibliotekę OpenSSL algorytmów kryptografii symetrycznej i ich odmian. Jest ich naprawdę sporo i powinny zaspokoić potrzeby najbardziej wymagających użytkowników. Wybór najbardziej nam pasującego z tej długiej listy, możliwy jest z poziomu rozwijanego menu typu combo-box.

Zakładka „Decryption”:

crypto_tool-02

Zakładka „Hashing”:

crypto_tool-03

Zakładka „HMAC”:

crypto_tool-04

Wynik działania skryptu można zapisać do pliku, co znakomicie ułatwia pracę.

A oto pełny kod źródłowy skryptu:

require 'gtk2'
require 'openssl'
require 'Base64'
require 'digest'

def message(parent, title, msg_text)
   dialog = Gtk::MessageDialog.new(
      parent,
      Gtk::Dialog::MODAL,
      Gtk::MessageDialog::INFO,
      Gtk::MessageDialog::BUTTONS_OK,
      msg_text
   )
   dialog.title = title
   dialog.run
   dialog.destroy
end

def get_ciphers()
   return ciphers = OpenSSL::Cipher.ciphers
end

def encrypt(alg, key, salt, string)
   begin
      encrypter = OpenSSL::Cipher.new alg
      encrypter.encrypt
      encrypter.pkcs5_keyivgen key, salt
      encrypted = encrypter.update string
      encrypted << encrypter.final       
      return Base64.encode64(encrypted)    
   rescue => e
      message($window, "Alert", "Problem in encrypt() function: #{e}")
      return ""
   end
end

def decrypt(alg, key, salt, string)
   begin
      decrypter = OpenSSL::Cipher.new alg
      decrypter.decrypt
      decrypter.pkcs5_keyivgen key, salt
      plain = decrypter.update Base64.decode64(string)
      plain << decrypter.final       
      return plain    
   rescue => e
      message($window, "Alert", "Problem in decrypt() function: #{e}")
      return ""
   end
end

def hashing(algorithm, text_to_hash)
   hashed_data = ""
   case algorithm
      when 'MD5'
         hashed_data = Digest::MD5.hexdigest(text_to_hash)
      when 'SHA-1'
         hashed_data = Digest::SHA1.hexdigest(text_to_hash)
      when 'SHA-2'
         hashed_data = Digest::SHA256.hexdigest(text_to_hash)
      when 'RMD'
         hashed_data = Digest::RMD160.hexdigest(text_to_hash)
      else
         message($window, "Alert", "Hashing function not supported")
         exit
   end
   return hashed_data
end

def hmac_calculate(algorithm, key, text_to_hash)
   hmac_data = ""
   case algorithm
      when 'MD5'
         hmac_data = Digest::HMAC.hexdigest(text_to_hash, key, Digest::MD5)    
      when 'SHA-1'
         hmac_data = Digest::HMAC.hexdigest(text_to_hash, key, Digest::SHA1)
      when 'SHA-256'
         hmac_data = Digest::HMAC.hexdigest(text_to_hash, key, Digest::SHA256)
      when 'RIPEMD-160'
         hmac_data = Digest::HMAC.hexdigest(text_to_hash, key, Digest::RMD160)
      else
         message($window, "Alert", "HMAC function not supported")
         exit
   end
   return hmac_data
end

def retrieve_text(tw)
   start_iter, end_iter, selected  = tw.buffer.selection_bounds
   if !selected
      start_iter, end_iter = tw.buffer.bounds
   end
   text = tw.buffer.get_text(start_iter, end_iter)
   return text
end

def filename(parent)
   fnm = ""
   dialog = Gtk::FileChooserDialog.new(
      "Save File As ...",
      parent,
      Gtk::FileChooser::ACTION_SAVE,
      nil,
      [ Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL ],
      [ Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT ]
   )
   dialog.signal_connect('response') do |w, r|
      case r
         when Gtk::Dialog::RESPONSE_ACCEPT
            fnm = dialog.filename
         when Gtk::Dialog::RESPONSE_CANCEL
            fnm = ""
         else 
            message($window, "Undefined response ID; perhaps Close-x? (#{r})")
      end
      dialog.destroy 
   end
   dialog.run
   return fnm
end

def save_as(file_to_save, text_to_save)
   status = nil
   begin
      file = File.open(file_to_save, "w")
      file.write(text_to_save)
      status = 1
   rescue IOError => e
      message($window, "Error: #{e}")
      status = nil
   ensure
      file.close unless file == nil
   end
   return status
end

$window = Gtk::Window.new(Gtk::Window::TOPLEVEL)
$window.set_title  "Crypto operations - Janusz Nawrat (2014)"
$window.border_width = 10
$window.set_size_request(500, -1)

$window.signal_connect('delete_event') { false }
$window.signal_connect('destroy') { Gtk.main_quit }
$window.signal_connect('delete_event') { Gtk.main_quit }

main_nb = Gtk::Notebook.new
encr_label = Gtk::Label.new("Encryption")
decr_label = Gtk::Label.new("Decryption")
hash_label = Gtk::Label.new("Hashing")
hmac_label = Gtk::Label.new("HMAC")

encr_box = Gtk::VBox.new()
decr_box = Gtk::VBox.new()
hash_box = Gtk::VBox.new()
hmac_box = Gtk::VBox.new()

# ------------------------ Encryption page -------------------------
encr_crypto_box = Gtk::HBox.new(true, 3)

encr_cipher_box = Gtk::HBox.new()
encr_cipher_box.border_width = 5

encr_cipher_frame = Gtk::Frame.new(" Cipher ")
encr_key_box = Gtk::HBox.new()
encr_key_box.border_width = 5

encr_key_frame = Gtk::Frame.new(" Crypto key ")
encr_cipher_frame.add(encr_cipher_box)
encr_key_frame.add(encr_key_box)
encr_crypto_box.pack_start(encr_cipher_frame, true, true, 2)
encr_crypto_box.pack_start(encr_key_frame, true, true, 2)

encr_salt_box = Gtk::HBox.new()
encr_salt_frame = Gtk::Frame.new(" Salt ")
encr_salt_frame.add(encr_salt_box)

encr_crypto_box.pack_start(encr_salt_frame, false, true, 2)

encr_cipher_combo = Gtk::ComboBox.new()
encr_cipher_box.pack_start(encr_cipher_combo, true, true, 5)

encr_alg = get_ciphers

encr_alg.each do |cipher|
   encr_cipher_combo.append_text cipher 
end

encr_cipher_combo.active = 0

encr_cipher_combo.signal_connect "changed" do
   encr_crypto_alg = encr_alg[encr_cipher_combo.active]
end

encr_key_entry = Gtk::Entry.new()
encr_key_entry.text = '$3cYouR3#'

encr_salt_entry = Gtk::Entry.new()
encr_salt_entry.text = "$@ltsaLT"
encr_salt_box.pack_start(encr_salt_entry, true, true, 2)

encr_key_box.pack_start(encr_key_entry, true, true, 2)

encr_inout_frame = Gtk::Frame.new(" INPUT/OUTPUT ")
encr_inout_textview = Gtk::TextView.new()
encr_inout_textview.set_size_request(-1, 300)
encr_inout_textview.border_width = 5
encr_inout_scrolled = Gtk::ScrolledWindow.new()
encr_inout_scrolled.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS)
encr_inout_scrolled.add(encr_inout_textview)
encr_inout_frame.add(encr_inout_scrolled)

font = Pango::FontDescription.new("Courier New 9")
encr_inout_textview.modify_font(font)

encr_box.pack_start(encr_crypto_box, true, true, 3)

encr_box.pack_start(encr_inout_frame, true, true, 5)

separator = Gtk::HSeparator.new

encr_box.pack_start(separator, false, false, 1)

encr_control_box = Gtk::HBox.new(true, 5)

encr_box.pack_start(encr_control_box, true, false, 5)

encr_exec_button = Gtk::Button.new("Encrypt")
encr_exec_button.signal_connect("clicked") do
   key = encr_key_entry.text
   salt = encr_salt_entry.text
   string = retrieve_text(encr_inout_textview)
   encr_inout_textview.buffer.text += "\n" + " Ciphertext Block: #{encr_alg[encr_cipher_combo.active]} ".center(60, '-') + "\n"
   encr_inout_textview.buffer.text += encrypt(encr_alg[encr_cipher_combo.active], key, salt, string)
   encr_inout_textview.buffer.text += "  End of cipher block  ".center(60, '-')
end

encr_clear_button = Gtk::Button.new("Clear")
encr_clear_button.signal_connect("clicked") do
   encr_inout_textview.buffer.text = ""
end

encr_save_button = Gtk::Button.new("Save to file")
encr_save_button.signal_connect("clicked") do
   filnm = filename($window)
   if (filnm.empty? == false) and (save_as(filnm, encr_inout_textview.buffer.text))
      message($window, "Results of operation", "Saved to file: #{filnm}")
   else
      message($window, "Results of operation", "Something went wrong with saving to file: #{filnm}")
   end
end

encr_exit_button = Gtk::Button.new("Exit")
encr_exit_button.signal_connect("clicked") do
   Gtk.main_quit
end

encr_control_box.pack_start(encr_exec_button, true, true, 2)
encr_control_box.pack_start(encr_clear_button, true, true, 2)
encr_control_box.pack_start(encr_save_button, true, true, 2)
encr_control_box.pack_start(encr_exit_button, true, true, 2)

# ------------------------ Decryption page -------------------------
decr_crypto_box = Gtk::HBox.new(true, 3)

decr_cipher_box = Gtk::HBox.new()
decr_cipher_box.border_width = 5

decr_cipher_frame = Gtk::Frame.new(" Cipher ")
decr_key_box = Gtk::HBox.new()
decr_key_box.border_width = 5

decr_key_frame = Gtk::Frame.new(" Crypto key ")
decr_cipher_frame.add(decr_cipher_box)
decr_key_frame.add(decr_key_box)
decr_crypto_box.pack_start(decr_cipher_frame, true, true, 2)
decr_crypto_box.pack_start(decr_key_frame, true, true, 2)

decr_salt_box = Gtk::HBox.new()
decr_salt_frame = Gtk::Frame.new(" Salt ")
decr_salt_frame.add(decr_salt_box)

decr_crypto_box.pack_start(decr_salt_frame, false, true, 2)

decr_cipher_combo = Gtk::ComboBox.new()
decr_cipher_box.pack_start(decr_cipher_combo, true, true, 5)

decr_alg = get_ciphers

decr_alg.each do |cipher|
   decr_cipher_combo.append_text cipher 
end

decr_cipher_combo.active = 0

decr_cipher_combo.signal_connect "changed" do
   decr_crypto_alg = decr_alg[decr_cipher_combo.active]
end

decr_key_entry = Gtk::Entry.new()
decr_key_entry.text = '$3cYouR3#'

decr_salt_entry = Gtk::Entry.new()
decr_salt_entry.text = "$@ltsaLT"
decr_salt_box.pack_start(decr_salt_entry, true, true, 2)

decr_key_box.pack_start(decr_key_entry, true, true, 2)

decr_inout_frame = Gtk::Frame.new(" INPUT/OUTPUT ")
decr_inout_textview = Gtk::TextView.new()
decr_inout_textview.set_size_request(-1, 300)
decr_inout_textview.border_width = 5
decr_inout_scrolled = Gtk::ScrolledWindow.new()
decr_inout_scrolled.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS)
decr_inout_scrolled.add(decr_inout_textview)
decr_inout_frame.add(decr_inout_scrolled)

font = Pango::FontDescription.new("Courier New 9")
decr_inout_textview.modify_font(font)

decr_box.pack_start(decr_crypto_box, true, true, 3)

decr_box.pack_start(decr_inout_frame, true, true, 5)

separator = Gtk::HSeparator.new

decr_box.pack_start(separator, false, false, 1)

decr_control_box = Gtk::HBox.new(true, 5)

decr_box.pack_start(decr_control_box, true, false, 5)

decr_exec_button = Gtk::Button.new("Decrypt")
decr_exec_button.signal_connect("clicked") do
   key = decr_key_entry.text
   salt = decr_salt_entry.text
   string = retrieve_text(decr_inout_textview)
   decr_inout_textview.buffer.text += "\n" + " Plaintext Block: #{decr_alg[decr_cipher_combo.active]} ".center(60, '-') + "\n"
   decr_inout_textview.buffer.text += decrypt(decr_alg[decr_cipher_combo.active], key, salt, string)
   decr_inout_textview.buffer.text += "\n" + "  End of plaintext block  ".center(60, '-')
end

decr_clear_button = Gtk::Button.new("Clear")
decr_clear_button.signal_connect("clicked") do
   decr_inout_textview.buffer.text = ""
end

decr_save_button = Gtk::Button.new("Save to file")
decr_save_button.signal_connect("clicked") do
   filnm = filename($window)
   if (filnm.empty? == false) and (save_as(filnm, decr_inout_textview.buffer.text))
      message($window, "Results of operation", "Saved to file: #{filnm}")
   else
      message($window, "Results of operation", "Something went wrong with saving to file: #{filnm}")
   end
end

decr_exit_button = Gtk::Button.new("Exit")
decr_exit_button.signal_connect("clicked") do
   Gtk.main_quit
end

decr_control_box.pack_start(decr_exec_button, true, true, 2)
decr_control_box.pack_start(decr_clear_button, true, true, 2)
decr_control_box.pack_start(decr_save_button, true, true, 2)
decr_control_box.pack_start(decr_exit_button, true, true, 2)
# ------------------------ Hashing page ----------------------------
hash_crypto_box = Gtk::HBox.new(true, 3)

hash_frame = Gtk::Frame.new(" Hashing functions ")

$hashing_function = 'MD5'

hash_radio1 = Gtk::RadioButton.new("MD5")
hash_radio2 = Gtk::RadioButton.new(hash_radio1, "SHA-1")
hash_radio3 = Gtk::RadioButton.new(hash_radio1, "SHA-256")
hash_radio4 = Gtk::RadioButton.new(hash_radio1, "RIPEMD-160")

hash_crypto_box.pack_start(hash_radio1, :expand => true, :fill => true, :padding => 5)
hash_crypto_box.pack_start(hash_radio2, :expand => true, :fill => true, :padding => 5)
hash_crypto_box.pack_start(hash_radio3, :expand => true, :fill => true, :padding => 5)
hash_crypto_box.pack_start(hash_radio4, :expand => true, :fill => true, :padding => 5)

hash_radio1.signal_connect("clicked") { $hashing_function = 'MD5' }
hash_radio2.signal_connect("clicked") { $hashing_function = 'SHA-1' }
hash_radio3.signal_connect("clicked") { $hashing_function = 'SHA-2' }
hash_radio4.signal_connect("clicked") { $hashing_function = 'RMD' }

hash_frame.add(hash_crypto_box)
hash_box.border_width = 5

hash_box.pack_start(hash_frame, true, true, 2)

hash_inout_frame = Gtk::Frame.new(" INPUT/OUTPUT ")
hash_inout_textview = Gtk::TextView.new()
hash_inout_textview.set_size_request(-1, 300)
hash_inout_textview.border_width = 5
hash_inout_scrolled = Gtk::ScrolledWindow.new()
hash_inout_scrolled.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS)
hash_inout_scrolled.add(hash_inout_textview)
hash_inout_frame.add(hash_inout_scrolled)

font = Pango::FontDescription.new("Courier New 9")
hash_inout_textview.modify_font(font)

hash_box.pack_start(hash_inout_frame, true, true, 5)

separator = Gtk::HSeparator.new

hash_box.pack_start(separator, false, false, 1)

hash_control_box = Gtk::HBox.new(true, 5)

hash_box.pack_start(hash_control_box, true, false, 5)

hash_exec_button = Gtk::Button.new("Calculate Hash")
hash_exec_button.signal_connect("clicked") do
   string = retrieve_text(hash_inout_textview)
   hash_inout_textview.buffer.text += "\n" + " Hash Block: #{$hashing_function} ".center(60, '-') + "\n"
   hash_inout_textview.buffer.text += hashing($hashing_function, string)
   hash_inout_textview.buffer.text += "\n" + "  End of hash block  ".center(60, '-')
end

hash_clear_button = Gtk::Button.new("Clear")
hash_clear_button.signal_connect("clicked") do
   hash_inout_textview.buffer.text = ""
end

hash_save_button = Gtk::Button.new("Save to file")
hash_save_button.signal_connect("clicked") do
   filnm = filename($window)
   if (filnm.empty? == false) and (save_as(filnm, hash_inout_textview.buffer.text))
      message($window, "Results of operation", "Saved to file: #{filnm}")
   else
      message($window, "Results of operation", "Something went wrong with saving to file: #{filnm}")
   end
end

hash_exit_button = Gtk::Button.new("Exit")
hash_exit_button.signal_connect("clicked") do
   Gtk.main_quit
end

hash_control_box.pack_start(hash_exec_button, true, true, 2)
hash_control_box.pack_start(hash_clear_button, true, true, 2)
hash_control_box.pack_start(hash_save_button, true, true, 2)
hash_control_box.pack_start(hash_exit_button, true, true, 2)

# ------------------------ HMAC page ----------------------------
hmac_crypto_box = Gtk::HBox.new(true, 3)

hmac_cipher_box = Gtk::HBox.new()
hmac_cipher_box.border_width = 5

hmac_cipher_frame = Gtk::Frame.new(" HMAC function ")
hmac_key_box = Gtk::HBox.new()
hmac_key_box.border_width = 5

hmac_key_frame = Gtk::Frame.new(" Key ")
hmac_cipher_frame.add(hmac_cipher_box)
hmac_key_frame.add(hmac_key_box)
hmac_crypto_box.pack_start(hmac_cipher_frame, true, true, 2)
hmac_crypto_box.pack_start(hmac_key_frame, true, true, 2)

hmac_cipher_combo = Gtk::ComboBox.new()
hmac_cipher_box.pack_start(hmac_cipher_combo, true, true, 5)

hmac_alg = ["MD5", "SHA-1", "SHA-256", "RIPEMD-160"]

hmac_alg.each do |cipher|
   hmac_cipher_combo.append_text cipher 
end

hmac_cipher_combo.active = 0

hmac_cipher_combo.signal_connect "changed" do
   hmac_crypto_alg = hmac_alg[hmac_cipher_combo.active]
end

hmac_key_entry = Gtk::Entry.new()
hmac_key_entry.text = '$3cYouR3#'

hmac_key_box.pack_start(hmac_key_entry, true, true, 2)

hmac_inout_frame = Gtk::Frame.new(" INPUT/OUTPUT ")
hmac_inout_textview = Gtk::TextView.new()
hmac_inout_textview.set_size_request(-1, 300)
hmac_inout_textview.border_width = 5
hmac_inout_scrolled = Gtk::ScrolledWindow.new()
hmac_inout_scrolled.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS)
hmac_inout_scrolled.add(hmac_inout_textview)
hmac_inout_frame.add(hmac_inout_scrolled)

font = Pango::FontDescription.new("Courier New 9")
hmac_inout_textview.modify_font(font)

hmac_box.pack_start(hmac_crypto_box, true, true, 3)

hmac_box.pack_start(hmac_inout_frame, true, true, 5)

separator = Gtk::HSeparator.new

hmac_box.pack_start(separator, false, false, 1)

hmac_control_box = Gtk::HBox.new(true, 5)

hmac_box.pack_start(hmac_control_box, true, false, 5)

hmac_exec_button = Gtk::Button.new("Calculate HMAC")
hmac_exec_button.signal_connect("clicked") do
   key = hmac_key_entry.text
   string = retrieve_text(hmac_inout_textview)
   hmac_inout_textview.buffer.text += "\n" + " HMAC Block: #{hmac_alg[hmac_cipher_combo.active]} ".center(60, '-') + "\n"
   hmac_inout_textview.buffer.text += hmac_calculate(hmac_alg[hmac_cipher_combo.active], key, string)
   hmac_inout_textview.buffer.text += "\n" + "  End of HMAC block  ".center(60, '-')
end

hmac_clear_button = Gtk::Button.new("Clear")
hmac_clear_button.signal_connect("clicked") do
   hmac_inout_textview.buffer.text = ""
end

hmac_save_button = Gtk::Button.new("Save to file")
hmac_save_button.signal_connect("clicked") do
   filnm = filename($window)
   if (filnm.empty? == false) and (save_as(filnm, hmac_inout_textview.buffer.text))
      message($window, "Results of operation", "Saved to file: #{filnm}")
   else
      message($window, "Results of operation", "Something went wrong with saving to file: #{filnm}")
   end
end

hmac_exit_button = Gtk::Button.new("Exit")
hmac_exit_button.signal_connect("clicked") do
   Gtk.main_quit
end

hmac_control_box.pack_start(hmac_exec_button, true, true, 2)
hmac_control_box.pack_start(hmac_clear_button, true, true, 2)
hmac_control_box.pack_start(hmac_save_button, true, true, 2)
hmac_control_box.pack_start(hmac_exit_button, true, true, 2)

# ------------------------ Main Program ----------------------------

main_nb.append_page(encr_box, encr_label)
main_nb.append_page(decr_box, decr_label)
main_nb.append_page(hash_box,  hash_label)
main_nb.append_page(hmac_box,  hmac_label)

$window.add(main_nb)
$window.show_all
Gtk.main

Informacje Janusz Nawrat
Just ordinary man who likes thinking...

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s

TOMASZ WEŁNA

artysta grafik | wykładowca

PRACOWNIA OKO

Szkoła Rysunku Malarstwa i Grafiki DR TOMASZA WEŁNY | KRAKÓW | Plac Matejki 10 | tel 691 81 75 74

Piękno neurobiologii

Blog Jerzego Vetulaniego

Teoria muzyki, zasady muzyki, podstawy muzyki

Teoria muzyki, zasady muzyki, podstawy muzyki - czyli to co każdy amator muzyki wiedzieć powinien :)

Personal Development & Inspirations

Przemyślenia i refleksje, którymi warto się podzielić (blog by Janusz Nawrat)

Business IT Cooperation Platform

Biznes i IT - dwa światy, które muszą współdziałać

%d bloggers like this: