bcrypt-ruby 2.1.4 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,34 @@
1
+ require 'ffi'
2
+
3
+ module BCrypt
4
+ class Engine
5
+ extend FFI::Library
6
+
7
+ BCRYPT_MAXSALT = 16
8
+ BCRYPT_SALT_OUTPUT_SIZE = 7 + (BCRYPT_MAXSALT * 4 + 2) / 3 + 1
9
+ BCRYPT_OUTPUT_SIZE = 128
10
+
11
+ ffi_lib File.expand_path("../bcrypt_ext", __FILE__)
12
+
13
+ attach_function :ruby_bcrypt, [:buffer_out, :string, :string], :string
14
+ attach_function :ruby_bcrypt_gensalt, [:buffer_out, :uint8, :pointer], :string
15
+
16
+ def self.__bc_salt(cost, seed)
17
+ buffer_out = FFI::Buffer.alloc_out(BCRYPT_SALT_OUTPUT_SIZE, 1)
18
+ seed_ptr = FFI::MemoryPointer.new(:uint8, BCRYPT_MAXSALT)
19
+ seed.bytes.to_a.each_with_index { |b, i| seed_ptr.int8_put(i, b) }
20
+ out = ruby_bcrypt_gensalt(buffer_out, cost, seed_ptr)
21
+ seed_ptr.free
22
+ buffer_out.free
23
+ out || ""
24
+ end
25
+
26
+ def self.__bc_crypt(key, salt, cost)
27
+ buffer_out = FFI::Buffer.alloc_out(BCRYPT_OUTPUT_SIZE, 1)
28
+ out = ruby_bcrypt(buffer_out, key || "", salt)
29
+ buffer_out.free
30
+ out && out.any? ? out : nil
31
+ end
32
+ end
33
+ end
34
+
@@ -30,9 +30,9 @@ end
30
30
  describe "Autodetecting of salt cost" do
31
31
 
32
32
  specify "should work" do
33
- BCrypt::Engine.autodetect_cost("$2a$08$hRx2IVeHNsTSYYtUWn61Ou").should == 8
34
- BCrypt::Engine.autodetect_cost("$2a$05$XKd1bMnLgUnc87qvbAaCUu").should == 5
35
- BCrypt::Engine.autodetect_cost("$2a$13$Lni.CZ6z5A7344POTFBBV.").should == 13
33
+ BCrypt::Engine.autodetect_cost("$2a$08$hRx2IVeHNsTSYYtUWn61Ou").should eq 8
34
+ BCrypt::Engine.autodetect_cost("$2a$05$XKd1bMnLgUnc87qvbAaCUu").should eq 5
35
+ BCrypt::Engine.autodetect_cost("$2a$13$Lni.CZ6z5A7344POTFBBV.").should eq 13
36
36
  end
37
37
 
38
38
  end
@@ -39,9 +39,9 @@ describe "Reading a hashed password" do
39
39
  password.version.should eql("2a")
40
40
  password.cost.should equal(5)
41
41
  password.salt.should eql("$2a$05$CCCCCCCCCCCCCCCCCCCCC.")
42
- password.salt.class.should == String
42
+ password.salt.class.should eq String
43
43
  password.checksum.should eq("E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW")
44
- password.checksum.class.should == String
44
+ password.checksum.class.should eq String
45
45
  password.to_s.should eql(@hash)
46
46
  end
47
47
 
@@ -65,3 +65,12 @@ describe "Comparing a hashed password with a secret" do
65
65
  (@password == "@secret").should be(false)
66
66
  end
67
67
  end
68
+
69
+ describe "Validating a generated salt" do
70
+ specify "should not accept an invalid salt" do
71
+ BCrypt::Engine.valid_salt?("invalid").should eq(false)
72
+ end
73
+ specify "should accept a valid salt" do
74
+ BCrypt::Engine.valid_salt?(BCrypt::Engine.generate_salt).should eq(true)
75
+ end
76
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bcrypt-ruby
3
3
  version: !ruby/object:Gem::Version
4
- hash: 3
4
+ hash: 7
5
5
  prerelease:
6
6
  segments:
