Module: GoSecure
- Defined in:
- lib/go_secure.rb
Defined Under Namespace
Modules: SecureJson
Class Method Summary collapse
- .browser_token ⇒ Object
- .decrypt(str, salt, ref, encryption_key = nil) ⇒ Object
- .encrypt(str, ref, encryption_key = nil) ⇒ Object
- .encryption_key ⇒ Object
- .generate_password(password) ⇒ Object
- .matches_password?(attempt, password_hash) ⇒ Boolean
- .nonce(str) ⇒ Object
- .outdated_password?(password_hash) ⇒ Boolean
- .sha512(str, salt, encryption_key = nil) ⇒ Object
- .valid_browser_token?(token) ⇒ Boolean
- .valid_browser_token_signature?(token) ⇒ Boolean
- .validate_encryption_key ⇒ Object
Class Method Details
.browser_token ⇒ Object
97 98 99 100 101 |
# File 'lib/go_secure.rb', line 97 def self.browser_token # TODO: checks around whether it's actually a web browser?? stamp = Time.now.strftime('%Y%j') stamp += '-' + GoSecure.sha512(stamp, 'browser_token') end |
.decrypt(str, salt, ref, encryption_key = nil) ⇒ Object
24 25 26 27 28 29 30 31 32 33 |
# File 'lib/go_secure.rb', line 24 def self.decrypt(str, salt, ref, encryption_key=nil) require 'base64' c = OpenSSL::Cipher::Cipher.new('aes-256-cbc') c.decrypt c.key = Digest::SHA2.hexdigest(ref + "_" + (encryption_key || self.encryption_key)) c.iv = Base64.decode64(salt) d = c.update(Base64.decode64(str)) d << c.final d.to_s end |
.encrypt(str, ref, encryption_key = nil) ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/go_secure.rb', line 12 def self.encrypt(str, ref, encryption_key=nil) require 'base64' c = OpenSSL::Cipher::Cipher.new('aes-256-cbc') c.encrypt c.key = Digest::SHA2.hexdigest(ref + "_" + (encryption_key || self.encryption_key)) c.iv = iv = c.random_iv e = c.update(str) e << c.final res = [Base64.encode64(e), Base64.encode64(iv)] res end |
.encryption_key ⇒ Object
93 94 95 |
# File 'lib/go_secure.rb', line 93 def self.encryption_key ENV['SECURE_ENCRYPTION_KEY'] end |
.generate_password(password) ⇒ Object
35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/go_secure.rb', line 35 def self.generate_password(password) raise "password required" if password == nil || password.length == 0 pw = {} # pw['hash_type'] = 'sha512' # pw['hash_type'] = 'bcrypt' pw['hash_type'] = 'pbkdf2-sha256' pw['salt'] = Digest::MD5.hexdigest(OpenSSL::Random.pseudo_bytes(4) + Time.now.to_i.to_s + self.encryption_key + "pw" + OpenSSL::Random.pseudo_bytes(16)) # pw['hashed_password'] = Digest::SHA512.hexdigest(self.encryption_key + pw['salt'] + password.to_s) # salted = Digest::SHA256.hexdigest(self.encryption_key + pw['salt'] + password.to_s) # pw['hashed_password'] = BCrypt::Password.create(salted) digest = OpenSSL::Digest::SHA256.new pw['hashed_password'] = Base64.encode64(OpenSSL::PKCS5.pbkdf2_hmac(password.to_s, pw['salt'], 100000, digest.digest_length, digest)) pw end |
.matches_password?(attempt, password_hash) ⇒ Boolean
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/go_secure.rb', line 54 def self.matches_password?(attempt, password_hash) if password_hash && password_hash['hash_type'] == 'sha512' && password_hash['salt'] str = Digest::SHA512.hexdigest(self.encryption_key + password_hash['salt'] + attempt.to_s) res = str == password_hash['hashed_password'] if !res && password_hash['old_passwords'] # TODO: support for migrating to new hashing algorithms else res end elsif password_hash && password_hash['hash_type'] == 'bcrypt' && password_hash['salt'] pw = BCrypt::Password.new(password_hash['hashed_password']) salted = Digest::SHA256.hexdigest(self.encryption_key + password_hash['salt'] + attempt.to_s) res = pw == salted elsif password_hash && password_hash['hash_type'] == 'pbkdf2-sha256' && password_hash['salt'] digest = OpenSSL::Digest::SHA256.new str = Base64.encode64(OpenSSL::PKCS5.pbkdf2_hmac(attempt.to_s, password_hash['salt'], 100000, digest.digest_length, digest)) res = str == password_hash['hashed_password'] else false end end |
.nonce(str) ⇒ Object
8 9 10 |
# File 'lib/go_secure.rb', line 8 def self.nonce(str) Digest::SHA512.hexdigest(str.to_s + Time.now.to_i.to_s + rand(999999).to_s + self.encryption_key)[0, 24] end |
.outdated_password?(password_hash) ⇒ Boolean
50 51 52 |
# File 'lib/go_secure.rb', line 50 def self.outdated_password?(password_hash) return password_hash && password_hash['hash_type'] != 'pbkdf2-sha256' end |
.sha512(str, salt, encryption_key = nil) ⇒ Object
4 5 6 |
# File 'lib/go_secure.rb', line 4 def self.sha512(str, salt, encryption_key=nil) Digest::SHA512.hexdigest(str.to_s + salt.to_s + (encryption_key || self.encryption_key)) end |
.valid_browser_token?(token) ⇒ Boolean
108 109 110 111 112 113 114 115 |
# File 'lib/go_secure.rb', line 108 def self.valid_browser_token?(token) return false if !token || token.length == 0 || !token.match(/-/) stamp, hash = token.split(/-/, 2) if Time.now.strftime('%Y%j').to_i - stamp.to_i < 14 # 14 days?! return valid_browser_token_signature?(token) end false end |
.valid_browser_token_signature?(token) ⇒ Boolean
103 104 105 106 |
# File 'lib/go_secure.rb', line 103 def self.valid_browser_token_signature?(token) stamp, hash = token.split(/-/, 2) return hash == GoSecure.sha512(stamp, 'browser_token') end |
.validate_encryption_key ⇒ Object
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/go_secure.rb', line 76 def self.validate_encryption_key if !self.encryption_key || self.encryption_key.length < 24 raise "SECURE_ENCRYPTION_KEY env variable should be at least 24 characters" end return if !ActiveRecord::Base.connection.data_source_exists?('settings') config_hash = Digest::SHA1.hexdigest(self.encryption_key) stored_hash = Setting.get('encryption_hash') return if stored_hash == config_hash if stored_hash.nil? Setting.set('encryption_hash', config_hash); else raise "SECURE_ENCRYPTION_KEY env variable doesn't match the value stored in the database." + " If this is intentional you can try DELETE FROM settings WHERE key='encryption_hash' to reset." end end |