Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/ruby
- # This script extends the functionality of the String#crypt method
- # for non-Linux environment. On Linux, String#crypt provides
- # all of the functionality of the standard library crypt method.
- # However, on other platforms only the "DES" hashing can be performed.
- # For example, on Windows with Ruby 1.9.3 you see this:
- # irb(main):001:0> "password".crypt("$5$salt")
- # => "$5vvFjbkJCcrk"
- # The expected output was the SHA256 hash of "password" with "salt".
- # On Linux, you instead see this (as should be expected):
- # irb(main):001:0> "password".crypt("$5$salt")
- # => "$5$salt$Gcm6FsVtF/Qa77ZKD.iwsJlCVPY0XSMgLJL0Hnww/c1"
- # I'm not the first to implement this. See also:
- # https://github.com/SJD/unix-crypt
- # The author utilized the documentation provided at this URL:
- # http://www.akkadia.org/drepper/SHA-crypt.txt
- # Copyright (C) 2012 Justin W Smith
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- require 'digest'
- class String
- @@sha_encodings = ['.', '/']
- @@sha_encodings += ('0'..'9').to_a
- @@sha_encodings += ('A'..'Z').to_a
- @@sha_encodings += ('a'..'z').to_a
- @@groups256 =
- [[0, 10, 20], [21, 1, 11], [12, 22, 2],
- [3, 13, 23], [24, 4, 14], [15, 25, 5],
- [6, 16, 26], [27, 7, 17], [18, 28, 8],
- [9, 19, 29], [-1, 31, 30]]
- @@groups512 =
- [[0, 21, 42], [22, 43, 1], [44, 2, 23],
- [3, 24, 45], [25, 46, 4], [47, 5, 26],
- [6, 27, 48], [28, 49, 7], [50, 8, 29],
- [9, 30, 51], [31, 52, 10],
- [53, 11, 32], [12, 33, 54], [34, 55, 13],
- [56, 14, 35], [15, 36, 57], [37, 58, 16],
- [59, 17, 38], [18, 39, 60], [40, 61, 19],
- [62, 20, 41], [-1, -1, 63]]
- @@default_rounds = 5000
- def sha_crypt(digest, salt, rounds = @@default_rounds)
- password = self
- a = digest.new.update(password).update(salt)
- b_result = digest.new.update(password).update(salt).update(password).digest
- (password.length / b_result.length).times { a.update(b_result) }
- a.update(b_result[0...(password.length % b_result.length)])
- password.length.to_s(2).reverse.each_char do |x|
- a.update(x.to_i == 1 ? b_result: password)
- end
- a_result = a.digest
- dp = digest.new
- password.length.times { dp.update(password) }
- dp_result = dp.digest
- pe = (dp_result * (password.length / dp_result.length))
- pe += dp_result[0...(password.length % dp_result.length)]
- ds = digest.new
- (16+a_result[0].ord).times { ds.update salt }
- ds_result = ds.digest
- s = (ds_result * (salt.length / ds_result.length))
- s = ds_result[0...(salt.length % ds_result.length)]
- d21 = a_result
- rounds.times do |i|
- c = digest.new
- c.update i.odd? ? pe : d21
- c.update(s) unless (i % 3).zero?
- c.update(pe) unless (i % 7).zero?
- c.update i.odd? ? d21 : pe
- d21 = c.digest
- end
- d21
- end
- def sha_encode cr, groups
- text = ""
- cr += "\x00"
- groups.each do |group|
- text += @@sha_encodings[cr[group[2]].ord & 0x3F]
- text += @@sha_encodings[((cr[group[2]].ord & 0xC0)>>6) | ((cr[group[1]].ord & 0x0F)<<2)]
- (text += @@sha_encodings[((cr[group[1]].ord & 0xF0)>>4) | ((cr[group[0]].ord & 0x03)<<4)]) unless group[0] < 0 && group[1] < 0
- (text += @@sha_encodings[(cr[group[0]].ord & 0xFC)>>2]) unless group[0] < 0
- end
- text
- end
- #cover my tracks
- method_sha_crypt = instance_method(:sha_crypt)
- method_sha_encode = instance_method(:sha_encode)
- remove_method :sha_crypt
- remove_method :sha_encode
- orig_crypt = instance_method(:crypt)
- define_method(:crypt) do |id_salt|
- if( (md = /^\$([0-9])\$([^\$]*)\$?$/.match id_salt).nil? )
- return orig_crypt.bind(self).(id_salt)
- end
- id = md[1]
- salt = md[2][0...16]
- #p "id: #{id}"
- #p "salt: #{salt}"
- case id.to_i
- when 5
- cr = method_sha_crypt.bind(self).(Digest::SHA256, salt)
- text = method_sha_encode.bind(self).( cr, @@groups256)
- when 6
- cr = method_sha_crypt.bind(self).(Digest::SHA512, salt)
- text = method_sha_encode.bind(self).( cr, @@groups512)
- else
- raise "Unsupported encryption method: #{id}"
- end
- "$#{id}$#{salt}$#{text}"
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement