Skip to content

Instantly share code, notes, and snippets.

@kidoman
Created October 31, 2012 01:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kidoman/3984361 to your computer and use it in GitHub Desktop.
Save kidoman/3984361 to your computer and use it in GitHub Desktop.
A simple ruby wrapper script over OpenSSL to assist in encryption/decryption using your RSA keys (id_rsa/id_rsa.pub will do just fine)

Encryption

enc_dec.rb -a e --rsa sender/id_rsa.pub --aes sender/aes_key --input sender/data --output sender/data.jpg.encrypted --overwrite

Decryption

enc_dec.rb -a d --rsa receiver/id_rsa --aes sender/aes_key --input sender/data.jpg.encrypted --output receiver/data.jpg --overwrite

Proof

Run enc_dec_test.rb

#!/usr/bin/env ruby
require "optparse"
require "tempfile"
require "stringio"
class OptionError < StandardError; end
class OpenSSLError < StandardError; end
module Base
def closed_temp_file(prefix)
Tempfile.new(prefix).tap do |file|
file.close
end
end
def run(msg)
puts msg
value = yield
raise OpenSSLError, value unless $?.exitstatus == 0
end
end
class Encypter
include Base
attr_accessor :public_key_file, :encrypted_aes_key_file, :input_file, :encrypted_output_file, :overwrite, :key_size
def initialize(options = {})
@public_key_file = options[:rsa_key] or raise OptionError, "RSA public key file must be given"
@encrypted_aes_key_file = options[:aes_key] or raise OptionError, "Target AES encrypted key file must be given"
@input_file = options[:input_file] or raise OptionError, "Please provide the file to encrypt"
@encrypted_output_file = options[:output_file] or raise OptionError, "Please provide the target outfile file name"
@overwrite = options[:overwrite] || false
@key_size = options[:key_size] || 64
raise OptionError, "Input file does not exist" unless File.exist?(input_file)
raise OptionError, "Target AES encrypted file must not exist before hand" if !overwrite & File.exist?(encrypted_aes_key_file)
raise OptionError, "Output file must not exist before hand" if !overwrite & File.exist?(encrypted_output_file)
end
def perform
aes_key_file = closed_temp_file("aes")
if File.read(public_key_file).start_with?("ssh-")
pem_public_key_file = closed_temp_file("pub_pem")
pem_public_key_file_path = pem_public_key_file.path
`ssh-keygen -f #{public_key_file} -e -m pkcs8 > #{pem_public_key_file_path}`
end
begin
run "Creating AES key..." do
`openssl rand -base64 #{key_size} | tr -d '\r\n' > #{aes_key_file.path}`
end
run "Encrypting the file..." do
`openssl enc -aes-256-cbc -in #{input_file} -out #{encrypted_output_file} -kfile #{aes_key_file.path}`
end
run "Encrypting the AES key..." do
`openssl rsautl -encrypt -inkey #{pem_public_key_file_path || public_key_file} -pubin -in #{aes_key_file.path} -out #{encrypted_aes_key_file} 2>&1`
end
puts "Encryption complete. Please send #{encrypted_output_file} and #{encrypted_aes_key_file} to the sender."
puts "They can decrypt #{File.basename(encrypted_output_file)} provided they have the right private key."
ensure
aes_key_file.unlink
pem_public_key_file.unlink if pem_public_key_file
end
end
end
class Decrypter
include Base
attr_accessor :private_key_file, :encrypted_aes_key_file, :encrypted_file, :output_file, :overwrite
def initialize(options = {})
@private_key_file = options[:rsa_key] or raise OptionError, "RSA private key file must be given"
@encrypted_aes_key_file = options[:aes_key] or raise OptionError, "AES encrypted key file must be given"
@encrypted_file = options[:input_file] or raise OptionError, "Please provide the file to decrypt"
@output_file = options[:output_file] or raise OptionError, "Please provide the target output file name"
@overwrite = options[:overwrite] || false
raise OptionError, "Input file does not exists" unless File.exist?(encrypted_file)
raise OptionError, "Output file must not exist before hand" if !overwrite & File.exist?(output_file)
end
def perform
decrypted_aes_key_file = closed_temp_file("aes")
begin
run "Decrypting your AES key..." do
`openssl rsautl -decrypt -inkey #{private_key_file} -in #{encrypted_aes_key_file} -out #{decrypted_aes_key_file.path}`
end
run "Decrypting your encrypted file..." do
`openssl enc -aes-256-cbc -d -in #{encrypted_file} -out #{output_file} -kfile #{decrypted_aes_key_file.path}`
end
puts "File decrypted. Check #{output_file}"
ensure
decrypted_aes_key_file.unlink
end
end
end
options = {}
opts = OptionParser.new do |opts|
opts.banner = "Usage: enc_dec.rb [options]"
opts.on("-a", "--action ACTION", {:encrypt => "Encypter", :decrypt => "Decrypter"}) do |action|
options[:action] = action
end
opts.on("--rsa FILE", "RSA key (either public when encrypting, or private when decrypting)") do |rsa_key|
options[:rsa_key] = rsa_key
end
opts.on("--aes FILE", "AES key file (encrypted or target)") do |aes_key|
options[:aes_key] = aes_key
end
opts.on("--key-size SIZE", Integer, "Key size to use when generating AES key (default 32)") do |key_size|
options[:key_size] = key_size
end
opts.on("--input FILE", "Input file to encrypt/decrypt") do |input_file|
options[:input_file] = input_file
end
opts.on("--output FILE", "Output file to encrypt/decrypt") do |output_file|
options[:output_file] = output_file
end
opts.on("--overwrite", "Overwrite target files") do
options[:overwrite] = true
end
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit
end
opts.on_tail("--version", "Show version") do
puts "0.1.0"
exit
end
end
opts.parse!(ARGV)
begin
action = options.delete(:action) or raise OptionError, "You must specify action"
crypto = Kernel.const_get(action).new(options)
crypto.perform
rescue OptionError => e
STDERR.puts "#{e.message}\n\n"
STDERR.puts opts
rescue OpenSSLError => e
STDERR.puts "\nOpenSSL is mis behaving. The error:\n\n"
STDERR.puts e.message
end
#!/usr/bin/env ruby
begin
# Generate the test key pair
`ssh-keygen -q -f test -N ""`
# Encrypt and then decrypt the file
`./enc_dec.rb -a e --rsa test.pub --aes aes_key.encrypted --input README.md --output README.md.encrypted`
`./enc_dec.rb -a d --rsa test --aes aes_key.encrypted --input README.md.encrypted --output README.md.decrypted`
# Compare contents
original = File.read("README.md")
decrypted = File.read("README.md.decrypted")
abort "Files do not match" unless original == decrypted
puts "Enc Dec works!"
ensure
`rm -f test test.pub aes_key.encrypted README.md.encrypted README.md.decrypted`
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment