Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Firebase SCrypt in Ruby. This file is Ruby version for this code: https://github.com/JaakkoL/firebase-scrypt-python/blob/master/firebasescrypt/firebasescrypt.py
require 'base64'
require 'scrypt'
def generate_derived_key password, salt, salt_separator, rounds, mem_cost
# Generates derived key from known parameters
n = 2 ** mem_cost
p = 1
r = rounds
# We're only using first 32 bytes of the derived key to match expected key length.
derived_key_length = 32
user_salt = Base64.decode64(salt).b
salt_separator = Base64.decode64(salt_separator).b
password = password.b
# https://stackoverflow.com/questions/40409876/encrypting-a-private-key-in-ruby-using-aes-128-ctr-scrypt
SCrypt::Engine.scrypt(password, (user_salt + salt_separator), n, r, p, derived_key_length)
end
# https://gist.github.com/treble37/55459f5f0f218ab9b5ebe74b325f4a41#file-gistfile1-L33-L43
def encrypt signer_key, derived_key
# https://github.com/spreedly/gala/blob/master/lib/gala/payment_token.rb#L113-L116
iv = 0.chr * 16
cipher = OpenSSL::Cipher::AES256.new :CTR
cipher.encrypt
cipher.iv = iv
cipher.key = derived_key
cipher.update(signer_key) + cipher.final
end
def verify_password password, known_hash, salt, salt_separator, signer_key, rounds, mem_cost
derived_key = generate_derived_key password, salt, salt_separator, rounds, mem_cost
signer_key = Base64.decode64(signer_key).b
result = encrypt(signer_key, derived_key)
# We use `strict_encode64` instead of `encode64` to ignore new line in result
# https://stackoverflow.com/questions/2620975/strange-n-in-base64-encoded-string-in-ruby
password_hash = Base64.strict_encode64(result).encode('utf-8')
# Please change this line to `Rack::Utils.secure_compare(a, b)` or `ActiveSupport::SecurityUtils.secure_compare(a, b)`
# If we use `==` method, it could lead to timing attacks.
# https://github.com/mailgun/documentation/issues/133
password_hash == known_hash
end
# Testing
salt_separator = "Bw=="
signer_key = "jxspr8Ki0RYycVU8zykbdLGjFQ3McFUH0uiiTvC8pVMXAn210wjLNmdZJzxUECKbm0QsEmYUSDzZvpjeJ9WmXA=="
rounds= 8
mem_cost=14
password = "user1password"
salt = "42xEC+ixf3L2lw=="
password_hash="lSrfV15cpx95/sZS2W9c9Kp6i/LVgQNDNC/qzrCnh1SAyZvqmZqAjTdn3aoItz+VHjoZilo78198JAdRuid5lQ=="
is_valid = verify_password(password, password_hash, salt, salt_separator, signer_key, rounds, mem_cost)
puts is_valid
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment