secure_string 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.txt ADDED
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2010, Jeffrey C. Reinecke
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+ * Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ * Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+ * Neither the name of the copyright holders nor the
12
+ names of its contributors may be used to endorse or promote products
13
+ derived from this software without specific prior written permission.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL JEFFREY REINECKE BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.rdoc ADDED
@@ -0,0 +1,63 @@
1
+ = Overview
2
+
3
+ SecureString is a special string subclass that provides two pieces of
4
+ functionality that can be used individually:
5
+
6
+ * Byte string support: Although a string can already contain bytes, this makes
7
+ it easier to view and work with strings holding binary data, including
8
+ conversion to/from raw hex or Base64 encoded values.
9
+ * Secure string support: Easy methods for RSA encryption, AES encoding, and
10
+ SHA/MD5 digest hashing, of the data in the strings.
11
+
12
+ = Contact
13
+
14
+ If you have any questions, comments, concerns, patches, or bugs, you can contact
15
+ me via the github repository at:
16
+
17
+ http://github.com/paploo/secure_string
18
+
19
+ or directly via e-mail at:
20
+
21
+ mailto:jeff@paploo.net
22
+
23
+ = Version History
24
+
25
+ [0.9.0 - 2010-Nov-03] Initial release.
26
+ * Feature complete, but lacks spec tests and examples.
27
+
28
+ = TODO List
29
+
30
+ * Add complete spec tests.
31
+ * Add examples.
32
+
33
+ = License
34
+
35
+ The files contained in this repository are released under the commercially and
36
+ GPL compatible "New BSD License", given below:
37
+
38
+ == License Text
39
+
40
+ Copyright (c) 2010, Jeffrey C. Reinecke
41
+ All rights reserved.
42
+
43
+ Redistribution and use in source and binary forms, with or without
44
+ modification, are permitted provided that the following conditions are met:
45
+ * Redistributions of source code must retain the above copyright
46
+ notice, this list of conditions and the following disclaimer.
47
+ * Redistributions in binary form must reproduce the above copyright
48
+ notice, this list of conditions and the following disclaimer in the
49
+ documentation and/or other materials provided with the distribution.
50
+ * Neither the name of the copyright holders nor the
51
+ names of its contributors may be used to endorse or promote products
52
+ derived from this software without specific prior written permission.
53
+
54
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
55
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
56
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
57
+ DISCLAIMED. IN NO EVENT SHALL JEFFREY REINECKE BE LIABLE FOR ANY
58
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
59
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
60
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
61
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
62
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ require 'rake'
2
+ require "rake/rdoctask"
3
+
4
+ # ===== RDOC BUILDING =====
5
+ # This isn't necessary if installing from a gem.
6
+
7
+ Rake::RDocTask.new do |rdoc|
8
+ rdoc.rdoc_dir = "rdoc"
9
+ rdoc.rdoc_files.add "lib/**/*.rb", "README.rdoc"
10
+ end
11
+
12
+ # ===== SPEC TESTING =====
13
+
14
+ begin
15
+ require "spec/rake/spectask"
16
+
17
+ Spec::Rake::SpecTask.new(:spec) do |spec|
18
+ spec.spec_opts = ['-c' '-f specdoc']
19
+ spec.spec_files = ['spec']
20
+ end
21
+
22
+ Spec::Rake::SpecTask.new(:spec_with_backtrace) do |spec|
23
+ spec.spec_opts = ['-c' '-f specdoc', '-b']
24
+ spec.spec_files = ['spec']
25
+ end
26
+ rescue LoadError
27
+ task :spec do
28
+ puts "You must have rspec installed to run this task."
29
+ end
30
+ end
31
+
32
+ # ===== GEM BUILDING =====
33
+
34
+ desc "Build the gem file for this package"
35
+ task :build_gem do
36
+ STDOUT.puts `gem build secure_string.gemspec`
37
+ end
@@ -0,0 +1,59 @@
1
+ require 'base64'
2
+
3
+ require_relative 'secure_string/digest_methods'
4
+ require_relative 'secure_string/base64_methods'
5
+ require_relative 'secure_string/cipher_methods'
6
+ require_relative 'secure_string/rsa_methods'
7
+
8
+ # SecureString is a String subclass whose emphasis is on byte data rather than
9
+ # human readable strings. class gives a number of conveniences, such
10
+ # as easier viewing of the byte data as hex, digest methods, and encryption
11
+ # and decryption methods.
12
+ class SecureString < String
13
+ include Base64Methods
14
+ include DigestMethods
15
+ include RSAMethods
16
+ include CipherMethods
17
+
18
+ # Creates the string from one many kinds of values:
19
+ # [:data] (default) The passed string value is directly used.
20
+ # [:hex] Initialize using a hexidecimal string.
21
+ # [:int] Initialize using the numeric value of the hexidecimal string.
22
+ # [:base64] Initialize using the given base64 encoded data.
23
+ def initialize(mode = :data, value)
24
+ case mode
25
+ when :hex
26
+ hex_string = value.to_s
27
+ data = [hex_string].pack('H' + hex_string.length.to_s)
28
+ when :data
29
+ data = value.to_s
30
+ when :int
31
+ self.send(__method__, :hex, value.to_i.to_s(16))
32
+ when :base64
33
+ data = Base64.decode64(value.to_s)
34
+ end
35
+
36
+ self.replace(data)
37
+ end
38
+
39
+ # Override the default String inspect to return the hexidecimal
40
+ # representation of the data contained in this string.
41
+ def inspect
42
+ return "<#{to_hex}>"
43
+ end
44
+
45
+ # Returns the hexidecimal string representation of the data.
46
+ def to_hex
47
+ return (self.empty? ? '' : self.unpack('H' + (self.length*2).to_s)[0])
48
+ end
49
+
50
+ # Returns the data converted from hexidecimal into an integer.
51
+ # This is usually as a BigInt.
52
+ #
53
+ # WARNING: If the data string is empty, then this returns -1, as there is no
54
+ # integer representation of the absence of data.
55
+ def to_i
56
+ return (self.empty? ? -1 : to_hex.hex)
57
+ end
58
+
59
+ end
@@ -0,0 +1,28 @@
1
+ require 'base64'
2
+
3
+ class SecureString < String
4
+ module Base64Methods
5
+
6
+ def self.included(mod)
7
+ mod.send(:include, InstanceMethods)
8
+ end
9
+
10
+ module InstanceMethods
11
+
12
+ # Encodes to Base64. By default, the output is made URL safe, which means all
13
+ # newlines are stripped out. If you want standard formatted Base64 with
14
+ # newlines, then call this method with url_safe as false.
15
+ def to_base64(url_safe = true)
16
+ encoded_data = (url_safe ? Base64.urlsafe_encode64(self) : Base64.encode64(self))
17
+ return self.class.new( encoded_data )
18
+ end
19
+
20
+ # Decode self as a Base64 data string and return the result.
21
+ def from_base64
22
+ return self.class.new( Base64.decode64(self) )
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,76 @@
1
+ require 'openssl'
2
+
3
+ class SecureString < String
4
+ module CipherMethods
5
+
6
+ def self.included(mod)
7
+ mod.send(:extend, ClassMethods)
8
+ mod.send(:include, InstanceMethods)
9
+ end
10
+
11
+ module ClassMethods
12
+
13
+ # A convenience method for generating random cipher keys and initialization
14
+ # vectors.
15
+ def cipher_keygen(cipher_name)
16
+ cipher = OpenSSL::Cipher::Cipher.new(cipher_name)
17
+ cipher.encrypt
18
+ return [cipher.random_key, cipher.random_iv].map {|s| self.new(s)}
19
+ end
20
+
21
+ # A convenience method for generating a random key and init vector for AES keys.
22
+ # Defaults to a key length of 256.
23
+ def aes_keygen(key_len=256)
24
+ return cipher_keygen("aes-#{key_len.to_i}-cbc")
25
+ end
26
+
27
+ end
28
+
29
+ module InstanceMethods
30
+
31
+ # Given an OpenSSL cipher name, a key, and initialization vector,
32
+ # encrypt the data.
33
+ #
34
+ # Use OpenSSL::Cipher.ciphers to get a list of available cipher names.
35
+ #
36
+ # To generate a new key and iv, do the following:
37
+ # cipher = OpenSSL::Cipher::Cipher.new(cipher_name)
38
+ # cipher.encrypt
39
+ # key = cipher.random_key
40
+ # iv = cipher.random_iv
41
+ def to_cipher(cipher_name, key, iv)
42
+ cipher = OpenSSL::Cipher.new(cipher_name)
43
+ cipher.encrypt # MUST set the mode BEFORE setting the key and iv!
44
+ cipher.key = key
45
+ cipher.iv = iv
46
+ msg = cipher.update(self)
47
+ msg << cipher.final
48
+ return self.class.new(msg)
49
+ end
50
+
51
+ # Given an OpenSSL cipher name, a key, and an init vector,
52
+ # decrypt the data.
53
+ def from_cipher(cipher_name, key, iv)
54
+ cipher = OpenSSL::Cipher.new(cipher_name)
55
+ cipher.decrypt # MUST set the mode BEFORE setting the key and iv!
56
+ cipher.key = key
57
+ cipher.iv = iv
58
+ msg = cipher.update(self)
59
+ msg << cipher.final
60
+ return self.class.new(msg)
61
+ end
62
+
63
+ # Given an AES key and initialization vector, AES encode the data.
64
+ def to_aes(key, iv, key_len=256)
65
+ return self.class.new( to_cipher("aes-#{key_len.to_i}-cbc", key, iv) )
66
+ end
67
+
68
+ # Given an AES key and init vector, AES decode the data.
69
+ def from_aes(key, iv, key_len=256)
70
+ return self.class.new( from_cipher("aes-#{key_len.to_i}-cbc", key, iv) )
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,48 @@
1
+ require 'openssl'
2
+
3
+ class SecureString < String
4
+ module DigestMethods
5
+
6
+ def self.included(mod)
7
+ mod.send(:include, InstanceMethods)
8
+ end
9
+
10
+ module InstanceMethods
11
+
12
+ # Returns the digest of the byte string as a SecureString, using the passed OpenSSL object.
13
+ def to_digest(digest_obj)
14
+ return self.class.new( digest_obj.digest(self) )
15
+ end
16
+
17
+ # Returns the MD5 of the byte string as a SecureString.
18
+ def to_md5
19
+ return to_digest( OpenSSL::Digest::MD5.new )
20
+ end
21
+
22
+ # Returns the SHA2 of the byte string as a SecureString.
23
+ #
24
+ # By default, this uses the 256 bit SHA2, but the optional arugment allows
25
+ # specification of which bit length to use.
26
+ def to_sha2(length=256)
27
+ if [224,256,384,512].include?(length)
28
+ digest_klass = OpenSSL::Digest.const_get("SHA#{length}", false)
29
+ return to_digest( digest_klass )
30
+ else
31
+ raise ArgumentError, "Invalid SHA2 length: #{length}"
32
+ end
33
+ end
34
+
35
+ # Returns the SHA2 256 of the data string. See +to_sha2+.
36
+ def to_sha256
37
+ return to_sha2(256)
38
+ end
39
+
40
+ # Returns the SHA2 512 of the data string. See +to_sha2+.
41
+ def to_sha512
42
+ return to_sha2(512)
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,65 @@
1
+ require 'openssl'
2
+
3
+ class SecureString < String
4
+ module RSAMethods
5
+
6
+ def self.included(mod)
7
+ mod.send(:extend, ClassMethods)
8
+ mod.send(:include, InstanceMethods)
9
+ end
10
+
11
+ module ClassMethods
12
+
13
+ # A convenience method for generating random public/private RSA key pairs.
14
+ # Defaults to a key length of 1024.
15
+ #
16
+ # Returns the private key first, then the public key. Returns them in PEM file
17
+ # format by default, as this is most useful for portability. DER format can
18
+ # be explicitly specified with the second argument.
19
+ def rsa_keygen(key_len=1024, format = :pem)
20
+ private_key_obj = OpenSSL::PKey::RSA.new(key_len.to_i)
21
+ public_key_obj = private_key_obj.public_key
22
+ formatting_method = (format == :der ? :to_der : :to_pem)
23
+ return [private_key_obj, public_key_obj].map {|k| self.new( k.send(formatting_method) )}
24
+ end
25
+
26
+ end
27
+
28
+ module InstanceMethods
29
+
30
+ # Given an RSA public key, it RSA encrypts the data string.
31
+ #
32
+ # Note that the key must be 11 bytes longer than the data string or it doesn't
33
+ # work.
34
+ def to_rsa(public_key)
35
+ key = OpenSSL::PKey::RSA.new(public_key)
36
+ return self.class.new( key.public_encrypt(self) )
37
+ end
38
+
39
+ # Given an RSA private key, it decrypts the data string back into the original text.
40
+ def from_rsa(private_key)
41
+ key = OpenSSL::PKey::RSA.new(private_key)
42
+ return self.class.new( key.private_decrypt(self) )
43
+ end
44
+
45
+ # Signs the given message using hte given private key.
46
+ #
47
+ # By default, signs using SHA256, but another digest object can be given.
48
+ def sign(private_key, digest_obj=OpenSSL::Digest::SHA256.new)
49
+ key = OpenSSL::PKey::RSA.new(private_key)
50
+ return self.class.new( key.sign(digest_obj, self) )
51
+ end
52
+
53
+ # Verifies the given signature matches the messages digest, using the
54
+ # signer's public key.
55
+ #
56
+ # By default, verifies using SHA256, but another digest object can be given.
57
+ def verify?(public_key, signature, digest_obj=OpenSSL::Digest::SHA256.new)
58
+ key = OpenSSL::PKey::RSA.new(public_key)
59
+ return key.verify(digest_obj, signature.to_s, self)
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,4 @@
1
+ # Add the lib dir to the load path.
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+ # Require the main require file.
4
+ require File.basename(File.expand_path(File.join(File.dirname(__FILE__),'..')))
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: secure_string
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 9
8
+ - 0
9
+ version: 0.9.0
10
+ platform: ruby
11
+ authors:
12
+ - Jeff Reinecke
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-11-03 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: " A String subclass to simplify handling of:\n 1. Binary data, including HEX encoding and Bin64 encoding.\n 2. Encryption such as RSA, AES, and digest methods such as SHA and MD5.\n"
22
+ email: jeff@paploo.net
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README.rdoc
29
+ files:
30
+ - README.rdoc
31
+ - LICENSE.txt
32
+ - Rakefile
33
+ - lib/secure_string/base64_methods.rb
34
+ - lib/secure_string/cipher_methods.rb
35
+ - lib/secure_string/digest_methods.rb
36
+ - lib/secure_string/rsa_methods.rb
37
+ - lib/secure_string.rb
38
+ - spec/spec_helper.rb
39
+ has_rdoc: true
40
+ homepage: http://www.github.com/paploo/secure_string
41
+ licenses:
42
+ - BSD
43
+ post_install_message:
44
+ rdoc_options: []
45
+
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 1
55
+ - 9
56
+ - 2
57
+ version: 1.9.2
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.3.7
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: A String subclass for simple handling of binary data and encryption.
73
+ test_files: []
74
+