Skip to content

Instantly share code, notes, and snippets.

@bhelx
Last active December 27, 2015 21:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bhelx/7389954 to your computer and use it in GitHub Desktop.
Save bhelx/7389954 to your computer and use it in GitHub Desktop.
Securely store and retrieve a file from an external drive
# This script allows securely storing and retrieving a file to USB drive using rbnacl
#
# Usage:
#
# 1) Generate a private key:
#
# ruby safe_store.rb --generate-key -k /Volumes/SAFEUSB/my_private_key.key
#
# 2) Write the ciphertext file to your drive (mine is named PATRIOT).
# This will write a file at /Volumes/PATRIOT/plain.txt.ctxt:
#
# ruby safe_store.rb -p plain.txt -k /Volumes/SAFEUSB/my_private_key.key -d /Volumes/PATRIOT/
#
# 3) To decrypt from drive. This will write to current working directory by default (./plain.txt)
#
# ruby safe_store.rb -c ~/code/plain.txt.ctxt -k /Volumes/SAFEUSB/my_private_key.key
#
require 'rbnacl'
require 'json'
require 'optparse'
class CipherFile
attr_accessor :nonce, :ciphertext
def self.load(file_path)
@file = File.open(file_path)
Marshal.load(@file.read)
end
def initialize(nonce, ciphertext)
@nonce = nonce
@ciphertext = ciphertext
end
def marshal_dump
[@nonce, @ciphertext]
end
def marshal_load(array)
@nonce, @ciphertext = array
end
def write(file_path)
IO.write(file_path, Marshal.dump(self))
end
end
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: ruby safe_store.rb [options]"
opts.on("-k path", String, "Key File") do |keyfile|
options[:keyfile] = keyfile
end
opts.on("-p path", String, "Plaintext file") do |plaintext|
options[:plaintext] = plaintext
end
opts.on("-c path", String, "Ciphertext file") do |ciphertext|
options[:ciphertext] = ciphertext
end
opts.on("-d path", String, "Destination folder") do |destination|
options[:destination] = destination
end
opts.on("--generate-key", "Generate keyfile") do |generate|
options[:generatekey] = generate
end
end.parse!
# generate keyfile here
if options[:generatekey]
keyfile = options[:keyfile] || 'private_key.key'
key = RbNaCl::Random.random_bytes(RbNaCl::SecretBox.key_bytes)
IO.write(keyfile, key)
puts "Key generated at #{keyfile}"
exit
end
key = IO.read(options[:keyfile])
# decrypt
if options[:ciphertext]
cipher_file = CipherFile.load(options[:ciphertext])
secret_box = RbNaCl::SecretBox.new(key)
nonce = cipher_file.nonce
plaintext = secret_box.decrypt(nonce, cipher_file.ciphertext)
plaintext_file = File.basename(options[:ciphertext], 'ctxt')
plaintext_file = File.join(options[:destination], plaintext_file) if options[:destination]
IO.write(plaintext_file, plaintext)
puts "Wrote plaintext to #{plaintext_file}"
end
if options[:plaintext]
secret_box = RbNaCl::SecretBox.new(key)
nonce = RbNaCl::Random.random_bytes(secret_box.nonce_bytes)
plaintext = IO.read(options[:plaintext])
ciphertext = secret_box.encrypt(nonce, plaintext)
file_path = File.basename(options[:plaintext]) + '.ctxt'
file_path = File.join(options[:destination], file_path) if options[:destination]
cipherfile = CipherFile.new(nonce, ciphertext)
IO.write(file_path, Marshal.dump(cipherfile))
puts "Wrote ciphertext to #{file_path}"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment