unix-crypt 1.0.2 → 1.1.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/lib/unix_crypt.rb +32 -4
- data/test/unix_crypt_test.rb +8 -0
- metadata +21 -41
    
        data/lib/unix_crypt.rb
    CHANGED
    
    | @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            require 'digest'
         | 
| 2 | 
            +
            require 'securerandom'
         | 
| 2 3 |  | 
| 3 4 | 
             
            module UnixCrypt
         | 
| 4 5 | 
             
              def self.valid?(password, string)
         | 
| @@ -6,17 +7,26 @@ module UnixCrypt | |
| 6 7 | 
             
                return password.crypt(string) == string if string.length == 13
         | 
| 7 8 |  | 
| 8 9 | 
             
                return false unless m = string.match(/\A\$([156])\$(?:rounds=(\d+)\$)?(.+)\$(.+)/)
         | 
| 10 | 
            +
             | 
| 9 11 | 
             
                hash = IDENTIFIER_MAPPINGS[m[1]].hash(password, m[3], m[2] && m[2].to_i)
         | 
| 10 12 | 
             
                hash == m[4]
         | 
| 11 13 | 
             
              end
         | 
| 12 14 |  | 
| 13 15 | 
             
              class Base
         | 
| 14 | 
            -
                def self.build(password, salt, rounds = nil)
         | 
| 16 | 
            +
                def self.build(password, salt = nil, rounds = nil)
         | 
| 17 | 
            +
                  salt ||= generate_salt
         | 
| 18 | 
            +
             | 
| 15 19 | 
             
                  "$#{identifier}$#{salt}$#{hash(password, salt, rounds)}"
         | 
| 16 20 | 
             
                end
         | 
| 17 21 |  | 
| 22 | 
            +
                def self.generate_salt
         | 
| 23 | 
            +
                  # Generates a random salt using the same character set as the base64 encoding
         | 
| 24 | 
            +
                  # used by the hash encoder.
         | 
| 25 | 
            +
                  SecureRandom.base64(default_salt_length).gsub("=", "").tr("+", ".")
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 18 28 | 
             
                protected
         | 
| 19 | 
            -
                def self. | 
| 29 | 
            +
                def self.bit_specified_base64encode(input)
         | 
| 20 30 | 
             
                  b64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
         | 
| 21 31 | 
             
                  input = input.bytes.to_a
         | 
| 22 32 | 
             
                  output = ""
         | 
| @@ -35,11 +45,23 @@ module UnixCrypt | |
| 35 45 | 
             
                  remainder = 0 if remainder == 3
         | 
| 36 46 | 
             
                  output[0..-1-remainder]
         | 
| 37 47 | 
             
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def self.prepare_password(password)
         | 
| 50 | 
            +
                  # For Ruby 1.9+, convert the password to UTF-8, then treat that new string
         | 
| 51 | 
            +
                  # as binary for the digest methods.
         | 
| 52 | 
            +
                  if password.respond_to?(:encode)
         | 
| 53 | 
            +
                    password = password.encode("UTF-8")
         | 
| 54 | 
            +
                    password.force_encoding("ASCII-8BIT")
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  password
         | 
| 58 | 
            +
                end
         | 
| 38 59 | 
             
              end
         | 
| 39 60 |  | 
| 40 61 | 
             
              class MD5 < Base
         | 
| 41 62 | 
             
                def self.digest; Digest::MD5; end
         | 
| 42 63 | 
             
                def self.length; 16; end
         | 
| 64 | 
            +
                def self.default_salt_length; 6; end
         | 
| 43 65 | 
             
                def self.identifier; 1; end
         | 
| 44 66 |  | 
| 45 67 | 
             
                def self.byte_indexes
         | 
| @@ -49,6 +71,8 @@ module UnixCrypt | |
| 49 71 | 
             
                def self.hash(password, salt, ignored = nil)
         | 
| 50 72 | 
             
                  salt = salt[0..7]
         | 
| 51 73 |  | 
| 74 | 
            +
                  password = prepare_password(password)
         | 
| 75 | 
            +
             | 
| 52 76 | 
             
                  b = digest.digest("#{password}#{salt}#{password}")
         | 
| 53 77 | 
             
                  a_string = "#{password}$1$#{salt}#{b * (password.length/length)}#{b[0...password.length % length]}"
         | 
| 54 78 |  | 
| @@ -68,11 +92,13 @@ module UnixCrypt | |
| 68 92 | 
             
                    input = digest.digest(c_string)
         | 
