pax_global_header00006660000000000000000000000064147035160530014516gustar00rootroot0000000000000052 comment=8c5732d04007a8adfc3cfc8e7ac26776627a390a rbnacl-7.1.2/000077500000000000000000000000001470351605300127665ustar00rootroot00000000000000rbnacl-7.1.2/.coveralls.yml000066400000000000000000000000311470351605300155530ustar00rootroot00000000000000service-name: travis-pro rbnacl-7.1.2/.github/000077500000000000000000000000001470351605300143265ustar00rootroot00000000000000rbnacl-7.1.2/.github/workflows/000077500000000000000000000000001470351605300163635ustar00rootroot00000000000000rbnacl-7.1.2/.github/workflows/ci.yml000066400000000000000000000015561470351605300175100ustar00rootroot00000000000000name: CI on: push: branches: [ main ] pull_request: branches: [ main ] env: BUNDLE_WITHOUT: "development" JRUBY_OPTS: "--dev --debug" jobs: test: strategy: matrix: ruby: - ruby-2.6 - ruby-2.7 - ruby-3.0 - ruby-3.1 - ruby-3.2 - ruby-3.3 - jruby-9.3.0 os: [ ubuntu-latest ] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true - run: bundle exec rspec --format progress lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 bundler-cache: true - run: bundle exec rubocop --format progress --color rbnacl-7.1.2/.gitignore000066400000000000000000000003021470351605300147510ustar00rootroot00000000000000*.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp libsodium libsodium-*.tar.gz .rakeTasks rbnacl-7.1.2/.rspec000066400000000000000000000001331470351605300141000ustar00rootroot00000000000000--color --format documentation --backtrace --order random --warnings --require spec_helper rbnacl-7.1.2/.rubocop.yml000066400000000000000000000012511470351605300152370ustar00rootroot00000000000000AllCops: TargetRubyVersion: 2.6 DisplayCopNames: true Exclude: - 'vendor/**/*' # # Layout # Metrics/LineLength: Max: 128 # # Metrics # Metrics/AbcSize: Max: 20 Metrics/BlockLength: Max: 128 ExcludedMethods: [ 'describe' ] Metrics/ClassLength: Max: 128 Metrics/MethodLength: CountComments: false Max: 50 Metrics/CyclomaticComplexity: Max: 15 Metrics/PerceivedComplexity: Max: 15 # # Naming # Naming/UncommunicativeMethodParamName: Enabled: false # # Style # Style/AccessModifierDeclarations: Enabled: false Style/GlobalVars: Enabled: false Style/SafeNavigation: Enabled: false Style/StringLiterals: EnforcedStyle: double_quotes rbnacl-7.1.2/.yardopts000066400000000000000000000001041470351605300146270ustar00rootroot00000000000000--markup markdown --no-private lib/**/*.rb - README.md LICENSE.txt rbnacl-7.1.2/CHANGES.md000066400000000000000000000131331470351605300143610ustar00rootroot00000000000000## [7.1.2] (2024-10-15) - Test on Ruby 3.3 ([#236]) - Support alpine 3.19 and up ([#234]) - Use libsodium constants for scrypt params ([#231]) - Fix error message generation when empty hmac key is given ([#224]) - Add ed25519 to curve25519 conversion helpers ([#217]) ## [7.1.1] (2020-01-27) - Test on Ruby 2.7 ([#208]) - Add project metadata to the gemspec ([#207]) - Resolve FFI deprecation warning ([#206]) ## [7.1.0] (2019-09-07) - Attached signature API ([#197], [#202]) - Fix the `generichash` state definition ([#200]) ## [7.0.0] (2019-05-23) - Drop support for Ruby 2.2 ([#194]) ## [6.0.1] (2019-01-27) - Add fallback `sodium_constants` for Argon2 ([#189]) - Support libsodium versions used by Heroku ([#186]) - Sealed boxes ([#184]) ## [6.0.0] (2018-11-08) - Deprecate rbnacl-libsodium ([#180]) - Add support for XChaCha20-Poly1305 ([#176]) - Fix buffer size type in `randombytes_buf` binding ([#174]) - Add support for argon2id digest ([#174]) - Support for non-32-byte HMAC-SHA256/512 keys ([#166]) ## 5.0.0 (2017-06-13) - Support the BLAKE2b Initialize-Update-Finalize API ([#159]) ## 4.0.2 (2017-03-12) - Raise error on degenerate keys. Fixes #152 ([#157]) ## 4.0.1 (2016-12-04) - Last minute changes to the ChaCha20Poly1305 API ([#148]) ## 4.0.0 (2016-12-04) - Add wrappers for ChaCha20Poly1305 AEAD ciphers ([#141]) - Added support for Argon2 password hash ([#142]) - Require Ruby 2.2.6+ ([#143]) ## 3.4.0 (2015-05-07) - Expose `RbNaCl::Signatures::Ed25519#keypair_bytes` ([#135]) - Expose HMAC-SHA512 with 64-byte keys ([#137]) ## 3.3.0 (2015-12-29) - Remove use of Thread.exclusive when initializing library ([#128]) - Add salt/personalisation strings for Blake2b ([#105]) ## 3.2.0 (2015-05-31) - Fix method signature for blake2b - RuboCop-friendly codebase ## 3.1.2 (2014-08-30) - Fix scrypt support with libsodium 0.7.0 (scryptsalsa208sha256) ## 3.1.1 (2014-06-14) - Fix undefined variable warning - RSpec 3 fixups - RuboCop ## 3.1.0 (2014-05-22) - The scrypt password hashing function: `RbNaCl::PasswordHash.scrypt` ## 3.0.1 (2014-05-12) - Load gem from `RBNACL_LIBSODIUM_GEM_LIB_PATH` if set. Used by rbnacl-libsodium gem to use libsodium compiled from a gem. ## 3.0.0 (2014-04-22) - Rename RandomNonceBox to SimpleBox (backwards compatibility preserved) - Reverse documented order of SimpleBox/RandomNonceBox initialize parameters. Technically backwards compatible, but confusing. - Ensure all strings are ASCII-8BIT/BINARY encoding prior to use ## 2.0.0 (2013-11-07) - Rename Crypto module to RbNaCl module - Add encrypt/decrypt aliases for `Crypto::RandomNonceBox` - `RbNaCl::VerifyKey#verify` operand order was reversed. New operand order is signature, message instead of message, signature - `RbNaCL::SecretBox#open`, `RbNaCl::Box#open`, `Auth#verify` and `VerifyKey#verify` all now raise a (descendent of) CryptoError if the check fails. This ensures failures are handled by the program. - `RbNaCl::SecretBox`, Box, etc. are all now aliases for the real implementations, which are named after the primitives they provide - Removed encoder functionality. - Add support for the Blake2b cryptographic hash algorithm. - Add checks that we have a sufficiently recent version of libsodium (0.4.3+) - Dropped ruby-1.8 support - Call the `sodium_init()` function, to select the best algorithms. - Fix some typos in the documentation - Changes in the low level binding for libsodium and removal of the NaCl module - Add a mutex around calls to randombytes in libsodium ## 1.1.0 (2013-04-19) - Provide API for querying primitives and details about them, such as key lengths, nonce lengths, etc. - Fixed bug on passing null bytes to sha256, sha512 functions. ## 1.0.0 (2013-03-08) - Initial release [7.1.2]: https://github.com/RubyCrypto/rbnacl/pull/240 [#236]: https://github.com/RubyCrypto/rbnacl/pull/236 [#234]: https://github.com/RubyCrypto/rbnacl/pull/234 [#231]: https://github.com/RubyCrypto/rbnacl/pull/231 [#224]: https://github.com/RubyCrypto/rbnacl/pull/224 [#217]: https://github.com/RubyCrypto/rbnacl/pull/217 [7.1.1]: https://github.com/RubyCrypto/rbnacl/pull/210 [#208]: https://github.com/RubyCrypto/rbnacl/pull/208 [#207]: https://github.com/RubyCrypto/rbnacl/pull/207 [#206]: https://github.com/RubyCrypto/rbnacl/pull/206 [7.1.0]: https://github.com/RubyCrypto/rbnacl/pull/203 [#202]: https://github.com/RubyCrypto/rbnacl/pull/202 [#200]: https://github.com/RubyCrypto/rbnacl/pull/200 [#197]: https://github.com/RubyCrypto/rbnacl/pull/197 [7.0.0]: https://github.com/RubyCrypto/rbnacl/pull/195 [#194]: https://github.com/RubyCrypto/rbnacl/pull/194 [6.0.1]: https://github.com/RubyCrypto/rbnacl/pull/191 [#189]: https://github.com/RubyCrypto/rbnacl/pull/189 [#186]: https://github.com/RubyCrypto/rbnacl/pull/186 [#184]: https://github.com/RubyCrypto/rbnacl/pull/184 [6.0.0]: https://github.com/RubyCrypto/rbnacl/pull/182 [#180]: https://github.com/RubyCrypto/rbnacl/pull/180 [#176]: https://github.com/RubyCrypto/rbnacl/pull/176 [#174]: https://github.com/RubyCrypto/rbnacl/pull/174 [#172]: https://github.com/RubyCrypto/rbnacl/pull/172 [#166]: https://github.com/RubyCrypto/rbnacl/pull/166 [#159]: https://github.com/RubyCrypto/rbnacl/pull/159 [#157]: https://github.com/RubyCrypto/rbnacl/pull/157 [#148]: https://github.com/RubyCrypto/rbnacl/pull/148 [#143]: https://github.com/RubyCrypto/rbnacl/pull/143 [#142]: https://github.com/RubyCrypto/rbnacl/pull/142 [#141]: https://github.com/RubyCrypto/rbnacl/pull/141 [#137]: https://github.com/RubyCrypto/rbnacl/pull/137 [#135]: https://github.com/RubyCrypto/rbnacl/pull/135 [#128]: https://github.com/RubyCrypto/rbnacl/pull/128 [#105]: https://github.com/RubyCrypto/rbnacl/pull/105 rbnacl-7.1.2/Gemfile000066400000000000000000000004041470351605300142570ustar00rootroot00000000000000# frozen_string_literal: true source "https://rubygems.org" gemspec group :development do gem "guard-rspec" end group :test do gem "coveralls", require: false gem "rspec" gem "rubocop", "= 0.70.0" end group :development, :test do gem "rake" end rbnacl-7.1.2/Guardfile000066400000000000000000000004101470351605300146060ustar00rootroot00000000000000# frozen_string_literal: true # A sample Guardfile # More info at https://github.com/guard/guard#readme guard :rspec do watch(%r{^spec/.+_spec\.rb$}) watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } watch("spec/spec_helper.rb") { "spec" } end rbnacl-7.1.2/LICENSE.txt000066400000000000000000000021021470351605300146040ustar00rootroot00000000000000Copyright (c) 2012-2018 Tony Arcieri, Jonathan Stott MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. rbnacl-7.1.2/README.md000066400000000000000000000152171470351605300142530ustar00rootroot00000000000000![RbNaCl](https://raw.github.com/RubyCrypto/rbnacl/master/images/logo.png) ====== [![Gem Version](https://badge.fury.io/rb/rbnacl.svg)](http://badge.fury.io/rb/rbnacl) [![Build Status](https://github.com/RubyCrypto/rbnacl/actions/workflows/ci.yml/badge.svg)](https://github.com/RubyCrypto/rbnacl/actions/workflows/ci.yml) [![Coverage Status](https://coveralls.io/repos/RubyCrypto/rbnacl/badge.svg?branch=master)](https://coveralls.io/r/RubyCrypto/rbnacl) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/RubyCrypto/rbnacl/blob/master/LICENSE.txt) Ruby binding for [libsodium], a fork of the [Networking and Cryptography][NaCl] library. [libsodium]: https://libsodium.org [NaCl]: http://nacl.cr.yp.to/ ## Why libsodium/NaCl? NaCl is a different kind of cryptographic library. In the past crypto libraries were kitchen sinks of little bits and pieces, like ciphers, MACs, signature algorithms, and hash functions. To accomplish anything you had to make a lot of decisions about which specific pieces to use, and if any of your decisions were wrong, the result was an insecure system. The choices are also not easy: EAX? GCM? CCM? AES-CTR? CMAC? OMAC1? AEAD? NIST? CBC? CFB? CTR? ECB? OMGWTFBBQ! NaCl puts cryptography on Rails! Instead of making you choose which cryptographic primitives to use, NaCl provides convention over configuration in the form of expertly-assembled high-level cryptographic APIs that ensure not only the confidentiality of your data, but also detect tampering. These high-level, easy-to-use APIs are designed to be hard to attack by default in ways primitives exposed by libraries like OpenSSL are not. This approach makes NaCl a lot closer to a system like GPG than it is to the cryptographic primitive APIs in a library like OpenSSL. In addition, NaCl also uses state-of-the-art encryption, including Curve25519 elliptic curves and the XSalsa20 stream cipher. This means with NaCl you not only get a system which is designed to be secure-by-default, you also get one which is extremely fast with comparatively small cryptographic keys. ### Is it any good? [Yes.](http://news.ycombinator.com/item?id=3067434) ## Supported platforms You can use RbNaCl on platforms libsodium is supported (see below). This library aims to support and is [tested against][github-action] the following Ruby versions: * Ruby 2.6 * Ruby 2.7 * Ruby 3.0 * Ruby 3.1 * Ruby 3.2 * Ruby 3.3 * JRuby 9.3 If something doesn't work on one of these versions, it's a bug. [github-action]: https://github.com/RubyCrypto/rbnacl/actions ## Installation Note: [Windows installation instructions are available](https://github.com/RubyCrypto/rbnacl/wiki/Installing-libsodium#windows). ### libsodium To use RbNaCl, you will need to install libsodium: https://github.com/jedisct1/libsodium At least version `1.0.0` is required. For OS X users, libsodium is available via homebrew and can be installed with: brew install libsodium For FreeBSD users, libsodium is available both via pkgng and ports. To install a binary package: pkg install libsodium To install from ports on FreeBSD, use your favorite ports front end (e.g. portmaster or portupgrade), or use make as follows: cd /usr/ports/security/libsodium; make install clean ### RbNaCl gem Once you have libsodium installed, add this line to your application's Gemfile: gem 'rbnacl' And then execute: $ bundle Or install it yourself as: $ gem install rbnacl Inside of your Ruby program do: require 'rbnacl' ...to pull it in as a dependency. ## Documentation RbNaCl's documentation can be found [in the Wiki][wiki]. The following features are supported: * [SimpleBox]: easy-to-use public-key or secret-key encryption "on Rails" * [Secret-key Encryption][secretkey]: authenticated symmetric encryption using a single key shared among parties * [Public-key Encryption][publickey]: securely send messages to a given public key which can only be decrypted by a secret key * [Digital Signatures][signatures]: sign messages with a private key which can be verified by a public one * [Authenticators][macs]: create codes which can be used to check the authenticity of messages * [Hash Functions][hashes]: compute a secure, fixed-length code from a message which does not reveal the contents of the message Additional power-user features are available. Please see the Wiki for further information. [YARD API documentation][yard] is also available. [wiki]: https://github.com/RubyCrypto/rbnacl/wiki [simplebox]: https://github.com/RubyCrypto/rbnacl/wiki/SimpleBox [secretkey]: https://github.com/RubyCrypto/rbnacl/wiki/Secret-Key-Encryption [publickey]: https://github.com/RubyCrypto/rbnacl/wiki/Public-Key-Encryption [signatures]: https://github.com/RubyCrypto/rbnacl/wiki/Digital-Signatures [macs]: https://github.com/RubyCrypto/rbnacl/wiki/HMAC [hashes]: https://github.com/RubyCrypto/rbnacl/wiki/Hash-Functions [yard]: http://www.rubydoc.info/gems/rbnacl ## Learn More While NaCl has designed to be easier-than-usual to use for a crypto library, cryptography is an incredibly difficult subject and it's always helpful to know as much as you can about it before applying it to a particular use case. That said, the creator of NaCl, Dan Bernstein, has published a number of papers about NaCl. If you are interested in learning more about how NaCl works, it's recommended that you read them: * [Cryptography in NaCl](http://cr.yp.to/highspeed/naclcrypto-20090310.pdf) * [Salsa20 Design](https://cr.yp.to/snuffle/design.pdf) * [Curve25519: new Diffie-Hellman speed records](http://cr.yp.to/ecdh/curve25519-20060209.pdf) * [Ed25519: High-speed high-security signatures](http://ed25519.cr.yp.to/ed25519-20110926.pdf) For more information on libsodium, please check out the [Introducing Sodium blog post](http://labs.umbrella.com/2013/03/06/announcing-sodium-a-new-cryptographic-library/) Have a general interest in cryptography? Check out the free course Coursera offers from Stanford University Professor Dan Boneh: [http://crypto-class.org](http://crypto-class.org) ## Important Questions ### Is it "Military Grade™"? Only if your military understands twisted Edwards curves ### Is it "Bank Grade™"? No, that means 3DES, which this library doesn't support, sorry ### Does it have a lock with a checkmark? Sure, here you go: ![Checkmarked Lock](http://i.imgur.com/dwA0Ffi.png) ## Contributing * Fork this repository on Github * Make your changes and send a pull request * If your changes look good, we'll merge 'em ## License Copyright (c) 2012-2018 Tony Arcieri, Jonathan Stott. Distributed under the MIT License. See [LICENSE.txt] for further details. [LICENSE.txt]: https://github.com/RubyCrypto/rbnacl/blob/master/LICENSE.txt rbnacl-7.1.2/Rakefile000066400000000000000000000003071470351605300144330ustar00rootroot00000000000000# frozen_string_literal: true require "bundler/gem_tasks" Dir[File.expand_path("tasks/**/*.rake", __dir__)].each { |task| load task } task default: %w[spec rubocop] task ci: %w[spec rubocop] rbnacl-7.1.2/images/000077500000000000000000000000001470351605300142335ustar00rootroot00000000000000rbnacl-7.1.2/images/hash.png000066400000000000000000000725721470351605300157010ustar00rootroot00000000000000PNG  IHDRFuAIDATx O3Ԋ"@J)@J)@J)@J)@J)@J)@J)@Jػ&_HB1F+hћ.^Kowwn-#'ƭɌċD @$u` IϾxv<|Q[]Y+h6cѕi3fpVZ]`_nW[YlqrmVWunc_kvtgTݴ"!TJi Yx ,VbO6jcʕVݘC_ l, +wt*7KUZ^x3wuL8S)2cHP)!~N[Jcd)WO]ST18W~(2f=vB,Xq搎=ؑ`j{mRnZE' 擏!TJH`C3,|pO+€C!iꮓDRlxSSfƤoUi"M@k9vb pw+9c{ _bP)!$"{lӬ);0y,͊xv~Щ5&X=‘` M GlZeM@A.skoF`fy2DD L[)ˆ2r^tk®߿mz+8C1O~໿Awrh:xN?_]\yB\9\8Al',H!|.0©Zi3U=6x{=Q$qcefmf˅G<k+;7vC8O'eDVN7?b+,c̔oyNHead:guM^A\f-5ugLh<&i1s4X >YǾxU9-OgθwE? +E/nJZ}2wGc㨄8C:v֭Y}ߙݯiHQj]ukDp?@^O"%;d󧈢@B"PS0YcɳؼeؖhCqK~?'4upqrڿ$%[p3$]|-uW acx` ps<`G~\\!:|l ͐sP)!$Yp װe= EhA97=)v2\hIQCO^ q17E|$1Q+w wpH P؂`?W)Z]E,QBx?w%>o2@<7 @At֟Hʈe@qW+'"n@(-4G@_: bg9\/II30y0) YddHAB"P  mF~^X<Rlh:R 6'*mz],ėVʡ2UT~Вܫ6_k5F<#W! RBH?pgBNn: 3 B~ՠ9'Ay:<5ZDEˢZ]^dr@Y8W+y*i39qӌ/<>!\'+ ?2` &YZ1)](m{&$^Wz䳋~+'u͂aFT $V &VZɮ?հ(Ix%mѝIKVL&Dl( BOIZ(97WBtwۙ#αs͛w&˴/k_X99Ew'/Y8f!rV/7DR#k(=r#dh`-vއ/q}q+NF`Ana`KI}}t @~4)<\$>:d<+7.;wF/`V_N1_tV>*Yz}Dg]^#.(\uˠq]= : ~Yjs=virh \e`H5n60B'č0K:1Tʛ Nxqߏ9etƢK̔F9( TlJ u׏2ffRe@X`[!(7,}2MBJ$΂f@T\*:bT>]qΎ&$+2{pdTҶ֋f<>1"Ω<dﵾGR evEfdE P)!F#.&;wCoXr$M˧$'l3z N%J mH:'2w>u2JN'S>/ZXxWw(槊5<7@`H5Pl߅] "Wq|'\6yUȕk!vt%!N.n#j7zziޏgݸuD{Nn f%Κ;M2OɛƜ@Vo~tI}qI[ꬻ ('@oMF0ruۏt>@\o2$JRBV*95qKXeѓMCgp1's5 P*UB"{`}[L&A?Hgi%?'dzY#), iQ /x *%-La*c)MFq'y@qBB^q%XKH"B0x bҷd}wG˃BG.@V=n-M"X z[ "E =b{cz^0,Q"!T&m+ )2G`JU 敲ȕJ歪-Zryu_mzQc@v"մUQ^)Z1ձb⭎\Uz#P)!$m:>?oJuDޣZYZf0",WYh"רS?;cg`vf6(6m3m۶6CPsy6b;n_~]P @@@@@@@@@@@%())Mq$?~o?_KNb @@@)--}v橍Kwz {<D @wN=i9Smݾ~Ԕ }gds+  JC#]߳i!׬.z&3=A4/,N,.J(.,@S{{{ddgde&$&rmڵmr C^Uk:$%' 0Ryu;Fz}Wf;Iۥq:~0/B%!0n=ϾomE) ر#Z}R)6֞|{H!!n'}nzUA vquHgпū )>]S3!ēBXv}3O_v'n] 2H$A ՚oJ1FR !So/ŕڍk6 `X 3;!E=zOЕ'?{SuM[\:yɋ7^p^?{uqq<' FC3 م{soGDI!ϼ'mԧ-Q._8̪Rgk s.om.~PU^ظYM*;ݵy$1:}r' !DsF[h$w^~/:) \R+FH ~|aR/Gt3h>v`Y_Q-/V1BDI!r3_=s-?;g@Q++EYohTHsp(lFvtfzQUjrν"BDI! "܇]^;P$~Уw7}EQ6iT98닛[;c˼(ӍXss.QB7G8M &͵//H T@$<A(DVjQ7=05F76e(~oޠv`~ڙys!BF)%^m VGkQ%$*&-wh?h667̪ͽhJmVG="JBagjB 쥺zO~fCw"nF3iYH )%DR '3 T?0}So 9ھ𩏯.\A!$n\پoʦTMz&3 T! <6o6*PUi~oh>,R>~շe5aW!$.~S'f عt9A]*zнn<ZIBD,{8:OV&:LAY;̳'ÍuͅQBK:ݕȖ`nNFhf94YOIS/oTVcòмtc嗟Y8}vbB1?IF]תʀTN#U!vI]=" uٞmwVwFۓ\o Fc0^mZ^6l^_|ї>5ߤ)6B<) !K,$*/.i6t-Vݐf"WmwEwqľ,IIKw[͢\UnpsNh Ͷ#KϺn+!D^+'7CMMd\U˕ќN:HI%跚Ncc<ܚ.SJe]Өɶr2$O|2-}=//MߔݯO pGs0-x,IV*@w ½ d T"sFQ׆TQ&QuQz63;pi'o>c­$v6WGחL(bX!{ncg-'3oNBnFߟP`f"BRDgZh<(Su.ZQs2p{>'cn'%!pˢN,]Uv(K:YBH4s:T"w* )*(JU:(ĉno4wм("IIlWV T3)J1qШL1ֹ'>x}vBꓒB曅jRZ|RVv]ޤon[ΞsP/MJ@ԋt9ʶ9FV*H*[Iu* bYwlZU:h} =a-)Bv4N-w p"D94p1ny98)$yBӝӇA tA] t bԲcvd0Nv8ۛHH$mYz*ҍER,=^萑r~vRUeqzj"j/oWrO覅O>=?sb%4=_cP-˺߭C@M""HB DP&4kI>eeUG޻F9Ҁ^e5'\DUt:#1eu8kw~/}OxbfL4=nvusPۈo^%t$@F"8IĵXH ,>zⲷ5z`n$BH-c^9JwH"zk~﻾aQe2M3Ji=*q~Vnd !$@I) L$$F$EDp{)#k$ `P$ If1 Ӵw_kgۿ 4(Y )vzR}9/ۈHʲdȐ[i$( !B}-Z81ł"QVE :eG()i5J7% d^_{Oڝ1MӌiUDWwrD!#,$hJrJ{$[cFR:XP'!QH$ : D:PU:C$Q:{?/4(i= .rY3bd)FHn$ D0 ־t8P0BgD8I$k\KrЁDUn]5N'__??h^0iF4Mk2:(ND*\rI @"B$  tZH*rR$[$Y2IxR q(Hw7,%0H"*t7᷿^[L4dgյ)\KeIJbG,e$!r$4H֒@$MPe%)d=F+m& ! #$H*4-lh!٣T@1WK? oL4dgHʋR%deB$!I$SZ݀$I4RI\;\:t0mH-%Rh.hI0:VIk HlI) $42:'RvG^ _>=?b%4=egcuY %lIeKFnHx#IPآ}jTut7FZ%Hj UI$' tn$ hH*-q&O_|C/x4(W; UrjYZp#ɿhI@n@ &) B$jٲ!mKRY0mT`` E6=tPC@( iE$\!ZnGGgs/g|}S4(鷸$s9v=$Ue[ DҿIתJCRwI$A:u$BKң;nw{t 'Ii)$Kѓl ID 4U崥ڶoyo1Mӌif.qPޭvRFB@$H b%4==ZQk IR˝%I'$D, FFۀZV42 (jP[ D6W!EȆBJP(nqѝZ/˿/Oɛ3Mӌi)/A뎥>ˢun%$F6P B09rC7HZZFMC#AH# .+EY8nIhImDa)kBD#CNcx)^SNU4M3Ji]D~b=?c@BBnttH;J$gɵFג$zE,YBzm\+E(ٶng8ij&ZDXdA$E@ %ʎ XoWmrAh7,zTU[oo_{ܧXn3Mӌi/KX:e:$H5Bn I[I' 04Ai$<HdcXt#H@!+iK^ )aHB] D" Pi@:unwF;i "F%9mGxrߟpǪzx=u UuaZݭ[!U? Vd@vp4(ߧv:?,ggkvR(J"$ ݋ {tgtwn:Iݺj{I$!N}-C;ԁ!J @j=OPN',$WIeK`ܻw}yq'l얂a1,Tk֮j:[w7KxYkSx]6B-,V/}}g|K⭙%4{Z]aֺ[*[R˹!DB &#N2N2:Н;R  mӲ@mw!VePH+DDPp# #i/эhXRѹNwN/.[ٝ??߮q%$۵.),rNwgvn+7G.p5_I_5s v4گ//y{;MimKnJVc Y5GB&!IGDAR%ZTNGdI:KgTOV 舲; M #mX EP` -Y#Bm%dvܽE{|5F/uyu| _ۋ[/'pSBvb_xi;Kzfơ +J\)]ˢwz[w|w'PvU[[1`[c N$Vph<8 )2w]g\$g!YBDt&*Vj ň@\s)Ҡ*XX*ʪ!O5DG21;sQfgM<5ѪHb1ϣd !o$r y6<#[wox <PkZtRP2H;OewozY Y0?۷nh7o~o7;G~GyEPR{+` a`%4X:J-M;2ԣ$G( H 8n*h w 8+wK˥tq yD4@K4w͢莸XGu7DějW }joG;lܔB{{;kx`xӗrVma .]Rƻϥ ײÍ97^rgYuaݟ5.=t*rn NXz)۞9ppPr߽U6k [_z%pp酈t ?˶ynjnc'sݍS-Nm3SOm+USW3 PETTWz`t4FFcVO<ҙ3fV`wE9Ñ (_V$ {7Nְ^:6w-q ϭ32Է^dqH&zd2Cdnf_)>u1V.qۮ%+ظbc&&^>[g=|bB"Y6IȔ6srd?W؉$a8hTQ $(AC4HZ E *HKEA sr̽U4H.D2X$s-Dkp3c-eͅɼUfBnE1!8N[?Nw2GԬ>ƬmvPH}ƍoXD)@r[6הu,m0KVz*lg69w! q#.0d샢L?ͧ ݌K>Ϻ!v /F3|j#fa~dp9=wEcF@8q}S[E4'kV\us.;S̸墳hVq& O Cqb6ƪ3#(=S)?-[p~]qdyK#2}Fy]1i 47gy;N"fޙ/E[qsO˥D^WT+anzuuݙ .ꮎ9b' fb74;H= X,e̼$2ɐۨS OЀ!TU ?U$AŒOP-4IJkJ)*'!\UDUR }ݿۿࡇzŏ4~A_~:ɠBK֘;;_zrՉt,TzrYl[Ӷ|XۋWJ .$`тATZk,yh\*?g7S4'?:q%\D||/mC1#c2C{w?o]xɠkJv<m#޳Bu'fW訝u⾜qC]LԔ7b7)Ě ҿB!oL{^ZlOnm{8USr[8Cx)TU3D!^`̗S5O˱T{PeR7ssfPO7QogXƬ?~™Fy0bv_(Cl`ekx { 1n2V.^Y*'1ĭ_g6|2ƝT{ο}S̩"㇦Uw3\Dڡp@̛,Cj6@@\+jn*8"x#ާ$3I\WUP]Lm*kJCNtDqUuR5ppJ텮PD͛?Ew+h#1{hp18?Žn1H󀸌"cCߒnUb4D+8Rbgy5h:j?n^CCm鱧(m}'_Nuѭu ^&iq>M"]}kб<%Ƌ7i˘ht휿rekײl /F$M_[8qìm/e3dɒ%"¡88eN4rUqa7傈hJi! al11f*1Ơ"NjVxPAj4Fz'>ϰ蕊&*GG5Exj10wf"̜xPu\1&`*h󈙸!<)NVjfTDA "pF=[w "y%&1O$9 ֕gZ$<$O9/ƍwygo۩x۩~}0%GD!P{Q73m/o0 |ݒc/S翝=#k}oxW9g'?3w6/Fyge<\%2n|s\T%/i[ rX;mp5[y9+]I$KOsjM9+VI (ڍx6_ΖA +6t7skE:Fwݕj\IPa.ff'j}ڜ/ @(U ܥ._Y=w4mF8H&料E3܍hroGu$,cq%}؉B5|VYP{^ H)$I4$D4&IUrW6',G31$]OɌǟĴC:tmtn^kopjqS7o龜];-Tw>P'wE_9e?Wwu7ckӡy qө2;~ 8\U8-X9LARK.dG0@S?6ʜ5Dϑ0&r,D9\/}EStPT{ 4h)% E :dcgoq,Dsw0|[rĢ5Dqws\hQDƯ0], X477so5 m6rr{ss\1D ɣd$ ;u2Kd&!E{NLT*ŦDA#řk>\uQ5Ir=GzEjcuuuhYK1W g欺ee{)lxpA;nB%'Yep1h7xsdszsˣ:vt(y>?~.-&qcCIK#Pa;*ۿƲՌg69Xƽ_r 2Hf.F'PزY\c0t9WYxꋋ,tMgu}[•GlĸyOXc.|M9XY30 ]_cݖV W̤z{(~.T7E;?߃9Gx|,zfdgy=HͣYzJgI&BX4<sUZqdV+##< b.yf{9f\5 I0ձRDwX5*j8hѾ!HsT*LԄ4-R )ݻ/ GɑAc‰X.><+]JBsiL,ѐʥj5$M%I3n_"v9߄u9h o8,8h  w,-U7tͦ2oMPg_,e.sȄci|/'L̸axt5o0;Bn# oS fggP96x5q_ /|xs>oBP*7P\9byޘf4 FU<3\i&bn`͖=fC"4nb4sWɊf:((6ZTU ATThuよCР%InAUTu EC;*=9\T|tjIJ{7QUL}Tg$pj))*!JU IUA+! "!^m43Gw?{jWuEE9$,=?]zxNiK$$tTzd!2k`ӮuZPfL3oݳg(]|ÂK?6w^B.};o[vum^tEsrǒn:xמvէ߶W;\7v ;vR,&z*4ټi-tG&96nqodl #mmNNb笼^vĩofN˭0xO[~sjt6S#IƫӬ׻.f뮻^,"2y ~a{I}3=i"DQ̝77ss-,FU k'||y>3I.rs\Wss\3GT\4IR1A&UU3D$8# 7 .+B"1ˣEjT)k><9=#wHљ$DQW)V"!MUV.B4k$Q-+Uu$s7wܩ[;2<6_fr883,:eO\o=w{)ϐwJ鬓8yNwgYiVGIx.C?'wrq'5PҷW1p2;ص,%84;vp[?ж[aZ!J0;gIOױ=j=(iq3swQp`]q_cu;T5fvG=\` " *M!$ [ 7!hI#f&!)5-yO#GIU!DԅՓFRj i:'vP*̣ i uĬP.䎦IH宮訦ifBz%'?SYHӘ8m]ahp_ Q.n)w}9sD黚Cߴ${6j#nKBJwƑ7!2^M>b^2h.bf6XѱӢ !Hp4 :~0Epd -qB"-BfE. .R$$$IdI%ɉ ]舛8(M8Y Icv$yqJ׋izo\rיK̪͙D_;v Nrt(6kWl<&j%Ѽ^#Q3hQ1uDqs;!f."qh53bGsWt"4.8E J Eנ8UUQUsd1Q0Q/BOABP0A7_BR*yx*oYxᲾR<$e;ӦMoO.dXA ]צCɴi#l\Gae/O5+? '{Ba$5-ןMz.#8y5bЅ#z3ġlО(b=zje,Fiq3wO$މ3 H[\<(A\EDThq=DEPPQQtiEPT\ :MNy/tܝi^U+NM4 ^}eYR]r׎Mq}'|sa:6nbp"'܏=x D2͂2^h5؀dƓw-Fs&ESPМ`UW(Eoƈ *BwG%sAwEi4$^7 &itEg&UeڴʂwT 3Aϯ:mPu<}}[Tvx!-?n]p̜[{ϯ,´À&%CZO1:Fn! ހy Y8N;E) d, IoBTr'4 8"w&;Lx uGT^CJ2 iH U$[~?ݿ"´iy]r?큿۷Q͝j8Gޓ+sN%0ۅ%kW~1[t;"H#N<8pi{U͇-!z$<.a,5Ⱦűwvbo6{C"y H1bBpC ٵ01T$ Tu=$( eesCSQ:J1QJe3@YEIBRU05rr8]y?_UIDO_ci&ǽ-%CQAbNT;r$B+IrUvc ݀ZA䚨m"j|2 *Qe !eQĪV.,K-}g_8liQ2M[)Iwl.T5$ 0$@npKJ"CJC"(m88`ពtI(%TM*ܨFC ƢXa8]w^~MifLq垤%T QSIPhG( ˺Ze4Vި@ j O.qbN^}=0MӌiBH/Ǹ]6㣕#t_*@R\n$<}U u@;}>nZOڭm, `YTQjv2F]ƈ#DJhjK3Kq_߾iz;D4MSp8rg3rU O%*U҈"ZI={_GV]{/Pɮ ڡ ue1e|2ǂ6?KGTizD4M[:'K_GG @@RUI UҁcX.yB@-% B$HJKІ$wHŵG^yYizD4M ߿+۶oIV PyJM"X jޏ{9-@H`i hgK0 @'![5TF-t}/O_O4Mo(i:Ncwior[O`w E  o"b䚠H-$UA0 X]c6X^ƨ;gW_Li]pgU BDEPB @I:AD@1v92tRR0Uw[@ V\jc=s_+oT fi*i Lg[<@ <(>ePnrR%D"wFJڡ*jɨ6#8Yqv§>۟y=dim}0j.Q$J @2@-@P-KۢgcYkHX}o"JJ av8=Z=ܷ}w,뚄iQ2Mt<>cO?|l?Q֣xR.QZITGu7QѨn f8qXǝ;~]7 4#d/˒dg9vxO%D ITn45@@Nj>>w8=]ٵbI&YIu=0[TшDXC=_}+3izE4MSy??,z=/lq wg/D ( 4k!]\DUpM;@c]FK SE麎~GiAQ2Mg}??,kUݻ=+Hu@J@ePh xm(mwqq2,Cg!1 BU [MT,LjLjdԺ,w||; /2M;1Ji>CwRTy|p_%-@ o'* Z*I(jX~./OUrm)sU$*Bp'g/OXizF4MNN_E, `5ȓ[ȵ\5Zcwȣl=NCֽC1HY,Feu?oO<4MS4MXw⓭m>s}|xJ RU(rQc,RНxqys.'U*X1{޷1zDSeZ겸,u_"QyI4M'^z/~/ؗp7 OwgJv7n(q7`80!Wm;<{aڒlf2333(>Qaf&a6X74Tё.OA7$I +|uۚVc>;Qb1Hmt`ؽu J؛+O@Ĕ(wRI@ABH'ɮ4%quʻڇP1P kg3M"YJ@zq^O=W}S5cQb,Y>_E5T.$85휸LN8!E%U9k頭ˁ TUB*+뺞 B0 qȉWzѕO?/" c)1|s.^L Ԭ ziRQ"Ux(Dwމs @iΟn^yDeH' U5nogi(D)">LM ~u9cJ;PYUpI$E9#T5H;uɅBb۵S6%-2JqEU 0DzbQůgK+V$1ԕdz$VNȺ%xq=E@Rx84gMfU'iAB*5禉MJ =) 1x@_O|{c#%ƘϰʹssVRUr,=w!P?{2bμ+{ELb{" }bQ'~Γ1ƢG䣏jԬT AzO>͑O.~}Pxc2qQz!=`/'~qQ=8/ruogXcOZιry5aRtC"{))Aw"A|>5AY: +KRRU,._yP+ؚc<{a( 4pKxk'g6ۻБ HQU9k5Ŝ|c3΢n'um;ۙݲwu2^[X>«1FJ1 $s_ln2#S v3]$3?@EM]1$ѳ*,7f p.nt=Yr}Cƃ3?Ks0|ncJI@yth]b9g34EU@2笪)%Poi3.~#Ht2֕1eq_0|Χo1FD4*a|xsլ"#$(bj&D8Q(R;򠪊"Én[7q$;Ϝ~{~cO1ƢceF[wPhV]Xr~wR\$?{rHBʷۓ˽R ;ws*ԭ|`c,]QI W vmHdM9z(kiL]J*P͛\EEyռմ= c?w c#%#e3A: i}CFo}g()b %RM)ŔtaAyf֭=hu)1ƘOHs\׵^<afn睷s̠U1jt]KEլ{ 1JOxqdu'zE1Ƣc>Q,E"*Te0g&w޸@.Ŧq fj{[uPa|Q%ݘGو_ry%c,J1RtE&ᙳ2eh6[p+)E![Mn!x4,D$6;[1 U^0Xc̯GqY5Iл_/k P{7w5id"h)47p}8Hwp}0u$ڴx'1Ƣc~Q"]IP5{?X޸t$;oD J0nmppfe\UeY5w#)nW_co17E)Ok\{S͹ڛMf RNۮ~aDu"正[ӧ>Iclc~UvdRP +]82 'N[nW[;[M\[_@v90C)7]e(=c0Xcok ޤڟκ6j󽕵Sx\GtaᚸǃG8vxPEI2p⫯:a(1ƘVoiԵ )>biaXs{ooui+-A*,->vS{U (AL]jnꯜ:c֔c҃?-Ǖ Gzo) Hs/ S͢!i]ũV;c~'%3>~2EtJ@HH"LhJj 4c^uLQ\Uc~'6}c1j'k%U% :+G#z/ދ~p{u=Ng9gq;gmDq ec߹U*G+/*B}2@]=oc 0;89jDwRtW*܇1FJ1fJEB2Ly@9|9dլ e9uW9]ץ.7S5XZ[/{=܇1FJ1f7 4$ReUjV*( ?{ͩ.j w4yB3:@,-Ua(1Ƙ>ߕs ( LN8UE Rx*)8WԵmEf ?P :cQb1åp=&a;sJ ڦ|8D$@' ~HQﴞMj,7|g(1Ƙj0\>s[ +v ]: UMYsGTUD*PBs*01ܗ1Ƭ:5c*PƣAΧ*C BDT5L0 LRUqMnAЁK'`1ྌ1fL( : a8,J( GPՔ89wm꺮i 9*3QϦmK1/c9rW8!&d(]()!DclS {cYE |%S<a1ྌ1&铑9G!" ""LQ<( C"ۦڶ#Hp>k:UN/_" c<cH~``TBBA!Uue15Msxuմ?m;UVՉsgIcc.=}qdP%22@ !UxGR"w.f ./m;#cE1?wnI||NSBs@q!U!U@Rj]׳twr:^]1Ƣcrd3 iض֔SJ!.҅C({UQ L)9Typ8whiwcyoޣs晳2Xc̅g9.E D""iU"#"ܹU7IH^|(+~c,J1湯[9 _ *U)"Nq!eHS !bq{k+HcQb1e?؅/y|pe #"@dї✫խݬT/< a1%Ƙ?WomUlݮmѻ jOIA$;oߚ!˪c7>e꺞bYs֔sP%R]~k5*>y/RccH>_{usE^VFKz2 U␈z5 WKWO1H1ًhg^Y(…he=L&󝝝~J''Q#ݜ7N;5?ycfcHmhAr8^LB 8CMwmѣ~Ǐ`1%Ƙ?O= xHnEѫÅ1AU!j׶_v4à__ c(1 e?doґ$H@HO8rˬs+:/Ƌ0cW߯cR g)eBͨ'j}:0cK/z:P!UO0)xڭ7>jm~g^o11?Stxf:'Dʚ7_ncus_?xa1%Ƙ?&Eo?_X^]Y;N=3_ϼսcQbc%"_]?|'5pn̩3_?ɇ.c,J1HyDSϡ (Brc ]1 Ĺ? u@L-žH %=rS %H %RPNR*'IENDB`rbnacl-7.1.2/images/logo.png000066400000000000000000000374541470351605300157160ustar00rootroot00000000000000PNG  IHDRR=J>IDATxàSd2@Xa~U}lȂŬ("K6@0dFhKU)PXBm&<{[Qs: ^Uc- Z`T\EZEz]@4U\q8 _ETPoPZ45lXF85\~4[5Ly!6f,D0hY܋`X|">FD˕ٵ1Dⶮ|(&+k3#泱Ͷl(f3h8Ehvby4;+ѻ85DsD܈fGnDq3֣5Dsbm,F:1KџRG hlnp=q!q!D hsA0ׇ8hX8[Y(D\+Q3j#F |1b> Ѽc9zF,(Dn=D<Qك1ySf=nGh

