secure_string 0.9.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +137 -1
- data/lib/secure_string.rb +1 -1
- data/lib/secure_string/base64_methods.rb +4 -0
- data/lib/secure_string/cipher_methods.rb +22 -5
- data/lib/secure_string/digest_methods.rb +9 -0
- data/lib/secure_string/rsa_methods.rb +15 -2
- data/spec/base64_methods_spec.rb +46 -0
- data/spec/cipher_methods_spec.rb +128 -0
- data/spec/digest_methods_spec.rb +121 -0
- data/spec/rsa_methods_spec.rb +166 -0
- data/spec/secure_string_spec.rb +90 -0
- data/spec/spec_helper.rb +17 -1
- metadata +8 -3
data/README.rdoc
CHANGED
@@ -9,6 +9,127 @@ functionality that can be used individually:
|
|
9
9
|
* Secure string support: Easy methods for RSA encryption, AES encoding, and
|
10
10
|
SHA/MD5 digest hashing, of the data in the strings.
|
11
11
|
|
12
|
+
One of the basic philosophies of SecureString is that it does not override--only
|
13
|
+
extends--the feature set of String. However there is one difference that
|
14
|
+
was added: +inspect+ is overridden to return the data as a hex-string, rather
|
15
|
+
than using the specified character encoding. This does not mean it's value has
|
16
|
+
in any way changed, just its presentation. Use +to_s+ to recover the standard
|
17
|
+
String version of the value.
|
18
|
+
|
19
|
+
WARNING: it is important to note that the String method +length+ is not a good
|
20
|
+
measure of a byte string's length, as depending on the encoding, it may count
|
21
|
+
multibyte characters as a single element. To ensure that you get the byte
|
22
|
+
length, use the standard string method +bytesize+.
|
23
|
+
|
24
|
+
= Examples
|
25
|
+
|
26
|
+
== Basic Usage
|
27
|
+
|
28
|
+
Creation of a SecureString from an normal String instance is easy:
|
29
|
+
|
30
|
+
ss = SecureString.new("Hello World!")
|
31
|
+
ss.to_s --> "Hello World!"
|
32
|
+
ss.inspect --> "<48656c6c6f20576f726c6421>"
|
33
|
+
|
34
|
+
Additionally, you can get at the byte data in various ways:
|
35
|
+
|
36
|
+
ss.to_hex --> "48656c6c6f20576f726c6421"
|
37
|
+
ss.to_i --> 22405534230753928650781647905
|
38
|
+
ss.to_base64 --> "SGVsbG8gV29ybGQh"
|
39
|
+
|
40
|
+
One can initialize a SecureString from any of these types like so:
|
41
|
+
|
42
|
+
ss1 = SecureString.new(:data, "Hello World!")
|
43
|
+
ss2 = SecureString.new(:hex, "48656c6c6f20576f726c6421")
|
44
|
+
ss3 = SecureString.new(:int, 22405534230753928650781647905)
|
45
|
+
ss4 = SecureString.new(:base64, "SGVsbG8gV29ybGQh")
|
46
|
+
|
47
|
+
ss1 == ss --> true
|
48
|
+
ss2 == ss --> true
|
49
|
+
ss3 == ss --> true
|
50
|
+
ss4 == ss --> true
|
51
|
+
|
52
|
+
All of these create equal-valued strings to <tt>"HelloWorld!"</tt>.
|
53
|
+
|
54
|
+
== Base64 Methods Overview
|
55
|
+
|
56
|
+
The SecureString::Base64Methods module adds +to_base64+, which we've seen:
|
57
|
+
|
58
|
+
SecureString.new("Hello World!").to_base64 --> "SGVsbG8gV29ybGQh"
|
59
|
+
|
60
|
+
It also adds +from_base64+, which can decode a Base64 encoded string. The
|
61
|
+
following example shows the various ways of decoding Bas64 data:
|
62
|
+
|
63
|
+
SecureString.new(:base64, "SGVsbG8gV29ybGQh") == "Hello World!" --> true
|
64
|
+
SecureString.new("SGVsbG8gV29ybGQh") == "Hello World!" --> false
|
65
|
+
SecureString.new("SGVsbG8gV29ybGQh").from_base64 == "Hello World!" --> true
|
66
|
+
|
67
|
+
== Digest Methods Overview
|
68
|
+
|
69
|
+
The SecureString::DigestMethods module adds convenience methods for calculating
|
70
|
+
cryptographic hash sums for the data in the string. Note that since SecureString
|
71
|
+
handles binary data well, the string value returns is NOT the hex string; to get
|
72
|
+
the hex digest, simply call to_hex:
|
73
|
+
|
74
|
+
ss.to_md5.to_hex
|
75
|
+
--> "ed076287532e86365e841e92bfc50d8c"
|
76
|
+
ss.to_sha1.to_hex
|
77
|
+
--> "2ef7bde608ce5404e97d5f042f95f89f1c232871"
|
78
|
+
ss.to_sha256.to_hex
|
79
|
+
--> "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"
|
80
|
+
ss.to_digest(OpenSSL::Digest::SHA512).to_hex
|
81
|
+
--> "861844d6704e8573fec34d967e20bcfef3d424cf48be04e6dc08f2bd58c729743371015ead891cc3cf1c9d34b49264b510751b1ff9e537937bc46b5d6ff4ecc8"
|
82
|
+
|
83
|
+
== RSA Methods Overview
|
84
|
+
|
85
|
+
The SecureString::RSAMethods module adds convenience methods for RSA key
|
86
|
+
generation, encryption, and signing, and verification.
|
87
|
+
|
88
|
+
The basic features of this module are illustrated on the following worked example:
|
89
|
+
|
90
|
+
First, alice and bob much each generate their public and private keys. For the
|
91
|
+
example, we do it like so:
|
92
|
+
|
93
|
+
alice_pvt_key, alice_pub_key = SecureString.rsa_keygen
|
94
|
+
bob_pvt_key, bob_pub_key = SecureString.rsa_keygen
|
95
|
+
|
96
|
+
Now, Alice creates a message and encrypts it for Bob and signs it.
|
97
|
+
|
98
|
+
message = SecureString.new("Hello World")
|
99
|
+
encrypted_message = message.to_rsa(bob_pub_key)
|
100
|
+
signature = encrypted_message.sign(alice_pvt_key)
|
101
|
+
|
102
|
+
Alice sends Bob the data in +encrypted_message+ and +signature+. Bob verifies
|
103
|
+
the message's signature, and then decrypts it:
|
104
|
+
|
105
|
+
is_verified = encrypted_message.verify?(alice_pub_key, signature)
|
106
|
+
if( is_verified )
|
107
|
+
decrypted_message = encrypted_message.from_rsa(bob_pvt_key).to_s
|
108
|
+
else
|
109
|
+
raise RuntimeError, "This is not from Alice!"
|
110
|
+
end
|
111
|
+
|
112
|
+
The value of Alice's original +message+ variable, and Bob's +decrypted_message+
|
113
|
+
should be identical.
|
114
|
+
|
115
|
+
== Cipher Methods Overview
|
116
|
+
|
117
|
+
The SecureString::CipherMethods module adds convenience methods for block cipher
|
118
|
+
encryption, particularly for the AES-256-CBC block cipher.
|
119
|
+
|
120
|
+
The following methods illustrate a sample session for the default AES-256-CBC
|
121
|
+
cipher:
|
122
|
+
|
123
|
+
# Generate a random key and initialization vector.
|
124
|
+
key, iv = SecureString.aes_keygen
|
125
|
+
|
126
|
+
# Now encrypt a message:
|
127
|
+
message = SecureString.new("Hello World!")
|
128
|
+
cipher_text = message.to_aes(key, iv)
|
129
|
+
|
130
|
+
# Now decrypt the message:
|
131
|
+
decoded_text = cipher_text.from_aes(key, iv)
|
132
|
+
|
12
133
|
= Contact
|
13
134
|
|
14
135
|
If you have any questions, comments, concerns, patches, or bugs, you can contact
|
@@ -21,7 +142,13 @@ or directly via e-mail at:
|
|
21
142
|
mailto:jeff@paploo.net
|
22
143
|
|
23
144
|
= Version History
|
24
|
-
|
145
|
+
[1.0.0 - 2010-Nov-04] Added Tests, Examples, and Bugfixes
|
146
|
+
* Added a full suite of spec tests.
|
147
|
+
* (FEATURE) Can get a list of supported ciphers.
|
148
|
+
* (FEATURE) Auto-determine AES key length in +to_aes+ and +from_aes+.
|
149
|
+
* (CHANGE) RSA now defaults to 2048-bit keys instead of just 1024.
|
150
|
+
* (FIX) Init from integer works now.
|
151
|
+
* (FIX) RSA signatures can take digest classes, not just instances.
|
25
152
|
[0.9.0 - 2010-Nov-03] Initial release.
|
26
153
|
* Feature complete, but lacks spec tests and examples.
|
27
154
|
|
@@ -29,6 +156,15 @@ mailto:jeff@paploo.net
|
|
29
156
|
|
30
157
|
* Add complete spec tests.
|
31
158
|
* Add examples.
|
159
|
+
* Pull out all methods into modules so that it can be an extension of all Strings.
|
160
|
+
* Add a +to_ss+ or +to_secure+ method to String for easy conversion.
|
161
|
+
* to_digest should be able to take a string that is the algorithm name.
|
162
|
+
* Explore how encodings affect the data. What about when finding length? What
|
163
|
+
methods should be recommended to users for finding byte-length vs. char length.
|
164
|
+
* RSA encoding/decoding should auto-detect if the given key is public or private,
|
165
|
+
and use the correct encoding routine? What about key confusion?
|
166
|
+
* RSA signature digests: accept Digest hashes, not just OpenSSL::Digest hashes.
|
167
|
+
|
32
168
|
|
33
169
|
= License
|
34
170
|
|
data/lib/secure_string.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
require 'base64'
|
2
2
|
|
3
3
|
class SecureString < String
|
4
|
+
# Adds methods for Base64 conversion.
|
5
|
+
# See Base64Methods::InstanceMethods for more details.
|
4
6
|
module Base64Methods
|
5
7
|
|
6
8
|
def self.included(mod)
|
7
9
|
mod.send(:include, InstanceMethods)
|
8
10
|
end
|
9
11
|
|
12
|
+
# Adds instance methods for Base64 support via inclusion of
|
13
|
+
# SecureString::Base64Methods to a class.
|
10
14
|
module InstanceMethods
|
11
15
|
|
12
16
|
# Encodes to Base64. By default, the output is made URL safe, which means all
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'openssl'
|
2
2
|
|
3
3
|
class SecureString < String
|
4
|
+
# Adds methods for OpenSSL::Cipher support including AES encryption.
|
5
|
+
# See CipherMethods::ClassMethods and CipherMethods::InstanceMethods for more details.
|
4
6
|
module CipherMethods
|
5
7
|
|
6
8
|
def self.included(mod)
|
@@ -8,12 +10,20 @@ class SecureString < String
|
|
8
10
|
mod.send(:include, InstanceMethods)
|
9
11
|
end
|
10
12
|
|
13
|
+
# Adds class methods for OpenSSL::Cipher support, including AES encryption,
|
14
|
+
# via inclusion of SecureString::CipherMethods into a class.
|
11
15
|
module ClassMethods
|
12
16
|
|
17
|
+
# Returns a list of supported ciphers. These can be passed directly into
|
18
|
+
# the cipher methods.
|
19
|
+
def supported_ciphers
|
20
|
+
return OpenSSL::Cipher.ciphers
|
21
|
+
end
|
22
|
+
|
13
23
|
# A convenience method for generating random cipher keys and initialization
|
14
24
|
# vectors.
|
15
25
|
def cipher_keygen(cipher_name)
|
16
|
-
cipher = OpenSSL::Cipher
|
26
|
+
cipher = OpenSSL::Cipher.new(cipher_name)
|
17
27
|
cipher.encrypt
|
18
28
|
return [cipher.random_key, cipher.random_iv].map {|s| self.new(s)}
|
19
29
|
end
|
@@ -26,6 +36,8 @@ class SecureString < String
|
|
26
36
|
|
27
37
|
end
|
28
38
|
|
39
|
+
# Adds instance methods for OpenSSL::Cipher support, including AES encryption,
|
40
|
+
# via inclusion of SecureString::CipherMethods into a class.
|
29
41
|
module InstanceMethods
|
30
42
|
|
31
43
|
# Given an OpenSSL cipher name, a key, and initialization vector,
|
@@ -60,13 +72,18 @@ class SecureString < String
|
|
60
72
|
return self.class.new(msg)
|
61
73
|
end
|
62
74
|
|
63
|
-
# Given an AES key and initialization vector, AES encode the data.
|
64
|
-
|
75
|
+
# Given an AES key and initialization vector, AES-CBC encode the data.
|
76
|
+
#
|
77
|
+
# Note that one normally never wants to use the same key and iv
|
78
|
+
# combination on two different messages as this weakens the security.
|
79
|
+
def to_aes(key, iv)
|
80
|
+
key_len = (key.bytesize * 8)
|
65
81
|
return self.class.new( to_cipher("aes-#{key_len.to_i}-cbc", key, iv) )
|
66
82
|
end
|
67
83
|
|
68
|
-
# Given an AES key and init vector, AES decode the data.
|
69
|
-
def from_aes(key, iv
|
84
|
+
# Given an AES key and init vector, AES-CBC decode the data.
|
85
|
+
def from_aes(key, iv)
|
86
|
+
key_len = (key.bytesize * 8)
|
70
87
|
return self.class.new( from_cipher("aes-#{key_len.to_i}-cbc", key, iv) )
|
71
88
|
end
|
72
89
|
|
@@ -1,12 +1,16 @@
|
|
1
1
|
require 'openssl'
|
2
2
|
|
3
3
|
class SecureString < String
|
4
|
+
# Adds methods for OpenSSL::Digest support.
|
5
|
+
# See DigestMethods::ClassMethods and DigestMethods::InstanceMethods for more details.
|
4
6
|
module DigestMethods
|
5
7
|
|
6
8
|
def self.included(mod)
|
7
9
|
mod.send(:include, InstanceMethods)
|
8
10
|
end
|
9
11
|
|
12
|
+
# Adds instance methods for OpenSSL::Digest support via inclusion of
|
13
|
+
# SecureString::DigestMethods to a class.
|
10
14
|
module InstanceMethods
|
11
15
|
|
12
16
|
# Returns the digest of the byte string as a SecureString, using the passed OpenSSL object.
|
@@ -19,6 +23,11 @@ class SecureString < String
|
|
19
23
|
return to_digest( OpenSSL::Digest::MD5.new )
|
20
24
|
end
|
21
25
|
|
26
|
+
# Returns the SHA1 of the byte string as SecureString
|
27
|
+
def to_sha1
|
28
|
+
return to_digest( OpenSSL::Digest::SHA1.new )
|
29
|
+
end
|
30
|
+
|
22
31
|
# Returns the SHA2 of the byte string as a SecureString.
|
23
32
|
#
|
24
33
|
# By default, this uses the 256 bit SHA2, but the optional arugment allows
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'openssl'
|
2
2
|
|
3
3
|
class SecureString < String
|
4
|
+
# Adds methods for OpenSSL::PKey::RSA support.
|
5
|
+
# See RSAMethods::ClassMethods and RSAMethods::InstanceMethods for more details.
|
4
6
|
module RSAMethods
|
5
7
|
|
6
8
|
def self.included(mod)
|
@@ -8,15 +10,22 @@ class SecureString < String
|
|
8
10
|
mod.send(:include, InstanceMethods)
|
9
11
|
end
|
10
12
|
|
13
|
+
# Adds class methods for OpenSSL::PKey::RSA support via inclusion of
|
14
|
+
# SecureString::RSAMethods to a class.
|
11
15
|
module ClassMethods
|
12
16
|
|
13
17
|
# A convenience method for generating random public/private RSA key pairs.
|
14
|
-
# Defaults to a key length of 1024
|
18
|
+
# Defaults to a key length of 2048, as 1024 is starting to be phased out
|
19
|
+
# as the standard for secure communications.
|
15
20
|
#
|
16
21
|
# Returns the private key first, then the public key. Returns them in PEM file
|
17
22
|
# format by default, as this is most useful for portability. DER format can
|
18
23
|
# be explicitly specified with the second argument.
|
19
|
-
|
24
|
+
#
|
25
|
+
# For advanced usage of keys, instantiate an OpenSSL::PKey::RSA object
|
26
|
+
# passing the returned key as the argument to +new+. This will allow
|
27
|
+
# introspection of common parameters such as p, q, n, e, and d.
|
28
|
+
def rsa_keygen(key_len=2048, format = :pem)
|
20
29
|
private_key_obj = OpenSSL::PKey::RSA.new(key_len.to_i)
|
21
30
|
public_key_obj = private_key_obj.public_key
|
22
31
|
formatting_method = (format == :der ? :to_der : :to_pem)
|
@@ -25,6 +34,8 @@ class SecureString < String
|
|
25
34
|
|
26
35
|
end
|
27
36
|
|
37
|
+
# Adds instance methods for OpenSSL::PKey::RSA support via inclusion of
|
38
|
+
# SecureString::RSAMethods to a class.
|
28
39
|
module InstanceMethods
|
29
40
|
|
30
41
|
# Given an RSA public key, it RSA encrypts the data string.
|
@@ -46,6 +57,7 @@ class SecureString < String
|
|
46
57
|
#
|
47
58
|
# By default, signs using SHA256, but another digest object can be given.
|
48
59
|
def sign(private_key, digest_obj=OpenSSL::Digest::SHA256.new)
|
60
|
+
digest_obj = (digest_obj.kind_of?(Class) ? digest_obj.new : digest_obj)
|
49
61
|
key = OpenSSL::PKey::RSA.new(private_key)
|
50
62
|
return self.class.new( key.sign(digest_obj, self) )
|
51
63
|
end
|
@@ -55,6 +67,7 @@ class SecureString < String
|
|
55
67
|
#
|
56
68
|
# By default, verifies using SHA256, but another digest object can be given.
|
57
69
|
def verify?(public_key, signature, digest_obj=OpenSSL::Digest::SHA256.new)
|
70
|
+
digest_obj = (digest_obj.kind_of?(Class) ? digest_obj.new : digest_obj)
|
58
71
|
key = OpenSSL::PKey::RSA.new(public_key)
|
59
72
|
return key.verify(digest_obj, signature.to_s, self)
|
60
73
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "SecureString" do
|
4
|
+
|
5
|
+
describe "Base64 Methods" do
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
@messages = MESSAGES
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should convert self to Base64; not URL safe' do
|
12
|
+
@messages.each do |message|
|
13
|
+
ss = SecureString.new(message[:string])
|
14
|
+
# First make sure that line feeds are being put in somewhere.
|
15
|
+
ss.to_base64(false).should include("\n")
|
16
|
+
# Now, compare the data itself (no line-feeds).
|
17
|
+
ss.to_base64(false).delete("\n").should == message[:base64].delete("\n")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should convert self to Base64; URL safe' do
|
22
|
+
@messages.each do |message|
|
23
|
+
ss = SecureString.new(message[:string])
|
24
|
+
# First make sure that there are no line feeds.
|
25
|
+
ss.to_base64(true).should_not include("\n")
|
26
|
+
# Now compare the result with the line-feed less expected value.
|
27
|
+
ss.to_base64(true).should == message[:base64].delete("\n")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should default to URL safe' do
|
32
|
+
@messages.each do |message|
|
33
|
+
ss = SecureString.new(message[:string])
|
34
|
+
ss.to_base64.should == ss.to_base64(true)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should convert self from Base64' do
|
39
|
+
@messages.each do |message|
|
40
|
+
ss = SecureString.new(message[:base64])
|
41
|
+
ss.from_base64.should == message[:string]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
describe "SecureString" do
|
2
|
+
|
3
|
+
describe "Cipher Methods" do
|
4
|
+
|
5
|
+
describe "Keygen" do
|
6
|
+
|
7
|
+
it 'should provide a keygen helper' do
|
8
|
+
SecureString.should respond_to(:cipher_keygen)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should provide generated keys as a SecureString class' do
|
12
|
+
key, iv = SecureString.cipher_keygen('DES')
|
13
|
+
|
14
|
+
key.should_not be_nil
|
15
|
+
iv.should_not be_nil
|
16
|
+
|
17
|
+
key.should be_kind_of(SecureString)
|
18
|
+
iv.should be_kind_of(SecureString)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should provide an AES keygen helper' do
|
22
|
+
SecureString.should respond_to(:aes_keygen)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should provide generated AES keysas a SecureString class' do
|
26
|
+
key, iv = SecureString.aes_keygen
|
27
|
+
|
28
|
+
key.should_not be_nil
|
29
|
+
iv.should_not be_nil
|
30
|
+
|
31
|
+
key.should be_kind_of(SecureString)
|
32
|
+
iv.should be_kind_of(SecureString)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should provide AES keys of various bit lengths' do
|
36
|
+
[128,192,256].each do |bits|
|
37
|
+
key, iv = SecureString.aes_keygen(bits)
|
38
|
+
(key.bytesize * 8).should == bits
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should raise an exception in an invalid AES bit length' do
|
43
|
+
lambda {SecureString.aes_keygen(1234)}.should raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should default to a 256 bit AES key' do
|
47
|
+
key, iv = SecureString.aes_keygen
|
48
|
+
(key.bytesize * 8).should == 256
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should provide a list of supported ciphers' do
|
52
|
+
SecureString.should respond_to(:supported_ciphers)
|
53
|
+
SecureString.supported_ciphers.should be_kind_of(Array)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "Cipher" do
|
59
|
+
|
60
|
+
before(:all) do
|
61
|
+
@cipher = "DES"
|
62
|
+
@key = SecureString.new(:hex, "4f42383e091ffc44")
|
63
|
+
@iv = SecureString.new(:hex, "0b9299d6c2cb5003")
|
64
|
+
@message = SecureString.new("We the People of the United States, in Order to form a more perfect Union, establish Justice, insure domestic Tranquility, provide for the common defence, promote the general Welfare, and secure the Blessings of Liberty to ourselves and our Posterity, do ordain and establish this Constitution for the United States of America.")
|
65
|
+
@encoded_message = SecureString.new(:hex, "cfe8245b2c1f3f789b8ab78930c9582d1fead6792d8fe7efd418ba06d7da4e96f8525e8b437cf29af71ec66801c2031292fc17d88f5aaa9c776b3ca048169b48394e05d5ae6cbba5c78461a25bc3d5abc646f5f760e3a159b8448d79eed80a209473ca67536ebf417a24f05cf029e9e3ca5b1fb22e4e03427705d79b622d720c7d64cf3621319581a1a89b4cbb630611eea29cbd2c48caef0cf774ea0218b16d600cb4c025dcae177b702040bd7c62569bbda33f8e775dbadba4154074f482385c56449882efa31b908dfe5be17d8c0d220fd99414a78f6ce3cfee007fbd5dfc7fd50c343e6118d1a9174bb75db7c5adbaa558010f56571d087982ae791960c31041bae08adfa4d1a88f457897e38bd56a7e92234d21c8742fa577878b2d65500877d2f910d1fdbb5460afa73642778de8bd4442981baa93a481482f1cfb90fa85025ddf8588ecc7")
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should encode to a SecureString' do
|
69
|
+
@message.to_cipher(@cipher, @key, @iv).should be_kind_of(SecureString)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should encode with a given cipher and key' do
|
73
|
+
encoded_message = @message.to_cipher(@cipher, @key, @iv)
|
74
|
+
encoded_message.should == @encoded_message
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should decode to a secure string' do
|
78
|
+
@encoded_message.from_cipher(@cipher, @key, @iv).should be_kind_of(SecureString)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should decode with a given cipher and key' do
|
82
|
+
decoded_message = @encoded_message.from_cipher(@cipher, @key, @iv)
|
83
|
+
decoded_message.should == @message
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "AES" do
|
89
|
+
|
90
|
+
before(:all) do
|
91
|
+
@key = SecureString.new(:hex, "83f8577c1bc406e85ceeebc166c9fd4d087670de792b0d957c58f1beae6fb514")
|
92
|
+
@iv = SecureString.new(:hex, "778c1086b5daf809e7abadde6995219d")
|
93
|
+
@message = SecureString.new("We the People of the United States, in Order to form a more perfect Union, establish Justice, insure domestic Tranquility, provide for the common defence, promote the general Welfare, and secure the Blessings of Liberty to ourselves and our Posterity, do ordain and establish this Constitution for the United States of America.")
|
94
|
+
@encoded_message = SecureString.new(:hex, "1fee4d01d33daf50915dc4b7aaf8b536f3b19ee9798b21200d475925460fd3aabc581d89e560b7b826e6017e02911687425d9c4a781d8e03a9d75dab5a85191f86b11fb74063133c3952201a8f2089afb0e298e29fe8becbe93ce110073b9abb968a268857aaabd94caa760fa402ce803f8643ad8870e77714b093e9ea09a4ad9d7e056836939f614a61f6b3e09057bc05f13432aa53cfc7de59d41a121f9fcb7c51825da2615c48debff6ed0fbaa0c85594aef54e11b73b8766f6e56d2cf7488909c14272e846cccca0008599bae334c5d404c122d286dcf04eec7b7711978686a66182f53e569297b91c25100ecfdad1f02de444c4de8f9d04067e885a2a17cad707b51ea8c2e8a15051138de617f8864cca8a4d201246a97b95cee5f78f742aace79629e03498f63b6385cff64d53a0425f7f52c6a8ba65771e043590b61191804fe91760e617412d842831928e57")
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should encode to a SecureString' do
|
98
|
+
@message.to_aes(@key, @iv).should be_kind_of(SecureString)
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should encode with a key' do
|
102
|
+
encoded_message = @message.to_aes(@key, @iv)
|
103
|
+
encoded_message.should == @encoded_message
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should decode to a secure string' do
|
107
|
+
@encoded_message.from_aes(@key, @iv).should be_kind_of(SecureString)
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should decode with a key' do
|
111
|
+
decoded_message = @encoded_message.from_aes(@key, @iv)
|
112
|
+
decoded_message.should == @message
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should encode and decode from a non 256 bit key' do
|
116
|
+
key, iv = SecureString.aes_keygen(128)
|
117
|
+
encoded_message = @message.to_aes(key, iv)
|
118
|
+
decoded_message = encoded_message.from_aes(key, iv)
|
119
|
+
|
120
|
+
encoded_message.should_not == decoded_message
|
121
|
+
decoded_message.should == @message
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# Make sure to test that the cipher methods are from openssl and not jsut digest?
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
4
|
+
|
5
|
+
describe "SecureString" do
|
6
|
+
|
7
|
+
describe "Digest Methods" do
|
8
|
+
|
9
|
+
describe "to_digest" do
|
10
|
+
|
11
|
+
before(:all) do
|
12
|
+
@openssl_digest_class_sample = [OpenSSL::Digest::MD5, OpenSSL::Digest::SHA1, OpenSSL::Digest::SHA256, OpenSSL::Digest::SHA512]
|
13
|
+
@digest_class_sample = [Digest::MD5, Digest::SHA1, Digest::SHA256, Digest::SHA512]
|
14
|
+
|
15
|
+
@message = SecureString.new("Hello World!")
|
16
|
+
@message_md5_hex = "ed076287532e86365e841e92bfc50d8c"
|
17
|
+
@message_sha512_hex = "861844d6704e8573fec34d967e20bcfef3d424cf48be04e6dc08f2bd58c729743371015ead891cc3cf1c9d34b49264b510751b1ff9e537937bc46b5d6ff4ecc8"
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should encode as a SecureString' do
|
21
|
+
@message.to_digest(OpenSSL::Digest::MD5).should be_kind_of(SecureString)
|
22
|
+
@message.to_digest(OpenSSL::Digest::SHA512).should be_kind_of(SecureString)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should contain the raw value, not the hex value' do
|
26
|
+
md5 = @message.to_digest(OpenSSL::Digest::MD5)
|
27
|
+
md5.should_not == @message_md5_hex
|
28
|
+
md5.to_hex.should == @message_md5_hex
|
29
|
+
|
30
|
+
sha512 = @message.to_digest(OpenSSL::Digest::SHA512)
|
31
|
+
sha512.should_not == @message_sha512_hex
|
32
|
+
sha512.to_hex.should == @message_sha512_hex
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should take an OpenSSL::Digest class' do
|
36
|
+
@openssl_digest_class_sample.each do |klass|
|
37
|
+
@message.to_digest(klass).to_hex.should == klass.hexdigest(@message)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should take an OpenSSL::Digest instance' do
|
42
|
+
@openssl_digest_class_sample.each do |klass|
|
43
|
+
@message.to_digest(klass.new).to_hex.should == klass.hexdigest(@message)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should take a Digest class' do
|
48
|
+
@digest_class_sample.each do |klass|
|
49
|
+
@message.to_digest(klass).to_hex.should == klass.hexdigest(@message)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should take a Digest instance' do
|
54
|
+
@digest_class_sample.each do |klass|
|
55
|
+
@message.to_digest(klass.new).to_hex.should == klass.hexdigest(@message)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
describe "Convenience Methods" do
|
63
|
+
|
64
|
+
before(:all) do
|
65
|
+
@message = SecureString.new("Hello World!")
|
66
|
+
|
67
|
+
@hex_digests = {
|
68
|
+
:md5 => "ed076287532e86365e841e92bfc50d8c",
|
69
|
+
:sha1 => "2ef7bde608ce5404e97d5f042f95f89f1c232871",
|
70
|
+
:sha256 => "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069",
|
71
|
+
:sha512 => "861844d6704e8573fec34d967e20bcfef3d424cf48be04e6dc08f2bd58c729743371015ead891cc3cf1c9d34b49264b510751b1ff9e537937bc46b5d6ff4ecc8"
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should MD5' do
|
76
|
+
@message.should respond_to(:to_md5)
|
77
|
+
digest = @message.to_md5
|
78
|
+
digest.should be_kind_of(SecureString)
|
79
|
+
digest.to_hex.should == @hex_digests[:md5]
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should SHA1' do
|
83
|
+
@message.should respond_to(:to_sha1)
|
84
|
+
digest = @message.to_sha1
|
85
|
+
digest.should be_kind_of(SecureString)
|
86
|
+
digest.to_hex.should == @hex_digests[:sha1]
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should SHA2-256' do
|
90
|
+
@message.should respond_to(:to_sha256)
|
91
|
+
digest = @message.to_sha256
|
92
|
+
digest.should be_kind_of(SecureString)
|
93
|
+
digest.to_hex.should == @hex_digests[:sha256]
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should SHA2=512' do
|
97
|
+
@message.should respond_to(:to_sha512)
|
98
|
+
digest = @message.to_sha512
|
99
|
+
digest.should be_kind_of(SecureString)
|
100
|
+
digest.to_hex.should == @hex_digests[:sha512]
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should SHA2' do
|
104
|
+
@message.should respond_to(:to_sha2)
|
105
|
+
digest = @message.to_sha2
|
106
|
+
digest.should be_kind_of(SecureString)
|
107
|
+
digest.should == @message.to_sha2(256)
|
108
|
+
|
109
|
+
digest = @message.to_sha2(256)
|
110
|
+
digest.should_not == @hex_digests[:sha256]
|
111
|
+
digest.to_hex.should == @hex_digests[:sha256]
|
112
|
+
|
113
|
+
digest = @message.to_sha2(512)
|
114
|
+
digest.should_not == @hex_digests[:sha512]
|
115
|
+
digest.to_hex.should == @hex_digests[:sha512]
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
describe "SecureString" do
|
2
|
+
|
3
|
+
describe "RSA Methods" do
|
4
|
+
|
5
|
+
describe "Keygen" do
|
6
|
+
|
7
|
+
it 'should generate a public/private key pair' do
|
8
|
+
SecureString.should respond_to(:rsa_keygen)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should generate key pairs of varying length' do
|
12
|
+
[256, 512, 1024, 2048].each do |bits|
|
13
|
+
pvt_key, pub_key = SecureString.rsa_keygen(bits)
|
14
|
+
[pvt_key, pub_key].each do |key|
|
15
|
+
key_obj = OpenSSL::PKey::RSA.new(key)
|
16
|
+
# The bit length of the key is the bit length of the modulus, n.
|
17
|
+
# It turns out that an OpenSSL::PKey::RSA object returns an
|
18
|
+
# OpenSSL::BN object when you get the modulus, which has a nice
|
19
|
+
# little method for getting the number of bytes it is long.
|
20
|
+
key_length_in_bits = key_obj.n.num_bytes * 8
|
21
|
+
key_length_in_bits.should == bits
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should default to a 2048 bit key' do
|
27
|
+
pvt_key, pub_key = SecureString.rsa_keygen
|
28
|
+
[pvt_key, pub_key].each do |key|
|
29
|
+
key_obj = OpenSSL::PKey::RSA.new(key)
|
30
|
+
# The bit length of the key is the bit length of the modulus, n.
|
31
|
+
# It turns out that an OpenSSL::PKey::RSA object returns an
|
32
|
+
# OpenSSL::BN object when you get the modulus, which has a nice
|
33
|
+
# little method for getting the number of bytes it is long.
|
34
|
+
key_length_in_bits = key_obj.n.num_bytes * 8
|
35
|
+
key_length_in_bits.should == 2048
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should return key pairs as SecureString instances' do
|
40
|
+
pvt_key, pub_key = SecureString.rsa_keygen
|
41
|
+
[pvt_key, pub_key].each do |key|
|
42
|
+
key.should be_kind_of(SecureString)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should support both pem and der formats' do
|
47
|
+
[:pem, :der].each do |format|
|
48
|
+
pvt_key, pub_key = SecureString.rsa_keygen(512, format)
|
49
|
+
[pvt_key, pub_key].each do |key|
|
50
|
+
key_obj = OpenSSL::PKey::RSA.new(key)
|
51
|
+
key.should == key_obj.send("to_#{format}".to_sym)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should default to pem format' do
|
57
|
+
pvt_key, pub_key = SecureString.rsa_keygen
|
58
|
+
[pvt_key, pub_key].each do |key|
|
59
|
+
key_obj = OpenSSL::PKey::RSA.new(key)
|
60
|
+
key.should == key_obj.to_pem
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "Encryption" do
|
67
|
+
|
68
|
+
before(:all) do
|
69
|
+
@key_length = 128
|
70
|
+
@pvt_key = SecureString.new(:hex, "2d2d2d2d2d424547494e205253412050524956415445204b45592d2d2d2d2d0a4d47454341514143455143364c704764426d334a78495048513945345537443141674d424141454345474c62517a6e724a6652525762433365474b3561656b430a4351446d633569312f5669666277494a414d37536b4534554b7750624167682b7831316430564274395149494a4648372f346f784a364d4343474e646e3933330a4a43774d0a2d2d2d2d2d454e44205253412050524956415445204b45592d2d2d2d2d0a")
|
71
|
+
@pub_key = SecureString.new(:hex, "2d2d2d2d2d424547494e20525341205055424c4943204b45592d2d2d2d2d0a4d426743455143364c704764426d334a78495048513945345537443141674d424141453d0a2d2d2d2d2d454e4420525341205055424c4943204b45592d2d2d2d2d0a")
|
72
|
+
@message = SecureString.new("Hello")
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should encrypt and decrypt to a SecureString' do
|
76
|
+
encrypted_message = @message.to_rsa(@pub_key)
|
77
|
+
encrypted_message.should be_kind_of(SecureString)
|
78
|
+
decrypted_message = encrypted_message.from_rsa(@pvt_key)
|
79
|
+
decrypted_message.should be_kind_of(SecureString)
|
80
|
+
end
|
81
|
+
|
82
|
+
# We cannot independently test encryption because it changes everytime
|
83
|
+
# thanks to padding generation.
|
84
|
+
it 'should encrypt and decrypy a message' do
|
85
|
+
encrypted_message = @message.to_rsa(@pub_key)
|
86
|
+
(encrypted_message.bytesize * 8).should == @key_length
|
87
|
+
|
88
|
+
decrypted_message = encrypted_message.from_rsa(@pvt_key)
|
89
|
+
decrypted_message.should == @message
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
describe "Verification" do
|
96
|
+
|
97
|
+
before(:all) do
|
98
|
+
@key_length = 1024
|
99
|
+
@alice_pvt_key, @alice_pub_key = SecureString.rsa_keygen(@key_length)
|
100
|
+
@bob_pvt_key, @bob_pub_key = SecureString.rsa_keygen(@key_length)
|
101
|
+
|
102
|
+
@message = SecureString.new("Hello")
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should sign and verify a message using a private key' do
|
106
|
+
# Alice encrypts a message for Bob and signs is.
|
107
|
+
@encrypted_message = @message.to_rsa(@bob_pub_key)
|
108
|
+
@signature = @encrypted_message.sign(@alice_pvt_key)
|
109
|
+
|
110
|
+
# Verify it came from Alice.
|
111
|
+
is_verified = @encrypted_message.verify?(@alice_pub_key, @signature)
|
112
|
+
is_verified.should be_true
|
113
|
+
|
114
|
+
# Verify it did not come from Bob.
|
115
|
+
is_verified = @encrypted_message.verify?(@bob_pub_key, @signature)
|
116
|
+
is_verified.should be_false
|
117
|
+
|
118
|
+
# Bob should now decrypt it
|
119
|
+
@decrypted_message = @encrypted_message.from_rsa(@bob_pvt_key)
|
120
|
+
@decrypted_message.should == @message
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should default to signing with SHA-256' do
|
124
|
+
encrypted_message = @message.to_rsa(@bob_pub_key)
|
125
|
+
encrypted_message.sign(@alice_pvt_key).should == encrypted_message.sign(@alice_pvt_key, OpenSSL::Digest::SHA256.new)
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should allow signing with other digest' do
|
129
|
+
encrypted_message = @message.to_rsa(@bob_pub_key)
|
130
|
+
comparison_digest_klass = OpenSSL::Digest::SHA256
|
131
|
+
[OpenSSL::Digest::SHA512, OpenSSL::Digest::MD5, OpenSSL::Digest::SHA1].each do |digest_klass|
|
132
|
+
next if digest_klass == comparison_digest_klass
|
133
|
+
signature = encrypted_message.sign(@alice_pvt_key, digest_klass.new)
|
134
|
+
signature.should_not == encrypted_message.sign(@alice_pvt_key, comparison_digest_klass.new)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should allow passing the digest method as an instance or class' do
|
139
|
+
encrypted_message = @message.to_rsa(@bob_pub_key)
|
140
|
+
[OpenSSL::Digest::SHA512, OpenSSL::Digest::SHA256, OpenSSL::Digest::MD5, OpenSSL::Digest::SHA1].each do |digest_klass|
|
141
|
+
signature1 = encrypted_message.sign(@alice_pvt_key, digest_klass.new)
|
142
|
+
signature2 = encrypted_message.sign(@alice_pvt_key, digest_klass)
|
143
|
+
signature1.should == signature2
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'should work with Digest scoped digest classes' do
|
148
|
+
pending "TODO: postponing feature"
|
149
|
+
encrypted_message = @message.to_rsa(@bob_pub_key)
|
150
|
+
signature1 = encrypted_message.sign(@alice_pvt_key, Digest::SHA256)
|
151
|
+
signature2 = encrypted_message.sign(@alice_pvt_key, OpenSSL::Digest::SHA256)
|
152
|
+
signature1.should == signature2
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'should work with Digest scoped digest instances' do
|
156
|
+
pending "TODO: postponing feature"
|
157
|
+
encrypted_message = @message.to_rsa(@bob_pub_key)
|
158
|
+
signature1 = encrypted_message.sign(@alice_pvt_key, Digest::SHA256.new)
|
159
|
+
signature2 = encrypted_message.sign(@alice_pvt_key, OpenSSL::Digest::SHA256.new)
|
160
|
+
signature1.should == signature2
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "SecureString" do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
@messages = MESSAGES
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should be a subclass of String' do
|
10
|
+
(SecureString < String).should be_true
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should initialize like a string by default.' do
|
14
|
+
@messages.each do |message|
|
15
|
+
s = String.new(message[:string])
|
16
|
+
ss = SecureString.new(message[:string])
|
17
|
+
ss.should == s
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should initialize from hex' do
|
22
|
+
@messages.each do |message|
|
23
|
+
ss = SecureString.new(:hex, message[:hex])
|
24
|
+
ss.should == message[:string]
|
25
|
+
|
26
|
+
ss = SecureString.new(:hex, message[:hex].upcase)
|
27
|
+
ss.should == message[:string]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should initialize from data' do
|
32
|
+
@messages.each do |message|
|
33
|
+
ss = SecureString.new(:data, message[:string])
|
34
|
+
ss.should == message[:string]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should initialize from int' do
|
39
|
+
@messages.each do |message|
|
40
|
+
ss = SecureString.new(:int, message[:int])
|
41
|
+
ss.should == message[:string]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should initialize from Base64' do
|
46
|
+
@messages.each do |message|
|
47
|
+
ss = SecureString.new(:base64, message[:base64])
|
48
|
+
ss.should == message[:string]
|
49
|
+
end
|
50
|
+
|
51
|
+
# We also want to make sure non newline terminated, and multi-line messages
|
52
|
+
# work right. The sample data should contain at least one with multiple
|
53
|
+
# linefeeds, and one with no linefeeds.
|
54
|
+
newline_count = @messages.map {|message| message[:base64].delete("^\n").length}
|
55
|
+
newline_count.should include(0)
|
56
|
+
newline_count.select {|nl_count| nl_count > 1}.should_not be_empty
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should be able to convert to a hex string' do
|
60
|
+
@messages.each do |message|
|
61
|
+
ss = SecureString.new(message[:string])
|
62
|
+
ss.to_hex.should == message[:hex]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should be able to convert to an int value' do
|
67
|
+
@messages.each do |message|
|
68
|
+
ss = SecureString.new(message[:string])
|
69
|
+
ss.to_i.should == message[:int]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should output like a string for to_s' do
|
74
|
+
@messages.each do |message|
|
75
|
+
s = String.new(message[:string])
|
76
|
+
ss = SecureString.new(message[:string])
|
77
|
+
ss.to_s.should == s.to_s
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should output the hex value with inspect' do
|
82
|
+
@messages.each do |message|
|
83
|
+
s = String.new(message[:string])
|
84
|
+
ss = SecureString.new(message[:string])
|
85
|
+
ss.inspect.should include(ss.to_hex)
|
86
|
+
ss.inspect.should_not include(s.to_s)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,20 @@
|
|
1
1
|
# Add the lib dir to the load path.
|
2
2
|
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
3
3
|
# Require the main require file.
|
4
|
-
require File.basename(File.expand_path(File.join(File.dirname(__FILE__),'..')))
|
4
|
+
require File.basename(File.expand_path(File.join(File.dirname(__FILE__),'..')))
|
5
|
+
|
6
|
+
MESSAGES = [
|
7
|
+
{
|
8
|
+
:string => "Hello",
|
9
|
+
:hex => "48656c6c6f",
|
10
|
+
:int => 310939249775,
|
11
|
+
:base64 => "SGVsbG8="
|
12
|
+
},
|
13
|
+
|
14
|
+
{
|
15
|
+
:string => "This is a test of the emergency broadcast system; this is only a test.",
|
16
|
+
:hex => "5468697320697320612074657374206f662074686520656d657267656e63792062726f6164636173742073797374656d3b2074686973206973206f6e6c79206120746573742e",
|
17
|
+
:int => 1244344095146357680190496293767338268850834164562379171846588371816488740307922111470765515885864931093899586331709567338989540039042962957732585272476408412061178229806,
|
18
|
+
:base64 => "VGhpcyBpcyBhIHRlc3Qgb2YgdGhlIGVtZXJnZW5jeSBicm9hZGNhc3Qgc3lz\ndGVtOyB0aGlzIGlzIG9ubHkgYSB0ZXN0Lg==\n"
|
19
|
+
}
|
20
|
+
].freeze
|
metadata
CHANGED
@@ -3,10 +3,10 @@ name: secure_string
|
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
|
+
- 1
|
6
7
|
- 0
|
7
|
-
- 9
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 1.0.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Jeff Reinecke
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-11-
|
17
|
+
date: 2010-11-04 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -35,6 +35,11 @@ files:
|
|
35
35
|
- lib/secure_string/digest_methods.rb
|
36
36
|
- lib/secure_string/rsa_methods.rb
|
37
37
|
- lib/secure_string.rb
|
38
|
+
- spec/base64_methods_spec.rb
|
39
|
+
- spec/cipher_methods_spec.rb
|
40
|
+
- spec/digest_methods_spec.rb
|
41
|
+
- spec/rsa_methods_spec.rb
|
42
|
+
- spec/secure_string_spec.rb
|
38
43
|
- spec/spec_helper.rb
|
39
44
|
has_rdoc: true
|
40
45
|
homepage: http://www.github.com/paploo/secure_string
|