├── .gitignore ├── .rspec ├── .rubocop.yml ├── .ruby-gemset ├── .travis.yml ├── CHANGELOG.md ├── COPYING ├── Gemfile ├── README.md ├── Rakefile ├── autotest └── discover.rb ├── certs ├── pbhogan.pem └── stakach.pem ├── checksum └── scrypt-3.0.6.gem.sha512 ├── ext ├── alt-impl │ ├── crypto_scrypt-nosse.c │ └── crypto_scrypt-ref.c └── scrypt │ ├── Rakefile │ ├── cpusupport.h │ ├── crypto_scrypt.c │ ├── crypto_scrypt.h │ ├── crypto_scrypt_internal.h │ ├── crypto_scrypt_smix.c │ ├── crypto_scrypt_smix.h │ ├── crypto_scrypt_smix_sse2.c │ ├── crypto_scrypt_smix_sse2.h │ ├── insecure_memzero.c │ ├── insecure_memzero.h │ ├── memlimit.c │ ├── memlimit.h │ ├── scrypt_calibrate.c │ ├── scrypt_calibrate.h │ ├── scrypt_ext.c │ ├── scrypt_ext.h │ ├── scrypt_platform.h │ ├── scryptenc_cpuperf.c │ ├── scryptenc_cpuperf.h │ ├── sha256.c │ ├── sha256.h │ ├── sysendian.h │ ├── warnp.c │ └── warnp.h ├── kdf-comparison.png ├── lib ├── scrypt.rb └── scrypt │ ├── engine.rb │ ├── errors.rb │ ├── password.rb │ ├── scrypt_ext.rb │ ├── security_utils.rb │ └── version.rb ├── scrypt.gemspec └── spec ├── scrypt ├── engine_spec.rb ├── password_spec.rb └── utils_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/c,ruby,macos,rubymine,visualstudiocode 3 | # Edit at https://www.gitignore.io/?templates=c,ruby,macos,rubymine,visualstudiocode 4 | 5 | ### C ### 6 | # Prerequisites 7 | *.d 8 | 9 | # Object files 10 | *.o 11 | *.ko 12 | *.obj 13 | *.elf 14 | 15 | # Linker output 16 | *.ilk 17 | *.map 18 | *.exp 19 | 20 | # Precompiled Headers 21 | *.gch 22 | *.pch 23 | 24 | # Libraries 25 | *.lib 26 | *.a 27 | *.la 28 | *.lo 29 | 30 | # Shared objects (inc. Windows DLLs) 31 | *.dll 32 | *.so 33 | *.so.* 34 | *.dylib 35 | 36 | # Executables 37 | *.exe 38 | *.out 39 | *.app 40 | *.i*86 41 | *.x86_64 42 | *.hex 43 | 44 | # Debug files 45 | *.dSYM/ 46 | *.su 47 | *.idb 48 | *.pdb 49 | 50 | # Kernel Module Compile Results 51 | *.mod* 52 | *.cmd 53 | .tmp_versions/ 54 | modules.order 55 | Module.symvers 56 | Mkfile.old 57 | dkms.conf 58 | 59 | ### macOS ### 60 | # General 61 | .DS_Store 62 | .AppleDouble 63 | .LSOverride 64 | 65 | # Icon must end with two \r 66 | Icon 67 | 68 | # Thumbnails 69 | ._* 70 | 71 | # Files that might appear in the root of a volume 72 | .DocumentRevisions-V100 73 | .fseventsd 74 | .Spotlight-V100 75 | .TemporaryItems 76 | .Trashes 77 | .VolumeIcon.icns 78 | .com.apple.timemachine.donotpresent 79 | 80 | # Directories potentially created on remote AFP share 81 | .AppleDB 82 | .AppleDesktop 83 | Network Trash Folder 84 | Temporary Items 85 | .apdisk 86 | 87 | ### Ruby ### 88 | *.gem 89 | *.rbc 90 | /.config 91 | /coverage/ 92 | /InstalledFiles 93 | /pkg/ 94 | /spec/reports/ 95 | /spec/examples.txt 96 | /test/tmp/ 97 | /test/version_tmp/ 98 | /tmp/ 99 | 100 | # Used by dotenv library to load environment variables. 101 | # .env 102 | 103 | # Ignore Byebug command history file. 104 | .byebug_history 105 | 106 | ## Specific to RubyMotion: 107 | .dat* 108 | .repl_history 109 | build/ 110 | *.bridgesupport 111 | build-iPhoneOS/ 112 | build-iPhoneSimulator/ 113 | 114 | ## Specific to RubyMotion (use of CocoaPods): 115 | # 116 | # We recommend against adding the Pods directory to your .gitignore. However 117 | # you should judge for yourself, the pros and cons are mentioned at: 118 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 119 | # vendor/Pods/ 120 | 121 | ## Documentation cache and generated files: 122 | /.yardoc/ 123 | /_yardoc/ 124 | /doc/ 125 | /rdoc/ 126 | 127 | ## Environment normalization: 128 | /.bundle/ 129 | /vendor/bundle 130 | /lib/bundler/man/ 131 | 132 | # for a library or gem, you might want to ignore these files since the code is 133 | # intended to run in multiple environments; otherwise, check them in: 134 | Gemfile.lock 135 | # .ruby-version 136 | # .ruby-gemset 137 | 138 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 139 | .rvmrc 140 | 141 | ### RubyMine ### 142 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 143 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 144 | 145 | # User-specific stuff 146 | .idea/**/workspace.xml 147 | .idea/**/tasks.xml 148 | .idea/**/usage.statistics.xml 149 | .idea/**/dictionaries 150 | .idea/**/shelf 151 | 152 | # Generated files 153 | .idea/**/contentModel.xml 154 | 155 | # Sensitive or high-churn files 156 | .idea/**/dataSources/ 157 | .idea/**/dataSources.ids 158 | .idea/**/dataSources.local.xml 159 | .idea/**/sqlDataSources.xml 160 | .idea/**/dynamic.xml 161 | .idea/**/uiDesigner.xml 162 | .idea/**/dbnavigator.xml 163 | 164 | # Gradle 165 | .idea/**/gradle.xml 166 | .idea/**/libraries 167 | 168 | # Gradle and Maven with auto-import 169 | # When using Gradle or Maven with auto-import, you should exclude module files, 170 | # since they will be recreated, and may cause churn. Uncomment if using 171 | # auto-import. 172 | # .idea/modules.xml 173 | # .idea/*.iml 174 | # .idea/modules 175 | # *.iml 176 | # *.ipr 177 | 178 | # CMake 179 | cmake-build-*/ 180 | 181 | # Mongo Explorer plugin 182 | .idea/**/mongoSettings.xml 183 | 184 | # File-based project format 185 | *.iws 186 | 187 | # IntelliJ 188 | out/ 189 | 190 | # mpeltonen/sbt-idea plugin 191 | .idea_modules/ 192 | 193 | # JIRA plugin 194 | atlassian-ide-plugin.xml 195 | 196 | # Cursive Clojure plugin 197 | .idea/replstate.xml 198 | 199 | # Crashlytics plugin (for Android Studio and IntelliJ) 200 | com_crashlytics_export_strings.xml 201 | crashlytics.properties 202 | crashlytics-build.properties 203 | fabric.properties 204 | 205 | # Editor-based Rest Client 206 | .idea/httpRequests 207 | 208 | # Android studio 3.1+ serialized cache file 209 | .idea/caches/build_file_checksums.ser 210 | 211 | ### RubyMine Patch ### 212 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 213 | 214 | # *.iml 215 | # modules.xml 216 | # .idea/misc.xml 217 | # *.ipr 218 | 219 | # Sonarlint plugin 220 | .idea/**/sonarlint/ 221 | 222 | # SonarQube Plugin 223 | .idea/**/sonarIssues.xml 224 | 225 | # Markdown Navigator plugin 226 | .idea/**/markdown-navigator.xml 227 | .idea/**/markdown-navigator/ 228 | 229 | ### VisualStudioCode ### 230 | .vscode/* 231 | # !.vscode/settings.json 232 | # !.vscode/tasks.json 233 | # !.vscode/launch.json 234 | # !.vscode/extensions.json 235 | 236 | ### VisualStudioCode Patch ### 237 | # Ignore all local history of files 238 | .history 239 | 240 | # End of https://www.gitignore.io/api/c,ruby,macos,rubymine,visualstudiocode 241 | 242 | *.bundle 243 | /.idea 244 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --colour 2 | --backtrace 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | 2 | # require: rubocop-rspec 3 | 4 | require: 5 | - rubocop-gitlab-security 6 | - rubocop-performance 7 | 8 | AllCops: 9 | Include: 10 | - Rakefile 11 | - lib/**/*.rb 12 | - lib/**/*.rake 13 | 14 | Exclude: 15 | - 'bin/**/*' 16 | - 'db/**/*.rb' 17 | - 'tmp/**/*' 18 | - 'vendor/**/*.rb' 19 | 20 | TargetRubyVersion: 2.3 21 | 22 | BlockLength: 23 | Max: 70 24 | 25 | MethodLength: 26 | Max: 40 27 | 28 | Metrics/AbcSize: 29 | Enabled: false 30 | 31 | Metrics/LineLength: 32 | Enabled: false 33 | 34 | Layout/IndentHeredoc: 35 | EnforcedStyle: powerpack 36 | 37 | Style/ClassAndModuleChildren: 38 | Enabled: false 39 | 40 | Style/Documentation: 41 | Enabled: false 42 | 43 | Style/Encoding: 44 | Enabled: true 45 | 46 | Style/FrozenStringLiteralComment: 47 | EnforcedStyle: always -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | scrypt -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | language: ruby 3 | rvm: 4 | - jruby-head 5 | - jruby-19mode 6 | - jruby-9.1.17.0 7 | - rbx-3 8 | - rbx-4 9 | - ruby-head 10 | - ruby-1.9.3-p551 11 | - ruby-2.1.10 12 | - ruby-2.2.10 13 | - ruby-2.3.8 14 | - ruby-2.4.9 15 | - ruby-2.5.7 16 | - ruby-2.6.5 17 | - ruby-2.7.0-preview1 18 | - truffleruby 19 | matrix: 20 | allow_failures: 21 | - rvm: rbx-3 22 | - rvm: rbx-4 23 | - rvm: ruby-head 24 | - rvm: jruby-head 25 | - rvm: truffleruby 26 | sudo: required -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 3.0.7 2 | ----- 3 | 4 | Changes: 5 | 6 | * Replaced `scanf` usage to avoid the need for a runtime dependency with the upcoming Ruby 2.7. 7 | * **Development:** Added Rubocop and rules to the project. 8 | * Refactored: 9 | * Extracted (organized) `Engine`, `Errors` and `Password` class/modules into dedicated files in `scrypt` sub-directory. 10 | * Logic and syntax cleanup and formatting. 11 | 12 | 3.0.6 13 | ----- 14 | Fixed: 15 | 16 | * Expanded complication flags in support of macOS Mojave. 17 | 18 | 3.0.5 19 | ----- 20 | 21 | Changes: 22 | 23 | * Make `rake` development dependency not runtime 24 | 25 | 3.0.4 26 | ----- 27 | 28 | Fixed: 29 | 30 | * Compilation on Archlinux 31 | 32 | 3.0.3 33 | ----- 34 | 35 | Fixed: 36 | 37 | * ~Compilation on Archlinux~ 38 | 39 | 40 | 3.0.2 41 | ----- 42 | 43 | Fixed: 44 | 45 | * ~~Compilation on Archlinux~~ 46 | 47 | 48 | 3.0.1 49 | ----- 50 | 51 | Fixed: 52 | 53 | * Windows support was broken in 3.0.0 54 | 55 | 56 | 3.0.0 57 | ----- 58 | 59 | Breaking Changes: 60 | 61 | * None 62 | 63 | Added: 64 | 65 | * Updated of core scrypt ext code: https://github.com/pbhogan/scrypt/pull/53 66 | * Support for platforms other than x86 such as ARM 67 | 68 | 2.1.1 69 | ----- 70 | 71 | Changes: 72 | 73 | * Uses more secure defaults: Increased max_mem from 1MB to 16MB, and salt_len from 8 to 32 bytes. 74 | * See discussion at https://github.com/pbhogan/scrypt/issues/25 75 | 76 | 2.0.1 77 | ----- 78 | 79 | Changes: 80 | * Adds a `:cost` option for specifying a cost string (e.g. `'400$8$19$'`) from the `calibrate` method 81 | (https://github.com/pbhogan/scrypt/commit/95ce6e3e37f4b2e8681a544713bfe783d2d69466) 82 | 83 | 2.0.0 84 | ----- 85 | 86 | Breaking Changes: 87 | 88 | * `SCrypt::Password#hash` has been renamed to `#checksum` 89 | (https://github.com/pbhogan/scrypt/commit/a1a60e06ec9d863c3156ac06fda32ce82cddd759) 90 | 91 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright 2010 Patrick Hogan 2 | 3 | Original implementation of scrypt by Colin Percival. 4 | This product includes software developed by Coda Hale. 5 | 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 1. Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 3. The name of the author may not be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | gemspec 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | scrypt [![Build Status](https://secure.travis-ci.org/pbhogan/scrypt.svg)](http://travis-ci.org/pbhogan/scrypt) 2 | ====== 3 | 4 | The scrypt key derivation function is designed to be far more secure against hardware brute-force attacks than alternative functions such as PBKDF2 or bcrypt. 5 | 6 | * http://www.tarsnap.com/scrypt.html 7 | * http://github.com/pbhogan/scrypt 8 | 9 | ## Why you should use scrypt 10 | 11 | ![KDF comparison](https://github.com/tarcieri/scrypt/raw/modern-readme/kdf-comparison.png) 12 | 13 | The designers of scrypt estimate that on modern (2009) hardware, if 5 seconds are spent computing a derived key, the cost of a hardware brute-force attack against scrypt is roughly 4000 times greater than the cost of a similar attack against bcrypt (to find the same password), and 20000 times greater than a similar attack against PBKDF2. 14 | 15 | ## How to install scrypt 16 | 17 | ``` 18 | gem install scrypt 19 | ``` 20 | 21 | ## How to use scrypt 22 | 23 | It works pretty similarly to ruby-bcrypt with a few minor differences, especially where the cost factor is concerned. 24 | 25 | ```ruby 26 | require "scrypt" 27 | 28 | # hash a user's password 29 | password = SCrypt::Password.create("my grand secret") 30 | # => "400$8$36$78f4ae6983f76119$37ec6ce55a2b928dc56ff9a7d0cdafbd7dbde49d9282c38a40b1434e88f24cf5" 31 | 32 | # compare to strings 33 | password == "my grand secret" # => true 34 | password == "a paltry guess" # => false 35 | ``` 36 | 37 | Password.create takes five options which will determine the key length and salt size, as well as the cost limits of the computation: 38 | 39 | * `:key_len` specifies the length in bytes of the key you want to generate. The default is 32 bytes (256 bits). Minimum is 16 bytes (128 bits). Maximum is 512 bytes (4096 bits). 40 | * `:salt_size` specifies the size in bytes of the random salt you want to generate. The default and maximum is 32 bytes (256 bits). Minimum is 8 bytes (64 bits). 41 | * `:max_time` specifies the maximum number of seconds the computation should take. 42 | * `:max_mem` specifies the maximum number of bytes the computation should take. A value of 0 specifies no upper limit. The minimum is always 1 MB. 43 | * `:max_memfrac` specifies the maximum memory in a fraction of available resources to use. Any value equal to 0 or greater than 0.5 will result in 0.5 being used. 44 | * `:cost` specifies a cost string (e.g. `'400$8$19$'`) from the `calibrate` method. The `:max_*` options will be ignored if this option is given, or if `calibrate!` has been called. 45 | 46 | Default options will result in calculation time of approx. 200 ms with 16 MB memory use. 47 | 48 | ## Other things you can do 49 | 50 | ```ruby 51 | require "scrypt" 52 | 53 | SCrypt::Engine.calibrate 54 | # => "400$8$25$" 55 | 56 | salt = SCrypt::Engine.generate_salt 57 | # => "400$8$26$b62e0f787a5fc373" 58 | 59 | SCrypt::Engine.hash_secret "my grand secret", salt 60 | # => "400$8$26$b62e0f787a5fc373$0399ccd4fa26642d92741b17c366b7f6bd12ccea5214987af445d2bed97bc6a2" 61 | 62 | SCrypt::Engine.calibrate!(max_mem: 16 * 1024 * 1024) 63 | # => "4000$8$4$" 64 | 65 | SCrypt::Engine.generate_salt 66 | # => "4000$8$4$c6d101522d3cb045" 67 | ``` 68 | 69 | ## Usage in Rails (and the like) 70 | 71 | ```ruby 72 | # store it safely in the user model 73 | user.update_attribute(:password, SCrypt::Password.create("my grand secret")) 74 | 75 | # read it back later 76 | user.reload! 77 | password = SCrypt::Password.new(user.password) 78 | password == "my grand secret" # => true 79 | ``` 80 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler/setup' 4 | require 'bundler/gem_tasks' 5 | 6 | require 'rake' 7 | require 'rake/clean' 8 | 9 | require 'rspec/core/rake_task' 10 | 11 | require 'ffi' 12 | require 'ffi-compiler/compile_task' 13 | 14 | require 'digest/sha2' 15 | require './lib/scrypt/version' 16 | 17 | require 'rubygems' 18 | require 'rubygems/package_task' 19 | 20 | require 'rdoc/task' 21 | 22 | task default: [:clean, :compile_ffi, :spec] 23 | 24 | desc 'clean, make and run specs' 25 | task :spec do 26 | RSpec::Core::RakeTask.new 27 | end 28 | 29 | desc 'generate checksum' 30 | task :checksum do 31 | built_gem_path = "pkg/scrypt-#{SCrypt::VERSION}.gem" 32 | checksum = Digest::SHA512.new.hexdigest(File.read(built_gem_path)) 33 | checksum_path = "checksum/scrypt-#{SCrypt::VERSION}.gem.sha512" 34 | File.open(checksum_path, 'w') { |f| f.write(checksum) } 35 | end 36 | 37 | desc 'FFI compiler' 38 | namespace 'ffi-compiler' do 39 | FFI::Compiler::CompileTask.new('ext/scrypt/scrypt_ext') do |t| 40 | target_cpu = RbConfig::CONFIG['target_cpu'] 41 | 42 | t.cflags << '-Wall -std=c99' 43 | t.cflags << '-msse -msse2' if t.platform.arch.include? '86' 44 | t.cflags << '-D_GNU_SOURCE=1' if RbConfig::CONFIG['host_os'].downcase =~ /mingw/ 45 | t.cflags << '-D_POSIX_C_SOURCE=200809L' if RbConfig::CONFIG['host_os'].downcase =~ /linux/ 46 | 47 | if 1.size == 4 && target_cpu =~ /i386|x86_32/ && t.platform.mac? 48 | t.cflags << '-arch i386' 49 | t.ldflags << '-arch i386' 50 | elsif 1.size == 8 && target_cpu =~ /i686|x86_64/ && t.platform.mac? 51 | t.cflags << '-arch x86_64' 52 | t.ldflags << '-arch x86_64' 53 | end 54 | 55 | t.add_define 'WINDOWS_OS' if FFI::Platform.windows? 56 | end 57 | end 58 | task compile_ffi: ['ffi-compiler:default'] 59 | 60 | CLEAN.include('ext/scrypt/*{.o,.log,.so,.bundle}') 61 | CLEAN.include('lib/**/*{.o,.log,.so,.bundle}') 62 | 63 | desc 'Generate RDoc' 64 | rd = Rake::RDocTask.new do |rdoc| 65 | rdoc.rdoc_dir = 'doc/rdoc' 66 | rdoc.options << '--title' << 'scrypt-ruby' << '--line-numbers' << '--inline-source' << '--main' << 'README' 67 | rdoc.template = ENV['TEMPLATE'] if ENV['TEMPLATE'] 68 | rdoc.rdoc_files.include('COPYING', 'lib/**/*.rb') 69 | end 70 | 71 | desc 'Run all specs' 72 | RSpec::Core::RakeTask.new do |_t| 73 | rspec_opts = ['--colour', '--backtrace'] 74 | end 75 | 76 | def gem_spec 77 | @gem_spec ||= Gem::Specification.load('scrypt.gemspec') 78 | end 79 | 80 | Gem::PackageTask.new(gem_spec) do |pkg| 81 | pkg.need_zip = true 82 | pkg.need_tar = true 83 | pkg.package_dir = 'pkg' 84 | end 85 | -------------------------------------------------------------------------------- /autotest/discover.rb: -------------------------------------------------------------------------------- 1 | Autotest.add_discovery { "rspec2" } -------------------------------------------------------------------------------- /certs/pbhogan.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEbDCCAtSgAwIBAgIBATANBgkqhkiG9w0BAQsFADA+MRAwDgYDVQQDDAdwYmhv 3 | Z2FuMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNjb20w 4 | HhcNMjQwNjA0MTUwOTUzWhcNMjUwNjA0MTUwOTUzWjA+MRAwDgYDVQQDDAdwYmhv 5 | Z2FuMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNjb20w 6 | ggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCevDHynbqCJNhCJjk+S1eV 7 | ow5qEIR4CexuOe+JQ0Rs4parAWlvYFqsKfzey7daM4ZHswZ0UC0KlOUWkqqyMLEs 8 | IOYCfD5VNW8hOw491wcqk38Yg4cAgXl7g3fbyryAvXJ1IxCeQkgPUBtBafnhCkYL 9 | Ql5f0/ie3beNqIf3hurH7Q/gOhFTwfzKXO3O5bAbb+ooQ+XqshVe4NPdxxLK5bgM 10 | n1E6FtFhuiY4OuNpimuaWxO/dzj1/qQrXrXwTaEOyP38cpxoUlxWujKETqLGYdmP 11 | jCyhdOivYTH9Jw+0C/IvZm7xikM5Dy+e8+BQU115NP7KTp3oTJrpa6gr6M6YUNFL 12 | UhBWm0OkwfvaCj10X/CiYtekuWmuV3MCf0qKEUSVSg3uQoKxH1MwKvhWX7oHhL/g 13 | pQ34cAagq58aQqMPCnOLBcpnjkHNdCECYssPMv/x8Zw2aAJm0OLq3RsdQ4mqXXXV 14 | 5iYqiCmeKEM6EoFtQ45w5euLhxuEZB61+fPe0ZBwtzECAwEAAaN1MHMwCQYDVR0T 15 | BAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFOZb4JOehkRESKP33BvbIDmOtQSN 16 | MBwGA1UdEQQVMBOBEXBiaG9nYW5AZ21haWwuY29tMBwGA1UdEgQVMBOBEXBiaG9n 17 | YW5AZ21haWwuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQAOMv+VFnM3VYGOXvkXKZIQ 18 | 1U9WNeFdoEErMT1UNJ2RUXrq74wLcNFHuTmpt1CiqvhEPKBPoro3UaBo8XOcLqOo 19 | c9pMZ8Od1zjmiwbMZoVJz7rzxy+/uG8CF8qlBh84B+L7M5HbhZBA0+M4tlmA24pf 20 | gsC4RXZICOb0IOt++HK+roi0iiXqtc7k1lFc9wvrNmQmg5ehqnIJduH7VLE4DXeR 21 | gFsk4zW1CsPxhNJGTUJawCcRDX3gS/dv1xa4+WaOFbG+pT0kVH1vFWBd6ylQgzOS 22 | GoK4s/sTBfyITuo91NPV8+NpdcOrzaZUmdO3i+dox2JR01OXRSaapuRTn8CmjGPq 23 | DvDKDJVWX/gAm+wYW871bYbzYtoPGrLO16fzYBKbwBDDHxxW2ju1CdM1PGR9fRVp 24 | j9xWOu4Z1nHLCxQxv+h4jQqTUXr6QS0Aei4heTJEH85yXqdgsn2EKsTMC1vAbBGR 25 | 2SIh/w6kd92reXNpKv+PzBa+yFT5pS7f+6CfMC8XdJE= 26 | -----END CERTIFICATE----- 27 | -------------------------------------------------------------------------------- /certs/stakach.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEfDCCAuSgAwIBAgIBATANBgkqhkiG9w0BAQsFADBCMQ4wDAYDVQQDDAVzdGV2 3 | ZTEbMBkGCgmSJomT8ixkARkWC2FjYXByb2plY3RzMRMwEQYKCZImiZPyLGQBGRYD 4 | Y29tMB4XDTE5MTExMzIzMDMwMFoXDTIwMTExMjIzMDMwMFowQjEOMAwGA1UEAwwF 5 | c3RldmUxGzAZBgoJkiaJk/IsZAEZFgthY2Fwcm9qZWN0czETMBEGCgmSJomT8ixk 6 | ARkWA2NvbTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALtarCg2Ux+m 7 | XjcGQ6XVxRbVwwVUxGWIBfpKXzq23WOXk0NkRooyYLuxSfkA/PFVd5OLZTMP+ULr 8 | KgM9w7+xR/Xhs/qxib/84u54H8rqHTCozYmldR5QpYTwsB4BeG0HpSbD0PGL+4N+ 9 | oa50wRyvwVBAZMG4F4QYUGnQlwBpLSm4Fhm6xhKqD9DDhbS5jgIg/S3Cr4dqghUG 10 | kqsIGjKd6X9wIOIqF1IWLZkXiwN1IcKCJ9FO2iTBEo7UidJXROO5xs5D0Vr3iyiw 11 | F3tmhpq1C7KkXkv0AxAxRK3SmdpIiagRukvdNFEAcpkgX6qUg62G8KMRGc3dP9lx 12 | tBP8IonLEcpLktQakuqsV4YETQaKQb5F4WADxh1tvIPcYJUxHsw3sdHZeDywT3De 13 | LPCNTbuBseIF33hj2qiZ77XMusgVxiqG1eaCD0X58zeVTd7ZDZUFuVKlgAudhyOi 14 | O30rMiCHNIchQqwVNLah0Tu4KAF7PGAwJhu01qMXOEl9WCEtApOS6wIDAQABo30w 15 | ezAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUjrc6E0haseLehiw2 16 | JME0lZzbYKMwIAYDVR0RBBkwF4EVc3RldmVAYWNhcHJvamVjdHMuY29tMCAGA1Ud 17 | EgQZMBeBFXN0ZXZlQGFjYXByb2plY3RzLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEA 18 | fpmwkaIoCUA8A5IDHTcGWDX5gFYwhrRLMPwvdbU3r9RUeo7slWjek1OCAH4gyLUM 19 | K+OeWIYyQjOzeRHllNapY3AnOWbwXX7rVrYa0OxFd8JgXgVS/XJR4elzNJ0lb8En 20 | szSDkj4xl2Yn7FDZBsT+Oq19zMKFZNSF3SYumTuLMq3AdJa3vO2Gg4I1r8oSfZBB 21 | 5V81o2GU9YTGCNrl57dmq+Iop1qVU9jF60wEXyiOz/Fkhvk+kdz2PveH8nhlpBiw 22 | t3kOzg645P903giemoqlYZJ1XTmBqHLhflfTSxNie6my4izqFQgB9UxtUeesRtaJ 23 | 5y48Vz2twr2OQfw+1lM//SY/H9rPJkaOPDM7AlPodnZvYrr1hAlwXUebgmOq+Mvm 24 | 13PWwCGItI0lMBPfAfadtZKJQNvzl4K4Iq76ksQy3tobcrYw1r4cKTyqvrrrKhWn 25 | 93B950TkkA8h64SLwNEzV3ayjvGKTI95l0cz0B1STPIwvQecQI2j1y8/DzyztNXO 26 | -----END CERTIFICATE----- 27 | -------------------------------------------------------------------------------- /checksum/scrypt-3.0.6.gem.sha512: -------------------------------------------------------------------------------- 1 | fb1b89bddfd5fa440994aad7f3edc6cce588c41018bf60ba82eab927863e243025c2e25094be2dfefdbe21a022dec62bdd072284ff83e472071791ff69bcb949 -------------------------------------------------------------------------------- /ext/alt-impl/crypto_scrypt-nosse.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2009 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * This file was originally written by Colin Percival as part of the Tarsnap 27 | * online backup system. 28 | */ 29 | #include "scrypt_platform.h" 30 | 31 | #include 32 | #ifndef __MINGW32__ 33 | #include 34 | #endif 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include "sha256.h" 42 | #include "sysendian.h" 43 | 44 | #include "crypto_scrypt.h" 45 | 46 | static void blkcpy(void *, void *, size_t); 47 | static void blkxor(void *, void *, size_t); 48 | static void salsa20_8(uint32_t[16]); 49 | static void blockmix_salsa8(uint32_t *, uint32_t *, uint32_t *, size_t); 50 | static uint64_t integerify(void *, size_t); 51 | static void smix(uint8_t *, size_t, uint64_t, uint32_t *, uint32_t *); 52 | 53 | static void 54 | blkcpy(void * dest, void * src, size_t len) 55 | { 56 | size_t * D = dest; 57 | size_t * S = src; 58 | size_t L = len / sizeof(size_t); 59 | size_t i; 60 | 61 | for (i = 0; i < L; i++) 62 | D[i] = S[i]; 63 | } 64 | 65 | static void 66 | blkxor(void * dest, void * src, size_t len) 67 | { 68 | size_t * D = dest; 69 | size_t * S = src; 70 | size_t L = len / sizeof(size_t); 71 | size_t i; 72 | 73 | for (i = 0; i < L; i++) 74 | D[i] ^= S[i]; 75 | } 76 | 77 | /** 78 | * salsa20_8(B): 79 | * Apply the salsa20/8 core to the provided block. 80 | */ 81 | static void 82 | salsa20_8(uint32_t B[16]) 83 | { 84 | uint32_t x[16]; 85 | size_t i; 86 | 87 | blkcpy(x, B, 64); 88 | for (i = 0; i < 8; i += 2) { 89 | #define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) 90 | /* Operate on columns. */ 91 | x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); 92 | x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); 93 | 94 | x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); 95 | x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); 96 | 97 | x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); 98 | x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); 99 | 100 | x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); 101 | x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); 102 | 103 | /* Operate on rows. */ 104 | x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); 105 | x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); 106 | 107 | x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); 108 | x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); 109 | 110 | x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); 111 | x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); 112 | 113 | x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); 114 | x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); 115 | #undef R 116 | } 117 | for (i = 0; i < 16; i++) 118 | B[i] += x[i]; 119 | } 120 | 121 | /** 122 | * blockmix_salsa8(Bin, Bout, X, r): 123 | * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r 124 | * bytes in length; the output Bout must also be the same size. The 125 | * temporary space X must be 64 bytes. 126 | */ 127 | static void 128 | blockmix_salsa8(uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r) 129 | { 130 | size_t i; 131 | 132 | /* 1: X <-- B_{2r - 1} */ 133 | blkcpy(X, &Bin[(2 * r - 1) * 16], 64); 134 | 135 | /* 2: for i = 0 to 2r - 1 do */ 136 | for (i = 0; i < 2 * r; i += 2) { 137 | /* 3: X <-- H(X \xor B_i) */ 138 | blkxor(X, &Bin[i * 16], 64); 139 | salsa20_8(X); 140 | 141 | /* 4: Y_i <-- X */ 142 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ 143 | blkcpy(&Bout[i * 8], X, 64); 144 | 145 | /* 3: X <-- H(X \xor B_i) */ 146 | blkxor(X, &Bin[i * 16 + 16], 64); 147 | salsa20_8(X); 148 | 149 | /* 4: Y_i <-- X */ 150 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ 151 | blkcpy(&Bout[i * 8 + r * 16], X, 64); 152 | } 153 | } 154 | 155 | /** 156 | * integerify(B, r): 157 | * Return the result of parsing B_{2r-1} as a little-endian integer. 158 | */ 159 | static uint64_t 160 | integerify(void * B, size_t r) 161 | { 162 | uint32_t * X = (void *)((uintptr_t)(B) + (2 * r - 1) * 64); 163 | 164 | return (((uint64_t)(X[1]) << 32) + X[0]); 165 | } 166 | 167 | /** 168 | * smix(B, r, N, V, XY): 169 | * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; 170 | * the temporary storage V must be 128rN bytes in length; the temporary 171 | * storage XY must be 256r + 64 bytes in length. The value N must be a 172 | * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a 173 | * multiple of 64 bytes. 174 | */ 175 | static void 176 | smix(uint8_t * B, size_t r, uint64_t N, uint32_t * V, uint32_t * XY) 177 | { 178 | uint32_t * X = XY; 179 | uint32_t * Y = &XY[32 * r]; 180 | uint32_t * Z = &XY[64 * r]; 181 | uint64_t i; 182 | uint64_t j; 183 | size_t k; 184 | 185 | /* 1: X <-- B */ 186 | for (k = 0; k < 32 * r; k++) 187 | X[k] = le32dec(&B[4 * k]); 188 | 189 | /* 2: for i = 0 to N - 1 do */ 190 | for (i = 0; i < N; i += 2) { 191 | /* 3: V_i <-- X */ 192 | blkcpy(&V[i * (32 * r)], X, 128 * r); 193 | 194 | /* 4: X <-- H(X) */ 195 | blockmix_salsa8(X, Y, Z, r); 196 | 197 | /* 3: V_i <-- X */ 198 | blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r); 199 | 200 | /* 4: X <-- H(X) */ 201 | blockmix_salsa8(Y, X, Z, r); 202 | } 203 | 204 | /* 6: for i = 0 to N - 1 do */ 205 | for (i = 0; i < N; i += 2) { 206 | /* 7: j <-- Integerify(X) mod N */ 207 | j = integerify(X, r) & (N - 1); 208 | 209 | /* 8: X <-- H(X \xor V_j) */ 210 | blkxor(X, &V[j * (32 * r)], 128 * r); 211 | blockmix_salsa8(X, Y, Z, r); 212 | 213 | /* 7: j <-- Integerify(X) mod N */ 214 | j = integerify(Y, r) & (N - 1); 215 | 216 | /* 8: X <-- H(X \xor V_j) */ 217 | blkxor(Y, &V[j * (32 * r)], 128 * r); 218 | blockmix_salsa8(Y, X, Z, r); 219 | } 220 | 221 | /* 10: B' <-- X */ 222 | for (k = 0; k < 32 * r; k++) 223 | le32enc(&B[4 * k], X[k]); 224 | } 225 | 226 | /** 227 | * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): 228 | * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, 229 | * p, buflen) and write the result into buf. The parameters r, p, and buflen 230 | * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N 231 | * must be a power of 2 greater than 1. 232 | * 233 | * Return 0 on success; or -1 on error. 234 | */ 235 | int 236 | crypto_scrypt(const uint8_t * passwd, size_t passwdlen, 237 | const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p, 238 | uint8_t * buf, size_t buflen) 239 | { 240 | void * B0, * V0, * XY0; 241 | uint8_t * B; 242 | uint32_t * V; 243 | uint32_t * XY; 244 | size_t r = _r, p = _p; 245 | uint32_t i; 246 | 247 | /* Sanity-check parameters. */ 248 | #if SIZE_MAX > UINT32_MAX 249 | if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { 250 | errno = EFBIG; 251 | goto err0; 252 | } 253 | #endif 254 | if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { 255 | errno = EFBIG; 256 | goto err0; 257 | } 258 | if (((N & (N - 1)) != 0) || (N < 2)) { 259 | errno = EINVAL; 260 | goto err0; 261 | } 262 | if ((r > SIZE_MAX / 128 / p) || 263 | #if SIZE_MAX / 256 <= UINT32_MAX 264 | (r > SIZE_MAX / 256) || 265 | #endif 266 | (N > SIZE_MAX / 128 / r)) { 267 | errno = ENOMEM; 268 | goto err0; 269 | } 270 | 271 | /* Allocate memory. */ 272 | #ifdef HAVE_POSIX_MEMALIGN 273 | if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0) 274 | goto err0; 275 | B = (uint8_t *)(B0); 276 | if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0) 277 | goto err1; 278 | XY = (uint32_t *)(XY0); 279 | #ifndef MAP_ANON 280 | if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0) 281 | goto err2; 282 | V = (uint32_t *)(V0); 283 | #endif 284 | #else 285 | if ((B0 = malloc(128 * r * p + 63)) == NULL) 286 | goto err0; 287 | B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63)); 288 | if ((XY0 = malloc(256 * r + 64 + 63)) == NULL) 289 | goto err1; 290 | XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63)); 291 | #ifndef MAP_ANON 292 | if ((V0 = malloc(128 * r * N + 63)) == NULL) 293 | goto err2; 294 | V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63)); 295 | #endif 296 | #endif 297 | #ifdef MAP_ANON 298 | if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE, 299 | #ifdef MAP_NOCORE 300 | MAP_ANON | MAP_PRIVATE | MAP_NOCORE, 301 | #else 302 | MAP_ANON | MAP_PRIVATE, 303 | #endif 304 | -1, 0)) == MAP_FAILED) 305 | goto err2; 306 | V = (uint32_t *)(V0); 307 | #endif 308 | 309 | /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ 310 | PBKDF2_scrypt_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); 311 | 312 | /* 2: for i = 0 to p - 1 do */ 313 | for (i = 0; i < p; i++) { 314 | /* 3: B_i <-- MF(B_i, N) */ 315 | smix(&B[i * 128 * r], r, N, V, XY); 316 | } 317 | 318 | /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ 319 | PBKDF2_scrypt_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); 320 | 321 | /* Free memory. */ 322 | #ifdef MAP_ANON 323 | if (munmap(V0, 128 * r * N)) 324 | goto err2; 325 | #else 326 | free(V0); 327 | #endif 328 | free(XY0); 329 | free(B0); 330 | 331 | /* Success! */ 332 | return (0); 333 | 334 | err2: 335 | free(XY0); 336 | err1: 337 | free(B0); 338 | err0: 339 | /* Failure! */ 340 | return (-1); 341 | } 342 | -------------------------------------------------------------------------------- /ext/alt-impl/crypto_scrypt-ref.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2009 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * This file was originally written by Colin Percival as part of the Tarsnap 27 | * online backup system. 28 | */ 29 | #include "scrypt_platform.h" 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "sha256.h" 37 | #include "sysendian.h" 38 | 39 | #include "crypto_scrypt.h" 40 | 41 | static void blkcpy(uint8_t *, uint8_t *, size_t); 42 | static void blkxor(uint8_t *, uint8_t *, size_t); 43 | static void salsa20_8(uint8_t[64]); 44 | static void blockmix_salsa8(uint8_t *, uint8_t *, size_t); 45 | static uint64_t integerify(uint8_t *, size_t); 46 | static void smix(uint8_t *, size_t, uint64_t, uint8_t *, uint8_t *); 47 | 48 | static void 49 | blkcpy(uint8_t * dest, uint8_t * src, size_t len) 50 | { 51 | size_t i; 52 | 53 | for (i = 0; i < len; i++) 54 | dest[i] = src[i]; 55 | } 56 | 57 | static void 58 | blkxor(uint8_t * dest, uint8_t * src, size_t len) 59 | { 60 | size_t i; 61 | 62 | for (i = 0; i < len; i++) 63 | dest[i] ^= src[i]; 64 | } 65 | 66 | /** 67 | * salsa20_8(B): 68 | * Apply the salsa20/8 core to the provided block. 69 | */ 70 | static void 71 | salsa20_8(uint8_t B[64]) 72 | { 73 | uint32_t B32[16]; 74 | uint32_t x[16]; 75 | size_t i; 76 | 77 | /* Convert little-endian values in. */ 78 | for (i = 0; i < 16; i++) 79 | B32[i] = le32dec(&B[i * 4]); 80 | 81 | /* Compute x = doubleround^4(B32). */ 82 | for (i = 0; i < 16; i++) 83 | x[i] = B32[i]; 84 | for (i = 0; i < 8; i += 2) { 85 | #define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) 86 | /* Operate on columns. */ 87 | x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); 88 | x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); 89 | 90 | x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); 91 | x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); 92 | 93 | x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); 94 | x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); 95 | 96 | x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); 97 | x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); 98 | 99 | /* Operate on rows. */ 100 | x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); 101 | x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); 102 | 103 | x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); 104 | x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); 105 | 106 | x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); 107 | x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); 108 | 109 | x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); 110 | x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); 111 | #undef R 112 | } 113 | 114 | /* Compute B32 = B32 + x. */ 115 | for (i = 0; i < 16; i++) 116 | B32[i] += x[i]; 117 | 118 | /* Convert little-endian values out. */ 119 | for (i = 0; i < 16; i++) 120 | le32enc(&B[4 * i], B32[i]); 121 | } 122 | 123 | /** 124 | * blockmix_salsa8(B, Y, r): 125 | * Compute B = BlockMix_{salsa20/8, r}(B). The input B must be 128r bytes in 126 | * length; the temporary space Y must also be the same size. 127 | */ 128 | static void 129 | blockmix_salsa8(uint8_t * B, uint8_t * Y, size_t r) 130 | { 131 | uint8_t X[64]; 132 | size_t i; 133 | 134 | /* 1: X <-- B_{2r - 1} */ 135 | blkcpy(X, &B[(2 * r - 1) * 64], 64); 136 | 137 | /* 2: for i = 0 to 2r - 1 do */ 138 | for (i = 0; i < 2 * r; i++) { 139 | /* 3: X <-- H(X \xor B_i) */ 140 | blkxor(X, &B[i * 64], 64); 141 | salsa20_8(X); 142 | 143 | /* 4: Y_i <-- X */ 144 | blkcpy(&Y[i * 64], X, 64); 145 | } 146 | 147 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ 148 | for (i = 0; i < r; i++) 149 | blkcpy(&B[i * 64], &Y[(i * 2) * 64], 64); 150 | for (i = 0; i < r; i++) 151 | blkcpy(&B[(i + r) * 64], &Y[(i * 2 + 1) * 64], 64); 152 | } 153 | 154 | /** 155 | * integerify(B, r): 156 | * Return the result of parsing B_{2r-1} as a little-endian integer. 157 | */ 158 | static uint64_t 159 | integerify(uint8_t * B, size_t r) 160 | { 161 | uint8_t * X = &B[(2 * r - 1) * 64]; 162 | 163 | return (le64dec(X)); 164 | } 165 | 166 | /** 167 | * smix(B, r, N, V, XY): 168 | * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; the 169 | * temporary storage V must be 128rN bytes in length; the temporary storage 170 | * XY must be 256r bytes in length. The value N must be a power of 2. 171 | */ 172 | static void 173 | smix(uint8_t * B, size_t r, uint64_t N, uint8_t * V, uint8_t * XY) 174 | { 175 | uint8_t * X = XY; 176 | uint8_t * Y = &XY[128 * r]; 177 | uint64_t i; 178 | uint64_t j; 179 | 180 | /* 1: X <-- B */ 181 | blkcpy(X, B, 128 * r); 182 | 183 | /* 2: for i = 0 to N - 1 do */ 184 | for (i = 0; i < N; i++) { 185 | /* 3: V_i <-- X */ 186 | blkcpy(&V[i * (128 * r)], X, 128 * r); 187 | 188 | /* 4: X <-- H(X) */ 189 | blockmix_salsa8(X, Y, r); 190 | } 191 | 192 | /* 6: for i = 0 to N - 1 do */ 193 | for (i = 0; i < N; i++) { 194 | /* 7: j <-- Integerify(X) mod N */ 195 | j = integerify(X, r) & (N - 1); 196 | 197 | /* 8: X <-- H(X \xor V_j) */ 198 | blkxor(X, &V[j * (128 * r)], 128 * r); 199 | blockmix_salsa8(X, Y, r); 200 | } 201 | 202 | /* 10: B' <-- X */ 203 | blkcpy(B, X, 128 * r); 204 | } 205 | 206 | /** 207 | * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): 208 | * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, 209 | * p, buflen) and write the result into buf. The parameters r, p, and buflen 210 | * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N 211 | * must be a power of 2. 212 | * 213 | * Return 0 on success; or -1 on error. 214 | */ 215 | int 216 | crypto_scrypt(const uint8_t * passwd, size_t passwdlen, 217 | const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p, 218 | uint8_t * buf, size_t buflen) 219 | { 220 | uint8_t * B; 221 | uint8_t * V; 222 | uint8_t * XY; 223 | size_t r = _r, p = _p; 224 | uint32_t i; 225 | 226 | /* Sanity-check parameters. */ 227 | #if SIZE_MAX > UINT32_MAX 228 | if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { 229 | errno = EFBIG; 230 | goto err0; 231 | } 232 | #endif 233 | if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { 234 | errno = EFBIG; 235 | goto err0; 236 | } 237 | if (((N & (N - 1)) != 0) || (N == 0)) { 238 | errno = EINVAL; 239 | goto err0; 240 | } 241 | if ((r > SIZE_MAX / 128 / p) || 242 | #if SIZE_MAX / 256 <= UINT32_MAX 243 | (r > SIZE_MAX / 256) || 244 | #endif 245 | (N > SIZE_MAX / 128 / r)) { 246 | errno = ENOMEM; 247 | goto err0; 248 | } 249 | 250 | /* Allocate memory. */ 251 | if ((B = malloc(128 * r * p)) == NULL) 252 | goto err0; 253 | if ((XY = malloc(256 * r)) == NULL) 254 | goto err1; 255 | if ((V = malloc(128 * r * N)) == NULL) 256 | goto err2; 257 | 258 | /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ 259 | PBKDF2_scrypt_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); 260 | 261 | /* 2: for i = 0 to p - 1 do */ 262 | for (i = 0; i < p; i++) { 263 | /* 3: B_i <-- MF(B_i, N) */ 264 | smix(&B[i * 128 * r], r, N, V, XY); 265 | } 266 | 267 | /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ 268 | PBKDF2_scrypt_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); 269 | 270 | /* Free memory. */ 271 | free(V); 272 | free(XY); 273 | free(B); 274 | 275 | /* Success! */ 276 | return (0); 277 | 278 | err2: 279 | free(XY); 280 | err1: 281 | free(B); 282 | err0: 283 | /* Failure! */ 284 | return (-1); 285 | } 286 | -------------------------------------------------------------------------------- /ext/scrypt/Rakefile: -------------------------------------------------------------------------------- 1 | require 'ffi-compiler/compile_task' 2 | 3 | target_cpu = RbConfig::CONFIG['target_cpu'] 4 | 5 | FFI::Compiler::CompileTask.new('scrypt_ext') do |t| 6 | t.cflags << '-Wall -std=c99' 7 | t.cflags << '-msse -msse2' if t.platform.arch.include? '86' 8 | t.cflags << '-D_GNU_SOURCE=1' if RbConfig::CONFIG['host_os'].downcase =~ /mingw/ 9 | t.cflags << '-D_POSIX_C_SOURCE=200809L' if RbConfig::CONFIG['host_os'].downcase =~ /linux/ 10 | 11 | if 1.size == 4 && target_cpu =~ /i386|x86_32/ && t.platform.mac? 12 | t.cflags << '-arch i386' 13 | t.ldflags << '-arch i386' 14 | elsif 1.size == 8 && target_cpu =~ /i686|x86_64/ && t.platform.mac? 15 | t.cflags << '-arch x86_64' 16 | t.ldflags << '-arch x86_64' 17 | end 18 | 19 | t.export '../../lib/scrypt/scrypt_ext.rb' 20 | 21 | t.add_define 'WINDOWS_OS' if FFI::Platform.windows? 22 | end 23 | -------------------------------------------------------------------------------- /ext/scrypt/cpusupport.h: -------------------------------------------------------------------------------- 1 | #ifndef _CPUSUPPORT_H_ 2 | #define _CPUSUPPORT_H_ 3 | 4 | /* 5 | * To enable support for non-portable CPU features at compile time, one or 6 | * more CPUSUPPORT_ARCH_FEATURE macros should be defined. This can be done 7 | * directly on the compiler command line via -D CPUSUPPORT_ARCH_FEATURE or 8 | * -D CPUSUPPORT_ARCH_FEATURE=1; or a file can be created with the 9 | * necessary #define lines and then -D CPUSUPPORT_CONFIG_FILE=cpuconfig.h 10 | * (or similar) can be provided to include that file here. 11 | */ 12 | #ifdef CPUSUPPORT_CONFIG_FILE 13 | #include CPUSUPPORT_CONFIG_FILE 14 | #endif 15 | 16 | /** 17 | * The CPUSUPPORT_FEATURE macro declares the necessary variables and 18 | * functions for detecting CPU feature support at run time. The function 19 | * defined in the macro acts to cache the result of the ..._detect function 20 | * using the ..._present and ..._init variables. The _detect function and the 21 | * _present and _init variables are turn defined by CPUSUPPORT_FEATURE_DECL in 22 | * appropriate cpusupport_foo_bar.c file. 23 | * 24 | * In order to allow CPUSUPPORT_FEATURE to be used for features which do not 25 | * have corresponding CPUSUPPORT_FEATURE_DECL blocks in another source file, 26 | * we abuse the C preprocessor: If CPUSUPPORT_${enabler} is defined to 1, then 27 | * we access _present_1, _init_1, and _detect_1; but if it is not defined, we 28 | * access _present_CPUSUPPORT_${enabler} etc., which we define as static, thus 29 | * preventing the compiler from emitting a reference to an external symbol. 30 | * 31 | * In this way, it becomes possible to issue CPUSUPPORT_FEATURE invocations 32 | * for nonexistent features without running afoul of the requirement that 33 | * "If an identifier declared with external linkage is used... in the entire 34 | * program there shall be exactly one external definition" (C99 standard, 6.9 35 | * paragraph 5). In practice, this means that users of the cpusupport code 36 | * can omit build and runtime detection files without changing the framework 37 | * code. 38 | */ 39 | #define CPUSUPPORT_FEATURE__(arch_feature, enabler, enabled) \ 40 | static int cpusupport_ ## arch_feature ## _present ## _CPUSUPPORT_ ## enabler; \ 41 | static int cpusupport_ ## arch_feature ## _init ## _CPUSUPPORT_ ## enabler; \ 42 | static inline int cpusupport_ ## arch_feature ## _detect ## _CPUSUPPORT_ ## enabler(void) { return (0); } \ 43 | extern int cpusupport_ ## arch_feature ## _present_ ## enabled; \ 44 | extern int cpusupport_ ## arch_feature ## _init_ ## enabled; \ 45 | int cpusupport_ ## arch_feature ## _detect_ ## enabled(void); \ 46 | \ 47 | static inline int \ 48 | cpusupport_ ## arch_feature(void) \ 49 | { \ 50 | \ 51 | if (cpusupport_ ## arch_feature ## _present_ ## enabled) \ 52 | return (1); \ 53 | else if (cpusupport_ ## arch_feature ## _init_ ## enabled) \ 54 | return (0); \ 55 | cpusupport_ ## arch_feature ## _present_ ## enabled = \ 56 | cpusupport_ ## arch_feature ## _detect_ ## enabled(); \ 57 | cpusupport_ ## arch_feature ## _init_ ## enabled = 1; \ 58 | return (cpusupport_ ## arch_feature ## _present_ ## enabled); \ 59 | } \ 60 | static void (* cpusupport_ ## arch_feature ## _dummyptr)(void); \ 61 | static inline void \ 62 | cpusupport_ ## arch_feature ## _dummyfunc(void) \ 63 | { \ 64 | \ 65 | (void)cpusupport_ ## arch_feature ## _present ## _CPUSUPPORT_ ## enabler; \ 66 | (void)cpusupport_ ## arch_feature ## _init ## _CPUSUPPORT_ ## enabler; \ 67 | (void)cpusupport_ ## arch_feature ## _detect ## _CPUSUPPORT_ ## enabler; \ 68 | (void)cpusupport_ ## arch_feature ## _present_ ## enabled; \ 69 | (void)cpusupport_ ## arch_feature ## _init_ ## enabled; \ 70 | (void)cpusupport_ ## arch_feature ## _detect_ ## enabled; \ 71 | (void)cpusupport_ ## arch_feature ## _dummyptr; \ 72 | } \ 73 | static void (* cpusupport_ ## arch_feature ## _dummyptr)(void) = cpusupport_ ## arch_feature ## _dummyfunc; \ 74 | struct cpusupport_ ## arch_feature ## _dummy 75 | #define CPUSUPPORT_FEATURE_(arch_feature, enabler, enabled) \ 76 | CPUSUPPORT_FEATURE__(arch_feature, enabler, enabled) 77 | #define CPUSUPPORT_FEATURE(arch, feature, enabler) \ 78 | CPUSUPPORT_FEATURE_(arch ## _ ## feature, enabler, CPUSUPPORT_ ## enabler) 79 | 80 | /* 81 | * CPUSUPPORT_FEATURE_DECL(arch, feature): 82 | * Macro which defines variables and provides a function declaration for 83 | * detecting the presence of "feature" on the "arch" architecture. The 84 | * function body following this macro expansion must return nonzero if the 85 | * feature is present, or zero if the feature is not present or the detection 86 | * fails for any reason. 87 | */ 88 | #define CPUSUPPORT_FEATURE_DECL(arch, feature) \ 89 | int cpusupport_ ## arch ## _ ## feature ## _present_1 = 0; \ 90 | int cpusupport_ ## arch ## _ ## feature ## _init_1 = 0; \ 91 | int \ 92 | cpusupport_ ## arch ## _ ## feature ## _detect_1(void) 93 | 94 | /* 95 | * List of features. If a feature here is not enabled by the appropriate 96 | * CPUSUPPORT_ARCH_FEATURE macro being defined, it has no effect; but if the 97 | * relevant macro may be defined (e.g., by Build/cpusupport.sh successfully 98 | * compiling Build/cpusupport-ARCH-FEATURE.c) then the C file containing the 99 | * corresponding run-time detection code (cpusupport_arch_feature.c) must be 100 | * compiled and linked in. 101 | */ 102 | CPUSUPPORT_FEATURE(x86, aesni, X86_AESNI); 103 | CPUSUPPORT_FEATURE(x86, sse2, X86_SSE2); 104 | 105 | #endif /* !_CPUSUPPORT_H_ */ 106 | -------------------------------------------------------------------------------- /ext/scrypt/crypto_scrypt.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2009 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * This file was originally written by Colin Percival as part of the Tarsnap 27 | * online backup system. 28 | */ 29 | /* #include "bsdtar_platform.h" */ 30 | 31 | #include 32 | #if !defined(WINDOWS_OS) 33 | #include 34 | #ifndef HAVE_MMAP 35 | #define HAVE_MMAP 1 36 | #endif 37 | #endif 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "cpusupport.h" 44 | #include "sha256.h" 45 | //#include "warnp.h" 46 | 47 | #include "crypto_scrypt_smix.h" 48 | #include "crypto_scrypt_smix_sse2.h" 49 | 50 | #include "crypto_scrypt.h" 51 | #include "warnp.h" 52 | 53 | static void (*smix_func)(uint8_t *, size_t, uint64_t, void *, void *) = NULL; 54 | 55 | /** 56 | * _crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen, smix): 57 | * Perform the requested scrypt computation, using ${smix} as the smix routine. 58 | */ 59 | static int 60 | _crypto_scrypt(const uint8_t * passwd, size_t passwdlen, 61 | const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p, 62 | uint8_t * buf, size_t buflen, 63 | void (*smix)(uint8_t *, size_t, uint64_t, void *, void *)) 64 | { 65 | void * B0, * V0, * XY0; 66 | uint8_t * B; 67 | uint32_t * V; 68 | uint32_t * XY; 69 | size_t r = _r, p = _p; 70 | uint32_t i; 71 | 72 | /* Sanity-check parameters. */ 73 | #if SIZE_MAX > UINT32_MAX 74 | if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { 75 | errno = EFBIG; 76 | goto err0; 77 | } 78 | #endif 79 | if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { 80 | errno = EFBIG; 81 | goto err0; 82 | } 83 | if (((N & (N - 1)) != 0) || (N < 2)) { 84 | errno = EINVAL; 85 | goto err0; 86 | } 87 | if ((r > SIZE_MAX / 128 / p) || 88 | #if SIZE_MAX / 256 <= UINT32_MAX 89 | (r > (SIZE_MAX - 64) / 256) || 90 | #endif 91 | (N > SIZE_MAX / 128 / r)) { 92 | errno = ENOMEM; 93 | goto err0; 94 | } 95 | 96 | /* Allocate memory. */ 97 | #ifdef HAVE_POSIX_MEMALIGN 98 | if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0) 99 | goto err0; 100 | B = (uint8_t *)(B0); 101 | if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0) 102 | goto err1; 103 | XY = (uint32_t *)(XY0); 104 | #if !defined(MAP_ANON) || !defined(HAVE_MMAP) 105 | if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0) 106 | goto err2; 107 | V = (uint32_t *)(V0); 108 | #endif 109 | #else 110 | if ((B0 = malloc(128 * r * p + 63)) == NULL) 111 | goto err0; 112 | B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63)); 113 | if ((XY0 = malloc(256 * r + 64 + 63)) == NULL) 114 | goto err1; 115 | XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63)); 116 | #if !defined(MAP_ANON) || !defined(HAVE_MMAP) 117 | if ((V0 = malloc(128 * r * N + 63)) == NULL) 118 | goto err2; 119 | V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63)); 120 | #endif 121 | #endif 122 | #if defined(MAP_ANON) && defined(HAVE_MMAP) 123 | if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE, 124 | #ifdef MAP_NOCORE 125 | MAP_ANON | MAP_PRIVATE | MAP_NOCORE, 126 | #else 127 | MAP_ANON | MAP_PRIVATE, 128 | #endif 129 | -1, 0)) == MAP_FAILED) 130 | goto err2; 131 | V = (uint32_t *)(V0); 132 | #endif 133 | 134 | /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ 135 | PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); 136 | 137 | /* 2: for i = 0 to p - 1 do */ 138 | for (i = 0; i < p; i++) { 139 | /* 3: B_i <-- MF(B_i, N) */ 140 | (smix)(&B[i * 128 * r], r, N, V, XY); 141 | } 142 | 143 | /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ 144 | PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); 145 | 146 | /* Free memory. */ 147 | #if defined(MAP_ANON) && defined(HAVE_MMAP) 148 | if (munmap(V0, 128 * r * N)) 149 | goto err2; 150 | #else 151 | free(V0); 152 | #endif 153 | free(XY0); 154 | free(B0); 155 | 156 | /* Success! */ 157 | return (0); 158 | 159 | err2: 160 | free(XY0); 161 | err1: 162 | free(B0); 163 | err0: 164 | /* Failure! */ 165 | return (-1); 166 | } 167 | 168 | #define TESTLEN 64 169 | static struct scrypt_test { 170 | const char * passwd; 171 | const char * salt; 172 | uint64_t N; 173 | uint32_t r; 174 | uint32_t p; 175 | uint8_t result[TESTLEN]; 176 | } testcase = { 177 | .passwd = "pleaseletmein", 178 | .salt = "SodiumChloride", 179 | .N = 16, 180 | .r = 8, 181 | .p = 1, 182 | .result = { 183 | 0x25, 0xa9, 0xfa, 0x20, 0x7f, 0x87, 0xca, 0x09, 184 | 0xa4, 0xef, 0x8b, 0x9f, 0x77, 0x7a, 0xca, 0x16, 185 | 0xbe, 0xb7, 0x84, 0xae, 0x18, 0x30, 0xbf, 0xbf, 186 | 0xd3, 0x83, 0x25, 0xaa, 0xbb, 0x93, 0x77, 0xdf, 187 | 0x1b, 0xa7, 0x84, 0xd7, 0x46, 0xea, 0x27, 0x3b, 188 | 0xf5, 0x16, 0xa4, 0x6f, 0xbf, 0xac, 0xf5, 0x11, 189 | 0xc5, 0xbe, 0xba, 0x4c, 0x4a, 0xb3, 0xac, 0xc7, 190 | 0xfa, 0x6f, 0x46, 0x0b, 0x6c, 0x0f, 0x47, 0x7b, 191 | } 192 | }; 193 | 194 | static int 195 | testsmix(void (*smix)(uint8_t *, size_t, uint64_t, void *, void *)) 196 | { 197 | uint8_t hbuf[TESTLEN]; 198 | 199 | /* Perform the computation. */ 200 | if (_crypto_scrypt( 201 | (const uint8_t *)testcase.passwd, strlen(testcase.passwd), 202 | (const uint8_t *)testcase.salt, strlen(testcase.salt), 203 | testcase.N, testcase.r, testcase.p, hbuf, TESTLEN, smix)) 204 | return (-1); 205 | 206 | /* Does it match? */ 207 | return (memcmp(testcase.result, hbuf, TESTLEN)); 208 | } 209 | 210 | static void 211 | selectsmix(void) 212 | { 213 | 214 | #ifdef CPUSUPPORT_X86_SSE2 215 | /* If we're running on an SSE2-capable CPU, try that code. */ 216 | if (cpusupport_x86_sse2()) { 217 | /* If SSE2ized smix works, use it. */ 218 | if (!testsmix(crypto_scrypt_smix_sse2)) { 219 | smix_func = crypto_scrypt_smix_sse2; 220 | return; 221 | } 222 | warn0("Disabling broken SSE2 scrypt support - please report bug!"); 223 | } 224 | #endif 225 | 226 | /* If generic smix works, use it. */ 227 | if (!testsmix(crypto_scrypt_smix)) { 228 | smix_func = crypto_scrypt_smix; 229 | return; 230 | } 231 | warn0("Generic scrypt code is broken - please report bug!"); 232 | 233 | /* If we get here, something really bad happened. */ 234 | abort(); 235 | } 236 | 237 | /** 238 | * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): 239 | * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, 240 | * p, buflen) and write the result into buf. The parameters r, p, and buflen 241 | * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N 242 | * must be a power of 2 greater than 1. 243 | * 244 | * Return 0 on success; or -1 on error. 245 | */ 246 | int 247 | crypto_scrypt(const uint8_t * passwd, size_t passwdlen, 248 | const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p, 249 | uint8_t * buf, size_t buflen) 250 | { 251 | 252 | if (smix_func == NULL) 253 | selectsmix(); 254 | 255 | return (_crypto_scrypt(passwd, passwdlen, salt, saltlen, N, _r, _p, 256 | buf, buflen, smix_func)); 257 | } 258 | -------------------------------------------------------------------------------- /ext/scrypt/crypto_scrypt.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2009 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * This file was originally written by Colin Percival as part of the Tarsnap 27 | * online backup system. 28 | */ 29 | #ifndef _CRYPTO_SCRYPT_H_ 30 | #define _CRYPTO_SCRYPT_H_ 31 | 32 | #include 33 | #include 34 | 35 | /** 36 | * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): 37 | * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, 38 | * p, buflen) and write the result into buf. The parameters r, p, and buflen 39 | * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N 40 | * must be a power of 2 greater than 1. 41 | * 42 | * Return 0 on success; or -1 on error. 43 | */ 44 | int crypto_scrypt(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t, 45 | uint32_t, uint32_t, uint8_t *, size_t); 46 | 47 | #endif /* !_CRYPTO_SCRYPT_H_ */ 48 | -------------------------------------------------------------------------------- /ext/scrypt/crypto_scrypt_internal.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbhogan/scrypt/ce9a1c5789d5904f0294d0dce68e8f2fb184afa5/ext/scrypt/crypto_scrypt_internal.h -------------------------------------------------------------------------------- /ext/scrypt/crypto_scrypt_smix.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2009 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * This file was originally written by Colin Percival as part of the Tarsnap 27 | * online backup system. 28 | */ 29 | #include 30 | #include 31 | 32 | #include "sysendian.h" 33 | 34 | #include "crypto_scrypt_smix.h" 35 | 36 | static void blkcpy(void *, const void *, size_t); 37 | static void blkxor(void *, const void *, size_t); 38 | static void salsa20_8(uint32_t[16]); 39 | static void blockmix_salsa8(const uint32_t *, uint32_t *, uint32_t *, size_t); 40 | static uint64_t integerify(const void *, size_t); 41 | 42 | static void 43 | blkcpy(void * dest, const void * src, size_t len) 44 | { 45 | size_t * D = dest; 46 | const size_t * S = src; 47 | size_t L = len / sizeof(size_t); 48 | size_t i; 49 | 50 | for (i = 0; i < L; i++) 51 | D[i] = S[i]; 52 | } 53 | 54 | static void 55 | blkxor(void * dest, const void * src, size_t len) 56 | { 57 | size_t * D = dest; 58 | const size_t * S = src; 59 | size_t L = len / sizeof(size_t); 60 | size_t i; 61 | 62 | for (i = 0; i < L; i++) 63 | D[i] ^= S[i]; 64 | } 65 | 66 | /** 67 | * salsa20_8(B): 68 | * Apply the salsa20/8 core to the provided block. 69 | */ 70 | static void 71 | salsa20_8(uint32_t B[16]) 72 | { 73 | uint32_t x[16]; 74 | size_t i; 75 | 76 | blkcpy(x, B, 64); 77 | for (i = 0; i < 8; i += 2) { 78 | #define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) 79 | /* Operate on columns. */ 80 | x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); 81 | x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); 82 | 83 | x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); 84 | x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); 85 | 86 | x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); 87 | x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); 88 | 89 | x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); 90 | x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); 91 | 92 | /* Operate on rows. */ 93 | x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); 94 | x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); 95 | 96 | x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); 97 | x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); 98 | 99 | x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); 100 | x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); 101 | 102 | x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); 103 | x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); 104 | #undef R 105 | } 106 | for (i = 0; i < 16; i++) 107 | B[i] += x[i]; 108 | } 109 | 110 | /** 111 | * blockmix_salsa8(Bin, Bout, X, r): 112 | * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r 113 | * bytes in length; the output Bout must also be the same size. The 114 | * temporary space X must be 64 bytes. 115 | */ 116 | static void 117 | blockmix_salsa8(const uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r) 118 | { 119 | size_t i; 120 | 121 | /* 1: X <-- B_{2r - 1} */ 122 | blkcpy(X, &Bin[(2 * r - 1) * 16], 64); 123 | 124 | /* 2: for i = 0 to 2r - 1 do */ 125 | for (i = 0; i < 2 * r; i += 2) { 126 | /* 3: X <-- H(X \xor B_i) */ 127 | blkxor(X, &Bin[i * 16], 64); 128 | salsa20_8(X); 129 | 130 | /* 4: Y_i <-- X */ 131 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ 132 | blkcpy(&Bout[i * 8], X, 64); 133 | 134 | /* 3: X <-- H(X \xor B_i) */ 135 | blkxor(X, &Bin[i * 16 + 16], 64); 136 | salsa20_8(X); 137 | 138 | /* 4: Y_i <-- X */ 139 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ 140 | blkcpy(&Bout[i * 8 + r * 16], X, 64); 141 | } 142 | } 143 | 144 | /** 145 | * integerify(B, r): 146 | * Return the result of parsing B_{2r-1} as a little-endian integer. 147 | */ 148 | static uint64_t 149 | integerify(const void * B, size_t r) 150 | { 151 | const uint32_t * X = (const void *)((uintptr_t)(B) + (2 * r - 1) * 64); 152 | 153 | return (((uint64_t)(X[1]) << 32) + X[0]); 154 | } 155 | 156 | /** 157 | * crypto_scrypt_smix(B, r, N, V, XY): 158 | * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; 159 | * the temporary storage V must be 128rN bytes in length; the temporary 160 | * storage XY must be 256r + 64 bytes in length. The value N must be a 161 | * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a 162 | * multiple of 64 bytes. 163 | */ 164 | void 165 | crypto_scrypt_smix(uint8_t * B, size_t r, uint64_t N, void * _V, void * XY) 166 | { 167 | uint32_t * X = XY; 168 | uint32_t * Y = (void *)((uint8_t *)(XY) + 128 * r); 169 | uint32_t * Z = (void *)((uint8_t *)(XY) + 256 * r); 170 | uint32_t * V = _V; 171 | uint64_t i; 172 | uint64_t j; 173 | size_t k; 174 | 175 | /* 1: X <-- B */ 176 | for (k = 0; k < 32 * r; k++) 177 | X[k] = le32dec(&B[4 * k]); 178 | 179 | /* 2: for i = 0 to N - 1 do */ 180 | for (i = 0; i < N; i += 2) { 181 | /* 3: V_i <-- X */ 182 | blkcpy(&V[i * (32 * r)], X, 128 * r); 183 | 184 | /* 4: X <-- H(X) */ 185 | blockmix_salsa8(X, Y, Z, r); 186 | 187 | /* 3: V_i <-- X */ 188 | blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r); 189 | 190 | /* 4: X <-- H(X) */ 191 | blockmix_salsa8(Y, X, Z, r); 192 | } 193 | 194 | /* 6: for i = 0 to N - 1 do */ 195 | for (i = 0; i < N; i += 2) { 196 | /* 7: j <-- Integerify(X) mod N */ 197 | j = integerify(X, r) & (N - 1); 198 | 199 | /* 8: X <-- H(X \xor V_j) */ 200 | blkxor(X, &V[j * (32 * r)], 128 * r); 201 | blockmix_salsa8(X, Y, Z, r); 202 | 203 | /* 7: j <-- Integerify(X) mod N */ 204 | j = integerify(Y, r) & (N - 1); 205 | 206 | /* 8: X <-- H(X \xor V_j) */ 207 | blkxor(Y, &V[j * (32 * r)], 128 * r); 208 | blockmix_salsa8(Y, X, Z, r); 209 | } 210 | 211 | /* 10: B' <-- X */ 212 | for (k = 0; k < 32 * r; k++) 213 | le32enc(&B[4 * k], X[k]); 214 | } 215 | -------------------------------------------------------------------------------- /ext/scrypt/crypto_scrypt_smix.h: -------------------------------------------------------------------------------- 1 | #ifndef _CRYPTO_SCRYPT_SMIX_H_ 2 | #define _CRYPTO_SCRYPT_SMIX_H_ 3 | 4 | /** 5 | * crypto_scrypt_smix(B, r, N, V, XY): 6 | * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; 7 | * the temporary storage V must be 128rN bytes in length; the temporary 8 | * storage XY must be 256r + 64 bytes in length. The value N must be a 9 | * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a 10 | * multiple of 64 bytes. 11 | */ 12 | void crypto_scrypt_smix(uint8_t *, size_t, uint64_t, void *, void *); 13 | 14 | #endif /* !_CRYPTO_SCRYPT_SMIX_H_ */ 15 | -------------------------------------------------------------------------------- /ext/scrypt/crypto_scrypt_smix_sse2.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2009 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * This file was originally written by Colin Percival as part of the Tarsnap 27 | * online backup system. 28 | */ 29 | #include "cpusupport.h" 30 | #ifdef CPUSUPPORT_X86_SSE2 31 | 32 | #include 33 | #include 34 | 35 | #include "sysendian.h" 36 | 37 | #include "crypto_scrypt_smix_sse2.h" 38 | 39 | static void blkcpy(void *, const void *, size_t); 40 | static void blkxor(void *, const void *, size_t); 41 | static void salsa20_8(__m128i *); 42 | static void blockmix_salsa8(const __m128i *, __m128i *, __m128i *, size_t); 43 | static uint64_t integerify(const void *, size_t); 44 | 45 | static void 46 | blkcpy(void * dest, const void * src, size_t len) 47 | { 48 | __m128i * D = dest; 49 | const __m128i * S = src; 50 | size_t L = len / 16; 51 | size_t i; 52 | 53 | for (i = 0; i < L; i++) 54 | D[i] = S[i]; 55 | } 56 | 57 | static void 58 | blkxor(void * dest, const void * src, size_t len) 59 | { 60 | __m128i * D = dest; 61 | const __m128i * S = src; 62 | size_t L = len / 16; 63 | size_t i; 64 | 65 | for (i = 0; i < L; i++) 66 | D[i] = _mm_xor_si128(D[i], S[i]); 67 | } 68 | 69 | /** 70 | * salsa20_8(B): 71 | * Apply the salsa20/8 core to the provided block. 72 | */ 73 | static void 74 | salsa20_8(__m128i B[4]) 75 | { 76 | __m128i X0, X1, X2, X3; 77 | __m128i T; 78 | size_t i; 79 | 80 | X0 = B[0]; 81 | X1 = B[1]; 82 | X2 = B[2]; 83 | X3 = B[3]; 84 | 85 | for (i = 0; i < 8; i += 2) { 86 | /* Operate on "columns". */ 87 | T = _mm_add_epi32(X0, X3); 88 | X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 7)); 89 | X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 25)); 90 | T = _mm_add_epi32(X1, X0); 91 | X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9)); 92 | X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); 93 | T = _mm_add_epi32(X2, X1); 94 | X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 13)); 95 | X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 19)); 96 | T = _mm_add_epi32(X3, X2); 97 | X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18)); 98 | X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); 99 | 100 | /* Rearrange data. */ 101 | X1 = _mm_shuffle_epi32(X1, 0x93); 102 | X2 = _mm_shuffle_epi32(X2, 0x4E); 103 | X3 = _mm_shuffle_epi32(X3, 0x39); 104 | 105 | /* Operate on "rows". */ 106 | T = _mm_add_epi32(X0, X1); 107 | X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 7)); 108 | X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 25)); 109 | T = _mm_add_epi32(X3, X0); 110 | X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9)); 111 | X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); 112 | T = _mm_add_epi32(X2, X3); 113 | X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 13)); 114 | X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 19)); 115 | T = _mm_add_epi32(X1, X2); 116 | X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18)); 117 | X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); 118 | 119 | /* Rearrange data. */ 120 | X1 = _mm_shuffle_epi32(X1, 0x39); 121 | X2 = _mm_shuffle_epi32(X2, 0x4E); 122 | X3 = _mm_shuffle_epi32(X3, 0x93); 123 | } 124 | 125 | B[0] = _mm_add_epi32(B[0], X0); 126 | B[1] = _mm_add_epi32(B[1], X1); 127 | B[2] = _mm_add_epi32(B[2], X2); 128 | B[3] = _mm_add_epi32(B[3], X3); 129 | } 130 | 131 | /** 132 | * blockmix_salsa8(Bin, Bout, X, r): 133 | * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r 134 | * bytes in length; the output Bout must also be the same size. The 135 | * temporary space X must be 64 bytes. 136 | */ 137 | static void 138 | blockmix_salsa8(const __m128i * Bin, __m128i * Bout, __m128i * X, size_t r) 139 | { 140 | size_t i; 141 | 142 | /* 1: X <-- B_{2r - 1} */ 143 | blkcpy(X, &Bin[8 * r - 4], 64); 144 | 145 | /* 2: for i = 0 to 2r - 1 do */ 146 | for (i = 0; i < r; i++) { 147 | /* 3: X <-- H(X \xor B_i) */ 148 | blkxor(X, &Bin[i * 8], 64); 149 | salsa20_8(X); 150 | 151 | /* 4: Y_i <-- X */ 152 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ 153 | blkcpy(&Bout[i * 4], X, 64); 154 | 155 | /* 3: X <-- H(X \xor B_i) */ 156 | blkxor(X, &Bin[i * 8 + 4], 64); 157 | salsa20_8(X); 158 | 159 | /* 4: Y_i <-- X */ 160 | /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ 161 | blkcpy(&Bout[(r + i) * 4], X, 64); 162 | } 163 | } 164 | 165 | /** 166 | * integerify(B, r): 167 | * Return the result of parsing B_{2r-1} as a little-endian integer. 168 | * Note that B's layout is permuted compared to the generic implementation. 169 | */ 170 | static uint64_t 171 | integerify(const void * B, size_t r) 172 | { 173 | const uint32_t * X = (const void *)((uintptr_t)(B) + (2 * r - 1) * 64); 174 | 175 | return (((uint64_t)(X[13]) << 32) + X[0]); 176 | } 177 | 178 | /** 179 | * crypto_scrypt_smix_sse2(B, r, N, V, XY): 180 | * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; 181 | * the temporary storage V must be 128rN bytes in length; the temporary 182 | * storage XY must be 256r + 64 bytes in length. The value N must be a 183 | * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a 184 | * multiple of 64 bytes. 185 | * 186 | * Use SSE2 instructions. 187 | */ 188 | void 189 | crypto_scrypt_smix_sse2(uint8_t * B, size_t r, uint64_t N, void * V, void * XY) 190 | { 191 | __m128i * X = XY; 192 | __m128i * Y = (void *)((uintptr_t)(XY) + 128 * r); 193 | __m128i * Z = (void *)((uintptr_t)(XY) + 256 * r); 194 | uint32_t * X32 = (void *)X; 195 | uint64_t i, j; 196 | size_t k; 197 | 198 | /* 1: X <-- B */ 199 | for (k = 0; k < 2 * r; k++) { 200 | for (i = 0; i < 16; i++) { 201 | X32[k * 16 + i] = 202 | le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]); 203 | } 204 | } 205 | 206 | /* 2: for i = 0 to N - 1 do */ 207 | for (i = 0; i < N; i += 2) { 208 | /* 3: V_i <-- X */ 209 | blkcpy((void *)((uintptr_t)(V) + i * 128 * r), X, 128 * r); 210 | 211 | /* 4: X <-- H(X) */ 212 | blockmix_salsa8(X, Y, Z, r); 213 | 214 | /* 3: V_i <-- X */ 215 | blkcpy((void *)((uintptr_t)(V) + (i + 1) * 128 * r), 216 | Y, 128 * r); 217 | 218 | /* 4: X <-- H(X) */ 219 | blockmix_salsa8(Y, X, Z, r); 220 | } 221 | 222 | /* 6: for i = 0 to N - 1 do */ 223 | for (i = 0; i < N; i += 2) { 224 | /* 7: j <-- Integerify(X) mod N */ 225 | j = integerify(X, r) & (N - 1); 226 | 227 | /* 8: X <-- H(X \xor V_j) */ 228 | blkxor(X, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r); 229 | blockmix_salsa8(X, Y, Z, r); 230 | 231 | /* 7: j <-- Integerify(X) mod N */ 232 | j = integerify(Y, r) & (N - 1); 233 | 234 | /* 8: X <-- H(X \xor V_j) */ 235 | blkxor(Y, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r); 236 | blockmix_salsa8(Y, X, Z, r); 237 | } 238 | 239 | /* 10: B' <-- X */ 240 | for (k = 0; k < 2 * r; k++) { 241 | for (i = 0; i < 16; i++) { 242 | le32enc(&B[(k * 16 + (i * 5 % 16)) * 4], 243 | X32[k * 16 + i]); 244 | } 245 | } 246 | } 247 | 248 | #endif /* CPUSUPPORT_X86_SSE2 */ 249 | -------------------------------------------------------------------------------- /ext/scrypt/crypto_scrypt_smix_sse2.h: -------------------------------------------------------------------------------- 1 | #ifndef _CRYPTO_SCRYPT_SMIX_SSE2_H_ 2 | #define _CRYPTO_SCRYPT_SMIX_SSE2_H_ 3 | 4 | /** 5 | * crypto_scrypt_smix_sse2(B, r, N, V, XY): 6 | * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; 7 | * the temporary storage V must be 128rN bytes in length; the temporary 8 | * storage XY must be 256r + 64 bytes in length. The value N must be a 9 | * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a 10 | * multiple of 64 bytes. 11 | * 12 | * Use SSE2 instructions. 13 | */ 14 | void crypto_scrypt_smix_sse2(uint8_t *, size_t, uint64_t, void *, void *); 15 | 16 | #endif /* !_CRYPTO_SCRYPT_SMIX_SSE2_H_ */ 17 | -------------------------------------------------------------------------------- /ext/scrypt/insecure_memzero.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "insecure_memzero.h" 5 | 6 | /* Function which does the zeroing. */ 7 | static void 8 | insecure_memzero_func(volatile void * buf, size_t len) 9 | { 10 | volatile uint8_t * _buf = buf; 11 | size_t i; 12 | 13 | for (i = 0; i < len; i++) 14 | _buf[i] = 0; 15 | } 16 | 17 | /* Pointer to memory-zeroing function. */ 18 | void (* volatile insecure_memzero_ptr)(volatile void *, size_t) = 19 | insecure_memzero_func; 20 | -------------------------------------------------------------------------------- /ext/scrypt/insecure_memzero.h: -------------------------------------------------------------------------------- 1 | #ifndef _INSECURE_MEMZERO_H_ 2 | #define _INSECURE_MEMZERO_H_ 3 | 4 | #include 5 | 6 | /* Pointer to memory-zeroing function. */ 7 | extern void (* volatile insecure_memzero_ptr)(volatile void *, size_t); 8 | 9 | /** 10 | * insecure_memzero(buf, len): 11 | * Attempt to zero ${len} bytes at ${buf} in spite of optimizing compilers' 12 | * best (standards-compliant) attempts to remove the buffer-zeroing. In 13 | * particular, to avoid performing the zeroing, a compiler would need to 14 | * use optimistic devirtualization; recognize that non-volatile objects do not 15 | * need to be treated as volatile, even if they are accessed via volatile 16 | * qualified pointers; and perform link-time optimization; in addition to the 17 | * dead-code elimination which often causes buffer-zeroing to be elided. 18 | * 19 | * Note however that zeroing a buffer does not guarantee that the data held 20 | * in the buffer is not stored elsewhere; in particular, there may be copies 21 | * held in CPU registers or in anonymous allocations on the stack, even if 22 | * every named variable is successfully sanitized. Solving the "wipe data 23 | * from the system" problem will require a C language extension which does not 24 | * yet exist. 25 | * 26 | * For more information, see: 27 | * http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html 28 | * http://www.daemonology.net/blog/2014-09-06-zeroing-buffers-is-insufficient.html 29 | */ 30 | static inline void 31 | insecure_memzero(volatile void * buf, size_t len) 32 | { 33 | 34 | (insecure_memzero_ptr)(buf, len); 35 | } 36 | 37 | #endif /* !_INSECURE_MEMZERO_H_ */ 38 | -------------------------------------------------------------------------------- /ext/scrypt/memlimit.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2009 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * This file was originally written by Colin Percival as part of the Tarsnap 27 | * online backup system. 28 | */ 29 | #include "scrypt_platform.h" 30 | 31 | #include 32 | #ifndef __MINGW32__ 33 | #include 34 | #endif 35 | 36 | #ifdef HAVE_SYS_PARAM_H 37 | #include 38 | #endif 39 | #ifdef HAVE_SYSCTL_HW_USERMEM 40 | #include 41 | #endif 42 | #ifdef HAVE_SYS_SYSINFO_H 43 | #include 44 | #endif 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | #ifdef DEBUG 52 | #include 53 | #endif 54 | 55 | #include "memlimit.h" 56 | 57 | #ifdef HAVE_SYSCTL_HW_USERMEM 58 | static int 59 | memlimit_sysctl_hw_usermem(size_t * memlimit) 60 | { 61 | int mib[2]; 62 | uint8_t usermembuf[8]; 63 | size_t usermemlen = 8; 64 | uint64_t usermem; 65 | 66 | /* Ask the kernel how much RAM we have. */ 67 | mib[0] = CTL_HW; 68 | mib[1] = HW_USERMEM; 69 | if (sysctl(mib, 2, usermembuf, &usermemlen, NULL, 0)) 70 | return (1); 71 | 72 | /* 73 | * Parse as either a uint64_t or a uint32_t based on the length of 74 | * output the kernel reports having copied out. It appears that all 75 | * systems providing a sysctl interface for reading integers copy 76 | * them out as system-endian values, so we don't need to worry about 77 | * parsing them. 78 | */ 79 | if (usermemlen == sizeof(uint64_t)) 80 | usermem = *(uint64_t *)usermembuf; 81 | else if (usermemlen == sizeof(uint32_t)) 82 | usermem = *(uint32_t *)usermembuf; 83 | else 84 | return (1); 85 | 86 | /* Return the sysctl value, but clamp to SIZE_MAX if necessary. */ 87 | #if UINT64_MAX > SIZE_MAX 88 | if (usermem > SIZE_MAX) 89 | *memlimit = SIZE_MAX; 90 | else 91 | *memlimit = usermem; 92 | #else 93 | *memlimit = usermem; 94 | #endif 95 | 96 | /* Success! */ 97 | return (0); 98 | } 99 | #endif 100 | 101 | /* If we don't HAVE_STRUCT_SYSINFO, we can't use sysinfo. */ 102 | #ifndef HAVE_STRUCT_SYSINFO 103 | #undef HAVE_SYSINFO 104 | #endif 105 | 106 | /* If we don't HAVE_STRUCT_SYSINFO_TOTALRAM, we can't use sysinfo. */ 107 | #ifndef HAVE_STRUCT_SYSINFO_TOTALRAM 108 | #undef HAVE_SYSINFO 109 | #endif 110 | 111 | #ifdef HAVE_SYSINFO 112 | static int 113 | memlimit_sysinfo(size_t * memlimit) 114 | { 115 | struct sysinfo info; 116 | uint64_t totalmem; 117 | 118 | /* Get information from the kernel. */ 119 | if (sysinfo(&info)) 120 | return (1); 121 | totalmem = info.totalram; 122 | 123 | /* If we're on a modern kernel, adjust based on mem_unit. */ 124 | #ifdef HAVE_STRUCT_SYSINFO_MEM_UNIT 125 | totalmem = totalmem * info.mem_unit; 126 | #endif 127 | 128 | /* Return the value, but clamp to SIZE_MAX if necessary. */ 129 | #if UINT64_MAX > SIZE_MAX 130 | if (totalmem > SIZE_MAX) 131 | *memlimit = SIZE_MAX; 132 | else 133 | *memlimit = totalmem; 134 | #else 135 | *memlimit = totalmem; 136 | #endif 137 | 138 | /* Success! */ 139 | return (0); 140 | } 141 | #endif /* HAVE_SYSINFO */ 142 | 143 | static int 144 | memlimit_rlimit(size_t * memlimit) 145 | { 146 | #ifndef __MINGW32__ 147 | struct rlimit rl; 148 | uint64_t memrlimit; 149 | 150 | /* Find the least of... */ 151 | memrlimit = (uint64_t)(-1); 152 | 153 | /* ... RLIMIT_AS... */ 154 | #ifdef RLIMIT_AS 155 | if (getrlimit(RLIMIT_AS, &rl)) 156 | return (1); 157 | if ((rl.rlim_cur != RLIM_INFINITY) && 158 | ((uint64_t)rl.rlim_cur < memrlimit)) 159 | memrlimit = rl.rlim_cur; 160 | #endif 161 | 162 | /* ... RLIMIT_DATA... */ 163 | if (getrlimit(RLIMIT_DATA, &rl)) 164 | return (1); 165 | if ((rl.rlim_cur != RLIM_INFINITY) && 166 | ((uint64_t)rl.rlim_cur < memrlimit)) 167 | memrlimit = rl.rlim_cur; 168 | 169 | /* ... and RLIMIT_RSS. */ 170 | #ifdef RLIMIT_RSS 171 | if (getrlimit(RLIMIT_RSS, &rl)) 172 | return (1); 173 | if ((rl.rlim_cur != RLIM_INFINITY) && 174 | ((uint64_t)rl.rlim_cur < memrlimit)) 175 | memrlimit = rl.rlim_cur; 176 | #endif 177 | 178 | /* Return the value, but clamp to SIZE_MAX if necessary. */ 179 | #if UINT64_MAX > SIZE_MAX 180 | if (memrlimit > SIZE_MAX) 181 | *memlimit = SIZE_MAX; 182 | else 183 | *memlimit = memrlimit; 184 | #else 185 | *memlimit = memrlimit; 186 | #endif 187 | #else 188 | *memlimit = SIZE_MAX; 189 | #endif 190 | /* Success! */ 191 | return (0); 192 | } 193 | 194 | #ifdef _SC_PHYS_PAGES 195 | 196 | /* Some systems define _SC_PAGESIZE instead of _SC_PAGE_SIZE. */ 197 | #ifndef _SC_PAGE_SIZE 198 | #define _SC_PAGE_SIZE _SC_PAGESIZE 199 | #endif 200 | 201 | static int 202 | memlimit_sysconf(size_t * memlimit) 203 | { 204 | long pagesize; 205 | long physpages; 206 | uint64_t totalmem; 207 | 208 | /* Set errno to 0 in order to distinguish "no limit" from "error". */ 209 | errno = 0; 210 | 211 | /* Read the two limits. */ 212 | if (((pagesize = sysconf(_SC_PAGE_SIZE)) == -1) || 213 | ((physpages = sysconf(_SC_PHYS_PAGES)) == -1)) { 214 | /* Did an error occur? */ 215 | if (errno != 0) 216 | return (1); 217 | 218 | /* If not, there is no limit. */ 219 | totalmem = (uint64_t)(-1); 220 | } else { 221 | /* Compute the limit. */ 222 | totalmem = (uint64_t)(pagesize) * (uint64_t)(physpages); 223 | } 224 | 225 | /* Return the value, but clamp to SIZE_MAX if necessary. */ 226 | #if UINT64_MAX > SIZE_MAX 227 | if (totalmem > SIZE_MAX) 228 | *memlimit = SIZE_MAX; 229 | else 230 | *memlimit = totalmem; 231 | #else 232 | *memlimit = totalmem; 233 | #endif 234 | 235 | /* Success! */ 236 | return (0); 237 | } 238 | #endif 239 | 240 | int 241 | memtouse(size_t maxmem, double maxmemfrac, size_t * memlimit) 242 | { 243 | size_t sysctl_memlimit, sysinfo_memlimit, rlimit_memlimit; 244 | size_t sysconf_memlimit; 245 | size_t memlimit_min; 246 | size_t memavail; 247 | 248 | /* Get memory limits. */ 249 | #ifdef HAVE_SYSCTL_HW_USERMEM 250 | if (memlimit_sysctl_hw_usermem(&sysctl_memlimit)) 251 | return (1); 252 | #else 253 | sysctl_memlimit = (size_t)(-1); 254 | #endif 255 | #ifdef HAVE_SYSINFO 256 | if (memlimit_sysinfo(&sysinfo_memlimit)) 257 | return (1); 258 | #else 259 | sysinfo_memlimit = (size_t)(-1); 260 | #endif 261 | if (memlimit_rlimit(&rlimit_memlimit)) 262 | return (1); 263 | #ifdef _SC_PHYS_PAGES 264 | if (memlimit_sysconf(&sysconf_memlimit)) 265 | return (1); 266 | #else 267 | sysconf_memlimit = (size_t)(-1); 268 | #endif 269 | 270 | #ifdef DEBUG 271 | fprintf(stderr, "Memory limits are %zu %zu %zu %zu\n", 272 | sysctl_memlimit, sysinfo_memlimit, rlimit_memlimit, 273 | sysconf_memlimit); 274 | #endif 275 | 276 | /* Find the smallest of them. */ 277 | memlimit_min = (size_t)(-1); 278 | if (memlimit_min > sysctl_memlimit) 279 | memlimit_min = sysctl_memlimit; 280 | if (memlimit_min > sysinfo_memlimit) 281 | memlimit_min = sysinfo_memlimit; 282 | if (memlimit_min > rlimit_memlimit) 283 | memlimit_min = rlimit_memlimit; 284 | if (memlimit_min > sysconf_memlimit) 285 | memlimit_min = sysconf_memlimit; 286 | 287 | /* Only use the specified fraction of the available memory. */ 288 | if ((maxmemfrac > 0.5) || (maxmemfrac == 0.0)) 289 | maxmemfrac = 0.5; 290 | memavail = maxmemfrac * memlimit_min; 291 | 292 | /* Don't use more than the specified maximum. */ 293 | if ((maxmem > 0) && (memavail > maxmem)) 294 | memavail = maxmem; 295 | 296 | /* But always allow at least 1 MiB. */ 297 | if (memavail < 1048576) 298 | memavail = 1048576; 299 | 300 | #ifdef DEBUG 301 | fprintf(stderr, "Allowing up to %zu memory to be used\n", memavail); 302 | #endif 303 | 304 | /* Return limit via the provided pointer. */ 305 | *memlimit = memavail; 306 | return (0); 307 | } 308 | -------------------------------------------------------------------------------- /ext/scrypt/memlimit.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2009 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * This file was originally written by Colin Percival as part of the Tarsnap 27 | * online backup system. 28 | */ 29 | #ifndef _MEMLIMIT_H_ 30 | #define _MEMLIMIT_H_ 31 | 32 | #include 33 | 34 | /** 35 | * memtouse(maxmem, maxmemfrac, memlimit): 36 | * Examine the system and return via memlimit the amount of RAM which should 37 | * be used -- the specified fraction of the available RAM, but no more than 38 | * maxmem, and no less than 1MiB. 39 | */ 40 | int memtouse(size_t, double, size_t *); 41 | 42 | #endif /* !_MEMLIMIT_H_ */ 43 | -------------------------------------------------------------------------------- /ext/scrypt/scrypt_calibrate.c: -------------------------------------------------------------------------------- 1 | /* 2 | * scrypt_calibrate.c 3 | * scrypt 4 | * 5 | * Created by Patrick Hogan on 12/15/10. 6 | * Copyright 2010 __MyCompanyName__. All rights reserved. 7 | * 8 | */ 9 | 10 | #include "scrypt_platform.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "memlimit.h" 20 | #include "scryptenc_cpuperf.h" 21 | #include "sysendian.h" 22 | 23 | #include "scrypt_calibrate.h" 24 | 25 | 26 | static int 27 | pickparams(size_t maxmem, double maxmemfrac, double maxtime, int * logN, uint32_t * r, uint32_t * p) 28 | { 29 | size_t memlimit; 30 | double opps; 31 | double opslimit; 32 | double maxN, maxrp; 33 | int rc; 34 | 35 | /* Figure out how much memory to use. */ 36 | if (memtouse(maxmem, maxmemfrac, &memlimit)) 37 | return (1); 38 | 39 | /* Figure out how fast the CPU is. */ 40 | if ((rc = scryptenc_cpuperf(&opps)) != 0) 41 | return (rc); 42 | opslimit = opps * maxtime; 43 | 44 | /* Allow a minimum of 2^15 salsa20/8 cores. */ 45 | if (opslimit < 32768) 46 | opslimit = 32768; 47 | 48 | /* Fix r = 8 for now. */ 49 | *r = 8; 50 | 51 | /* 52 | * The memory limit requires that 128Nr <= memlimit, while the CPU 53 | * limit requires that 4Nrp <= opslimit. If opslimit < memlimit/32, 54 | * opslimit imposes the stronger limit on N. 55 | */ 56 | #ifdef DEBUG 57 | fprintf(stderr, "Requiring 128Nr <= %zu, 4Nrp <= %f\n", 58 | memlimit, opslimit); 59 | #endif 60 | if (opslimit < memlimit/32) { 61 | /* Set p = 1 and choose N based on the CPU limit. */ 62 | *p = 1; 63 | maxN = opslimit / (*r * 4); 64 | for (*logN = 1; *logN < 63; *logN += 1) { 65 | if ((uint64_t)(1) << *logN > maxN / 2) 66 | break; 67 | } 68 | } else { 69 | /* Set N based on the memory limit. */ 70 | maxN = memlimit / (*r * 128); 71 | for (*logN = 1; *logN < 63; *logN += 1) { 72 | if ((uint64_t)(1) << *logN > maxN / 2) 73 | break; 74 | } 75 | 76 | /* Choose p based on the CPU limit. */ 77 | maxrp = (opslimit / 4) / ((uint64_t)(1) << *logN); 78 | if (maxrp > 0x3fffffff) 79 | maxrp = 0x3fffffff; 80 | *p = (uint32_t)(maxrp) / *r; 81 | } 82 | 83 | #ifdef DEBUG 84 | fprintf(stderr, "N = %zu r = %d p = %d\n", 85 | (size_t)(1) << *logN, (int)(*r), (int)(*p)); 86 | #endif 87 | 88 | /* Success! */ 89 | return (0); 90 | } 91 | 92 | int 93 | calibrate(size_t maxmem, double maxmemfrac, double maxtime, uint64_t * n, uint32_t * r, uint32_t * p) 94 | { 95 | int logN = 0; 96 | int result = pickparams( maxmem, maxmemfrac, maxtime, & logN, r, p ); 97 | if (result == 0) 98 | { 99 | *n = (uint64_t)(1) << logN; 100 | } 101 | return result; 102 | } -------------------------------------------------------------------------------- /ext/scrypt/scrypt_calibrate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * scrypt_calibrate.h 3 | * scrypt 4 | * 5 | * Created by Patrick Hogan on 12/15/10. 6 | * 7 | */ 8 | 9 | #ifndef _SCRYPT_CALIBRATE_H_ 10 | #define _SCRYPT_CALIBRATE_H_ 11 | 12 | #include 13 | #include 14 | 15 | int calibrate( size_t maxmem, double maxmemfrac, double maxtime, uint64_t * n, uint32_t * r, uint32_t * p ); 16 | 17 | #endif 18 | 19 | 20 | -------------------------------------------------------------------------------- /ext/scrypt/scrypt_ext.c: -------------------------------------------------------------------------------- 1 | #include "scrypt_ext.h" 2 | #include "scrypt_calibrate.h" 3 | #include "crypto_scrypt.h" 4 | 5 | 6 | typedef struct { 7 | uint64_t n; 8 | uint32_t r; 9 | uint32_t p; 10 | } Calibration; 11 | 12 | 13 | RBFFI_EXPORT int sc_calibrate(size_t maxmem, double maxmemfrac, double maxtime, Calibration *result) 14 | { 15 | return calibrate(maxmem, maxmemfrac, maxtime, &result->n, &result->r, &result->p); // 0 == success 16 | } 17 | -------------------------------------------------------------------------------- /ext/scrypt/scrypt_ext.h: -------------------------------------------------------------------------------- 1 | #ifndef SCRYPT_EXT_H 2 | #define SCRYPT_EXT_H 1 3 | 4 | #ifndef RBFFI_EXPORT 5 | # ifdef __cplusplus 6 | # define RBFFI_EXPORT extern "C" 7 | # else 8 | # define RBFFI_EXPORT 9 | # endif 10 | #endif 11 | 12 | 13 | #endif /* SCRYPT_EXT_H */ 14 | -------------------------------------------------------------------------------- /ext/scrypt/scrypt_platform.h: -------------------------------------------------------------------------------- 1 | #ifndef _SCRYPT_PLATFORM_H_ 2 | #define _SCRYPT_PLATFORM_H_ 3 | 4 | #endif 5 | -------------------------------------------------------------------------------- /ext/scrypt/scryptenc_cpuperf.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2009 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * This file was originally written by Colin Percival as part of the Tarsnap 27 | * online backup system. 28 | */ 29 | #include "scrypt_platform.h" 30 | 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | #include "crypto_scrypt.h" 38 | 39 | #include "scryptenc_cpuperf.h" 40 | 41 | #if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) 42 | struct timespec { 43 | long tv_sec; 44 | long tv_nsec; 45 | }; 46 | #endif 47 | 48 | #ifdef HAVE_CLOCK_GETTIME 49 | 50 | static clock_t clocktouse; 51 | 52 | static int 53 | getclockres(double * resd) 54 | { 55 | struct timespec res; 56 | 57 | /* 58 | * Try clocks in order of preference until we find one which works. 59 | * (We assume that if clock_getres works, clock_gettime will, too.) 60 | * The use of if/else/if/else/if/else rather than if/elif/elif/else 61 | * is ugly but legal, and allows us to #ifdef things appropriately. 62 | */ 63 | #ifdef CLOCK_VIRTUAL 64 | if (clock_getres(CLOCK_VIRTUAL, &res) == 0) 65 | clocktouse = CLOCK_VIRTUAL; 66 | else 67 | #endif 68 | #ifdef CLOCK_MONOTONIC 69 | if (clock_getres(CLOCK_MONOTONIC, &res) == 0) 70 | clocktouse = CLOCK_MONOTONIC; 71 | else 72 | #endif 73 | if (clock_getres(CLOCK_REALTIME, &res) == 0) 74 | clocktouse = CLOCK_REALTIME; 75 | else 76 | return (-1); 77 | 78 | /* Convert clock resolution to a double. */ 79 | *resd = res.tv_sec + res.tv_nsec * 0.000000001; 80 | 81 | return (0); 82 | } 83 | 84 | static int 85 | getclocktime(struct timespec * ts) 86 | { 87 | 88 | if (clock_gettime(clocktouse, ts)) 89 | return (-1); 90 | 91 | return (0); 92 | } 93 | 94 | #else 95 | static int 96 | getclockres(double * resd) 97 | { 98 | 99 | *resd = 1.0 / CLOCKS_PER_SEC; 100 | 101 | return (0); 102 | } 103 | 104 | static int 105 | getclocktime(struct timespec * ts) 106 | { 107 | struct timeval tv; 108 | 109 | if (gettimeofday(&tv, NULL)) 110 | return (-1); 111 | ts->tv_sec = tv.tv_sec; 112 | ts->tv_nsec = tv.tv_usec * 1000; 113 | 114 | return (0); 115 | } 116 | #endif 117 | 118 | static int 119 | getclockdiff(struct timespec * st, double * diffd) 120 | { 121 | struct timespec en; 122 | 123 | if (getclocktime(&en)) 124 | return (1); 125 | *diffd = (en.tv_nsec - st->tv_nsec) * 0.000000001 + 126 | (en.tv_sec - st->tv_sec); 127 | 128 | return (0); 129 | } 130 | 131 | /** 132 | * scryptenc_cpuperf(opps): 133 | * Estimate the number of salsa20/8 cores which can be executed per second, 134 | * and return the value via opps. 135 | */ 136 | int 137 | scryptenc_cpuperf(double * opps) 138 | { 139 | struct timespec st; 140 | double resd, diffd; 141 | uint64_t i = 0; 142 | 143 | /* Get the clock resolution. */ 144 | if (getclockres(&resd)) 145 | return (2); 146 | 147 | #ifdef DEBUG 148 | fprintf(stderr, "Clock resolution is %f\n", resd); 149 | #endif 150 | 151 | /* Loop until the clock ticks. */ 152 | if (getclocktime(&st)) 153 | return (2); 154 | do { 155 | /* Do an scrypt. */ 156 | if (crypto_scrypt(NULL, 0, NULL, 0, 16, 1, 1, NULL, 0)) 157 | return (3); 158 | 159 | /* Has the clock ticked? */ 160 | if (getclockdiff(&st, &diffd)) 161 | return (2); 162 | if (diffd > 0) 163 | break; 164 | } while (1); 165 | 166 | /* Count how many scrypts we can do before the next tick. */ 167 | if (getclocktime(&st)) 168 | return (2); 169 | do { 170 | /* Do an scrypt. */ 171 | if (crypto_scrypt(NULL, 0, NULL, 0, 128, 1, 1, NULL, 0)) 172 | return (3); 173 | 174 | /* We invoked the salsa20/8 core 512 times. */ 175 | i += 512; 176 | 177 | /* Check if we have looped for long enough. */ 178 | if (getclockdiff(&st, &diffd)) 179 | return (2); 180 | if (diffd > resd) 181 | break; 182 | } while (1); 183 | 184 | #ifdef DEBUG 185 | fprintf(stderr, "%ju salsa20/8 cores performed in %f seconds\n", 186 | (uintmax_t)i, diffd); 187 | #endif 188 | 189 | /* We can do approximately i salsa20/8 cores per diffd seconds. */ 190 | *opps = i / diffd; 191 | return (0); 192 | } 193 | -------------------------------------------------------------------------------- /ext/scrypt/scryptenc_cpuperf.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2009 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * This file was originally written by Colin Percival as part of the Tarsnap 27 | * online backup system. 28 | */ 29 | #ifndef _SCRYPTENC_CPUPERF_H_ 30 | #define _SCRYPTENC_CPUPERF_H_ 31 | 32 | /** 33 | * scryptenc_cpuperf(opps): 34 | * Estimate the number of salsa20/8 cores which can be executed per second, 35 | * and return the value via opps. 36 | */ 37 | int scryptenc_cpuperf(double *); 38 | 39 | #endif /* !_SCRYPTENC_CPUPERF_H_ */ 40 | -------------------------------------------------------------------------------- /ext/scrypt/sha256.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "insecure_memzero.h" 6 | #include "sysendian.h" 7 | 8 | #include "sha256.h" 9 | 10 | /* 11 | * Encode a length len/4 vector of (uint32_t) into a length len vector of 12 | * (uint8_t) in big-endian form. Assumes len is a multiple of 4. 13 | */ 14 | static void 15 | be32enc_vect(uint8_t * dst, const uint32_t * src, size_t len) 16 | { 17 | size_t i; 18 | 19 | /* Sanity-check. */ 20 | assert(len % 4 == 0); 21 | 22 | /* Encode vector, one word at a time. */ 23 | for (i = 0; i < len / 4; i++) 24 | be32enc(dst + i * 4, src[i]); 25 | } 26 | 27 | /* 28 | * Decode a big-endian length len vector of (uint8_t) into a length 29 | * len/4 vector of (uint32_t). Assumes len is a multiple of 4. 30 | */ 31 | static void 32 | be32dec_vect(uint32_t * dst, const uint8_t * src, size_t len) 33 | { 34 | size_t i; 35 | 36 | /* Sanity-check. */ 37 | assert(len % 4 == 0); 38 | 39 | /* Decode vector, one word at a time. */ 40 | for (i = 0; i < len / 4; i++) 41 | dst[i] = be32dec(src + i * 4); 42 | } 43 | 44 | /* SHA256 round constants. */ 45 | static const uint32_t K[64] = { 46 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 47 | 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 48 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 49 | 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 50 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 51 | 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 52 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 53 | 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 54 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 55 | 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 56 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 57 | 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 58 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 59 | 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 60 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 61 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 62 | }; 63 | 64 | /* Elementary functions used by SHA256 */ 65 | #define Ch(x, y, z) ((x & (y ^ z)) ^ z) 66 | #define Maj(x, y, z) ((x & (y | z)) | (y & z)) 67 | #define SHR(x, n) (x >> n) 68 | #define ROTR(x, n) ((x >> n) | (x << (32 - n))) 69 | #define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) 70 | #define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) 71 | #define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) 72 | #define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) 73 | 74 | /* SHA256 round function */ 75 | #define RND(a, b, c, d, e, f, g, h, k) \ 76 | h += S1(e) + Ch(e, f, g) + k; \ 77 | d += h; \ 78 | h += S0(a) + Maj(a, b, c); 79 | 80 | /* Adjusted round function for rotating state */ 81 | #define RNDr(S, W, i, ii) \ 82 | RND(S[(64 - i) % 8], S[(65 - i) % 8], \ 83 | S[(66 - i) % 8], S[(67 - i) % 8], \ 84 | S[(68 - i) % 8], S[(69 - i) % 8], \ 85 | S[(70 - i) % 8], S[(71 - i) % 8], \ 86 | W[i + ii] + K[i + ii]) 87 | 88 | /* Message schedule computation */ 89 | #define MSCH(W, ii, i) \ 90 | W[i + ii + 16] = s1(W[i + ii + 14]) + W[i + ii + 9] + s0(W[i + ii + 1]) + W[i + ii] 91 | 92 | /* 93 | * SHA256 block compression function. The 256-bit state is transformed via 94 | * the 512-bit input block to produce a new state. 95 | */ 96 | static void 97 | SHA256_Transform(uint32_t state[static restrict 8], 98 | const uint8_t block[static restrict 64], 99 | uint32_t W[static restrict 64], uint32_t S[static restrict 8]) 100 | { 101 | int i; 102 | 103 | /* 1. Prepare the first part of the message schedule W. */ 104 | be32dec_vect(W, block, 64); 105 | 106 | /* 2. Initialize working variables. */ 107 | memcpy(S, state, 32); 108 | 109 | /* 3. Mix. */ 110 | for (i = 0; i < 64; i += 16) { 111 | RNDr(S, W, 0, i); 112 | RNDr(S, W, 1, i); 113 | RNDr(S, W, 2, i); 114 | RNDr(S, W, 3, i); 115 | RNDr(S, W, 4, i); 116 | RNDr(S, W, 5, i); 117 | RNDr(S, W, 6, i); 118 | RNDr(S, W, 7, i); 119 | RNDr(S, W, 8, i); 120 | RNDr(S, W, 9, i); 121 | RNDr(S, W, 10, i); 122 | RNDr(S, W, 11, i); 123 | RNDr(S, W, 12, i); 124 | RNDr(S, W, 13, i); 125 | RNDr(S, W, 14, i); 126 | RNDr(S, W, 15, i); 127 | 128 | if (i == 48) 129 | break; 130 | MSCH(W, 0, i); 131 | MSCH(W, 1, i); 132 | MSCH(W, 2, i); 133 | MSCH(W, 3, i); 134 | MSCH(W, 4, i); 135 | MSCH(W, 5, i); 136 | MSCH(W, 6, i); 137 | MSCH(W, 7, i); 138 | MSCH(W, 8, i); 139 | MSCH(W, 9, i); 140 | MSCH(W, 10, i); 141 | MSCH(W, 11, i); 142 | MSCH(W, 12, i); 143 | MSCH(W, 13, i); 144 | MSCH(W, 14, i); 145 | MSCH(W, 15, i); 146 | } 147 | 148 | /* 4. Mix local working variables into global state. */ 149 | for (i = 0; i < 8; i++) 150 | state[i] += S[i]; 151 | } 152 | 153 | static const uint8_t PAD[64] = { 154 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 156 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 158 | }; 159 | 160 | /* Add padding and terminating bit-count. */ 161 | static void 162 | SHA256_Pad(SHA256_CTX * ctx, uint32_t tmp32[static restrict 72]) 163 | { 164 | size_t r; 165 | 166 | /* Figure out how many bytes we have buffered. */ 167 | r = (ctx->count >> 3) & 0x3f; 168 | 169 | /* Pad to 56 mod 64, transforming if we finish a block en route. */ 170 | if (r < 56) { 171 | /* Pad to 56 mod 64. */ 172 | memcpy(&ctx->buf[r], PAD, 56 - r); 173 | } else { 174 | /* Finish the current block and mix. */ 175 | memcpy(&ctx->buf[r], PAD, 64 - r); 176 | SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]); 177 | 178 | /* The start of the final block is all zeroes. */ 179 | memset(&ctx->buf[0], 0, 56); 180 | } 181 | 182 | /* Add the terminating bit-count. */ 183 | be64enc(&ctx->buf[56], ctx->count); 184 | 185 | /* Mix in the final block. */ 186 | SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]); 187 | } 188 | 189 | /* Magic initialization constants. */ 190 | static const uint32_t initstate[8] = { 191 | 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 192 | 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 193 | }; 194 | 195 | /** 196 | * SHA256_Init(ctx): 197 | * Initialize the SHA256 context ${ctx}. 198 | */ 199 | void 200 | SHA256_Init(SHA256_CTX * ctx) 201 | { 202 | 203 | /* Zero bits processed so far. */ 204 | ctx->count = 0; 205 | 206 | /* Initialize state. */ 207 | memcpy(ctx->state, initstate, sizeof(initstate)); 208 | } 209 | 210 | /** 211 | * SHA256_Update(ctx, in, len): 212 | * Input ${len} bytes from ${in} into the SHA256 context ${ctx}. 213 | */ 214 | static void 215 | _SHA256_Update(SHA256_CTX * ctx, const void * in, size_t len, 216 | uint32_t tmp32[static restrict 72]) 217 | { 218 | uint32_t r; 219 | const uint8_t * src = in; 220 | 221 | /* Return immediately if we have nothing to do. */ 222 | if (len == 0) 223 | return; 224 | 225 | /* Number of bytes left in the buffer from previous updates. */ 226 | r = (ctx->count >> 3) & 0x3f; 227 | 228 | /* Update number of bits. */ 229 | ctx->count += (uint64_t)(len) << 3; 230 | 231 | /* Handle the case where we don't need to perform any transforms. */ 232 | if (len < 64 - r) { 233 | memcpy(&ctx->buf[r], src, len); 234 | return; 235 | } 236 | 237 | /* Finish the current block. */ 238 | memcpy(&ctx->buf[r], src, 64 - r); 239 | SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]); 240 | src += 64 - r; 241 | len -= 64 - r; 242 | 243 | /* Perform complete blocks. */ 244 | while (len >= 64) { 245 | SHA256_Transform(ctx->state, src, &tmp32[0], &tmp32[64]); 246 | src += 64; 247 | len -= 64; 248 | } 249 | 250 | /* Copy left over data into buffer. */ 251 | memcpy(ctx->buf, src, len); 252 | } 253 | 254 | /* Wrapper function for intermediate-values sanitization. */ 255 | void 256 | SHA256_Update(SHA256_CTX * ctx, const void * in, size_t len) 257 | { 258 | uint32_t tmp32[72]; 259 | 260 | /* Call the real function. */ 261 | _SHA256_Update(ctx, in, len, tmp32); 262 | 263 | /* Clean the stack. */ 264 | insecure_memzero(tmp32, 288); 265 | } 266 | 267 | /** 268 | * SHA256_Final(digest, ctx): 269 | * Output the SHA256 hash of the data input to the context ${ctx} into the 270 | * buffer ${digest}. 271 | */ 272 | static void 273 | _SHA256_Final(uint8_t digest[32], SHA256_CTX * ctx, 274 | uint32_t tmp32[static restrict 72]) 275 | { 276 | 277 | /* Add padding. */ 278 | SHA256_Pad(ctx, tmp32); 279 | 280 | /* Write the hash. */ 281 | be32enc_vect(digest, ctx->state, 32); 282 | } 283 | 284 | /* Wrapper function for intermediate-values sanitization. */ 285 | void 286 | SHA256_Final(uint8_t digest[32], SHA256_CTX * ctx) 287 | { 288 | uint32_t tmp32[72]; 289 | 290 | /* Call the real function. */ 291 | _SHA256_Final(digest, ctx, tmp32); 292 | 293 | /* Clear the context state. */ 294 | insecure_memzero(ctx, sizeof(SHA256_CTX)); 295 | 296 | /* Clean the stack. */ 297 | insecure_memzero(tmp32, 288); 298 | } 299 | 300 | /** 301 | * SHA256_Buf(in, len, digest): 302 | * Compute the SHA256 hash of ${len} bytes from $in} and write it to ${digest}. 303 | */ 304 | void 305 | SHA256_Buf(const void * in, size_t len, uint8_t digest[32]) 306 | { 307 | SHA256_CTX ctx; 308 | uint32_t tmp32[72]; 309 | 310 | SHA256_Init(&ctx); 311 | _SHA256_Update(&ctx, in, len, tmp32); 312 | _SHA256_Final(digest, &ctx, tmp32); 313 | 314 | /* Clean the stack. */ 315 | insecure_memzero(&ctx, sizeof(SHA256_CTX)); 316 | insecure_memzero(tmp32, 288); 317 | } 318 | 319 | /** 320 | * HMAC_SHA256_Init(ctx, K, Klen): 321 | * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from 322 | * ${K}. 323 | */ 324 | static void 325 | _HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen, 326 | uint32_t tmp32[static restrict 72], uint8_t pad[static restrict 64], 327 | uint8_t khash[static restrict 32]) 328 | { 329 | const uint8_t * K = _K; 330 | size_t i; 331 | 332 | /* If Klen > 64, the key is really SHA256(K). */ 333 | if (Klen > 64) { 334 | SHA256_Init(&ctx->ictx); 335 | _SHA256_Update(&ctx->ictx, K, Klen, tmp32); 336 | _SHA256_Final(khash, &ctx->ictx, tmp32); 337 | K = khash; 338 | Klen = 32; 339 | } 340 | 341 | /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ 342 | SHA256_Init(&ctx->ictx); 343 | memset(pad, 0x36, 64); 344 | for (i = 0; i < Klen; i++) 345 | pad[i] ^= K[i]; 346 | _SHA256_Update(&ctx->ictx, pad, 64, tmp32); 347 | 348 | /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ 349 | SHA256_Init(&ctx->octx); 350 | memset(pad, 0x5c, 64); 351 | for (i = 0; i < Klen; i++) 352 | pad[i] ^= K[i]; 353 | _SHA256_Update(&ctx->octx, pad, 64, tmp32); 354 | } 355 | 356 | /* Wrapper function for intermediate-values sanitization. */ 357 | void 358 | HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen) 359 | { 360 | uint32_t tmp32[72]; 361 | uint8_t pad[64]; 362 | uint8_t khash[32]; 363 | 364 | /* Call the real function. */ 365 | _HMAC_SHA256_Init(ctx, _K, Klen, tmp32, pad, khash); 366 | 367 | /* Clean the stack. */ 368 | insecure_memzero(tmp32, 288); 369 | insecure_memzero(khash, 32); 370 | insecure_memzero(pad, 64); 371 | } 372 | 373 | /** 374 | * HMAC_SHA256_Update(ctx, in, len): 375 | * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}. 376 | */ 377 | static void 378 | _HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len, 379 | uint32_t tmp32[static restrict 72]) 380 | { 381 | 382 | /* Feed data to the inner SHA256 operation. */ 383 | _SHA256_Update(&ctx->ictx, in, len, tmp32); 384 | } 385 | 386 | /* Wrapper function for intermediate-values sanitization. */ 387 | void 388 | HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len) 389 | { 390 | uint32_t tmp32[72]; 391 | 392 | /* Call the real function. */ 393 | _HMAC_SHA256_Update(ctx, in, len, tmp32); 394 | 395 | /* Clean the stack. */ 396 | insecure_memzero(tmp32, 288); 397 | } 398 | 399 | /** 400 | * HMAC_SHA256_Final(digest, ctx): 401 | * Output the HMAC-SHA256 of the data input to the context ${ctx} into the 402 | * buffer ${digest}. 403 | */ 404 | static void 405 | _HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx, 406 | uint32_t tmp32[static restrict 72], uint8_t ihash[static restrict 32]) 407 | { 408 | 409 | /* Finish the inner SHA256 operation. */ 410 | _SHA256_Final(ihash, &ctx->ictx, tmp32); 411 | 412 | /* Feed the inner hash to the outer SHA256 operation. */ 413 | _SHA256_Update(&ctx->octx, ihash, 32, tmp32); 414 | 415 | /* Finish the outer SHA256 operation. */ 416 | _SHA256_Final(digest, &ctx->octx, tmp32); 417 | } 418 | 419 | /* Wrapper function for intermediate-values sanitization. */ 420 | void 421 | HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx) 422 | { 423 | uint32_t tmp32[72]; 424 | uint8_t ihash[32]; 425 | 426 | /* Call the real function. */ 427 | _HMAC_SHA256_Final(digest, ctx, tmp32, ihash); 428 | 429 | /* Clean the stack. */ 430 | insecure_memzero(tmp32, 288); 431 | insecure_memzero(ihash, 32); 432 | } 433 | 434 | /** 435 | * HMAC_SHA256_Buf(K, Klen, in, len, digest): 436 | * Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of 437 | * length ${Klen}, and write the result to ${digest}. 438 | */ 439 | void 440 | HMAC_SHA256_Buf(const void * K, size_t Klen, const void * in, size_t len, 441 | uint8_t digest[32]) 442 | { 443 | HMAC_SHA256_CTX ctx; 444 | uint32_t tmp32[72]; 445 | uint8_t tmp8[96]; 446 | 447 | _HMAC_SHA256_Init(&ctx, K, Klen, tmp32, &tmp8[0], &tmp8[64]); 448 | _HMAC_SHA256_Update(&ctx, in, len, tmp32); 449 | _HMAC_SHA256_Final(digest, &ctx, tmp32, &tmp8[0]); 450 | 451 | /* Clean the stack. */ 452 | insecure_memzero(&ctx, sizeof(HMAC_SHA256_CTX)); 453 | insecure_memzero(tmp32, 288); 454 | insecure_memzero(tmp8, 96); 455 | } 456 | 457 | /** 458 | * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): 459 | * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and 460 | * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). 461 | */ 462 | void 463 | PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, 464 | size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) 465 | { 466 | HMAC_SHA256_CTX Phctx, PShctx, hctx; 467 | uint32_t tmp32[72]; 468 | uint8_t tmp8[96]; 469 | size_t i; 470 | uint8_t ivec[4]; 471 | uint8_t U[32]; 472 | uint8_t T[32]; 473 | uint64_t j; 474 | int k; 475 | size_t clen; 476 | 477 | /* Sanity-check. */ 478 | assert(dkLen <= 32 * (size_t)(UINT32_MAX)); 479 | 480 | /* Compute HMAC state after processing P. */ 481 | _HMAC_SHA256_Init(&Phctx, passwd, passwdlen, 482 | tmp32, &tmp8[0], &tmp8[64]); 483 | 484 | /* Compute HMAC state after processing P and S. */ 485 | memcpy(&PShctx, &Phctx, sizeof(HMAC_SHA256_CTX)); 486 | _HMAC_SHA256_Update(&PShctx, salt, saltlen, tmp32); 487 | 488 | /* Iterate through the blocks. */ 489 | for (i = 0; i * 32 < dkLen; i++) { 490 | /* Generate INT(i + 1). */ 491 | be32enc(ivec, (uint32_t)(i + 1)); 492 | 493 | /* Compute U_1 = PRF(P, S || INT(i)). */ 494 | memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX)); 495 | _HMAC_SHA256_Update(&hctx, ivec, 4, tmp32); 496 | _HMAC_SHA256_Final(U, &hctx, tmp32, tmp8); 497 | 498 | /* T_i = U_1 ... */ 499 | memcpy(T, U, 32); 500 | 501 | for (j = 2; j <= c; j++) { 502 | /* Compute U_j. */ 503 | memcpy(&hctx, &Phctx, sizeof(HMAC_SHA256_CTX)); 504 | _HMAC_SHA256_Update(&hctx, U, 32, tmp32); 505 | _HMAC_SHA256_Final(U, &hctx, tmp32, tmp8); 506 | 507 | /* ... xor U_j ... */ 508 | for (k = 0; k < 32; k++) 509 | T[k] ^= U[k]; 510 | } 511 | 512 | /* Copy as many bytes as necessary into buf. */ 513 | clen = dkLen - i * 32; 514 | if (clen > 32) 515 | clen = 32; 516 | memcpy(&buf[i * 32], T, clen); 517 | } 518 | 519 | /* Clean the stack. */ 520 | insecure_memzero(&Phctx, sizeof(HMAC_SHA256_CTX)); 521 | insecure_memzero(&PShctx, sizeof(HMAC_SHA256_CTX)); 522 | insecure_memzero(&hctx, sizeof(HMAC_SHA256_CTX)); 523 | insecure_memzero(tmp32, 288); 524 | insecure_memzero(tmp8, 96); 525 | insecure_memzero(U, 32); 526 | insecure_memzero(T, 32); 527 | } 528 | -------------------------------------------------------------------------------- /ext/scrypt/sha256.h: -------------------------------------------------------------------------------- 1 | #ifndef _SHA256_H_ 2 | #define _SHA256_H_ 3 | 4 | #include 5 | #include 6 | 7 | /* 8 | * Use #defines in order to avoid namespace collisions with anyone else's 9 | * SHA256 code (e.g., the code in OpenSSL). 10 | */ 11 | #define SHA256_Init libcperciva_SHA256_Init 12 | #define SHA256_Update libcperciva_SHA256_Update 13 | #define SHA256_Final libcperciva_SHA256_Final 14 | #define SHA256_Buf libcperciva_SHA256_Buf 15 | #define SHA256_CTX libcperciva_SHA256_CTX 16 | #define HMAC_SHA256_Init libcperciva_HMAC_SHA256_Init 17 | #define HMAC_SHA256_Update libcperciva_HMAC_SHA256_Update 18 | #define HMAC_SHA256_Final libcperciva_HMAC_SHA256_Final 19 | #define HMAC_SHA256_Buf libcperciva_HMAC_SHA256_Buf 20 | #define HMAC_SHA256_CTX libcperciva_HMAC_SHA256_CTX 21 | 22 | /* Context structure for SHA256 operations. */ 23 | typedef struct { 24 | uint32_t state[8]; 25 | uint64_t count; 26 | uint8_t buf[64]; 27 | } SHA256_CTX; 28 | 29 | /** 30 | * SHA256_Init(ctx): 31 | * Initialize the SHA256 context ${ctx}. 32 | */ 33 | void SHA256_Init(SHA256_CTX *); 34 | 35 | /** 36 | * SHA256_Update(ctx, in, len): 37 | * Input ${len} bytes from ${in} into the SHA256 context ${ctx}. 38 | */ 39 | void SHA256_Update(SHA256_CTX *, const void *, size_t); 40 | 41 | /** 42 | * SHA256_Final(digest, ctx): 43 | * Output the SHA256 hash of the data input to the context ${ctx} into the 44 | * buffer ${digest}. 45 | */ 46 | void SHA256_Final(uint8_t[32], SHA256_CTX *); 47 | 48 | /** 49 | * SHA256_Buf(in, len, digest): 50 | * Compute the SHA256 hash of ${len} bytes from $in} and write it to ${digest}. 51 | */ 52 | void SHA256_Buf(const void *, size_t, uint8_t[32]); 53 | 54 | /* Context structure for HMAC-SHA256 operations. */ 55 | typedef struct { 56 | SHA256_CTX ictx; 57 | SHA256_CTX octx; 58 | } HMAC_SHA256_CTX; 59 | 60 | /** 61 | * HMAC_SHA256_Init(ctx, K, Klen): 62 | * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from 63 | * ${K}. 64 | */ 65 | void HMAC_SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t); 66 | 67 | /** 68 | * HMAC_SHA256_Update(ctx, in, len): 69 | * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}. 70 | */ 71 | void HMAC_SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t); 72 | 73 | /** 74 | * HMAC_SHA256_Final(digest, ctx): 75 | * Output the HMAC-SHA256 of the data input to the context ${ctx} into the 76 | * buffer ${digest}. 77 | */ 78 | void HMAC_SHA256_Final(uint8_t[32], HMAC_SHA256_CTX *); 79 | 80 | /** 81 | * HMAC_SHA256_Buf(K, Klen, in, len, digest): 82 | * Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of 83 | * length ${Klen}, and write the result to ${digest}. 84 | */ 85 | void HMAC_SHA256_Buf(const void *, size_t, const void *, size_t, uint8_t[32]); 86 | 87 | /** 88 | * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): 89 | * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and 90 | * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). 91 | */ 92 | void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, 93 | uint64_t, uint8_t *, size_t); 94 | 95 | #endif /* !_SHA256_H_ */ 96 | -------------------------------------------------------------------------------- /ext/scrypt/sysendian.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2007-2009 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * This file was originally written by Colin Percival as part of the Tarsnap 27 | * online backup system. 28 | */ 29 | #ifndef _SYSENDIAN_H_ 30 | #define _SYSENDIAN_H_ 31 | 32 | #include "scrypt_platform.h" 33 | 34 | /* If we don't have be64enc, the we have isn't usable. */ 35 | #if !HAVE_DECL_BE64ENC 36 | #undef HAVE_SYS_ENDIAN_H 37 | #endif 38 | 39 | #ifdef HAVE_SYS_ENDIAN_H 40 | 41 | #include 42 | 43 | #else 44 | 45 | #include 46 | 47 | static inline uint32_t 48 | be32dec(const void *pp) 49 | { 50 | const uint8_t *p = (uint8_t const *)pp; 51 | 52 | return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + 53 | ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); 54 | } 55 | 56 | static inline void 57 | be32enc(void *pp, uint32_t x) 58 | { 59 | uint8_t * p = (uint8_t *)pp; 60 | 61 | p[3] = x & 0xff; 62 | p[2] = (x >> 8) & 0xff; 63 | p[1] = (x >> 16) & 0xff; 64 | p[0] = (x >> 24) & 0xff; 65 | } 66 | 67 | static inline uint64_t 68 | be64dec(const void *pp) 69 | { 70 | const uint8_t *p = (uint8_t const *)pp; 71 | 72 | return ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) + 73 | ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) + 74 | ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) + 75 | ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56)); 76 | } 77 | 78 | static inline void 79 | be64enc(void *pp, uint64_t x) 80 | { 81 | uint8_t * p = (uint8_t *)pp; 82 | 83 | p[7] = x & 0xff; 84 | p[6] = (x >> 8) & 0xff; 85 | p[5] = (x >> 16) & 0xff; 86 | p[4] = (x >> 24) & 0xff; 87 | p[3] = (x >> 32) & 0xff; 88 | p[2] = (x >> 40) & 0xff; 89 | p[1] = (x >> 48) & 0xff; 90 | p[0] = (x >> 56) & 0xff; 91 | } 92 | 93 | static inline uint32_t 94 | le32dec(const void *pp) 95 | { 96 | const uint8_t *p = (uint8_t const *)pp; 97 | 98 | return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + 99 | ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); 100 | } 101 | 102 | static inline void 103 | le32enc(void *pp, uint32_t x) 104 | { 105 | uint8_t * p = (uint8_t *)pp; 106 | 107 | p[0] = x & 0xff; 108 | p[1] = (x >> 8) & 0xff; 109 | p[2] = (x >> 16) & 0xff; 110 | p[3] = (x >> 24) & 0xff; 111 | } 112 | 113 | static inline uint64_t 114 | le64dec(const void *pp) 115 | { 116 | const uint8_t *p = (uint8_t const *)pp; 117 | 118 | return ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) + 119 | ((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) + 120 | ((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) + 121 | ((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56)); 122 | } 123 | 124 | static inline void 125 | le64enc(void *pp, uint64_t x) 126 | { 127 | uint8_t * p = (uint8_t *)pp; 128 | 129 | p[0] = x & 0xff; 130 | p[1] = (x >> 8) & 0xff; 131 | p[2] = (x >> 16) & 0xff; 132 | p[3] = (x >> 24) & 0xff; 133 | p[4] = (x >> 32) & 0xff; 134 | p[5] = (x >> 40) & 0xff; 135 | p[6] = (x >> 48) & 0xff; 136 | p[7] = (x >> 56) & 0xff; 137 | } 138 | #endif /* !HAVE_SYS_ENDIAN_H */ 139 | 140 | #endif /* !_SYSENDIAN_H_ */ 141 | -------------------------------------------------------------------------------- /ext/scrypt/warnp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "warnp.h" 8 | 9 | static int initialized = 0; 10 | static char * name = NULL; 11 | 12 | /* Free the name string. */ 13 | static void 14 | done(void) 15 | { 16 | 17 | free(name); 18 | name = NULL; 19 | } 20 | 21 | /** 22 | * warnp_setprogname(progname): 23 | * Set the program name to be used by warn() and warnx() to ${progname}. 24 | */ 25 | void 26 | warnp_setprogname(const char * progname) 27 | { 28 | const char * p; 29 | 30 | /* Free the name if we already have one. */ 31 | free(name); 32 | 33 | /* Find the last segment of the program name. */ 34 | for (p = progname; progname[0] != '\0'; progname++) 35 | if (progname[0] == '/') 36 | p = progname + 1; 37 | 38 | /* Copy the name string. */ 39 | name = strdup(p); 40 | 41 | /* If we haven't already done so, register our exit handler. */ 42 | if (initialized == 0) { 43 | atexit(done); 44 | initialized = 1; 45 | } 46 | } 47 | 48 | void 49 | warn(const char * fmt, ...) 50 | { 51 | va_list ap; 52 | 53 | va_start(ap, fmt); 54 | fprintf(stderr, "%s", (name != NULL) ? name : "(unknown)"); 55 | if (fmt != NULL) { 56 | fprintf(stderr, ": "); 57 | vfprintf(stderr, fmt, ap); 58 | } 59 | fprintf(stderr, ": %s\n", strerror(errno)); 60 | va_end(ap); 61 | } 62 | 63 | void 64 | warnx(const char * fmt, ...) 65 | { 66 | va_list ap; 67 | 68 | va_start(ap, fmt); 69 | fprintf(stderr, "%s", (name != NULL) ? name : "(unknown)"); 70 | if (fmt != NULL) { 71 | fprintf(stderr, ": "); 72 | vfprintf(stderr, fmt, ap); 73 | } 74 | fprintf(stderr, "\n"); 75 | va_end(ap); 76 | } 77 | -------------------------------------------------------------------------------- /ext/scrypt/warnp.h: -------------------------------------------------------------------------------- 1 | #ifndef _WARNP_H_ 2 | #define _WARNP_H_ 3 | 4 | #include 5 | 6 | /* Avoid namespace collisions with BSD . */ 7 | #define warn libcperciva_warn 8 | #define warnx libcperciva_warnx 9 | 10 | /** 11 | * warnp_setprogname(progname): 12 | * Set the program name to be used by warn() and warnx() to ${progname}. 13 | */ 14 | void warnp_setprogname(const char *); 15 | #define WARNP_INIT do { \ 16 | if (argv[0] != NULL) \ 17 | warnp_setprogname(argv[0]); \ 18 | } while (0) 19 | 20 | /* As in BSD . */ 21 | void warn(const char *, ...); 22 | void warnx(const char *, ...); 23 | 24 | /* 25 | * If compiled with DEBUG defined, print __FILE__ and __LINE__. 26 | */ 27 | #ifdef DEBUG 28 | #define warnline do { \ 29 | warnx("%s, %d", __FILE__, __LINE__); \ 30 | } while (0) 31 | #else 32 | #define warnline 33 | #endif 34 | 35 | /* 36 | * Call warn(3) or warnx(3) depending upon whether errno == 0; and clear 37 | * errno (so that the standard error message isn't repeated later). 38 | */ 39 | #define warnp(...) do { \ 40 | warnline; \ 41 | if (errno != 0) { \ 42 | warn(__VA_ARGS__); \ 43 | errno = 0; \ 44 | } else \ 45 | warnx(__VA_ARGS__); \ 46 | } while (0) 47 | 48 | /* 49 | * Call warnx(3) and set errno == 0. Unlike warnp, this should be used 50 | * in cases where we're reporting a problem which we discover ourselves 51 | * rather than one which is reported to us from a library or the kernel. 52 | */ 53 | #define warn0(...) do { \ 54 | warnline; \ 55 | warnx(__VA_ARGS__); \ 56 | errno = 0; \ 57 | } while (0) 58 | 59 | #endif /* !_WARNP_H_ */ 60 | -------------------------------------------------------------------------------- /kdf-comparison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbhogan/scrypt/ce9a1c5789d5904f0294d0dce68e8f2fb184afa5/kdf-comparison.png -------------------------------------------------------------------------------- /lib/scrypt.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # A wrapper for the scrypt algorithm. 4 | 5 | require 'scrypt/errors' 6 | require 'scrypt/scrypt_ext' 7 | require 'scrypt/security_utils' 8 | 9 | require 'scrypt/engine' 10 | require 'scrypt/password' 11 | -------------------------------------------------------------------------------- /lib/scrypt/engine.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'ffi' 4 | require 'openssl' 5 | 6 | module SCrypt 7 | module Ext 8 | # rubocop:disable Style/SymbolArray 9 | # Bind the external functions 10 | attach_function :sc_calibrate, 11 | [:size_t, :double, :double, :pointer], 12 | :int, 13 | blocking: true 14 | 15 | attach_function :crypto_scrypt, 16 | [:pointer, :size_t, :pointer, :size_t, :uint64, :uint32, :uint32, :pointer, :size_t], 17 | :int, 18 | blocking: true # todo 19 | # rubocop:enable 20 | end 21 | 22 | class Engine 23 | # rubocop:disable Style/MutableConstant 24 | DEFAULTS = { 25 | key_len: 32, 26 | salt_size: 32, 27 | max_mem: 16 * 1024 * 1024, 28 | max_memfrac: 0.5, 29 | max_time: 0.2, 30 | cost: nil 31 | } 32 | # rubocop:enable 33 | 34 | class Calibration < FFI::Struct 35 | layout :n, :uint64, 36 | :r, :uint32, 37 | :p, :uint32 38 | end 39 | 40 | class << self 41 | def scrypt(secret, salt, *args) 42 | if args.length == 2 43 | # args is [cost_string, key_len] 44 | n, r, p = args[0].split('$').map { |x| x.to_i(16) } 45 | key_len = args[1] 46 | 47 | __sc_crypt(secret, salt, n, r, p, key_len) 48 | elsif args.length == 4 49 | # args is [n, r, p, key_len] 50 | n, r, p = args[0, 3] 51 | key_len = args[3] 52 | 53 | __sc_crypt(secret, salt, n, r, p, key_len) 54 | else 55 | raise ArgumentError, 'invalid number of arguments (4 or 6)' 56 | end 57 | end 58 | 59 | # Given a secret and a valid salt (see SCrypt::Engine.generate_salt) calculates an scrypt password hash. 60 | def hash_secret(secret, salt, key_len = DEFAULTS[:key_len]) 61 | raise Errors::InvalidSecret, 'invalid secret' unless valid_secret?(secret) 62 | raise Errors::InvalidSalt, 'invalid salt' unless valid_salt?(salt) 63 | 64 | cost = autodetect_cost(salt) 65 | salt_only = salt[/\$([A-Za-z0-9]{16,64})$/, 1] 66 | 67 | if salt_only.length == 40 68 | # Old-style hash with 40-character salt 69 | salt + '$' + Digest::SHA1.hexdigest(scrypt(secret.to_s, salt, cost, 256)) 70 | else 71 | # New-style hash 72 | salt_only = [salt_only.sub(/^(00)+/, '')].pack('H*') 73 | salt + '$' + scrypt(secret.to_s, salt_only, cost, key_len).unpack('H*').first.rjust(key_len * 2, '0') 74 | end 75 | end 76 | 77 | # Generates a random salt with a given computational cost. Uses a saved 78 | # cost if SCrypt::Engine.calibrate! has been called. 79 | # 80 | # Options: 81 | # :cost is a cost string returned by SCrypt::Engine.calibrate 82 | def generate_salt(options = {}) 83 | options = DEFAULTS.merge(options) 84 | cost = options[:cost] || calibrate(options) 85 | salt = OpenSSL::Random.random_bytes(options[:salt_size]).unpack('H*').first.rjust(16, '0') 86 | 87 | if salt.length == 40 88 | # If salt is 40 characters, the regexp will think that it is an old-style hash, so add a '0'. 89 | salt = '0' + salt 90 | end 91 | cost + salt 92 | end 93 | 94 | # Returns true if +cost+ is a valid cost, false if not. 95 | def valid_cost?(cost) 96 | cost.match(/^[0-9a-z]+\$[0-9a-z]+\$[0-9a-z]+\$$/) != nil 97 | end 98 | 99 | # Returns true if +salt+ is a valid salt, false if not. 100 | def valid_salt?(salt) 101 | salt.match(/^[0-9a-z]+\$[0-9a-z]+\$[0-9a-z]+\$[A-Za-z0-9]{16,64}$/) != nil 102 | end 103 | 104 | # Returns true if +secret+ is a valid secret, false if not. 105 | def valid_secret?(secret) 106 | secret.respond_to?(:to_s) 107 | end 108 | 109 | # Returns the cost value which will result in computation limits less than the given options. 110 | # 111 | # Options: 112 | # :max_time specifies the maximum number of seconds the computation should take. 113 | # :max_mem specifies the maximum number of bytes the computation should take. A value of 0 specifies no upper limit. The minimum is always 1 MB. 114 | # :max_memfrac specifies the maximum memory in a fraction of available resources to use. Any value equal to 0 or greater than 0.5 will result in 0.5 being used. 115 | # 116 | # Example: 117 | # 118 | # # should take less than 200ms 119 | # SCrypt::Engine.calibrate(:max_time => 0.2) 120 | # 121 | def calibrate(options = {}) 122 | options = DEFAULTS.merge(options) 123 | '%x$%x$%x$' % __sc_calibrate(options[:max_mem], options[:max_memfrac], options[:max_time]) 124 | end 125 | 126 | # Calls SCrypt::Engine.calibrate and saves the cost string for future calls to 127 | # SCrypt::Engine.generate_salt. 128 | def calibrate!(options = {}) 129 | DEFAULTS[:cost] = calibrate(options) 130 | end 131 | 132 | # Computes the memory use of the given +cost+ 133 | def memory_use(cost) 134 | n, r, p = cost.split('$').map { |i| i.to_i(16) } 135 | (128 * r * p) + (256 * r) + (128 * r * n) 136 | end 137 | 138 | # Autodetects the cost from the salt string. 139 | def autodetect_cost(salt) 140 | salt[/^[0-9a-z]+\$[0-9a-z]+\$[0-9a-z]+\$/] 141 | end 142 | 143 | private 144 | 145 | def __sc_calibrate(max_mem, max_memfrac, max_time) 146 | result = nil 147 | 148 | calibration = Calibration.new 149 | ret_val = SCrypt::Ext.sc_calibrate(max_mem, max_memfrac, max_time, calibration) 150 | 151 | raise "calibration error #{result}" unless ret_val.zero? 152 | 153 | [calibration[:n], calibration[:r], calibration[:p]] 154 | end 155 | 156 | def __sc_crypt(secret, salt, n, r, p, key_len) 157 | result = nil 158 | 159 | FFI::MemoryPointer.new(:char, key_len) do |buffer| 160 | ret_val = SCrypt::Ext.crypto_scrypt( 161 | secret, secret.bytesize, salt, salt.bytesize, 162 | n, r, p, 163 | buffer, key_len 164 | ) 165 | 166 | raise "scrypt error #{ret_val}" unless ret_val.zero? 167 | 168 | result = buffer.read_string(key_len) 169 | end 170 | 171 | result 172 | end 173 | end 174 | end 175 | end 176 | -------------------------------------------------------------------------------- /lib/scrypt/errors.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SCrypt 4 | module Errors 5 | # The salt parameter provided is invalid. 6 | class InvalidSalt < StandardError; end 7 | 8 | # The hash parameter provided is invalid. 9 | class InvalidHash < StandardError; end 10 | 11 | # The secret parameter provided is invalid. 12 | class InvalidSecret < StandardError; end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/scrypt/password.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SCrypt 4 | # A password management class which allows you to safely store users' passwords and compare them. 5 | # 6 | # Example usage: 7 | # 8 | # include "scrypt" 9 | # 10 | # # hash a user's password 11 | # @password = Password.create("my grand secret") 12 | # @password #=> "2000$8$1$f5f2fa5fe5484a7091f1299768fbe92b5a7fbc77$6a385f22c54d92c314b71a4fd5ef33967c93d679" 13 | # 14 | # # store it safely 15 | # @user.update_attribute(:password, @password) 16 | # 17 | # # read it back 18 | # @user.reload! 19 | # @db_password = Password.new(@user.password) 20 | # 21 | # # compare it after retrieval 22 | # @db_password == "my grand secret" #=> true 23 | # @db_password == "a paltry guess" #=> false 24 | # 25 | class Password < String 26 | # The hash portion of the stored password hash. 27 | attr_reader :digest 28 | # The salt of the store password hash 29 | attr_reader :salt 30 | # The cost factor used to create the hash. 31 | attr_reader :cost 32 | 33 | class << self 34 | # Hashes a secret, returning a SCrypt::Password instance. 35 | # Takes five options (optional), which will determine the salt/key's length and the cost limits of the computation. 36 | # :key_len specifies the length in bytes of the key you want to generate. The default is 32 bytes (256 bits). Minimum is 16 bytes (128 bits). Maximum is 512 bytes (4096 bits). 37 | # :salt_size specifies the size in bytes of the random salt you want to generate. The default and minimum is 8 bytes (64 bits). Maximum is 32 bytes (256 bits). 38 | # :max_time specifies the maximum number of seconds the computation should take. 39 | # :max_mem specifies the maximum number of bytes the computation should take. A value of 0 specifies no upper limit. The minimum is always 1 MB. 40 | # :max_memfrac specifies the maximum memory in a fraction of available resources to use. Any value equal to 0 or greater than 0.5 will result in 0.5 being used. 41 | # The scrypt key derivation function is designed to be far more secure against hardware brute-force attacks than alternative functions such as PBKDF2 or bcrypt. 42 | # The designers of scrypt estimate that on modern (2009) hardware, if 5 seconds are spent computing a derived key, the cost of a hardware brute-force attack against scrypt is roughly 4000 times greater than the cost of a similar attack against bcrypt (to find the same password), and 20000 times greater than a similar attack against PBKDF2. 43 | # Default options will result in calculation time of approx. 200 ms with 1 MB memory use. 44 | # 45 | # Example: 46 | # @password = SCrypt::Password.create("my secret", :max_time => 0.25) 47 | # 48 | def create(secret, options = {}) 49 | options = SCrypt::Engine::DEFAULTS.merge(options) 50 | 51 | # Clamp minimum/maximum keylen 52 | options[:key_len] = 16 if options[:key_len] < 16 53 | options[:key_len] = 512 if options[:key_len] > 512 54 | 55 | # Clamp minimum/maximum salt_size 56 | options[:salt_size] = 8 if options[:salt_size] < 8 57 | options[:salt_size] = 32 if options[:salt_size] > 32 58 | 59 | salt = SCrypt::Engine.generate_salt(options) 60 | hash = SCrypt::Engine.hash_secret(secret, salt, options[:key_len]) 61 | 62 | Password.new(hash) 63 | end 64 | end 65 | 66 | # Initializes a SCrypt::Password instance with the data from a stored hash. 67 | def initialize(raw_hash) 68 | raise Errors::InvalidHash, 'invalid hash' unless valid_hash?(raw_hash) 69 | 70 | replace(raw_hash) 71 | 72 | @cost, @salt, @digest = split_hash(to_s) 73 | end 74 | 75 | # Compares a potential secret against the hash. Returns true if the secret is the original secret, false otherwise. 76 | def ==(other) 77 | SecurityUtils.secure_compare(self, SCrypt::Engine.hash_secret(other, @cost + @salt, digest.length / 2)) 78 | end 79 | alias is_password? == 80 | 81 | private 82 | 83 | # Returns true if +h+ is a valid hash. 84 | def valid_hash?(h) 85 | h.match(/^[0-9a-z]+\$[0-9a-z]+\$[0-9a-z]+\$[A-Za-z0-9]{16,64}\$[A-Za-z0-9]{32,1024}$/) != nil 86 | end 87 | 88 | # call-seq: 89 | # split_hash(raw_hash) -> cost, salt, hash 90 | # 91 | # Splits +h+ into cost, salt, and hash and returns them in that order. 92 | def split_hash(h) 93 | n, v, r, salt, hash = h.split('$') 94 | [[n, v, r].join('$') + '$', salt, hash] 95 | end 96 | end 97 | end 98 | -------------------------------------------------------------------------------- /lib/scrypt/scrypt_ext.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'ffi' 4 | require 'ffi-compiler/loader' 5 | 6 | module SCrypt 7 | module Ext 8 | extend FFI::Library 9 | 10 | ffi_lib FFI::Compiler::Loader.find('scrypt_ext') 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/scrypt/security_utils.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # NOTE:: a verbatim copy of https://github.com/rails/rails/blob/c8c660002f4b0e9606de96325f20b95248b6ff2d/activesupport/lib/active_support/security_utils.rb 4 | # Please see the Rails license: https://github.com/rails/rails/blob/master/activesupport/MIT-LICENSE 5 | 6 | module SCrypt 7 | module SecurityUtils 8 | # Constant time string comparison. 9 | # 10 | # The values compared should be of fixed length, such as strings 11 | # that have already been processed by HMAC. This should not be used 12 | # on variable length plaintext strings because it could leak length info 13 | # via timing attacks. 14 | def self.secure_compare(a, b) 15 | return false unless a.bytesize == b.bytesize 16 | 17 | l = a.unpack "C#{a.bytesize}" 18 | 19 | res = 0 20 | b.each_byte { |byte| res |= byte ^ l.shift } 21 | res.zero? 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/scrypt/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SCrypt 4 | VERSION = "3.0.8" 5 | end 6 | -------------------------------------------------------------------------------- /scrypt.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # rubocop:disable Performance/EndWith, Style/SpecialGlobalVars 4 | 5 | $:.push File.expand_path("../lib", __FILE__) 6 | require 'scrypt/version' 7 | 8 | Gem::Specification.new do |s| 9 | s.name = 'scrypt' 10 | s.version = SCrypt::VERSION 11 | s.authors = ['Patrick Hogan', 12 | 'Stephen von Takach', 13 | 'Rene van Paassen', 14 | 'Johanns Gregorian'] 15 | s.email = ['pbhogan@gmail.com', 16 | 'steve@advancedcontrol.com.au', 17 | 'rene.vanpaassen@gmail.com', 18 | 'io+scrypt@jsg.io'] 19 | s.cert_chain = ['certs/pbhogan.pem'] 20 | s.license = 'BSD-3-Clause' 21 | 22 | s.signing_key = File.expand_path('~/.ssh/gem-private_key.pem') if $0 =~ /gem\z/ 23 | 24 | s.homepage = 'https://github.com/pbhogan/scrypt' 25 | s.summary = 'scrypt password hashing algorithm.' 26 | 27 | s.description = <<-DESC 28 | The scrypt key derivation function is designed to be far 29 | more secure against hardware brute-force attacks than 30 | alternative functions such as PBKDF2 or bcrypt. 31 | DESC 32 | 33 | s.required_ruby_version = '>= 2.3.0' 34 | 35 | s.add_dependency 'ffi-compiler', '>= 1.0', '< 2.0' 36 | s.add_dependency 'rake', '>= 9', '< 14' 37 | s.add_development_dependency 'awesome_print', '>= 1', '< 2' 38 | s.add_development_dependency 'rake', '>= 9', '< 14' 39 | s.add_development_dependency 'rdoc', '>= 4', '< 5' 40 | s.add_development_dependency 'rspec', '>= 3', '< 4' 41 | 42 | if RUBY_VERSION >= '2.5' 43 | s.add_development_dependency 'rubocop', '>= 0.76.0', '< 1.0.0' 44 | s.add_development_dependency 'rubocop-gitlab-security', '>= 0.1.1', '< 0.2' 45 | s.add_development_dependency 'rubocop-performance', '>= 1.5.0', '< 1.6.0' 46 | end 47 | 48 | s.extensions = ['ext/scrypt/Rakefile'] 49 | 50 | s.files = %w[Rakefile scrypt.gemspec README.md COPYING] + Dir.glob('{lib,spec,autotest}/**/*') 51 | s.files += Dir.glob('ext/scrypt/*') 52 | s.test_files = Dir.glob('spec/**/*') 53 | s.require_paths = ['lib'] 54 | end 55 | 56 | # rubocop:enable 57 | -------------------------------------------------------------------------------- /spec/scrypt/engine_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) 4 | 5 | describe 'The SCrypt engine' do 6 | it 'should calculate a valid cost factor' do 7 | first = SCrypt::Engine.calibrate(max_time: 0.2) 8 | expect(SCrypt::Engine.valid_cost?(first)).to equal(true) 9 | end 10 | end 11 | 12 | describe 'Generating SCrypt salts' do 13 | it 'should produce strings' do 14 | expect(SCrypt::Engine.generate_salt).to be_an_instance_of(String) 15 | end 16 | 17 | it 'should produce random data' do 18 | expect(SCrypt::Engine.generate_salt).not_to equal(SCrypt::Engine.generate_salt) 19 | end 20 | 21 | it 'should used the saved cost factor' do 22 | # Verify cost is different before saving 23 | cost = SCrypt::Engine.calibrate(max_time: 0.01) 24 | expect(SCrypt::Engine.generate_salt(max_time: 30, max_mem: 64 * 1024 * 1024)).not_to start_with(cost) 25 | 26 | cost = SCrypt::Engine.calibrate!(max_time: 0.01) 27 | expect(SCrypt::Engine.generate_salt(max_time: 30, max_mem: 64 * 1024 * 1024)).to start_with(cost) 28 | end 29 | end 30 | 31 | describe 'Autodetecting of salt cost' do 32 | it 'should work' do 33 | expect(SCrypt::Engine.autodetect_cost('2a$08$c3$randomjunkgoeshere')).to eq('2a$08$c3$') 34 | end 35 | end 36 | 37 | describe 'Generating SCrypt hashes' do 38 | class MyInvalidSecret 39 | undef to_s 40 | end 41 | 42 | before :each do 43 | @salt = SCrypt::Engine.generate_salt 44 | @password = 'woo' 45 | end 46 | 47 | it 'should produce a string' do 48 | expect(SCrypt::Engine.hash_secret(@password, @salt)).to be_an_instance_of(String) 49 | end 50 | 51 | it 'should raise an InvalidSalt error if the salt is invalid' do 52 | expect { SCrypt::Engine.hash_secret(@password, 'nino') }.to raise_error(SCrypt::Errors::InvalidSalt) 53 | end 54 | 55 | it 'should raise an InvalidSecret error if the secret is invalid' do 56 | expect { SCrypt::Engine.hash_secret(MyInvalidSecret.new, @salt) }.to raise_error(SCrypt::Errors::InvalidSecret) 57 | expect { SCrypt::Engine.hash_secret(nil, @salt) }.to_not raise_error 58 | expect { SCrypt::Engine.hash_secret(false, @salt) }.to_not raise_error 59 | end 60 | 61 | it 'should call #to_s on the secret and use the return value as the actual secret data' do 62 | expect(SCrypt::Engine.hash_secret(false, @salt)).to eq(SCrypt::Engine.hash_secret('false', @salt)) 63 | end 64 | end 65 | 66 | describe 'SCrypt test vectors' do 67 | it 'should match results of SCrypt function' do 68 | expect(SCrypt::Engine.scrypt('', '', 16, 1, 1, 64).unpack('H*').first).to eq('77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906') 69 | expect(SCrypt::Engine.scrypt('password', 'NaCl', 1024, 8, 16, 64).unpack('H*').first).to eq('fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640') 70 | expect(SCrypt::Engine.scrypt('pleaseletmein', 'SodiumChloride', 16_384, 8, 1, 64).unpack('H*').first).to eq('7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887') 71 | # Raspberry is memory limited, and fails on this test 72 | # expect(SCrypt::Engine.scrypt('pleaseletmein', 'SodiumChloride', 1048576, 8, 1, 64).unpack('H*').first).to eq('2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049e8a952fbcbf45c6fa77a41a4') 73 | end 74 | 75 | it 'should match equivalent results sent through hash_secret() function' do 76 | expect(SCrypt::Engine.hash_secret('', '10$1$1$0000000000000000', 64)).to match(/\$77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906$/) 77 | expect(SCrypt::Engine.hash_secret('password', '400$8$10$000000004e61436c', 64)).to match(/\$fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640$/) 78 | expect(SCrypt::Engine.hash_secret('pleaseletmein', '4000$8$1$536f6469756d43686c6f72696465', 64)).to match(/\$7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887$/) 79 | # expect(SCrypt::Engine.hash_secret('pleaseletmein', '100000$8$1$536f6469756d43686c6f72696465', 64)).to match(/\$2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049e8a952fbcbf45c6fa77a41a4$/) 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /spec/scrypt/password_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) 4 | 5 | describe 'Creating a hashed password' do 6 | before :each do 7 | @password = SCrypt::Password.create('s3cr3t', max_time: 0.25) 8 | end 9 | 10 | it 'should return a SCrypt::Password' do 11 | expect(@password).to be_an_instance_of(SCrypt::Password) 12 | end 13 | 14 | it 'should return a valid password' do 15 | expect(-> { SCrypt::Password.new(@password) }).to_not raise_error 16 | end 17 | 18 | it 'should behave normally if the secret is not a string' do 19 | expect(-> { SCrypt::Password.create(nil) }).to_not raise_error 20 | expect(-> { SCrypt::Password.create(woo: 'yeah') }).to_not raise_error 21 | expect(-> { SCrypt::Password.create(false) }).to_not raise_error 22 | end 23 | 24 | it 'should tolerate empty string secrets' do 25 | expect(-> { SCrypt::Password.create("\n".chop) }).to_not raise_error 26 | expect(-> { SCrypt::Password.create('') }).to_not raise_error 27 | expect(-> { SCrypt::Password.create('') }).to_not raise_error 28 | end 29 | end 30 | 31 | describe 'Reading a hashed password' do 32 | before :each do 33 | @secret = 'my secret' 34 | @hash = '400$8$d$173a8189751c095a29b933789560b73bf17b2e01$9bf66d74bd6f3ebcf99da3b379b689b89db1cb07' 35 | end 36 | 37 | it 'should read the cost, salt, and hash' do 38 | password = SCrypt::Password.new(@hash) 39 | expect(password.cost).to eq('400$8$d$') 40 | expect(password.salt).to eq('173a8189751c095a29b933789560b73bf17b2e01') 41 | expect(password.to_s).to eq(@hash) 42 | end 43 | 44 | it 'should raise an InvalidHashError when given an invalid hash' do 45 | expect { SCrypt::Password.new('not a valid hash') }.to raise_error(SCrypt::Errors::InvalidHash) 46 | end 47 | end 48 | 49 | describe 'Comparing a hashed password with a secret' do 50 | before :each do 51 | @secret = 's3cr3t' 52 | @password = SCrypt::Password.create(@secret) 53 | end 54 | 55 | it 'should compare successfully to the original secret' do 56 | expect((@password == @secret)).to be(true) 57 | end 58 | 59 | it 'should compare unsuccessfully to anything besides original secret' do 60 | expect((@password == '@secret')).to be(false) 61 | end 62 | end 63 | 64 | describe 'non-default salt sizes' do 65 | before :each do 66 | @secret = 's3cret' 67 | end 68 | 69 | it 'should enforce a minimum salt of 8 bytes' do 70 | @password = SCrypt::Password.create(@secret, salt_size: 7) 71 | expect(@password.salt.length).to eq(8 * 2) 72 | end 73 | 74 | it 'should allow a salt of 32 bytes' do 75 | @password = SCrypt::Password.create(@secret, salt_size: 32) 76 | expect(@password.salt.length).to eq(32 * 2) 77 | end 78 | 79 | it 'should enforce a maximum salt of 32 bytes' do 80 | @password = SCrypt::Password.create(@secret, salt_size: 33) 81 | expect(@password.salt.length).to eq(32 * 2) 82 | end 83 | 84 | it 'should pad a 20-byte salt to not look like a 20-byte SHA1' do 85 | @password = SCrypt::Password.create(@secret, salt_size: 20) 86 | expect(@password.salt.length).to eq(41) 87 | end 88 | 89 | it 'should properly compare a non-standard salt hash' do 90 | @password = SCrypt::Password.create(@secret, salt_size: 20) 91 | expect((SCrypt::Password.new(@password.to_s) == @secret)).to be(true) 92 | end 93 | end 94 | 95 | describe 'non-default key lengths' do 96 | before :each do 97 | @secret = 's3cret' 98 | end 99 | 100 | it 'should enforce a minimum keylength of 16 bytes' do 101 | @password = SCrypt::Password.create(@secret, key_len: 15) 102 | expect(@password.digest.length).to eq(16 * 2) 103 | end 104 | 105 | it 'should allow a keylength of 512 bytes' do 106 | @password = SCrypt::Password.create(@secret, key_len: 512) 107 | expect(@password.digest.length).to eq(512 * 2) 108 | end 109 | 110 | it 'should enforce a maximum keylength of 512 bytes' do 111 | @password = SCrypt::Password.create(@secret, key_len: 513) 112 | expect(@password.digest.length).to eq(512 * 2) 113 | end 114 | 115 | it 'should properly compare a non-standard hash' do 116 | @password = SCrypt::Password.create(@secret, key_len: 512) 117 | expect((SCrypt::Password.new(@password.to_s) == @secret)).to be(true) 118 | end 119 | end 120 | 121 | describe 'Old-style hashes' do 122 | before :each do 123 | @secret = 'my secret' 124 | @hash = '400$8$d$173a8189751c095a29b933789560b73bf17b2e01$9bf66d74bd6f3ebcf99da3b379b689b89db1cb07' 125 | end 126 | 127 | it 'should compare successfully' do 128 | expect((SCrypt::Password.new(@hash) == @secret)).to be(true) 129 | end 130 | end 131 | 132 | describe 'Respecting standard ruby behaviors' do 133 | it 'should hash as an integer' do 134 | password = SCrypt::Password.create('') 135 | expect(password.hash).to be_kind_of(Integer) 136 | end 137 | end 138 | -------------------------------------------------------------------------------- /spec/scrypt/utils_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) 4 | 5 | describe 'Security Utils' do 6 | it 'should perform a string comparison' do 7 | expect(SCrypt::SecurityUtils.secure_compare('a', 'a')).to equal(true) 8 | expect(SCrypt::SecurityUtils.secure_compare('a', 'b')).to equal(false) 9 | expect(SCrypt::SecurityUtils.secure_compare('aa', 'aa')).to equal(true) 10 | expect(SCrypt::SecurityUtils.secure_compare('aa', 'ab')).to equal(false) 11 | expect(SCrypt::SecurityUtils.secure_compare('aa', 'aaa')).to equal(false) 12 | expect(SCrypt::SecurityUtils.secure_compare('aaa', 'aa')).to equal(false) 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib')) 4 | 5 | require 'rubygems' 6 | require 'rspec' 7 | require 'scrypt' 8 | --------------------------------------------------------------------------------