crypto_sha512crypt.c revision 63be61852bd7ad1f74569843fb90629d63adb591
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* This file is based on nss_sha512crypt.c which is based on the work of
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Ulrich Drepper (http://people.redhat.com/drepper/SHA-crypt.txt).
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * libcrypto is used to provide SHA512 and random number generation.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * (http://www.openssl.org/docs/crypto/crypto.html).
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Sumit Bose <sbose@redhat.com>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * George McCollister <georgem@novatech-llc.com>
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* SHA512-based Unix crypt implementation.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define _GNU_SOURCE
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <endian.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <errno.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <limits.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <stdbool.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <stdint.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <stdio.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <stdlib.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <string.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/param.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/types.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "util/util.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <openssl/evp.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <openssl/rand.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* Define our magic string to mark salt for SHA512 "encryption" replacement. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinconst char sha512_salt_prefix[] = "$6$";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define SALT_PREF_SIZE (sizeof(sha512_salt_prefix) - 1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* Prefix for optional rounds specification. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinconst char sha512_rounds_prefix[] = "rounds=";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define ROUNDS_SIZE (sizeof(sha512_rounds_prefix) - 1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define SALT_LEN_MAX 16
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define ROUNDS_DEFAULT 5000
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define ROUNDS_MIN 1000
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define ROUNDS_MAX 999999999
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* Table with characters for base64 transformation. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinconst char b64t[64] =
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* base64 conversion function */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic inline void b64_from_24bit(char **dest, size_t *len, size_t n,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint8_t b2, uint8_t b1, uint8_t b0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint32_t w;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size_t i;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*len < n) n = *len;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w = (b2 << 16) | (b1 << 8) | b0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (i = 0; i < n; i++) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*dest)[i] = b64t[w & 0x3f];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin w >>= 6;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *len -= i;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *dest += i;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define PTR_2_INT(x) ((x) - ((__typeof__ (x)) NULL))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define ALIGN64 __alignof__(uint64_t)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int sha512_crypt_r(const char *key,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin const char *salt,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *buffer, size_t buflen)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unsigned char temp_result[64] __attribute__((__aligned__(ALIGN64)));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unsigned char alt_result[64] __attribute__((__aligned__(ALIGN64)));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size_t rounds = ROUNDS_DEFAULT;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bool rounds_custom = false;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_MD_CTX alt_ctx;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_MD_CTX ctx;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size_t salt_len;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size_t key_len;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size_t cnt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *copied_salt = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *copied_key = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *p_bytes = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *s_bytes = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int p1, p2, p3, pt, n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unsigned int part;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *cp, *tmp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int ret;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Find beginning of salt string. The prefix should normally always be
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * present. Just in case it is not. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (strncmp(salt, sha512_salt_prefix, SALT_PREF_SIZE) == 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Skip salt prefix. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin salt += SALT_PREF_SIZE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (strncmp(salt, sha512_rounds_prefix, ROUNDS_SIZE) == 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unsigned long int srounds;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin const char *num;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *endp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin num = salt + ROUNDS_SIZE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin srounds = strtoul(num, &endp, 10);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*endp == '$') {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin salt = endp + 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (srounds < ROUNDS_MIN) srounds = ROUNDS_MIN;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (srounds > ROUNDS_MAX) srounds = ROUNDS_MAX;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rounds = srounds;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rounds_custom = true;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin key_len = strlen(key);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((PTR_2_INT(key) % ALIGN64) != 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin tmp = (char *)alloca(key_len + ALIGN64);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin key = copied_key = memcpy(tmp + ALIGN64 - PTR_2_INT(tmp) % ALIGN64, key, key_len);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if (PTR_2_INT(salt) % ALIGN64 != 0) {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin tmp = (char *)alloca(salt_len + ALIGN64);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin salt = copied_salt = memcpy(tmp + ALIGN64 - PTR_2_INT(tmp) % ALIGN64, salt, salt_len);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz EVP_MD_CTX_init(&ctx);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz EVP_MD_CTX_init(&alt_ctx);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz /* Prepare for the real work. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!EVP_DigestInit_ex(&ctx, EVP_sha512(), NULL)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ret = EIO;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto done;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Add the key string. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestUpdate(&ctx, (const unsigned char *)key, key_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* The last part is the salt string. This must be at most 16
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * characters and it ends at the first `$' character (for
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin * compatibility with existing implementations). */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestUpdate(&ctx, (const unsigned char *)salt, salt_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Compute alternate SHA512 sum with input KEY, SALT, and KEY.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The final result will be added to the first context. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!EVP_DigestInit_ex(&alt_ctx, EVP_sha512(), NULL)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ret = EIO;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto done;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Add key. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestUpdate(&alt_ctx, (const unsigned char *)key, key_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Add salt. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestUpdate(&alt_ctx, (const unsigned char *)salt, salt_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Add key again. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestUpdate(&alt_ctx, (const unsigned char *)key, key_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Now get result of this (64 bytes) and add it to the other context. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestFinal_ex(&alt_ctx, alt_result, &part);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Add for any character in the key one byte of the alternate sum. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (cnt = key_len; cnt > 64; cnt -= 64) {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz EVP_DigestUpdate(&ctx, alt_result, 64);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner EVP_DigestUpdate(&ctx, alt_result, cnt);
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Take the binary representation of the length of the key and for every
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * 1 add the alternate sum, for every 0 the key. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (cnt = key_len; cnt > 0; cnt >>= 1) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((cnt & 1) != 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestUpdate(&ctx, alt_result, 64);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } else {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestUpdate(&ctx, (const unsigned char *)key, key_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Create intermediate result. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestFinal_ex(&ctx, alt_result, &part);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Start computation of P byte sequence. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!EVP_DigestInit_ex(&alt_ctx, EVP_sha512(), NULL)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ret = EIO;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto done;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* For every character in the password add the entire password. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (cnt = 0; cnt < key_len; cnt++) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestUpdate(&alt_ctx, (const unsigned char *)key, key_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Finish the digest. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestFinal_ex(&alt_ctx, temp_result, &part);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Create byte sequence P. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp = p_bytes = alloca(key_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (cnt = key_len; cnt >= 64; cnt -= 64) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp = mempcpy(cp, temp_result, 64);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memcpy(cp, temp_result, cnt);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Start computation of S byte sequence. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!EVP_DigestInit_ex(&alt_ctx, EVP_sha512(), NULL)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ret = EIO;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto done;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* For every character in the password add the entire salt. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (cnt = 0; cnt < 16 + alt_result[0]; cnt++) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestUpdate(&alt_ctx, (const unsigned char *)salt, salt_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Finish the digest. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestFinal_ex(&alt_ctx, temp_result, &part);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz /* Create byte sequence S. */
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz cp = s_bytes = alloca(salt_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (cnt = salt_len; cnt >= 64; cnt -= 64) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp = mempcpy(cp, temp_result, 64);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memcpy(cp, temp_result, cnt);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Repeatedly run the collected hash value through SHA512 to burn CPU cycles. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (cnt = 0; cnt < rounds; cnt++) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!EVP_DigestInit_ex(&ctx, EVP_sha512(), NULL)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ret = EIO;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto done;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Add key or last result. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((cnt & 1) != 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestUpdate(&ctx, (const unsigned char *)p_bytes, key_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } else {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestUpdate(&ctx, alt_result, 64);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Add salt for numbers not divisible by 3. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (cnt % 3 != 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestUpdate(&ctx, (const unsigned char *)s_bytes, salt_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Add key for numbers not divisible by 7. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (cnt % 7 != 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestUpdate(&ctx, (const unsigned char *)p_bytes, key_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Add key or last result. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((cnt & 1) != 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestUpdate(&ctx, alt_result, 64);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } else {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestUpdate(&ctx, (const unsigned char *)p_bytes, key_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Create intermediate result. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_DigestFinal_ex(&ctx, alt_result, &part);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz /* Now we can construct the result string.
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner * It consists of three parts. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (buflen <= SALT_PREF_SIZE) {
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner ret = ERANGE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto done;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp = __stpncpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin buflen -= SALT_PREF_SIZE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (rounds_custom) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = snprintf(cp, buflen, "%s%zu$",
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sha512_rounds_prefix, rounds);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (n < 0 || n >= buflen) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ret = ERANGE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto done;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp += n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin buflen -= n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (buflen <= salt_len + 1) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ret = ERANGE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto done;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp = __stpncpy(cp, salt, salt_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp++ = '$';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin buflen -= salt_len + 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* fuzzyfill the base 64 string */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p1 = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p2 = 21;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p3 = 42;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (n = 0; n < 21; n++) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin b64_from_24bit(&cp, &buflen, 4, alt_result[p1], alt_result[p2], alt_result[p3]);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (buflen == 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ret = ERANGE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto done;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pt = p1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p1 = p2 + 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p2 = p3 + 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p3 = pt + 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* 64th and last byte */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin b64_from_24bit(&cp, &buflen, 2, 0, 0, alt_result[p3]);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (buflen == 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ret = ERANGE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto done;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *cp = '\0';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ret = EOK;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chindone:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Clear the buffer for the intermediate result so that people attaching
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * to processes or reading core dumps cannot get any information. We do it
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * in this way to clear correct_words[] inside the SHA512 implementation
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * as well. */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_MD_CTX_cleanup(&ctx);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin EVP_MD_CTX_cleanup(&alt_ctx);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (p_bytes) memset(p_bytes, '\0', key_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (s_bytes) memset(s_bytes, '\0', salt_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (copied_key) memset(copied_key, '\0', key_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (copied_salt) memset(copied_salt, '\0', salt_len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin memset(temp_result, '\0', sizeof(temp_result));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return ret;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint s3crypt_sha512(TALLOC_CTX *memctx,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin const char *key, const char *salt, char **_hash)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *hash;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int hlen = (sizeof (sha512_salt_prefix) - 1
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin + sizeof (sha512_rounds_prefix) + 9 + 1
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin + strlen (salt) + 1 + 86 + 1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int ret;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hash = talloc_size(memctx, hlen);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!hash) return ENOMEM;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ret = sha512_crypt_r(key, salt, hash, hlen);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (ret) return ret;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *_hash = hash;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return ret;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define SALT_RAND_LEN 12
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint s3crypt_gen_salt(TALLOC_CTX *memctx, char **_salt)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint8_t rb[SALT_RAND_LEN];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *salt, *cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size_t slen;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int ret;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin salt = talloc_size(memctx, SALT_LEN_MAX + 1);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if (!salt) {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return ENOMEM;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ret = RAND_bytes(rb, SALT_RAND_LEN);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if (ret == 0) {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return EIO;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin slen = SALT_LEN_MAX;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cp = salt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin b64_from_24bit(&cp, &slen, 4, rb[0], rb[1], rb[2]);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin b64_from_24bit(&cp, &slen, 4, rb[3], rb[4], rb[5]);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin b64_from_24bit(&cp, &slen, 4, rb[6], rb[7], rb[8]);
b64_from_24bit(&cp, &slen, 4, rb[9], rb[10], rb[11]);
*cp = '\0';
*_salt = salt;
return EOK;
}