Skip to content

Instantly share code, notes, and snippets.

@boykoc
Created July 12, 2017 17:13
Show Gist options
  • Save boykoc/e4795e456d0e983f4f10b73c807331a4 to your computer and use it in GitHub Desktop.
Save boykoc/e4795e456d0e983f4f10b73c807331a4 to your computer and use it in GitHub Desktop.
Ruby OpenSSL Symmetric Encryption and Decryption.
# Get the encryption classes needed. Assuming they are in the same directory.
require './symmetric_encrypt.rb'
require './symmetric_decrypt.rb'
puts "What would you like to do?"
puts "Type 'encrypt', 'decrypt' or 'exit'."
input = gets.chomp
input.downcase
if input == 'encrypt'
puts "Enter the file name, extension and path encrypt"
file = gets.chomp
puts "Enter a super hard password and remember it, you'll need it again to see the file contents"
password = gets.chomp
e = SymmetricEncrypt.new(file, password)
e.encrypt
e.remove_file
puts "Done."
exit
elsif input == 'decrypt'
puts "Enter the file name, extension and path to decrypt"
file = gets.chomp
puts "Enter a super hard password *that you used to encrypt the file*"
password = gets.chomp
d = SymmetricDecrypt.new(file, password)
d.decrypt
d.remove_file
puts "Done."
exit
elsif input == 'exit'
exit
end
class SymmetricDecrypt
require 'openssl'
require 'base64'
attr_reader :file, :password
def initialize(file, password)
@file = file
@password = password
end
##
# Decrypt the file given during instantiation using
# a symmetric key.
def decrypt
cipher = OpenSSL::Cipher.new 'AES-128-CBC'
cipher.decrypt
# Get the initialization vector from the encrypted file and decode from base64.
cipher.iv = Base64.decode64(File.read(file).each_line.take(1).last.chomp)
pwd = password
# Get the SALT from the encrypted file and decode from base64.
salt = Base64.decode64(File.read(file).each_line.take(2).last.chomp)
iter = 20000
key_len = cipher.key_len
digest = OpenSSL::Digest::SHA256.new
key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest)
cipher.key = key
decrypted = ""
# Decrypt each line in the original file.
File.foreach(file).with_index do |line, index|
# Skip the first 2 lines (the IV and SALT).
next if index < 2
decrypted << cipher.update(line)
end
decrypted << cipher.final
# Strip out the .enc filetype.
output_file = file.gsub('.enc', '')
# Write the decrypted information to a new file.
File.open(output_file, 'w') do |f|
f.write(decrypted)
end
end
##
# Remove original file.
def remove_file
File.delete file
end
end
class SymmetricEncrypt
require 'openssl'
require 'base64'
attr_reader :file, :password
def initialize(file, password)
@file = file
@password = password
end
##
# Encrypt the file given during intantiation using
# a symmetric key.
def encrypt
cipher = OpenSSL::Cipher.new 'AES-128-CBC'
cipher.encrypt
# Use a random initialization vector each time
# a file is encrypted.
iv = cipher.random_iv
pwd = password
# Use a random salt each time a file is encrypted.
salt = OpenSSL::Random.random_bytes 16
iter = 20000
key_len = cipher.key_len
digest = OpenSSL::Digest::SHA256.new
key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest)
cipher.key = key
# Create an encrypted version of the file. Include the IV and SALT
# to recreate symmetric key when decrypting.
File.open("#{file}.enc", 'w') do |f|
# Base64 encode IV and SALT to prevent encoding issues.
# These are publicly sharable. The important part is to not
# share the password used to create the key, and to use
# random values for the IV and SALT. Basically, don't share the key
# publicly/with the data in transit. The sender and reciever need the key only.
# If it's always the same it'll be easier to eventually figure out the key.
f.write Base64.encode64(iv)
f.write Base64.encode64(salt)
encrypted = cipher.update File.read(file)
encrypted << cipher.final
f.write encrypted
end
end
##
# Remove original file.
def remove_file
File.delete file
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment