{"id":19791094,"url":"https://github.com/mudge/argon2id","last_synced_at":"2025-04-09T12:06:41.867Z","repository":{"id":260488246,"uuid":"881340027","full_name":"mudge/argon2id","owner":"mudge","description":"Ruby bindings to Argon2, the password-hashing function that won the 2015 Password Hashing Competition.","archived":false,"fork":false,"pushed_at":"2025-02-28T14:36:31.000Z","size":156,"stargazers_count":30,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-02T10:14:02.171Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mudge.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"mudge"}},"created_at":"2024-10-31T11:33:42.000Z","updated_at":"2025-02-28T14:36:34.000Z","dependencies_parsed_at":"2025-01-09T02:33:23.676Z","dependency_job_id":"79d5f524-64ce-4cd7-87d9-696f5aa5878f","html_url":"https://github.com/mudge/argon2id","commit_stats":{"total_commits":81,"total_committers":2,"mean_commits":40.5,"dds":"0.012345679012345734","last_synced_commit":"c4c740836c3085a2b051715a859617606179b70e"},"previous_names":["mudge/argon2id"],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mudge%2Fargon2id","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mudge%2Fargon2id/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mudge%2Fargon2id/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mudge%2Fargon2id/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mudge","download_url":"https://codeload.github.com/mudge/argon2id/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248036063,"owners_count":21037092,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T07:01:27.562Z","updated_at":"2025-04-09T12:06:41.849Z","avatar_url":"https://github.com/mudge.png","language":"C","funding_links":["https://github.com/sponsors/mudge"],"categories":["C"],"sub_categories":[],"readme":"# Argon2id - Ruby bindings to the OWASP recommended password-hashing function\n\nRuby bindings to [Argon2][], the password-hashing function that won the 2015\n[Password Hashing Competition][].\n\n[![Build Status](https://github.com/mudge/argon2id/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/mudge/argon2id/actions)\n\n**Current version:** 0.8.0  \n**Bundled Argon2 version:** libargon2.1 (20190702)\n\n```ruby\nArgon2id::Password.create(\"password\").to_s\n#=\u003e \"$argon2id$v=19$m=19456,t=2,p=1$agNV6OfDL1OwE44WdrFCJw$ITrBwvCsW4b5GjgZuL67RCcvVMEWBWXtASc9TVyI3rY\"\n\npassword = Argon2id::Password.new(\"$argon2id$v=19$m=19456,t=2,p=1$ZS2nBFWBpnt28HjtzNOW4w$SQ+p+dIcWbpzWpZQ/ZZFj8IQkyhYZf127U4QdkRmKFU\")\npassword == \"password\"     #=\u003e true\npassword == \"not password\" #=\u003e false\n\npassword.m_cost #=\u003e 19456\npassword.salt   #=\u003e \"e-\\xA7\\x04U\\x81\\xA6{v\\xF0x\\xED\\xCC\\xD3\\x96\\xE3\"\n```\n\n## Table of contents\n\n* [Why Argon2id?](#why-argon2id)\n* [Usage](#usage)\n    * [Hashing passwords](#hashing-passwords)\n    * [Verifying passwords](#verifying-passwords)\n    * [Validating encoded hashes](#validating-encoded-hashes)\n    * [Errors](#errors)\n    * [Usage with Active Record](#usage-with-active-record)\n* [Requirements](#requirements)\n    * [Native gems](#native-gems)\n    * [Verifying the gems](#verifying-the-gems)\n    * [Installing the `ruby` platform gem](#installing-the-ruby-platform-gem)\n* [Thanks](#thanks)\n* [Contact](#contact)\n* [License](#license)\n    * [Dependencies](#dependencies)\n\n## Why Argon2id?\n\n\u003e Argon2 is a password-hashing function that summarizes the state of the art in\n\u003e the design of memory-hard functions and can be used to hash passwords for\n\u003e credential storage, key derivation, or other applications.\n\u003e\n\u003e It has a simple design aimed at the highest memory filling rate and effective\n\u003e use of multiple computing units, while still providing defense against\n\u003e tradeoff attacks (by exploiting the cache and memory organization of the\n\u003e recent processors).\n\n— [Argon2][]\n\n\u003e Argon2 was the winner of the 2015 Password Hashing Competition. Out of the\n\u003e three Argon2 versions, use the Argon2id variant since it provides a balanced\n\u003e approach to resisting both side-channel and GPU-based attacks.\n\n— [OWASP Password Storage Cheat Sheet][]\n\nSee also [argon2-cffi's \"Why 'just use bcrypt' Is Not the Best Answer (Anymore)\"](https://argon2-cffi.readthedocs.io/en/23.1.0/argon2.html#why-just-use-bcrypt-is-not-the-best-answer-anymore).\n\n## Usage\n\nInstall argon2id as a dependency:\n\n```ruby\n# In your Gemfile\ngem \"argon2id\"\n\n# Or without Bundler\ngem install argon2id\n```\n\nInclude in your code:\n\n```ruby\nrequire \"argon2id\"\n```\n\n### Hashing passwords\n\nHash a plain text password (e.g. from user input) with\n`Argon2id::Password.create`:\n\n```ruby\npassword = Argon2id::Password.create(\"opensesame\")\n```\n\nThe encoded value of the resulting hash is available via\n`Argon2id::Password#to_s` (ideal for persisting somewhere):\n\n```ruby\npassword.to_s\n#=\u003e \"$argon2id$v=19$m=19456,t=2,p=1$ZS2nBFWBpnt28HjtzNOW4w$SQ+p+dIcWbpzWpZQ/ZZFj8IQkyhYZf127U4QdkRmKFU\"\n```\n\nBy default, `Argon2id::Password.create` will use the second set of parameters\nrecommended by [OWASP][OWASP Password Storage Cheat Sheet] but these can be\noverridden by passing keyword arguments to `Argon2id::Password.create`:\n\n* `t_cost`: the \"time cost\" given as a number of iterations (defaults to 2)\n* `m_cost`: the \"memory cost\" given in kibibytes (defaults to 19 mebibytes)\n* `parallelism`: the number of threads and compute lanes to use (defaults to 1)\n* `salt_len`: the salt size in bytes (defaults to 16)\n* `output_len`: the desired length of the hash in bytes (defaults to 32)\n\n```ruby\npassword = Argon2id::Password.create(\"opensesame\", t_cost: 3, m_cost: 12288)\npassword.to_s\n#=\u003e \"$argon2id$v=19$m=12288,t=3,p=1$uukIsLS6y6etvsgoN20kVg$exMvDX/P9exvEPmnZL2gZClRyMdrnqjqyysLMP/VUWA\"\n```\n\nIf you want to override the parameters for all calls to\n`Argon2id::Password.create`, you can set them on `Argon2id` directly:\n\n```ruby\nArgon2id.t_cost = 3\nArgon2id.m_cost = 12288\nArgon2id.parallelism = 1\nArgon2id.salt_len = 16\nArgon2id.output_len = 32\n```\n\n### Verifying passwords\n\nTo verify a password against a hash, use `Argon2id::Password#==`:\n\n```ruby\npassword = Argon2id::Password.create(\"opensesame\")\npassword == \"opensesame\"    #=\u003e true\npassword == \"notopensesame\" #=\u003e false\n```\n\nOr, if you only have the encoded hash (e.g. retrieved from storage):\n\n```ruby\npassword = Argon2id::Password.new(\"$argon2id$v=19$m=19456,t=2,p=1$ZS2nBFWBpnt28HjtzNOW4w$SQ+p+dIcWbpzWpZQ/ZZFj8IQkyhYZf127U4QdkRmKFU\")\npassword == \"opensesame\"    #=\u003e true\npassword == \"notopensesame\" #=\u003e false\n```\n\n\u003e [!WARNING]\n\u003e `Argon2id::Password.new` does not support hashes generated from other Argon2\n\u003e variants such as Argon2i and Argon2d.\n\nFor compatibility with [bcrypt-ruby][], `Argon2id::Password#==` is aliased to `Argon2id::Password.is_password?`:\n\n```ruby\npassword = Argon2id::Password.new(\"$argon2id$v=19$m=19456,t=2,p=1$ZS2nBFWBpnt28HjtzNOW4w$SQ+p+dIcWbpzWpZQ/ZZFj8IQkyhYZf127U4QdkRmKFU\")\npassword.is_password?(\"opensesame\")    #=\u003e true\npassword.is_password?(\"notopensesame\") #=\u003e false\n```\n\n\u003e [!CAUTION]\n\u003e `Argon2id::Password#==` only works if the plain text password is on the right, e.g. the following behaviour may be surprising:\n\u003e\n\u003e ```ruby\n\u003e password = Argon2id::Password.create(\"password\")\n\u003e password == \"password\" #=\u003e true\n\u003e \"password\" == password #=\u003e false\n\u003e password == password   #=\u003e false\n\u003e ```\n\u003e\n\u003e If you want to avoid this ambiguity, prefer the `Argon2id::Password#is_password?` alias instead.\n\nThe various parts of the encoded hash can be retrieved:\n\n```ruby\npassword = Argon2id::Password.new(\"$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4\")\npassword.version     #=\u003e 19\npassword.m_cost      #=\u003e 256\npassword.t_cost      #=\u003e 2\npassword.parallelism #=\u003e 1\npassword.salt        #=\u003e \"somesalt\"\npassword.output\n#=\u003e \"\\x9D\\xFE\\xB9\\x10\\xE8\\v\\xAD\\x03\\x11\\xFE\\xE2\\x0F\\x9C\\x0E+\\x12\\xC1y\\x87\\xB4\\xCA\\xC9\\f.\\xF5M[0!\\xC6\\x8B\\xFE\"\n```\n\n### Validating encoded hashes\n\nIf you need to check ahead of time whether an encoded password hash is a valid Argon2id hash (e.g. if you're migrating between hashing functions and need to test what kind of password has been stored for a user), you can use `Argon2id::Password.valid_hash?` like so:\n\n```ruby\nArgon2id::Password.valid_hash?(\"$argon2id$v=19$m=65536,t=2,p=1$c29tZXNhbHQ$CTFhFdXPJO1aFaMaO6Mm5c8y7cJHAph8ArZWb2GRPPc\")\n#=\u003e true\n\nArgon2id::Password.valid_hash?(\"$2a$12$stsRn7Mi9r02.keRyF4OK.Aq4UWOU185lWggfUQfcupAi.b7AI/nS\")\n#=\u003e false\n```\n\n### Errors\n\nAny errors returned from Argon2 will be raised as `Argon2id::Error`, e.g.\n\n```ruby\nArgon2id::Password.create(\"password\", salt_len: 0)\n# Salt is too short (Argon2id::Error)\n```\n\n### Usage with Active Record\n\nIf you're planning to use this with Active Record instead of [Rails' own\nbcrypt-based\n`has_secure_password`](https://api.rubyonrails.org/v8.0/classes/ActiveModel/SecurePassword/ClassMethods.html),\nyou can use the following as a starting point:\n\n#### The `User` model\n\n```ruby\nrequire \"argon2id\"\n\n# Schema: User(name: string, password_digest:string)\nclass User \u003c ApplicationRecord\n  attr_reader :password\n\n  validates :password_digest, presence: true\n  validates :password, confirmation: true, allow_blank: true\n\n  def password=(unencrypted_password)\n    if unencrypted_password.nil?\n      @password = nil\n      self.password_digest = nil\n    elsif !unencrypted_password.empty?\n      @password = unencrypted_password\n      self.password_digest = Argon2id::Password.create(unencrypted_password)\n    end\n  end\n\n  def authenticate(unencrypted_password)\n    password_digest? \u0026\u0026 Argon2id::Password.new(password_digest).is_password?(unencrypted_password) \u0026\u0026 self\n  end\n\n  def password_salt\n    Argon2id::Password.new(password_digest).salt if password_digest?\n  end\nend\n```\n\nThis can then be used like so:\n\n```ruby\nuser = User.new(name: \"alice\", password: \"\", password_confirmation: \"diffpassword\")\nuser.save                               #=\u003e false, password required\nuser.password = \"password\"\nuser.save                               #=\u003e false, confirmation doesn't match\nuser.password_confirmation = \"password\"\nuser.save                               #=\u003e true\n\nuser.authenticate(\"notright\") #=\u003e false\nuser.authenticate(\"password\") #=\u003e user\n\nUser.find_by(name: \"alice\")\u0026.authenticate(\"notright\") #=\u003e false\nUser.find_by(name: \"alice\")\u0026.authenticate(\"password\") #=\u003e user\n```\n\n## Requirements\n\nThis gem requires any of the following to run:\n\n* [Ruby](https://www.ruby-lang.org/en/) 2.6 to 3.4\n* [JRuby](https://www.jruby.org) 9.4\n* [TruffleRuby](https://www.graalvm.org/ruby/) 24.1\n\n\u003e [!NOTE]\n\u003e The JRuby version of the gem uses\n\u003e [JRuby-OpenSSL](https://github.com/jruby/jruby-openssl)'s implementation of\n\u003e Argon2 while the others use the reference C implementation.\n\n### Native gems\n\nWhere possible, a pre-compiled native gem will be provided for the following platforms:\n\n* Linux\n    * `aarch64-linux`, `arm-linux`, `x86-linux`, `x86_64-linux` (requires [glibc](https://www.gnu.org/software/libc/) 2.29+, RubyGems 3.3.22+ and Bundler 2.3.21+)\n    * [musl](https://musl.libc.org/)-based systems such as [Alpine](https://alpinelinux.org) are supported with Bundler 2.5.6+\n* macOS `x86_64-darwin` and `arm64-darwin`\n* Windows `x64-mingw32` and `x64-mingw-ucrt`\n* Java: any platform running JRuby 9.4 or higher\n\n### Verifying the gems\n\nSHA256 checksums are included in the [release\nnotes](https://github.com/mudge/argon2id/releases) for each version and can be\nchecked with `sha256sum`, e.g.\n\n```console\n$ gem fetch argon2id -v 0.7.0\nFetching argon2id-0.7.0-arm64-darwin.gem\nDownloaded argon2id-0.7.0-arm64-darwin\n$ sha256sum argon2id-0.7.0-arm64-darwin.gem\n26bba5bcefa56827c728222e6df832aef5c8c4f4d3285875859a1d911477ec68  argon2id-0.7.0-arm64-darwin.gem\n```\n\n[GPG](https://www.gnupg.org/) signatures are attached to each release (the\nassets ending in `.sig`) and can be verified if you import [our signing key\n`0x39AC3530070E0F75`](https://mudge.name/39AC3530070E0F75.asc) (or fetch it\nfrom a public keyserver, e.g. `gpg --keyserver keyserver.ubuntu.com --recv-key\n0x39AC3530070E0F75`):\n\n```console\n$ gpg --verify argon2id-0.7.0-arm64-darwin.gem.sig argon2id-0.7.0-arm64-darwin.gem\ngpg: Signature made Fri  8 Nov 13:45:18 2024 GMT\ngpg:                using RSA key 702609D9C790F45B577D7BEC39AC3530070E0F75\ngpg: Good signature from \"Paul Mucur \u003cmudge@mudge.name\u003e\" [unknown]\ngpg:                 aka \"Paul Mucur \u003cpaul@ghostcassette.com\u003e\" [unknown]\ngpg: WARNING: This key is not certified with a trusted signature!\ngpg:          There is no indication that the signature belongs to the owner.\nPrimary key fingerprint: 7026 09D9 C790 F45B 577D  7BEC 39AC 3530 070E 0F75\n```\n\nThe fingerprint should be as shown above or you can independently verify it\nwith the ones shown in the footer of https://mudge.name.\n\n### Installing the `ruby` platform gem\n\n\u003e [!WARNING]\n\u003e We strongly recommend using the native gems where possible to avoid the need\n\u003e for compiling the C extension and its dependencies which will take longer and\n\u003e be less reliable.\n\nIf you wish to compile the gem, you will need to explicitly install the `ruby` platform gem:\n\n```ruby\n# In your Gemfile with Bundler 2.3.18+\ngem \"argon2id\", force_ruby_platform: true\n\n# With Bundler 2.1+\nbundle config set force_ruby_platform true\n\n# With older versions of Bundler\nbundle config force_ruby_platform true\n\n# Without Bundler\ngem install argon2id --platform=ruby\n```\n\nYou will need a full compiler toolchain for compiling Ruby C extensions (see\n[Nokogiri's \"The Compiler\nToolchain\"](https://nokogiri.org/tutorials/installing_nokogiri.html#appendix-a-the-compiler-toolchain))\nplus the toolchain required for compiling the vendored version of Argon2.\n\n## Thanks\n\n* Thanks to [Mike Dalessio](https://github.com/flavorjones) for his advice and\n [Ruby C Extensions Explained](https://github.com/flavorjones/ruby-c-extensions-explained)\n project\n\n## Contact\n\nAll issues and suggestions should go to [GitHub\nIssues](https://github.com/mudge/argon2id/issues).\n\n## License\n\nThis library is licensed under the BSD 3-Clause License, see `LICENSE`.\n\nCopyright © 2024, Paul Mucur.\n\n### Dependencies\n\nThe source code of [Argon2][] is distributed in the gem. This code is copyright\n© 2015 Daniel Dinu, Dmitry Khovratovich (main authors), Jean-Philippe Aumasson\nand Samuel Neves, and dual licensed under the [CC0 License][] and the [Apache\n2.0 License][].\n\n  [Argon2]: https://github.com/P-H-C/phc-winner-argon2/\n  [OWASP Password Storage Cheat Sheet]: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id\n  [bcrypt-ruby]: https://github.com/bcrypt-ruby/bcrypt-ruby\n  [CC0 License]: https://creativecommons.org/about/cc0\n  [Apache 2.0 License]: https://www.apache.org/licenses/LICENSE-2.0\n  [Password Hashing Competition]: https://www.password-hashing.net\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmudge%2Fargon2id","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmudge%2Fargon2id","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmudge%2Fargon2id/lists"}