require 'encrypted_strings/no_private_key_error'
require 'encrypted_strings/no_public_key_error'
module PluginAWeek #:nodoc:
module EncryptedStrings #:nodoc:
# Encryption in which the keys used to encrypt/decrypt come in pairs. Also known
# as public key encryption. Anything that's encrypted using the public key can
# only be decrypted with the same algorithm and a matching private key.
# Any message that is encrypted with the private key can only be decrypted
# with the matching public key.
#
# http://support.microsoft.com/kb/246071
class AsymmetricEncryptor < Encryptor
# The default private key to use during encryption. Default is nil.
@@default_private_key_file = nil
cattr_accessor :default_private_key_file
# The default public key to use during encryption. Default is nil.
@@default_public_key_file = nil
cattr_accessor :default_public_key_file
# The default algorithm to use. Default is nil.
@@default_algorithm = nil
cattr_accessor :default_algorithm
attr_reader :private_key_file
attr_reader :public_key_file
attr_accessor :algorithm
attr_accessor :key
# Configuration options:
# * private_key_file - Encrypted private key file
# * public_key_file - Public key file
# * key - The key to use in the symmetric encryptor
# * algorithm - Algorithm to use symmetrically encrypted strings
def initialize(options = {})
options = options.symbolize_keys
options.assert_valid_keys(
:private_key_file,
:public_key_file,
:key,
:algorithm
)
options.reverse_merge!(
:private_key_file => @@default_private_key_file,
:public_key_file => @@default_public_key_file,
:algorithm => @@default_algorithm
)
@public_key = @private_key = nil
@key = options[:key]
@algorithm = options[:algorithm]
self.private_key_file = options[:private_key_file]
self.public_key_file = options[:public_key_file]
super()
end
# Encrypts the given data
def encrypt(data)
raise NoPublicKeyError, "Public key file: #{@public_key_file}" unless public?
encrypted_data = public_rsa.public_encrypt(data)
Base64.encode64(encrypted_data)
end
# Decrypts the given data
def decrypt(data)
raise NoPrivateKeyError, "Private key file: #{@private_key_file}" unless private?
decrypted_data = Base64.decode64(data)
private_rsa.private_decrypt(decrypted_data)
end
# Sets the location of the private key and loads it
def private_key_file=(file)
@private_key_file = file and load_private_key
end
# Sets the location of the public key and loads it
def public_key_file=(file)
@public_key_file = file and load_public_key
end
# Is this string encrypted using a public key?
def public?
return true unless @public_key.nil?
load_public_key
!@public_key.nil?
end
# Is this string encrypted using a private key?
def private?
return true unless @private_key.nil?
load_private_key
!@private_key.nil?
end
private
def load_private_key #:nodoc:
@private_rsa = nil
if @private_key_file && File.file?(@private_key_file)
@private_key = File.open(@private_key_file) {|f| f.read}
end
end
def load_public_key #:nodoc:
@public_rsa = nil
if @public_key_file && File.file?(@public_key_file)
@public_key = File.open(@public_key_file) {|f| f.read}
end
end
# Retrieves private RSA from the encrypted private key
def private_rsa #:nodoc:
return @private_rsa ||= OpenSSL::PKey::RSA.new(@private_key) unless @key
private_key = SymmetricEncryptor.new(:key => @key, :algorithm => @algorithm).decrypt(@private_key)
OpenSSL::PKey::RSA.new(private_key)
end
# Retrieves the public RSA
def public_rsa #:nodoc:
@public_rsa ||= OpenSSL::PKey::RSA.new(@public_key)
end
end
end
end