| 69 93 | 
             
                  end
         | 
| 70 94 |  | 
| 71 | 
            -
                   | 
| 95 | 
            +
                  bit_specified_base64encode(input)
         | 
| 72 96 | 
             
                end
         | 
| 73 97 | 
             
              end
         | 
| 74 98 |  | 
| 75 99 | 
             
              class SHABase < Base
         | 
| 100 | 
            +
                def self.default_salt_length; 12; end
         | 
| 101 | 
            +
             | 
| 76 102 | 
             
                def self.hash(password, salt, rounds = nil)
         | 
| 77 103 | 
             
                  rounds ||= 5000
         | 
| 78 104 | 
             
                  rounds = 1000        if rounds < 1000
         | 
| @@ -80,6 +106,8 @@ module UnixCrypt | |
| 80 106 |  | 
| 81 107 | 
             
                  salt = salt[0..15]
         | 
| 82 108 |  | 
| 109 | 
            +
                  password = prepare_password(password)
         | 
| 110 | 
            +
             | 
| 83 111 | 
             
                  b = digest.digest("#{password}#{salt}#{password}")
         | 
| 84 112 |  | 
| 85 113 | 
             
                  a_string = password + salt + b * (password.length/length) + b[0...password.length % length]
         | 
| @@ -106,7 +134,7 @@ module UnixCrypt | |
| 106 134 | 
             
                    input = digest.digest(c_string)
         | 
| 107 135 | 
             
                  end
         | 
| 108 136 |  | 
| 109 | 
            -
                   | 
| 137 | 
            +
                  bit_specified_base64encode(input)
         | 
| 110 138 | 
             
                end
         | 
| 111 139 | 
             
              end
         | 
| 112 140 |  | 
    
        data/test/unix_crypt_test.rb
    CHANGED
    
    | @@ -1,3 +1,4 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 1 2 | 
             
            #
         | 
| 2 3 | 
             
            # MD5 test cases constructed by Mark Johnston, taken from
         | 
| 3 4 | 
             
            # http://code.activestate.com/recipes/325204-passwd-file-compatible-1-md5-crypt/
         | 
| @@ -23,6 +24,7 @@ class UnixCryptTest < Test::Unit::TestCase | |
| 23 24 | 
             
                  [nil, '____sixteen_____', '$1$dL3xbVZI$kkgqhCanLdxODGq14g/tW1'],
         | 
| 24 25 | 
             
                  [nil, '____seventeen____', '$1$NaH5na7J$j7y8Iss0hcRbu3kzoJs5V.'],
         | 
| 25 26 | 
             
                  [nil, '__________thirty-three___________', '$1$HO7Q6vzJ$yGwp2wbL5D7eOVzOmxpsy.'],
         | 
| 27 | 
            +
                  [nil, 'Pässword', '$1$NaH5na7J$MvnEHcxaKZzgBk8QdjdAQ0'],
         | 
| 26 28 |  | 
| 27 29 | 
             
                  # SHA256
         | 
| 28 30 | 
             
                  ["$5$saltstring", "Hello world!", "$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5"],
         | 
| @@ -47,4 +49,10 @@ class UnixCryptTest < Test::Unit::TestCase | |
| 47 49 | 
             
                  assert UnixCrypt.valid?(password, expected), "Password '#{password}' (index #{index}) failed"
         | 
| 48 50 | 
             
                end
         | 
| 49 51 | 
             
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              def test_salt_generation
         | 
| 54 | 
            +
                assert_match %r{\A\$1\$[a-zA-Z0-9./]{8}\$[a-zA-Z0-9./]{22}\z}, UnixCrypt::MD5.build("test password")
         | 
| 55 | 
            +
                assert_match %r{\A\$5\$[a-zA-Z0-9./]{16}\$[a-zA-Z0-9./]{43}\z}, UnixCrypt::SHA256.build("test password")
         | 
| 56 | 
            +
                assert_match %r{\A\$6\$[a-zA-Z0-9./]{16}\$[a-zA-Z0-9./]{86}\z}, UnixCrypt::SHA512.build("test password")
         | 
| 57 | 
            +
              end
         | 
| 50 58 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,68 +1,48 @@ | |
| 1 | 
            -
            --- !ruby/object:Gem::Specification | 
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: unix-crypt
         | 
| 3 | 
            -
            version: !ruby/object:Gem::Version | 
| 4 | 
            -
               | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 1.1.0
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 | 
            -
              segments: 
         | 