7
- - 2
8
- - 1
9
- - 4
10
- version: 2.1.4
7
+ - 3
8
+ - 0
9
+ - 0
10
+ version: 3.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Coda Hale
@@ -15,8 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-01-08 00:00:00 -08:00
19
- default_executable:
18
+ date: 2011-08-24 00:00:00 Z
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
22
21
  name: rake-compiler
@@ -53,32 +52,36 @@ executables: []
53
52
  extensions:
54
53
  - ext/mri/extconf.rb
55
54
  extra_rdoc_files:
56
- - README
55
+ - README.md
57
56
  - COPYING
58
57
  - CHANGELOG
59
58
  - lib/bcrypt.rb
59
+ - lib/bcrypt_engine.rb
60
60
  files:
61
61
  - .gitignore
62
62
  - .rspec
63
63
  - CHANGELOG
64
64
  - COPYING
65
65
  - Gemfile
66
- - README
66
+ - Gemfile.lock
67
+ - README.md
67
68
  - Rakefile
68
69
  - bcrypt-ruby.gemspec
69
70
  - ext/jruby/bcrypt_jruby/BCrypt.java
70
- - ext/mri/bcrypt.c
71
- - ext/mri/bcrypt.h
72
71
  - ext/mri/bcrypt_ext.c
73
- - ext/mri/blf.h
74
- - ext/mri/blowfish.c
72
+ - ext/mri/crypt.c
73
+ - ext/mri/crypt.h
74
+ - ext/mri/crypt_blowfish.c
75
+ - ext/mri/crypt_gensalt.c
75
76
  - ext/mri/extconf.rb
77
+ - ext/mri/ow-crypt.h
78
+ - ext/mri/wrapper.c
76
79
  - lib/bcrypt.rb
80
+ - lib/bcrypt_engine.rb
77
81
  - spec/TestBCrypt.java
78
82
  - spec/bcrypt/engine_spec.rb
79
83
  - spec/bcrypt/password_spec.rb
80
84
  - spec/spec_helper.rb
81
- has_rdoc: true
82
85
  homepage: http://bcrypt-ruby.rubyforge.org
83
86
  licenses: []
84
87
 
@@ -89,7 +92,7 @@ rdoc_options:
89
92
  - --line-numbers
90
93
  - --inline-source
91
94
  - --main
92
- - README
95
+ - README.md
93
96
  require_paths:
94
97
  - lib
95
98
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -113,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
116
  requirements: []
114
117
 
115
118
  rubyforge_project: bcrypt-ruby
116
- rubygems_version: 1.4.0
119
+ rubygems_version: 1.8.8
117
120
  signing_key:
118
121
  specification_version: 3
119
122
  summary: OpenBSD's bcrypt() password hashing algorithm.