8D8T,GO8D8y,EODq9z\Q UOcdffffy |)6͸Yafff&'<E7"@43hxL4Ox8Gc(Fhfp*3333<%9ьh#)f|+֣Gd=nEfDshΧ].{D3S\LL4 0z\uF<!c vAV,Zp9^ x\`)p3pN|F ċ蝑HRE2sQŜsιM17 Dx[vFg/b)TH=-<Ǐq%.'qވݱ#ge4?FbE,EŸ b ȌfrJh^͸ơ H b4hN3{Yōx@3/i5R3e43Wg~Ӹ{Fܾwq2@jCFfT?g4;=q5!\`ނTFfA Wιu0hB YF30#797#TF3]N0e4a8\=f4;:q,E6fg4Ф,({hvέ#T;F3Up6e4Dʜ3sAjhvFH5a4h&hv'Z!Մ,N1g4;ގEՔf-1H5a4hι ՜f-3x%RM2ghvεyDf-X&f٨~hv`Vd4;YuR2Q͜7ma܈K1C'fX=[a јKpEhvF H5b4h73s-\h# =Ѓ:敦yx R2f/~1r 롄mS<敧jh܋f\s:PP|s0Ѽg%/kpN'p~و;Ff@/Cι!jfעujx3~^yF\2c1aDM܃1e4p>g4;A?q&A;m$>njfhƯQcjh ,X5W!h筆ql491Gh:1e4\ι1QGp"Фp80f9C4gЁqQ#2e4\g4;V|kAD#ܡl4͙9Cp?D;YFsF=[:3DǦp:?i4FsG3>ňf(8ٹΫp/n| dfh63}f͙#fB]X-Ch6=u;DFsR23u99#k.0Op#0h6vfSh6 L:pFsp0b{mn0fo\TYFs5np899܀5so0][F  @'R5fpMf|-F5f`W,AdRuf]pMf\f ыw Z%Fkh6 28ZF Lnh8ιXqnnO2]{FѼ:FT'H3e4WJt5%sQ-fDDŞD zF \\Gsnu fhzQl4hQpFsu}ph6 m97@3f9K2j6G3s'"2 fh.WfYFs31 %hvuD&9Fs6G,*Da(mFsPD&c8g4Fs!.ETh$Rf#0 QiX%hvqph6\݈ϙ,QX%hvm A3f ?DTh5 f͌ua20a8rhv}kl4ͅQg22e436S59ׁ 293f@y)3YF3cݸQх3s 2F\=Rf͌ mL6Ls"DsFl45 MB*,ᘊ(U4+d4;7#2x53f@GTH1e43n-"ph6B Q"hHLC"Fs#2x'3f@ B;#ea4nӈeIc2p6CRE3c#1QQͮ[܁阃x0n7Q9sFl4Db0R%8 0?G0]Hq436 39%hvc>[1Ex3zпs;"2F\ *e4q3z{ F3ca60C 38ij-!2F\3D~XkThfl'<(xB\F \󚆑H2;QXhΰ}1u-3[F\a8s }n.LF(#hfhacLGĥHFh!hf  Fs#y ܍x2?ќFsx  ɘzfUdRfƆ` 0BhnzO͹g4+d4"x5Rfƺq30u4B!*3hVcd65!hfl8nC춌fyO"V 3UhV&?G PF3c1Q3*51d4Qaph?Y=HF2z7Rf-46l4`4 Q1Fh4["ź,1' %^t\{Q RfFb0fu j/gMx%FaC$`$+&on,5e!*32Yr$(pH}65X(/ g4363Q01QGc$0bѼʻQ9phnf-X$.^24DD*(,0_o4rAA51P.F;z`6[Bp f 3C g43f# ͵xQtʍeyh6fƫ`SX(YH2NxQk4fAdNCrnh63Ѭ ќ<R!^rl " 2cRDAn(e- f fg4F@2[!hu\(ħh~c s1hU F 1wETfg4D2HkGҲ7pbC0 ǡFDv<m0g4;Y3j BS Ҳ7QFsq "Ϳ@Tl#8g4|F$9/"y&#-h.~Q0h.fYDF0u['5h=F7B"2{RvT< EtDF8u]~HFEh,HE0_&!2 R͙v,0Sќu-LCd^}kOh4bG9&35P$ZHm`@d#uxDanp9Ed4 mTãMsFs3.$͋26%!2y?(om4gELah?g4qW h> V$Fs]7Q)Xhtx 3 Ѭ`$ש_!2 Fsw60e4W|੆Fֈ̀sFs 5WlZEHml{,Ad0 Fsw0WhGh}<08g4@Hc4߀_Gd0hnhnbDa.EhMEdp}C1qc 3jR/EjMQ=։I\h46@d0 ЄhQSќFsEf`2#2:6#57Fs! s<`{3"Д K63hH2& 2jh~R{a4׺0QWahҾh~b5zFl4wDFwb5ͳ0aFTZ!(~ާ[ɶi`4%p l4昇KHE3FjS{Fs{7# 3hub!baѼ1"5xFl4 2;XFH >"*km Q8hmԽaќKM g4F3p="ǰRqщPDTl77S>-}MV Ɉ=l4i<@*|9R}Qߺ"l4ig!*4,OGdYfhDdvRQlD>n47b#1 Qk4.ETh1ɻajD_sFl4p!"F+ M2(|1kq0߰h%D3fx0);Yt!5ܟܨLDAbѼқEɽQ- ^ fhX*滐B#*ܸmوƎFJm!B'&7Ad0 Fo&"2;)+H 3 31h^3`âywD 0F )\Qu͍E!4M.͝`3fߌ|DFwc5,"AThnvDAaE3bCRQؕ f`3fߜ,棑B["*-0b]Bst LsFl4/!Uh>)ԃ6Fs7ϻ}zC1}sFl40x R惐BC/ Ct8ӸhfD&G9h6q("ЉTy_@hl4gQ 1c#*4+f_g sFl4/@ќhθc.h.`440x8g4F2a"%afhv9˳FF3c_Bd9h6;zMGwR Q癛(ejyf1G󎈌fh~@dv-z$+r6lF316حLzr8g4F2㏈i4cB=k4FsqR K #݁Aph6el`{ك*b]F[3m 7̓"3l4dDf`<`.B 틨3Ha4.6DvKf>h1^fh^F ?Adv<`~:QF ub\ZX[RhN":3fy Dfb*Rh"B+9:BThbrXh4> 8g4Fx"a`h#*}٭0hξ^r; FsDf9h6enF^FÈ }h^!b4gu =ۍG-ph6e&DQwͫ8׍l,b#䝃`4IDf3fy{Q/4շ-l4>l8n3xD< n9{cm8g4F2>l2@jIma4 Fs rl`<(-sFl4p7"~5IDBhu+gy8b&w?Cʙm4l4;Df~ Q"ٍ4MGTl4q?6_t?A{`ќ{F Bh4Ё0 *v.; ލlonܯ;A]·FX(t-4y0}c4?h6ށTM4mg!2k !JD܊j@,}`4zF |Q7h! DjH2Fsl],Dd6uqG7iCq/Om 1W~.\faaѼ5d4q(fE\X\Ob "xѬ嘊r3]'0QCF?A(h\Gg4MFH.`Ѽ 5d4NBfh61Z Xr "l4ݱh^5Wؿ"-~l4Fs[ckH4Oǫ14 # ;"^FskDEh6fzx/kH4' Cwa=.aѼ{9EF*oO _06xXtFќ;FE30_D{ ͮM0b)=['V/1(yFl4g'z\q ݄*b47anܧ톻mY|C?د;3mY۶ۨvڶm۶m_O\'ybx(Z}xYӬiF0>k(A!셉6,iÒj@ӬPa 0Oz r)p?MYXXT8@j LmC M.5&k\Y7 [xANӬi4{]q;P ``1"h+hiVI(0>wa5*3DKx ni4kCOT4C&%9h'ŢWDYn8#{~4X|Z 0Q`"'i=LӜ]f D:,adgQ3<莿l/A戗08 T6vQ ?K8 sQ# a#iRDƲAVr'z> _D0\X6>E%RnfMdCm r@{HRf9Mt:F4E3؋՘h $L4#1 `nc6zrA)?r:Z7`.-nlAw4CydxWدC(X- <`6h(6b3 EaX֙8pE3%:f X-(.la/ ofJ2MZ^4@6|KF4@6{h2-bh Dsh-=>u%~Ahn'iYY}o@M7+ϲ,+@GzL3=FeYМ>1f\eY-Ce%hh64654[%禛eYlh,Cٺ44dhR(?hxVܬWIp24[L,C .RUhAY|]ɭx`p^`Atl-lh64xnjh>j4cƛeh,#fehlhfGk9phjgXfK Ceh,ClhFz/B/?ylYf ͖eh64 K:G);xA薡24[f24 ͆:[eѫ̛QqN ͖~ ͆}XЏ8ceh647X{yw?[;X8B2u_}D.פvmG5ywvh,D?؂|y3ӿ U }= -Q}AO[/.C/ĘjGLqh~׆f>891D x~Ja?fȡZi#y~[|C/Hikeh64T{5@p0[gfؾ(47ocF61@ 2xc3o)CM^vF o<6o@hG_Gw4j/3oz@7w9ox7ߣza}?fy_ ` ͆'pAfL мq@9f;C3no߮'qh,.4L-Xiwփ}N14q_FfCsWDyI, nNJ@[qo^gs^EcЭsmf#ۦnd;>G9Ь r},|>Au,Z*ͅ83xYh9L~<̶_kvoDCxG܇oyA}N14qeh64W[ߍ ^:q}hJ4kxj⛒} )l'cl߆fߝB A\~D_ Gr ͏s%u@sŁJSOwD15 ̳XKK0@M|l< jog՝f}N14tqeh64*w $fP^ m^Ƌ}c,džfC~=́m`>q`QxՋއ>}A^ yx㟆hnEjb5";=4||r[o\qSiKap3wyk"la}?)f}_(`,ConX64@3=9Y y~Fٝ{|qm@sRۮd)D/ċeDC? la}?)f}_(`,CnX14֡xe:/[@3 V,gGO St`m㉰1V6M~/eAӿY_ ͪ A z2~rhpWr쭟&ra=wNLn寞 ]~SX7 2Oa}}C}lh64 |÷84/3{x-Tq~C,)<4E添w 满Y_ "_Ljp~МCssӝ$ + K@١Yo;fCs}6>sY>k N??U|^iֿhÄ́yt`j[SG v^iYZ,)f4>C v}14sfXP"i.(4w:K4A6 qΐfiC}le7vYAr TF J59@3` l'{+ZPw yل܂<4}XߏsY5ز |C3j*vS@n`NP+CTO<4WXW,a=4끡Y5ز |"24B{o'y n Igz 4R]DN]g_a-6x"uC죇f}=04lq[hhϙ*h@`../E ,C3?S,\I͠[ycw b[l&f{^Vު۞gs#nC/9jeqsU*mA󍙑}*Vkyh^+m)y&$Hޤ] 6<e Y`;sH,4גϷ;ËۤEez#bh>G ,C3f>Y$l(GȲ vwcTD[:ݦ+x0X/jYo;xe\ި d;vʩRg>G9Ь }lYfZ6 $fQjO*OfǓ|?q>TQr5FO (h$4?w2_YwU}ǥ|84YT5ز @A I,,=4 f. X=, |.4_=ybb<&~NqL@)Yo;x+Xޒ[qc3l.(_] Q"-˲`rlTphC/ijeAf< b`o*1DCṒb"yW>eЬ }lYflf8~UCywbd1wjB3||f7V^r`=4m_S6O5= `UU |I٠YV ͪ cge58g- }6x7^[A8Hf;qB+cPj;+8maya>OBcsƿ7}qP PQ0SP(S0S0S(Sv$+K P\W/Tp&vn=rX?@^,=v۴ rX?@CVprX?H 8\Mxo@{b{`NizC8oN=XbhF?=s vE c,@ZbWjݶ g~ ~7.1|@װ}`n9z MĮAa njt ϓZ%h?~ϐɰ1PkIENDB`rbnacl-7.1.2/lib/000077500000000000000000000000001470351605300135345ustar00rootroot00000000000000rbnacl-7.1.2/lib/rbnacl.rb000066400000000000000000000072001470351605300153210ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true if defined?(RBNACL_LIBSODIUM_GEM_LIB_PATH) raise "rbnacl-libsodium is not supported by rbnacl 6.0+. "\ "Please remove it as a dependency and install libsodium using your system package manager. "\ "See https://github.com/RubyCrypto/rbnacl#installation" end require "rbnacl/version" require "rbnacl/sodium" require "rbnacl/sodium/version" require "rbnacl/serializable" require "rbnacl/key_comparator" require "rbnacl/auth" require "rbnacl/util" require "rbnacl/random" require "rbnacl/simple_box" require "rbnacl/test_vectors" require "rbnacl/init" require "rbnacl/aead/base" # NaCl/libsodium for Ruby module RbNaCl # Oh no, something went wrong! # # This indicates a failure in the operation of a cryptographic primitive such # as authentication failing on an attempt to decrypt a ciphertext. Classes # in the library may define more specific subclasses. class CryptoError < StandardError; end # Something, probably a key, is the wrong length # # This indicates some argument with an expected length was not that length. # Since this is probably a cryptographic key, you should check that! class LengthError < ArgumentError; end # An incorrect primitive has been passed to a method # # This indicates that an attempt has been made to use something (probably a key) # with an incorrect primitive class IncorrectPrimitiveError < ArgumentError; end # The signature was forged or otherwise corrupt class BadSignatureError < CryptoError; end # The authenticator was forged or otherwise corrupt class BadAuthenticatorError < CryptoError; end # Public Key Encryption (Box): Curve25519XSalsa20Poly1305 require "rbnacl/boxes/curve25519xsalsa20poly1305" require "rbnacl/boxes/curve25519xsalsa20poly1305/private_key" require "rbnacl/boxes/curve25519xsalsa20poly1305/public_key" # Sealed boxes require "rbnacl/boxes/sealed" # Secret Key Encryption (SecretBox): XSalsa20Poly1305 require "rbnacl/secret_boxes/xsalsa20poly1305" # Digital Signatures: Ed25519 require "rbnacl/signatures/ed25519" require "rbnacl/signatures/ed25519/signing_key" require "rbnacl/signatures/ed25519/verify_key" # Group Elements: Curve25519 require "rbnacl/group_elements/curve25519" # One-time Authentication: Poly1305 require "rbnacl/one_time_auths/poly1305" # Hash functions: SHA256/512 and Blake2b require "rbnacl/hash" require "rbnacl/hash/sha256" require "rbnacl/hash/sha512" require "rbnacl/hash/blake2b" # Password hash functions require "rbnacl/password_hash" require "rbnacl/password_hash/scrypt" require "rbnacl/password_hash/argon2" if RbNaCl::Sodium::Version::ARGON2_SUPPORTED # HMAC: SHA256/512 and SHA512256 require "rbnacl/hmac/sha256" require "rbnacl/hmac/sha512256" require "rbnacl/hmac/sha512" # AEAD: ChaCha20-Poly1305 require "rbnacl/aead/chacha20poly1305_legacy" require "rbnacl/aead/chacha20poly1305_ietf" require "rbnacl/aead/xchacha20poly1305_ietf" # # Bind aliases used by the public API # Box = Boxes::Curve25519XSalsa20Poly1305 PrivateKey = Boxes::Curve25519XSalsa20Poly1305::PrivateKey PublicKey = Boxes::Curve25519XSalsa20Poly1305::PublicKey SealedBox = Boxes::Sealed SecretBox = SecretBoxes::XSalsa20Poly1305 SigningKey = Signatures::Ed25519::SigningKey VerifyKey = Signatures::Ed25519::VerifyKey GroupElement = GroupElements::Curve25519 OneTimeAuth = OneTimeAuths::Poly1305 end # Select platform-optimized versions of algorithms RbNaCl::Init.sodium_init # Perform self test on load require "rbnacl/self_test" unless defined?($RBNACL_SELF_TEST) && $RBNACL_SELF_TEST == false rbnacl-7.1.2/lib/rbnacl/000077500000000000000000000000001470351605300147755ustar00rootroot00000000000000rbnacl-7.1.2/lib/rbnacl/aead/000077500000000000000000000000001470351605300156675ustar00rootroot00000000000000rbnacl-7.1.2/lib/rbnacl/aead/base.rb000066400000000000000000000107571470351605300171400ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module AEAD # Abstract base class for Authenticated Encryption with Additional Data # # This construction encrypts a message, and computes an authentication # tag for the encrypted message and some optional additional data # # RbNaCl provides wrappers for both ChaCha20-Poly1305 AEAD implementations # in libsodium: the original, and the IETF version. class Base # Number of bytes in a valid key KEYBYTES = 0 # Number of bytes in a valid nonce NPUBBYTES = 0 attr_reader :key private :key # Create a new AEAD using the IETF chacha20poly1305 construction # # Sets up AEAD with a secret key for encrypting and decrypting messages. # # @param key [String] The key to encrypt and decrypt with # # @raise [RbNaCl::LengthError] on invalid keys # # @return [RbNaCl::AEAD::Chacha20Poly1305IETF] The new AEAD construct, ready to use def initialize(key) @key = Util.check_string(key, key_bytes, "Secret key") end # Encrypts and authenticates a message with additional authenticated data # # @param nonce [String] An 8-byte string containing the nonce. # @param message [String] The message to be encrypted. # @param additional_data [String] The additional authenticated data # # @raise [RbNaCl::LengthError] If the nonce is not valid # @raise [RbNaCl::CryptoError] If the ciphertext cannot be authenticated. # # @return [String] The encrypted message with the authenticator tag appended def encrypt(nonce, message, additional_data) Util.check_length(nonce, nonce_bytes, "Nonce") ciphertext_len = Util.zeros(1) ciphertext = Util.zeros(data_len(message) + tag_bytes) success = do_encrypt(ciphertext, ciphertext_len, nonce, message, additional_data) raise CryptoError, "Encryption failed" unless success ciphertext end # Decrypts and verifies an encrypted message with additional authenticated data # # @param nonce [String] An 8-byte string containing the nonce. # @param ciphertext [String] The message to be decrypted. # @param additional_data [String] The additional authenticated data # # @raise [RbNaCl::LengthError] If the nonce is not valid # @raise [RbNaCl::CryptoError] If the ciphertext cannot be authenticated. # # @return [String] The decrypted message def decrypt(nonce, ciphertext, additional_data) Util.check_length(nonce, nonce_bytes, "Nonce") message_len = Util.zeros(1) message = Util.zeros(data_len(ciphertext) - tag_bytes) success = do_decrypt(message, message_len, nonce, ciphertext, additional_data) raise CryptoError, "Decryption failed. Ciphertext failed verification." unless success message end # The crypto primitive for this aead instance # # @return [Symbol] The primitive used def primitive self.class.primitive end # The nonce bytes for the AEAD class # # @return [Integer] The number of bytes in a valid nonce def self.nonce_bytes self::NPUBBYTES end # The nonce bytes for the AEAD instance # # @return [Integer] The number of bytes in a valid nonce def nonce_bytes self.class.nonce_bytes end # The key bytes for the AEAD class # # @return [Integer] The number of bytes in a valid key def self.key_bytes self::KEYBYTES end # The key bytes for the AEAD instance # # @return [Integer] The number of bytes in a valid key def key_bytes self.class.key_bytes end # The number bytes in the tag or authenticator from this AEAD class # # @return [Integer] number of tag bytes def self.tag_bytes self::ABYTES end # The number of bytes in the tag or authenticator for this AEAD instance # # @return [Integer] number of tag bytes def tag_bytes self.class.tag_bytes end private def data_len(data) return 0 if data.nil? data.bytesize end def do_encrypt(_ciphertext, _ciphertext_len, _nonce, _message, _additional_data) raise NotImplementedError end def do_decrypt(_message, _message_len, _nonce, _ciphertext, _additional_data) raise NotImplementedError end end end end rbnacl-7.1.2/lib/rbnacl/aead/chacha20poly1305_ietf.rb000066400000000000000000000035711470351605300220170ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module AEAD # This class contains wrappers for the IETF implementation of # Authenticated Encryption with Additional Data using ChaCha20-Poly1305 class ChaCha20Poly1305IETF < RbNaCl::AEAD::Base extend Sodium if Sodium::Version.supported_version?("1.0.9") sodium_type :aead sodium_primitive :chacha20poly1305_ietf sodium_constant :KEYBYTES sodium_constant :NPUBBYTES sodium_constant :ABYTES sodium_function :aead_chacha20poly1305_ietf_encrypt, :crypto_aead_chacha20poly1305_ietf_encrypt, %i[pointer pointer pointer ulong_long pointer ulong_long pointer pointer pointer] sodium_function :aead_chacha20poly1305_ietf_decrypt, :crypto_aead_chacha20poly1305_ietf_decrypt, %i[pointer pointer pointer pointer ulong_long pointer ulong_long pointer pointer] private def do_encrypt(ciphertext, ciphertext_len, nonce, message, additional_data) self.class.aead_chacha20poly1305_ietf_encrypt(ciphertext, ciphertext_len, message, data_len(message), additional_data, data_len(additional_data), nil, nonce, @key) end def do_decrypt(message, message_len, nonce, ciphertext, additional_data) self.class.aead_chacha20poly1305_ietf_decrypt(message, message_len, nil, ciphertext, data_len(ciphertext), additional_data, data_len(additional_data), nonce, @key) end end end end end rbnacl-7.1.2/lib/rbnacl/aead/chacha20poly1305_legacy.rb000066400000000000000000000033311470351605300223260ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module AEAD # This class contains wrappers for the original libsodium implementation of # Authenticated Encryption with Additional Data using ChaCha20-Poly1305 class ChaCha20Poly1305Legacy < RbNaCl::AEAD::Base extend Sodium sodium_type :aead sodium_primitive :chacha20poly1305 sodium_constant :KEYBYTES sodium_constant :NPUBBYTES sodium_constant :ABYTES sodium_function :aead_chacha20poly1305_encrypt, :crypto_aead_chacha20poly1305_encrypt, %i[pointer pointer pointer ulong_long pointer ulong_long pointer pointer pointer] sodium_function :aead_chacha20poly1305_decrypt, :crypto_aead_chacha20poly1305_decrypt, %i[pointer pointer pointer pointer ulong_long pointer ulong_long pointer pointer] private def do_encrypt(ciphertext, ciphertext_len, nonce, message, additional_data) self.class.aead_chacha20poly1305_encrypt(ciphertext, ciphertext_len, message, data_len(message), additional_data, data_len(additional_data), nil, nonce, @key) end def do_decrypt(message, message_len, nonce, ciphertext, additional_data) self.class.aead_chacha20poly1305_decrypt(message, message_len, nil, ciphertext, data_len(ciphertext), additional_data, data_len(additional_data), nonce, @key) end end end end rbnacl-7.1.2/lib/rbnacl/aead/xchacha20poly1305_ietf.rb000066400000000000000000000036101470351605300222010ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module AEAD # This class contains wrappers for the IETF implementation of # Authenticated Encryption with Additional Data using ChaCha20-Poly1305 class XChaCha20Poly1305IETF < RbNaCl::AEAD::Base extend Sodium if Sodium::Version.supported_version?("1.0.12") sodium_type :aead sodium_primitive :xchacha20poly1305_ietf sodium_constant :KEYBYTES sodium_constant :NPUBBYTES sodium_constant :ABYTES sodium_function :aead_xchacha20poly1305_ietf_encrypt, :crypto_aead_xchacha20poly1305_ietf_encrypt, %i[pointer pointer pointer ulong_long pointer ulong_long pointer pointer pointer] sodium_function :aead_xchacha20poly1305_ietf_decrypt, :crypto_aead_xchacha20poly1305_ietf_decrypt, %i[pointer pointer pointer pointer ulong_long pointer ulong_long pointer pointer] private def do_encrypt(ciphertext, ciphertext_len, nonce, message, additional_data) self.class.aead_xchacha20poly1305_ietf_encrypt(ciphertext, ciphertext_len, message, data_len(message), additional_data, data_len(additional_data), nil, nonce, @key) end def do_decrypt(message, message_len, nonce, ciphertext, additional_data) self.class.aead_xchacha20poly1305_ietf_decrypt(message, message_len, nil, ciphertext, data_len(ciphertext), additional_data, data_len(additional_data), nonce, @key) end end end end end rbnacl-7.1.2/lib/rbnacl/auth.rb000066400000000000000000000067161470351605300162750ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl # Secret Key Authenticators # # These provide a means of verifying the integrity of a message, but only # with the knowledge of a shared key. This can be a preshared key, or one # that is derived through some cryptographic protocol. class Auth # Number of bytes in a valid key KEYBYTES = 0 # Number of bytes in a valid authenticator BYTES = 0 attr_reader :key private :key # A new authenticator, ready for auth and verification # # @param [#to_str] key the key used for authenticators, 32 bytes. def initialize(key) @key = Util.check_string(key, key_bytes, "#{self.class} key") end # Compute authenticator for message # # @param [#to_str] key the key used for the authenticator # @param [#to_str] message message to construct an authenticator for # # @return [String] The authenticator, as raw bytes def self.auth(key, message) new(key).auth(message) end # Verifies the given authenticator with the message. # # @param [#to_str] key the key used for the authenticator # @param [#to_str] authenticator to be checked # @param [#to_str] message the message to be authenticated # # @raise [BadAuthenticatorError] if the tag isn't valid # @raise [LengthError] if the tag is of the wrong length # # @return [Boolean] Was it valid? def self.verify(key, authenticator, message) new(key).verify(authenticator, message) end # Compute authenticator for message # # @param [#to_str] message the message to authenticate # # @return [String] the authenticator as raw bytes def auth(message) authenticator = Util.zeros(tag_bytes) message = message.to_str compute_authenticator(authenticator, message) authenticator end # Verifies the given authenticator with the message. # # @param [#to_str] authenticator to be checked # @param [#to_str] message the message to be authenticated # # @raise [BadAuthenticatorError] if the tag isn't valid # @raise [LengthError] if the tag is of the wrong length # # @return [Boolean] Was it valid? def verify(authenticator, message) auth = authenticator.to_s Util.check_length(auth, tag_bytes, "Provided authenticator") verify_message(auth, message) || raise(BadAuthenticatorError, "Invalid authenticator provided, message is corrupt") end # The crypto primitive for this authenticator instance # # @return [Symbol] The primitive used def primitive self.class.primitive end # The number of key bytes for this Auth class # # @return [Integer] number of key bytes def self.key_bytes self::KEYBYTES end # The number of key bytes for this Auth instance # # @return [Integer] number of key bytes def key_bytes self.class.key_bytes end # The number bytes in the tag or authenticator from this Auth class # # @return [Integer] number of tag bytes def self.tag_bytes self::BYTES end # The number of bytes in the tag or authenticator for this Auth instance # # @return [Integer] number of tag bytes def tag_bytes self.class.tag_bytes end private def compute_authenticator(_authenticator, _message) raise NotImplementedError end def verify_message(_authenticator, _message) raise NotImplementedError end end end rbnacl-7.1.2/lib/rbnacl/boxes/000077500000000000000000000000001470351605300161155ustar00rootroot00000000000000rbnacl-7.1.2/lib/rbnacl/boxes/curve25519xsalsa20poly1305.rb000066400000000000000000000171571470351605300230020ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module Boxes # The Box class boxes and unboxes messages between a pair of keys # # This class uses the given public and secret keys to derive a shared key, # which is used with the nonce given to encrypt the given messages and # decrypt the given ciphertexts. The same shared key will generated from # both pairing of keys, so given two keypairs belonging to alice (pkalice, # skalice) and bob(pkbob, skbob), the key derived from (pkalice, skbob) with # equal that from (pkbob, skalice). This is how the system works: # # @example # # On bob's system # bobkey = RbNaCl::PrivateKey.generate # #=> # # # # send bobkey.public_key to alice # # receive alice's public key, alicepk # # NB: This is actually the hard part of the system. How to do it securely # # is left as an exercise to for the reader. # alice_pubkey = "..." # # # make a box # alicebob_box = RbNaCl::Box.new(alice_pubkey, bobkey) # #=> # # # # encrypt a message to alice # cipher_text = alicebob_box.box("A bad example of a nonce", "Hello, Alice!") # #=> "..." # a string of bytes, 29 bytes long # # # send ["A bad example of a nonce", cipher_text] to alice # # note that nonces don't have to be secret # # receive [nonce, cipher_text_to_bob] from alice # # # decrypt the reply # # Alice has been a little more sensible than bob, and has a random nonce # # that is too fiddly to type here. But there are other choices than just # # random # plain_text = alicebob_box.open(nonce, cipher_text_to_bob) # #=> "Hey there, Bob!" # # # we have a new message! # # But Eve has tampered with this message, by flipping some bytes around! # # [nonce2, cipher_text_to_bob_honest_love_eve] # alicebob_box.open(nonce2, cipher_text_to_bob_honest_love_eve) # # # BOOM! # # Bob gets a RbNaCl::CryptoError to deal with! # # It is VITALLY important that the nonce is a nonce, i.e. it is a number used # only once for any given pair of keys. If you fail to do this, you # compromise the privacy of the the messages encrypted. Also, bear in mind # the property mentioned just above. Give your nonces a different prefix, or # have one side use an odd counter and one an even counter. Just make sure # they are different. # # The ciphertexts generated by this class include a 16-byte authenticator which # is checked as part of the decryption. An invalid authenticator will cause # the unbox function to raise. The authenticator is not a signature. Once # you've looked in the box, you've demonstrated the ability to create # arbitrary valid messages, so messages you send are repudiable. For # non-repudiable messages, sign them before or after encryption. class Curve25519XSalsa20Poly1305 extend Sodium sodium_type :box sodium_primitive :curve25519xsalsa20poly1305 sodium_constant :NONCEBYTES sodium_constant :ZEROBYTES sodium_constant :BOXZEROBYTES sodium_constant :BEFORENMBYTES sodium_constant :PUBLICKEYBYTES sodium_constant :SECRETKEYBYTES, name: :PRIVATEKEYBYTES sodium_function :box_curve25519xsalsa20poly1305_beforenm, :crypto_box_curve25519xsalsa20poly1305_beforenm, %i[pointer pointer pointer] sodium_function :box_curve25519xsalsa20poly1305_open_afternm, :crypto_box_curve25519xsalsa20poly1305_open_afternm, %i[pointer pointer ulong_long pointer pointer] sodium_function :box_curve25519xsalsa20poly1305_afternm, :crypto_box_curve25519xsalsa20poly1305_afternm, %i[pointer pointer ulong_long pointer pointer] # Create a new Box # # Sets up the Box for deriving the shared key and encrypting and # decrypting messages. # # @param public_key [String,RbNaCl::PublicKey] The public key to encrypt to # @param private_key [String,RbNaCl::PrivateKey] The private key to encrypt with # # @raise [RbNaCl::LengthError] on invalid keys # # @return [RbNaCl::Box] The new Box, ready to use def initialize(public_key, private_key) @public_key = public_key.is_a?(PublicKey) ? public_key : PublicKey.new(public_key) @private_key = private_key.is_a?(PrivateKey) ? private_key : PrivateKey.new(private_key) raise IncorrectPrimitiveError unless @public_key.primitive == primitive && @private_key.primitive == primitive end # Encrypts a message # # Encrypts the message with the given nonce to the keypair set up when # initializing the class. Make sure the nonce is unique for any given # keypair, or you might as well just send plain text. # # This function takes care of the padding required by the NaCL C API. # # @param nonce [String] A 24-byte string containing the nonce. # @param message [String] The message to be encrypted. # # @raise [RbNaCl::LengthError] If the nonce is not valid # # @return [String] The ciphertext without the nonce prepended (BINARY encoded) def box(nonce, message) Util.check_length(nonce, nonce_bytes, "Nonce") msg = Util.prepend_zeros(ZEROBYTES, message) ct = Util.zeros(msg.bytesize) success = self.class.box_curve25519xsalsa20poly1305_afternm(ct, msg, msg.bytesize, nonce, beforenm) raise CryptoError, "Encryption failed" unless success Util.remove_zeros(BOXZEROBYTES, ct) end alias encrypt box # Decrypts a ciphertext # # Decrypts the ciphertext with the given nonce using the keypair setup when # initializing the class. # # This function takes care of the padding required by the NaCL C API. # # @param nonce [String] A 24-byte string containing the nonce. # @param ciphertext [String] The message to be decrypted. # # @raise [RbNaCl::LengthError] If the nonce is not valid # @raise [RbNaCl::CryptoError] If the ciphertext cannot be authenticated. # # @return [String] The decrypted message (BINARY encoded) def open(nonce, ciphertext) Util.check_length(nonce, nonce_bytes, "Nonce") ct = Util.prepend_zeros(BOXZEROBYTES, ciphertext) message = Util.zeros(ct.bytesize) success = self.class.box_curve25519xsalsa20poly1305_open_afternm(message, ct, ct.bytesize, nonce, beforenm) raise CryptoError, "Decryption failed. Ciphertext failed verification." unless success Util.remove_zeros(ZEROBYTES, message) end alias decrypt open # The crypto primitive for the box class # # @return [Symbol] The primitive used def primitive self.class.primitive end # The nonce bytes for the box class # # @return [Integer] The number of bytes in a valid nonce def self.nonce_bytes NONCEBYTES end # The nonce bytes for the box instance # # @return [Integer] The number of bytes in a valid nonce def nonce_bytes NONCEBYTES end private def beforenm @beforenm ||= begin key = Util.zeros(BEFORENMBYTES) success = self.class.box_curve25519xsalsa20poly1305_beforenm(key, @public_key.to_s, @private_key.to_s) raise CryptoError, "Failed to derive shared key" unless success key end end end end end rbnacl-7.1.2/lib/rbnacl/boxes/curve25519xsalsa20poly1305/000077500000000000000000000000001470351605300224425ustar00rootroot00000000000000rbnacl-7.1.2/lib/rbnacl/boxes/curve25519xsalsa20poly1305/private_key.rb000066400000000000000000000054231470351605300253150ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module Boxes class Curve25519XSalsa20Poly1305 # RbNaCl::Box private key. Keep it safe # # This class generates and stores NaCL private keys, as well as providing a # reference to the public key associated with this private key, if that's # provided. # # Note that the documentation for NaCl refers to this as a secret key, but in # this library its a private key, to avoid confusing the issue with the # SecretBox, which does symmetric encryption. class PrivateKey include KeyComparator include Serializable extend Sodium sodium_type :box sodium_primitive :curve25519xsalsa20poly1305 sodium_function :box_curve25519xsalsa20poly1305_keypair, :crypto_box_curve25519xsalsa20poly1305_keypair, %i[pointer pointer] # The size of the key, in bytes BYTES = Boxes::Curve25519XSalsa20Poly1305::PRIVATEKEYBYTES # Initializes a new PrivateKey for key operations. # # Takes the (optionally encoded) private key bytes. This class can then be # used for various key operations, including deriving the corresponding # PublicKey # # @param private_key [String] The private key # # @raise [TypeError] If the key is nil # @raise [RbNaCl::LengthError] If the key is not valid after decoding. # # @return A new PrivateKey def initialize(private_key) @private_key = Util.check_string(private_key, BYTES, "Private key") end # Generates a new keypair # # @raise [RbNaCl::CryptoError] if key generation fails, due to insufficient randomness. # # @return [RbNaCl::PrivateKey] A new private key, with the associated public key also set. def self.generate pk = Util.zeros(Boxes::Curve25519XSalsa20Poly1305::PUBLICKEYBYTES) sk = Util.zeros(Boxes::Curve25519XSalsa20Poly1305::PRIVATEKEYBYTES) box_curve25519xsalsa20poly1305_keypair(pk, sk) || raise(CryptoError, "Failed to generate a key pair") new(sk) end # The raw bytes of the key # # @return [String] the raw bytes. def to_bytes @private_key end # the public key associated with this private key # # @return [PublicKey] the key def public_key @public_key ||= PublicKey.new GroupElements::Curve25519.base.mult(to_bytes) end # The crypto primitive this PrivateKey is to be used for. # # @return [Symbol] The primitive def primitive self.class.primitive end end end end end rbnacl-7.1.2/lib/rbnacl/boxes/curve25519xsalsa20poly1305/public_key.rb000066400000000000000000000031711470351605300251170ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module Boxes class Curve25519XSalsa20Poly1305 # RbNaCl::Box public key. Send it (securely!) to your friends. # # This class stores the NaCL public key, and provides some convenience # functions for working with it. class PublicKey include KeyComparator include Serializable # The size of the key, in bytes BYTES = Boxes::Curve25519XSalsa20Poly1305::PUBLICKEYBYTES # Initializes a new PublicKey for key operations. # # Takes the (optionally encoded) public key bytes. This can be shared with # many people and used to establish key pairs with their private key, for # the exchanging of messages using a RbNaCl::Box # # @param public_key [String] The public key # # @raise [RbNaCl::LengthError] If the key is not valid after decoding. # # @return A new PublicKey def initialize(public_key) @public_key = Util.check_string(public_key, BYTES, "Public key") end # The raw bytes of the key # # @return [String] the raw bytes. def to_bytes @public_key end # The crypto primitive the PublicKey class is to be used for # # @return [Symbol] The primitive def self.primitive :curve25519xsalsa20poly1305 end # The crypto primitive this PublicKey is to be used for. # # @return [Symbol] The primitive def primitive self.class.primitive end end end end end rbnacl-7.1.2/lib/rbnacl/boxes/sealed.rb000066400000000000000000000112651470351605300177040ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module Boxes # Sealed boxes are designed to anonymously send messages to a recipient # given its public key. # # Only the recipient can decrypt these messages, using its private key. # While the recipient can verify the integrity of the message, it cannot # verify the identity of the sender. # # A message is encrypted using an ephemeral key pair, whose secret part # is destroyed right after the encryption process. # # Without knowing the secret key used for a given message, the sender # cannot decrypt its own message later. And without additional data, # a message cannot be correlated with the identity of its sender. class Sealed extend Sodium sodium_type :box sodium_constant :SEALBYTES sodium_primitive :curve25519xsalsa20poly1305 sodium_function :box_seal, :crypto_box_seal, %i[pointer pointer ulong_long pointer] sodium_function :box_seal_open, :crypto_box_seal_open, %i[pointer pointer ulong_long pointer pointer] # WARNING: you should strongly prefer the from_private_key/from_public_key class methods. # # Create a new Sealed Box # # Sets up the Box for deriving the shared key and encrypting and # decrypting messages. # # @param public_key [String,RbNaCl::PublicKey] The public key to encrypt to # @param private_key [String,RbNaCl::PrivateKey] The private key to decrypt with # # @raise [RbNaCl::LengthError] on invalid keys # # @return [RbNaCl::SealedBox] The new Box, ready to use def initialize(public_key, private_key = nil) unless private_key.nil? @private_key = private_key.is_a?(PrivateKey) ? private_key : PrivateKey.new(private_key) raise IncorrectPrimitiveError unless @private_key.primitive == primitive public_key = @private_key.public_key if public_key.nil? end @public_key = public_key.is_a?(PublicKey) ? public_key : PublicKey.new(public_key) raise IncorrectPrimitiveError unless @public_key.primitive == primitive end # Create a new Sealed Box for decrypting # # Sets up the Box for decryption of new messages. # # @param private_key [String,RbNaCl::PrivateKey] The private key to decrypt with # # @raise [RbNaCl::LengthError] on invalid keys # # @return [RbNaCl::SealedBox] The new Box, ready to use def self.from_private_key(private_key) new(nil, private_key) end # Create a new Sealed Box for encrypting # # Sets up the Box for encryption of new messages. # # @param public_key [String,RbNaCl::PublicKey] The public key to encrypt to # # @raise [RbNaCl::LengthError] on invalid keys # # @return [RbNaCl::SealedBox] The new Box, ready to use def self.from_public_key(public_key) new(public_key, nil) end # Encrypts a message # # @param message [String] The message to be encrypted. # # @raise [RbNaCl::CryptoError] If the encrytion fails. # # @return [String] The ciphertext (BINARY encoded) def box(message) # No padding needed. msg = message # variable name to match other RbNaCl code. # ensure enough space in result ct = Util.zeros(msg.bytesize + SEALBYTES) success = self.class.box_seal(ct, msg, msg.bytesize, @public_key.to_s) raise CryptoError, "Encryption failed" unless success ct end alias encrypt box # Decrypts a ciphertext # # @param ciphertext [String] The message to be decrypted. # # @raise [RbNaCl::CryptoError] If no private key is available. # @raise [RbNaCl::CryptoError] If the ciphertext cannot be authenticated. # # @return [String] The decrypted message (BINARY encoded) def open(ciphertext) raise CryptoError, "Decryption failed. No private key." unless @private_key ct = ciphertext raise CryptoError, "Decryption failed. Ciphertext failed verification." if ct.bytesize < SEALBYTES message = Util.zeros(ct.bytesize - SEALBYTES) success = self.class.box_seal_open(message, ct, ct.bytesize, @public_key.to_s, @private_key.to_s) raise CryptoError, "Decryption failed. Ciphertext failed verification." unless success message end alias decrypt open # The crypto primitive for the box class # # @return [Symbol] The primitive used def primitive self.class.primitive end end end end rbnacl-7.1.2/lib/rbnacl/group_elements/000077500000000000000000000000001470351605300200255ustar00rootroot00000000000000rbnacl-7.1.2/lib/rbnacl/group_elements/curve25519.rb000066400000000000000000000063171470351605300221130ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module GroupElements # Points provide the interface to NaCl's Curve25519 high-speed elliptic # curve cryptography, which can be used for implementing Diffie-Hellman # and other forms of public key cryptography (e.g. RbNaCl::Box) # # Objects of the Point class represent points on Edwards curves. NaCl # defines a base point (the "standard group element") which we can # multiply by an arbitrary integer. This is how NaCl computes public # keys from private keys. class Curve25519 # NaCl's Curve25519 base point (a.k.a. standard group element), serialized as hex STANDARD_GROUP_ELEMENT = ["0900000000000000000000000000000000000000000000000000000000000000"].pack("H*").freeze # Order of the standard group STANDARD_GROUP_ORDER = 2**252 + 27_742_317_777_372_353_535_851_937_790_883_648_493 # Degenerate key (all-zeroes, results in an all-zero shared secret) DEGENERATE_KEY = "\0" * 32 include KeyComparator include Serializable extend Sodium sodium_type :scalarmult sodium_primitive :curve25519 sodium_function :scalarmult_curve25519, :crypto_scalarmult_curve25519, %i[pointer pointer pointer] # Number of bytes in a scalar on this curve SCALARBYTES = 32 BYTES = 32 # Number of bytes in a scalar on this curve # Creates a new Point from the given serialization # # @param [String] point location of a group element (32-bytes) # # @return [RbNaCl::Point] the Point at this location def initialize(point) @point = point.to_str raise CryptoError, "degenerate key detected" if @point == DEGENERATE_KEY # FIXME: really should have a separate constant here for group element size # Group elements and scalars are both 32-bits, but that's for convenience Util.check_length(@point, SCALARBYTES, "group element") end # Multiply the given integer by this point # This ordering is a bit confusing because traditionally the point # would be the right-hand operand. # # @param [String] integer value to multiply with this Point (32-bytes) # # @return [RbNaCl::Point] result as a Point object def mult(integer) integer = integer.to_str Util.check_length(integer, SCALARBYTES, "integer") result = Util.zeros(SCALARBYTES) raise CryptoError, "degenerate key detected" unless self.class.scalarmult_curve25519(result, integer, @point) self.class.new(result) end # Return the point serialized as bytes # # @return [String] 32-byte string representing this point def to_bytes @point end @base_point = new(STANDARD_GROUP_ELEMENT) # NaCl's standard base point for all Curve25519 public keys # # @return [RbNaCl::Point] standard base point (a.k.a. standard group element) def self.base # TODO: better support fixed-based scalar multiplication (this glosses over native support) @base_point end class << self attr_reader :base_point end end end end rbnacl-7.1.2/lib/rbnacl/hash.rb000066400000000000000000000053401470351605300162470ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl # Cryptographic hash functions # # Cryptographic hash functions take a variable length message and compute a # fixed length string, the message digest. Even a small change in the input # data should produce a large change in the digest, and it is 'very difficult' # to create two messages with the same digest. # # A cryptographic hash can be used for checking the integrity of data, but # there is no secret involved in the hashing, so anyone can create the hash of # a given message. # # RbNaCl provides the SHA-256,SHA-512 as well as the Blake2b hash functions. module Hash # Returns the SHA-256 hash of the given data # # There's no streaming done, just pass in the data and be done with it. # # @param [#to_str] data The data, as a collection of bytes # # @raise [CryptoError] If the hashing fails for some reason. # # @return [String] The SHA-256 hash digest as raw bytes def self.sha256(data) data = data.to_str digest = Util.zeros(SHA256::BYTES) SHA256.hash_sha256(digest, data, data.bytesize) || raise(CryptoError, "Hashing failed!") digest end # Returns the SHA-512 hash of the given data # # There's no streaming done, just pass in the data and be done with it. # # @param [#to_str] data The data, as a collection of bytes # # @raise [CryptoError] If the hashing fails for some reason. # # @return [String] The SHA-512 hash digest as raw bytes def self.sha512(data) digest = Util.zeros(SHA512::BYTES) SHA512.hash_sha512(digest, data, data.bytesize) || raise(CryptoError, "Hashing failed!") digest end # Returns the Blake2b hash of the given data # # There's no streaming done, just pass in the data and be done with it. # This method returns a 64-byte hash by default. # # @param [String] data The data, as a collection of bytes # @option options [Fixnum] digest_size Size in bytes (1-64, default 64) # @option options [String] key 64-byte (or less) key for keyed mode # @option options [String] salt Provide a salt to support randomised hashing. # This is mixed into the parameters block to start the hashing. # @option options [Personal] personal Provide personalisation string to allow pinning a hash for a particular purpose. # This is mixed into the parameters block to start the hashing # # @raise [CryptoError] If the hashing fails for some reason. # # @return [String] The Blake2b hash digest as raw bytes def self.blake2b(data, options = {}) Blake2b.digest(data, options) end end end rbnacl-7.1.2/lib/rbnacl/hash/000077500000000000000000000000001470351605300157205ustar00rootroot00000000000000rbnacl-7.1.2/lib/rbnacl/hash/blake2b.rb000066400000000000000000000162601470351605300175540ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module Hash # The Blake2b hash function # # Blake2b is based on Blake, a SHA3 finalist which was snubbed in favor of # Keccak, a much slower hash function but one sufficiently different from # SHA2 to let the SHA3 judges panel sleep easy. Back in the real world, # it'd be great if we can calculate hashes quickly if possible. # # Blake2b provides for up to 64-bit digests and also supports a keyed mode # similar to HMAC class Blake2b extend Sodium sodium_type :generichash sodium_primitive :blake2b sodium_constant :BYTES_MIN sodium_constant :BYTES_MAX sodium_constant :KEYBYTES_MIN sodium_constant :KEYBYTES_MAX sodium_constant :SALTBYTES sodium_constant :PERSONALBYTES sodium_function :generichash_blake2b, :crypto_generichash_blake2b_salt_personal, %i[pointer size_t pointer ulong_long pointer size_t pointer pointer] sodium_function :generichash_blake2b_init, :crypto_generichash_blake2b_init_salt_personal, %i[pointer pointer size_t size_t pointer pointer] sodium_function :generichash_blake2b_update, :crypto_generichash_blake2b_update, %i[pointer pointer ulong_long] sodium_function :generichash_blake2b_final, :crypto_generichash_blake2b_final, %i[pointer pointer size_t] EMPTY_PERSONAL = ("\0" * PERSONALBYTES).freeze EMPTY_SALT = ("\0" * SALTBYTES).freeze # Calculate a Blake2b digest # # @param [String] message Message to be hashed # @param [Hash] options Blake2b configuration # @option opts [String] :key for Blake2b keyed mode # @option opts [Integer] :digest_size size of output digest in bytes # @option opts [String] :salt Provide a salt to support randomised hashing. # This is mixed into the parameters block to start the hashing. # @option opts [Personal] :personal Provide personalisation string to allow pinning a hash for a particular purpose. # This is mixed into the parameters block to start the hashing # # @raise [RbNaCl::LengthError] Invalid length specified for one or more options # # @return [String] Blake2b digest of the string as raw bytes def self.digest(message, options) opts = validate_opts(options) digest = Util.zeros(opts[:digest_size]) generichash_blake2b(digest, opts[:digest_size], message, message.bytesize, opts[:key], opts[:key_size], opts[:salt], opts[:personal]) || raise(CryptoError, "Hashing failed!") digest end # Validate and sanitize values for Blake2b configuration # # @param [Hash] options Blake2b configuration # @option opts [String] :key for Blake2b keyed mode # @option opts [Integer] :digest_size size of output digest in bytes # @option opts [String] :salt Provide a salt to support randomised hashing. # This is mixed into the parameters block to start the hashing. # @option opts [Personal] :personal Provide personalisation string to allow pinning a hash for a particular purpose. # This is mixed into the parameters block to start the hashing # # @raise [RbNaCl::LengthError] Invalid length specified for one or more options # # @return [Hash] opts Configuration hash with sanitized values def self.validate_opts(opts) key = opts.fetch(:key, nil) if key key_size = key.bytesize raise LengthError, "key too short" if key_size < KEYBYTES_MIN raise LengthError, "key too long" if key_size > KEYBYTES_MAX else key_size = 0 end opts[:key_size] = key_size digest_size = opts.fetch(:digest_size, BYTES_MAX) raise LengthError, "digest size too short" if digest_size < BYTES_MIN raise LengthError, "digest size too long" if digest_size > BYTES_MAX opts[:digest_size] = digest_size personal = opts.fetch(:personal, EMPTY_PERSONAL) opts[:personal] = Util.zero_pad(PERSONALBYTES, personal) salt = opts.fetch(:salt, EMPTY_SALT) opts[:salt] = Util.zero_pad(SALTBYTES, salt) opts end private_class_method :validate_opts def self.new(opts = {}) opts = validate_opts(opts) super end # Create a new Blake2b hash object # # @param [Hash] opts Blake2b configuration # @option opts [String] :key for Blake2b keyed mode # @option opts [Integer] :digest_size size of output digest in bytes # @option opts [String] :salt Provide a salt to support randomised hashing. # This is mixed into the parameters block to start the hashing. # @option opts [Personal] :personal Provide personalisation string to allow pinning a hash for a particular purpose. # This is mixed into the parameters block to start the hashing # # @raise [RbNaCl::LengthError] Invalid length specified for one or more options # # @return [RbNaCl::Hash::Blake2b] A Blake2b hasher object def initialize(opts = {}) @key = opts[:key] @key_size = opts[:key_size] @digest_size = opts[:digest_size] @personal = opts[:personal] @salt = opts[:salt] @incycle = false @instate = nil end # Initialize state for Blake2b hash calculation, # this will be called automatically from #update if needed def reset @instate.release if @instate @instate = State.new self.class.generichash_blake2b_init(@instate.pointer, @key, @key_size, @digest_size, @salt, @personal) || raise(CryptoError, "Hash init failed!") @incycle = true @digest = nil end # Reentrant version of Blake2b digest calculation method # # @param [String] message Message to be hashed def update(message) reset unless @incycle self.class.generichash_blake2b_update(@instate.pointer, message, message.bytesize) || raise(CryptoError, "Hashing failed!") end alias << update # Finalize digest calculation, return cached digest if any # # @return [String] Blake2b digest of the string as raw bytes def digest raise(CryptoError, "No message to hash yet!") unless @incycle return @digest if @digest @digest = Util.zeros(@digest_size) self.class.generichash_blake2b_final(@instate.pointer, @digest, @digest_size) || raise(CryptoError, "Hash finalization failed!") @digest end # The crypto_generichash_blake2b_state struct representation # ref: jedisct1/libsodium/blob/c87df74c7b5969f4/src/libsodium/include/sodium/crypto_generichash_blake2b.h#L23-L25 class State < FFI::Struct layout :opaque, [:uint8, 384] end end end end rbnacl-7.1.2/lib/rbnacl/hash/sha256.rb000066400000000000000000000006341470351605300172600ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module Hash # Provides a binding for the SHA256 function in libsodium module SHA256 extend Sodium sodium_type :hash sodium_primitive :sha256 sodium_constant :BYTES sodium_function :hash_sha256, :crypto_hash_sha256, %i[pointer pointer ulong_long] end end end rbnacl-7.1.2/lib/rbnacl/hash/sha512.rb000066400000000000000000000006261470351605300172540ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module Hash # Provides the binding for the SHA512 hash function module SHA512 extend Sodium sodium_type :hash sodium_primitive :sha512 sodium_constant :BYTES sodium_function :hash_sha512, :crypto_hash_sha512, %i[pointer pointer ulong_long] end end end rbnacl-7.1.2/lib/rbnacl/hmac/000077500000000000000000000000001470351605300157055ustar00rootroot00000000000000rbnacl-7.1.2/lib/rbnacl/hmac/sha256.rb000066400000000000000000000070351470351605300172470ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module HMAC # Computes an authenticator as HMAC-SHA-256 # # The authenticator can be used at a later time to verify the provenance of # the message by recomputing the HMAC over the message and then comparing it to # the provided authenticator. The class provides methods for generating # signatures and also has a constant-time implementation for checking them. # # This is a secret key authenticator, i.e. anyone who can verify signatures # can also create them. # # @see http://nacl.cr.yp.to/auth.html class SHA256 < Auth extend Sodium sodium_type :auth sodium_primitive :hmacsha256 sodium_constant :BYTES sodium_constant :KEYBYTES sodium_function :auth_hmacsha256_init, :crypto_auth_hmacsha256_init, %i[pointer pointer size_t] sodium_function :auth_hmacsha256_update, :crypto_auth_hmacsha256_update, %i[pointer pointer ulong_long] sodium_function :auth_hmacsha256_final, :crypto_auth_hmacsha256_final, %i[pointer pointer] # Create instance without checking key length # # RFC 2104 HMAC # The key for HMAC can be of any length. # # see https://tools.ietf.org/html/rfc2104#section-3 def initialize(key) @key = Util.check_hmac_key(key, "#{self.class} key") @state = State.new @authenticator = Util.zeros(tag_bytes) self.class.auth_hmacsha256_init(@state, key, key.bytesize) end # Compute authenticator for message # # @params [#to_str] message message to construct an authenticator for def update(message) self.class.auth_hmacsha256_update(@state, message, message.bytesize) self.class.auth_hmacsha256_final(@state.clone, @authenticator) hexdigest end # Return the authenticator, as raw bytes # # @return [String] The authenticator, as raw bytes def digest @authenticator end # Return the authenticator, as hex string # # @return [String] The authenticator, as hex string def hexdigest @authenticator.unpack("H*").last end private def compute_authenticator(authenticator, message) state = State.new self.class.auth_hmacsha256_init(state, key, key.bytesize) self.class.auth_hmacsha256_update(state, message, message.bytesize) self.class.auth_hmacsha256_final(state, authenticator) end # libsodium crypto_auth_hmacsha256_verify works only for 32 byte keys # ref: https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_auth/hmacsha256/auth_hmacsha256.c#L109 def verify_message(authenticator, message) correct = Util.zeros(BYTES) compute_authenticator(correct, message) Util.verify32(correct, authenticator) end # The crypto_auth_hmacsha256_state struct representation # ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_auth_hmacsha256.h class SHA256State < FFI::Struct layout :state, [:uint32, 8], :count, :uint64, :buf, [:uint8, 64] end # The crypto_hash_sha256_state struct representation # ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_hash_sha256.h class State < FFI::Struct layout :ictx, SHA256State, :octx, SHA256State end end end end rbnacl-7.1.2/lib/rbnacl/hmac/sha512.rb000066400000000000000000000070431470351605300172410ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module HMAC # Computes an authenticator as HMAC-SHA-512 # # The authenticator can be used at a later time to verify the provenance of # the message by recomputing the HMAC over the message and then comparing it to # the provided authenticator. The class provides methods for generating # signatures and also has a constant-time implementation for checking them. # # This is a secret key authenticator, i.e. anyone who can verify signatures # can also create them. # # @see http://nacl.cr.yp.to/auth.html class SHA512 < Auth extend Sodium sodium_type :auth sodium_primitive :hmacsha512 sodium_constant :BYTES sodium_constant :KEYBYTES sodium_function :auth_hmacsha512_init, :crypto_auth_hmacsha512_init, %i[pointer pointer size_t] sodium_function :auth_hmacsha512_update, :crypto_auth_hmacsha512_update, %i[pointer pointer ulong_long] sodium_function :auth_hmacsha512_final, :crypto_auth_hmacsha512_final, %i[pointer pointer] # Create instance without checking key length # # RFC 2104 HMAC # The key for HMAC can be of any length. # # see https://tools.ietf.org/html/rfc2104#section-3 def initialize(key) @key = Util.check_hmac_key(key, "#{self.class} key") @state = State.new @authenticator = Util.zeros(tag_bytes) self.class.auth_hmacsha512_init(@state, key, key.bytesize) end # Compute authenticator for message # # @params [#to_str] message message to construct an authenticator for def update(message) self.class.auth_hmacsha512_update(@state, message, message.bytesize) self.class.auth_hmacsha512_final(@state.clone, @authenticator) hexdigest end # Return the authenticator, as raw bytes # # @return [String] The authenticator, as raw bytes def digest @authenticator end # Return the authenticator, as hex string # # @return [String] The authenticator, as hex string def hexdigest @authenticator.unpack("H*").last end private def compute_authenticator(authenticator, message) state = State.new self.class.auth_hmacsha512_init(state, key, key.bytesize) self.class.auth_hmacsha512_update(state, message, message.bytesize) self.class.auth_hmacsha512_final(state, authenticator) end # libsodium crypto_auth_hmacsha512_verify works only for 32 byte keys # ref: https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_auth/hmacsha512/auth_hmacsha512.c#L109 def verify_message(authenticator, message) correct = Util.zeros(BYTES) compute_authenticator(correct, message) Util.verify64(correct, authenticator) end # The crypto_auth_hmacsha512_state struct representation # ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_auth_hmacsha512.h class SHA512State < FFI::Struct layout :state, [:uint64, 8], :count, [:uint64, 2], :buf, [:uint8, 128] end # The crypto_hash_sha512_state struct representation # ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_hash_sha512.h class State < FFI::Struct layout :ictx, SHA512State, :octx, SHA512State end end end end rbnacl-7.1.2/lib/rbnacl/hmac/sha512256.rb000066400000000000000000000066531470351605300175040ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module HMAC # Computes an authenticator as HMAC-SHA-512 truncated to 256-bits # # The authenticator can be used at a later time to verify the provenance of # the message by recomputing the HMAC over the message and then comparing it to # the provided authenticator. The class provides methods for generating # signatures and also has a constant-time implementation for checking them. # # This is a secret key authenticator, i.e. anyone who can verify signatures # can also create them. # # @see http://nacl.cr.yp.to/auth.html class SHA512256 < Auth extend Sodium sodium_type :auth sodium_primitive :hmacsha512256 sodium_constant :BYTES sodium_constant :KEYBYTES sodium_function :auth_hmacsha512256_init, :crypto_auth_hmacsha512256_init, %i[pointer pointer size_t] sodium_function :auth_hmacsha512256_update, :crypto_auth_hmacsha512256_update, %i[pointer pointer ulong_long] sodium_function :auth_hmacsha512256_final, :crypto_auth_hmacsha512256_final, %i[pointer pointer] # Create instance without checking key length # # RFC 2104 HMAC # The key for HMAC can be of any length. # # see https://tools.ietf.org/html/rfc2104#section-3 def initialize(key) @key = Util.check_hmac_key(key, "#{self.class} key") @state = State.new @authenticator = Util.zeros(tag_bytes) self.class.auth_hmacsha512256_init(@state, key, key.bytesize) end # Compute authenticator for message # # @params [#to_str] message message to construct an authenticator for def update(message) self.class.auth_hmacsha512256_update(@state, message, message.bytesize) self.class.auth_hmacsha512256_final(@state.clone, @authenticator) hexdigest end # Return the authenticator, as raw bytes # # @return [String] The authenticator, as raw bytes def digest @authenticator end # Return the authenticator, as hex string # # @return [String] The authenticator, as hex string def hexdigest @authenticator.unpack("H*").last end private def compute_authenticator(authenticator, message) state = State.new self.class.auth_hmacsha512256_init(state, key, key.bytesize) self.class.auth_hmacsha512256_update(state, message, message.bytesize) self.class.auth_hmacsha512256_final(state, authenticator) end def verify_message(authenticator, message) correct = Util.zeros(BYTES) compute_authenticator(correct, message) Util.verify32(correct, authenticator) end # The crypto_auth_hmacsha512256_state struct representation # ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_auth_hmacsha512256.h class SHA512256State < FFI::Struct layout :state, [:uint64, 8], :count, [:uint64, 2], :buf, [:uint8, 128] end # The crypto_hash_sha512_state struct representation # ref: jedisct1/libsodium/src/libsodium/include/sodium/crypto_hash_sha512.h class State < FFI::Struct layout :ictx, SHA512256State, :octx, SHA512256State end end end end rbnacl-7.1.2/lib/rbnacl/init.rb000066400000000000000000000004241470351605300162650ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl # Defines the libsodium init function module Init extend FFI::Library ffi_lib ["sodium", "libsodium.so.18", "libsodium.so.23", "libsodium.so.26"] attach_function :sodium_init, [], :int end end rbnacl-7.1.2/lib/rbnacl/key_comparator.rb000066400000000000000000000034151470351605300203440ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl # Implements comparisons of keys # # This permits both timing invariant equality tests, as well as # lexicographical sorting. module KeyComparator include Comparable # spaceship operator # # @param other [KeyComparator,#to_str] The thing to compare # # @return [0] if the keys are equal # @return [1] if the key is larger than the other key # @return [-1] if the key is smaller than the other key # @return [nil] if comparison doesn't make sense def <=>(other) if KeyComparator > other.class other = other.to_bytes elsif other.respond_to?(:to_str) other = other.to_str else return nil end compare32(other) end # equality operator # # The equality operator is explicity defined, despite including Comparable # and having a spaceship operator, so that if equality tests are desired, # they can be timing invariant, without any chance that the further # comparisons for greater than and less than can leak information. Maybe # this is too paranoid, but I don't know how ruby works under the hood with # comparable. # # @param other [KeyComparator,#to_str] The thing to compare # # @return [true] if the keys are equal # @return [false] if they keys are not equal def ==(other) if KeyComparator > other.class other = other.to_bytes elsif other.respond_to?(:to_str) other = other.to_str else return false end Util.verify32(to_bytes, other) end private def compare32(other) if Util.verify32(to_bytes, other) 0 elsif to_bytes > other 1 else -1 end end end end rbnacl-7.1.2/lib/rbnacl/one_time_auths/000077500000000000000000000000001470351605300200005ustar00rootroot00000000000000rbnacl-7.1.2/lib/rbnacl/one_time_auths/poly1305.rb000066400000000000000000000032731470351605300216260ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module OneTimeAuths # Computes an authenticator using poly1305 # # The authenticator can be used at a later time to verify the provenance of # the message by recomputing the tag over the message and then comparing it to # the provided authenticator. The class provides methods for generating # signatures and also has a constant-time implementation for checking them. # # As the name suggests, this is a **ONE TIME** authenticator. Computing an # authenticator for two messages using the same key probably gives an # attacker enough information to forge further authenticators for the same # key. # # This is a secret key authenticator, i.e. anyone who can verify signatures # can also create them. # # @see http://nacl.cr.yp.to/onetimeauth.html class Poly1305 < Auth extend Sodium sodium_type :onetimeauth sodium_primitive :poly1305 sodium_constant :BYTES sodium_constant :KEYBYTES sodium_function :onetimeauth_poly1305, :crypto_onetimeauth_poly1305, %i[pointer pointer ulong_long pointer] sodium_function :onetimeauth_poly1305_verify, :crypto_onetimeauth_poly1305_verify, %i[pointer pointer ulong_long pointer] private def compute_authenticator(authenticator, message) self.class.onetimeauth_poly1305(authenticator, message, message.bytesize, key) end def verify_message(authenticator, message) self.class.onetimeauth_poly1305_verify(authenticator, message, message.bytesize, key) end end end end rbnacl-7.1.2/lib/rbnacl/password_hash.rb000066400000000000000000000114511470351605300201710ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl # Password hashing functions # # These hash functions are designed specifically for the purposes of securely # storing passwords in a way that they can be checked against a supplied # password but an attacker who obtains a hash cannot easily reverse them back # into the original password. # # Unlike normal hash functions, which are intentionally designed to hash data # as quickly as they can while remaining secure, password hashing functions # are intentionally designed to be slow so they are hard for attackers to # brute force. # # All password hashing functions take a "salt" value which should be randomly # generated on a per-password basis (using RbNaCl::Random, accept no # substitutes) # # All of them also take a CPU work factor, which increases the amount of # computation needed to produce the digest. module PasswordHash # scrypt: the original sequential memory-hard password hashing function. # # @param [String] password to be hashed # @param [String] salt to make the digest unique # @param [Integer] opslimit the CPU cost (e.g. 2**20) # @param [Integer] memlimit the memory cost (e.g. 2**24) # @param [Integer] digest_size of the output # # @raise [CryptoError] If calculating the digest fails for some reason. # # @return [String] The scrypt digest as raw bytes def self.scrypt(password, salt, opslimit = SCrypt::OPSLIMIT_SENSITIVE, memlimit = SCrypt::MEMLIMIT_SENSITIVE, digest_size = 64) SCrypt.new(opslimit, memlimit, digest_size).digest(password, salt) end # argon2: state of the art in the design of memory-hard hashing functions # (default digest algorithm). # # @param [String] password to be hashed # @param [String] salt to make the digest unique # @param [Integer] opslimit the CPU cost (3..10) # @param [Integer] memlimit the memory cost, in bytes # @param [Integer] digest_size of the output # # @raise [CryptoError] If calculating the digest fails for some reason. # # @return [String] The argon2 digest as raw bytes def self.argon2(password, salt, opslimit, memlimit, digest_size = 64) argon2_supported? && Argon2.new(opslimit, memlimit, digest_size).digest(password, salt) end # argon2i: argon2, using argon2i digest algorithm. # # @param [String] password to be hashed # @param [String] salt to make the digest unique # @param [Integer] opslimit the CPU cost (3..10) # @param [Integer] memlimit the memory cost, in bytes # @param [Integer] digest_size of the output # # @raise [CryptoError] If calculating the digest fails for some reason. # # @return [String] The argon2i digest as raw bytes def self.argon2i(password, salt, opslimit, memlimit, digest_size = 64) argon2_supported? && Argon2.new(opslimit, memlimit, digest_size).digest(password, salt, :argon2i) end # argon2id: argon2, using argon2id digest algorithm. # # @param [String] password to be hashed # @param [String] salt to make the digest unique # @param [Integer] opslimit the CPU cost (3..10) # @param [Integer] memlimit the memory cost, in bytes # @param [Integer] digest_size of the output # # @raise [CryptoError] If calculating the digest fails for some reason. # # @return [String] The argon2id digest as raw bytes def self.argon2id(password, salt, opslimit, memlimit, digest_size = 64) argon2_supported? && Argon2.new(opslimit, memlimit, digest_size).digest(password, salt, :argon2id) end # argon2_str: crypt-style password digest # # @param [String] password to be hashed # @param [Integer] opslimit the CPU cost (3..10) # @param [Integer] memlimit the memory cost, in bytes # # @raise [CryptoError] If calculating the digest fails for some reason. # # @return [String] The argon2i digest as crypt-style string def self.argon2_str(password, opslimit = :interactive, memlimit = :interactive) argon2_supported? && Argon2.new(opslimit, memlimit).digest_str(password) end # argon2_valid?: verify crypt-style password digest # # @param [String] password to verify # @param [String] str_digest to verify # # @return [Boolean] true if digest was created using password def self.argon2_valid?(password, str_digest) argon2_supported? && Argon2.digest_str_verify(password, str_digest) end class << self protected def argon2_supported? if RbNaCl::Sodium::Version::ARGON2_SUPPORTED true else raise NotImplementedError, "argon2 requires libsodium version >= 1.0.9" \ " (currently running #{RbNaCl::Sodium::Version::STRING})" end end end end end rbnacl-7.1.2/lib/rbnacl/password_hash/000077500000000000000000000000001470351605300176425ustar00rootroot00000000000000rbnacl-7.1.2/lib/rbnacl/password_hash/argon2.rb000066400000000000000000000212061470351605300213600ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module PasswordHash # Since version 1.0.9, Sodium provides a password hashing scheme called # Argon2. Argon2 summarizes the state of the art in the design of memory- # hard functions. It aims at the highest memory filling rate and effective # use of multiple computing units, while still providing defense against # tradeoff attacks. It prevents ASICs from having a significant advantage # over software implementations. class Argon2 extend Sodium sodium_type :pwhash sodium_constant :ALG_DEFAULT sodium_constant :ALG_ARGON2I13 sodium_constant :ALG_ARGON2ID13 if Sodium::Version::ARGON2ID_SUPPORTED sodium_constant :SALTBYTES, fallback: 16 sodium_constant :STRBYTES, fallback: 128 sodium_constant :OPSLIMIT_INTERACTIVE, fallback: 4 sodium_constant :MEMLIMIT_INTERACTIVE, fallback: 2**25 # (32mb) sodium_constant :OPSLIMIT_MODERATE, fallback: 6 sodium_constant :MEMLIMIT_MODERATE, fallback: 2**27 # (128mb) sodium_constant :OPSLIMIT_SENSITIVE, fallback: 8 sodium_constant :MEMLIMIT_SENSITIVE, fallback: 2**29 # (512mb) sodium_constant :MEMLIMIT_MIN, fallback: 8192 sodium_constant :MEMLIMIT_MAX, fallback: 4_294_967_296 sodium_constant :OPSLIMIT_MIN, fallback: 3 sodium_constant :OPSLIMIT_MAX, fallback: 10 ARGON2_MIN_OUTLEN = 16 ARGON2_MAX_OUTLEN = 0xFFFFFFFF sodium_function_with_return_code( :pwhash, :crypto_pwhash, %i[pointer ulong_long pointer ulong_long pointer ulong_long size_t int] ) sodium_function( :pwhash_str, :crypto_pwhash_str, %i[pointer pointer ulong_long ulong_long size_t] ) sodium_function( :pwhash_str_verify, :crypto_pwhash_str_verify, %i[pointer pointer ulong_long] ) ARGON_ERROR_CODES = { -1 => "ARGON2_OUTPUT_PTR_NULL", -2 => "ARGON2_OUTPUT_TOO_SHORT", -3 => "ARGON2_OUTPUT_TOO_LONG", -4 => "ARGON2_PWD_TOO_SHORT", -5 => "ARGON2_PWD_TOO_LONG", -6 => "ARGON2_SALT_TOO_SHORT", -7 => "ARGON2_SALT_TOO_LONG", -8 => "ARGON2_AD_TOO_SHORT", -9 => "ARGON2_AD_TOO_LONG", -10 => "ARGON2_SECRET_TOO_SHORT", -11 => "ARGON2_SECRET_TOO_LONG", -12 => "ARGON2_TIME_TOO_SMALL", -13 => "ARGON2_TIME_TOO_LARGE", -14 => "ARGON2_MEMORY_TOO_LITTLE", -15 => "ARGON2_MEMORY_TOO_MUCH", -16 => "ARGON2_LANES_TOO_FEW", -17 => "ARGON2_LANES_TOO_MANY", -18 => "ARGON2_PWD_PTR_MISMATCH", -19 => "ARGON2_SALT_PTR_MISMATCH", -20 => "ARGON2_SECRET_PTR_MISMATCH", -21 => "ARGON2_AD_PTR_MISMATCH", -22 => "ARGON2_MEMORY_ALLOCATION_ERROR", -23 => "ARGON2_FREE_MEMORY_CBK_NULL", -24 => "ARGON2_ALLOCATE_MEMORY_CBK_NULL", -25 => "ARGON2_INCORRECT_PARAMETER", -26 => "ARGON2_INCORRECT_TYPE", -27 => "ARGON2_OUT_PTR_MISMATCH", -28 => "ARGON2_THREADS_TOO_FEW", -29 => "ARGON2_THREADS_TOO_MANY", -30 => "ARGON2_MISSING_ARGS", -31 => "ARGON2_ENCODING_FAIL", -32 => "ARGON2_DECODING_FAIL", -33 => "ARGON2_THREAD_FAIL", -34 => "ARGON2_DECODING_LENGTH_FAIL", -35 => "ARGON2_VERIFY_MISMATCH" }.freeze # Create a new Argon2 password hash object # # opslimit and memlimit may be an integer, or one of the following # symbols: # # [:interactive] Suitable for interactive online operations. This # requires 32 Mb of dedicated RAM. # [:moderate] A compromise between interactive and sensitive. This # requires 128 Mb of dedicated RAM, and takes about 0.7 # seconds on a 2.8 Ghz Core i7 CPU. # [:sensitive] For highly sensitive and non-interactive operations. This # requires 128 Mb of dedicated RAM, and takes about 0.7 # seconds on a 2.8 Ghz Core i7 CPU # # @param [Integer] opslimit the CPU cost (1..10) # @param [Integer] memlimit the memory cost (e.g. 2**24) # @param [Integer] digest_size the byte length of the resulting digest # # @return [RbNaCl::PasswordHash::Argon2] An Argon2 password hasher object def initialize(opslimit, memlimit, digest_size = nil) @opslimit = self.class.opslimit_value(opslimit) @memlimit = self.class.memlimit_value(memlimit) @digest_size = self.class.digest_size_value(digest_size) if digest_size end # Calculate an Argon2 digest for a given password and salt # # @param [String] password to be hashed # @param [String] salt to make the digest unique # @param [Symbol] digest algorithm to use (may be :argon2i or :argon2id) # if nil, the default is determined by libsodium # (argon2i for libsodium < 1.0.15, and argon2id for # libsodium >= 1.0.15). # # @return [String] scrypt digest of the string as raw bytes def digest(password, salt, algo = nil) raise ArgumentError, "digest_size is required" unless @digest_size digest = Util.zeros(@digest_size) salt = Util.check_string(salt, SALTBYTES, "salt") if algo.nil? algorithm = ALG_DEFAULT elsif algo == :argon2i algorithm = ALG_ARGON2I13 elsif algo == :argon2id && Sodium::Version::ARGON2ID_SUPPORTED algorithm = ALG_ARGON2ID13 else raise ArgumentError, "digest algorithm is not supported" end status = self.class.pwhash( digest, @digest_size, password, password.bytesize, salt, @opslimit, @memlimit, algorithm ) raise CryptoError, ARGON_ERROR_CODES[status] if status.nonzero? digest end # Calculate an Argon2 digest in the form of a crypt-style string. # The resulting string encodes the parameters and salt. # # @param [String] password to be hashed # # @return [String] argon2 digest string def digest_str(password) raise ArgumentError, "password must be a String" unless password.is_a?(String) result = Util.zeros(STRBYTES) ok = self.class.pwhash_str( result, password, password.bytesize, @opslimit, @memlimit ) raise CryptoError, "unknown error in Argon2#digest_str" unless ok result.delete("\x00") end # Compares a password with a digest string # # @param [String] password to be hashed # @param [String] digest_string to compare to # # @return [boolean] true if password matches digest_string def self.digest_str_verify(password, digest_string) raise ArgumentError, "password must be a String" unless password.is_a?(String) raise ArgumentError, "digest_string must be a String" unless digest_string.is_a?(String) pwhash_str_verify( digest_string, password, password.bytesize ) end # Clamps opslimit to an acceptable range (3..10) # # @param [Integer] opslimit value to be checked # # @raise [ArgumentError] if the value is out of range # # @return [Integer] opslimit a valid value for opslimit def self.opslimit_value(opslimit) case opslimit when :interactive then OPSLIMIT_INTERACTIVE when :moderate then OPSLIMIT_MODERATE when :sensitive then OPSLIMIT_SENSITIVE when OPSLIMIT_MIN..OPSLIMIT_MAX then opslimit.to_i else raise ArgumentError, "opslimit must be within the range 3..10" end end # Clamps memlimit between 8192 bytes and 4 TB (eg. 2**32) # # @param [Integer] memlimit, in bytes # # @raise [ArgumentError] if the value is out of range # # @return [Integer] memlimit a valid value for memlimit def self.memlimit_value(memlimit) case memlimit when :interactive then MEMLIMIT_INTERACTIVE when :moderate then MEMLIMIT_MODERATE when :sensitive then MEMLIMIT_SENSITIVE when MEMLIMIT_MIN..MEMLIMIT_MAX then memlimit.to_i else raise ArgumentError, "memlimit must be within the range 2**(13..32)" end end # Clamps digest size between 16..4294967295 # # @raise [LengthError] if the value is out of range # # @return [Integer] digest_size a valid value for digest size def self.digest_size_value(digest_size) digest_size = digest_size.to_i raise LengthError, "digest size too short" if digest_size < ARGON2_MIN_OUTLEN raise LengthError, "digest size too long" if digest_size > ARGON2_MAX_OUTLEN digest_size end end end end rbnacl-7.1.2/lib/rbnacl/password_hash/scrypt.rb000066400000000000000000000051271470351605300215200ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module PasswordHash # The scrypt sequential memory hard password hashing function # # scrypt is a password hash (or password based KDF). That is to say, where # most hash functions are designed to be fast because hashing is often a # bottleneck, scrypt is slow by design, because it's trying to "strengthen" # the password by combining it with a random "salt" value then perform a # series of operation on the result which are slow enough to defeat # brute-force password cracking attempts. # # scrypt is similar to the bcrypt and pbkdf2 password hashes in that it's # designed to strengthen passwords, but includes a new design element # called "sequential memory hardness" which helps defeat attempts by # attackers to compensate for their lack of memory (since they're typically # on GPUs or FPGAs) with additional computation. class SCrypt extend Sodium sodium_type :pwhash sodium_primitive :scryptsalsa208sha256 sodium_constant :SALTBYTES sodium_constant :OPSLIMIT_SENSITIVE sodium_constant :MEMLIMIT_SENSITIVE sodium_function :scrypt, :crypto_pwhash_scryptsalsa208sha256, %i[pointer ulong_long pointer ulong_long pointer ulong_long size_t] # Create a new SCrypt password hash object # # @param [Integer] opslimit the CPU cost (e.g. 2**20) # @param [Integer] memlimit the memory cost (e.g. 2**24) # # @return [RbNaCl::PasswordHash::SCrypt] An SCrypt password hasher object def initialize(opslimit, memlimit, digest_size = 64) # TODO: sanity check these parameters @opslimit = opslimit @memlimit = memlimit # TODO: check digest size validity # raise LengthError, "digest size too short" if @digest_size < BYTES_MIN # raise LengthError, "digest size too long" if @digest_size > BYTES_MAX @digest_size = digest_size end # Calculate an scrypt digest for a given password and salt # # @param [String] password to be hashed # @param [String] salt to make the digest unique # # @return [String] scrypt digest of the string as raw bytes def digest(password, salt) digest = Util.zeros(@digest_size) salt = Util.check_string(salt, SALTBYTES, "salt") success = self.class.scrypt(digest, @digest_size, password, password.bytesize, salt, @opslimit, @memlimit) raise CryptoError, "scrypt failed!" unless success digest end end end end rbnacl-7.1.2/lib/rbnacl/random.rb000066400000000000000000000013351470351605300166040ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl # Functions for random number generation # # This uses the underlying source of random number generation on the OS, so # /dev/urandom on UNIX-like systems, and the MS crypto providor on windows. module Random extend Sodium @mutex = Mutex.new sodium_function :c_random_bytes, :randombytes_buf, %i[pointer size_t] # Returns a string of random bytes # # @param [Integer] n number of random bytes desired # # @return [String] random bytes. def self.random_bytes(n = 32) buf = RbNaCl::Util.zeros(n) @mutex.synchronize { c_random_bytes(buf, n) } buf end end end rbnacl-7.1.2/lib/rbnacl/secret_boxes/000077500000000000000000000000001470351605300174625ustar00rootroot00000000000000rbnacl-7.1.2/lib/rbnacl/secret_boxes/xsalsa20poly1305.rb000066400000000000000000000117131470351605300226640ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module SecretBoxes # The SecretBox class boxes and unboxes messages # # This class uses the given secret key to encrypt and decrypt messages. # # It is VITALLY important that the nonce is a nonce, i.e. it is a number used # only once for any given pair of keys. If you fail to do this, you # compromise the privacy of the messages encrypted. Give your nonces a # different prefix, or have one side use an odd counter and one an even counter. # Just make sure they are different. # # The ciphertexts generated by this class include a 16-byte authenticator which # is checked as part of the decryption. An invalid authenticator will cause # the unbox function to raise. The authenticator is not a signature. Once # you've looked in the box, you've demonstrated the ability to create # arbitrary valid messages, so messages you send are repudiable. For # non-repudiable messages, sign them before or after encryption. class XSalsa20Poly1305 extend Sodium sodium_type :secretbox sodium_primitive :xsalsa20poly1305 sodium_constant :KEYBYTES sodium_constant :NONCEBYTES sodium_constant :ZEROBYTES sodium_constant :BOXZEROBYTES sodium_function :secretbox_xsalsa20poly1305, :crypto_secretbox_xsalsa20poly1305, %i[pointer pointer ulong_long pointer pointer] sodium_function :secretbox_xsalsa20poly1305_open, :crypto_secretbox_xsalsa20poly1305_open, %i[pointer pointer ulong_long pointer pointer] # Create a new SecretBox # # Sets up the Box with a secret key fro encrypting and decrypting messages. # # @param key [String] The key to encrypt and decrypt with # # @raise [RbNaCl::LengthError] on invalid keys # # @return [RbNaCl::SecretBox] The new Box, ready to use def initialize(key) @key = Util.check_string(key, KEYBYTES, "Secret key") end # Encrypts a message # # Encrypts the message with the given nonce to the key set up when # initializing the class. Make sure the nonce is unique for any given # key, or you might as well just send plain text. # # This function takes care of the padding required by the NaCL C API. # # @param nonce [String] A 24-byte string containing the nonce. # @param message [String] The message to be encrypted. # # @raise [RbNaCl::LengthError] If the nonce is not valid # # @return [String] The ciphertext without the nonce prepended (BINARY encoded) def box(nonce, message) Util.check_length(nonce, nonce_bytes, "Nonce") msg = Util.prepend_zeros(ZEROBYTES, message) ct = Util.zeros(msg.bytesize) success = self.class.secretbox_xsalsa20poly1305(ct, msg, msg.bytesize, nonce, @key) raise CryptoError, "Encryption failed" unless success Util.remove_zeros(BOXZEROBYTES, ct) end alias encrypt box # Decrypts a ciphertext # # Decrypts the ciphertext with the given nonce using the key setup when # initializing the class. # # This function takes care of the padding required by the NaCL C API. # # @param nonce [String] A 24-byte string containing the nonce. # @param ciphertext [String] The message to be decrypted. # # @raise [RbNaCl::LengthError] If the nonce is not valid # @raise [RbNaCl::CryptoError] If the ciphertext cannot be authenticated. # # @return [String] The decrypted message (BINARY encoded) def open(nonce, ciphertext) Util.check_length(nonce, nonce_bytes, "Nonce") ct = Util.prepend_zeros(BOXZEROBYTES, ciphertext) message = Util.zeros(ct.bytesize) success = self.class.secretbox_xsalsa20poly1305_open(message, ct, ct.bytesize, nonce, @key) raise CryptoError, "Decryption failed. Ciphertext failed verification." unless success Util.remove_zeros(ZEROBYTES, message) end alias decrypt open # The crypto primitive for the SecretBox instance # # @return [Symbol] The primitive used def primitive self.class.primitive end # The nonce bytes for the SecretBox class # # @return [Integer] The number of bytes in a valid nonce def self.nonce_bytes NONCEBYTES end # The nonce bytes for the SecretBox instance # # @return [Integer] The number of bytes in a valid nonce def nonce_bytes NONCEBYTES end # The key bytes for the SecretBox class # # @return [Integer] The number of bytes in a valid key def self.key_bytes KEYBYTES end # The key bytes for the SecretBox instance # # @return [Integer] The number of bytes in a valid key def key_bytes KEYBYTES end end end end rbnacl-7.1.2/lib/rbnacl/self_test.rb000066400000000000000000000070571470351605300173230ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true start = Time.now if $DEBUG # NaCl/libsodium for Ruby module RbNaCl class SelfTestFailure < RbNaCl::CryptoError; end # Self-test performed at startup module SelfTest module_function def vector(name) [TEST_VECTORS[name]].pack("H*") end def box_test alicepk = RbNaCl::PublicKey.new(vector(:alice_public)) bobsk = RbNaCl::PrivateKey.new(vector(:bob_private)) box = RbNaCl::Box.new(alicepk, bobsk) box_common_test(box) end def secret_box_test box = SecretBox.new(vector(:secret_key)) box_common_test(box) end def box_common_test(box) nonce = vector :box_nonce message = vector :box_message ciphertext = vector :box_ciphertext raise SelfTestFailure, "failed to generate correct ciphertext" unless box.encrypt(nonce, message) == ciphertext raise SelfTestFailure, "failed to decrypt ciphertext correctly" unless box.decrypt(nonce, ciphertext) == message begin passed = false corrupt_ct = ciphertext.dup corrupt_ct[23] = " " box.decrypt(nonce, corrupt_ct) rescue CryptoError passed = true ensure passed || raise(SelfTestFailure, "failed to detect corrupt ciphertext") end end def digital_signature_test signing_key = SigningKey.new(vector(:sign_private)) verify_key = signing_key.verify_key unless verify_key.to_s == vector(:sign_public) # :nocov: raise SelfTestFailure, "failed to generate verify key correctly" # :nocov: end message = vector :sign_message signature = signing_key.sign(message) unless signature == vector(:sign_signature) # :nocov: raise SelfTestFailure, "failed to generate correct signature" # :nocov: end unless verify_key.verify(signature, message) # :nocov: raise SelfTestFailure, "failed to verify a valid signature" # :nocov: end begin passed = false bad_signature = signature[0, 63] + "0" verify_key.verify(bad_signature, message) rescue CryptoError passed = true ensure passed || raise(SelfTestFailure, "failed to detect corrupt ciphertext") end end def sha256_test message = vector :sha256_message digest = vector :sha256_digest raise SelfTestFailure, "failed to generate a correct SHA256 digest" unless RbNaCl::Hash.sha256(message) == digest end def hmac_test(klass, tag) authenticator = klass.new(vector("auth_key_#{klass.key_bytes}".to_sym)) message = vector :auth_message raise SelfTestFailure, "#{klass} generated incorrect authentication tag" unless authenticator.auth(message) == vector(tag) raise SelfTestFailure, "#{klass} failed to verify authentication tag" unless authenticator.verify(vector(tag), message) begin passed = false authenticator.verify(vector(tag), message + " ") rescue CryptoError passed = true ensure passed || raise(SelfTestFailure, "failed to detect corrupt ciphertext") end end end end RbNaCl::SelfTest.box_test RbNaCl::SelfTest.secret_box_test RbNaCl::SelfTest.digital_signature_test RbNaCl::SelfTest.sha256_test RbNaCl::SelfTest.hmac_test RbNaCl::HMAC::SHA256, :auth_hmacsha256 RbNaCl::SelfTest.hmac_test RbNaCl::HMAC::SHA512256, :auth_hmacsha512256 RbNaCl::SelfTest.hmac_test RbNaCl::OneTimeAuth, :auth_onetime puts "POST Completed in #{Time.now - start} s" if $DEBUG rbnacl-7.1.2/lib/rbnacl/serializable.rb000066400000000000000000000006201470351605300177660ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl # Serialization features shared across all "key-like" classes module Serializable def to_s to_bytes end def to_str to_bytes end # Inspect this key # # @return [String] a string representing this key def inspect "#<#{self.class}:#{Util.bin2hex(to_bytes)[0, 8]}>" end end end rbnacl-7.1.2/lib/rbnacl/signatures/000077500000000000000000000000001470351605300171615ustar00rootroot00000000000000rbnacl-7.1.2/lib/rbnacl/signatures/ed25519.rb000066400000000000000000000007661470351605300205150ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module Signatures # The EdDSA signature system implemented using the Ed25519 elliptic curve module Ed25519 extend Sodium sodium_type :sign sodium_primitive :ed25519 sodium_constant :SEEDBYTES sodium_constant :PUBLICKEYBYTES, name: :VERIFYKEYBYTES sodium_constant :SECRETKEYBYTES, name: :SIGNINGKEYBYTES sodium_constant :BYTES, name: :SIGNATUREBYTES end end end rbnacl-7.1.2/lib/rbnacl/signatures/ed25519/000077500000000000000000000000001470351605300201575ustar00rootroot00000000000000rbnacl-7.1.2/lib/rbnacl/signatures/ed25519/signing_key.rb000066400000000000000000000120241470351605300230110ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module Signatures module Ed25519 # Private key for producing digital signatures using the Ed25519 algorithm. # Ed25519 provides a 128-bit security level, that is to say, all known attacks # take at least 2^128 operations, providing the same security level as # AES-128, NIST P-256, and RSA-3072. # # Signing keys are produced from a 32-byte (256-bit) random seed value. # This value can be passed into the SigningKey constructor as a String # whose bytesize is 32. # # The public VerifyKey can be computed from the private 32-byte seed value # as well, eliminating the need to store a "keypair". # # SigningKey produces 64-byte (512-bit) signatures. The signatures are # deterministic: signing the same message will always produce the same # signature. This prevents "entropy failure" seen in other signature # algorithms like DSA and ECDSA, where poor random number generators can # leak enough information to recover the private key. class SigningKey include KeyComparator include Serializable extend Sodium sodium_type :sign sodium_primitive :ed25519 sodium_function :sign_ed25519, :crypto_sign_ed25519, %i[pointer pointer pointer ulong_long pointer] sodium_function :sign_ed25519_seed_keypair, :crypto_sign_ed25519_seed_keypair, %i[pointer pointer pointer] sodium_function :to_private_key, :crypto_sign_ed25519_sk_to_curve25519, %i[pointer pointer] attr_reader :verify_key # Generate a random SigningKey # # @return [RbNaCl::SigningKey] Freshly-generated random SigningKey def self.generate new RbNaCl::Random.random_bytes(Ed25519::SEEDBYTES) end # Create a SigningKey from a seed value # # @param seed [String] Random 32-byte value (i.e. private key) # # @return [RbNaCl::SigningKey] Key which can sign messages def initialize(seed) seed = seed.to_s Util.check_length(seed, Ed25519::SEEDBYTES, "seed") pk = Util.zeros(Ed25519::VERIFYKEYBYTES) sk = Util.zeros(Ed25519::SIGNINGKEYBYTES) self.class.sign_ed25519_seed_keypair(pk, sk, seed) || raise(CryptoError, "Failed to generate a key pair") @seed = seed @signing_key = sk @verify_key = VerifyKey.new(pk) end # Sign a message using this key # # @param message [String] Message to be signed by this key # # @return [String] Signature as bytes def sign(message) sign_attached(message)[0, signature_bytes] end # Sign a message using this key, attaching the signature to the message # # @param message [String] Message to be signed by this key # # @return [String] Signature and the message as bytes def sign_attached(message) buffer = Util.prepend_zeros(signature_bytes, message) buffer_len = Util.zeros(FFI::Type::LONG_LONG.size) self.class.sign_ed25519(buffer, buffer_len, message, message.bytesize, @signing_key) buffer end # Return the raw seed value of this key # # @return [String] seed used to create this key def to_bytes @seed end # Return the raw 64 byte value of this key # # @return [String] The signature key bytes. Left half is 32-byte # curve25519 private scalar, right half is 32-byte group element def keypair_bytes @signing_key end # The crypto primitive this SigningKey class uses for signatures # # @return [Symbol] The primitive def primitive self.class.primitive end # The size of signatures generated by the SigningKey class # # @return [Integer] The number of bytes in a signature def self.signature_bytes Ed25519::SIGNATUREBYTES end # The size of signatures generated by the SigningKey instance # # @return [Integer] The number of bytes in a signature def signature_bytes Ed25519::SIGNATUREBYTES end # Return a new curve25519 (x25519) private key converted from this key # # it's recommeneded to read https://libsodium.gitbook.io/doc/advanced/ed25519-curve25519 # as it encourages using distinct keys for signing and for encryption # # @return [RbNaCl::PrivateKey] def to_curve25519_private_key buffer = Util.zeros(Boxes::Curve25519XSalsa20Poly1305::PrivateKey::BYTES) self.class.crypto_sign_ed25519_sk_to_curve25519(buffer, @signing_key) Boxes::Curve25519XSalsa20Poly1305::PrivateKey.new(buffer) end end end end end rbnacl-7.1.2/lib/rbnacl/signatures/ed25519/verify_key.rb000066400000000000000000000102501470351605300226560ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl module Signatures module Ed25519 # The public key counterpart to an Ed25519 SigningKey for producing digital # signatures. Like the name says, VerifyKeys can be used to verify that a # given digital signature is authentic. # # For more information on the Ed25519 digital signature system, please see # the SigningKey documentation. class VerifyKey include KeyComparator include Serializable extend Sodium sodium_type :sign sodium_primitive :ed25519 sodium_function :sign_ed25519_open, :crypto_sign_ed25519_open, %i[pointer pointer pointer ulong_long pointer] sodium_function :to_public_key, :crypto_sign_ed25519_pk_to_curve25519, %i[pointer pointer] # Create a new VerifyKey object from a public key. # # @param key [String] Ed25519 public key # # @return [RbNaCl::VerifyKey] Key which can verify messages def initialize(key) @key = key.to_str Util.check_length(@key, Ed25519::VERIFYKEYBYTES, "key") end # Verify a signature for a given message # # Raises if the signature is invalid. # # @param signature [String] Alleged signature to be checked # @param message [String] Message to be authenticated # # @raise [BadSignatureError] if the signature check fails # @raise [LengthError] if the signature is of the wrong length # # @return [Boolean] was the signature authentic? def verify(signature, message) signature = signature.to_str Util.check_length(signature, signature_bytes, "signature") verify_attached(signature + message) end # Verify a signature for a given signed message # # Raises if the signature is invalid. # # @param signed_message [String] Message combined with signature to be authenticated # # @raise [BadSignatureError] if the signature check fails # # @return [Boolean] was the signature authentic? def verify_attached(signed_message) raise LengthError, "Signed message can not be nil" if signed_message.nil? raise LengthError, "Signed message can not be shorter than a signature" if signed_message.bytesize <= signature_bytes buffer = Util.zeros(signed_message.bytesize) buffer_len = Util.zeros(FFI::Type::LONG_LONG.size) success = self.class.sign_ed25519_open(buffer, buffer_len, signed_message, signed_message.bytesize, @key) raise(BadSignatureError, "signature was forged/corrupt") unless success true end # Return the raw key in byte format # # @return [String] raw key as bytes def to_bytes @key end # The crypto primitive this VerifyKey class uses for signatures # # @return [Symbol] The primitive def primitive self.class.primitive end # The size of signatures verified by the VerifyKey class # # @return [Integer] The number of bytes in a signature def self.signature_bytes Ed25519::SIGNATUREBYTES end # The size of signatures verified by the VerifyKey instance # # @return [Integer] The number of bytes in a signature def signature_bytes Ed25519::SIGNATUREBYTES end # Return a new curve25519 (x25519) public key converted from this key # # it's recommeneded to read https://libsodium.gitbook.io/doc/advanced/ed25519-curve25519 # as it encourages using distinct keys for signing and for encryption # # @return [RbNaCl::PublicKey] def to_curve25519_public_key buffer = Util.zeros(Boxes::Curve25519XSalsa20Poly1305::PublicKey::BYTES) self.class.crypto_sign_ed25519_pk_to_curve25519(buffer, @key) Boxes::Curve25519XSalsa20Poly1305::PublicKey.new(buffer) end end end end end rbnacl-7.1.2/lib/rbnacl/simple_box.rb000066400000000000000000000076351470351605300174760ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true require "forwardable" # NaCl/libsodium for Ruby module RbNaCl # The simplest nonce strategy that could possibly work # # This class implements the simplest possible nonce generation strategy to # wrap a RbNaCl::Box or RbNaCl::SecretBox. A 24-byte random nonce is used # for the encryption and is prepended to the message. When it is time to # open the box, the message is split into nonce and ciphertext, and then the # box is decrypted. # # Thanks to the size of the nonce, the chance of a collision is negligible. For # example, after encrypting 2^64 messages, the odds of their having been # repeated nonce is approximately 2^-64. As an additional convenience, the # ciphertexts may be encoded or decoded by any of the encoders implemented in # the library. # # The resulting ciphertexts are 40 bytes longer than the plain text (24 byte # nonce plus a 16 byte authenticator). This might be annoying if you're # encrypting tweets, but for files represents a fairly small overhead. # # Some caveats: # # * If your random source is broken, so is the security of the messages. You # have bigger problems than just this library at that point, but it's worth # saying. # * The confidentiality of your messages is assured with this strategy, but # there is no protection against messages being reordered and replayed by an # active adversary. class SimpleBox extend Forwardable def_delegators :@box, :nonce_bytes, :primitive # Create a new SimpleBox # # @param box [SecretBox, Box] the SecretBox or Box to use. # # @return [SimpleBox] Ready for use def initialize(box) @box = box end # Use a secret key to create a SimpleBox # # This is a convenience method. It takes a secret key and instantiates a # SecretBox under the hood, then returns the new SimpleBox. # # @param secret_key [String] The secret key, 32 bytes long. # # @return [SimpleBox] Ready for use def self.from_secret_key(secret_key) new(SecretBox.new(secret_key)) end # Use a pair of keys to create a SimpleBox # # This is a convenience method. It takes a pair of keys and instantiates a # Box under the hood, then returns the new SimpleBox. # # @param public_key [PublicKey, String] The RbNaCl public key, as class or string # @param private_key [PrivateKey, String] The RbNaCl private key, as class or string # # @return [SimpleBox] Ready for use def self.from_keypair(public_key, private_key) new(Box.new(public_key, private_key)) end # Encrypts the message with a random nonce # # Encrypts the message with a random nonce, then returns the ciphertext with # the nonce prepended. Optionally encodes the message using an encoder. # # @param message [String] The message to encrypt # # @return [String] The enciphered message def box(message) nonce = generate_nonce cipher_text = @box.box(nonce, message) nonce + cipher_text end alias encrypt box # Decrypts the ciphertext with a random nonce # # Takes a ciphertext, optionally decodes it, then splits the nonce off the # front and uses this to decrypt. Returns the message. # # @param enciphered_message [String] The message to decrypt. # # @raise [CryptoError] If the message has been tampered with. # # @return [String] The decoded message def open(enciphered_message) nonce, ciphertext = extract_nonce(enciphered_message.to_s) @box.open(nonce, ciphertext) end alias decrypt open private def generate_nonce Random.random_bytes(nonce_bytes) end def extract_nonce(bytes) nonce = bytes.slice(0, nonce_bytes) [nonce, bytes.slice(nonce_bytes..-1)] end end # Backwards compatibility with the old RandomNonceBox name RandomNonceBox = SimpleBox end rbnacl-7.1.2/lib/rbnacl/sodium.rb000066400000000000000000000031521470351605300166230ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true require "ffi" module RbNaCl # Provides helpers for defining the libsodium bindings module Sodium def self.extended(klass) klass.extend FFI::Library klass.ffi_lib ["sodium", "libsodium.so.18", "libsodium.so.23", "libsodium.so.26"] end def sodium_type(type = nil) return @type if type.nil? @type = type end def sodium_primitive(primitive = nil) if primitive.nil? @primitive if defined?(@primitive) else @primitive = primitive end end def primitive sodium_primitive end def sodium_constant(constant, name: constant, fallback: nil) fn_name_components = ["crypto", sodium_type, sodium_primitive, constant.to_s.downcase] fn_name = fn_name_components.compact.join("_") begin attach_function fn_name, [], :size_t rescue FFI::NotFoundError raise if fallback.nil? define_singleton_method fn_name, -> { fallback } end const_set(name, public_send(fn_name)) end def sodium_function(name, function, arguments) module_eval <<-RUBY, __FILE__, __LINE__ + 1 attach_function #{function.inspect}, #{arguments.inspect}, :int def self.#{name}(*args) ret = #{function}(*args) ret == 0 end RUBY end def sodium_function_with_return_code(name, function, arguments) module_eval <<-RUBY, __FILE__, __LINE__ + 1 attach_function #{function.inspect}, #{arguments.inspect}, :int def self.#{name}(*args) #{function}(*args) end RUBY end end end rbnacl-7.1.2/lib/rbnacl/sodium/000077500000000000000000000000001470351605300162755ustar00rootroot00000000000000rbnacl-7.1.2/lib/rbnacl/sodium/version.rb000066400000000000000000000022331470351605300203070ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true require "rbnacl/sodium" module RbNaCl module Sodium # libsodium version API module Version MINIMUM_LIBSODIUM_VERSION = [0, 4, 3].freeze MINIMUM_LIBSODIUM_VERSION_FOR_ARGON2 = [1, 0, 9].freeze MINIMUM_LIBSODIUM_VERSION_FOR_ARGON2ID = [1, 0, 13].freeze extend Sodium attach_function :sodium_version_string, [], :string STRING = sodium_version_string MAJOR, MINOR, PATCH = STRING.split(".").map(&:to_i) INSTALLED_VERSION = [MAJOR, MINOR, PATCH].freeze case INSTALLED_VERSION <=> MINIMUM_LIBSODIUM_VERSION when -1 raise "Sorry, you need to install libsodium #{MINIMUM_LIBSODIUM_VERSION}+. You have #{Version::STRING} installed" end ARGON2_SUPPORTED = (INSTALLED_VERSION <=> MINIMUM_LIBSODIUM_VERSION_FOR_ARGON2) != -1 ARGON2ID_SUPPORTED = (INSTALLED_VERSION <=> MINIMUM_LIBSODIUM_VERSION_FOR_ARGON2ID) != -1 # Determine if a given feature is supported based on Sodium version def self.supported_version?(version) Gem::Version.new(sodium_version_string) >= Gem::Version.new(version) end end end end rbnacl-7.1.2/lib/rbnacl/test_vectors.rb000066400000000000000000000375311470351605300200570ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true # NaCl/libsodium for Ruby # rubocop:disable Metrics/ModuleLength module RbNaCl # Reference library of test vectors used to verify the software is correct TEST_VECTORS = { # # Curve25519 test vectors # Taken from the NaCl distribution # alice_private: "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a", alice_public: "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a", bob_private: "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb", bob_public: "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f", alice_mult_bob: "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742", # # Box test vectors # Taken from the NaCl distribution # secret_key: "1b27556473e985d462cd51197a9a46c76009549eac6474f206c4ee0844f68389", box_nonce: "69696ee955b62b73cd62bda875fc73d68219e0036b7a0b37", box_message: "be075fc53c81f2d5cf141316ebeb0c7b5228c52a4c62cbd44b66849b64244ffc" \ "e5ecbaaf33bd751a1ac728d45e6c61296cdc3c01233561f41db66cce314adb31" \ "0e3be8250c46f06dceea3a7fa1348057e2f6556ad6b1318a024a838f21af1fde" \ "048977eb48f59ffd4924ca1c60902e52f0a089bc76897040e082f93776384864" \ "5e0705", box_ciphertext: "f3ffc7703f9400e52a7dfb4b3d3305d98e993b9f48681273c29650ba32fc76ce" \ "48332ea7164d96a4476fb8c531a1186ac0dfc17c98dce87b4da7f011ec48c972" \ "71d2c20f9b928fe2270d6fb863d51738b48eeee314a7cc8ab932164548e526ae" \ "90224368517acfeabd6bb3732bc0e9da99832b61ca01b6de56244a9e88d5f9b3" \ "7973f622a43d14a6599b1f654cb45a74e355a5", # # Ed25519 test vectors # Taken from the Python test vectors: http://ed25519.cr.yp.to/python/sign.input # sign_private: "b18e1d0045995ec3d010c387ccfeb984d783af8fbb0f40fa7db126d889f6dadd", sign_public: "77f48b59caeda77751ed138b0ec667ff50f8768c25d48309a8f386a2bad187fb", sign_keypair: "b18e1d0045995ec3d010c387ccfeb984d783af8fbb0f40fa7db126d889f6dadd" \ "77f48b59caeda77751ed138b0ec667ff50f8768c25d48309a8f386a2bad187fb", sign_message: "916c7d1d268fc0e77c1bef238432573c39be577bbea0998936add2b50a653171" \ "ce18a542b0b7f96c1691a3be6031522894a8634183eda38798a0c5d5d79fbd01" \ "dd04a8646d71873b77b221998a81922d8105f892316369d5224c9983372d2313" \ "c6b1f4556ea26ba49d46e8b561e0fc76633ac9766e68e21fba7edca93c4c7460" \ "376d7f3ac22ff372c18f613f2ae2e856af40", sign_signature: "6bd710a368c1249923fc7a1610747403040f0cc30815a00f9ff548a896bbda0b" \ "4eb2ca19ebcf917f0f34200a9edbad3901b64ab09cc5ef7b9bcc3c40c0ff7509", sign_curve25519_private: "38e5cdf33bc9e13086f58a3fea86d574e85e7865cffa5e8c9335f200a41d036c", sign_curve25519_public: "35488a98f7ec26ae27099809afb27587b198b1197b5bcb0dec41153db2bf9952", # # SHA256 test vectors # Taken from the NSRL test vectors: http://www.nsrl.nist.gov/testdata/ sha256_message: "6162636462636465636465666465666765666768666768696768696a68696a6b" \ "696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f7071", sha256_digest: "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", sha256_empty: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", # # SHA512 test vectors # self-created (FIXME: find standard test vectors) sha512_message: "54686520717569636b2062726f776e20666f78206a756d7073206f7665722074" \ "6865206c617a7920646f672e", sha512_digest: "91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bb" \ "c6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed", sha512_empty: "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce" \ "47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", # Blake2b test vectors # self-created? (TODO: double check, fix) blake2b_message: "54686520717569636b2062726f776e20666f78206a756d7073206f7665722074" \ "6865206c617a7920646f67", blake2b_digest: "a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673" \ "f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918", blake2b_empty: "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419" \ "d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce", # from the Blake2 paper(?) (TODO: double check) blake2b_keyed_message: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" \ "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" \ "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" \ "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" \ "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f" \ "a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf" \ "c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf" \ "e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe", blake2b_key: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" \ "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", blake2b_keyed_digest: "142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e9248" \ "4be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461", # Generated using the blake2 reference code blake2b_personal: "000102030405060708090a0b0c0d0e0f", blake2b_personal_digest: "7c86d3f929c9ac7f08c7940095da7c1cad2cf29db2e7a25fb05d99163e587cbd" \ "f3564e8ce727b734a0559ee76f6ff5aeebd4e1e8872f1829174c9b1a9dab80e3", blake2b_salt: "000102030405060708090a0b0c0d0e0f", blake2b_salt_digest: "16e2e2cfb97e6061bccf2fcc1e605e117dee806c959ef2ad01249d4d12ce98cb" \ "c993f400003ba57449f60a7b071ffdaff9c0acb16891a01a9b397ffe89db96bb", blake2b_personal_short: "0001020304050607", blake2b_personal_short_digest: "41b984967f852308710a6042d25f5faf4a84900b2001039075dab13aecfab7c8" \ "40def9506326563fbb355b3da629181d97d2556e4624711d68f8f655b7cbb435", blake2b_salt_short: "0001020304050607", blake2b_salt_short_digest: "873f35a1ca28febc872d6f842a8cd23136f3a2c22c19e8f0dac4cc704ced3371"\ "abe5105f65d344cd48bad8aba755620f63f1e0b35ae4439bf871ffe72485a309", # scrypt test vectors # Taken from http://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#page-14 scrypt_password: "4a857e2ee8aa9b6056f2424e84d24a72473378906ee04a46cb05311502d5250b" \ "82ad86b83c8f20a23dbb74f6da60b0b6ecffd67134d45946ac8ebfb3064294bc" \ "097d43ced68642bfb8bbbdd0f50b30118f5e", scrypt_salt: "39d82eef32010b8b79cc5ba88ed539fbaba741100f2edbeca7cc171ffeabf258", scrypt_opslimit: 33_554_432, scrypt_memlimit: 1_073_741_824, scrypt_digest: "11a4c60b98411758ba9e89a28587c074ae674c367326c79a999e415110b14460" \ "5921bd3c897098a837fa40d9eef5338268754ea5e243f630a58fa698df95d1ed", # argon2 vectors # from libsodium/test/default/pwhash_argon2i.c argon2i_password: "a347ae92bce9f80f6f595a4480fc9c2fe7e7d7148d371e9487d75f5c23008ffae0" \ "65577a928febd9b1973a5a95073acdbeb6a030cfc0d79caa2dc5cd011cef02c08d" \ "a232d76d52dfbca38ca8dcbd665b17d1665f7cf5fe59772ec909733b24de97d6f5" \ "8d220b20c60d7c07ec1fd93c52c31020300c6c1facd77937a597c7a6", argon2i_salt: "5541fbc995d5c197ba290346d2c559de", argon2i_outlen: 155, argon2i_opslimit: 5, argon2i_memlimit: 7_256_678, argon2i_digest: "23b803c84eaa25f4b44634cc1e5e37792c53fcd9b1eb20f865329c68e09cbfa9f19" \ "68757901b383fce221afe27713f97914a041395bbe1fb70e079e5bed2c7145b1f61" \ "54046f5958e9b1b29055454e264d1f2231c316f26be2e3738e83a80315e9a0951ce" \ "4b137b52e7d5ee7b37f7d936dcee51362bcf792595e3c896ad5042734fc90c92cae" \ "572ce63ff659a2f7974a3bd730d04d525d253ccc38", # from libsodium/test/default/pwhash_argon2id.c argon2id_password: "a347ae92bce9f80f6f595a4480fc9c2fe7e7d7148d371e9487d75f5c23008ffae0" \ "65577a928febd9b1973a5a95073acdbeb6a030cfc0d79caa2dc5cd011cef02c08d" \ "a232d76d52dfbca38ca8dcbd665b17d1665f7cf5fe59772ec909733b24de97d6f5" \ "8d220b20c60d7c07ec1fd93c52c31020300c6c1facd77937a597c7a6", argon2id_salt: "5541fbc995d5c197ba290346d2c559de", argon2id_outlen: 155, argon2id_opslimit: 5, argon2id_memlimit: 7_256_678, argon2id_digest: "18acec5d6507739f203d1f5d9f1d862f7c2cdac4f19d2bdff64487e60d969e3ced6" \ "15337b9eec6ac4461c6ca07f0939741e57c24d0005c7ea171a0ee1e7348249d135b" \ "38f222e4dad7b9a033ed83f5ca27277393e316582033c74affe2566a2bea47f91f0" \ "fd9fe49ece7e1f79f3ad6e9b23e0277c8ecc4b313225748dd2a80f5679534a0700e" \ "246a79a49b3f74eb89ec6205fe1eeb941c73b1fcf1", # argon2_str vectors # from libsodium/test/default/pwhash.c argon2_str_digest: "$argon2i$v=19$m=4096,t=3,p=2$b2RpZHVlamRpc29kaXNrdw" \ "$TNnWIwlu1061JHrnCqIAmjs3huSxYIU+0jWipu7Kc9M", argon2_str_passwd: "password", # Auth test vectors # Taken from NaCl distribution # auth_key_32: "eea6a7251c1e72916d11c2cb214d3c252539121d8e234e652d651fa4c8cff880", auth_key_64: "eaaa4c73ef13e7e9a53011304c5be141da9c3713b5ca822037ed57aded31b70a" \ "50a0dd80843d580fe5b57e470bb534333e907a624cf02873c6b9eaba70e0fc7e", auth_message: "8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186a" \ "c0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738" \ "b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da" \ "99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74" \ "e355a5", auth_onetime: "f3ffc7703f9400e52a7dfb4b3d3305d9", # self-created (FIXME: find standard test vectors) auth_hmacsha256: "7f7b9b707e8790ca8620ff94df5e6533ddc8e994060ce310c9d7de04d44aabc3", auth_hmacsha512256: "b2a31b8d4e01afcab2ee545b5caf4e3d212a99d7b3a116a97cec8e83c32e107d", auth_hmacsha512: "b2a31b8d4e01afcab2ee545b5caf4e3d212a99d7b3a116a97cec8e83c32e107d" \ "270e3921f69016c267a63ab4b226449a0dee0dc7dcb897a9bce9d27d788f8e8d", # HMAC-SHA Identifiers and Test Vectors # ref: https://tools.ietf.org/html/rfc4231#section-4.8 # auth_hmac_key: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \ "aaaaaa", auth_hmac_data: "5468697320697320612074657374207573696e672061206c6172676572207468" \ "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" \ "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" \ "647320746f20626520686173686564206265666f7265206265696e6720757365" \ "642062792074686520484d414320616c676f726974686d2e", auth_hmacsha256_tag: "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2", auth_hmacsha512_tag: "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944" \ "b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58", auth_hmacsha512256_tag: "bfaae3b4292b56d6170154cc089af73f79e089ecf27d4720eed6fd0a7ffcccf1", auth_hmacsha256_mult_tag: "367a7a7e8292759844dcf820c90daa5fea5a4b769e537038cd0dc28290fbf2cb", auth_hmacsha512_mult_tag: "1006b7bef1e24725ed55049c8b787b7b174f4afbe197124a389205c499956a90" \ "fea5c44b616a9e1a286d024c2880c67ae0e1ec7524530f15ae1086b144192d93", auth_hmacsha512256_mult_tag: "bf280508996bba2bd590a2c1662d8c47fcceb8111bfcc4bdff5f2c28b0301449", # AEAD ChaCha20-Poly1305 original implementation test vectors # Taken from https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04 aead_chacha20poly1305_orig_key: "4290bcb154173531f314af57f3be3b5006da371ece272afa1b5dbdd1100a1007", aead_chacha20poly1305_orig_message: "86d09974840bded2a5ca", aead_chacha20poly1305_orig_nonce: "cd7cf67be39c794a", aead_chacha20poly1305_orig_ad: "87e229d4500845a079c0", aead_chacha20poly1305_orig_ciphertext: "e3e446f7ede9a19b62a4677dabf4e3d24b876bb284753896e1d6", # AEAD ChaCha20-Poly1305 IETF test vectors # Taken from https://tools.ietf.org/html/rfc7539 aead_chacha20poly1305_ietf_key: "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f", aead_chacha20poly1305_ietf_message: "4c616469657320616e642047656e746c656d656e206f662074686520636c6173" \ "73206f66202739393a204966204920636f756c64206f6666657220796f75206f" \ "6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73" \ "637265656e20776f756c642062652069742e", aead_chacha20poly1305_ietf_nonce: "070000004041424344454647", aead_chacha20poly1305_ietf_ad: "50515253c0c1c2c3c4c5c6c7", aead_chacha20poly1305_ietf_ciphertext: "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d6" \ "3dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b36" \ "92ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc" \ "3ff4def08e4b7a9de576d26586cec64b61161ae10b594f09e26a7e902ecbd060" \ "0691", # Jank AEAD XChaCha20-Poly1305 test vectors # Unfortunately, I couldn't find any public variants of these, so I used: # https://github.com/jedisct1/libsodium/blob/1.0.16/test/default/aead_xchacha20poly1305.c # Doubly unfortunately, that doesn't even have a ciphertext vector. I # generated one using crypto_aead_xchacha20poly1305_ietf_encrypt on # libsodium 1.0.16 aead_xchacha20poly1305_ietf_key: "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f", aead_xchacha20poly1305_ietf_message: "4c616469657320616e642047656e746c656d656e206f662074686520636c6173" \ "73206f66202739393a204966204920636f756c64206f6666657220796f75206f" \ "6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73" \ "637265656e20776f756c642062652069742e", aead_xchacha20poly1305_ietf_nonce: "07000000404142434445464748494a4b0000000000000000", aead_xchacha20poly1305_ietf_ad: "50515253c0c1c2c3c4c5c6c7", aead_xchacha20poly1305_ietf_ciphertext: "453c0693a7407f04ff4c56aedb17a3c0a1afff01174930fc22287c33dbcf0ac8" \ "b89ad929530a1bb3ab5e69f24c7f6070c8f840c9abb4f69fbfc8a7ff5126faee" \ "bbb55805ee9c1cf2ce5a57263287aec5780f04ec324c3514122cfc3231fc1a8b" \ "718a62863730a2702bb76366116bed09e0fd5c6d84b6b0c1abaf249d5dd0f7f5" \ "a7ea" }.freeze end # rubocop:enable Metrics/ModuleLength rbnacl-7.1.2/lib/rbnacl/util.rb000066400000000000000000000226621470351605300163070ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true module RbNaCl # Various utility functions module Util extend Sodium sodium_function :c_verify16, :crypto_verify_16, %i[pointer pointer] sodium_function :c_verify32, :crypto_verify_32, %i[pointer pointer] sodium_function :c_verify64, :crypto_verify_64, %i[pointer pointer] module_function # Returns a string of n zeros # # Lots of the functions require us to create strings to pass into functions of a specified size. # # @param [Integer] n the size of the string to make # # @return [String] A nice collection of zeros def zeros(n = 32) zeros = "\0" * n # make sure they're 8-bit zeros, not 7-bit zeros. Otherwise we might get # encoding errors later zeros.respond_to?(:force_encoding) ? zeros.force_encoding("ASCII-8BIT") : zeros end # Prepends a message with zeros # # Many functions require a string with some zeros prepended. # # @param [Integer] n The number of zeros to prepend # @param [String] message The string to be prepended # # @return [String] a bunch of zeros def prepend_zeros(n, message) zeros(n) + message end # Remove zeros from the start of a message # # Many functions require a string with some zeros prepended, then need them removing after. # Note: this modifies the passed in string # # @param [Integer] n The number of zeros to remove # @param [String] message The string to be slice # # @return [String] less a bunch of zeros def remove_zeros(n, message) message.slice!(n, message.bytesize - n) end # Pad a string out to n characters with zeros # # @param [Integer] n The length of the resulting string # @param [String] message the message to be padded # # @raise [RbNaCl::LengthError] If the string is too long # # @return [String] A string, n bytes long def zero_pad(n, message) len = message.bytesize if len == n message elsif len > n raise LengthError, "String too long for zero-padding to #{n} bytes" else message + zeros(n - len) end end # Check the length of the passed in string # # In several places through the codebase we have to be VERY strict with # what length of string we accept. This method supports that. # # @raise [RbNaCl::LengthError] If the string is not the right length # # @param string [String] The string to compare # @param length [Integer] The desired length # @param description [String] Description of the string (used in the error) def check_length(string, length, description) if string.nil? # code below is runs only in test cases # nil can't be converted to str with #to_str method raise LengthError, "#{description} was nil (Expected #{length.to_int})", caller end if string.bytesize != length.to_int raise LengthError, "#{description} was #{string.bytesize} bytes (Expected #{length.to_int})", caller end true end # Check a passed in string, converting the argument if necessary # # In several places through the codebase we have to be VERY strict with # the strings we accept. This method supports that. # # @raise [ArgumentError] If we cannot convert to a string with #to_str # @raise [RbNaCl::LengthError] If the string is not the right length # # @param string [#to_str] The input string # @param length [Integer] The only acceptable length of the string # @param description [String] Description of the string (used in the error) def check_string(string, length, description) check_string_validation(string) string = string.to_s check_length(string, length, description) string end # Check a passed in string, convertion if necessary # # This method will check the key, and raise error # if argument is not a string, and if it's empty string. # # RFC 2104 HMAC # The key for HMAC can be of any length (keys longer than B bytes are # first hashed using H). However, less than L bytes is strongly # discouraged as it would decrease the security strength of the # function. Keys longer than L bytes are acceptable but the extra # length would not significantly increase the function strength. (A # longer key may be advisable if the randomness of the key is # considered weak.) # # see https://tools.ietf.org/html/rfc2104#section-3 # # # @raise [ArgumentError] If we cannot convert to a string with #to_str # @raise [RbNaCl::LengthError] If the string is empty # # @param string [#to_str] The input string # @param description [String] Description of the string (used in the error) def check_hmac_key(string, description) check_string_validation(string) string = string.to_str if string.bytesize.zero? raise LengthError, "#{description} was #{string.bytesize} bytes (Expected more than 0)", caller end string end # Check a passed string is it valid # # Raise an error if passed argument is invalid # # @raise [TypeError] If string cannot convert to a string with #to_str # @raise [EncodingError] If string have wrong encoding # # @param string [#to_str] The input string def check_string_validation(string) raise TypeError, "can't convert #{string.class} into String with #to_str" unless string.respond_to? :to_str string = string.to_str raise EncodingError, "strings must use BINARY encoding (got #{string.encoding})" if string.encoding != Encoding::BINARY end # Compare two 64 byte strings in constant time # # This should help to avoid timing attacks for string comparisons in your # application. Note that many of the functions (such as HmacSha512#verify) # use this method under the hood already. # # @param [String] one String #1 # @param [String] two String #2 # # @return [Boolean] Well, are they equal? def verify64(one, two) return false unless two.bytesize == 64 && one.bytesize == 64 c_verify64(one, two) end # Compare two 64 byte strings in constant time # # This should help to avoid timing attacks for string comparisons in your # application. Note that many of the functions (such as HmacSha512#verify) # use this method under the hood already. # # @param [String] one String #1 # @param [String] two String #2 # # @raise [ArgumentError] If the strings are not equal in length # # @return [Boolean] Well, are they equal? def verify64!(one, two) check_length(one, 64, "First message") check_length(two, 64, "Second message") c_verify64(one, two) end # Compare two 32 byte strings in constant time # # This should help to avoid timing attacks for string comparisons in your # application. Note that many of the functions (such as HmacSha256#verify) # use this method under the hood already. # # @param [String] one String #1 # @param [String] two String #2 # # @return [Boolean] Well, are they equal? def verify32(one, two) return false unless two.bytesize == 32 && one.bytesize == 32 c_verify32(one, two) end # Compare two 32 byte strings in constant time # # This should help to avoid timing attacks for string comparisons in your # application. Note that many of the functions (such as HmacSha256#verify) # use this method under the hood already. # # @param [String] one String #1 # @param [String] two String #2 # # @raise [ArgumentError] If the strings are not equal in length # # @return [Boolean] Well, are they equal? def verify32!(one, two) check_length(one, 32, "First message") check_length(two, 32, "Second message") c_verify32(one, two) end # Compare two 16 byte strings in constant time # # This should help to avoid timing attacks for string comparisons in your # application. Note that many of the functions (such as OneTime#verify) # use this method under the hood already. # # @param [String] one String #1 # @param [String] two String #2 # # @return [Boolean] Well, are they equal? def verify16(one, two) return false unless two.bytesize == 16 && one.bytesize == 16 c_verify16(one, two) end # Compare two 16 byte strings in constant time # # This should help to avoid timing attacks for string comparisons in your # application. Note that many of the functions (such as OneTime#verify) # use this method under the hood already. # # @param [String] one String #1 # @param [String] two String #2 # # @raise [ArgumentError] If the strings are not equal in length # # @return [Boolean] Well, are they equal? def verify16!(one, two) check_length(one, 16, "First message") check_length(two, 16, "Second message") c_verify16(one, two) end # Hex encodes a message # # @param [String] bytes The bytes to encode # # @return [String] Tasty, tasty hexadecimal def bin2hex(bytes) bytes.to_s.unpack1("H*") end # Hex decodes a message # # @param [String] hex hex to decode. # # @return [String] crisp and clean bytes def hex2bin(hex) [hex.to_s].pack("H*") end end end rbnacl-7.1.2/lib/rbnacl/version.rb000066400000000000000000000002141470351605300170040ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true # NaCl/libsodium for Ruby module RbNaCl # The library's version VERSION = "7.1.2" end rbnacl-7.1.2/rbnacl.gemspec000066400000000000000000000030421470351605300155730ustar00rootroot00000000000000# frozen_string_literal: true lib = File.expand_path("lib", __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require "rbnacl/version" Gem::Specification.new do |spec| spec.name = "rbnacl" spec.version = RbNaCl::VERSION spec.authors = ["Tony Arcieri", "Jonathan Stott"] spec.email = ["bascule@gmail.com", "jonathan.stott@gmail.com"] spec.homepage = "https://github.com/RubyCrypto/rbnacl" spec.licenses = ["MIT"] spec.summary = "Ruby binding to the libsodium/NaCl cryptography library" spec.description = <<-DESCRIPTION.strip.gsub(/\s+/, " ") The Networking and Cryptography (NaCl) library provides a high-level toolkit for building cryptographic systems and protocols DESCRIPTION spec.metadata = { "bug_tracker_uri" => "#{spec.homepage}/issues", "changelog_uri" => "#{spec.homepage}/blob/master/CHANGES.md", "documentation_uri" => "https://www.rubydoc.info/gems/#{spec.name}/#{spec.version}", "source_code_uri" => "#{spec.homepage}/tree/v#{spec.version}", "wiki_uri" => "#{spec.homepage}/wiki" } spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR).reject do |f| f.start_with?("images/", "spec/", "tasks/", "Rakefile") end spec.executables = spec.files.grep(%r{^bin/}).map { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ["lib"] spec.required_ruby_version = ">= 2.6.0" spec.add_runtime_dependency "ffi", "~> 1" spec.add_development_dependency "bundler", "~> 2" end rbnacl-7.1.2/spec/000077500000000000000000000000001470351605300137205ustar00rootroot00000000000000rbnacl-7.1.2/spec/rbnacl/000077500000000000000000000000001470351605300151615ustar00rootroot00000000000000rbnacl-7.1.2/spec/rbnacl/aead/000077500000000000000000000000001470351605300160535ustar00rootroot00000000000000rbnacl-7.1.2/spec/rbnacl/aead/chacha20poly1305_ietf_spec.rb000066400000000000000000000010471470351605300232110ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::AEAD::ChaCha20Poly1305IETF do if RbNaCl::Sodium::Version.supported_version?("1.0.9") include_examples "aead" do let(:key) { vector :aead_chacha20poly1305_ietf_key } let(:message) { vector :aead_chacha20poly1305_ietf_message } let(:nonce) { vector :aead_chacha20poly1305_ietf_nonce } let(:ad) { vector :aead_chacha20poly1305_ietf_ad } let(:ciphertext) { vector :aead_chacha20poly1305_ietf_ciphertext } end end end rbnacl-7.1.2/spec/rbnacl/aead/chacha20poly1305_legacy_spec.rb000066400000000000000000000007341470351605300235300ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::AEAD::ChaCha20Poly1305Legacy do include_examples "aead" do let(:key) { vector :aead_chacha20poly1305_orig_key } let(:message) { vector :aead_chacha20poly1305_orig_message } let(:nonce) { vector :aead_chacha20poly1305_orig_nonce } let(:ad) { vector :aead_chacha20poly1305_orig_ad } let(:ciphertext) { vector :aead_chacha20poly1305_orig_ciphertext } end end rbnacl-7.1.2/spec/rbnacl/aead/xchacha20poly1305_ietf_spec.rb000066400000000000000000000010561470351605300234010ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::AEAD::XChaCha20Poly1305IETF do if RbNaCl::Sodium::Version.supported_version?("1.0.12") include_examples "aead" do let(:key) { vector :aead_xchacha20poly1305_ietf_key } let(:message) { vector :aead_xchacha20poly1305_ietf_message } let(:nonce) { vector :aead_xchacha20poly1305_ietf_nonce } let(:ad) { vector :aead_xchacha20poly1305_ietf_ad } let(:ciphertext) { vector :aead_xchacha20poly1305_ietf_ciphertext } end end end rbnacl-7.1.2/spec/rbnacl/authenticators/000077500000000000000000000000001470351605300202165ustar00rootroot00000000000000rbnacl-7.1.2/spec/rbnacl/authenticators/poly1305_spec.rb000066400000000000000000000016261470351605300230560ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::OneTimeAuth do let(:key) { vector "auth_key_#{described_class.key_bytes}".to_sym } let(:message) { vector :auth_message } let(:tag) { vector :auth_onetime } context ".new" do it "raises ArgumentError on a key which is too long" do expect { described_class.new("\0" * described_class.key_bytes.succ) }.to raise_error(ArgumentError) end end context ".auth" do it "raises ArgumentError on a key which is too long" do expect { described_class.auth("\0" * described_class.key_bytes.succ, message) }.to raise_error(ArgumentError) end end context ".verify" do it "raises ArgumentError on a key which is too long" do expect { described_class.verify("\0" * described_class.key_bytes.succ, tag, message) }.to raise_error(ArgumentError) end end include_examples "authenticator" end rbnacl-7.1.2/spec/rbnacl/boxes/000077500000000000000000000000001470351605300163015ustar00rootroot00000000000000rbnacl-7.1.2/spec/rbnacl/boxes/curve25519xsalsa20poly1305/000077500000000000000000000000001470351605300226265ustar00rootroot00000000000000rbnacl-7.1.2/spec/rbnacl/boxes/curve25519xsalsa20poly1305/private_key_spec.rb000066400000000000000000000030571470351605300265140ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::PrivateKey do let(:bobsk) { vector :bob_private } let(:bobpk) { vector :bob_public } subject { RbNaCl::PrivateKey.new(bobsk) } context "generate" do let(:secret_key) { RbNaCl::PrivateKey.generate } it "returns a secret key" do expect(secret_key).to be_a RbNaCl::PrivateKey end it "has the public key also set" do expect(secret_key.public_key).to be_a RbNaCl::PublicKey end end context "new" do it "accepts a valid key" do expect { RbNaCl::PrivateKey.new(bobsk) }.not_to raise_error end it "raises TypeError when given a nil key" do expect { RbNaCl::PrivateKey.new(nil) }.to raise_error(TypeError) end it "raises ArgumentError when given a short key" do expect { RbNaCl::PrivateKey.new("short") }.to raise_error(ArgumentError) end end context "public_key" do it "returns a public key" do expect(subject.public_key).to be_a RbNaCl::PublicKey end it "returns the correct public key" do expect(subject.public_key.to_s).to eql bobpk end end context "#to_bytes" do it "returns the bytes of the key" do expect(subject.to_bytes).to eq bobsk end end context "#to_s" do it "returns the raw bytes of the key" do expect(subject.to_s).to eq bobsk end end include_examples "key equality" do let(:key) { subject } let(:key_bytes) { subject.to_bytes } let(:other_key) { described_class.new(bobpk) } end include_examples "serializable" end rbnacl-7.1.2/spec/rbnacl/boxes/curve25519xsalsa20poly1305/public_key_spec.rb000066400000000000000000000017321470351605300263160ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::PublicKey do let(:alicepk) { vector :alice_public } subject { RbNaCl::PublicKey.new(alicepk) } context "new" do it "accepts a valid key" do expect { RbNaCl::PublicKey.new(alicepk) }.not_to raise_error end it "rejects a nil key" do expect { RbNaCl::PublicKey.new(nil) }.to raise_error(TypeError) end it "rejects a short key" do expect { RbNaCl::PublicKey.new("short") }.to raise_error(ArgumentError) end end context "#to_bytes" do it "returns the bytes of the key" do expect(subject.to_bytes).to eq alicepk end end context "#to_s" do it "returns the bytes of the key" do expect(subject.to_s).to eq alicepk end end include_examples "key equality" do let(:key) { subject } let(:key_bytes) { subject.to_bytes } let(:other_key) { described_class.new(alicepk.succ) } end include_examples "serializable" end rbnacl-7.1.2/spec/rbnacl/boxes/curve25519xsalsa20poly1305_spec.rb000066400000000000000000000025251470351605300241710ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::Box do let(:alicepk) { vector :alice_public } let(:bobsk) { vector :bob_private } let(:alice_key) { RbNaCl::PublicKey.new(alicepk) } let(:bob_key) { RbNaCl::PrivateKey.new(bobsk) } context "new" do it "accepts strings" do expect do RbNaCl::Box.new(alicepk, bobsk) end.to_not raise_error end it "accepts KeyPairs" do expect do RbNaCl::Box.new(alice_key, bob_key) end.to_not raise_error end it "raises TypeError on a nil public key" do expect do RbNaCl::Box.new(nil, bobsk) end.to raise_error(TypeError) end it "raises RbNaCl::LengthError on an invalid public key" do expect do RbNaCl::Box.new("hello", bobsk) end.to raise_error(RbNaCl::LengthError, /Public key was 5 bytes \(Expected 32\)/) end it "raises TypeError on a nil secret key" do expect do RbNaCl::Box.new(alicepk, nil) end.to raise_error(TypeError) end it "raises RbNaCl::LengthError on an invalid secret key" do expect do RbNaCl::Box.new(alicepk, "hello") end.to raise_error(RbNaCl::LengthError, /Private key was 5 bytes \(Expected 32\)/) end end include_examples "box" do let(:box) { RbNaCl::Box.new(alicepk, bobsk) } end end rbnacl-7.1.2/spec/rbnacl/boxes/sealed_spec.rb000066400000000000000000000033601470351605300210770ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::SealedBox do let(:alicepk) { vector :alice_public } let(:alicesk) { vector :alice_private } let(:alice_pubkey) { RbNaCl::PublicKey.new(alicepk) } let(:alice_privkey) { RbNaCl::PrivateKey.new(alicesk) } context "new" do it "accepts public key strings" do expect do RbNaCl::SealedBox.from_public_key(alicepk) end.to_not raise_error end it "accepts public KeyPairs" do expect do RbNaCl::SealedBox.from_public_key(alice_pubkey) end.to_not raise_error end it "accepts private key strings" do expect do RbNaCl::SealedBox.from_private_key(alicepk) end.to_not raise_error end it "accepts private KeyPairs" do expect do RbNaCl::SealedBox.from_private_key(alice_privkey) end.to_not raise_error end it "raises TypeError on a nil public key" do expect do RbNaCl::SealedBox.from_public_key(nil) end.to raise_error(TypeError) end it "raises RbNaCl::LengthError on an invalid public key" do expect do RbNaCl::SealedBox.from_public_key("hello") end.to raise_error(RbNaCl::LengthError, /Public key was 5 bytes \(Expected 32\)/) end it "raises TypeError on a nil private key" do expect do RbNaCl::SealedBox.from_private_key(nil) end.to raise_error(TypeError) end it "raises RbNaCl::LengthError on an invalid private key" do expect do RbNaCl::SealedBox.from_private_key("hello") end.to raise_error(RbNaCl::LengthError, /Private key was 5 bytes \(Expected 32\)/) end end include_examples "sealed_box" do let(:box) { RbNaCl::SealedBox.new(alicepk, alicesk) } end end rbnacl-7.1.2/spec/rbnacl/group_element_spec.rb000066400000000000000000000017011470351605300213640ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::GroupElement do let(:alice_private) { vector :alice_private } let(:alice_public) { vector :alice_public } let(:bob_public) { vector :bob_public } let(:alice_mult_bob) { vector :alice_mult_bob } let(:degenerate_key) { RbNaCl::GroupElements::Curve25519::DEGENERATE_KEY } subject { described_class.new(bob_public) } it "multiplies integers with the base point" do expect(described_class.base.mult(alice_private).to_s).to eq alice_public end it "multiplies integers with arbitrary points" do expect(described_class.new(bob_public).mult(alice_private).to_s).to eq alice_mult_bob end it "serializes to bytes" do expect(subject.to_bytes).to eq bob_public end it "detects degenerate keys" do expect { described_class.new(degenerate_key).mult(alice_private) }.to raise_error RbNaCl::CryptoError end include_examples "serializable" end rbnacl-7.1.2/spec/rbnacl/hash/000077500000000000000000000000001470351605300161045ustar00rootroot00000000000000rbnacl-7.1.2/spec/rbnacl/hash/blake2b_spec.rb000066400000000000000000000115521470351605300207510ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::Hash::Blake2b do let(:reference_string) { vector :blake2b_message } let(:reference_string_hash) { vector :blake2b_digest } let(:empty_string_hash) { vector :blake2b_empty } it "calculates the correct hash for a reference string" do expect(RbNaCl::Hash.blake2b(reference_string)).to eq reference_string_hash end it "calculates the correct hash for an empty string" do expect(RbNaCl::Hash.blake2b("")).to eq empty_string_hash end context "arbitrary length message API" do let(:blake2b) { RbNaCl::Hash::Blake2b.new } it "calculates the correct hash for a reference string" do blake2b << reference_string expect(blake2b.digest).to eq reference_string_hash end it "calculates the correct hash for an empty string" do blake2b << "" expect(blake2b.digest).to eq empty_string_hash end it "raise CryptoError when digest called without reset / message" do expect { blake2b.digest }.to raise_error(RbNaCl::CryptoError) end it "calculates hash for empty string when digest called directly after reset" do blake2b.reset expect(blake2b.digest).to eq empty_string_hash end end context "keyed" do let(:reference_string) { vector :blake2b_keyed_message } let(:reference_key) { vector :blake2b_key } let(:reference_string_hash) { vector :blake2b_keyed_digest } it "calculates keyed hashes correctly" do expect(RbNaCl::Hash.blake2b(reference_string, key: reference_key)).to eq reference_string_hash end it "doesn't accept empty strings as a key" do expect { RbNaCl::Hash.blake2b(reference_string, key: "") }.to raise_error(RbNaCl::LengthError) end context "arbitrary length message API" do let(:blake2b) { RbNaCl::Hash::Blake2b.new(key: "") } let(:blake2b_wk) { RbNaCl::Hash::Blake2b.new(key: reference_key) } it "calculates keyed hashes correctly" do blake2b_wk << reference_string expect(blake2b_wk.digest).to eq reference_string_hash end it "doesn't accept empty strings as a key" do expect do blake2b << reference_string blake2b.digest end.to raise_error(RbNaCl::LengthError) end end end context "personalized" do let(:reference_string) { vector :blake2b_message } let(:reference_personal) { vector :blake2b_personal } let(:reference_personal_hash) { vector :blake2b_personal_digest } let(:reference_personal_short) { vector :blake2b_personal_short } let(:reference_personal_short_hash) { vector :blake2b_personal_short_digest } it "calculates personalised hashes correctly" do expect(RbNaCl::Hash.blake2b(reference_string, personal: reference_personal)).to eq reference_personal_hash end it "calculates personalised hashes correctly with a short personal" do expect(RbNaCl::Hash.blake2b(reference_string, personal: reference_personal_short)).to eq reference_personal_short_hash end context "arbitrary length message API" do let(:blake2b) { RbNaCl::Hash::Blake2b.new(personal: reference_personal) } let(:blake2b_sh) { RbNaCl::Hash::Blake2b.new(personal: reference_personal_short) } it "calculates personalised hashes correctly" do blake2b << reference_string expect(blake2b.digest).to eq reference_personal_hash end it "calculates personalised hashes correctly with a short personal" do blake2b_sh << reference_string expect(blake2b_sh.digest).to eq reference_personal_short_hash end end end context "salted" do let(:reference_string) { vector :blake2b_message } let(:reference_salt) { vector :blake2b_salt } let(:reference_salt_hash) { vector :blake2b_salt_digest } let(:reference_salt_short) { vector :blake2b_salt_short } let(:reference_salt_short_hash) { vector :blake2b_salt_short_digest } it "calculates saltised hashes correctly" do expect(RbNaCl::Hash.blake2b(reference_string, salt: reference_salt)).to eq reference_salt_hash end it "calculates saltised hashes correctly with a short salt" do expect(RbNaCl::Hash.blake2b(reference_string, salt: reference_salt_short)).to eq reference_salt_short_hash end context "arbitrary length message API" do let(:blake2b) { RbNaCl::Hash::Blake2b.new(salt: reference_salt) } let(:blake2b_sh) { RbNaCl::Hash::Blake2b.new(salt: reference_salt_short) } it "calculates saltised hashes correctly" do blake2b << reference_string expect(blake2b.digest).to eq reference_salt_hash end it "calculates saltised hashes correctly with a short salt" do blake2b_sh << reference_string expect(blake2b_sh.digest).to eq reference_salt_short_hash end end end end rbnacl-7.1.2/spec/rbnacl/hash_spec.rb000066400000000000000000000024001470351605300174370ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::Hash do context "sha256" do let(:reference_string) { vector :sha256_message } let(:reference_string_hash) { vector :sha256_digest } let(:empty_string_hash) { vector :sha256_empty } it "calculates the correct hash for a reference string" do expect(RbNaCl::Hash.sha256(reference_string)).to eq reference_string_hash end it "calculates the correct hash for an empty string" do expect(RbNaCl::Hash.sha256("")).to eq empty_string_hash end it "doesn't raise on a null byte" do expect { RbNaCl::Hash.sha256("\0") }.to_not raise_error end end context "sha512" do let(:reference_string) { vector :sha512_message } let(:reference_string_hash) { vector :sha512_digest } let(:empty_string_hash) { vector :sha512_empty } it "calculates the correct hash for a reference string" do expect(RbNaCl::Hash.sha512(reference_string)).to eq reference_string_hash end it "calculates the correct hash for an empty string" do expect(RbNaCl::Hash.sha512("")).to eq empty_string_hash end it "doesn't raise on a null byte" do expect { RbNaCl::Hash.sha512("\0") }.to_not raise_error end end end rbnacl-7.1.2/spec/rbnacl/hmac/000077500000000000000000000000001470351605300160715ustar00rootroot00000000000000rbnacl-7.1.2/spec/rbnacl/hmac/sha256_spec.rb000066400000000000000000000006111470351605300204360ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::HMAC::SHA256 do let(:key) { vector :auth_hmac_key } let(:message) { vector :auth_hmac_data } let(:tag) { vector :auth_hmacsha256_tag } let(:mult_tag) { vector :auth_hmacsha256_mult_tag } let(:wrong_key) { "key".encode("utf-8") } include_examples "HMAC" include_examples "authenticator" end rbnacl-7.1.2/spec/rbnacl/hmac/sha512256_spec.rb000066400000000000000000000006201470351605300206660ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::HMAC::SHA512256 do let(:key) { vector :auth_hmac_key } let(:message) { vector :auth_message } let(:tag) { vector :auth_hmacsha512256_tag } let(:mult_tag) { vector :auth_hmacsha512256_mult_tag } let(:wrong_key) { "key".encode("utf-8") } include_examples "HMAC" include_examples "authenticator" end rbnacl-7.1.2/spec/rbnacl/hmac/sha512_spec.rb000066400000000000000000000006111470351605300204310ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::HMAC::SHA512 do let(:key) { vector :auth_hmac_key } let(:message) { vector :auth_hmac_data } let(:tag) { vector :auth_hmacsha512_tag } let(:mult_tag) { vector :auth_hmacsha512_mult_tag } let(:wrong_key) { "key".encode("utf-8") } include_examples "HMAC" include_examples "authenticator" end rbnacl-7.1.2/spec/rbnacl/password_hash/000077500000000000000000000000001470351605300200265ustar00rootroot00000000000000rbnacl-7.1.2/spec/rbnacl/password_hash/argon2_spec.rb000066400000000000000000000056061470351605300225640ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true if RbNaCl::Sodium::Version::ARGON2_SUPPORTED RSpec.describe RbNaCl::PasswordHash::Argon2 do let(:argon2i_password) { vector :argon2i_password } let(:argon2i_salt) { vector :argon2i_salt } let(:argon2i_opslimit) { RbNaCl::TEST_VECTORS[:argon2i_opslimit] } let(:argon2i_memlimit) { RbNaCl::TEST_VECTORS[:argon2i_memlimit] } let(:argon2i_digest) { vector :argon2i_digest } let(:argon2i_outlen) { RbNaCl::TEST_VECTORS[:argon2i_outlen] } let(:argon2id_password) { vector :argon2id_password } let(:argon2id_salt) { vector :argon2id_salt } let(:argon2id_opslimit) { RbNaCl::TEST_VECTORS[:argon2id_opslimit] } let(:argon2id_memlimit) { RbNaCl::TEST_VECTORS[:argon2id_memlimit] } let(:argon2id_digest) { vector :argon2id_digest } let(:argon2id_outlen) { RbNaCl::TEST_VECTORS[:argon2id_outlen] } let(:str_ref_password) { RbNaCl::TEST_VECTORS[:argon2_str_passwd] } let(:str_ref_digest) { RbNaCl::TEST_VECTORS[:argon2_str_digest] } it "calculates the correct argon2i digest for a reference password/salt" do digest = RbNaCl::PasswordHash.argon2i( argon2i_password, argon2i_salt, argon2i_opslimit, argon2i_memlimit, argon2i_outlen ) expect(digest).to eq argon2i_digest end if RbNaCl::Sodium::Version::ARGON2_SUPPORTED it "calculates the correct argon2id digest for a reference password/salt" do digest = RbNaCl::PasswordHash.argon2id( argon2id_password, argon2id_salt, argon2id_opslimit, argon2id_memlimit, argon2id_outlen ) expect(digest).to eq argon2id_digest end it "calculates the correct argon2 default digest" do if RbNaCl::Sodium::Version.supported_version?("1.0.15") digest = RbNaCl::PasswordHash.argon2( argon2id_password, argon2id_salt, argon2id_opslimit, argon2id_memlimit, argon2id_outlen ) expect(digest).to eq argon2id_digest else digest = RbNaCl::PasswordHash.argon2( argon2i_password, argon2i_salt, argon2i_opslimit, argon2i_memlimit, argon2i_outlen ) expect(digest).to eq argon2i_digest end end end it "verifies password" do valid = RbNaCl::PasswordHash.argon2_valid?(str_ref_password, str_ref_digest) expect(valid).to eq true end it "creates digest string" do digest = RbNaCl::PasswordHash.argon2_str(str_ref_password) valid = RbNaCl::PasswordHash.argon2_valid?(str_ref_password, digest) expect(valid).to eq true end it "fails on invalid passwords" do valid = RbNaCl::PasswordHash.argon2_valid?("wrongpassword", str_ref_digest) expect(valid).to eq false end end end rbnacl-7.1.2/spec/rbnacl/password_hash/scrypt_spec.rb000066400000000000000000000015571470351605300227210ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::PasswordHash::SCrypt do let(:reference_password) { vector :scrypt_password } let(:reference_salt) { vector :scrypt_salt } let(:reference_opslimit) { RbNaCl::TEST_VECTORS[:scrypt_opslimit] } let(:reference_memlimit) { RbNaCl::TEST_VECTORS[:scrypt_memlimit] } let(:reference_digest) { vector :scrypt_digest } it "calculates the correct digest for a reference password/salt" do digest = RbNaCl::PasswordHash.scrypt( reference_password, reference_salt, reference_opslimit, reference_memlimit ) expect(digest).to eq reference_digest end it "calculates the correct digest using libsodium primitives" do digest = RbNaCl::PasswordHash.scrypt( reference_password, reference_salt ) expect(digest).to eq reference_digest end end rbnacl-7.1.2/spec/rbnacl/random_spec.rb000066400000000000000000000005031470351605300177760ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::Random do it "produces random bytes" do expect(RbNaCl::Random.random_bytes(16).bytesize).to eq(16) end it "produces different random bytes" do expect(RbNaCl::Random.random_bytes(16)).not_to eq(RbNaCl::Random.random_bytes(16)) end end rbnacl-7.1.2/spec/rbnacl/secret_box_spec.rb000066400000000000000000000010671470351605300206610ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::SecretBox do let(:key) { vector :secret_key } context "new" do it "accepts strings" do expect { RbNaCl::SecretBox.new(key) }.to_not raise_error end it "raises on a nil key" do expect { RbNaCl::SecretBox.new(nil) }.to raise_error(TypeError) end it "raises on a short key" do expect { RbNaCl::SecretBox.new("hello") }.to raise_error RbNaCl::LengthError end end include_examples "box" do let(:box) { RbNaCl::SecretBox.new(key) } end end rbnacl-7.1.2/spec/rbnacl/signatures/000077500000000000000000000000001470351605300173455ustar00rootroot00000000000000rbnacl-7.1.2/spec/rbnacl/signatures/ed25519/000077500000000000000000000000001470351605300203435ustar00rootroot00000000000000rbnacl-7.1.2/spec/rbnacl/signatures/ed25519/signing_key_spec.rb000066400000000000000000000027571470351605300242230ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::SigningKey do let(:signing_key) { vector :sign_private } let(:signing_keypair) { vector :sign_keypair } let(:message) { vector :sign_message } let(:signature) { vector :sign_signature } let(:curve25519_private_key) { vector :sign_curve25519_private } subject { described_class.new(signing_key) } it "generates keys" do expect(described_class.generate).to be_a described_class end it "signs messages as bytes" do expect(subject.sign(message)).to eq signature end it "signs messages, full version" do expect(subject.sign_attached(message)[0, RbNaCl::SigningKey.signature_bytes]).to eq signature expect(subject.sign_attached(message)[RbNaCl::SigningKey.signature_bytes, message.length]).to eq message end it "serializes to bytes" do expect(subject.to_bytes).to eq signing_key end it "serializes the internal signing key to bytes" do expect(subject.keypair_bytes.length).to eq 64 expect(subject.keypair_bytes).to eq signing_keypair end it "can be converted to curve25519 private key" do sk = subject.to_curve25519_private_key expect(sk).to be_a_kind_of RbNaCl::PrivateKey expect(sk.to_s).to eq curve25519_private_key end include_examples "key equality" do let(:key_bytes) { signing_key } let(:key) { described_class.new(key_bytes) } let(:other_key) { described_class.new("B" * 32) } end include_examples "serializable" end rbnacl-7.1.2/spec/rbnacl/signatures/ed25519/verify_key_spec.rb000066400000000000000000000041511470351605300240570ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::VerifyKey do let(:signing_key) { vector :sign_private } let(:verify_key) { vector :sign_public } let(:message) { vector :sign_message } let(:signature) { vector :sign_signature } let(:curve25519_public_key) { vector :sign_curve25519_public } let(:bad_signature) do sig = signature.dup sig[0] = (sig[0].ord + 1).chr sig end subject { RbNaCl::SigningKey.new(signing_key).verify_key } it "verifies correct signatures" do expect(subject.verify(signature, message)).to eq true end it "verifies correct signatures, full version" do expect(subject.verify_attached(signature + message)).to eq true end it "raises when asked to verify a bad signature" do expect { subject.verify(bad_signature, message) }.to raise_exception RbNaCl::BadSignatureError end it "raises when asked to verify a bad signature, full version" do expect { subject.verify_attached(bad_signature + message) }.to raise_exception RbNaCl::BadSignatureError end it "raises when asked to verify a short signature" do expect { subject.verify(bad_signature[0, 63], message) }.to raise_exception RbNaCl::LengthError end it "raises when asked to verify a nil signed message" do expect { subject.verify_attached(nil) }.to raise_exception RbNaCl::LengthError end it "raises when asked to verify too short signed message" do expect { subject.verify_attached(signature) }.to raise_exception RbNaCl::LengthError end it "serializes to bytes" do expect(subject.to_bytes).to eq verify_key end it "initializes from bytes" do expect(described_class.new(verify_key).to_s).to eq verify_key end it "can be converted to curve25519 public key" do pk = subject.to_curve25519_public_key expect(pk).to be_a_kind_of RbNaCl::PublicKey expect(pk.to_s).to eq curve25519_public_key end include_examples "key equality" do let(:key_bytes) { verify_key } let(:key) { described_class.new(verify_key) } let(:other_key) { described_class.new("B" * 32) } end include_examples "serializable" end rbnacl-7.1.2/spec/rbnacl/simple_box_spec.rb000066400000000000000000000037051470351605300206660ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::SimpleBox do let(:secret_key) { vector :secret_key } let(:secret_box) { RbNaCl::SecretBox.new(secret_key) } let(:alicepk) { vector :alice_public } let(:alicesk) { vector :alice_private } let(:bobpk) { vector :bob_public } let(:bobsk) { vector :bob_private } context "instantiation" do it "can be instantiated from an already existing box" do expect { described_class.new(secret_box) }.not_to raise_error end it "can be instantiated from a secret key" do expect(described_class.from_secret_key(secret_key)).to be_a described_class end it "raises TypeError when given a nil secret key" do expect { described_class.from_secret_key(nil) }.to raise_error(TypeError) end it "can be instantiated from a key-pair" do expect(described_class.from_keypair(alicepk, bobsk)).to be_a described_class end it "raises TypeError when given nil secret keys in the pair" do expect { described_class.from_keypair(nil, bobsk) }.to raise_error(TypeError) expect { described_class.from_keypair(alicepk, nil) }.to raise_error(TypeError) end end context "cryptography" do let(:nonce) { vector :box_nonce } let(:message) { vector :box_message } let(:ciphertext) { vector :box_ciphertext } let(:alice) { described_class.from_keypair(bobpk, alicesk) } let(:bob) { described_class.from_keypair(alicepk, bobsk) } describe "bob" do it "decrypts a message from alice" do alices_ciphertext = alice.encrypt(message) expect(bob.decrypt(alices_ciphertext)).to eql message end it "decrypts own message" do bobs_ciphertext = bob.encrypt(message) expect(bob.decrypt(bobs_ciphertext)).to eql message end it "decrypts a message with a 'random' nonce" do expect(bob.decrypt(nonce + ciphertext)).to eql message end end end end rbnacl-7.1.2/spec/rbnacl/sodium_spec.rb000066400000000000000000000026741470351605300200310ustar00rootroot00000000000000# frozen_string_literal: true RSpec.describe RbNaCl::Sodium do subject(:sodium_class) do class SodiumExtendedClass extend RbNaCl::Sodium sodium_type :auth sodium_primitive :hmacsha512 # sodium_constant :BYTES # sodium_constant :KEYBYTES end SodiumExtendedClass end context ".sodium_constant" do it "retrieves the libsodium constant" do sodium_class.sodium_constant :BYTES expect(sodium_class::BYTES).to eq(64) end context "with alternate constant name" do it "sets the alternate constant name" do sodium_class.sodium_constant :BYTES, name: :COOL_BYTES expect(sodium_class::COOL_BYTES).to eq(64) end end context "when libsodium does not define the constant" do it "raises an exception" do expect do sodium_class.sodium_constant :MIN_DANCING_PARTNERS end.to raise_error(FFI::NotFoundError) end end context "with fallback" do context "when libsodium defines the constant" do it "return the libsodium value" do sodium_class.sodium_constant :BYTES, fallback: 888 expect(sodium_class::BYTES).to eq(64) end end context "when libsodium does not define the constant" do it "uses the fallback" do sodium_class.sodium_constant :MAX_PANDAS, fallback: 24 expect(sodium_class::MAX_PANDAS).to eq(24) end end end end end rbnacl-7.1.2/spec/rbnacl/util_spec.rb000066400000000000000000000174111470351605300175010ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.describe RbNaCl::Util do context ".verify64" do let(:msg) { RbNaCl::Util.zeros(64) } let(:identical_msg) { RbNaCl::Util.zeros(64) } let(:other_msg) { RbNaCl::Util.zeros(63) + "\001" } let(:short_msg) { RbNaCl::Util.zeros(63) } let(:long_msg) { RbNaCl::Util.zeros(65) } it "confirms identical messages are identical" do expect(RbNaCl::Util.verify64(msg, identical_msg)).to be true end it "confirms non-identical messages are non-identical" do expect(RbNaCl::Util.verify64(msg, other_msg)).to be false expect(RbNaCl::Util.verify64(other_msg, msg)).to be false expect(RbNaCl::Util.verify64(short_msg, msg)).to be false expect(RbNaCl::Util.verify64(msg, short_msg)).to be false expect(RbNaCl::Util.verify64(long_msg, msg)).to be false expect(RbNaCl::Util.verify64(msg, long_msg)).to be false end end context ".verify64!" do let(:msg) { RbNaCl::Util.zeros(64) } let(:identical_msg) { RbNaCl::Util.zeros(64) } let(:other_msg) { RbNaCl::Util.zeros(63) + "\001" } let(:short_msg) { RbNaCl::Util.zeros(63) } let(:long_msg) { RbNaCl::Util.zeros(65) } it "confirms identical messages are identical" do expect(RbNaCl::Util.verify64!(msg, identical_msg)).to be true end it "confirms non-identical messages are non-identical" do expect(RbNaCl::Util.verify64!(msg, other_msg)).to be false expect(RbNaCl::Util.verify64!(other_msg, msg)).to be false end it "raises descriptively on a short message in position 1" do expect { RbNaCl::Util.verify64!(short_msg, msg) }.to raise_error(RbNaCl::LengthError) end it "raises descriptively on a short message in position 2" do expect { RbNaCl::Util.verify64!(msg, short_msg) }.to raise_error(RbNaCl::LengthError) end it "raises descriptively on a long message in position 1" do expect { RbNaCl::Util.verify64!(long_msg, msg) }.to raise_error(RbNaCl::LengthError) end it "raises descriptively on a long message in position 2" do expect { RbNaCl::Util.verify64!(msg, long_msg) }.to raise_error(RbNaCl::LengthError) end end context ".verify32!" do let(:msg) { RbNaCl::Util.zeros(32) } let(:identical_msg) { RbNaCl::Util.zeros(32) } let(:other_msg) { RbNaCl::Util.zeros(31) + "\001" } let(:short_msg) { RbNaCl::Util.zeros(31) } let(:long_msg) { RbNaCl::Util.zeros(33) } it "confirms identical messages are identical" do expect(RbNaCl::Util.verify32!(msg, identical_msg)).to be true end it "confirms non-identical messages are non-identical" do expect(RbNaCl::Util.verify32!(msg, other_msg)).to be false expect(RbNaCl::Util.verify32!(other_msg, msg)).to be false end it "raises descriptively on a short message in position 1" do expect { RbNaCl::Util.verify32!(short_msg, msg) }.to raise_error(RbNaCl::LengthError) end it "raises descriptively on a short message in position 2" do expect { RbNaCl::Util.verify32!(msg, short_msg) }.to raise_error(RbNaCl::LengthError) end it "raises descriptively on a long message in position 1" do expect { RbNaCl::Util.verify32!(long_msg, msg) }.to raise_error(RbNaCl::LengthError) end it "raises descriptively on a long message in position 2" do expect { RbNaCl::Util.verify32!(msg, long_msg) }.to raise_error(RbNaCl::LengthError) end end context ".verify32" do let(:msg) { RbNaCl::Util.zeros(32) } let(:identical_msg) { RbNaCl::Util.zeros(32) } let(:other_msg) { RbNaCl::Util.zeros(31) + "\001" } let(:short_msg) { RbNaCl::Util.zeros(31) } let(:long_msg) { RbNaCl::Util.zeros(33) } it "confirms identical messages are identical" do expect(RbNaCl::Util.verify32(msg, identical_msg)).to be true end it "confirms non-identical messages are non-identical" do expect(RbNaCl::Util.verify32(msg, other_msg)).to be false expect(RbNaCl::Util.verify32(other_msg, msg)).to be false expect(RbNaCl::Util.verify32(short_msg, msg)).to be false expect(RbNaCl::Util.verify32(msg, short_msg)).to be false expect(RbNaCl::Util.verify32(long_msg, msg)).to be false expect(RbNaCl::Util.verify32(msg, long_msg)).to be false end end context ".verify16!" do let(:msg) { RbNaCl::Util.zeros(16) } let(:identical_msg) { RbNaCl::Util.zeros(16) } let(:other_msg) { RbNaCl::Util.zeros(15) + "\001" } let(:short_msg) { RbNaCl::Util.zeros(15) } let(:long_msg) { RbNaCl::Util.zeros(17) } it "confirms identical messages are identical" do expect(RbNaCl::Util.verify16!(msg, identical_msg)).to be true end it "confirms non-identical messages are non-identical" do expect(RbNaCl::Util.verify16!(msg, other_msg)).to be false expect(RbNaCl::Util.verify16!(other_msg, msg)).to be false end it "raises descriptively on a short message in position 1" do expect { RbNaCl::Util.verify16!(short_msg, msg) }.to raise_error(RbNaCl::LengthError) end it "raises descriptively on a short message in position 2" do expect { RbNaCl::Util.verify16!(msg, short_msg) }.to raise_error(RbNaCl::LengthError) end it "raises descriptively on a long message in position 1" do expect { RbNaCl::Util.verify16!(long_msg, msg) }.to raise_error(RbNaCl::LengthError) end it "raises descriptively on a long message in position 2" do expect { RbNaCl::Util.verify16!(msg, long_msg) }.to raise_error(RbNaCl::LengthError) end end context ".verify16" do let(:msg) { RbNaCl::Util.zeros(16) } let(:identical_msg) { RbNaCl::Util.zeros(16) } let(:other_msg) { RbNaCl::Util.zeros(15) + "\001" } let(:short_msg) { RbNaCl::Util.zeros(15) } let(:long_msg) { RbNaCl::Util.zeros(17) } it "confirms identical messages are identical" do expect(RbNaCl::Util.verify16(msg, identical_msg)).to be true end it "confirms non-identical messages are non-identical" do expect(RbNaCl::Util.verify16(msg, other_msg)).to be false expect(RbNaCl::Util.verify16(other_msg, msg)).to be false expect(RbNaCl::Util.verify16(short_msg, msg)).to be false expect(RbNaCl::Util.verify16(msg, short_msg)).to be false expect(RbNaCl::Util.verify16(long_msg, msg)).to be false expect(RbNaCl::Util.verify16(msg, long_msg)).to be false end end context "check_length" do it "accepts strings of the correct length" do expect do RbNaCl::Util.check_length("A" * 4, 4, "Test String") end.not_to raise_error end it "rejects strings which are too short" do expect do RbNaCl::Util.check_length("A" * 3, 4, "Test String") end.to raise_error(RbNaCl::LengthError, "Test String was 3 bytes (Expected 4)") end it "rejects strings which are too long" do expect do RbNaCl::Util.check_length("A" * 5, 4, "Test String") end.to raise_error(RbNaCl::LengthError, "Test String was 5 bytes (Expected 4)") end it "rejects nil strings" do expect do RbNaCl::Util.check_length(nil, 4, "Test String") end.to raise_error(RbNaCl::LengthError, "Test String was nil (Expected 4)") end end context "check_string" do let(:example_string) { "foobar".dup.force_encoding("UTF-8") } it "raises EncodingError when given strings with non-BINARY encoding" do expect do RbNaCl::Util.check_string(example_string, example_string.bytesize, "encoding test") end.to raise_error(EncodingError) end end context "hex encoding" do let(:bytes) { [0xDE, 0xAD, 0xBE, 0xEF].pack("c*") } let(:hex) { "deadbeef" } it "encodes to hex with bin2hex" do expect(RbNaCl::Util.bin2hex(bytes)).to eq hex end it "decodes from hex with hex2bin" do expect(RbNaCl::Util.hex2bin(hex)).to eq bytes end end end rbnacl-7.1.2/spec/shared/000077500000000000000000000000001470351605300151665ustar00rootroot00000000000000rbnacl-7.1.2/spec/shared/aead.rb000066400000000000000000000061361470351605300164130ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.shared_examples "aead" do let(:corrupt_ciphertext) { ciphertext.succ } let(:trunc_ciphertext) { ciphertext[0, 20] } let(:invalid_nonce) { nonce[0, nonce.bytesize / 2] } # too short! let(:invalid_nonce_long) { nonce + nonce } # too long! let(:nonce_error_regex) { /Nonce.*(Expected #{aead.nonce_bytes})/ } let(:corrupt_ad) { ad.succ } let(:trunc_ad) { ad[0, ad.bytesize / 2] } let(:aead) { described_class.new(key) } context "new" do it "accepts strings" do expect { described_class.new(key) }.to_not raise_error end it "raises on a nil key" do expect { described_class.new(nil) }.to raise_error(TypeError) end it "raises on a short key" do expect { described_class.new("hello") }.to raise_error RbNaCl::LengthError end it "raises on a long key" do expect { described_class.new("hello" + key) }.to raise_error RbNaCl::LengthError end end context "encrypt" do it "encrypts a message" do expect(aead.encrypt(nonce, message, ad)).to eq ciphertext end it "raises on a short nonce" do expect do aead.encrypt(invalid_nonce, message, ad) end.to raise_error(RbNaCl::LengthError, nonce_error_regex) end it "raises on a long nonce" do expect do aead.encrypt(invalid_nonce_long, message, ad) end.to raise_error(RbNaCl::LengthError, nonce_error_regex) end it "works with an empty message" do expect do aead.encrypt(nonce, nil, ad) end.to_not raise_error end it "works with an empty additional data" do expect do aead.encrypt(nonce, message, nil) end.to_not raise_error end end context "decrypt" do it "decrypts a message" do expect(aead.decrypt(nonce, ciphertext, ad)).to eq message end it "raises on a truncated message to decrypt" do expect do aead.decrypt(nonce, trunc_ciphertext, ad) end.to raise_error(RbNaCl::CryptoError, /Decryption failed. Ciphertext failed verification./) end it "raises on a corrupt ciphertext" do expect do aead.decrypt(nonce, corrupt_ciphertext, ad) end.to raise_error(RbNaCl::CryptoError, /Decryption failed. Ciphertext failed verification./) end it "raises when the additional data is truncated" do expect do aead.decrypt(nonce, ciphertext, corrupt_ad) end.to raise_error(RbNaCl::CryptoError, /Decryption failed. Ciphertext failed verification./) end it "raises when the additional data is corrupt " do expect do aead.decrypt(nonce, ciphertext, trunc_ad) end.to raise_error(RbNaCl::CryptoError, /Decryption failed. Ciphertext failed verification./) end it "raises on a short nonce" do expect do aead.decrypt(invalid_nonce, message, ad) end.to raise_error(RbNaCl::LengthError, nonce_error_regex) end it "raises on a long nonce" do expect do aead.decrypt(invalid_nonce_long, message, ad) end.to raise_error(RbNaCl::LengthError, nonce_error_regex) end end end rbnacl-7.1.2/spec/shared/authenticator.rb000066400000000000000000000045121470351605300203670ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.shared_examples "authenticator" do context ".new" do it "accepts a key" do expect { described_class.new(key) }.to_not raise_error end it "requires a key" do expect { described_class.new }.to raise_error(ArgumentError) end it "raises TypeError on a nil key" do expect { described_class.new(nil) }.to raise_error(TypeError) end end context ".auth" do it "produces an authenticator" do expect(described_class.auth(key, message)).to eq tag end it "raises TypeError on a nil key" do expect { described_class.auth(nil, message) }.to raise_error(TypeError) end end context ".verify" do it "verify an authenticator" do expect(described_class.verify(key, tag, message)).to eq true end it "raises TypeError on a nil key" do expect { described_class.verify(nil, tag, message) }.to raise_error(TypeError) end it "fails to validate an invalid authenticator" do expect { described_class.verify(key, tag, message + "\0") }.to raise_error(RbNaCl::BadAuthenticatorError) end it "fails to validate a short authenticator" do expect { described_class.verify(key, tag[0, tag.bytesize - 2], message) }.to raise_error(RbNaCl::LengthError) end it "fails to validate a long authenticator" do expect { described_class.verify(key, tag + "\0", message) }.to raise_error(RbNaCl::LengthError) end end context "Instance methods" do let(:authenticator) { described_class.new(key) } context "#auth" do it "produces an authenticator" do expect(authenticator.auth(message)).to eq tag end end context "#verify" do it "verifies an authenticator" do expect(authenticator.verify(tag, message)).to be true end it "fails to validate an invalid authenticator" do expect { authenticator.verify(tag, message + "\0") }.to raise_error(RbNaCl::BadAuthenticatorError) end it "fails to validate a short authenticator" do expect { authenticator.verify(tag[0, tag.bytesize - 2], message) }.to raise_error(RbNaCl::LengthError) end it "fails to validate a long authenticator" do expect { authenticator.verify(tag + "\0", message) }.to raise_error(RbNaCl::LengthError) end end end end rbnacl-7.1.2/spec/shared/box.rb000066400000000000000000000034411470351605300163050ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.shared_examples "box" do let(:nonce) { vector :box_nonce } let(:invalid_nonce) { nonce[0, 12] } # too short! let(:invalid_nonce_long) { nonce + nonce } # too long! let(:message) { vector :box_message } let(:ciphertext) { vector :box_ciphertext } let(:nonce_error_regex) { /Nonce.*(Expected #{box.nonce_bytes})/ } let(:corrupt_ciphertext) { ciphertext[80] = " " } # picked at random by fair diceroll context "box" do it "encrypts a message" do expect(box.box(nonce, message)).to eq ciphertext end it "raises on a short nonce" do expect do box.box(invalid_nonce, message) end.to raise_error(RbNaCl::LengthError, nonce_error_regex) end it "raises on a long nonce" do expect do box.box(invalid_nonce_long, message) end.to raise_error(RbNaCl::LengthError, nonce_error_regex) end end context "open" do it "decrypts a message" do expect(box.open(nonce, ciphertext)).to eq message end it "raises on a truncated message to decrypt" do expect do box.open(nonce, ciphertext[0, 64]) end.to raise_error(RbNaCl::CryptoError, /Decryption failed. Ciphertext failed verification./) end it "raises on a corrupt ciphertext" do expect do box.open(nonce, corrupt_ciphertext) end.to raise_error(RbNaCl::CryptoError, /Decryption failed. Ciphertext failed verification./) end it "raises on a short nonce" do expect do box.open(invalid_nonce, message) end.to raise_error(RbNaCl::LengthError, nonce_error_regex) end it "raises on a long nonce" do expect do box.open(invalid_nonce_long, message) end.to raise_error(RbNaCl::LengthError, nonce_error_regex) end end end rbnacl-7.1.2/spec/shared/hmac.rb000066400000000000000000000025601470351605300164260ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.shared_examples "HMAC" do context ".new" do it "raises EncodingError on a key with wrong encoding" do expect { described_class.new(wrong_key) }.to raise_error(EncodingError) end it "raises LengthError when key is zero bytes" do expect { described_class.new("") }.to raise_error(::RbNaCl::LengthError) end end context ".auth" do it "raises EncodingError on a key with wrong encoding " do expect { described_class.auth(wrong_key, message) }.to raise_error(EncodingError) end end context ".verify" do it "raises EncodingError on a key with wrong encoding" do expect { described_class.verify(wrong_key, tag, message) }.to raise_error(EncodingError) end end context "Instance methods" do let(:authenticator) { described_class.new(key) } before(:each) { authenticator.update(message) } context "#update" do it "returns hexdigest when produces an authenticator" do expect(authenticator.update(message)).to eq mult_tag.unpack1("H*") end end context "#digest" do it "returns an authenticator" do expect(authenticator.digest).to eq tag end end context "#hexdigest" do it "returns hex authenticator" do expect(authenticator.hexdigest).to eq tag.unpack1("H*") end end end end rbnacl-7.1.2/spec/shared/key_equality.rb000066400000000000000000000015271470351605300202250ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.shared_examples "key equality" do context "equality" do it "equal keys are equal" do expect(described_class.new(key_bytes) == key).to be true end it "equal keys are equal to the string" do expect(key == key_bytes).to be true end it "keys are not equal to zero" do expect(key == RbNaCl::Util.zeros(32)).to be false end it "keys are not equal to another key" do expect(key == other_key).to be false end end context "lexicographic sorting" do it "can be compared lexicographically to a key smaller than it" do expect(key > RbNaCl::Util.zeros(32)).to be true end it "can be compared lexicographically to a key larger than it" do expect(described_class.new(RbNaCl::Util.zeros(32)) < key).to be true end end end rbnacl-7.1.2/spec/shared/sealed_box.rb000066400000000000000000000015301470351605300176170ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.shared_examples "sealed_box" do let(:message) { vector :box_message } let(:ciphertext) { vector :box_ciphertext } let(:corrupt_ciphertext) { ciphertext[80] = " " } # picked at random by fair diceroll context "box" do it "roundtrips" do ciphertext = box.box(message) expect(box.open(ciphertext)).to eq message end end context "open" do it "raises on a truncated message to decrypt" do expect do box.open(ciphertext[0, 64]) end.to raise_error(RbNaCl::CryptoError, /Decryption failed. Ciphertext failed verification./) end it "raises on a corrupt ciphertext" do expect do box.open(corrupt_ciphertext) end.to raise_error(RbNaCl::CryptoError, /Decryption failed. Ciphertext failed verification./) end end end rbnacl-7.1.2/spec/shared/serializable.rb000066400000000000000000000005641470351605300201660ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true RSpec.shared_examples "serializable" do context "serialization" do it "supports #to_s" do expect(subject.to_s).to be_a String end it "supports #to_str" do expect(subject.to_str).to be_a String end it "supports #inspect" do expect(subject.inspect).to be_a String end end end rbnacl-7.1.2/spec/spec_helper.rb000066400000000000000000000012121470351605300165320ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true require "json" require "coveralls" Coveralls.wear! # Run the specs prior to running the self-test $RBNACL_SELF_TEST = false require "bundler/setup" require "rbnacl" require "shared/box" require "shared/sealed_box" require "shared/authenticator" require "shared/key_equality" require "shared/serializable" require "shared/aead" require "shared/hmac" def vector(name) [RbNaCl::TEST_VECTORS[name]].pack("H*") end RSpec.configure do |config| config.after :all do # Run the self-test after all the specs have passed require "rbnacl/self_test" end config.disable_monkey_patching! end rbnacl-7.1.2/tasks/000077500000000000000000000000001470351605300141135ustar00rootroot00000000000000rbnacl-7.1.2/tasks/rspec.rake000066400000000000000000000002731470351605300160750ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true gem "rspec" require "rspec/core/rake_task" RSpec::Core::RakeTask.new RSpec::Core::RakeTask.new(:rcov) do |task| task.rcov = true end rbnacl-7.1.2/tasks/rubocop.rake000066400000000000000000000001451470351605300164300ustar00rootroot00000000000000# encoding: binary # frozen_string_literal: true require "rubocop/rake_task" RuboCop::RakeTask.new