diff options
| author | tedu <> | 2014-03-23 23:19:21 +0000 |
|---|---|---|
| committer | tedu <> | 2014-03-23 23:19:21 +0000 |
| commit | 5b35fc25520771de7fbac332def10ee625709c8d (patch) | |
| tree | c09c8bcc755b7ba36261f229eb033d456f02cd7f /src/lib/libc/crypt/bcrypt.c | |
| parent | 35c387ad7bdcb1925b8afb40488f879ff652603f (diff) | |
| download | openbsd-5b35fc25520771de7fbac332def10ee625709c8d.tar.gz openbsd-5b35fc25520771de7fbac332def10ee625709c8d.tar.bz2 openbsd-5b35fc25520771de7fbac332def10ee625709c8d.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/libc/crypt/bcrypt.c')
| -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 | |||