data/README DELETED
@@ -1,175 +0,0 @@
1
- = bcrypt-ruby
2
-
3
- An easy way to keep your users' passwords secure.
4
-
5
- * http://bcrypt-ruby.rubyforge.org/
6
- * http://github.com/codahale/bcrypt-ruby/tree/master
7
-
8
- == Why you should use bcrypt
9
-
10
- If you store user passwords in the clear, then an attacker who steals a copy of your database has a giant list of emails
11
- and passwords. Some of your users will only have one password -- for their email account, for their banking account, for
12
- your application. A simple hack could escalate into massive identity theft.
13
-
14
- It's your responsibility as a web developer to make your web application secure -- blaming your users for not being
15
- security experts is not a professional response to risk.
16
-
17
- bcrypt allows you to easily harden your application against these kinds of attacks.
18
-
19
- == How to install bcrypt
20
-
21
- sudo gem install bcrypt-ruby
22
-
23
- You'll need a working compiler. (Win32 folks should use Cygwin or um, something else.)
24
-
25
- == How to use bcrypt in your Rails application
26
-
27
- === The +User+ model
28
-
29
- require 'bcrypt'
30
-
31
- class User < ActiveRecord::Base
32
- # users.password_hash in the database is a :string
33
- include BCrypt
34
-
35
- def password
36
- @password ||= Password.new(password_hash)
37
- end
38
-
39
- def password=(new_password)
40
- @password = Password.create(new_password)
41
- self.password_hash = @password
42
- end
43
-
44
- end
45
-
46
- === Creating an account
47
-
48
- def create
49
- @user = User.new(params[:user])
50
- @user.password = params[:password]
51
- @user.save!
52
- end
53
-
54
- === Authenticating a user
55
-
56
- def login
57
- @user = User.find_by_email(params[:email])
58
- if @user.password == params[:password]
59
- give_token
60
- else
61
- redirect_to home_url
62
- end
63
- end
64
-
65
- === If a user forgets their password?
66
-
67
- # assign them a random one and mail it to them, asking them to change it
68
- def forgot_password
69
- @user = User.find_by_email(params[:email])
70
- random_password = Array.new(10).map { (65 + rand(58)).chr }.join
71
- @user.password = random_password
72
- @user.save!
73
- Mailer.create_and_deliver_password_change(@user, random_password)
74
- end
75
-
76
- == How to use bcrypt-ruby in general
77
-
78
- require 'bcrypt'
79
-
80
- my_password = BCrypt::Password.create("my password") #=> "$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa"
81
-
82
- my_password.version #=> "2a"
83
- my_password.cost #=> 10
84
- my_password == "my password" #=> true
85
- my_password == "not my password" #=> false
86
-
87
- my_password = BCrypt::Password.new("$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa")
88
- my_password == "my password" #=> true
89
- my_password == "not my password" #=> false
90
-
91
- Check the rdocs for more details -- BCrypt, BCrypt::Password.
92
-
93
- == How bcrypt() works
94
-
95
- bcrypt() is a hashing algorithm designed by Niels Provos and David Mazières of the OpenBSD Project.
96
-
97
- === Background
98
-
99
- Hash algorithms take a chunk of data (e.g., your user's password) and create a "digital fingerprint," or hash, of it.
100
- Because this process is not reversible, there's no way to go from the hash back to the password.
101
-
102
- In other words:
103
-
104
- hash(p) #=> <unique gibberish>
105
-
106
- You can store the hash and check it against a hash made of a potentially valid password:
107
-
108
- <unique gibberish> =? hash(just_entered_password)
109
-
110
- === Rainbow Tables
111
-
112
- But even this has weaknesses -- attackers can just run lists of possible passwords through the same algorithm, store the
113
- results in a big database, and then look up the passwords by their hash:
114
-
115
- PrecomputedPassword.find_by_hash(<unique gibberish>).password #=> "secret1"
116
-
117
- === Salts
118
-
119
- The solution to this is to add a small chunk of random data -- called a salt -- to the password before it's hashed:
120
-
121
- hash(salt + p) #=> <really unique gibberish>
122
-
123
- The salt is then stored along with the hash in the database, and used to check potentially valid passwords:
124
-
125
- <really unique gibberish> =? hash(salt + just_entered_password)
126
-
127
- bcrypt-ruby automatically handles the storage and generation of these salts for you.
128
-
129
- Adding a salt means that an attacker has to have a gigantic database for each unique salt -- for a salt made of 4
130
- letters, that's 456,976 different databases. Pretty much no one has that much storage space, so attackers try a
131
- different, slower method -- throw a list of potential passwords at each individual password:
132
-
133
- hash(salt + "aadvark") =? <really unique gibberish>
134
- hash(salt + "abacus") =? <really unique gibberish>
135
- etc.
136
-
137
- This is much slower than the big database approach, but most hash algorithms are pretty quick -- and therein lies the
138
- problem. Hash algorithms aren't usually designed to be slow, they're designed to turn gigabytes of data into secure
139
- fingerprints as quickly as possible. bcrypt(), though, is designed to be computationally expensive:
140
-
141
- Ten thousand iterations:
142
- user system total real
143
- md5 0.070000 0.000000 0.070000 ( 0.070415)
144
- bcrypt 22.230000 0.080000 22.310000 ( 22.493822)
145
-
146
- If an attacker was using Ruby to check each password, they could check ~140,000 passwords a second with MD5 but only
147
- ~450 passwords a second with bcrypt().
148
-
149
- === Cost Factors
150
-
151
- In addition, bcrypt() allows you to increase the amount of work required to hash a password as computers get faster. Old
152
- passwords will still work fine, but new passwords can keep up with the times.
153
-
154
- The default cost factor used by bcrypt-ruby is 10, which is fine for session-based authentication. If you are using a
155
- stateless authentication architecture (e.g., HTTP Basic Auth), you will want to lower the cost factor to reduce your
156
- server load and keep your request times down. This will lower the security provided you, but there are few alternatives.
157
-
158
- == More Information
159
-
160
- bcrypt() is currently used as the default password storage hash in OpenBSD, widely regarded as the most secure operating
161
- system available.
162
-
163
-
164
- For a more technical explanation of the algorithm and its design criteria, please read Niels Provos and David Mazières'
165
- Usenix99 paper:
166
- http://www.usenix.org/events/usenix99/provos.html
167
-
168
- If you'd like more down-to-earth advice regarding cryptography, I suggest reading <i>Practical Cryptography</i> by Niels
169
- Ferguson and Bruce Schneier:
170
- http://www.schneier.com/book-practical.html
171
-
172
- = Etc
173
-
174
- Author :: Coda Hale <coda.hale@gmail.com>
175
- Website :: http://blog.codahale.com
@@ -1,297 +0,0 @@
1
- /* $OpenBSD: bcrypt.c,v 1.22 2007/02/20 01:44:16 ray Exp $ */
2
-
3
- /*
4
- * Modified by <coda.hale@gmail.com> on 2009-09-16:
5
- *
6
- * - Standardized on stdint.h's numerical types and removed some debug cruft.
7
- *
8
- * Modified by <hongli@phusion.nl> on 2009-08-05:
9
- *
10
- * - Got rid of the global variables; they're not thread-safe.
11
- * Modified the functions to accept local buffers instead.
12
- *
13
- * Modified by <coda.hale@gmail.com> on 2007-02-27:
14
- *
15
- * - Changed bcrypt_gensalt to accept a random seed as a parameter,
16
- * to remove the code's dependency on arc4random(), which isn't
17
- * available on Linux.
18
- */
19
-
20
- /*
21
- * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
22
- * All rights reserved.
23
- *
24
- * Redistribution and use in source and binary forms, with or without
25
- * modification, are permitted provided that the following conditions
26
- * are met:
27
- * 1. Redistributions of source code must retain the above copyright
28
- * notice, this list of conditions and the following disclaimer.
29
- * 2. Redistributions in binary form must reproduce the above copyright
30
- * notice, this list of conditions and the following disclaimer in the
31
- * documentation and/or other materials provided with the distribution.
32
- * 3. All advertising materials mentioning features or use of this software
33
- * must display the following acknowledgement:
34
- * This product includes software developed by Niels Provos.
35
- * 4. The name of the author may not be used to endorse or promote products
36
- * derived from this software without specific prior written permission.
37
- *
38
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
39
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
40
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
41
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
42
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
47
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48
- */
49
-
50
- /* This password hashing algorithm was designed by David Mazieres
51
- * <dm@lcs.mit.edu> and works as follows:
52
- *
53
- * 1. state := InitState ()
54
- * 2. state := ExpandKey (state, salt, password) 3.
55
- * REPEAT rounds:
56
- * state := ExpandKey (state, 0, salt)
57
- * state := ExpandKey(state, 0, password)
58
- * 4. ctext := "OrpheanBeholderScryDoubt"
59
- * 5. REPEAT 64:
60
- * ctext := Encrypt_ECB (state, ctext);
61
- * 6. RETURN Concatenate (salt, ctext);
62
- *
63
- */
64
-
65
- #include <stdio.h>
66
- #include <stdlib.h>
67
- #include <string.h>
68
- #include "blf.h"
69
- #include "bcrypt.h"
70
-
71
- /* This implementation is adaptable to current computing power.
72
- * You can have up to 2^31 rounds which should be enough for some
73
- * time to come.
74
- */
75
-
76
- static void encode_salt(char *, uint8_t *, uint16_t, uint8_t);
77
- static void encode_base64(uint8_t *, uint8_t *, uint16_t);
78
- static void decode_base64(uint8_t *, uint16_t, uint8_t *);
79
-
80
- static const uint8_t Base64Code[] =
81
- "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
82
-
83
- static const uint8_t index_64[128] = {
84
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
85
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
86
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
87
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
88
- 255, 255, 255, 255, 255, 255, 0, 1, 54, 55,
89
- 56, 57, 58, 59, 60, 61, 62, 63, 255, 255,
90
- 255, 255, 255, 255, 255, 2, 3, 4, 5, 6,
91
- 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
92
- 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
93
- 255, 255, 255, 255, 255, 255, 28, 29, 30,
94
- 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
95
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
96
- 51, 52, 53, 255, 255, 255, 255, 255
97
- };
98
- #define CHAR64(c) ( (c) > 127 ? 255 : index_64[(c)])
99
-
100
- static void
101
- decode_base64(uint8_t *buffer, uint16_t len, uint8_t *data)
102
- {
103
- uint8_t *bp = buffer;
104
- uint8_t *p = data;
105
- uint8_t c1, c2, c3, c4;
106
- while (bp < buffer + len) {
107
- c1 = CHAR64(*p);
108
- c2 = CHAR64(*(p + 1));
109
-
110
- /* Invalid data */
111
- if (c1 == 255 || c2 == 255)
112
- break;
113
-
114
- *bp++ = (c1 << 2) | ((c2 & 0x30) >> 4);
115
- if (bp >= buffer + len)
116
- break;
117
-
118
- c3 = CHAR64(*(p + 2));
119
- if (c3 == 255)
120
- break;
121
-
122
- *bp++ = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);
123
- if (bp >= buffer + len)
124
- break;
125
-
126
- c4 = CHAR64(*(p + 3));
127
- if (c4 == 255)
128
- break;
129
- *bp++ = ((c3 & 0x03) << 6) | c4;
130
-
131
- p += 4;
132
- }
133
- }
134
-
135
- static void
136
- encode_salt(char *salt, uint8_t *csalt, uint16_t clen, uint8_t logr)
137
- {
138
- salt[0] = '$';
139
- salt[1] = BCRYPT_VERSION;
140
- salt[2] = 'a';
141
- salt[3] = '$';
142
-
143
- snprintf(salt + 4, 4, "%2.2u$", logr);
144
-
145
- encode_base64((uint8_t *) salt + 7, csalt, clen);
146
- }
147
- /* Generates a salt for this version of crypt.
148
- Since versions may change. Keeping this here
149
- seems sensible.
150
- */
151
-
152
- char *
153
- ruby_bcrypt_gensalt(char *output, uint8_t log_rounds, uint8_t *rseed)
154
- {
155
- if (log_rounds < 4)
156
- log_rounds = 4;
157
- else if (log_rounds > 31)
158
- log_rounds = 31;
159
-
160
- encode_salt(output, rseed, BCRYPT_MAXSALT, log_rounds);
161
- return output;
162
- }
163
- /* We handle $Vers$log2(NumRounds)$salt+passwd$
164
- i.e. $2$04$iwouldntknowwhattosayetKdJ6iFtacBqJdKe6aW7ou */
165
-
166
- char *
167
- ruby_bcrypt(char *output, const char *key, const char *salt)
168
- {
169
- blf_ctx state;
170
- uint32_t rounds, i, k;
171
- uint16_t j;
172
- uint8_t key_len, salt_len, logr, minor;
173
- uint8_t ciphertext[4 * BCRYPT_BLOCKS] = "OrpheanBeholderScryDoubt";
174
- uint8_t csalt[BCRYPT_MAXSALT];
175
- uint32_t cdata[BCRYPT_BLOCKS];
176
- int n;
177
-
178
- /* Discard "$" identifier */
179
- salt++;
180
-
181
- if (*salt > BCRYPT_VERSION) {
182
- return NULL;
183
- }
184
-
185
- /* Check for minor versions */
186
- if (salt[1] != '$') {
187
- switch (salt[1]) {
188
- case 'a':
189
- /* 'ab' should not yield the same as 'abab' */
190
- minor = salt[1];
191
- salt++;
192
- break;
193
- default:
194
- return NULL;
195
- }
196
- } else
197
- minor = 0;
198
-
199
- /* Discard version + "$" identifier */
200
- salt += 2;
201
-
202
- if (salt[2] != '$')
203
- /* Out of sync with passwd entry */
204
- return NULL;
205
-
206
- /* Computer power doesn't increase linear, 2^x should be fine */
207
- n = atoi(salt);
208
- if (n > 31 || n < 0)
209
- return NULL;
210
- logr = (uint8_t)n;
211
- if ((rounds = (uint32_t) 1 << logr) < BCRYPT_MINROUNDS)
212
- return NULL;
213
-
214
- /* Discard num rounds + "$" identifier */
215
- salt += 3;
216
-
217
- if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT)
218
- return NULL;
219
-
220
- /* We dont want the base64 salt but the raw data */
221
- decode_base64(csalt, BCRYPT_MAXSALT, (uint8_t *) salt);
222
- salt_len = BCRYPT_MAXSALT;
223
- key_len = strlen(key) + (minor >= 'a' ? 1 : 0);
224
-
225
- /* Setting up S-Boxes and Subkeys */
226
- Blowfish_initstate(&state);
227
- Blowfish_expandstate(&state, csalt, salt_len,
228
- (uint8_t *) key, key_len);
229
- for (k = 0; k < rounds; k++) {
230
- Blowfish_expand0state(&state, (uint8_t *) key, key_len);
231
- Blowfish_expand0state(&state, csalt, salt_len);
232
- }
233
-
234
- /* This can be precomputed later */
235
- j = 0;
236
- for (i = 0; i < BCRYPT_BLOCKS; i++)
237
- cdata[i] = Blowfish_stream2word(ciphertext, 4 * BCRYPT_BLOCKS, &j);
238
-
239
- /* Now do the encryption */
240
- for (k = 0; k < 64; k++)
241
- blf_enc(&state, cdata, BCRYPT_BLOCKS / 2);
242
-
243
- for (i = 0; i < BCRYPT_BLOCKS; i++) {
244
- ciphertext[4 * i + 3] = cdata[i] & 0xff;
245
- cdata[i] = cdata[i] >> 8;
246
- ciphertext[4 * i + 2] = cdata[i] & 0xff;
247
- cdata[i] = cdata[i] >> 8;
248
- ciphertext[4 * i + 1] = cdata[i] & 0xff;
249
- cdata[i] = cdata[i] >> 8;
250
- ciphertext[4 * i + 0] = cdata[i] & 0xff;
251
- }
252
-
253
-
254
- i = 0;
255
- output[i++] = '$';
256
- output[i++] = BCRYPT_VERSION;
257
- if (minor)
258
- output[i++] = minor;
259
- output[i++] = '$';
260
-
261
- snprintf(output + i, 4, "%2.2u$", logr);
262
-
263
- encode_base64((uint8_t *) output + i + 3, csalt, BCRYPT_MAXSALT);
264
- encode_base64((uint8_t *) output + strlen(output), ciphertext,
265
- 4 * BCRYPT_BLOCKS - 1);
266
- return output;
267
- }
268
-
269
- static void
270
- encode_base64(uint8_t *buffer, uint8_t *data, uint16_t len)
271
- {
272
- uint8_t *bp = buffer;
273
- uint8_t *p = data;
274
- uint8_t c1, c2;
275
- while (p < data + len) {
276
- c1 = *p++;
277
- *bp++ = Base64Code[(c1 >> 2)];
278
- c1 = (c1 & 0x03) << 4;
279
- if (p >= data + len) {
280
- *bp++ = Base64Code[c1];
281
- break;
282
- }
283
- c2 = *p++;
284
- c1 |= (c2 >> 4) & 0x0f;
285
- *bp++ = Base64Code[c1];
286
- c1 = (c2 & 0x0f) << 2;
287
- if (p >= data + len) {
288
- *bp++ = Base64Code[c1];
289
- break;
290
- }
291
- c2 = *p++;
292
- c1 |= (c2 >> 6) & 0x03;
293
- *bp++ = Base64Code[c1];
294
- *bp++ = Base64Code[c2 & 0x3f];
295
- }
296
- *bp = '\0';
297
- }