| 7 | 
            -
              - 1
         | 
| 8 | 
            -
              - 0
         | 
| 9 | 
            -
              - 2
         | 
| 10 | 
            -
              version: 1.0.2
         | 
| 11 6 | 
             
            platform: ruby
         | 
| 12 | 
            -
            authors: | 
| 7 | 
            +
            authors:
         | 
| 13 8 | 
             
            - Roger Nesbitt
         | 
| 14 9 | 
             
            autorequire: 
         | 
| 15 10 | 
             
            bindir: bin
         | 
| 16 11 | 
             
            cert_chain: []
         | 
| 17 | 
            -
             | 
| 18 | 
            -
            date: 2012-03-22 00:00:00 +13:00
         | 
| 19 | 
            -
            default_executable: 
         | 
| 12 | 
            +
            date: 2013-04-02 00:00:00.000000000 Z
         | 
| 20 13 | 
             
            dependencies: []
         | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 14 | 
            +
            description: Performs the UNIX crypt(3) algorithm using DES (standard 13 character
         | 
| 15 | 
            +
              passwords), MD5 (starting with $1$), SHA256 (starting with $5$) and SHA512 (starting
         | 
| 16 | 
            +
              with $6$)
         | 
| 23 17 | 
             
            email: roger@seriousorange.com
         | 
| 24 18 | 
             
            executables: []
         | 
| 25 | 
            -
             | 
| 26 19 | 
             
            extensions: []
         | 
| 27 | 
            -
             | 
| 28 20 | 
             
            extra_rdoc_files: []
         | 
| 29 | 
            -
             | 
| 30 | 
            -
            files: 
         | 
| 21 | 
            +
            files:
         | 
| 31 22 | 
             
            - lib/unix_crypt.rb
         | 
| 32 23 | 
             
            - test/unix_crypt_test.rb
         | 
| 33 | 
            -
            has_rdoc: true
         | 
| 34 24 | 
             
            homepage: 
         | 
| 35 25 | 
             
            licenses: []
         | 
| 36 | 
            -
             | 
| 37 26 | 
             
            post_install_message: 
         | 
| 38 27 | 
             
            rdoc_options: []
         | 
| 39 | 
            -
             | 
| 40 | 
            -
            require_paths: 
         | 
| 28 | 
            +
            require_paths:
         | 
| 41 29 | 
             
            - lib
         | 
| 42 | 
            -
            required_ruby_version: !ruby/object:Gem::Requirement | 
| 30 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 43 31 | 
             
              none: false
         | 
| 44 | 
            -
              requirements: | 
| 45 | 
            -
              - -  | 
| 46 | 
            -
                - !ruby/object:Gem::Version | 
| 47 | 
            -
                   | 
| 48 | 
            -
             | 
| 49 | 
            -
                  - 0
         | 
| 50 | 
            -
                  version: "0"
         | 
| 51 | 
            -
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 32 | 
            +
              requirements:
         | 
| 33 | 
            +
              - - ! '>='
         | 
| 34 | 
            +
                - !ruby/object:Gem::Version
         | 
| 35 | 
            +
                  version: '0'
         | 
| 36 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 52 37 | 
             
              none: false
         | 
| 53 | 
            -
              requirements: | 
| 54 | 
            -
              - -  | 
| 55 | 
            -
                - !ruby/object:Gem::Version | 
| 56 | 
            -
                   | 
| 57 | 
            -
                  segments: 
         | 
| 58 | 
            -
                  - 0
         | 
| 59 | 
            -
                  version: "0"
         | 
| 38 | 
            +
              requirements:
         | 
| 39 | 
            +
              - - ! '>='
         | 
| 40 | 
            +
                - !ruby/object:Gem::Version
         | 
| 41 | 
            +
                  version: '0'
         | 
| 60 42 | 
             
            requirements: []
         | 
| 61 | 
            -
             | 
| 62 43 | 
             
            rubyforge_project: 
         | 
| 63 | 
            -
            rubygems_version: 1. | 
| 44 | 
            +
            rubygems_version: 1.8.23
         | 
| 64 45 | 
             
            signing_key: 
         | 
| 65 46 | 
             
            specification_version: 3
         | 
| 66 47 | 
             
            summary: Performs the UNIX crypt(3) algorithm using DES, MD5, SHA256 or SHA512
         | 
| 67 48 | 
             
            test_files: []
         | 
| 68 | 
            -
             |