secure_string 0.9.0

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/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
+