diff options
author | tedu <> | 2014-03-23 23:19:21 +0000 |
---|---|---|
committer | tedu <> | 2014-03-23 23:19:21 +0000 |
commit | 6ecd5909f6d077b669db3958976e4da8d24f48c3 (patch) | |
tree | c09c8bcc755b7ba36261f229eb033d456f02cd7f /src/lib | |
parent | b8fc64a9347b0fd25c7bc04720bb381adc4bd035 (diff) | |
download | openbsd-6ecd5909f6d077b669db3958976e4da8d24f48c3.tar.gz openbsd-6ecd5909f6d077b669db3958976e4da8d24f48c3.tar.bz2 openbsd-6ecd5909f6d077b669db3958976e4da8d24f48c3.zip |
minimal change to implementation of bcrypt to not require static globals.
add some friendlier functions.
move the classic static data api into wrapper functions.
a few more changes to come...
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/libc/crypt/bcrypt.c | 127 |
1 files changed, 88 insertions, 39 deletions
diff --git a/src/lib/libc/crypt/bcrypt.c b/src/lib/libc/crypt/bcrypt.c index 156997b232..29ea4550c9 100644 --- a/src/lib/libc/crypt/bcrypt.c +++ b/src/lib/libc/crypt/bcrypt.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* $OpenBSD: bcrypt.c,v 1.31 2014/03/22 23:02:03 tedu Exp $ */ | 1 | /* $OpenBSD: bcrypt.c,v 1.32 2014/03/23 23:19:21 tedu Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2014 Ted Unangst <tedu@openbsd.org> | ||
4 | * Copyright (c) 1997 Niels Provos <provos@umich.edu> | 5 | * Copyright (c) 1997 Niels Provos <provos@umich.edu> |
5 | * | 6 | * |
6 | * Permission to use, copy, modify, and distribute this software for any | 7 | * Permission to use, copy, modify, and distribute this software for any |
@@ -47,37 +48,23 @@ | |||
47 | #define BCRYPT_BLOCKS 6 /* Ciphertext blocks */ | 48 | #define BCRYPT_BLOCKS 6 /* Ciphertext blocks */ |
48 | #define BCRYPT_MINLOGROUNDS 4 /* we have log2(rounds) in salt */ | 49 | #define BCRYPT_MINLOGROUNDS 4 /* we have log2(rounds) in salt */ |
49 | 50 | ||
51 | #define BCRYPT_SALTSPACE (7 + (BCRYPT_MAXSALT * 4 + 2) / 3 + 1) | ||
52 | |||
50 | char *bcrypt_gensalt(u_int8_t); | 53 | char *bcrypt_gensalt(u_int8_t); |
51 | 54 | ||
52 | static void encode_salt(char *, u_int8_t *, u_int16_t, u_int8_t); | ||
53 | static void encode_base64(u_int8_t *, u_int8_t *, u_int16_t); | 55 | static void encode_base64(u_int8_t *, u_int8_t *, u_int16_t); |
54 | static void decode_base64(u_int8_t *, u_int16_t, u_int8_t *); | 56 | static void decode_base64(u_int8_t *, u_int16_t, u_int8_t *); |
55 | 57 | ||
56 | static char encrypted[_PASSWORD_LEN]; | 58 | /* |
57 | static char gsalt[7 + (BCRYPT_MAXSALT * 4 + 2) / 3 + 1]; | 59 | * Generates a salt for this version of crypt. |
58 | static char error[] = ":"; | ||
59 | |||
60 | static void | ||
61 | encode_salt(char *salt, u_int8_t *csalt, u_int16_t clen, u_int8_t logr) | ||
62 | { | ||
63 | salt[0] = '$'; | ||
64 | salt[1] = BCRYPT_VERSION; | ||
65 | salt[2] = 'a'; | ||
66 | salt[3] = '$'; | ||
67 | |||
68 | snprintf(salt + 4, 4, "%2.2u$", logr); | ||
69 | |||
70 | encode_base64((u_int8_t *) salt + 7, csalt, clen); | ||
71 | } | ||
72 | /* Generates a salt for this version of crypt. | ||
73 | Since versions may change. Keeping this here | ||
74 | seems sensible. | ||
75 | */ | 60 | */ |
76 | 61 | int | |
77 | char * | 62 | bcrypt_initsalt(int log_rounds, uint8_t *salt, size_t saltbuflen) |
78 | bcrypt_gensalt(u_int8_t log_rounds) | ||
79 | { | 63 | { |
80 | u_int8_t csalt[BCRYPT_MAXSALT]; | 64 | uint8_t csalt[BCRYPT_MAXSALT]; |
65 | |||
66 | if (saltbuflen < BCRYPT_SALTSPACE) | ||
67 | return -1; | ||
81 | 68 | ||
82 | arc4random_buf(csalt, sizeof(csalt)); | 69 | arc4random_buf(csalt, sizeof(csalt)); |
83 | 70 | ||
@@ -86,14 +73,18 @@ bcrypt_gensalt(u_int8_t log_rounds) | |||
86 | else if (log_rounds > 31) | 73 | else if (log_rounds > 31) |
87 | log_rounds = 31; | 74 | log_rounds = 31; |
88 | 75 | ||
89 | encode_salt(gsalt, csalt, BCRYPT_MAXSALT, log_rounds); | 76 | snprintf(salt, 4, "$2a$%2.2u$", log_rounds); |
90 | return gsalt; | 77 | encode_base64((uint8_t *)salt + 7, csalt, sizeof(csalt)); |
78 | |||
79 | return 0; | ||
91 | } | 80 | } |
92 | /* We handle $Vers$log2(NumRounds)$salt+passwd$ | ||
93 | i.e. $2$04$iwouldntknowwhattosayetKdJ6iFtacBqJdKe6aW7ou */ | ||
94 | 81 | ||
95 | char * | 82 | /* |
96 | bcrypt(const char *key, const char *salt) | 83 | * the core bcrypt function |
84 | */ | ||
85 | int | ||
86 | bcrypt_hashpass(const char *key, const char *salt, char *encrypted, | ||
87 | size_t encryptedlen) | ||
97 | { | 88 | { |
98 | blf_ctx state; | 89 | blf_ctx state; |
99 | u_int32_t rounds, i, k; | 90 | u_int32_t rounds, i, k; |
@@ -109,8 +100,7 @@ bcrypt(const char *key, const char *salt) | |||
109 | salt++; | 100 | salt++; |
110 | 101 | ||
111 | if (*salt > BCRYPT_VERSION) { | 102 | if (*salt > BCRYPT_VERSION) { |
112 | /* How do I handle errors ? Return ':' */ | 103 | return -1; |
113 | return error; | ||
114 | } | 104 | } |
115 | 105 | ||
116 | /* Check for minor versions */ | 106 | /* Check for minor versions */ |
@@ -122,7 +112,7 @@ bcrypt(const char *key, const char *salt) | |||
122 | salt++; | 112 | salt++; |
123 | break; | 113 | break; |
124 | default: | 114 | default: |
125 | return error; | 115 | return -1; |
126 | } | 116 | } |
127 | } else | 117 | } else |
128 | minor = 0; | 118 | minor = 0; |
@@ -132,15 +122,15 @@ bcrypt(const char *key, const char *salt) | |||
132 | 122 | ||
133 | if (salt[2] != '$') | 123 | if (salt[2] != '$') |
134 | /* Out of sync with passwd entry */ | 124 | /* Out of sync with passwd entry */ |
135 | return error; | 125 | return -1; |
136 | 126 | ||
137 | memcpy(arounds, salt, sizeof(arounds)); | 127 | memcpy(arounds, salt, sizeof(arounds)); |
138 | if (arounds[sizeof(arounds) - 1] != '$') | 128 | if (arounds[sizeof(arounds) - 1] != '$') |
139 | return error; | 129 | return -1; |
140 | arounds[sizeof(arounds) - 1] = 0; | 130 | arounds[sizeof(arounds) - 1] = 0; |
141 | logr = strtonum(arounds, BCRYPT_MINLOGROUNDS, 31, NULL); | 131 | logr = strtonum(arounds, BCRYPT_MINLOGROUNDS, 31, NULL); |
142 | if (logr == 0) | 132 | if (logr == 0) |
143 | return error; | 133 | return -1; |
144 | /* Computer power doesn't increase linearly, 2^x should be fine */ | 134 | /* Computer power doesn't increase linearly, 2^x should be fine */ |
145 | rounds = 1U << logr; | 135 | rounds = 1U << logr; |
146 | 136 | ||
@@ -148,7 +138,7 @@ bcrypt(const char *key, const char *salt) | |||
148 | salt += 3; | 138 | salt += 3; |
149 | 139 | ||
150 | if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT) | 140 | if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT) |
151 | return error; | 141 | return -1; |
152 | 142 | ||
153 | /* We dont want the base64 salt but the raw data */ | 143 | /* We dont want the base64 salt but the raw data */ |
154 | decode_base64(csalt, BCRYPT_MAXSALT, (u_int8_t *) salt); | 144 | decode_base64(csalt, BCRYPT_MAXSALT, (u_int8_t *) salt); |
@@ -211,9 +201,41 @@ bcrypt(const char *key, const char *salt) | |||
211 | memset(ciphertext, 0, sizeof(ciphertext)); | 201 | memset(ciphertext, 0, sizeof(ciphertext)); |
212 | memset(csalt, 0, sizeof(csalt)); | 202 | memset(csalt, 0, sizeof(csalt)); |
213 | memset(cdata, 0, sizeof(cdata)); | 203 | memset(cdata, 0, sizeof(cdata)); |
214 | return encrypted; | 204 | return 0; |
205 | } | ||
206 | |||
207 | /* | ||
208 | * user friendly functions | ||
209 | */ | ||
210 | int | ||
211 | bcrypt_newhash(const char *pass, int log_rounds, char *hash, size_t hashlen) | ||
212 | { | ||
213 | char salt[BCRYPT_SALTSPACE]; | ||
214 | |||
215 | if (bcrypt_initsalt(log_rounds, salt, sizeof(salt)) != 0) | ||
216 | return -1; | ||
217 | |||
218 | if (bcrypt_hashpass(pass, salt, hash, hashlen) != 0) | ||
219 | return -1; | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | int | ||
225 | bcrypt_checkpass(const char *pass, const char *goodhash) | ||
226 | { | ||
227 | char hash[_PASSWORD_LEN]; | ||
228 | |||
229 | if (bcrypt_hashpass(pass, goodhash, hash, sizeof(hash)) != 0) | ||
230 | return -1; | ||
231 | if (strcmp(hash, goodhash) != 0) | ||
232 | return -1; | ||
233 | return 0; | ||
215 | } | 234 | } |
216 | 235 | ||
236 | /* | ||
237 | * internal utilities | ||
238 | */ | ||
217 | const static u_int8_t Base64Code[] = | 239 | const static u_int8_t Base64Code[] = |
218 | "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | 240 | "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; |
219 | 241 | ||
@@ -298,3 +320,30 @@ encode_base64(u_int8_t *buffer, u_int8_t *data, u_int16_t len) | |||
298 | } | 320 | } |
299 | *bp = '\0'; | 321 | *bp = '\0'; |
300 | } | 322 | } |
323 | |||
324 | /* | ||
325 | * classic interface | ||
326 | */ | ||
327 | char * | ||
328 | bcrypt_gensalt(u_int8_t log_rounds) | ||
329 | { | ||
330 | static char gsalt[7 + (BCRYPT_MAXSALT * 4 + 2) / 3 + 1]; | ||
331 | |||
332 | bcrypt_initsalt(log_rounds, gsalt, sizeof(gsalt)); | ||
333 | |||
334 | return gsalt; | ||
335 | } | ||
336 | |||
337 | char * | ||
338 | bcrypt(const char *pass, const char *salt) | ||
339 | { | ||
340 | static char gencrypted[_PASSWORD_LEN]; | ||
341 | static char gerror[] = ":"; | ||
342 | |||
343 | /* How do I handle errors ? Return ':' */ | ||
344 | if (bcrypt_hashpass(pass, salt, gencrypted, sizeof(gencrypted)) != 0) | ||
345 | return gerror; | ||
346 | |||
347 | return gencrypted; | ||
348 | } | ||
349 | |||