Skip to content

Instantly share code, notes, and snippets.

@Inversion-des
Created December 10, 2024 17:02
Show Gist options
  • Save Inversion-des/0d0f538a624a57c85808db7f60769e4e to your computer and use it in GitHub Desktop.
Save Inversion-des/0d0f538a624a57c85808db7f60769e4e to your computer and use it in GitHub Desktop.
require 'optparse'
class Practice
def initialize
@fname = 'data.txt'
# predefined key for the demo (32-byte)
@key = "12345678901234567890123456789012"
# prepage libraries in bg for faster start
@libs_loading_thr = Thread.new do
require 'openssl'
require 'base64'
end
#-- parse cmd options
opt_parser = OptionParser.new do |opts|
opts.banner = 'Accepted cmd options:'
opts.on '--demo', 'Interactive demo' do
demo
end
opts.on '-e', '--encrypt', 'Encrypt '+@fname do
ensure_file_exists!
puts "Encrypting #{@fname}..."
@libs_loading_thr.join
encrypt_file
end
opts.on '-d', '--decrypt', 'Decrypt '+@fname do
ensure_file_exists!
puts "Decrypting #{@fname}..."
@libs_loading_thr.join
decrypt_file
end
end
# if no options -- show help
if ARGV.empty?
puts opt_parser.help
exit
end
opt_parser.parse!
rescue RuntimeError
puts 'Error: '+$!.to_s
end
def demo
# create the file if not exists
unless File.exist? @fname
File.write @fname, 'This is a secret message.'
end
puts "Prepare #{@fname} in the current folder."
print 'Press Enter when ready -- file content will be encrypted...'
@libs_loading_thr.join
gets
encrypt_file
print 'Press Enter to decrypt the text...'
gets
decrypt_file
end
def encrypt_file
text = File.read @fname
encrypted_text = aes_encrypt(text, @key)
File.write @fname, encrypted_text
puts 'Now, text in the file is encrypted.'
end
def decrypt_file
encrypted_text = File.read @fname
decrypted_text = aes_decrypt(encrypted_text, @key)
File.write @fname, decrypted_text
puts 'Now, text in the file is decrypted.'
end
def ensure_file_exists!
raise "File not found: #{@fname}" unless File.exist? @fname
end
# AES256 encryption
def aes_encrypt(text, key)
cipher = get_cipher.tap { _1.encrypt; _1.key = key }
iv = cipher.random_iv # 16 bytes
cipher_text = cipher.update(text) + cipher.final
# *ensure there is no newline char in the encrypted text
Base64.strict_encode64(iv + cipher_text)
end
def aes_decrypt(encrypted_text, key)
decrypted_text = Base64.decode64(encrypted_text)
iv, cipher_text = decrypted_text.then { [_1[0..15], _1[16..]] }
cipher = get_cipher.tap { _1.decrypt; _1.key = key; _1.iv = iv }
cipher.update(cipher_text) + cipher.final
rescue
raise 'Looks like file was not encrypted'
end
def get_cipher
OpenSSL::Cipher::AES256.new(:CBC)
end
end
Practice.new
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment