| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include "crypt-port.h" |
| #include "crypt-private.h" |
| #include "alg-des.h" |
| |
| #include <errno.h> |
| |
| #if INCLUDE_des || INCLUDE_des_xbsd || INCLUDE_des_big |
| |
| #define DES_TRD_OUTPUT_LEN 14 /* SShhhhhhhhhhh0 */ |
| #define DES_EXT_OUTPUT_LEN 21 /* _CCCCSSSShhhhhhhhhhh0 */ |
| #define DES_BIG_OUTPUT_LEN ((16*11) + 2 + 1) /* SS (hhhhhhhhhhh){1,16} 0 */ |
| |
| #define DES_MAX_OUTPUT_LEN \ |
| MAX (DES_TRD_OUTPUT_LEN, MAX (DES_EXT_OUTPUT_LEN, DES_BIG_OUTPUT_LEN)) |
| |
| static_assert (DES_MAX_OUTPUT_LEN <= CRYPT_OUTPUT_SIZE, |
| "CRYPT_OUTPUT_SIZE is too small for DES"); |
| |
| |
| |
| |
| struct des_buffer |
| { |
| struct des_ctx ctx; |
| uint8_t keybuf[8]; |
| uint8_t pkbuf[8]; |
| }; |
| |
| static_assert (sizeof (struct des_buffer) <= ALG_SPECIFIC_SIZE, |
| "ALG_SPECIFIC_SIZE is too small for DES"); |
| |
| |
| static const uint8_t ascii64[] = |
| "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; |
| |
| |
| |
| static inline int |
| ascii_to_bin(char ch) |
| { |
| if (ch > 'z') |
| return -1; |
| if (ch >= 'a') |
| return ch - 'a' + 38; |
| if (ch > 'Z') |
| return -1; |
| if (ch >= 'A') |
| return ch - 'A' + 12; |
| if (ch > '9') |
| return -1; |
| if (ch >= '.') |
| return ch - '.'; |
| return -1; |
| } |
| |
| |
| |
| |
| |
| static void |
| des_gen_hash (struct des_ctx *ctx, uint32_t count, uint8_t *output, |
| uint8_t cbuf[8]) |
| { |
| uint8_t plaintext[8]; |
| XCRYPT_SECURE_MEMSET (plaintext, 8); |
| des_crypt_block (ctx, cbuf, plaintext, count, false); |
| |
| |
| const uint8_t *sptr = cbuf; |
| const uint8_t *end = sptr + 8; |
| unsigned int c1, c2; |
| |
| do |
| { |
| c1 = *sptr++; |
| *output++ = ascii64[c1 >> 2]; |
| c1 = (c1 & 0x03) << 4; |
| if (sptr >= end) |
| { |
| *output++ = ascii64[c1]; |
| break; |
| } |
| |
| c2 = *sptr++; |
| c1 |= c2 >> 4; |
| *output++ = ascii64[c1]; |
| c1 = (c2 & 0x0f) << 2; |
| if (sptr >= end) |
| { |
| *output++ = ascii64[c1]; |
| break; |
| } |
| |
| c2 = *sptr++; |
| c1 |= c2 >> 6; |
| *output++ = ascii64[c1]; |
| *output++ = ascii64[c2 & 0x3f]; |
| } |
| while (sptr < end); |
| *output = '\0'; |
| } |
| #endif |
| |
| #if INCLUDE_des |
| |
| void |
| crypt_des_rn (const char *phrase, size_t ARG_UNUSED (phr_size), |
| const char *setting, size_t ARG_UNUSED (set_size), |
| uint8_t *output, size_t out_size, |
| void *scratch, size_t scr_size) |
| { |
| |
| if (out_size < DES_TRD_OUTPUT_LEN || scr_size < sizeof (struct des_buffer)) |
| { |
| errno = ERANGE; |
| return; |
| } |
| |
| struct des_buffer *buf = scratch; |
| struct des_ctx *ctx = &buf->ctx; |
| uint32_t salt = 0; |
| uint8_t *keybuf = buf->keybuf, *pkbuf = buf->pkbuf; |
| uint8_t *cp = output; |
| int i; |
| |
| |
| |
| |
| i = ascii_to_bin (setting[0]); |
| if (i < 0) |
| { |
| errno = EINVAL; |
| return; |
| } |
| salt = (unsigned int)i; |
| i = ascii_to_bin (setting[1]); |
| if (i < 0) |
| { |
| errno = EINVAL; |
| return; |
| } |
| salt |= ((unsigned int)i << 6); |
| |
| |
| |
| |
| |
| |
| *cp++ = ascii64[salt & 0x3f]; |
| *cp++ = ascii64[(salt >> 6) & 0x3f]; |
| |
| |
| |
| for (i = 0; i < 8; i++) |
| { |
| keybuf[i] = (uint8_t)(*phrase << 1); |
| if (*phrase) |
| phrase++; |
| } |
| |
| des_set_key (ctx, keybuf); |
| des_set_salt (ctx, salt); |
| des_gen_hash (ctx, 25, cp, pkbuf); |
| } |
| #endif |
| |
| #if INCLUDE_des_big |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| void |
| crypt_des_big_rn (const char *phrase, size_t phr_size, |
| const char *setting, size_t set_size, |
| uint8_t *output, size_t out_size, |
| void *scratch, size_t scr_size) |
| { |
| #if INCLUDE_des |
| |
| |
| |
| |
| if (strlen (setting) <= 13) |
| { |
| crypt_des_rn (phrase, phr_size, setting, set_size, |
| output, out_size, scratch, scr_size); |
| return; |
| } |
| #endif |
| |
| |
| if (out_size < DES_BIG_OUTPUT_LEN || scr_size < sizeof (struct des_buffer)) |
| { |
| errno = ERANGE; |
| return; |
| } |
| |
| struct des_buffer *buf = scratch; |
| struct des_ctx *ctx = &buf->ctx; |
| uint32_t salt = 0; |
| uint8_t *keybuf = buf->keybuf, *pkbuf = buf->pkbuf; |
| uint8_t *cp = output; |
| int i, seg; |
| |
| |
| |
| i = ascii_to_bin (setting[0]); |
| if (i < 0) |
| { |
| errno = EINVAL; |
| return; |
| } |
| salt = (unsigned int)i; |
| i = ascii_to_bin (setting[1]); |
| if (i < 0) |
| { |
| errno = EINVAL; |
| return; |
| } |
| salt |= ((unsigned int)i << 6); |
| |
| *cp++ = ascii64[salt & 0x3f]; |
| *cp++ = ascii64[(salt >> 6) & 0x3f]; |
| |
| for (seg = 0; seg < 16; seg++) |
| { |
| |
| for (i = 0; i < 8; i++) |
| { |
| keybuf[i] = (uint8_t)(*phrase << 1); |
| if (*phrase) |
| phrase++; |
| } |
| |
| des_set_key (ctx, keybuf); |
| des_set_salt (ctx, salt); |
| des_gen_hash (ctx, 25, cp, pkbuf); |
| |
| if (*phrase == 0) |
| break; |
| |
| |
| |
| salt = (unsigned int)ascii_to_bin ((char)cp[0]); |
| salt |= (unsigned int)ascii_to_bin ((char)cp[1]) << 6; |
| cp += 11; |
| } |
| } |
| #endif |
| |
| #if INCLUDE_des_xbsd |
| |
| |
| |
| void |
| crypt_des_xbsd_rn (const char *phrase, size_t ARG_UNUSED (phr_size), |
| const char *setting, size_t set_size, |
| uint8_t *output, size_t out_size, |
| void *scratch, size_t scr_size) |
| { |
| |
| if (out_size < DES_EXT_OUTPUT_LEN || scr_size < sizeof (struct des_buffer)) |
| { |
| errno = ERANGE; |
| return; |
| } |
| |
| |
| |
| if (*setting != '_' || set_size < 9) |
| { |
| errno = EINVAL; |
| return; |
| } |
| |
| struct des_buffer *buf = scratch; |
| struct des_ctx *ctx = &buf->ctx; |
| uint32_t count = 0, salt = 0; |
| uint8_t *keybuf = buf->keybuf, *pkbuf = buf->pkbuf; |
| uint8_t *cp = output; |
| int i, x; |
| |
| |
| |
| |
| |
| for (i = 1; i < 5; i++) |
| { |
| x = ascii_to_bin(setting[i]); |
| if (x < 0) |
| { |
| errno = EINVAL; |
| return; |
| } |
| count |= (unsigned int)x << ((i - 1) * 6); |
| } |
| |
| for (i = 5; i < 9; i++) |
| { |
| x = ascii_to_bin(setting[i]); |
| if (x < 0) |
| { |
| errno = EINVAL; |
| return; |
| } |
| salt |= (unsigned int)x << ((i - 5) * 6); |
| } |
| |
| memcpy (cp, setting, 9); |
| cp += 9; |
| |
| |
| |
| |
| |
| |
| |
| des_set_salt (ctx, 0); |
| XCRYPT_SECURE_MEMSET (pkbuf, 8); |
| for (;;) |
| { |
| for (i = 0; i < 8; i++) |
| { |
| keybuf[i] = (uint8_t)(pkbuf[i] ^ (*phrase << 1)); |
| if (*phrase) |
| phrase++; |
| } |
| des_set_key (ctx, keybuf); |
| if (*phrase == 0) |
| break; |
| des_crypt_block (ctx, pkbuf, keybuf, 1, false); |
| } |
| |
| |
| des_set_salt (ctx, salt); |
| des_gen_hash (ctx, count, cp, pkbuf); |
| } |
| #endif |
| |
| #if INCLUDE_des || INCLUDE_des_big |
| void |
| gensalt_des_rn (unsigned long count, |
| const uint8_t *rbytes, size_t nrbytes, |
| uint8_t *output, size_t output_size) |
| { |
| if (output_size < 3) |
| { |
| errno = ERANGE; |
| return; |
| } |
| |
| if (nrbytes < 2 || (count != 0 && count != 25)) |
| { |
| errno = EINVAL; |
| return; |
| } |
| |
| output[0] = ascii64[(unsigned int) rbytes[0] & 0x3f]; |
| output[1] = ascii64[(unsigned int) rbytes[1] & 0x3f]; |
| output[2] = '\0'; |
| } |
| #if INCLUDE_des_big |
| strong_alias (gensalt_des_rn, gensalt_des_big_rn); |
| #endif |
| #endif |
| |
| #if INCLUDE_des_xbsd |
| void |
| gensalt_des_xbsd_rn (unsigned long count, |
| const uint8_t *rbytes, size_t nrbytes, |
| uint8_t *output, size_t output_size) |
| { |
| if (output_size < 1 + 4 + 4 + 1) |
| { |
| errno = ERANGE; |
| return; |
| } |
| |
| if (count == 0) |
| count = 725; |
| |
| |
| |
| if (nrbytes < 3 || count > 0xffffff || count % 2 == 0) |
| { |
| errno = EINVAL; |
| return; |
| } |
| |
| unsigned long value = |
| ((unsigned long) (unsigned char) rbytes[0] << 0) | |
| ((unsigned long) (unsigned char) rbytes[1] << 8) | |
| ((unsigned long) (unsigned char) rbytes[2] << 16); |
| |
| output[0] = '_'; |
| |
| output[1] = ascii64[(count >> 0) & 0x3f]; |
| output[2] = ascii64[(count >> 6) & 0x3f]; |
| output[3] = ascii64[(count >> 12) & 0x3f]; |
| output[4] = ascii64[(count >> 18) & 0x3f]; |
| |
| output[5] = ascii64[(value >> 0) & 0x3f]; |
| output[6] = ascii64[(value >> 6) & 0x3f]; |
| output[7] = ascii64[(value >> 12) & 0x3f]; |
| output[8] = ascii64[(value >> 18) & 0x3f]; |
| |
| output[9] = '\0'; |
| } |
| #endif |