Add libsodium password hashing
parent
a358929e62
commit
a26800765e
|
@ -0,0 +1,22 @@
|
||||||
|
require "../spec_helper"
|
||||||
|
|
||||||
|
describe Cox::Pwhash do
|
||||||
|
it "hashes and verifies a password" do
|
||||||
|
pwhash = Cox::Pwhash.new
|
||||||
|
|
||||||
|
# set to minimum to speed up tests
|
||||||
|
pwhash.memlimit = Cox::Pwhash::MEMLIMIT_MIN
|
||||||
|
pwhash.opslimit = Cox::Pwhash::OPSLIMIT_MIN
|
||||||
|
|
||||||
|
pass = "1234"
|
||||||
|
hash = pwhash.hash_str pass
|
||||||
|
pwhash.verify hash, pass
|
||||||
|
expect_raises(Cox::Pwhash::PasswordVerifyError) do
|
||||||
|
pwhash.verify hash, "5678"
|
||||||
|
end
|
||||||
|
|
||||||
|
pwhash.needs_rehash?(hash).should be_false
|
||||||
|
pwhash.opslimit = Cox::Pwhash::OPSLIMIT_MAX
|
||||||
|
pwhash.needs_rehash?(hash).should be_true
|
||||||
|
end
|
||||||
|
end
|
|
@ -12,6 +12,15 @@ module Cox
|
||||||
fun crypto_sign_bytes() : LibC::SizeT
|
fun crypto_sign_bytes() : LibC::SizeT
|
||||||
fun crypto_kdf_keybytes() : LibC::SizeT
|
fun crypto_kdf_keybytes() : LibC::SizeT
|
||||||
fun crypto_kdf_contextbytes() : LibC::SizeT
|
fun crypto_kdf_contextbytes() : LibC::SizeT
|
||||||
|
fun crypto_pwhash_memlimit_min() : LibC::SizeT
|
||||||
|
fun crypto_pwhash_memlimit_interactive() : LibC::SizeT
|
||||||
|
fun crypto_pwhash_memlimit_max() : LibC::SizeT
|
||||||
|
fun crypto_pwhash_opslimit_min() : LibC::SizeT
|
||||||
|
fun crypto_pwhash_opslimit_interactive() : LibC::SizeT
|
||||||
|
fun crypto_pwhash_opslimit_moderate() : LibC::SizeT
|
||||||
|
fun crypto_pwhash_opslimit_sensitive() : LibC::SizeT
|
||||||
|
fun crypto_pwhash_opslimit_max() : LibC::SizeT
|
||||||
|
fun crypto_pwhash_strbytes() : LibC::SizeT
|
||||||
|
|
||||||
PUBLIC_KEY_BYTES = crypto_box_publickeybytes()
|
PUBLIC_KEY_BYTES = crypto_box_publickeybytes()
|
||||||
SECRET_KEY_BYTES = crypto_box_secretkeybytes()
|
SECRET_KEY_BYTES = crypto_box_secretkeybytes()
|
||||||
|
@ -22,6 +31,7 @@ module Cox
|
||||||
SIGNATURE_BYTES = crypto_sign_bytes()
|
SIGNATURE_BYTES = crypto_sign_bytes()
|
||||||
KDF_KEY_BYTES = crypto_kdf_keybytes()
|
KDF_KEY_BYTES = crypto_kdf_keybytes()
|
||||||
KDF_CONTEXT_BYTES = crypto_kdf_contextbytes()
|
KDF_CONTEXT_BYTES = crypto_kdf_contextbytes()
|
||||||
|
PWHASH_STR_BYTES = crypto_pwhash_strbytes()
|
||||||
|
|
||||||
fun crypto_box_keypair(
|
fun crypto_box_keypair(
|
||||||
public_key_output : Pointer(LibC::UChar),
|
public_key_output : Pointer(LibC::UChar),
|
||||||
|
@ -66,7 +76,6 @@ module Cox
|
||||||
public_key : Pointer(LibC::UChar)
|
public_key : Pointer(LibC::UChar)
|
||||||
) : LibC::Int
|
) : LibC::Int
|
||||||
|
|
||||||
|
|
||||||
fun crypto_kdf_derive_from_key(
|
fun crypto_kdf_derive_from_key(
|
||||||
subkey : Pointer(LibC::UChar),
|
subkey : Pointer(LibC::UChar),
|
||||||
subkey_len : LibC::SizeT,
|
subkey_len : LibC::SizeT,
|
||||||
|
@ -74,5 +83,25 @@ module Cox
|
||||||
ctx : Pointer(LibC::UChar),
|
ctx : Pointer(LibC::UChar),
|
||||||
key : Pointer(LibC::UChar)
|
key : Pointer(LibC::UChar)
|
||||||
) : LibC::Int
|
) : LibC::Int
|
||||||
|
|
||||||
|
fun crypto_pwhash_str(
|
||||||
|
outstr : Pointer(LibC::UChar),
|
||||||
|
pass : Pointer(LibC::UChar),
|
||||||
|
pass_size : LibC::ULongLong,
|
||||||
|
optslimit : LibC::ULongLong,
|
||||||
|
memlimit : LibC::SizeT,
|
||||||
|
) : LibC::Int
|
||||||
|
|
||||||
|
fun crypto_pwhash_str_verify(
|
||||||
|
str : Pointer(LibC::UChar),
|
||||||
|
pass : Pointer(LibC::UChar),
|
||||||
|
pass_size : LibC::ULongLong,
|
||||||
|
) : LibC::Int
|
||||||
|
|
||||||
|
fun crypto_pwhash_str_needs_rehash(
|
||||||
|
str : Pointer(LibC::UChar),
|
||||||
|
optslimit : LibC::ULongLong,
|
||||||
|
memlimit : LibC::SizeT,
|
||||||
|
) : LibC::Int
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
module Cox
|
||||||
|
class Pwhash
|
||||||
|
class PasswordVerifyError < Cox::Error
|
||||||
|
end
|
||||||
|
|
||||||
|
OPSLIMIT_MIN = LibSodium.crypto_pwhash_opslimit_min
|
||||||
|
OPSLIMIT_INTERACTIVE = LibSodium.crypto_pwhash_opslimit_interactive
|
||||||
|
OPSLIMIT_MODERATE = LibSodium.crypto_pwhash_opslimit_moderate
|
||||||
|
OPSLIMIT_SENSITIVE = LibSodium.crypto_pwhash_opslimit_sensitive
|
||||||
|
OPSLIMIT_MAX = LibSodium.crypto_pwhash_opslimit_max
|
||||||
|
|
||||||
|
MEMLIMIT_MIN = LibSodium.crypto_pwhash_memlimit_min
|
||||||
|
MEMLIMIT_MAX = LibSodium.crypto_pwhash_memlimit_max
|
||||||
|
MEMLIMIT_INTERACTIVE = LibSodium.crypto_pwhash_memlimit_interactive
|
||||||
|
|
||||||
|
property opslimit = OPSLIMIT_INTERACTIVE
|
||||||
|
property memlimit = MEMLIMIT_INTERACTIVE
|
||||||
|
|
||||||
|
def hash_str(pass)
|
||||||
|
outstr = Bytes.new LibSodium::PWHASH_STR_BYTES
|
||||||
|
if LibSodium.crypto_pwhash_str(outstr, pass, pass.bytesize, @opslimit, @memlimit) != 0
|
||||||
|
raise Cox::Error.new("crypto_pwhash_str")
|
||||||
|
end
|
||||||
|
outstr
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify(str, pass)
|
||||||
|
# BUG: verify str length
|
||||||
|
case LibSodium.crypto_pwhash_str_verify(str, pass, pass.bytesize)
|
||||||
|
when 0
|
||||||
|
true
|
||||||
|
else
|
||||||
|
raise PasswordVerifyError.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def needs_rehash?(str)
|
||||||
|
# BUG: verify str length
|
||||||
|
case LibSodium.crypto_pwhash_str_needs_rehash(str, @opslimit, @memlimit)
|
||||||
|
when 0
|
||||||
|
false
|
||||||
|
when 1
|
||||||
|
true
|
||||||
|
else
|
||||||
|
raise Cox::Error.new("crypto_pwhash_str_needs_rehash")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue