secure_string 1.1.0 → 1.1.1
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/README.rdoc +72 -11
- data/lib/secure_string.rb +17 -0
- data/lib/securize_string/binary_string_data_methods.rb +7 -18
- data/lib/securize_string/cipher_methods.rb +4 -4
- data/lib/securize_string/digest_finder.rb +56 -0
- data/lib/securize_string/digest_methods.rb +21 -7
- data/lib/securize_string/rsa_methods.rb +34 -12
- data/spec/base64_methods_spec.rb +1 -0
- data/spec/binary_string_data_methods_spec.rb +11 -3
- data/spec/digest_finder_spec.rb +48 -0
- data/spec/digest_methods_spec.rb +4 -6
- data/spec/example_spec.rb +75 -0
- data/spec/rsa_methods_spec.rb +48 -23
- data/spec/secure_string_spec.rb +70 -0
- metadata +8 -5
    
        data/README.rdoc
    CHANGED
    
    | @@ -19,13 +19,20 @@ String version of the value. | |
| 19 19 | 
             
            WARNING: it is important to note that the String method +length+ is not a good
         | 
| 20 20 | 
             
            measure of a byte string's length, as depending on the encoding, it may count
         | 
| 21 21 | 
             
            multibyte characters as a single element.  To ensure that you get the byte
         | 
| 22 | 
            -
            length, use the standard string method +bytesize+.
         | 
| 22 | 
            +
            length, use the standard string method +bytesize+.  See the section on
         | 
| 23 | 
            +
            String Encodings for more detail.
         | 
| 23 24 |  | 
| 24 25 | 
             
            = Installation & Configuration
         | 
| 25 26 |  | 
| 26 27 | 
             
            == Installation
         | 
| 27 28 |  | 
| 28 | 
            -
             | 
| 29 | 
            +
            SecureString is currently only supported in Ruby 1.9.x.
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            To install, first install the gem:
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              gem install secure_string
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            Then require the gem like so:
         | 
| 29 36 |  | 
| 30 37 | 
             
              require 'secure_string'
         | 
| 31 38 |  | 
| @@ -108,13 +115,14 @@ cryptographic hash sums for the data in the string.  Note that since SecureStrin | |
| 108 115 | 
             
            handles binary data well, the string value returns is NOT the hex string; to get
         | 
| 109 116 | 
             
            the hex digest, simply call to_hex:
         | 
| 110 117 |  | 
| 118 | 
            +
              ss = SecureString.new("Hello World!")
         | 
| 111 119 | 
             
              ss.to_md5.to_hex
         | 
| 112 120 | 
             
                --> "ed076287532e86365e841e92bfc50d8c"
         | 
| 113 121 | 
             
              ss.to_sha1.to_hex
         | 
| 114 122 | 
             
                --> "2ef7bde608ce5404e97d5f042f95f89f1c232871"
         | 
| 115 123 | 
             
              ss.to_sha256.to_hex
         | 
| 116 124 | 
             
                 --> "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"
         | 
| 117 | 
            -
              ss.to_digest( | 
| 125 | 
            +
              ss.to_digest('SHA-512').to_hex
         | 
| 118 126 | 
             
                --> "861844d6704e8573fec34d967e20bcfef3d424cf48be04e6dc08f2bd58c729743371015ead891cc3cf1c9d34b49264b510751b1ff9e537937bc46b5d6ff4ecc8"
         | 
| 119 127 |  | 
| 120 128 | 
             
            == RSA Methods Overview
         | 
| @@ -167,6 +175,53 @@ cipher: | |
| 167 175 | 
             
              # Now decrypt the message:
         | 
| 168 176 | 
             
              decoded_text = cipher_text.from_aes(key, iv)
         | 
| 169 177 |  | 
| 178 | 
            +
            = String Encodings
         | 
| 179 | 
            +
             | 
| 180 | 
            +
            == Overview
         | 
| 181 | 
            +
             | 
| 182 | 
            +
            Starting in Ruby 1.9.x, String instances manage their own encodings.  For example,
         | 
| 183 | 
            +
            a string with Unicode characters are usually encoded as UTF-8, while a lot of
         | 
| 184 | 
            +
            source is still written in US-ASCII.
         | 
| 185 | 
            +
             | 
| 186 | 
            +
            Binary data is independent of the encoding that encodes it, however using the
         | 
| 187 | 
            +
            binary data when it is assigned a multi-byte character encoding strategy can
         | 
| 188 | 
            +
            lead to a few surprises.
         | 
| 189 | 
            +
             | 
| 190 | 
            +
            For example, for a Unicode string, the +length+ method returns the number of
         | 
| 191 | 
            +
            characters in the string, while +bytesize+ returns the number of bytes encoded
         | 
| 192 | 
            +
            in the string:
         | 
| 193 | 
            +
             | 
| 194 | 
            +
              s = "Resum\u00E9"
         | 
| 195 | 
            +
              s.encoding --> UTF-8
         | 
| 196 | 
            +
              s.length   --> 6
         | 
| 197 | 
            +
              s.bytesize --> 7
         | 
| 198 | 
            +
             | 
| 199 | 
            +
            == SecureString Encoding
         | 
| 200 | 
            +
             | 
| 201 | 
            +
            SecureString's basic design philosophy is to--as much as possible--only extend the
         | 
| 202 | 
            +
            behavior of String, not replace it.  <b>Therefore, SecureString does NOT affect the
         | 
| 203 | 
            +
            encoding of the string it is using.</b>
         | 
| 204 | 
            +
             | 
| 205 | 
            +
            This is normally not a problem--as long as you use +bytesize+ instead of +length+
         | 
| 206 | 
            +
            to get the byte count of the data in the string.
         | 
| 207 | 
            +
             | 
| 208 | 
            +
            In rare cases, you may want to change a String to the ASCII-8BIT binary
         | 
| 209 | 
            +
            encoding without changing its data.  To accomplish this, one should call
         | 
| 210 | 
            +
            +force_encoding+ like so:
         | 
| 211 | 
            +
             | 
| 212 | 
            +
              s = "Resum\u00E9"
         | 
| 213 | 
            +
              s.force_encoding('BINARY')
         | 
| 214 | 
            +
              s.encoding --> ASCII-8BIT
         | 
| 215 | 
            +
              s.length   --> 7
         | 
| 216 | 
            +
              s.bytesize --> 7
         | 
| 217 | 
            +
              
         | 
| 218 | 
            +
            Note that when you do this, equality tests can be broken like so:
         | 
| 219 | 
            +
             | 
| 220 | 
            +
              s = "Resum\u00E9"
         | 
| 221 | 
            +
              b = s.dup.force_encoding('BINARY')
         | 
| 222 | 
            +
              s == b                       --> false
         | 
| 223 | 
            +
              s.bytes.to_a == b.bytes.to_a --> true
         | 
| 224 | 
            +
              
         | 
| 170 225 | 
             
            = Contact
         | 
| 171 226 |  | 
| 172 227 | 
             
            If you have any questions, comments, concerns, patches, or bugs, you can contact
         | 
| @@ -179,7 +234,17 @@ or directly via e-mail at: | |
| 179 234 | 
             
            mailto:jeff@paploo.net
         | 
| 180 235 |  | 
| 181 236 | 
             
            = Version History
         | 
| 182 | 
            -
            [1.1. | 
| 237 | 
            +
            [1.1.1 - 2010-Nov-05] Backed down requirements to ruby 1.9.x; Bugfixes and minor changes.
         | 
| 238 | 
            +
                                  * Tested in 1.9.1 and 1.9.2.
         | 
| 239 | 
            +
                                  * Added some documentation and tests on String encodings.
         | 
| 240 | 
            +
                                  * Added more spec tests.
         | 
| 241 | 
            +
                                  * (FEATURE) Digest methods may be supplied via string now.
         | 
| 242 | 
            +
                                  * (FEATURE) RSA encryption works with both public and private keys.
         | 
| 243 | 
            +
                                  * (FEATURE) RSA keys encoded as SecureString can be asked if public or private.
         | 
| 244 | 
            +
                                  * (CHANGE) BinaryStringDataMethods now is non-clobbering and independent.
         | 
| 245 | 
            +
                                  * (CHANGE) An empty string's integer value is now zero.
         | 
| 246 | 
            +
                                  * (FIX) Non-hex characters are ignored when accepting hex data input.
         | 
| 247 | 
            +
            [1.1.0 - 2010-Nov-04] Extracted methods into a module that can be easily included
         | 
| 183 248 | 
             
                                  on any String class.
         | 
| 184 249 | 
             
            [1.0.0 - 2010-Nov-04] Added Tests, Examples, and Bugfixes
         | 
| 185 250 | 
             
                                  * Added a full suite of spec tests.
         | 
| @@ -193,13 +258,9 @@ mailto:jeff@paploo.net | |
| 193 258 |  | 
| 194 259 | 
             
            = TODO List
         | 
| 195 260 |  | 
| 196 | 
            -
            *  | 
| 197 | 
            -
             | 
| 198 | 
            -
             | 
| 199 | 
            -
              methods should be recommended to users for finding byte-length vs. char length.
         | 
| 200 | 
            -
            * RSA encoding/decoding should auto-detect if the given key is public or private,
         | 
| 201 | 
            -
              and use the correct encoding routine?  What about key confusion?
         | 
| 202 | 
            -
            * RSA signature digests: accept Digest hashes, not just OpenSSL::Digest hashes.
         | 
| 261 | 
            +
            * See what happens when including SecurizeString into an object that is not a String.
         | 
| 262 | 
            +
              What are the expected root methods?  +to_s+, <tt>self.new(string)</tt> are two
         | 
| 263 | 
            +
              that I know of.
         | 
| 203 264 |  | 
| 204 265 |  | 
| 205 266 | 
             
            = License
         | 
    
        data/lib/secure_string.rb
    CHANGED
    
    | @@ -17,4 +17,21 @@ class SecureString < String | |
| 17 17 | 
             
                self.replace( data_string )
         | 
| 18 18 | 
             
              end
         | 
| 19 19 |  | 
| 20 | 
            +
              # Override the default to_i method to return the integer value of the data
         | 
| 21 | 
            +
              # contained in the string, rather than the parsed value of the characters.
         | 
| 22 | 
            +
              def to_i
         | 
| 23 | 
            +
                return data_to_i
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
              
         | 
| 26 | 
            +
              # Add a method to convert the internal binary data into a hex string.
         | 
| 27 | 
            +
              def to_hex
         | 
| 28 | 
            +
                return data_to_hex
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
              
         | 
| 31 | 
            +
              # Override the default inspect to return the hexidecimal
         | 
| 32 | 
            +
              # representation of the data contained in this string.
         | 
| 33 | 
            +
              def inspect
         | 
| 34 | 
            +
                return "<#{to_hex}>"
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
              
         | 
| 20 37 | 
             
            end
         | 
| @@ -1,8 +1,7 @@ | |
| 1 1 | 
             
            require 'base64'
         | 
| 2 2 |  | 
| 3 3 | 
             
            module SecurizeString
         | 
| 4 | 
            -
              # Adds  | 
| 5 | 
            -
              # binary data better.
         | 
| 4 | 
            +
              # Adds base methods that help in interpreting the binary data represented by the String value of an object.
         | 
| 6 5 | 
             
              # See BinaryStringDataMethods::ClassMethods and BinaryStringDataMethods::InstanceMethods for more deatils.
         | 
| 7 6 | 
             
              module BinaryStringDataMethods
         | 
| 8 7 |  | 
| @@ -11,8 +10,7 @@ module SecurizeString | |
| 11 10 | 
             
                  mod.send(:include, InstanceMethods)
         | 
| 12 11 | 
             
                end
         | 
| 13 12 |  | 
| 14 | 
            -
                # Adds basic binary data class methods  | 
| 15 | 
            -
                # an include of SecurizeString::BinaryStringDataMethods
         | 
| 13 | 
            +
                # Adds basic binary data class methods via an include of SecurizeString::BinaryStringDataMethods.
         | 
| 16 14 | 
             
                module ClassMethods
         | 
| 17 15 |  | 
| 18 16 | 
             
                  # Creates a data string from one many kinds of values:
         | 
| @@ -23,7 +21,7 @@ module SecurizeString | |
| 23 21 | 
             
                  def parse_data(mode = :data, value)
         | 
| 24 22 | 
             
                    case mode
         | 
| 25 23 | 
             
                    when :hex
         | 
| 26 | 
            -
                      hex_string = value.to_s
         | 
| 24 | 
            +
                      hex_string = value.to_s.delete('^0-9a-fA-F')
         | 
| 27 25 | 
             
                      data_string = [hex_string].pack('H' + hex_string.bytesize.to_s)
         | 
| 28 26 | 
             
                    when :data
         | 
| 29 27 | 
             
                      data_string = value.to_s
         | 
| @@ -38,28 +36,19 @@ module SecurizeString | |
| 38 36 |  | 
| 39 37 | 
             
                end
         | 
| 40 38 |  | 
| 41 | 
            -
                # Adds basic binary data instance methods  | 
| 42 | 
            -
                # an include of SecurizeString::BinaryStringDataMethods.
         | 
| 39 | 
            +
                # Adds basic binary data instance methods via an include of SecurizeString::BinaryStringDataMethods.
         | 
| 43 40 | 
             
                module InstanceMethods
         | 
| 44 41 |  | 
| 45 | 
            -
                  # Override the default inspect to return the hexidecimal
         | 
| 46 | 
            -
                  # representation of the data contained in this string.
         | 
| 47 | 
            -
                  def inspect
         | 
| 48 | 
            -
                    return "<#{to_hex}>"
         | 
| 49 | 
            -
                  end
         | 
| 50 | 
            -
                  
         | 
| 51 42 | 
             
                  # Returns the hexidecimal string representation of the data.
         | 
| 52 | 
            -
                  def  | 
| 43 | 
            +
                  def data_to_hex
         | 
| 53 44 | 
             
                    return (self.to_s.empty? ? '' : self.to_s.unpack('H' + (self.to_s.bytesize*2).to_s)[0])
         | 
| 54 45 | 
             
                  end
         | 
| 55 46 |  | 
| 56 47 | 
             
                  # Returns the data converted from hexidecimal into an integer.
         | 
| 57 48 | 
             
                  # This is usually as a BigInt.
         | 
| 58 49 | 
             
                  #
         | 
| 59 | 
            -
                   | 
| 60 | 
            -
             | 
| 61 | 
            -
                  def to_i
         | 
| 62 | 
            -
                    return (self.to_s.empty? ? -1 : to_hex.hex)
         | 
| 50 | 
            +
                  def data_to_i
         | 
| 51 | 
            +
                    return (self.to_s.empty? ? 0 : self.data_to_hex.hex)
         | 
| 63 52 | 
             
                  end
         | 
| 64 53 |  | 
| 65 54 | 
             
                end
         | 
| @@ -55,7 +55,7 @@ module SecurizeString | |
| 55 55 | 
             
                    cipher.encrypt # MUST set the mode BEFORE setting the key and iv!
         | 
| 56 56 | 
             
                    cipher.key = key
         | 
| 57 57 | 
             
                    cipher.iv = iv
         | 
| 58 | 
            -
                    msg = cipher.update(self)
         | 
| 58 | 
            +
                    msg = cipher.update(self.to_s)
         | 
| 59 59 | 
             
                    msg << cipher.final
         | 
| 60 60 | 
             
                    return self.class.new(msg)
         | 
| 61 61 | 
             
                  end
         | 
| @@ -67,7 +67,7 @@ module SecurizeString | |
| 67 67 | 
             
                    cipher.decrypt # MUST set the mode BEFORE setting the key and iv!
         | 
| 68 68 | 
             
                    cipher.key = key
         | 
| 69 69 | 
             
                    cipher.iv = iv
         | 
| 70 | 
            -
                    msg = cipher.update(self)
         | 
| 70 | 
            +
                    msg = cipher.update(self.to_s)
         | 
| 71 71 | 
             
                    msg << cipher.final
         | 
| 72 72 | 
             
                    return self.class.new(msg)
         | 
| 73 73 | 
             
                  end
         | 
| @@ -78,13 +78,13 @@ module SecurizeString | |
| 78 78 | 
             
                  # combination on two different messages as this weakens the security.
         | 
| 79 79 | 
             
                  def to_aes(key, iv)
         | 
| 80 80 | 
             
                    key_len = (key.bytesize * 8)
         | 
| 81 | 
            -
                    return self.class.new( to_cipher("aes-#{key_len | 
| 81 | 
            +
                    return self.class.new( to_cipher("aes-#{key_len}-cbc", key, iv) )
         | 
| 82 82 | 
             
                  end
         | 
| 83 83 |  | 
| 84 84 | 
             
                  # Given an AES key and init vector, AES-CBC decode the data.
         | 
| 85 85 | 
             
                  def from_aes(key, iv)
         | 
| 86 86 | 
             
                    key_len = (key.bytesize * 8)
         | 
| 87 | 
            -
                    return self.class.new( from_cipher("aes-#{key_len | 
| 87 | 
            +
                    return self.class.new( from_cipher("aes-#{key_len}-cbc", key, iv) )
         | 
| 88 88 | 
             
                  end
         | 
| 89 89 |  | 
| 90 90 | 
             
                end
         | 
| @@ -0,0 +1,56 @@ | |
| 1 | 
            +
            require 'digest'
         | 
| 2 | 
            +
            require 'openssl'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module SecurizeString
         | 
| 5 | 
            +
              #  A Helper class to look-up digests easily.
         | 
| 6 | 
            +
              class DigestFinder
         | 
| 7 | 
            +
                DIGESTS = {
         | 
| 8 | 
            +
                  'DSS'        => OpenSSL::Digest::DSS      ,
         | 
| 9 | 
            +
                  'DSS1'       => OpenSSL::Digest::DSS1     ,
         | 
| 10 | 
            +
                  'MD2'        => OpenSSL::Digest::MD2      ,
         | 
| 11 | 
            +
                  'MD4'        => OpenSSL::Digest::MD4      ,
         | 
| 12 | 
            +
                  'MD5'        => OpenSSL::Digest::MD5      ,
         | 
| 13 | 
            +
                  'SHA'        => OpenSSL::Digest::SHA      ,
         | 
| 14 | 
            +
                  'SHA-0'      => OpenSSL::Digest::SHA      ,
         | 
| 15 | 
            +
                  'SHA0'       => OpenSSL::Digest::SHA      ,
         | 
| 16 | 
            +
                  'SHA-1'      => OpenSSL::Digest::SHA1     ,
         | 
| 17 | 
            +
                  'SHA1'       => OpenSSL::Digest::SHA1     ,
         | 
| 18 | 
            +
                  'SHA-224'    => OpenSSL::Digest::SHA224   ,
         | 
| 19 | 
            +
                  'SHA-256'    => OpenSSL::Digest::SHA256   ,
         | 
| 20 | 
            +
                  'SHA-384'    => OpenSSL::Digest::SHA384   ,
         | 
| 21 | 
            +
                  'SHA-512'    => OpenSSL::Digest::SHA512   ,
         | 
| 22 | 
            +
                  'SHA224'     => OpenSSL::Digest::SHA224   ,
         | 
| 23 | 
            +
                  'SHA256'     => OpenSSL::Digest::SHA256   ,
         | 
| 24 | 
            +
                  'SHA384'     => OpenSSL::Digest::SHA384   ,
         | 
| 25 | 
            +
                  'SHA512'     => OpenSSL::Digest::SHA512   ,
         | 
| 26 | 
            +
                  'RIPEMD-160' => OpenSSL::Digest::RIPEMD160,
         | 
| 27 | 
            +
                  'RIPEMD160'  => OpenSSL::Digest::RIPEMD160
         | 
| 28 | 
            +
                }.freeze
         | 
| 29 | 
            +
                
         | 
| 30 | 
            +
                # Returns the complete list of digest strings recognized by find.
         | 
| 31 | 
            +
                def self.digests
         | 
| 32 | 
            +
                  @supported_digests = DIGESTS.keys.inject([]) {|a,v| a | [v.upcase, v.downcase]}.sort if @supported_digests.nil?
         | 
| 33 | 
            +
                  return @supported_digests
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
                
         | 
| 36 | 
            +
                # Returns the OpenSSL::Digest class that goes with a given argument.
         | 
| 37 | 
            +
                def self.find(obj)
         | 
| 38 | 
            +
                  if( obj.kind_of?(OpenSSL::Digest) )
         | 
| 39 | 
            +
                    klass = obj.class
         | 
| 40 | 
            +
                  elsif( obj.kind_of?(Class) && (obj < OpenSSL::Digest) )
         | 
| 41 | 
            +
                    klass = obj
         | 
| 42 | 
            +
                  elsif( obj.kind_of?(Class) && (obj < Digest::Base) )
         | 
| 43 | 
            +
                    klass = DIGESTS[obj.name.split('::').last.upcase]
         | 
| 44 | 
            +
                  elsif( obj.kind_of?(Digest::Base) )
         | 
| 45 | 
            +
                    klass = DIGESTS[obj.class.name.split('::').last.upcase]
         | 
| 46 | 
            +
                  else
         | 
| 47 | 
            +
                    klass = DIGESTS[obj.to_s.upcase]
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
                  
         | 
| 50 | 
            +
                  raise ArgumentError, "Cannot convert to OpenSSL::Digest: #{obj.inspect}" if klass.nil?
         | 
| 51 | 
            +
                  
         | 
| 52 | 
            +
                  return klass
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
            end
         | 
| @@ -1,31 +1,45 @@ | |
| 1 1 | 
             
            require 'openssl'
         | 
| 2 | 
            +
            require_relative 'digest_finder'
         | 
| 2 3 |  | 
| 3 4 | 
             
            module SecurizeString
         | 
| 4 5 | 
             
              # Adds methods for OpenSSL::Digest support.
         | 
| 5 6 | 
             
              # See DigestMethods::ClassMethods and DigestMethods::InstanceMethods for more details.
         | 
| 6 7 | 
             
              module DigestMethods
         | 
| 7 | 
            -
                
         | 
| 8 8 | 
             
                def self.included(mod)
         | 
| 9 9 | 
             
                  mod.send(:include, InstanceMethods)
         | 
| 10 10 | 
             
                end
         | 
| 11 11 |  | 
| 12 | 
            +
                # Adds instance methods for OpenSSL::Digest support via inclusion of
         | 
| 13 | 
            +
                # SecurizeString::DigestMethods to a class.
         | 
| 14 | 
            +
                module ClassMethods
         | 
| 15 | 
            +
                  
         | 
| 16 | 
            +
                  # Returns a list of supported digests.  These can be passed directly into
         | 
| 17 | 
            +
                  # the cipher methods.
         | 
| 18 | 
            +
                  def supported_digests
         | 
| 19 | 
            +
                    return DigestFinder.digests
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                  
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
                
         | 
| 12 24 | 
             
                # Adds instance methods for OpenSSL::Digest support via inclusion of
         | 
| 13 25 | 
             
                # SecurizeString::DigestMethods to a class.
         | 
| 14 26 | 
             
                module InstanceMethods
         | 
| 15 27 |  | 
| 16 | 
            -
                  # Returns the digest of the byte string as a SecureString | 
| 17 | 
            -
                   | 
| 28 | 
            +
                  # Returns the digest of the byte string as a SecureString using the passed
         | 
| 29 | 
            +
                  # digest from the list of digests in +supported_digests+.
         | 
| 30 | 
            +
                  def to_digest(digest)
         | 
| 31 | 
            +
                    digest_obj = DigestFinder.find(digest).new
         | 
| 18 32 | 
             
                    return self.class.new( digest_obj.digest(self) )
         | 
| 19 33 | 
             
                  end
         | 
| 20 34 |  | 
| 21 35 | 
             
                  # Returns the MD5 of the byte string as a SecureString.
         | 
| 22 36 | 
             
                  def to_md5
         | 
| 23 | 
            -
                    return to_digest( | 
| 37 | 
            +
                    return to_digest('MD5')
         | 
| 24 38 | 
             
                  end
         | 
| 25 39 |  | 
| 26 40 | 
             
                  # Returns the SHA1 of the byte string as SecureString
         | 
| 27 41 | 
             
                  def to_sha1
         | 
| 28 | 
            -
                    return to_digest( | 
| 42 | 
            +
                    return to_digest('SHA-1')
         | 
| 29 43 | 
             
                  end
         | 
| 30 44 |  | 
| 31 45 | 
             
                  # Returns the SHA2 of the byte string as a SecureString.
         | 
| @@ -34,8 +48,8 @@ module SecurizeString | |
| 34 48 | 
             
                  # specification of which bit length to use.
         | 
| 35 49 | 
             
                  def to_sha2(length=256)
         | 
| 36 50 | 
             
                    if [224,256,384,512].include?(length)
         | 
| 37 | 
            -
                       | 
| 38 | 
            -
                      return to_digest(  | 
| 51 | 
            +
                      digest = "SHA-#{length}"
         | 
| 52 | 
            +
                      return to_digest( digest )
         | 
| 39 53 | 
             
                    else
         | 
| 40 54 | 
             
                      raise ArgumentError, "Invalid SHA2 length: #{length}"
         | 
| 41 55 | 
             
                    end
         | 
| @@ -42,22 +42,25 @@ module SecurizeString | |
| 42 42 | 
             
                  #
         | 
| 43 43 | 
             
                  # Note that the key must be 11 bytes longer than the data string or it doesn't
         | 
| 44 44 | 
             
                  # work.
         | 
| 45 | 
            -
                  def to_rsa( | 
| 46 | 
            -
                    key = OpenSSL::PKey::RSA.new( | 
| 47 | 
            -
                     | 
| 45 | 
            +
                  def to_rsa(key)
         | 
| 46 | 
            +
                    key = OpenSSL::PKey::RSA.new(key)        
         | 
| 47 | 
            +
                    cipher_text = key.private? ? key.private_encrypt(self.to_s) : key.public_encrypt(self.to_s)
         | 
| 48 | 
            +
                    return self.class.new(cipher_text)
         | 
| 48 49 | 
             
                  end
         | 
| 49 50 |  | 
| 50 51 | 
             
                  # Given an RSA private key, it decrypts the data string back into the original text.
         | 
| 51 | 
            -
                  def from_rsa( | 
| 52 | 
            -
                    key = OpenSSL::PKey::RSA.new( | 
| 53 | 
            -
                     | 
| 52 | 
            +
                  def from_rsa(key)
         | 
| 53 | 
            +
                    key = OpenSSL::PKey::RSA.new(key)
         | 
| 54 | 
            +
                    plain_text = key.private? ? key.private_decrypt(self.to_s) : key.public_decrypt(self.to_s)
         | 
| 55 | 
            +
                    return self.class.new(plain_text)
         | 
| 54 56 | 
             
                  end
         | 
| 55 57 |  | 
| 56 58 | 
             
                  # Signs the given message using hte given private key.
         | 
| 57 59 | 
             
                  #
         | 
| 58 | 
            -
                  # By default,  | 
| 59 | 
            -
                   | 
| 60 | 
            -
             | 
| 60 | 
            +
                  # By default, verifies using SHA256, but another digest method can be given
         | 
| 61 | 
            +
                  # using the list of DigestFinder supported digests.
         | 
| 62 | 
            +
                  def sign(private_key, digest_method='SHA-256')
         | 
| 63 | 
            +
                    digest_obj = DigestFinder.find(digest_method).new
         | 
| 61 64 | 
             
                    key = OpenSSL::PKey::RSA.new(private_key)
         | 
| 62 65 | 
             
                    return self.class.new( key.sign(digest_obj, self) )
         | 
| 63 66 | 
             
                  end
         | 
| @@ -65,13 +68,32 @@ module SecurizeString | |
| 65 68 | 
             
                  # Verifies the given signature matches the messages digest, using the
         | 
| 66 69 | 
             
                  # signer's public key.
         | 
| 67 70 | 
             
                  #
         | 
| 68 | 
            -
                  # By default, verifies using SHA256, but another digest  | 
| 69 | 
            -
                   | 
| 70 | 
            -
             | 
| 71 | 
            +
                  # By default, verifies using SHA256, but another digest method can be given
         | 
| 72 | 
            +
                  # using the list of DigestFinder supported digests.
         | 
| 73 | 
            +
                  def verify?(public_key, signature, digest_method='SHA-256')
         | 
| 74 | 
            +
                    digest_obj = DigestFinder.find(digest_method).new
         | 
| 71 75 | 
             
                    key = OpenSSL::PKey::RSA.new(public_key)
         | 
| 72 76 | 
             
                    return key.verify(digest_obj, signature.to_s, self)
         | 
| 73 77 | 
             
                  end
         | 
| 74 78 |  | 
| 79 | 
            +
                  # Interpret the conetents of the string as an RSA key, and determine if it is public.
         | 
| 80 | 
            +
                  #
         | 
| 81 | 
            +
                  # Even though private keys contain all the information necessary to reconstitute
         | 
| 82 | 
            +
                  # a public key, this method returns false.  This is in contrast to the
         | 
| 83 | 
            +
                  # behavior of OpenSSL::PKey::RSA, which return true for both public and
         | 
| 84 | 
            +
                  # private checks with a private key (since it reconstituted the public
         | 
| 85 | 
            +
                  # key and it is available for use).
         | 
| 86 | 
            +
                  def public_rsa_key?
         | 
| 87 | 
            +
                    # There is an interesting bug I came across, where +public?+ can be true on a private key!
         | 
| 88 | 
            +
                    return !private_rsa_key?
         | 
| 89 | 
            +
                  end
         | 
| 90 | 
            +
                  
         | 
| 91 | 
            +
                  # Interpret the conents of the string as an RSA key, and determine if it is private.
         | 
| 92 | 
            +
                  def private_rsa_key?
         | 
| 93 | 
            +
                    key = OpenSSL::PKey::RSA.new(self.to_s)
         | 
| 94 | 
            +
                    return key.private?
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
                  
         | 
| 75 97 | 
             
                end
         | 
| 76 98 |  | 
| 77 99 | 
             
              end
         | 
    
        data/spec/base64_methods_spec.rb
    CHANGED
    
    
| @@ -11,14 +11,14 @@ describe "SecurityString" do | |
| 11 11 | 
             
                it 'should be able to convert to a hex string' do
         | 
| 12 12 | 
             
                  @messages.each do |message|
         | 
| 13 13 | 
             
                    ss = SecureString.new(message[:string])
         | 
| 14 | 
            -
                    ss. | 
| 14 | 
            +
                    ss.data_to_hex.should == message[:hex]
         | 
| 15 15 | 
             
                  end
         | 
| 16 16 | 
             
                end
         | 
| 17 17 |  | 
| 18 18 | 
             
                it 'should be able to convert to an int value' do
         | 
| 19 19 | 
             
                  @messages.each do |message|
         | 
| 20 20 | 
             
                    ss = SecureString.new(message[:string])
         | 
| 21 | 
            -
                    ss. | 
| 21 | 
            +
                    ss.data_to_i.should == message[:int]
         | 
| 22 22 | 
             
                  end
         | 
| 23 23 | 
             
                end
         | 
| 24 24 |  | 
| @@ -34,11 +34,19 @@ describe "SecurityString" do | |
| 34 34 | 
             
                  @messages.each do |message|
         | 
| 35 35 | 
             
                    s = String.new(message[:string])
         | 
| 36 36 | 
             
                    ss = SecureString.new(message[:string])
         | 
| 37 | 
            -
                    ss.inspect.should include(ss. | 
| 37 | 
            +
                    ss.inspect.should include(ss.data_to_hex)
         | 
| 38 38 | 
             
                    ss.inspect.should_not include(s.to_s)
         | 
| 39 39 | 
             
                  end
         | 
| 40 40 | 
             
                end
         | 
| 41 41 |  | 
| 42 | 
            +
                it 'should return appropriate values on an empty string' do
         | 
| 43 | 
            +
                  ss = SecureString.new('')
         | 
| 44 | 
            +
                  
         | 
| 45 | 
            +
                  ss.data_to_hex.should == ''
         | 
| 46 | 
            +
                  ss.data_to_i.should be_kind_of(Integer)
         | 
| 47 | 
            +
                  ss.data_to_i.should == 0
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
                
         | 
| 42 50 | 
             
              end
         | 
| 43 51 |  | 
| 44 52 | 
             
            end
         | 
| @@ -0,0 +1,48 @@ | |
| 1 | 
            +
            require File.join(File.dirname(__FILE__), 'spec_helper')
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe "Digest Finder" do
         | 
| 4 | 
            +
              
         | 
| 5 | 
            +
              it 'should give a list of digests' do
         | 
| 6 | 
            +
                digests = SecurizeString::DigestFinder.digests
         | 
| 7 | 
            +
                digests.should be_kind_of(Array)
         | 
| 8 | 
            +
                digests.should_not be_empty
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
              
         | 
| 11 | 
            +
              it 'should list both upcase and downcase versions of each digest, just like OpenSSL::Cipher::ciphers' do
         | 
| 12 | 
            +
                digests = SecurizeString::DigestFinder.digests
         | 
| 13 | 
            +
                lower = digests.select {|d| d == d.downcase}
         | 
| 14 | 
            +
                upper = digests.select {|d| d == d.upcase}
         | 
| 15 | 
            +
                
         | 
| 16 | 
            +
                lower.length == upper.length
         | 
| 17 | 
            +
                (lower.length * 2) == digests.length
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
              
         | 
| 20 | 
            +
              it 'should find an OpenSSL::Digest instance for a string' do
         | 
| 21 | 
            +
                SecurizeString::DigestFinder.find('SHA-256').should == OpenSSL::Digest::SHA256
         | 
| 22 | 
            +
                SecurizeString::DigestFinder.find('sha-256').should == OpenSSL::Digest::SHA256
         | 
| 23 | 
            +
                SecurizeString::DigestFinder.find('sha256').should  == OpenSSL::Digest::SHA256
         | 
| 24 | 
            +
                SecurizeString::DigestFinder.find('SHA256').should  == OpenSSL::Digest::SHA256
         | 
| 25 | 
            +
                
         | 
| 26 | 
            +
                lambda{ SecurizeString::DigestFinder.find('foobar') }.should raise_error(ArgumentError)
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
              
         | 
| 29 | 
            +
              it 'should pass through a valid OpenSSL::Digest instance' do
         | 
| 30 | 
            +
                SecurizeString::DigestFinder.find(OpenSSL::Digest::SHA256).should == OpenSSL::Digest::SHA256
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
              
         | 
| 33 | 
            +
              it 'should instantiate an OpenSSL::Digest class' do
         | 
| 34 | 
            +
                digest_obj = OpenSSL::Digest::SHA256.new
         | 
| 35 | 
            +
                SecurizeString::DigestFinder.find(digest_obj).should == OpenSSL::Digest::SHA256
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
              
         | 
| 38 | 
            +
              it 'should instantiate a Digest class' do
         | 
| 39 | 
            +
                SecurizeString::DigestFinder.find(Digest::SHA256).should == OpenSSL::Digest::SHA256
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
              
         | 
| 42 | 
            +
              it 'sould convert a Digest instance' do
         | 
| 43 | 
            +
                digest_obj = Digest::SHA256.new
         | 
| 44 | 
            +
                
         | 
| 45 | 
            +
                SecurizeString::DigestFinder.find(digest_obj).should == OpenSSL::Digest::SHA256
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
              
         | 
| 48 | 
            +
            end
         | 
    
        data/spec/digest_methods_spec.rb
    CHANGED
    
    | @@ -1,5 +1,3 @@ | |
| 1 | 
            -
            # Make sure to test that the cipher methods are from openssl and not jsut digest?
         | 
| 2 | 
            -
             | 
| 3 1 | 
             
            require File.join(File.dirname(__FILE__), 'spec_helper')
         | 
| 4 2 |  | 
| 5 3 | 
             
            describe "SecureString" do
         | 
| @@ -18,16 +16,16 @@ describe "SecureString" do | |
| 18 16 | 
             
                  end
         | 
| 19 17 |  | 
| 20 18 | 
             
                  it 'should encode as a SecureString' do
         | 
| 21 | 
            -
                    @message.to_digest( | 
| 22 | 
            -
                    @message.to_digest( | 
| 19 | 
            +
                    @message.to_digest('MD5').should be_kind_of(SecureString)
         | 
| 20 | 
            +
                    @message.to_digest('SHA-512').should be_kind_of(SecureString)
         | 
| 23 21 | 
             
                  end
         | 
| 24 22 |  | 
| 25 23 | 
             
                  it 'should contain the raw value, not the hex value' do
         | 
| 26 | 
            -
                    md5 = @message.to_digest( | 
| 24 | 
            +
                    md5 = @message.to_digest('MD5')
         | 
| 27 25 | 
             
                    md5.should_not == @message_md5_hex
         | 
| 28 26 | 
             
                    md5.to_hex.should == @message_md5_hex
         | 
| 29 27 |  | 
| 30 | 
            -
                    sha512 = @message.to_digest( | 
| 28 | 
            +
                    sha512 = @message.to_digest('SHA-512')
         | 
| 31 29 | 
             
                    sha512.should_not == @message_sha512_hex
         | 
| 32 30 | 
             
                    sha512.to_hex.should == @message_sha512_hex
         | 
| 33 31 | 
             
                  end
         | 
| @@ -0,0 +1,75 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe "Examples" do
         | 
| 4 | 
            +
              
         | 
| 5 | 
            +
              it 'should perform the basic usage example' do
         | 
| 6 | 
            +
                
         | 
| 7 | 
            +
                ss = SecureString.new("Hello World!")
         | 
| 8 | 
            +
                ss.to_s.should == "Hello World!"
         | 
| 9 | 
            +
                ss.inspect.should == "<48656c6c6f20576f726c6421>"
         | 
| 10 | 
            +
                
         | 
| 11 | 
            +
                ss.to_hex.should == "48656c6c6f20576f726c6421"
         | 
| 12 | 
            +
                ss.to_i.should == 22405534230753928650781647905
         | 
| 13 | 
            +
                ss.to_base64.should == "SGVsbG8gV29ybGQh"
         | 
| 14 | 
            +
                
         | 
| 15 | 
            +
                ss1 = SecureString.new(:data, "Hello World!")
         | 
| 16 | 
            +
                ss2 = SecureString.new(:hex, "48656c6c6f20576f726c6421")
         | 
| 17 | 
            +
                ss3 = SecureString.new(:int, 22405534230753928650781647905)
         | 
| 18 | 
            +
                ss4 = SecureString.new(:base64, "SGVsbG8gV29ybGQh")
         | 
| 19 | 
            +
                
         | 
| 20 | 
            +
                ss1.should == ss
         | 
| 21 | 
            +
                ss2.should == ss
         | 
| 22 | 
            +
                ss3.should == ss 
         | 
| 23 | 
            +
                ss4.should == ss 
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
              
         | 
| 26 | 
            +
              it 'should perform the base64 example' do
         | 
| 27 | 
            +
                SecureString.new("Hello World!").to_base64.should == "SGVsbG8gV29ybGQh"
         | 
| 28 | 
            +
                
         | 
| 29 | 
            +
                (SecureString.new(:base64, "SGVsbG8gV29ybGQh") == "Hello World!"   ).should be_true
         | 
| 30 | 
            +
                (SecureString.new("SGVsbG8gV29ybGQh") == "Hello World!"            ).should be_false
         | 
| 31 | 
            +
                (SecureString.new("SGVsbG8gV29ybGQh").from_base64 == "Hello World!").should be_true
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
              
         | 
| 34 | 
            +
              it 'should perform digest example' do
         | 
| 35 | 
            +
                ss = SecureString.new("Hello World!")
         | 
| 36 | 
            +
                ss.to_md5.to_hex.should == "ed076287532e86365e841e92bfc50d8c"
         | 
| 37 | 
            +
                ss.to_sha1.to_hex.should == "2ef7bde608ce5404e97d5f042f95f89f1c232871"
         | 
| 38 | 
            +
                ss.to_sha256.to_hex.should == "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"
         | 
| 39 | 
            +
                ss.to_digest(OpenSSL::Digest::SHA512).to_hex.should == "861844d6704e8573fec34d967e20bcfef3d424cf48be04e6dc08f2bd58c729743371015ead891cc3cf1c9d34b49264b510751b1ff9e537937bc46b5d6ff4ecc8"
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
              
         | 
| 42 | 
            +
              it 'should perform the cipher example' do
         | 
| 43 | 
            +
                # Generate a random key and initialization vector.
         | 
| 44 | 
            +
                key, iv = SecureString.aes_keygen
         | 
| 45 | 
            +
                
         | 
| 46 | 
            +
                # Now encrypt a message:
         | 
| 47 | 
            +
                message = SecureString.new("Hello World!")
         | 
| 48 | 
            +
                cipher_text = message.to_aes(key, iv)
         | 
| 49 | 
            +
                
         | 
| 50 | 
            +
                # Now decrypt the message:
         | 
| 51 | 
            +
                decoded_text = cipher_text.from_aes(key, iv)
         | 
| 52 | 
            +
                
         | 
| 53 | 
            +
                decoded_text.should == message
         | 
| 54 | 
            +
                cipher_text.should_not == message
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
              
         | 
| 57 | 
            +
              it 'should perform the char encoding example' do
         | 
| 58 | 
            +
                s = "Resum\u00E9"
         | 
| 59 | 
            +
                s.encoding.should == Encoding.find("UTF-8")
         | 
| 60 | 
            +
                s.length.should == 6
         | 
| 61 | 
            +
                s.bytesize.should == 7
         | 
| 62 | 
            +
                
         | 
| 63 | 
            +
                s = "Resum\u00E9"
         | 
| 64 | 
            +
                s.force_encoding('BINARY')
         | 
| 65 | 
            +
                s.encoding.should == Encoding.find("ASCII-8BIT")
         | 
| 66 | 
            +
                s.length.should == 7
         | 
| 67 | 
            +
                s.bytesize.should == 7
         | 
| 68 | 
            +
                
         | 
| 69 | 
            +
                s = "Resum\u00E9"
         | 
| 70 | 
            +
                b = s.dup.force_encoding('BINARY')
         | 
| 71 | 
            +
                (s == b).should be_false
         | 
| 72 | 
            +
                (s.bytes.to_a == b.bytes.to_a).should be_true
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
              
         | 
| 75 | 
            +
            end
         | 
    
        data/spec/rsa_methods_spec.rb
    CHANGED
    
    | @@ -61,14 +61,29 @@ describe "SecureString" do | |
| 61 61 | 
             
                    end
         | 
| 62 62 | 
             
                  end
         | 
| 63 63 |  | 
| 64 | 
            +
                  it 'should be able to determine if the key is public or private' do
         | 
| 65 | 
            +
                    pvt_key, pub_key = SecureString.rsa_keygen
         | 
| 66 | 
            +
                    
         | 
| 67 | 
            +
                    pvt_key.public_rsa_key?.should be_false
         | 
| 68 | 
            +
                    pvt_key.private_rsa_key?.should be_true
         | 
| 69 | 
            +
                    
         | 
| 70 | 
            +
                    pub_key.public_rsa_key?.should be_true
         | 
| 71 | 
            +
                    pub_key.private_rsa_key?.should be_false
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                  
         | 
| 64 74 | 
             
                end
         | 
| 65 75 |  | 
| 66 76 | 
             
                describe "Encryption" do
         | 
| 67 77 |  | 
| 68 78 | 
             
                  before(:all) do
         | 
| 69 79 | 
             
                    @key_length = 128
         | 
| 70 | 
            -
                     | 
| 71 | 
            -
                     | 
| 80 | 
            +
                    
         | 
| 81 | 
            +
                    #@pvt_key = SecureString.new(:hex, "2d2d2d2d2d424547494e205253412050524956415445204b45592d2d2d2d2d0a4d47454341514143455143364c704764426d334a78495048513945345537443141674d424141454345474c62517a6e724a6652525762433365474b3561656b430a4351446d633569312f5669666277494a414d37536b4534554b7750624167682b7831316430564274395149494a4648372f346f784a364d4343474e646e3933330a4a43774d0a2d2d2d2d2d454e44205253412050524956415445204b45592d2d2d2d2d0a")
         | 
| 82 | 
            +
                    @pvt_key = SecureString.new("-----BEGIN RSA PRIVATE KEY-----\nMGECAQACEQC6LpGdBm3JxIPHQ9E4U7D1AgMBAAECEGLbQznrJfRRWbC3eGK5aekC\nCQDmc5i1/VifbwIJAM7SkE4UKwPbAgh+x11d0VBt9QIIJFH7/4oxJ6MCCGNdn933\nJCwM\n-----END RSA PRIVATE KEY-----")
         | 
| 83 | 
            +
                    
         | 
| 84 | 
            +
                    #@pub_key = SecureString.new(:hex, "2d2d2d2d2d424547494e20525341205055424c4943204b45592d2d2d2d2d0a4d426743455143364c704764426d334a78495048513945345537443141674d424141453d0a2d2d2d2d2d454e4420525341205055424c4943204b45592d2d2d2d2d0a")
         | 
| 85 | 
            +
                    @pub_key = SecureString.new("-----BEGIN RSA PUBLIC KEY-----\nMBgCEQC6LpGdBm3JxIPHQ9E4U7D1AgMBAAE=\n-----END RSA PUBLIC KEY-----")
         | 
| 86 | 
            +
                    
         | 
| 72 87 | 
             
                    @message = SecureString.new("Hello")
         | 
| 73 88 | 
             
                  end
         | 
| 74 89 |  | 
| @@ -81,7 +96,7 @@ describe "SecureString" do | |
| 81 96 |  | 
| 82 97 | 
             
                  # We cannot independently test encryption because it changes everytime
         | 
| 83 98 | 
             
                  # thanks to padding generation.
         | 
| 84 | 
            -
                  it 'should encrypt and  | 
| 99 | 
            +
                  it 'should encrypt and decrypt a message' do
         | 
| 85 100 | 
             
                    encrypted_message = @message.to_rsa(@pub_key)
         | 
| 86 101 | 
             
                    (encrypted_message.bytesize * 8).should == @key_length
         | 
| 87 102 |  | 
| @@ -89,6 +104,14 @@ describe "SecureString" do | |
| 89 104 | 
             
                    decrypted_message.should == @message
         | 
| 90 105 | 
             
                  end
         | 
| 91 106 |  | 
| 107 | 
            +
                  it 'should encrypt and decrypt a message swapping pub and pvt keys' do
         | 
| 108 | 
            +
                    encrypted_message = @message.to_rsa(@pvt_key)
         | 
| 109 | 
            +
                    (encrypted_message.bytesize * 8).should == @key_length
         | 
| 110 | 
            +
                    
         | 
| 111 | 
            +
                    decrypted_message = encrypted_message.from_rsa(@pub_key)
         | 
| 112 | 
            +
                    decrypted_message.should == @message
         | 
| 113 | 
            +
                  end
         | 
| 114 | 
            +
                  
         | 
| 92 115 | 
             
                end
         | 
| 93 116 |  | 
| 94 117 |  | 
| @@ -102,50 +125,53 @@ describe "SecureString" do | |
| 102 125 | 
             
                    @message = SecureString.new("Hello")
         | 
| 103 126 | 
             
                  end
         | 
| 104 127 |  | 
| 105 | 
            -
                  it 'should  | 
| 128 | 
            +
                  it 'should do a standard encrypt/sign then verify/decrypt cycle' do
         | 
| 106 129 | 
             
                    # Alice encrypts a message for Bob and signs is.
         | 
| 107 | 
            -
                     | 
| 108 | 
            -
                     | 
| 130 | 
            +
                    encrypted_message = @message.to_rsa(@bob_pub_key)
         | 
| 131 | 
            +
                    signature = encrypted_message.sign(@alice_pvt_key)
         | 
| 132 | 
            +
                    encrypted_message.should_not be_empty
         | 
| 133 | 
            +
                    signature.should_not be_empty
         | 
| 109 134 |  | 
| 110 135 | 
             
                    # Verify it came from Alice.
         | 
| 111 | 
            -
                    is_verified =  | 
| 136 | 
            +
                    is_verified = encrypted_message.verify?(@alice_pub_key, signature)
         | 
| 112 137 | 
             
                    is_verified.should be_true
         | 
| 113 138 |  | 
| 114 139 | 
             
                    # Verify it did not come from Bob.
         | 
| 115 | 
            -
                    is_verified =  | 
| 140 | 
            +
                    is_verified = encrypted_message.verify?(@bob_pub_key, signature)
         | 
| 116 141 | 
             
                    is_verified.should be_false
         | 
| 117 142 |  | 
| 118 143 | 
             
                    # Bob should now decrypt it
         | 
| 119 | 
            -
                     | 
| 120 | 
            -
                     | 
| 144 | 
            +
                    decrypted_message = encrypted_message.from_rsa(@bob_pvt_key)
         | 
| 145 | 
            +
                    decrypted_message.should == @message
         | 
| 121 146 | 
             
                  end
         | 
| 122 147 |  | 
| 123 148 | 
             
                  it 'should default to signing with SHA-256' do
         | 
| 124 149 | 
             
                    encrypted_message = @message.to_rsa(@bob_pub_key)
         | 
| 125 | 
            -
                    encrypted_message.sign(@alice_pvt_key).should == encrypted_message.sign(@alice_pvt_key,  | 
| 150 | 
            +
                    encrypted_message.sign(@alice_pvt_key).should == encrypted_message.sign(@alice_pvt_key, 'SHA-256')
         | 
| 126 151 | 
             
                  end
         | 
| 127 152 |  | 
| 128 | 
            -
                  it 'should allow signing with other  | 
| 153 | 
            +
                  it 'should allow signing with other digests' do
         | 
| 129 154 | 
             
                    encrypted_message = @message.to_rsa(@bob_pub_key)
         | 
| 130 | 
            -
                     | 
| 131 | 
            -
                    [ | 
| 132 | 
            -
                      next if  | 
| 133 | 
            -
                      signature = encrypted_message.sign(@alice_pvt_key,  | 
| 134 | 
            -
                      signature.should_not == encrypted_message.sign(@alice_pvt_key,  | 
| 155 | 
            +
                    comparison_digest_method = 'SHA-256'
         | 
| 156 | 
            +
                    ['SHA-512', 'MD5', 'SHA-1'].each do |digest_method|
         | 
| 157 | 
            +
                      next if digest_method == comparison_digest_method
         | 
| 158 | 
            +
                      signature = encrypted_message.sign(@alice_pvt_key, digest_method)
         | 
| 159 | 
            +
                      signature.should_not == encrypted_message.sign(@alice_pvt_key, comparison_digest_method)
         | 
| 135 160 | 
             
                    end
         | 
| 136 161 | 
             
                  end
         | 
| 137 162 |  | 
| 138 | 
            -
                  it 'should allow passing the digest method as an instance or  | 
| 163 | 
            +
                  it 'should allow passing the digest method as an instance, class, or string' do
         | 
| 139 164 | 
             
                    encrypted_message = @message.to_rsa(@bob_pub_key)
         | 
| 140 165 | 
             
                    [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 | 
| 142 | 
            -
                      signature2 = encrypted_message.sign(@alice_pvt_key, digest_klass)
         | 
| 143 | 
            -
                       | 
| 166 | 
            +
                      signature1 = encrypted_message.sign(@alice_pvt_key, digest_klass)
         | 
| 167 | 
            +
                      signature2 = encrypted_message.sign(@alice_pvt_key, digest_klass.new)
         | 
| 168 | 
            +
                      signature3 = encrypted_message.sign(@alice_pvt_key, digest_klass.name.split('::').last)
         | 
| 169 | 
            +
                      signature2.should == signature1
         | 
| 170 | 
            +
                      signature3.should == signature1
         | 
| 144 171 | 
             
                    end
         | 
| 145 172 | 
             
                  end
         | 
| 146 173 |  | 
| 147 174 | 
             
                  it 'should work with Digest scoped digest classes' do
         | 
| 148 | 
            -
                    pending "TODO: postponing feature"
         | 
| 149 175 | 
             
                    encrypted_message = @message.to_rsa(@bob_pub_key)
         | 
| 150 176 | 
             
                    signature1 = encrypted_message.sign(@alice_pvt_key, Digest::SHA256)
         | 
| 151 177 | 
             
                    signature2 = encrypted_message.sign(@alice_pvt_key, OpenSSL::Digest::SHA256)
         | 
| @@ -153,7 +179,6 @@ describe "SecureString" do | |
| 153 179 | 
             
                  end
         | 
| 154 180 |  | 
| 155 181 | 
             
                  it 'should work with Digest scoped digest instances' do
         | 
| 156 | 
            -
                    pending "TODO: postponing feature"
         | 
| 157 182 | 
             
                    encrypted_message = @message.to_rsa(@bob_pub_key)
         | 
| 158 183 | 
             
                    signature1 = encrypted_message.sign(@alice_pvt_key, Digest::SHA256.new)
         | 
| 159 184 | 
             
                    signature2 = encrypted_message.sign(@alice_pvt_key, OpenSSL::Digest::SHA256.new)
         | 
    
        data/spec/secure_string_spec.rb
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            #encoding: UTF-8
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            require File.join(File.dirname(__FILE__), 'spec_helper')
         | 
| 2 4 |  | 
| 3 5 | 
             
            describe "SecureString" do
         | 
| @@ -56,4 +58,72 @@ describe "SecureString" do | |
| 56 58 | 
             
                newline_count.select {|nl_count| nl_count > 1}.should_not be_empty
         | 
| 57 59 | 
             
              end
         | 
| 58 60 |  | 
| 61 | 
            +
              it 'should implement to_hex' do
         | 
| 62 | 
            +
                SecureString.instance_methods.should include(:to_hex)
         | 
| 63 | 
            +
                
         | 
| 64 | 
            +
                @messages.each do |message|
         | 
| 65 | 
            +
                  ss = SecureString.new(message[:string])
         | 
| 66 | 
            +
                  ss.to_hex.should == ss.data_to_hex
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
              
         | 
| 70 | 
            +
              it 'should implement to_i properly' do
         | 
| 71 | 
            +
                SecureString.instance_methods.should include(:to_i)
         | 
| 72 | 
            +
                
         | 
| 73 | 
            +
                @messages.each do |message|
         | 
| 74 | 
            +
                  ss = SecureString.new(message[:string])
         | 
| 75 | 
            +
                  ss.to_i.should == ss.data_to_i
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
              
         | 
| 79 | 
            +
              it 'should parse hex data with spaces' do
         | 
| 80 | 
            +
                
         | 
| 81 | 
            +
                data = <<-DATA
         | 
| 82 | 
            +
                a766a602 b65cffe7 73bcf258 26b322b3 d01b1a97 2684ef53 3e3b4b7f 53fe3762
         | 
| 83 | 
            +
                24c08e47 e959b2bc 3b519880 b9286568 247d110f 70f5c5e2 b4590ca3 f55f52fe
         | 
| 84 | 
            +
                effd4c8f e68de835 329e603c c51e7f02 545410d1 671d108d f5a4000d cf20a439
         | 
| 85 | 
            +
                4949d72c d14fbb03 45cf3a29 5dcda89f 998f8755 2c9a58b1 bdc38483 5e477185
         | 
| 86 | 
            +
                f96e68be bb0025d2 d2b69edf 21724198 f688b41d eb9b4913 fbe696b5 457ab399
         | 
| 87 | 
            +
                21e1d759 1f89de84 57e8613c 6c9e3b24 2879d4d8 783b2d9c a9935ea5 26a729c0
         | 
| 88 | 
            +
                6edfc501 37e69330 be976012 cc5dfe1c 14c4c68b d1db3ecb 24438a59 a09b5db4
         | 
| 89 | 
            +
                35563e0d 8bdf572f 77b53065 cef31f32 dc9dbaa0 4146261e 9994bd5c d0758e3d"
         | 
| 90 | 
            +
                DATA
         | 
| 91 | 
            +
                
         | 
| 92 | 
            +
                ss = SecureString.new(:hex, data)
         | 
| 93 | 
            +
                
         | 
| 94 | 
            +
                # This was taken from a publically published SHA-0 data collision document,
         | 
| 95 | 
            +
                # so the best way to know that the data is good is to SHA-0 it and see if
         | 
| 96 | 
            +
                # we get back the value!  (http://fr.wikipedia.org/wiki/SHA-0)
         | 
| 97 | 
            +
                OpenSSL::Digest::SHA.hexdigest(ss).should == "c9f160777d4086fe8095fba58b7e20c228a4006b"
         | 
| 98 | 
            +
              end
         | 
| 99 | 
            +
              
         | 
| 100 | 
            +
              describe 'Encodings' do
         | 
| 101 | 
            +
                
         | 
| 102 | 
            +
                before(:each) do
         | 
| 103 | 
            +
                  @unicode_string = "A resumé for the moose; Eine Zusammenfassung für die Elche; Резюме для лосей; アメリカヘラジカのための概要; Μια περίληψη για τις άλκες; 麋的一份簡歷; Un résumé pour les orignaux."
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
                
         | 
| 106 | 
            +
                it 'should NOT change the encoding of a string' do
         | 
| 107 | 
            +
                  @unicode_string.encoding.should == Encoding.find("UTF-8")
         | 
| 108 | 
            +
                  ss = SecureString.new(@unicode_string)
         | 
| 109 | 
            +
                  ss.encoding.should == @unicode_string.encoding
         | 
| 110 | 
            +
                end
         | 
| 111 | 
            +
                
         | 
| 112 | 
            +
                it 'should NOT change the length to the byte count for UTF-8 encoded strings.' do
         | 
| 113 | 
            +
                  @unicode_string.encoding.should == Encoding.find("UTF-8")
         | 
| 114 | 
            +
                  ss = SecureString.new(@unicode_string)
         | 
| 115 | 
            +
                  ss.length.should < ss.bytesize
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
                
         | 
| 118 | 
            +
                it 'should allow forced transcoding to binary' do
         | 
| 119 | 
            +
                  ss = SecureString.new(@unicode_string)
         | 
| 120 | 
            +
                  
         | 
| 121 | 
            +
                  ss.encoding.should == Encoding.find("UTF-8")
         | 
| 122 | 
            +
                  ss.force_encoding("Binary")
         | 
| 123 | 
            +
                  ss.encoding.should == Encoding.find("ASCII-8BIT")
         | 
| 124 | 
            +
                  @unicode_string.encoding.should == Encoding.find("UTF-8")
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
                
         | 
| 127 | 
            +
              end
         | 
| 128 | 
            +
              
         | 
| 59 129 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version | |
| 5 5 | 
             
              segments: 
         | 
| 6 6 | 
             
              - 1
         | 
| 7 7 | 
             
              - 1
         | 
| 8 | 
            -
              -  | 
| 9 | 
            -
              version: 1.1. | 
| 8 | 
            +
              - 1
         | 
| 9 | 
            +
              version: 1.1.1
         | 
| 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-05 00:00:00 -07:00
         | 
| 18 18 | 
             
            default_executable: 
         | 
| 19 19 | 
             
            dependencies: []
         | 
| 20 20 |  | 
| @@ -34,13 +34,16 @@ files: | |
| 34 34 | 
             
            - lib/securize_string/base64_methods.rb
         | 
| 35 35 | 
             
            - lib/securize_string/binary_string_data_methods.rb
         | 
| 36 36 | 
             
            - lib/securize_string/cipher_methods.rb
         | 
| 37 | 
            +
            - lib/securize_string/digest_finder.rb
         | 
| 37 38 | 
             
            - lib/securize_string/digest_methods.rb
         | 
| 38 39 | 
             
            - lib/securize_string/rsa_methods.rb
         | 
| 39 40 | 
             
            - lib/securize_string.rb
         | 
| 40 41 | 
             
            - spec/base64_methods_spec.rb
         | 
| 41 42 | 
             
            - spec/binary_string_data_methods_spec.rb
         | 
| 42 43 | 
             
            - spec/cipher_methods_spec.rb
         | 
| 44 | 
            +
            - spec/digest_finder_spec.rb
         | 
| 43 45 | 
             
            - spec/digest_methods_spec.rb
         | 
| 46 | 
            +
            - spec/example_spec.rb
         | 
| 44 47 | 
             
            - spec/rsa_methods_spec.rb
         | 
| 45 48 | 
             
            - spec/secure_string_spec.rb
         | 
| 46 49 | 
             
            - spec/spec_helper.rb
         | 
| @@ -61,8 +64,8 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 61 64 | 
             
                  segments: 
         | 
| 62 65 | 
             
                  - 1
         | 
| 63 66 | 
             
                  - 9
         | 
| 64 | 
            -
                  -  | 
| 65 | 
            -
                  version: 1.9. | 
| 67 | 
            +
                  - 0
         | 
| 68 | 
            +
                  version: 1.9.0
         | 
| 66 69 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 67 70 | 
             
              none: false
         | 
| 68 71 | 
             
              requirements: 
         |