bcrypt_pbkdf 1.1.1.rc2-arm64-darwin
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +48 -0
- data/.gitignore +5 -0
- data/CHANGELOG.md +3 -0
- data/COPYING +23 -0
- data/Gemfile +2 -0
- data/README.md +32 -0
- data/Rakefile +168 -0
- data/bcrypt_pbkdf.gemspec +28 -0
- data/ext/mri/bcrypt_pbkdf.c +169 -0
- data/ext/mri/bcrypt_pbkdf_ext.c +44 -0
- data/ext/mri/blf.h +90 -0
- data/ext/mri/blowfish.c +698 -0
- data/ext/mri/crypto_api.h +3 -0
- data/ext/mri/crypto_hash_sha512.h +19 -0
- data/ext/mri/explicit_bzero.c +20 -0
- data/ext/mri/extconf.rb +3 -0
- data/ext/mri/hash_sha512.c +320 -0
- data/ext/mri/includes.h +27 -0
- data/ext/mri/sha2.h +13 -0
- data/ext/mri/util.h +0 -0
- data/ext/mri/utils.h +5 -0
- data/lib/2.7/bcrypt_pbkdf_ext.bundle +0 -0
- data/lib/3.0/bcrypt_pbkdf_ext.bundle +0 -0
- data/lib/3.1/bcrypt_pbkdf_ext.bundle +0 -0
- data/lib/3.2/bcrypt_pbkdf_ext.bundle +0 -0
- data/lib/3.3/bcrypt_pbkdf_ext.bundle +0 -0
- data/lib/bcrypt_pbkdf.rb +24 -0
- data/test/bcrypt_pnkdf/engine_test.rb +77 -0
- data/test/test_helper.rb +2 -0
- metadata +155 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1844d4c1eb29b66d9fe5f690f9037d296c75622501574a7207da823644424aec
|
4
|
+
data.tar.gz: 38c09be3cc4098edec514495520f5c5d3ba8e50d20daedf2da64b7d872c527cb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dff4a5add34aa8645dd3654019d113ba49a52c1abda5eeb3fd97316a66f9b40f51418f94b08ffcc53c68ce3c1b49a282c9d1d83ee0c4719139342f401f976c96
|
7
|
+
data.tar.gz: 5edf90ed50c402747cef0be9b11480843cc02434b4ab50d3e12db17aebea29170ef6876305fa5487d70c2747f97cc847cddb63282bfc702440eeeed7c0a9ace1
|
@@ -0,0 +1,48 @@
|
|
1
|
+
---
|
2
|
+
name: ci
|
3
|
+
|
4
|
+
on:
|
5
|
+
pull_request:
|
6
|
+
branches: [ main ]
|
7
|
+
push:
|
8
|
+
branches: [ main ]
|
9
|
+
workflow_dispatch:
|
10
|
+
|
11
|
+
concurrency:
|
12
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
13
|
+
cancel-in-progress: true
|
14
|
+
|
15
|
+
jobs:
|
16
|
+
windows:
|
17
|
+
name: ${{ matrix.os }} ruby ${{ matrix.ruby }}
|
18
|
+
strategy:
|
19
|
+
fail-fast: false
|
20
|
+
matrix:
|
21
|
+
ruby: [2.7, 3.3, head, mingw, mswin, ucrt]
|
22
|
+
os: [windows-latest]
|
23
|
+
runs-on: ${{ matrix.os }}
|
24
|
+
steps:
|
25
|
+
- uses: actions/checkout@v4
|
26
|
+
- uses: ruby/setup-ruby@v1
|
27
|
+
with:
|
28
|
+
ruby-version: ${{ matrix.ruby }}
|
29
|
+
bundler-cache: true
|
30
|
+
- run: bundle exec rake compile
|
31
|
+
- run: bundle exec rake test
|
32
|
+
|
33
|
+
unix:
|
34
|
+
name: ${{ matrix.os }} ruby ${{ matrix.ruby }}
|
35
|
+
strategy:
|
36
|
+
fail-fast: false
|
37
|
+
matrix:
|
38
|
+
ruby: [2.7, 3.3, head]
|
39
|
+
os: [ubuntu-latest, macos-latest]
|
40
|
+
runs-on: ${{ matrix.os }}
|
41
|
+
steps:
|
42
|
+
- uses: actions/checkout@v4
|
43
|
+
- uses: ruby/setup-ruby@v1
|
44
|
+
with:
|
45
|
+
ruby-version: ${{ matrix.ruby }}
|
46
|
+
bundler-cache: true
|
47
|
+
- run: bundle exec rake compile
|
48
|
+
- run: bundle exec rake test
|
data/CHANGELOG.md
ADDED
data/COPYING
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright 2007-2016: Miklós Fazekas <mfazekas@szemafor.com>
|
4
|
+
C implementation of bcrypt_pbkdf: OpenBSD: Copyright (c) 2013 Ted Unangst <tedu@openbsd.org>
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
a copy of this software and associated documentation files (the
|
8
|
+
'Software'), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
20
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
21
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
22
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
23
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# bcrypt_pbkdf-ruby
|
2
|
+
|
3
|
+
bcrypt_pbkdf is a ruby gem implementing bcrypt_pbkdf from OpenBSD. This is currently used by net-ssh to read password encrypted Ed25519 keys.
|
4
|
+
|
5
|
+
[![Build Status](https://github.com/net-ssh/bcrypt_pbkdf-ruby/actions/workflows/ci.yml/badge.svg?branch=master&event=push)](https://github.com/net-ssh/bcrypt_pbkdf-ruby/actions/workflows/ci.yml)
|
6
|
+
|
7
|
+
## Acknowledgements
|
8
|
+
|
9
|
+
* The gut of the code is based on OpenBSD's bcrypt_pbkdf.c implementation
|
10
|
+
* Some ideas/code were taken adopted bcrypt-ruby: https://github.com/codahale/bcrypt-ruby
|
11
|
+
|
12
|
+
## Links
|
13
|
+
|
14
|
+
* http://www.tedunangst.com/flak/post/bcrypt-pbkdf
|
15
|
+
* http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libutil/bcrypt_pbkdf.c?rev=1.13&content-type=text/x-cvsweb-markup
|
16
|
+
|
17
|
+
## Building
|
18
|
+
|
19
|
+
For windows and osx cross build make sure you checked out the gem source under the home directory and have docker installed.
|
20
|
+
|
21
|
+
```sh
|
22
|
+
gem install rake-compiler-dock
|
23
|
+
```
|
24
|
+
|
25
|
+
```sh
|
26
|
+
bundle exec rake compile
|
27
|
+
bundle exec rake test
|
28
|
+
bundle exec rake clean clobber
|
29
|
+
bundle exec rake gem:all
|
30
|
+
bundle exec rake release
|
31
|
+
bundle exec rake gem:release
|
32
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require 'rubygems/package_task'
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/extensiontask'
|
5
|
+
require 'rake/clean'
|
6
|
+
require 'rdoc/task'
|
7
|
+
require 'benchmark'
|
8
|
+
require 'rake_compiler_dock'
|
9
|
+
|
10
|
+
CLEAN.add("{ext,lib}/**/*.{o,so}", "pkg")
|
11
|
+
|
12
|
+
cross_rubies = ["3.3.0", "3.2.0", "3.1.0", "3.0.0", "2.7.0"]
|
13
|
+
cross_platforms = [
|
14
|
+
"arm64-darwin",
|
15
|
+
"x64-mingw-ucrt",
|
16
|
+
"x64-mingw32",
|
17
|
+
"x86-mingw32",
|
18
|
+
"x86_64-darwin",
|
19
|
+
]
|
20
|
+
ENV["RUBY_CC_VERSION"] = cross_rubies.join(":")
|
21
|
+
|
22
|
+
GEMSPEC = Gem::Specification.load("bcrypt_pbkdf.gemspec")
|
23
|
+
|
24
|
+
task :default => [:compile, :spec]
|
25
|
+
|
26
|
+
desc "Run all tests"
|
27
|
+
Rake::TestTask.new do |t|
|
28
|
+
#t.pattern =
|
29
|
+
t.test_files = FileList['test/**/*_test.rb']
|
30
|
+
t.ruby_opts = ['-w']
|
31
|
+
t.libs << "test"
|
32
|
+
t.verbose = true
|
33
|
+
end
|
34
|
+
task :spec => :test
|
35
|
+
|
36
|
+
desc 'Generate RDoc'
|
37
|
+
RDoc::Task.new do |rdoc|
|
38
|
+
rdoc.rdoc_dir = 'doc/rdoc'
|
39
|
+
rdoc.options += GEMSPEC.rdoc_options
|
40
|
+
rdoc.template = ENV['TEMPLATE'] if ENV['TEMPLATE']
|
41
|
+
rdoc.rdoc_files.include(*GEMSPEC.extra_rdoc_files)
|
42
|
+
end
|
43
|
+
|
44
|
+
Rake::ExtensionTask.new("bcrypt_pbkdf_ext", GEMSPEC) do |ext|
|
45
|
+
ext.ext_dir = 'ext/mri'
|
46
|
+
ext.cross_compile = true
|
47
|
+
ext.cross_platform = cross_platforms
|
48
|
+
ext.cross_config_options << "--enable-cross-build" # so extconf.rb knows we're cross-compiling
|
49
|
+
end
|
50
|
+
|
51
|
+
namespace "gem" do
|
52
|
+
cross_platforms.each do |platform|
|
53
|
+
desc "build native gem for #{platform}"
|
54
|
+
task platform do
|
55
|
+
RakeCompilerDock.sh(<<~EOF, platform: platform, verbose: true)
|
56
|
+
gem install bundler --no-document &&
|
57
|
+
BUNDLE_IGNORE_CONFIG=1 BUNDLE_PATH=.bundle/#{platform} bundle &&
|
58
|
+
BUNDLE_IGNORE_CONFIG=1 BUNDLE_PATH=.bundle/#{platform} bundle exec rake gem:#{platform}:buildit
|
59
|
+
EOF
|
60
|
+
end
|
61
|
+
|
62
|
+
namespace platform do
|
63
|
+
# this runs in the rake-compiler-dock docker container
|
64
|
+
task "buildit" do
|
65
|
+
# use Task#invoke because the pkg/*gem task is defined at runtime
|
66
|
+
Rake::Task["native:#{platform}"].invoke
|
67
|
+
Rake::Task["pkg/#{GEMSPEC.full_name}-#{Gem::Platform.new(platform)}.gem"].invoke
|
68
|
+
end
|
69
|
+
|
70
|
+
task "release" do
|
71
|
+
sh "gem push pkg/#{GEMSPEC.full_name}-#{Gem::Platform.new(platform)}.gem"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
desc "build native gem for all platforms"
|
77
|
+
task "all" do
|
78
|
+
cross_platforms.each do |platform|
|
79
|
+
Rake::Task["gem:#{platform}"].invoke
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
desc "release native gem for all platforms"
|
84
|
+
task "release" do
|
85
|
+
cross_platforms.each do |platform|
|
86
|
+
Rake::Task["gem:#{platform}:release"].invoke
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def change_version(&block)
|
92
|
+
version = GEMSPEC.version
|
93
|
+
version_file = 'bcrypt_pbkdf.gemspec'
|
94
|
+
raise "No version found" if version.nil?
|
95
|
+
final = version.segments.take_while{ |i| i.is_a?(Integer) }.to_a
|
96
|
+
pre = version.segments.drop_while{ |i| i.is_a?(Integer) }.to_a.join("")
|
97
|
+
pre = nil if pre.empty?
|
98
|
+
tiny = final.last
|
99
|
+
result = block[pre: pre, tiny: tiny]
|
100
|
+
raise ArgumentError, "Version change logic should always return a pre" unless result.key?(:pre)
|
101
|
+
|
102
|
+
puts "result: #{result.inspect}"
|
103
|
+
|
104
|
+
new_pre = result[:pre] || []
|
105
|
+
new_tiny = result[:tiny] || tiny
|
106
|
+
final[-1] = new_tiny
|
107
|
+
new_version = Gem::Version.new([final, *new_pre].join("."))
|
108
|
+
|
109
|
+
found = false
|
110
|
+
File.open("#{version_file}.new", "w") do |f|
|
111
|
+
File.readlines(version_file).each do |line|
|
112
|
+
match = /^(\s+s\.version\s*=\s*\')[\d[a-z]\.]+(\'\s*)$/.match(line)
|
113
|
+
if match
|
114
|
+
prefix = match[1]
|
115
|
+
postfix = match[2]
|
116
|
+
new_line = "#{prefix}#{new_version.to_s}#{postfix}"
|
117
|
+
puts "Changing:\n - #{line} + #{new_line}"
|
118
|
+
line = new_line
|
119
|
+
found = true
|
120
|
+
end
|
121
|
+
f.write(line)
|
122
|
+
end
|
123
|
+
raise ArgumentError, "Cound not find version line in #{version_file}" unless found
|
124
|
+
end
|
125
|
+
|
126
|
+
FileUtils.mv version_file, "#{version_file}.old"
|
127
|
+
FileUtils.mv "#{version_file}.new", version_file
|
128
|
+
FileUtils.rm_f "#{version_file}.old"
|
129
|
+
end
|
130
|
+
|
131
|
+
namespace :vbump do
|
132
|
+
desc "Final release"
|
133
|
+
task :final do
|
134
|
+
change_version do |pre:, tiny:|
|
135
|
+
_ = tiny
|
136
|
+
if pre.nil?
|
137
|
+
{ tiny: tiny + 1, pre: nil }
|
138
|
+
else
|
139
|
+
raise ArgumentError, "Unexpected pre: #{pre}" if pre.nil?
|
140
|
+
|
141
|
+
{ pre: nil }
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
desc "Increment prerelease"
|
147
|
+
task :pre, [:type] do |_t, args|
|
148
|
+
change_version do |pre:, tiny:|
|
149
|
+
puts " PRE => #{pre.inspect}"
|
150
|
+
match = /^([a-z]+)(\d+)/.match(pre)
|
151
|
+
raise ArgumentError, "Unexpected pre: #{pre}" if match.nil? && args[:type].nil?
|
152
|
+
|
153
|
+
if match.nil? || (!args[:type].nil? && args[:type] != match[1])
|
154
|
+
if pre.nil?
|
155
|
+
{ pre: "#{args[:type]}1", tiny: tiny + 1 }
|
156
|
+
else
|
157
|
+
{ pre: "#{args[:type]}1" }
|
158
|
+
end
|
159
|
+
else
|
160
|
+
{ pre: "#{match[1]}#{match[2].to_i + 1}" }
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
task "package" => cross_platforms.map { |p| "gem:#{p}" } # "package" task for all the native platforms
|
167
|
+
|
168
|
+
Rake::Task["package"].prerequisites.prepend("compile")
|
@@ -0,0 +1,28 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'bcrypt_pbkdf'
|
3
|
+
s.version = '1.1.1.rc2'
|
4
|
+
|
5
|
+
s.summary = "OpenBSD's bcrypt_pbkdf (a variant of PBKDF2 with bcrypt-based PRF)"
|
6
|
+
s.description = <<-EOF
|
7
|
+
This gem implements bcrypt_pbkdf (a variant of PBKDF2 with bcrypt-based PRF)
|
8
|
+
EOF
|
9
|
+
|
10
|
+
s.files = `git ls-files`.split("\n")
|
11
|
+
s.require_path = 'lib'
|
12
|
+
|
13
|
+
s.add_development_dependency 'rake-compiler', '~> 1.2.5'
|
14
|
+
s.add_development_dependency 'minitest', '~> 5'
|
15
|
+
s.add_development_dependency 'openssl', '~> 3'
|
16
|
+
s.add_development_dependency 'rdoc', '~> 6'
|
17
|
+
s.add_development_dependency 'rake-compiler-dock', '~> 1.5.0'
|
18
|
+
|
19
|
+
s.rdoc_options += ['--title', 'bcrypt_pbkdf', '--line-numbers', '--inline-source', '--main', 'README.md']
|
20
|
+
s.extra_rdoc_files += ['README.md', 'COPYING', 'CHANGELOG.md', *Dir['lib/**/*.rb']]
|
21
|
+
|
22
|
+
s.extensions = 'ext/mri/extconf.rb'
|
23
|
+
|
24
|
+
s.authors = ["Miklos Fazekas"]
|
25
|
+
s.email = "mfazekas@szemafor.com"
|
26
|
+
s.homepage = "https://github.com/net-ssh/bcrypt_pbkdf-ruby"
|
27
|
+
s.license = "MIT"
|
28
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
/* $OpenBSD: bcrypt_pbkdf.c,v 1.13 2015/01/12 03:20:04 tedu Exp $ */
|
2
|
+
/*
|
3
|
+
* Copyright (c) 2013 Ted Unangst <tedu@openbsd.org>
|
4
|
+
*
|
5
|
+
* Permission to use, copy, modify, and distribute this software for any
|
6
|
+
* purpose with or without fee is hereby granted, provided that the above
|
7
|
+
* copyright notice and this permission notice appear in all copies.
|
8
|
+
*
|
9
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
10
|
+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
11
|
+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
12
|
+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
13
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
14
|
+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
15
|
+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#include <sys/types.h>
|
19
|
+
|
20
|
+
#include <stdint.h>
|
21
|
+
#include <stdlib.h>
|
22
|
+
#include "blf.h"
|
23
|
+
#include "sha2.h"
|
24
|
+
#include <string.h>
|
25
|
+
#include "util.h"
|
26
|
+
|
27
|
+
#define MINIMUM(a,b) (((a) < (b)) ? (a) : (b))
|
28
|
+
|
29
|
+
/*
|
30
|
+
* pkcs #5 pbkdf2 implementation using the "bcrypt" hash
|
31
|
+
*
|
32
|
+
* The bcrypt hash function is derived from the bcrypt password hashing
|
33
|
+
* function with the following modifications:
|
34
|
+
* 1. The input password and salt are preprocessed with SHA512.
|
35
|
+
* 2. The output length is expanded to 256 bits.
|
36
|
+
* 3. Subsequently the magic string to be encrypted is lengthened and modifed
|
37
|
+
* to "OxychromaticBlowfishSwatDynamite"
|
38
|
+
* 4. The hash function is defined to perform 64 rounds of initial state
|
39
|
+
* expansion. (More rounds are performed by iterating the hash.)
|
40
|
+
*
|
41
|
+
* Note that this implementation pulls the SHA512 operations into the caller
|
42
|
+
* as a performance optimization.
|
43
|
+
*
|
44
|
+
* One modification from official pbkdf2. Instead of outputting key material
|
45
|
+
* linearly, we mix it. pbkdf2 has a known weakness where if one uses it to
|
46
|
+
* generate (e.g.) 512 bits of key material for use as two 256 bit keys, an
|
47
|
+
* attacker can merely run once through the outer loop, but the user
|
48
|
+
* always runs it twice. Shuffling output bytes requires computing the
|
49
|
+
* entirety of the key material to assemble any subkey. This is something a
|
50
|
+
* wise caller could do; we just do it for you.
|
51
|
+
*/
|
52
|
+
|
53
|
+
#define BCRYPT_WORDS 8
|
54
|
+
#define BCRYPT_HASHSIZE (BCRYPT_WORDS * 4)
|
55
|
+
|
56
|
+
void
|
57
|
+
bcrypt_hash(const uint8_t *sha2pass, const uint8_t *sha2salt, uint8_t *out)
|
58
|
+
{
|
59
|
+
blf_ctx state;
|
60
|
+
uint8_t ciphertext[BCRYPT_HASHSIZE] =
|
61
|
+
"OxychromaticBlowfishSwatDynamite";
|
62
|
+
uint32_t cdata[BCRYPT_WORDS];
|
63
|
+
int i;
|
64
|
+
uint16_t j;
|
65
|
+
size_t shalen = SHA512_DIGEST_LENGTH;
|
66
|
+
|
67
|
+
/* key expansion */
|
68
|
+
Blowfish_initstate(&state);
|
69
|
+
Blowfish_expandstate(&state, sha2salt, shalen, sha2pass, shalen);
|
70
|
+
for (i = 0; i < 64; i++) {
|
71
|
+
Blowfish_expand0state(&state, sha2salt, shalen);
|
72
|
+
Blowfish_expand0state(&state, sha2pass, shalen);
|
73
|
+
}
|
74
|
+
|
75
|
+
/* encryption */
|
76
|
+
j = 0;
|
77
|
+
for (i = 0; i < BCRYPT_WORDS; i++)
|
78
|
+
cdata[i] = Blowfish_stream2word(ciphertext, sizeof(ciphertext),
|
79
|
+
&j);
|
80
|
+
for (i = 0; i < 64; i++)
|
81
|
+
blf_enc(&state, cdata, sizeof(cdata) / sizeof(uint64_t));
|
82
|
+
|
83
|
+
/* copy out */
|
84
|
+
for (i = 0; i < BCRYPT_WORDS; i++) {
|
85
|
+
out[4 * i + 3] = (cdata[i] >> 24) & 0xff;
|
86
|
+
out[4 * i + 2] = (cdata[i] >> 16) & 0xff;
|
87
|
+
out[4 * i + 1] = (cdata[i] >> 8) & 0xff;
|
88
|
+
out[4 * i + 0] = cdata[i] & 0xff;
|
89
|
+
}
|
90
|
+
|
91
|
+
/* zap */
|
92
|
+
explicit_bzero(ciphertext, sizeof(ciphertext));
|
93
|
+
explicit_bzero(cdata, sizeof(cdata));
|
94
|
+
explicit_bzero(&state, sizeof(state));
|
95
|
+
}
|
96
|
+
|
97
|
+
int
|
98
|
+
bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, size_t saltlen,
|
99
|
+
uint8_t *key, size_t keylen, unsigned int rounds)
|
100
|
+
{
|
101
|
+
SHA2_CTX ctx;
|
102
|
+
uint8_t sha2pass[SHA512_DIGEST_LENGTH];
|
103
|
+
uint8_t sha2salt[SHA512_DIGEST_LENGTH];
|
104
|
+
uint8_t out[BCRYPT_HASHSIZE];
|
105
|
+
uint8_t tmpout[BCRYPT_HASHSIZE];
|
106
|
+
uint8_t countsalt[4];
|
107
|
+
size_t i, j, amt, stride;
|
108
|
+
uint32_t count;
|
109
|
+
size_t origkeylen = keylen;
|
110
|
+
|
111
|
+
/* nothing crazy */
|
112
|
+
if (rounds < 1)
|
113
|
+
return -1;
|
114
|
+
if (passlen == 0 || saltlen == 0 || keylen == 0 ||
|
115
|
+
keylen > sizeof(out) * sizeof(out))
|
116
|
+
return -1;
|
117
|
+
stride = (keylen + sizeof(out) - 1) / sizeof(out);
|
118
|
+
amt = (keylen + stride - 1) / stride;
|
119
|
+
|
120
|
+
/* collapse password */
|
121
|
+
SHA512Init(&ctx);
|
122
|
+
SHA512Update(&ctx, pass, passlen);
|
123
|
+
SHA512Final(sha2pass, &ctx);
|
124
|
+
|
125
|
+
|
126
|
+
/* generate key, sizeof(out) at a time */
|
127
|
+
for (count = 1; keylen > 0; count++) {
|
128
|
+
countsalt[0] = (count >> 24) & 0xff;
|
129
|
+
countsalt[1] = (count >> 16) & 0xff;
|
130
|
+
countsalt[2] = (count >> 8) & 0xff;
|
131
|
+
countsalt[3] = count & 0xff;
|
132
|
+
|
133
|
+
/* first round, salt is salt */
|
134
|
+
SHA512Init(&ctx);
|
135
|
+
SHA512Update(&ctx, salt, saltlen);
|
136
|
+
SHA512Update(&ctx, countsalt, sizeof(countsalt));
|
137
|
+
SHA512Final(sha2salt, &ctx);
|
138
|
+
bcrypt_hash(sha2pass, sha2salt, tmpout);
|
139
|
+
memcpy(out, tmpout, sizeof(out));
|
140
|
+
|
141
|
+
for (i = 1; i < rounds; i++) {
|
142
|
+
/* subsequent rounds, salt is previous output */
|
143
|
+
SHA512Init(&ctx);
|
144
|
+
SHA512Update(&ctx, tmpout, sizeof(tmpout));
|
145
|
+
SHA512Final(sha2salt, &ctx);
|
146
|
+
bcrypt_hash(sha2pass, sha2salt, tmpout);
|
147
|
+
for (j = 0; j < sizeof(out); j++)
|
148
|
+
out[j] ^= tmpout[j];
|
149
|
+
}
|
150
|
+
|
151
|
+
/*
|
152
|
+
* pbkdf2 deviation: output the key material non-linearly.
|
153
|
+
*/
|
154
|
+
amt = MINIMUM(amt, keylen);
|
155
|
+
for (i = 0; i < amt; i++) {
|
156
|
+
size_t dest = i * stride + (count - 1);
|
157
|
+
if (dest >= origkeylen)
|
158
|
+
break;
|
159
|
+
key[dest] = out[i];
|
160
|
+
}
|
161
|
+
keylen -= i;
|
162
|
+
}
|
163
|
+
|
164
|
+
/* zap */
|
165
|
+
explicit_bzero(&ctx, sizeof(ctx));
|
166
|
+
explicit_bzero(out, sizeof(out));
|
167
|
+
|
168
|
+
return 0;
|
169
|
+
}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#include "includes.h"
|
2
|
+
#include <ruby.h>
|
3
|
+
|
4
|
+
static VALUE mBCryptPbkdf;
|
5
|
+
static VALUE cBCryptPbkdfEngine;
|
6
|
+
|
7
|
+
/* Given a secret and a salt a key and the number of rounds and returns the encrypted secret
|
8
|
+
*/
|
9
|
+
static VALUE bc_crypt_pbkdf(VALUE self, VALUE pass, VALUE salt, VALUE keylen, VALUE rounds) {
|
10
|
+
size_t okeylen = NUM2ULONG(keylen);
|
11
|
+
u_int8_t* okey = xmalloc(okeylen);
|
12
|
+
VALUE out;
|
13
|
+
|
14
|
+
int ret = bcrypt_pbkdf(
|
15
|
+
StringValuePtr(pass), RSTRING_LEN(pass),
|
16
|
+
(const u_int8_t*)StringValuePtr(salt), RSTRING_LEN(salt),
|
17
|
+
okey, okeylen,
|
18
|
+
NUM2ULONG(rounds));
|
19
|
+
if (ret < 0)
|
20
|
+
return Qnil;
|
21
|
+
out = rb_str_new((const char*)okey, okeylen);
|
22
|
+
xfree(okey);
|
23
|
+
return out;
|
24
|
+
}
|
25
|
+
|
26
|
+
static VALUE bc_crypt_hash(VALUE self, VALUE pass, VALUE salt) {
|
27
|
+
u_int8_t hash[BCRYPT_HASHSIZE];
|
28
|
+
if (RSTRING_LEN(pass) != 64U)
|
29
|
+
return Qnil;
|
30
|
+
if (RSTRING_LEN(salt) != 64U)
|
31
|
+
return Qnil;
|
32
|
+
bcrypt_hash((const u_int8_t*)StringValuePtr(pass), (const u_int8_t*)StringValuePtr(salt), hash);
|
33
|
+
return rb_str_new((const char*)hash, sizeof(hash));
|
34
|
+
}
|
35
|
+
|
36
|
+
|
37
|
+
/* Create the BCryptPbkdf and BCryptPbkdf::Engine modules, and populate them with methods. */
|
38
|
+
void Init_bcrypt_pbkdf_ext(){
|
39
|
+
mBCryptPbkdf = rb_define_module("BCryptPbkdf");
|
40
|
+
cBCryptPbkdfEngine = rb_define_class_under(mBCryptPbkdf, "Engine", rb_cObject);
|
41
|
+
|
42
|
+
rb_define_singleton_method(cBCryptPbkdfEngine, "__bc_crypt_pbkdf", bc_crypt_pbkdf, 4);
|
43
|
+
rb_define_singleton_method(cBCryptPbkdfEngine, "__bc_crypt_hash", bc_crypt_hash, 2);
|
44
|
+
}
|
data/ext/mri/blf.h
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
/* $OpenBSD: blf.h,v 1.7 2007/03/14 17:59:41 grunk Exp $ */
|
2
|
+
/*
|
3
|
+
* Blowfish - a fast block cipher designed by Bruce Schneier
|
4
|
+
*
|
5
|
+
* Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
|
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. All advertising materials mentioning features or use of this software
|
17
|
+
* must display the following acknowledgement:
|
18
|
+
* This product includes software developed by Niels Provos.
|
19
|
+
* 4. The name of the author may not be used to endorse or promote products
|
20
|
+
* derived from this software without specific prior written permission.
|
21
|
+
*
|
22
|
+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
23
|
+
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
24
|
+
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
25
|
+
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
26
|
+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
27
|
+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
28
|
+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
29
|
+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
30
|
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
31
|
+
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32
|
+
*/
|
33
|
+
|
34
|
+
#ifndef _BLF_H_
|
35
|
+
#define _BLF_H_
|
36
|
+
|
37
|
+
#include "includes.h"
|
38
|
+
|
39
|
+
#if !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H)
|
40
|
+
|
41
|
+
/* Schneier specifies a maximum key length of 56 bytes.
|
42
|
+
* This ensures that every key bit affects every cipher
|
43
|
+
* bit. However, the subkeys can hold up to 72 bytes.
|
44
|
+
* Warning: For normal blowfish encryption only 56 bytes
|
45
|
+
* of the key affect all cipherbits.
|
46
|
+
*/
|
47
|
+
|
48
|
+
#define BLF_N 16 /* Number of Subkeys */
|
49
|
+
#define BLF_MAXKEYLEN ((BLF_N-2)*4) /* 448 bits */
|
50
|
+
#define BLF_MAXUTILIZED ((BLF_N+2)*4) /* 576 bits */
|
51
|
+
|
52
|
+
/* Blowfish context */
|
53
|
+
typedef struct BlowfishContext {
|
54
|
+
u_int32_t S[4][256]; /* S-Boxes */
|
55
|
+
u_int32_t P[BLF_N + 2]; /* Subkeys */
|
56
|
+
} blf_ctx;
|
57
|
+
|
58
|
+
/* Raw access to customized Blowfish
|
59
|
+
* blf_key is just:
|
60
|
+
* Blowfish_initstate( state )
|
61
|
+
* Blowfish_expand0state( state, key, keylen )
|
62
|
+
*/
|
63
|
+
|
64
|
+
void Blowfish_encipher(blf_ctx *, u_int32_t *, u_int32_t *);
|
65
|
+
void Blowfish_decipher(blf_ctx *, u_int32_t *, u_int32_t *);
|
66
|
+
void Blowfish_initstate(blf_ctx *);
|
67
|
+
void Blowfish_expand0state(blf_ctx *, const u_int8_t *, u_int16_t);
|
68
|
+
void Blowfish_expandstate
|
69
|
+
(blf_ctx *, const u_int8_t *, u_int16_t, const u_int8_t *, u_int16_t);
|
70
|
+
|
71
|
+
/* Standard Blowfish */
|
72
|
+
|
73
|
+
void blf_key(blf_ctx *, const u_int8_t *, u_int16_t);
|
74
|
+
void blf_enc(blf_ctx *, u_int32_t *, u_int16_t);
|
75
|
+
void blf_dec(blf_ctx *, u_int32_t *, u_int16_t);
|
76
|
+
|
77
|
+
void blf_ecb_encrypt(blf_ctx *, u_int8_t *, u_int32_t);
|
78
|
+
void blf_ecb_decrypt(blf_ctx *, u_int8_t *, u_int32_t);
|
79
|
+
|
80
|
+
void blf_cbc_encrypt(blf_ctx *, u_int8_t *, u_int8_t *, u_int32_t);
|
81
|
+
void blf_cbc_decrypt(blf_ctx *, u_int8_t *, u_int8_t *, u_int32_t);
|
82
|
+
|
83
|
+
/* Converts u_int8_t to u_int32_t */
|
84
|
+
u_int32_t Blowfish_stream2word(const u_int8_t *, u_int16_t , u_int16_t *);
|
85
|
+
|
86
|
+
#define DEF_WEAK(foo)
|
87
|
+
|
88
|
+
#endif /* !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H) */
|
89
|
+
#endif /* _BLF_H */
|
90
|
+
|