Path: blob/main/secure/lib/libcrypt/crypt-blowfish.c
39507 views
/* $OpenBSD: bcrypt.c,v 1.29 2014/02/24 19:45:43 tedu Exp $ */12/*3* Copyright 1997 Niels Provos <[email protected]>4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14* 3. All advertising materials mentioning features or use of this software15* must display the following acknowledgement:16* This product includes software developed by Niels Provos.17* 4. The name of the author may not be used to endorse or promote products18* derived from this software without specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR21* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES22* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.23* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,24* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT25* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,26* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY27* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT28* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF29* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.30*/3132#include <sys/cdefs.h>33/* This password hashing algorithm was designed by David Mazieres34* <[email protected]> and works as follows:35*36* 1. state := InitState ()37* 2. state := ExpandKey (state, salt, password)38* 3. REPEAT rounds:39* state := ExpandKey (state, 0, password)40* state := ExpandKey (state, 0, salt)41* 4. ctext := "OrpheanBeholderScryDoubt"42* 5. REPEAT 64:43* ctext := Encrypt_ECB (state, ctext);44* 6. RETURN Concatenate (salt, ctext);45*46*/4748/*49* FreeBSD implementation by Paul Herman <[email protected]>50* and updated by Xin Li <[email protected]>51*/5253#include <stdio.h>54#include <stdlib.h>55#include <sys/types.h>56#include <string.h>57#include <pwd.h>58#include "blowfish.h"59#include "crypt.h"6061/* This implementation is adaptable to current computing power.62* You can have up to 2^31 rounds which should be enough for some63* time to come.64*/6566#define BCRYPT_VERSION '2'67#define BCRYPT_MAXSALT 16 /* Precomputation is just so nice */68#define BCRYPT_BLOCKS 6 /* Ciphertext blocks */69#define BCRYPT_MINLOGROUNDS 4 /* we have log2(rounds) in salt */707172static void encode_base64(u_int8_t *, u_int8_t *, u_int16_t);73static void decode_base64(u_int8_t *, u_int16_t, const u_int8_t *);7475const static u_int8_t Base64Code[] =76"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";7778const static u_int8_t index_64[128] = {79255, 255, 255, 255, 255, 255, 255, 255, 255, 255,80255, 255, 255, 255, 255, 255, 255, 255, 255, 255,81255, 255, 255, 255, 255, 255, 255, 255, 255, 255,82255, 255, 255, 255, 255, 255, 255, 255, 255, 255,83255, 255, 255, 255, 255, 255, 0, 1, 54, 55,8456, 57, 58, 59, 60, 61, 62, 63, 255, 255,85255, 255, 255, 255, 255, 2, 3, 4, 5, 6,867, 8, 9, 10, 11, 12, 13, 14, 15, 16,8717, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,88255, 255, 255, 255, 255, 255, 28, 29, 30,8931, 32, 33, 34, 35, 36, 37, 38, 39, 40,9041, 42, 43, 44, 45, 46, 47, 48, 49, 50,9151, 52, 53, 255, 255, 255, 255, 25592};93#define CHAR64(c) ( (c) > 127 ? 255 : index_64[(c)])9495static void96decode_base64(u_int8_t *buffer, u_int16_t len, const u_int8_t *data)97{98u_int8_t *bp = buffer;99const u_int8_t *p = data;100u_int8_t c1, c2, c3, c4;101while (bp < buffer + len) {102c1 = CHAR64(*p);103c2 = CHAR64(*(p + 1));104105/* Invalid data */106if (c1 == 255 || c2 == 255)107break;108109*bp++ = (c1 << 2) | ((c2 & 0x30) >> 4);110if (bp >= buffer + len)111break;112113c3 = CHAR64(*(p + 2));114if (c3 == 255)115break;116117*bp++ = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);118if (bp >= buffer + len)119break;120121c4 = CHAR64(*(p + 3));122if (c4 == 255)123break;124*bp++ = ((c3 & 0x03) << 6) | c4;125126p += 4;127}128}129130/* We handle $Vers$log2(NumRounds)$salt+passwd$131i.e. $2$04$iwouldntknowwhattosayetKdJ6iFtacBqJdKe6aW7ou */132133int134crypt_blowfish(const char *key, const char *salt, char *buffer)135{136blf_ctx state;137u_int32_t rounds, i, k;138u_int16_t j;139size_t key_len;140u_int8_t salt_len, logr, minr;141u_int8_t ciphertext[4 * BCRYPT_BLOCKS] = "OrpheanBeholderScryDoubt";142u_int8_t csalt[BCRYPT_MAXSALT];143u_int32_t cdata[BCRYPT_BLOCKS];144char arounds[3];145146/* Defaults */147minr = 'b';148logr = BCRYPT_MINLOGROUNDS;149rounds = 1U << logr;150151if (*salt == '$') {152/* Discard "$" identifier */153salt++;154155if (*salt > BCRYPT_VERSION)156return (-1);157158/* Check for minor versions */159if (salt[1] != '$') {160switch (salt[1]) {161case 'a': /* 'ab' should not yield the same as 'abab' */162case 'b': /* cap input length at 72 bytes */163case 'y': /* same as 'b', for compatibility164* with openwall crypt_blowfish165*/166minr = salt[1];167salt++;168break;169default:170return (-1);171}172} else173minr = 0;174175/* Discard version + "$" identifier */176salt += 2;177178if (salt[2] != '$')179/* Out of sync with passwd entry */180return (-1);181182memcpy(arounds, salt, sizeof(arounds));183if (arounds[sizeof(arounds) - 1] != '$')184return (-1);185arounds[sizeof(arounds) - 1] = 0;186logr = strtonum(arounds, BCRYPT_MINLOGROUNDS, 31, NULL);187if (logr == 0)188return (-1);189/* Computer power doesn't increase linearly, 2^x should be fine */190rounds = 1U << logr;191192/* Discard num rounds + "$" identifier */193salt += 3;194}195196if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT)197return (-1);198199/* We dont want the base64 salt but the raw data */200decode_base64(csalt, BCRYPT_MAXSALT, (const u_int8_t *) salt);201salt_len = BCRYPT_MAXSALT;202if (minr <= 'a')203key_len = (u_int8_t)(strlen(key) + (minr >= 'a' ? 1 : 0));204else {205/* strlen() returns a size_t, but the function calls206* below result in implicit casts to a narrower integer207* type, so cap key_len at the actual maximum supported208* length here to avoid integer wraparound */209key_len = strlen(key);210if (key_len > 72)211key_len = 72;212key_len++; /* include the NUL */213}214215/* Setting up S-Boxes and Subkeys */216Blowfish_initstate(&state);217Blowfish_expandstate(&state, csalt, salt_len,218(const u_int8_t *) key, key_len);219for (k = 0; k < rounds; k++) {220Blowfish_expand0state(&state, (const u_int8_t *) key, key_len);221Blowfish_expand0state(&state, csalt, salt_len);222}223224/* This can be precomputed later */225j = 0;226for (i = 0; i < BCRYPT_BLOCKS; i++)227cdata[i] = Blowfish_stream2word(ciphertext, 4 * BCRYPT_BLOCKS, &j);228229/* Now do the encryption */230for (k = 0; k < 64; k++)231blf_enc(&state, cdata, BCRYPT_BLOCKS / 2);232233for (i = 0; i < BCRYPT_BLOCKS; i++) {234ciphertext[4 * i + 3] = cdata[i] & 0xff;235cdata[i] = cdata[i] >> 8;236ciphertext[4 * i + 2] = cdata[i] & 0xff;237cdata[i] = cdata[i] >> 8;238ciphertext[4 * i + 1] = cdata[i] & 0xff;239cdata[i] = cdata[i] >> 8;240ciphertext[4 * i + 0] = cdata[i] & 0xff;241}242243244*buffer++ = '$';245*buffer++ = BCRYPT_VERSION;246if (minr)247*buffer++ = minr;248*buffer++ = '$';249250snprintf(buffer, 4, "%2.2u$", logr);251buffer += 3;252253encode_base64((u_int8_t *)buffer, csalt, BCRYPT_MAXSALT);254buffer += strlen(buffer);255encode_base64((u_int8_t *)buffer, ciphertext, 4 * BCRYPT_BLOCKS - 1);256memset(&state, 0, sizeof(state));257memset(ciphertext, 0, sizeof(ciphertext));258memset(csalt, 0, sizeof(csalt));259memset(cdata, 0, sizeof(cdata));260return (0);261}262263static void264encode_base64(u_int8_t *buffer, u_int8_t *data, u_int16_t len)265{266u_int8_t *bp = buffer;267u_int8_t *p = data;268u_int8_t c1, c2;269while (p < data + len) {270c1 = *p++;271*bp++ = Base64Code[(c1 >> 2)];272c1 = (c1 & 0x03) << 4;273if (p >= data + len) {274*bp++ = Base64Code[c1];275break;276}277c2 = *p++;278c1 |= (c2 >> 4) & 0x0f;279*bp++ = Base64Code[c1];280c1 = (c2 & 0x0f) << 2;281if (p >= data + len) {282*bp++ = Base64Code[c1];283break;284}285c2 = *p++;286c1 |= (c2 >> 6) & 0x03;287*bp++ = Base64Code[c1];288*bp++ = Base64Code[c2 & 0x3f];289}290*bp = '\0';291}292#if 0293void294main()295{296char blubber[73];297char salt[100];298char *p;299salt[0] = '$';300salt[1] = BCRYPT_VERSION;301salt[2] = '$';302303snprintf(salt + 3, 4, "%2.2u$", 5);304305printf("24 bytes of salt: ");306fgets(salt + 6, sizeof(salt) - 6, stdin);307salt[99] = 0;308printf("72 bytes of password: ");309fpurge(stdin);310fgets(blubber, sizeof(blubber), stdin);311blubber[72] = 0;312313p = crypt(blubber, salt);314printf("Passwd entry: %s\n\n", p);315316p = bcrypt_gensalt(5);317printf("Generated salt: %s\n", p);318p = crypt(blubber, p);319printf("Passwd entry: %s\n", p);320}321#endif322323324