pluginaweek-encrypted_strings 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +59 -0
- data/LICENSE +20 -0
- data/README.rdoc +88 -0
- data/Rakefile +96 -0
- data/init.rb +1 -0
- data/lib/encrypted_strings.rb +7 -0
- data/lib/encrypted_strings/asymmetric_cipher.rb +185 -0
- data/lib/encrypted_strings/cipher.rb +17 -0
- data/lib/encrypted_strings/extensions/string.rb +205 -0
- data/lib/encrypted_strings/sha_cipher.rb +67 -0
- data/lib/encrypted_strings/symmetric_cipher.rb +101 -0
- data/test/asymmetric_cipher_test.rb +183 -0
- data/test/cipher_test.rb +15 -0
- data/test/keys/encrypted_private +12 -0
- data/test/keys/private +9 -0
- data/test/keys/public +4 -0
- data/test/sha_cipher_test.rb +82 -0
- data/test/string_test.rb +222 -0
- data/test/symmetric_cipher_test.rb +99 -0
- data/test/test_helper.rb +4 -0
- metadata +79 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
module EncryptedStrings
|
2
|
+
# Represents the base class for all ciphers. By default, all ciphers are
|
3
|
+
# assumed to be able to decrypt strings. Note, however, that certain
|
4
|
+
# encryption algorithms do not allow decryption.
|
5
|
+
class Cipher
|
6
|
+
# Can this string be decrypted? Default is true.
|
7
|
+
def can_decrypt?
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
# Attempts to decrypt the given data using the current configuration. By
|
12
|
+
# default, decryption is not implemented.
|
13
|
+
def decrypt(data)
|
14
|
+
raise NotImplementedError, "Decryption is not supported using a(n) #{self.class.name}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
module EncryptedStrings
|
2
|
+
module Extensions #:nodoc:
|
3
|
+
# Adds support for in-place encryption/decryption of strings
|
4
|
+
module String
|
5
|
+
def self.included(base) #:nodoc:
|
6
|
+
base.class_eval do
|
7
|
+
attr_accessor :cipher
|
8
|
+
|
9
|
+
alias_method :equals_without_encryption, :==
|
10
|
+
alias_method :==, :equals_with_encryption
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Encrypts the current string using the specified cipher. The default
|
15
|
+
# cipher is sha.
|
16
|
+
#
|
17
|
+
# Configuration options are cipher-specific. See each individual cipher
|
18
|
+
# class to find out the options available.
|
19
|
+
#
|
20
|
+
# == Example
|
21
|
+
#
|
22
|
+
# The following uses an SHA cipher to encrypt the string:
|
23
|
+
#
|
24
|
+
# password = 'shhhh'
|
25
|
+
# password.encrypt # => "66c85d26dadde7e1db27e15a0776c921e27143bd"
|
26
|
+
#
|
27
|
+
# == Custom encryption mode
|
28
|
+
#
|
29
|
+
# The following uses Symmetric cipher (with a default password) to
|
30
|
+
# encrypt the string:
|
31
|
+
#
|
32
|
+
# EncryptedStrings::SymmetricCipher.default_password = 'secret'
|
33
|
+
# password = 'shhhh'
|
34
|
+
# password.encrypt(:symmetric) # => "jDACXI5hMPI=\n"
|
35
|
+
#
|
36
|
+
# == Custom encryption options
|
37
|
+
#
|
38
|
+
# Some encryption modes also support additional configuration options
|
39
|
+
# that determine how to encrypt the string. For example, SHA supports
|
40
|
+
# a salt which seeds the algorithm:
|
41
|
+
#
|
42
|
+
# password = 'shhhh'
|
43
|
+
# password.encrypt(:sha, :salt => 'secret') # => "3b22cbe4acde873c3efc82681096f3ae69aff828"
|
44
|
+
def encrypt(*args)
|
45
|
+
cipher = cipher_from_args(*args)
|
46
|
+
encrypted_string = cipher.encrypt(self)
|
47
|
+
encrypted_string.cipher = cipher
|
48
|
+
|
49
|
+
encrypted_string
|
50
|
+
end
|
51
|
+
|
52
|
+
# Encrypts this string and replaces it with the encrypted value. This
|
53
|
+
# takes the same parameters as #encrypt, but returns the same string
|
54
|
+
# instead of a different one.
|
55
|
+
#
|
56
|
+
# == Example
|
57
|
+
#
|
58
|
+
# password = 'shhhh'
|
59
|
+
# password.encrypt!(:symmetric, :password => 'secret') # => "qSg8vOo6QfU=\n"
|
60
|
+
# password # => "qSg8vOo6QfU=\n"
|
61
|
+
def encrypt!(*args)
|
62
|
+
encrypted_string = encrypt(*args)
|
63
|
+
self.cipher = encrypted_string.cipher
|
64
|
+
|
65
|
+
replace(encrypted_string)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Is this string encrypted? This will return true if the string is the
|
69
|
+
# result of a call to #encrypt or #encrypt!.
|
70
|
+
#
|
71
|
+
# == Example
|
72
|
+
#
|
73
|
+
# password = 'shhhh'
|
74
|
+
# password.encrypted? # => false
|
75
|
+
# password.encrypt! # => "66c85d26dadde7e1db27e15a0776c921e27143bd"
|
76
|
+
# password.encrypted? # => true
|
77
|
+
def encrypted?
|
78
|
+
!cipher.nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
# Decrypts this string. If this is not a string that was previously
|
82
|
+
# encrypted, the cipher must be specified in the same way that it is
|
83
|
+
# when encrypting a string.
|
84
|
+
#
|
85
|
+
# == Example
|
86
|
+
#
|
87
|
+
# Without being previously encrypted:
|
88
|
+
#
|
89
|
+
# password = "qSg8vOo6QfU=\n"
|
90
|
+
# password.decrypt(:symmetric, :password => 'secret') # => "shhhh"
|
91
|
+
#
|
92
|
+
# After being previously encrypted:
|
93
|
+
#
|
94
|
+
# password = 'shhhh'
|
95
|
+
# password.encrypt!(:symmetric, :password => 'secret') # => "qSg8vOo6QfU=\n"
|
96
|
+
# password.decrypt # => "shhhh"
|
97
|
+
def decrypt(*args)
|
98
|
+
raise ArgumentError, 'Cipher cannot be inferred: must specify it as an argument' if args.empty? && !encrypted?
|
99
|
+
|
100
|
+
cipher = args.empty? && self.cipher || cipher_from_args(*args)
|
101
|
+
encrypted_string = cipher.decrypt(self)
|
102
|
+
encrypted_string.cipher = nil
|
103
|
+
|
104
|
+
encrypted_string
|
105
|
+
end
|
106
|
+
|
107
|
+
# Decrypts this string and replaces it with the decrypted value This
|
108
|
+
# takes the same parameters as #decrypt, but returns the same string
|
109
|
+
# instead of a different one.
|
110
|
+
#
|
111
|
+
# For example,
|
112
|
+
#
|
113
|
+
# password = "qSg8vOo6QfU=\n"
|
114
|
+
# password.decrypt!(:symmetric, :password => 'secret') # => "shhhh"
|
115
|
+
# password # => "shhhh"
|
116
|
+
def decrypt!(*args)
|
117
|
+
value = replace(decrypt(*args))
|
118
|
+
self.cipher = nil
|
119
|
+
value
|
120
|
+
end
|
121
|
+
|
122
|
+
# Can this string be decrypted? Strings can only be decrypted if they
|
123
|
+
# have previously been decrypted *and* the cipher supports decryption.
|
124
|
+
# To determine whether or not the cipher supports decryption, see the
|
125
|
+
# api for the cipher.
|
126
|
+
def can_decrypt?
|
127
|
+
encrypted? && cipher.can_decrypt?
|
128
|
+
end
|
129
|
+
|
130
|
+
# Tests whether the other object is equal to this one. Encrypted strings
|
131
|
+
# will be tested not only on their encrypted strings, but also by
|
132
|
+
# decrypting them and running tests against the decrypted value.
|
133
|
+
#
|
134
|
+
# == Equality with strings
|
135
|
+
#
|
136
|
+
# password = 'shhhh'
|
137
|
+
# password.encrypt! # => "66c85d26dadde7e1db27e15a0776c921e27143bd"
|
138
|
+
# password # => "66c85d26dadde7e1db27e15a0776c921e27143bd"
|
139
|
+
# password == "shhhh" # => true
|
140
|
+
#
|
141
|
+
# == Equality with encrypted strings
|
142
|
+
#
|
143
|
+
# password = 'shhhh'
|
144
|
+
# password.encrypt! # => "66c85d26dadde7e1db27e15a0776c921e27143bd"
|
145
|
+
# password # => "66c85d26dadde7e1db27e15a0776c921e27143bd"
|
146
|
+
# password == 'shhhh' # => true
|
147
|
+
#
|
148
|
+
# another_password = 'shhhh'
|
149
|
+
# another_password.encrypt! # => "66c85d26dadde7e1db27e15a0776c921e27143bd"
|
150
|
+
# password == another_password # => true
|
151
|
+
def equals_with_encryption(other)
|
152
|
+
if !(is_equal = equals_without_encryption(other)) && String === other
|
153
|
+
if encrypted?
|
154
|
+
if other.encrypted?
|
155
|
+
# We're both encrypted, so check if:
|
156
|
+
# (1) The other string is the encrypted value of this string
|
157
|
+
# (2) This string is the encrypted value of the other string
|
158
|
+
# (3) The other string is the encrypted value of this string, decrypted
|
159
|
+
# (4) This string is the encrypted value of the other string, decrypted
|
160
|
+
is_string_equal?(self, other) || is_string_equal?(other, self) || self.can_decrypt? && is_string_equal?(self.decrypt, other) || other.can_decrypt? && is_string_equal?(other.decrypt, self)
|
161
|
+
else
|
162
|
+
# Only we're encrypted
|
163
|
+
is_string_equal?(other, self)
|
164
|
+
end
|
165
|
+
else
|
166
|
+
if other.encrypted?
|
167
|
+
# Only the other string is encrypted
|
168
|
+
is_string_equal?(self, other)
|
169
|
+
else
|
170
|
+
# Neither are encrypted and equality test didn't work before, so
|
171
|
+
# they can't be equal
|
172
|
+
false
|
173
|
+
end
|
174
|
+
end
|
175
|
+
else
|
176
|
+
# The other value wasn't a string, so we can't check encryption equality
|
177
|
+
is_equal
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
private
|
182
|
+
def is_string_equal?(value, encrypted_value) #:nodoc:
|
183
|
+
# If the encrypted value can be decrypted, then test against the decrypted value
|
184
|
+
if encrypted_value.can_decrypt?
|
185
|
+
encrypted_value.decrypt.equals_without_encryption(value)
|
186
|
+
else
|
187
|
+
# Otherwise encrypt this value based on the cipher used on the encrypted value
|
188
|
+
# and test the equality of those strings
|
189
|
+
encrypted_value.equals_without_encryption(encrypted_value.cipher.encrypt(value))
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Builds the cipher to use from the given arguments
|
194
|
+
def cipher_from_args(*args) #:nodoc:
|
195
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
196
|
+
name = (args.first || :sha).to_s.gsub(/(?:^|_)(.)/) {$1.upcase}
|
197
|
+
EncryptedStrings.const_get("#{name}Cipher").new(options)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
::String.class_eval do
|
204
|
+
include EncryptedStrings::Extensions::String
|
205
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
|
3
|
+
module EncryptedStrings
|
4
|
+
# Encrypts a string using a Secure Hash Algorithm (SHA), specifically SHA-1.
|
5
|
+
#
|
6
|
+
# == Encrypting
|
7
|
+
#
|
8
|
+
# To encrypt a string using an SHA cipher, the salt used to seed the
|
9
|
+
# algorithm must be specified. You can define the default for this value
|
10
|
+
# like so:
|
11
|
+
#
|
12
|
+
# EncryptedStrings::ShaCipher.default_salt = 'secret'
|
13
|
+
#
|
14
|
+
# If these configuration options are not passed in to #encrypt, then the
|
15
|
+
# default values will be used. You can override the default values like so:
|
16
|
+
#
|
17
|
+
# password = 'shhhh'
|
18
|
+
# password.encrypt(:sha, :salt => 'secret') # => "ae645b35bb5dfea6c9133ac872e6adfa92a3c2bd"
|
19
|
+
#
|
20
|
+
# == Decrypting
|
21
|
+
#
|
22
|
+
# SHA-encrypted strings cannot be decrypted. The only way to determine
|
23
|
+
# whether an unencrypted value is equal to an SHA-encrypted string is to
|
24
|
+
# encrypt the value with the same salt. For example,
|
25
|
+
#
|
26
|
+
# password = 'shhhh'.encrypt(:sha, :salt => 'secret') # => "3b22cbe4acde873c3efc82681096f3ae69aff828"
|
27
|
+
# input = 'shhhh'.encrypt(:sha, :salt => 'secret') # => "3b22cbe4acde873c3efc82681096f3ae69aff828"
|
28
|
+
# password == input # => true
|
29
|
+
class ShaCipher < Cipher
|
30
|
+
class << self
|
31
|
+
# The default salt value to use during encryption
|
32
|
+
attr_accessor :default_salt
|
33
|
+
end
|
34
|
+
|
35
|
+
# Set defaults
|
36
|
+
@default_salt = 'salt'
|
37
|
+
|
38
|
+
# The salt value to use for encryption
|
39
|
+
attr_accessor :salt
|
40
|
+
|
41
|
+
# Creates a new cipher that uses an SHA encryption strategy.
|
42
|
+
#
|
43
|
+
# Configuration options:
|
44
|
+
# * <tt>:salt</tt> - Random bytes used as one of the inputs for generating
|
45
|
+
# the encrypted string
|
46
|
+
def initialize(options = {})
|
47
|
+
invalid_options = options.keys - [:salt]
|
48
|
+
raise ArgumentError, "Unknown key(s): #{invalid_options.join(", ")}" unless invalid_options.empty?
|
49
|
+
|
50
|
+
options = {:salt => ShaCipher.default_salt}.merge(options)
|
51
|
+
|
52
|
+
self.salt = options[:salt].to_s
|
53
|
+
|
54
|
+
super()
|
55
|
+
end
|
56
|
+
|
57
|
+
# Decryption is not supported
|
58
|
+
def can_decrypt?
|
59
|
+
false
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns the encrypted value of the data
|
63
|
+
def encrypt(data)
|
64
|
+
Digest::SHA1.hexdigest(data + salt)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module EncryptedStrings
|
2
|
+
# Indicates no password was specified for the symmetric cipher
|
3
|
+
class NoPasswordError < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
# Symmetric encryption uses a specific algorithm and password to encrypt
|
7
|
+
# the string. As long as the algorithm and password are known, the string
|
8
|
+
# can be decrypted.
|
9
|
+
#
|
10
|
+
# Source: http://support.microsoft.com/kb/246071
|
11
|
+
#
|
12
|
+
# == Encrypting
|
13
|
+
#
|
14
|
+
# To encrypt a string using a symmetric cipher, the algorithm and password
|
15
|
+
# must be specified. You can define the defaults for these values like so:
|
16
|
+
#
|
17
|
+
# EncryptedStrings::SymmetricCipher.default_algorithm = 'des-ecb'
|
18
|
+
# EncryptedStrings::SymmetricCipher.default_password = 'secret'
|
19
|
+
#
|
20
|
+
# If these configuration options are not passed in to #encrypt, then the
|
21
|
+
# default values will be used. You can override the default values like so:
|
22
|
+
#
|
23
|
+
# password = 'shhhh'
|
24
|
+
# password.encrypt(:symmetric, :algorithm => 'des-ecb', :password => 'secret') # => "S/sEkViX3v4=\n"
|
25
|
+
#
|
26
|
+
# An exception will be raised if no password is specified.
|
27
|
+
#
|
28
|
+
# == Decrypting
|
29
|
+
#
|
30
|
+
# To decrypt a string using an symmetric cipher, the algorithm and password
|
31
|
+
# must be specified. Defaults for these values can be defined as show above.
|
32
|
+
#
|
33
|
+
# If these configuration options are not passed in to #decrypt, then the
|
34
|
+
# default values will be used. You can override the default values like so:
|
35
|
+
#
|
36
|
+
# password = "S/sEkViX3v4=\n"
|
37
|
+
# password.decrypt(:symmetric, :algorithm => 'des-ecb', :password => 'secret') # => "shhhh"
|
38
|
+
#
|
39
|
+
# An exception will be raised if no password is specified.
|
40
|
+
class SymmetricCipher < Cipher
|
41
|
+
class << self
|
42
|
+
# The default algorithm to use for encryption. Default is DES-EDE3-CBC.
|
43
|
+
attr_accessor :default_algorithm
|
44
|
+
|
45
|
+
# The default password to use for generating the key and initialization
|
46
|
+
# vector. Default is nil.
|
47
|
+
attr_accessor :default_password
|
48
|
+
end
|
49
|
+
|
50
|
+
# Set default values
|
51
|
+
@default_algorithm = 'DES-EDE3-CBC'
|
52
|
+
|
53
|
+
# The algorithm to use for encryption/decryption
|
54
|
+
attr_accessor :algorithm
|
55
|
+
|
56
|
+
# The password that generates the key/initialization vector for the
|
57
|
+
# algorithm
|
58
|
+
attr_accessor :password
|
59
|
+
|
60
|
+
# Creates a new cipher that uses a symmetric encryption strategy.
|
61
|
+
#
|
62
|
+
# Configuration options:
|
63
|
+
# * <tt>:algorithm</tt> - The algorithm to use for generating the encrypted string
|
64
|
+
# * <tt>:password</tt> - The secret value to use for generating the
|
65
|
+
# key/initialization vector for the algorithm
|
66
|
+
def initialize(options = {})
|
67
|
+
invalid_options = options.keys - [:algorithm, :password]
|
68
|
+
raise ArgumentError, "Unknown key(s): #{invalid_options.join(", ")}" unless invalid_options.empty?
|
69
|
+
|
70
|
+
options = {
|
71
|
+
:algorithm => SymmetricCipher.default_algorithm,
|
72
|
+
:password => SymmetricCipher.default_password
|
73
|
+
}.merge(options)
|
74
|
+
|
75
|
+
self.algorithm = options[:algorithm]
|
76
|
+
self.password = options[:password]
|
77
|
+
raise NoPasswordError if password.nil?
|
78
|
+
|
79
|
+
super()
|
80
|
+
end
|
81
|
+
|
82
|
+
# Decrypts the current string using the current key and algorithm specified
|
83
|
+
def decrypt(data)
|
84
|
+
cipher = build_cipher(:decrypt)
|
85
|
+
cipher.update(data.unpack('m')[0]) + cipher.final
|
86
|
+
end
|
87
|
+
|
88
|
+
# Encrypts the current string using the current key and algorithm specified
|
89
|
+
def encrypt(data)
|
90
|
+
cipher = build_cipher(:encrypt)
|
91
|
+
[cipher.update(data) + cipher.final].pack('m')
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
def build_cipher(type) #:nodoc:
|
96
|
+
cipher = OpenSSL::Cipher::Cipher.new(algorithm).send(type)
|
97
|
+
cipher.pkcs5_keyivgen(password)
|
98
|
+
cipher
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class NoPrivateKeyErrorTest < Test::Unit::TestCase
|
4
|
+
def test_should_exist
|
5
|
+
assert_not_nil EncryptedStrings::NoPrivateKeyError
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class NoPublicKeyErrorTest < Test::Unit::TestCase
|
10
|
+
def test_should_exist
|
11
|
+
assert_not_nil EncryptedStrings::NoPublicKeyError
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class AsymmetricCipherByDefaultTest < Test::Unit::TestCase
|
16
|
+
def setup
|
17
|
+
@asymmetric_cipher = EncryptedStrings::AsymmetricCipher.new(:public_key_file => File.dirname(__FILE__) + '/keys/public')
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_should_raise_an_exception
|
21
|
+
assert_raise(ArgumentError) {EncryptedStrings::AsymmetricCipher.new}
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_should_not_have_a_public_key_file
|
25
|
+
@asymmetric_cipher = EncryptedStrings::AsymmetricCipher.new(:private_key_file => File.dirname(__FILE__) + '/keys/private')
|
26
|
+
assert_nil @asymmetric_cipher.public_key_file
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_should_not_have_a_private_key_file
|
30
|
+
assert_nil @asymmetric_cipher.private_key_file
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_should_not_have_an_algorithm
|
34
|
+
assert_nil @asymmetric_cipher.algorithm
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_should_not_have_a_password
|
38
|
+
assert_nil @asymmetric_cipher.password
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class AsymmetricCipherWithCustomDefaultsTest < Test::Unit::TestCase
|
43
|
+
def setup
|
44
|
+
@original_default_public_key_file = EncryptedStrings::AsymmetricCipher.default_public_key_file
|
45
|
+
@original_default_private_key_file = EncryptedStrings::AsymmetricCipher.default_private_key_file
|
46
|
+
|
47
|
+
EncryptedStrings::AsymmetricCipher.default_public_key_file = File.dirname(__FILE__) + '/keys/public'
|
48
|
+
EncryptedStrings::AsymmetricCipher.default_private_key_file = File.dirname(__FILE__) + '/keys/private'
|
49
|
+
|
50
|
+
@asymmetric_cipher = EncryptedStrings::AsymmetricCipher.new
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_should_use_default_public_key_file
|
54
|
+
assert_equal File.dirname(__FILE__) + '/keys/public', @asymmetric_cipher.public_key_file
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_should_use_default_private_key_file
|
58
|
+
assert_equal File.dirname(__FILE__) + '/keys/private', @asymmetric_cipher.private_key_file
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_should_not_have_an_algorithm
|
62
|
+
assert_nil @asymmetric_cipher.algorithm
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_should_not_have_a_password
|
66
|
+
assert_nil @asymmetric_cipher.password
|
67
|
+
end
|
68
|
+
|
69
|
+
def teardown
|
70
|
+
EncryptedStrings::AsymmetricCipher.default_public_key_file = @original_default_public_key_file
|
71
|
+
EncryptedStrings::AsymmetricCipher.default_private_key_file = @original_default_private_key_file
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class AsymmetricCipherWithInvalidOptionsTest < Test::Unit::TestCase
|
76
|
+
def test_should_throw_an_exception
|
77
|
+
assert_raise(ArgumentError) {EncryptedStrings::AsymmetricCipher.new(:invalid => true)}
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class AsymmetricCipherTest < Test::Unit::TestCase
|
82
|
+
def setup
|
83
|
+
@asymmetric_cipher = EncryptedStrings::AsymmetricCipher.new(:public_key_file => File.dirname(__FILE__) + '/keys/public')
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_should_be_able_to_decrypt
|
87
|
+
assert @asymmetric_cipher.can_decrypt?
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class AsymmetricCipherWithoutPublicKeyTest < Test::Unit::TestCase
|
92
|
+
def setup
|
93
|
+
@asymmetric_cipher = EncryptedStrings::AsymmetricCipher.new(:public_key_file => nil, :private_key_file => File.dirname(__FILE__) + '/keys/private')
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_should_not_be_public
|
97
|
+
assert !@asymmetric_cipher.public?
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_should_not_be_able_to_encrypt
|
101
|
+
assert_raise(EncryptedStrings::NoPublicKeyError) {@asymmetric_cipher.encrypt('test')}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class AsymmetricCipherWithPublicKeyTest < Test::Unit::TestCase
|
106
|
+
def setup
|
107
|
+
@asymmetric_cipher = EncryptedStrings::AsymmetricCipher.new(:public_key_file => File.dirname(__FILE__) + '/keys/public')
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_should_be_public
|
111
|
+
assert @asymmetric_cipher.public?
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_should_not_be_private
|
115
|
+
assert !@asymmetric_cipher.private?
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_should_be_able_to_encrypt
|
119
|
+
assert_equal 90, @asymmetric_cipher.encrypt('test').length
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_should_not_be_able_to_decrypt
|
123
|
+
assert_raise(EncryptedStrings::NoPrivateKeyError) {@asymmetric_cipher.decrypt("HbEh0Hwri26S7SWYqO26DBbzfhR1h/0pXYLjSKUpxF5DOaOCtD9oRN748+Na\nrfNaVN5Eg7RUhbRFZE+UnNHo6Q==\n")}
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class AsymmetricCipherWithoutPrivateKeyTest < Test::Unit::TestCase
|
128
|
+
def setup
|
129
|
+
@asymmetric_cipher = EncryptedStrings::AsymmetricCipher.new(:private_key_file => nil, :public_key_file => File.dirname(__FILE__) + '/keys/public')
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_should_not_be_private
|
133
|
+
assert !@asymmetric_cipher.private?
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_should_not_be_able_to_decrypt
|
137
|
+
assert_raise(EncryptedStrings::NoPrivateKeyError) {@asymmetric_cipher.decrypt("HbEh0Hwri26S7SWYqO26DBbzfhR1h/0pXYLjSKUpxF5DOaOCtD9oRN748+Na\nrfNaVN5Eg7RUhbRFZE+UnNHo6Q==\n")}
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class AsymmetricCipherWithPrivateKeyTest < Test::Unit::TestCase
|
142
|
+
def setup
|
143
|
+
@asymmetric_cipher = EncryptedStrings::AsymmetricCipher.new(:private_key_file => File.dirname(__FILE__) + '/keys/private')
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_should_not_be_public
|
147
|
+
assert !@asymmetric_cipher.public?
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_should_be_private
|
151
|
+
assert @asymmetric_cipher.private?
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_not_should_be_able_to_encrypt
|
155
|
+
assert_raise(EncryptedStrings::NoPublicKeyError) {@asymmetric_cipher.encrypt('test')}
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_should_be_able_to_decrypt
|
159
|
+
assert_equal 'test', @asymmetric_cipher.decrypt("HbEh0Hwri26S7SWYqO26DBbzfhR1h/0pXYLjSKUpxF5DOaOCtD9oRN748+Na\nrfNaVN5Eg7RUhbRFZE+UnNHo6Q==\n")
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
class AsymmetricCipherWithEncryptedPrivateKeyTest < Test::Unit::TestCase
|
164
|
+
def setup
|
165
|
+
@asymmetric_cipher = EncryptedStrings::AsymmetricCipher.new(:private_key_file => File.dirname(__FILE__) + '/keys/encrypted_private', :algorithm => 'DES-EDE3-CBC', :password => 'secret')
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_should_not_be_public
|
169
|
+
assert !@asymmetric_cipher.public?
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_should_be_private
|
173
|
+
assert @asymmetric_cipher.private?
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_should_not_be_able_to_encrypt
|
177
|
+
assert_raise(EncryptedStrings::NoPublicKeyError) {@asymmetric_cipher.encrypt('test')}
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_should_be_able_to_decrypt
|
181
|
+
assert_equal 'test', @asymmetric_cipher.decrypt("HbEh0Hwri26S7SWYqO26DBbzfhR1h/0pXYLjSKUpxF5DOaOCtD9oRN748+Na\nrfNaVN5Eg7RUhbRFZE+UnNHo6Q==\n")
|
182
|
+
end
|
183
|
+
end
|