diff --git a/README.md b/README.md index 713dddb..f03c3d0 100644 --- a/README.md +++ b/README.md @@ -83,8 +83,8 @@ Several features in libsodium are already provided by Crystal: | [`Sodium::Cipher::SecretStream`](https://didactic-drunk.github.io/sodium.cr/Sodium/Cipher/SecretStream/XChaCha20Poly1305.html) | I have a shared key and want encrypt + authenticate streamed data. | | [`Sodium::Digest::Blake2b`](https://didactic-drunk.github.io/sodium.cr/Sodium/Digest::Blake2b.html) | I want to hash data fast and securely. | | `Sodium::Digest::SipHash` | I want to hash data really fast and less securely. (Not implemented yet) | -| [`Sodium::Pwhash`](https://didactic-drunk.github.io/sodium.cr/Sodium/Pwhash.html) | I want to hash a password and store it. | -| [`Sodium::Pwhash`](https://didactic-drunk.github.io/sodium.cr/Sodium/Pwhash.html) | I want to derive a key from a password. | +| [`Sodium::Password::Hash`](https://didactic-drunk.github.io/sodium.cr/Sodium/Password/Hash.html) | I want to hash a password and store it. | +| [`Sodium::Password::Key`](https://didactic-drunk.github.io/sodium.cr/Sodium/Password/Key.html) | I want to derive a key from a password. | | [`Sodium::Kdf`](https://didactic-drunk.github.io/sodium.cr/Sodium/Kdf.html) | I have a high quality master key and want to make subkeys. | | [`Sodium::Cipher::Chalsa`](https://didactic-drunk.github.io/sodium.cr/Sodium/Cipher/Chalsa.html) | What goes with guacamole? | | Everything else | I want to design my own crypto protocol and probably do it wrong. | @@ -228,15 +228,31 @@ subkey3 = kdf.derive "context2", 0, 32 subkey4 = kdf.derive "context2", 1, 64 ``` -### Password Hashing +### Password based keys ```crystal -pwhash = Sodium::Pwhash.new +pwcreate = Sodium::Password::Key::Create.new -pwhash.memlimit = Sodium::Pwhash::MEMLIMIT_MIN -pwhash.opslimit = Sodium::Pwhash::OPSLIMIT_MIN +# Take approximately 1 second to derive a key. +pwcreate.tcost = 1.0 pass = "1234" -hash = pwhash.hash_str pass +key, params = pwcreate.create_key pass +# Store `params` or `params.to_h` for later. + +# Derive the same key from the stored params. +pwkey = Sodium::Password::Key.from_params params.to_h +key = pekey.derive_key pass +``` + +### Password Hashing +```crystal +pwhash = Sodium::Password::Hash.new + +pwhash.mem = Sodium::Password::MEMLIMIT_MIN +pwhash.ops = Sodium::Password::OPSLIMIT_MIN + +pass = "1234" +hash = pwhash.create pass pwhash.verify hash, pass ``` @@ -260,6 +276,8 @@ Ops limit → | 2097152K | 2.119s | | Memory | + + ## Contributing 1. Fork it ( https://github.com/didactic-drunk/sodium.cr/fork ) diff --git a/examples/constants.cr b/examples/constants.cr index 9c4e0b4..9c05ae3 100644 --- a/examples/constants.cr +++ b/examples/constants.cr @@ -23,17 +23,17 @@ puts "" puts "" {% for name in %w(OPSLIMIT_MIN OPSLIMIT_INTERACTIVE OPSLIMIT_MODERATE OPSLIMIT_SENSITIVE OPSLIMIT_MAX) %} - puts "Sodium::Password::{{ name.id }} #{Sodium::Pwhash::{{ name.id }}}" + puts "Sodium::Password::{{ name.id }} #{Sodium::Password::{{ name.id }}}" {% end %} puts "" {% for name in %w(MEMLIMIT_MIN MEMLIMIT_INTERACTIVE MEMLIMIT_MAX) %} - puts "Sodium::Password::{{ name.id }} #{Sodium::Pwhash::{{ name.id }}}" + puts "Sodium::Password::{{ name.id }} #{Sodium::Password::{{ name.id }}}" {% end %} puts "" {% for name in %w(SALT_SIZE STR_SIZE) %} - puts "Sodium::Password::{{ name.id }} #{Sodium::Pwhash::{{ name.id }}}" + puts "Sodium::Password::{{ name.id }} #{Sodium::Password::{{ name.id }}}" {% end %} puts "" diff --git a/src/sodium/password.cr b/src/sodium/password.cr index 242e9b8..e9db0c9 100644 --- a/src/sodium/password.cr +++ b/src/sodium/password.cr @@ -2,13 +2,15 @@ require "./lib_sodium" require "./secure_buffer" # [Argon2 Password Hashing](https://libsodium.gitbook.io/doc/password_hashing/the_argon2i_function) -# * #store #verify #needs_rehash? are used together for password verification. -# * #derive_key is used on it's own to generate password based keys. +# * `Sodium::Password::Hash` +# * - Use for server side authentication replacing scrypt, bcrypt or crypt. +# * `Sodium::Password::Key::Create` +# * - Use to create a key with auto set parameters based on time. +# * - Often used in single user application such as password safes, gpg/ssh keys or other encrypted storage. +# * `Sodium::Password::Key` +# * - Use with the `params` returned by `Create#create_key` or set your own to derive a consistent key or kdf. # # **See `examples/pwhash_selector.cr` for help on selecting parameters.** -# -# ## Creating a key for encryption with auto set parameters based on time. -# module Sodium::Password OPSLIMIT_MIN = LibSodium.crypto_pwhash_opslimit_min OPSLIMIT_INTERACTIVE = LibSodium.crypto_pwhash_opslimit_interactive diff --git a/src/sodium/password/abstract.cr b/src/sodium/password/abstract.cr index 15aa3a6..fc67181 100644 --- a/src/sodium/password/abstract.cr +++ b/src/sodium/password/abstract.cr @@ -1,5 +1,4 @@ -require "../lib_sodium" -require "../secure_buffer" +require "../password" abstract class Sodium::Password::Abstract property ops = OPSLIMIT_INTERACTIVE @@ -29,8 +28,8 @@ abstract class Sodium::Password::Abstract if pw.responds_to?(:tcost=) && (tcost = hash["tcost"]?) pw.tcost = tcost.as(Float64) end - if pw.responds_to?(:auth=) && (auth = hash["auth"]?) - pw.auth = auth.as(Bytes) + if pw.responds_to?(:verify=) && (verify = hash["verify"]?) + pw.verify = verify.as(Bytes) end pw diff --git a/src/sodium/password/create_key.cr b/src/sodium/password/create_key.cr index 7df8e9e..b25c832 100644 --- a/src/sodium/password/create_key.cr +++ b/src/sodium/password/create_key.cr @@ -20,12 +20,15 @@ require "./key" # key, params = pwkc.create_key pass, 32 # # # Save params.[mode, ops, mem, salt, key_size] to derive the same key later. +# # Or serialize `params.to_h` # ``` # # ## Deriving a previously created key. # # Usage: # ``` +# pwkey = Sodium::Password::Key.from_params hash +# # Or # pwkey = Sodium::Password::Key.new # pwkey.mode = Mode.parse serialized[:mode] # pwkey.ops = serialized[:ops] diff --git a/src/sodium/password/hash.cr b/src/sodium/password/hash.cr index 80b594f..73121f7 100644 --- a/src/sodium/password/hash.cr +++ b/src/sodium/password/hash.cr @@ -1,6 +1,23 @@ require "./abstract" module Sodium::Password + # Argon2 password hashing. A modern substitute for scrypt, bcrypt or crypt. + # + # Often used to store password hashes on a server and authenticate clients against the stored hash. + # + # Usage: + # ```crystal + # pwhash = Sodium::Password::Hash.new + # + # pwhash.mem = Sodium::Password::MEMLIMIT_MIN + # pwhash.ops = Sodium::Password::OPSLIMIT_MIN + # + # pass = "1234" + # hash = pwhash.create pass + # pwhash.verify hash, pass + # ``` + # + # Use `examples/pwhash_selector.cr` to help choose ops/mem limits. class Hash < Abstract # Apply the most recent password hashing algorithm against a password. # Returns a opaque String which includes: diff --git a/src/sodium/password/params.cr b/src/sodium/password/params.cr index 4c394c0..a16f3cf 100644 --- a/src/sodium/password/params.cr +++ b/src/sodium/password/params.cr @@ -1,14 +1,18 @@ # Contains the params necessary for #derive_key. class Sodium::Password::Params - property mode : Mode property ops : UInt64 property mem : UInt64 + property mode : Mode? property salt : Bytes? property key_size : Int32? - property tcost : Float64? - property auth : Bytes? - def initialize(@mode, @ops, @mem, @salt = nil, @key_size = nil, @tcost = nil, @auth = nil) + # Information only. Not used to derive a key. + property tcost : Float64? + + # Application specific param to verify a password. + property verify : Bytes? + + def initialize(@mode, @ops, @mem, @salt = nil, @key_size = nil, @tcost = nil, @verify = nil) end def to_h @@ -27,14 +31,10 @@ class Sodium::Password::Params if ks = @key_size hash["key_size"] = ks end - if au = @auth - hash["auth"] = au + if v = @verify + hash["verify"] = v end hash end - - def self.from_h(hash) - self.new Pwhash::Mode.parse(hash["mode"]), hash["ops"], hash["mem"], hash["tcost"]?, hash["salt"]? - end end