Eric Andersen | 27f64e1 | 2002-06-23 04:24:25 +0000 | [diff] [blame] | 1 | /* vi: set sw=4 ts=4: */ |
| 2 | /* |
Denis Vlasenko | d1a84a2 | 2008-12-07 01:16:34 +0000 | [diff] [blame] | 3 | * Utility routines. |
Eric Andersen | 27f64e1 | 2002-06-23 04:24:25 +0000 | [diff] [blame] | 4 | * |
Eric Andersen | c7bda1c | 2004-03-15 08:29:22 +0000 | [diff] [blame] | 5 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> |
Eric Andersen | 27f64e1 | 2002-06-23 04:24:25 +0000 | [diff] [blame] | 6 | * |
Denys Vlasenko | 0ef64bd | 2010-08-16 20:14:46 +0200 | [diff] [blame] | 7 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
Eric Andersen | 27f64e1 | 2002-06-23 04:24:25 +0000 | [diff] [blame] | 8 | */ |
Denys Vlasenko | 4767a53 | 2019-07-16 15:09:06 +0200 | [diff] [blame] | 9 | #if !ENABLE_USE_BB_CRYPT |
Alex Samorukov | 09aba8b | 2021-01-04 01:36:05 +0100 | [diff] [blame] | 10 | # if !defined(__FreeBSD__) |
| 11 | # include <crypt.h> |
| 12 | # endif |
Denys Vlasenko | 4767a53 | 2019-07-16 15:09:06 +0200 | [diff] [blame] | 13 | #endif |
Rob Landley | ea224be | 2006-06-18 20:20:07 +0000 | [diff] [blame] | 14 | #include "libbb.h" |
Eric Andersen | 27f64e1 | 2002-06-23 04:24:25 +0000 | [diff] [blame] | 15 | |
Denys Vlasenko | 3e134eb | 2016-04-22 18:09:21 +0200 | [diff] [blame] | 16 | /* static const uint8_t ascii64[] ALIGN1 = |
Denis Vlasenko | d1a84a2 | 2008-12-07 01:16:34 +0000 | [diff] [blame] | 17 | * "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; |
| 18 | */ |
| 19 | |
| 20 | static int i64c(int i) |
| 21 | { |
| 22 | i &= 0x3f; |
| 23 | if (i == 0) |
| 24 | return '.'; |
| 25 | if (i == 1) |
| 26 | return '/'; |
| 27 | if (i < 12) |
| 28 | return ('0' - 2 + i); |
| 29 | if (i < 38) |
| 30 | return ('A' - 12 + i); |
| 31 | return ('a' - 38 + i); |
| 32 | } |
| 33 | |
Denys Vlasenko | 12a4327 | 2011-05-13 03:19:01 +0200 | [diff] [blame] | 34 | int FAST_FUNC crypt_make_salt(char *p, int cnt /*, int x */) |
Denis Vlasenko | d1a84a2 | 2008-12-07 01:16:34 +0000 | [diff] [blame] | 35 | { |
Denys Vlasenko | 12a4327 | 2011-05-13 03:19:01 +0200 | [diff] [blame] | 36 | /* was: x += ... */ |
Rostislav Skudnov | 8762512 | 2017-02-01 18:35:13 +0000 | [diff] [blame] | 37 | unsigned x = getpid() + monotonic_us(); |
Denis Vlasenko | d1a84a2 | 2008-12-07 01:16:34 +0000 | [diff] [blame] | 38 | do { |
| 39 | /* x = (x*1664525 + 1013904223) % 2^32 generator is lame |
| 40 | * (low-order bit is not "random", etc...), |
| 41 | * but for our purposes it is good enough */ |
| 42 | x = x*1664525 + 1013904223; |
| 43 | /* BTW, Park and Miller's "minimal standard generator" is |
| 44 | * x = x*16807 % ((2^31)-1) |
| 45 | * It has no problem with visibly alternating lowest bit |
| 46 | * but is also weak in cryptographic sense + needs div, |
| 47 | * which needs more code (and slower) on many CPUs */ |
| 48 | *p++ = i64c(x >> 16); |
| 49 | *p++ = i64c(x >> 22); |
| 50 | } while (--cnt); |
| 51 | *p = '\0'; |
| 52 | return x; |
| 53 | } |
| 54 | |
Denys Vlasenko | 12a4327 | 2011-05-13 03:19:01 +0200 | [diff] [blame] | 55 | char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo) |
| 56 | { |
| 57 | int len = 2/2; |
| 58 | char *salt_ptr = salt; |
Pascal Bach | 2c0d3f5 | 2015-12-18 19:01:14 +0100 | [diff] [blame] | 59 | |
| 60 | /* Standard chpasswd uses uppercase algos ("MD5", not "md5"). |
| 61 | * Need to be case-insensitive in the code below. |
| 62 | */ |
| 63 | if ((algo[0]|0x20) != 'd') { /* not des */ |
Denys Vlasenko | 12a4327 | 2011-05-13 03:19:01 +0200 | [diff] [blame] | 64 | len = 8/2; /* so far assuming md5 */ |
| 65 | *salt_ptr++ = '$'; |
| 66 | *salt_ptr++ = '1'; |
| 67 | *salt_ptr++ = '$'; |
| 68 | #if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA |
Pascal Bach | 2c0d3f5 | 2015-12-18 19:01:14 +0100 | [diff] [blame] | 69 | if ((algo[0]|0x20) == 's') { /* sha */ |
| 70 | salt[1] = '5' + (strcasecmp(algo, "sha512") == 0); |
Denys Vlasenko | 12a4327 | 2011-05-13 03:19:01 +0200 | [diff] [blame] | 71 | len = 16/2; |
| 72 | } |
| 73 | #endif |
| 74 | } |
| 75 | crypt_make_salt(salt_ptr, len); |
| 76 | return salt_ptr; |
| 77 | } |
| 78 | |
Denis Vlasenko | b4c5bf6 | 2008-06-15 18:35:34 +0000 | [diff] [blame] | 79 | #if ENABLE_USE_BB_CRYPT |
| 80 | |
Denis Vlasenko | d1a84a2 | 2008-12-07 01:16:34 +0000 | [diff] [blame] | 81 | static char* |
| 82 | to64(char *s, unsigned v, int n) |
| 83 | { |
| 84 | while (--n >= 0) { |
| 85 | /* *s++ = ascii64[v & 0x3f]; */ |
| 86 | *s++ = i64c(v); |
| 87 | v >>= 6; |
| 88 | } |
| 89 | return s; |
| 90 | } |
| 91 | |
Denis Vlasenko | 4ea83bf | 2008-06-12 16:55:59 +0000 | [diff] [blame] | 92 | /* |
| 93 | * DES and MD5 crypt implementations are taken from uclibc. |
| 94 | * They were modified to not use static buffers. |
Denis Vlasenko | 4ea83bf | 2008-06-12 16:55:59 +0000 | [diff] [blame] | 95 | */ |
Denis Vlasenko | 2211d52 | 2008-11-10 18:52:35 +0000 | [diff] [blame] | 96 | |
Denis Vlasenko | 4ea83bf | 2008-06-12 16:55:59 +0000 | [diff] [blame] | 97 | #include "pw_encrypt_des.c" |
| 98 | #include "pw_encrypt_md5.c" |
Denis Vlasenko | 2211d52 | 2008-11-10 18:52:35 +0000 | [diff] [blame] | 99 | #if ENABLE_USE_BB_CRYPT_SHA |
| 100 | #include "pw_encrypt_sha.c" |
| 101 | #endif |
Denis Vlasenko | 4ea83bf | 2008-06-12 16:55:59 +0000 | [diff] [blame] | 102 | |
Denis Vlasenko | 2211d52 | 2008-11-10 18:52:35 +0000 | [diff] [blame] | 103 | /* Other advanced crypt ids (TODO?): */ |
Denis Vlasenko | 30e1ab6 | 2008-11-07 13:36:46 +0000 | [diff] [blame] | 104 | /* $2$ or $2a$: Blowfish */ |
Denis Vlasenko | 4ea83bf | 2008-06-12 16:55:59 +0000 | [diff] [blame] | 105 | |
| 106 | static struct const_des_ctx *des_cctx; |
| 107 | static struct des_ctx *des_ctx; |
| 108 | |
| 109 | /* my_crypt returns malloc'ed data */ |
| 110 | static char *my_crypt(const char *key, const char *salt) |
Eric Andersen | 27f64e1 | 2002-06-23 04:24:25 +0000 | [diff] [blame] | 111 | { |
Denis Vlasenko | 2211d52 | 2008-11-10 18:52:35 +0000 | [diff] [blame] | 112 | /* MD5 or SHA? */ |
| 113 | if (salt[0] == '$' && salt[1] && salt[2] == '$') { |
| 114 | if (salt[1] == '1') |
| 115 | return md5_crypt(xzalloc(MD5_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt); |
| 116 | #if ENABLE_USE_BB_CRYPT_SHA |
| 117 | if (salt[1] == '5' || salt[1] == '6') |
| 118 | return sha_crypt((char*)key, (char*)salt); |
| 119 | #endif |
Denis Vlasenko | 4ea83bf | 2008-06-12 16:55:59 +0000 | [diff] [blame] | 120 | } |
| 121 | |
Denis Vlasenko | 2211d52 | 2008-11-10 18:52:35 +0000 | [diff] [blame] | 122 | if (!des_cctx) |
| 123 | des_cctx = const_des_init(); |
| 124 | des_ctx = des_init(des_ctx, des_cctx); |
Denys Vlasenko | 73d93d9 | 2020-12-15 23:19:22 +0100 | [diff] [blame] | 125 | /* Can return NULL if salt is bad ("" or "<one_char>") */ |
Denis Vlasenko | 2211d52 | 2008-11-10 18:52:35 +0000 | [diff] [blame] | 126 | return des_crypt(des_ctx, xzalloc(DES_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt); |
Denis Vlasenko | 4ea83bf | 2008-06-12 16:55:59 +0000 | [diff] [blame] | 127 | } |
| 128 | |
| 129 | /* So far nobody wants to have it public */ |
| 130 | static void my_crypt_cleanup(void) |
| 131 | { |
| 132 | free(des_cctx); |
| 133 | free(des_ctx); |
| 134 | des_cctx = NULL; |
| 135 | des_ctx = NULL; |
| 136 | } |
| 137 | |
Denis Vlasenko | defc1ea | 2008-06-27 02:52:20 +0000 | [diff] [blame] | 138 | char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup) |
Denis Vlasenko | 4ea83bf | 2008-06-12 16:55:59 +0000 | [diff] [blame] | 139 | { |
Denis Vlasenko | fdddab0 | 2008-06-12 16:56:52 +0000 | [diff] [blame] | 140 | char *encrypted; |
Eric Andersen | 27f64e1 | 2002-06-23 04:24:25 +0000 | [diff] [blame] | 141 | |
Denis Vlasenko | fdddab0 | 2008-06-12 16:56:52 +0000 | [diff] [blame] | 142 | encrypted = my_crypt(clear, salt); |
Denys Vlasenko | 73d93d9 | 2020-12-15 23:19:22 +0100 | [diff] [blame] | 143 | if (!encrypted) |
| 144 | bb_simple_error_msg_and_die("bad salt"); |
Denis Vlasenko | 4ea83bf | 2008-06-12 16:55:59 +0000 | [diff] [blame] | 145 | |
| 146 | if (cleanup) |
| 147 | my_crypt_cleanup(); |
| 148 | |
Denis Vlasenko | fdddab0 | 2008-06-12 16:56:52 +0000 | [diff] [blame] | 149 | return encrypted; |
Eric Andersen | 27f64e1 | 2002-06-23 04:24:25 +0000 | [diff] [blame] | 150 | } |
Denis Vlasenko | b4c5bf6 | 2008-06-15 18:35:34 +0000 | [diff] [blame] | 151 | |
| 152 | #else /* if !ENABLE_USE_BB_CRYPT */ |
| 153 | |
Denis Vlasenko | defc1ea | 2008-06-27 02:52:20 +0000 | [diff] [blame] | 154 | char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup) |
Denis Vlasenko | b4c5bf6 | 2008-06-15 18:35:34 +0000 | [diff] [blame] | 155 | { |
Denys Vlasenko | 73d93d9 | 2020-12-15 23:19:22 +0100 | [diff] [blame] | 156 | char *encrypted; |
Denys Vlasenko | 8ed9672 | 2014-02-09 14:38:03 +0100 | [diff] [blame] | 157 | |
Denys Vlasenko | 73d93d9 | 2020-12-15 23:19:22 +0100 | [diff] [blame] | 158 | encrypted = crypt(clear, salt); |
Denys Vlasenko | 8ed9672 | 2014-02-09 14:38:03 +0100 | [diff] [blame] | 159 | /* |
| 160 | * glibc used to return "" on malformed salts (for example, ""), |
| 161 | * but since 2.17 it returns NULL. |
| 162 | */ |
Denys Vlasenko | 73d93d9 | 2020-12-15 23:19:22 +0100 | [diff] [blame] | 163 | if (!encrypted || !encrypted[0]) |
| 164 | bb_simple_error_msg_and_die("bad salt"); |
| 165 | return xstrdup(encrypted); |
Denis Vlasenko | b4c5bf6 | 2008-06-15 18:35:34 +0000 | [diff] [blame] | 166 | } |
| 167 | |
| 168 | #endif |