int s3crypt_gen_salt(TALLOC_CTX *memctx, char **_salt)
{
    uint8_t rb[SALT_RAND_LEN];
    char *salt, *cp;
    size_t slen;
    int ret;

    ret = nspr_nss_init();
    if (ret != EOK) {
        return EIO;
    }

    salt = talloc_size(memctx, SALT_LEN_MAX + 1);
    if (!salt) {
        return ENOMEM;
    }

    ret = PK11_GenerateRandom(rb, SALT_RAND_LEN);
    if (ret != SECSuccess) {
        return EIO;
    }

    slen = SALT_LEN_MAX;
    cp = salt;
    b64_from_24bit(&cp, &slen, 4, rb[0], rb[1], rb[2]);
    b64_from_24bit(&cp, &slen, 4, rb[3], rb[4], rb[5]);
    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;
}
Example #2
0
char *yahoo_crypt(const char *key, const char *salt)
{
    static char *buffer = NULL;
    static int buflen = 0;
    int needed = 3 + strlen (salt) + 1 + 26 + 1;

    size_t salt_len;
    size_t key_len;
    size_t cnt;
    char *cp;

    if (buflen < needed) {
        buflen = needed;
        if ((buffer = (char*)realloc(buffer, buflen)) == NULL)
            return NULL;
    }

    /* Find beginning of salt string.  The prefix should normally always
       be present.  Just in case it is not.  */
    if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
        /* Skip salt prefix.  */
        salt += sizeof (md5_salt_prefix) - 1;

    salt_len = MIN (strcspn (salt, "$"), 8);
    key_len = strlen (key);

	string ct = key;
	ct += md5_salt_prefix;
	ct += salt;

	string ct_alt = key;
	ct_alt += salt;
	ct_alt += key;
	ct_alt = md5(ct_alt.c_str());

    /* Add for any character in the key one byte of the alternate sum.  */
    for (cnt = key_len; cnt > 16; cnt -= 16)
		ct.append(ct_alt.c_str(), 16);
    ct.append(ct_alt.c_str(), cnt);

    char nil[] = "";

    /* The original implementation now does something weird: for every 1
       bit in the key the first 0 is added to the buffer, for every 0
       bit the first character of the key.  This does not seem to be
       what was intended but we have to follow this to be compatible.  */
    for (cnt = key_len; cnt > 0; cnt >>= 1)
        ct.append((cnt & 1) != 0 ? nil : key, 1);

    /* Create intermediate result.  */
    ct_alt = md5(ct.c_str(), ct.length());

    /* Now comes another weirdness.  In fear of password crackers here
       comes a quite long loop which just processes the output of the
       previous round again.  We cannot ignore this here.  */
    for (cnt = 0; cnt < 1000; ++cnt) {
        /* New context.  */
		ct = "";

        /* Add key or last result.  */
        if ((cnt & 1) != 0)
            ct += key;
        else
            ct.append(ct_alt.c_str(), 16);

        /* Add salt for numbers not divisible by 3.  */
        if (cnt % 3 != 0)
            ct += salt;

        /* Add key for numbers not divisible by 7.  */
        if (cnt % 7 != 0)
            ct += key;

        /* Add key or last result.  */
        if ((cnt & 1) != 0)
            ct.append(ct_alt.c_str(), 16);
        else
            ct += key;

        /* Create intermediate result.  */
        ct_alt = md5(ct.c_str(), ct.length());
    }

    /* Now we can construct the result string.  It consists of three
       parts.  */

    strncpy(buffer, md5_salt_prefix, MAX (0, buflen));
    cp = buffer + strlen(buffer);
    buflen -= sizeof (md5_salt_prefix);

    strncpy(cp, salt, MIN ((size_t) buflen, salt_len));
    cp = cp + strlen(cp);
    buflen -= MIN ((size_t) buflen, salt_len);

    if (buflen > 0) {
        *cp++ = '$';
        --buflen;
    }

#define b64_from_24bit(B2, B1, B0, N) \
	{ \
		unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \
		int n = (N); \
		while (n-- > 0 && buflen > 0) { \
			*cp++ = b64t[w & 0x3f]; \
			--buflen; \
			w >>= 6; \
		}\
	}

    b64_from_24bit (ct_alt[0], ct_alt[6], ct_alt[12], 4);
    b64_from_24bit (ct_alt[1], ct_alt[7], ct_alt[13], 4);
    b64_from_24bit (ct_alt[2], ct_alt[8], ct_alt[14], 4);
    b64_from_24bit (ct_alt[3], ct_alt[9], ct_alt[15], 4);
    b64_from_24bit (ct_alt[4], ct_alt[10], ct_alt[5], 4);
    b64_from_24bit (0, 0, ct_alt[11], 2);
    if (buflen <= 0) {
        free(buffer);
        buffer = NULL;
    } else
        *cp = '\0';	/* Terminate the string.  */

    return buffer;
}
Example #3
0
static char *
crypt_sha512_r(const char *key, const char *salt, char *buffer, int buflen)
{
	u_long srounds;
	int n;
	uint8_t alt_result[64], temp_result[64];
	SHA512_CTX ctx, alt_ctx;
	size_t salt_len, key_len, cnt, rounds;
	char *cp, *copied_key, *copied_salt, *p_bytes, *s_bytes, *endp;
	const char *num;
	bool rounds_custom;

	copied_key = NULL;
	copied_salt = NULL;

	/* Default number of rounds. */
	rounds = ROUNDS_DEFAULT;
	rounds_custom = false;

	/* Find beginning of salt string. The prefix should normally always
	 * be present. Just in case it is not. */
	if (strncmp(sha512_salt_prefix, salt, sizeof(sha512_salt_prefix) - 1) == 0)
		/* Skip salt prefix. */
		salt += sizeof(sha512_salt_prefix) - 1;

	if (strncmp(salt, sha512_rounds_prefix, sizeof(sha512_rounds_prefix) - 1)
	    == 0) {
		num = salt + sizeof(sha512_rounds_prefix) - 1;
		srounds = strtoul(num, &endp, 10);

		if (*endp == '$') {
			salt = endp + 1;
			rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX));
			rounds_custom = true;
		}
	}

	salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX);
	key_len = strlen(key);

	/* Prepare for the real work. */
	SHA512_Init(&ctx);

	/* Add the key string. */
	SHA512_Update(&ctx, key, key_len);

	/* The last part is the salt string. This must be at most 8
	 * characters and it ends at the first `$' character (for
	 * compatibility with existing implementations). */
	SHA512_Update(&ctx, salt, salt_len);

	/* Compute alternate SHA512 sum with input KEY, SALT, and KEY. The
	 * final result will be added to the first context. */
	SHA512_Init(&alt_ctx);

	/* Add key. */
	SHA512_Update(&alt_ctx, key, key_len);

	/* Add salt. */
	SHA512_Update(&alt_ctx, salt, salt_len);

	/* Add key again. */
	SHA512_Update(&alt_ctx, key, key_len);

	/* Now get result of this (64 bytes) and add it to the other context. */
	SHA512_Final(alt_result, &alt_ctx);

	/* Add for any character in the key one byte of the alternate sum. */
	for (cnt = key_len; cnt > 64; cnt -= 64)
		SHA512_Update(&ctx, alt_result, 64);
	SHA512_Update(&ctx, alt_result, cnt);

	/* Take the binary representation of the length of the key and for
	 * every 1 add the alternate sum, for every 0 the key. */
	for (cnt = key_len; cnt > 0; cnt >>= 1)
		if ((cnt & 1) != 0)
			SHA512_Update(&ctx, alt_result, 64);
		else
			SHA512_Update(&ctx, key, key_len);

	/* Create intermediate result. */
	SHA512_Final(alt_result, &ctx);

	/* Start computation of P byte sequence. */
	SHA512_Init(&alt_ctx);

	/* For every character in the password add the entire password. */
	for (cnt = 0; cnt < key_len; ++cnt)
		SHA512_Update(&alt_ctx, key, key_len);

	/* Finish the digest. */
	SHA512_Final(temp_result, &alt_ctx);

	/* Create byte sequence P. */
	cp = p_bytes = alloca(key_len);
	for (cnt = key_len; cnt >= 64; cnt -= 64) {
		memcpy(cp, temp_result, 64);
		cp += 64;
	}
	memcpy(cp, temp_result, cnt);

	/* Start computation of S byte sequence. */
	SHA512_Init(&alt_ctx);

	/* For every character in the password add the entire password. */
	for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
		SHA512_Update(&alt_ctx, salt, salt_len);

	/* Finish the digest. */
	SHA512_Final(temp_result, &alt_ctx);

	/* Create byte sequence S. */
	cp = s_bytes = alloca(salt_len);
	for (cnt = salt_len; cnt >= 64; cnt -= 64) {
		memcpy(cp, temp_result, 64);
		cp += 64;
	}
	memcpy(cp, temp_result, cnt);

	/* Repeatedly run the collected hash value through SHA512 to burn CPU
	 * cycles. */
	for (cnt = 0; cnt < rounds; ++cnt) {
		/* New context. */
		SHA512_Init(&ctx);

		/* Add key or last result. */
		if ((cnt & 1) != 0)
			SHA512_Update(&ctx, p_bytes, key_len);
		else
			SHA512_Update(&ctx, alt_result, 64);

		/* Add salt for numbers not divisible by 3. */
		if (cnt % 3 != 0)
			SHA512_Update(&ctx, s_bytes, salt_len);

		/* Add key for numbers not divisible by 7. */
		if (cnt % 7 != 0)
			SHA512_Update(&ctx, p_bytes, key_len);

		/* Add key or last result. */
		if ((cnt & 1) != 0)
			SHA512_Update(&ctx, alt_result, 64);
		else
			SHA512_Update(&ctx, p_bytes, key_len);

		/* Create intermediate result. */
		SHA512_Final(alt_result, &ctx);
	}

	/* Now we can construct the result string. It consists of three
	 * parts. */
	cp = stpncpy(buffer, sha512_salt_prefix, MAX(0, buflen));
	buflen -= sizeof(sha512_salt_prefix) - 1;

	if (rounds_custom) {
		n = snprintf(cp, MAX(0, buflen), "%s%zu$",
			 sha512_rounds_prefix, rounds);

		cp += n;
		buflen -= n;
	}

	cp = stpncpy(cp, salt, MIN((size_t)MAX(0, buflen), salt_len));
	buflen -= MIN((size_t)MAX(0, buflen), salt_len);

	if (buflen > 0) {
		*cp++ = '$';
		--buflen;
	}

	b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4, &buflen, &cp);
	b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4, &buflen, &cp);
	b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4, &buflen, &cp);
	b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4, &buflen, &cp);
	b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4, &buflen, &cp);
	b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4, &buflen, &cp);
	b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4, &buflen, &cp);
	b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4, &buflen, &cp);
	b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4, &buflen, &cp);
	b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4, &buflen, &cp);
	b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4, &buflen, &cp);
	b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4, &buflen, &cp);
	b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4, &buflen, &cp);
	b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4, &buflen, &cp);
	b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4, &buflen, &cp);
	b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4, &buflen, &cp);
	b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4, &buflen, &cp);
	b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4, &buflen, &cp);
	b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4, &buflen, &cp);
	b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4, &buflen, &cp);
	b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4, &buflen, &cp);
	b64_from_24bit(0, 0, alt_result[63], 2, &buflen, &cp);

	if (buflen <= 0) {
		errno = ERANGE;
		buffer = NULL;
	}
	else
		*cp = '\0';	/* Terminate the string. */

	/* Clear the buffer for the intermediate result so that people
	 * attaching to processes or reading core dumps cannot get any
	 * information. We do it in this way to clear correct_words[] inside
	 * the SHA512 implementation as well. */
	SHA512_Init(&ctx);
	SHA512_Final(alt_result, &ctx);
	memset(temp_result, '\0', sizeof(temp_result));
	memset(p_bytes, '\0', key_len);
	memset(s_bytes, '\0', salt_len);
	memset(&ctx, '\0', sizeof(ctx));
	memset(&alt_ctx, '\0', sizeof(alt_ctx));
	if (copied_key != NULL)
		memset(copied_key, '\0', key_len);
	if (copied_salt != NULL)
		memset(copied_salt, '\0', salt_len);

	return buffer;
}
static int sha512_crypt_r(const char *key,
                          const char *salt,
                          char *buffer, size_t buflen)
{
    unsigned char temp_result[64] __attribute__((__aligned__(ALIGN64)));
    unsigned char alt_result[64] __attribute__((__aligned__(ALIGN64)));
    size_t rounds = ROUNDS_DEFAULT;
    bool rounds_custom = false;
    HASHContext *alt_ctx = NULL;
    HASHContext *ctx = NULL;
    size_t salt_len;
    size_t key_len;
    size_t cnt;
    char *copied_salt = NULL;
    char *copied_key = NULL;
    char *p_bytes = NULL;
    char *s_bytes = NULL;
    int p1, p2, p3, pt, n;
    unsigned int part;
    char *cp, *tmp;
    int ret;

    /* Find beginning of salt string. The prefix should normally always be
     * present. Just in case it is not. */
    if (strncmp(salt, sha512_salt_prefix, SALT_PREF_SIZE) == 0) {
        /* Skip salt prefix.  */
        salt += SALT_PREF_SIZE;
    }

    if (strncmp(salt, sha512_rounds_prefix, ROUNDS_SIZE) == 0) {
        unsigned long int srounds;
        const char *num;
        char *endp;

        num = salt + ROUNDS_SIZE;
        srounds = strtoul(num, &endp, 10);
        if (*endp == '$') {
            salt = endp + 1;
            if (srounds < ROUNDS_MIN) srounds = ROUNDS_MIN;
            if (srounds > ROUNDS_MAX) srounds = ROUNDS_MAX;
            rounds = srounds;
            rounds_custom = true;
        }
    }

    salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX);
    key_len = strlen(key);

    if ((PTR_2_INT(key) % ALIGN64) != 0) {
        tmp = (char *)alloca(key_len + ALIGN64);
        key = copied_key = memcpy(tmp + ALIGN64 - PTR_2_INT(tmp) % ALIGN64, key, key_len);
    }

    if (PTR_2_INT(salt) % ALIGN64 != 0) {
        tmp = (char *)alloca(salt_len + ALIGN64);
        salt = copied_salt = memcpy(tmp + ALIGN64 - PTR_2_INT(tmp) % ALIGN64, salt, salt_len);
    }

    ret = nspr_nss_init();
    if (ret != EOK) {
        ret = EIO;
        goto done;
    }

    ctx = HASH_Create(HASH_AlgSHA512);
    if (!ctx) {
        ret = EIO;
        goto done;
    }

    alt_ctx = HASH_Create(HASH_AlgSHA512);
    if (!alt_ctx) {
        ret = EIO;
        goto done;
    }

    /* Prepare for the real work.  */
    HASH_Begin(ctx);

    /* Add the key string.  */
    HASH_Update(ctx, (const unsigned char *)key, key_len);

    /* The last part is the salt string. This must be at most 16
     * characters and it ends at the first `$' character (for
     * compatibility with existing implementations). */
    HASH_Update(ctx, (const unsigned char *)salt, salt_len);


    /* Compute alternate SHA512 sum with input KEY, SALT, and KEY.
     * The final result will be added to the first context. */
    HASH_Begin(alt_ctx);

    /* Add key. */
    HASH_Update(alt_ctx, (const unsigned char *)key, key_len);

    /* Add salt. */
    HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len);

    /* Add key again. */
    HASH_Update(alt_ctx, (const unsigned char *)key, key_len);

    /* Now get result of this (64 bytes) and add it to the other context. */
    HASH_End(alt_ctx, alt_result, &part, HASH_ResultLenContext(alt_ctx));

    /* Add for any character in the key one byte of the alternate sum. */
    for (cnt = key_len; cnt > 64; cnt -= 64) {
        HASH_Update(ctx, alt_result, 64);
    }
    HASH_Update(ctx, alt_result, cnt);

    /* Take the binary representation of the length of the key and for every
     * 1 add the alternate sum, for every 0 the key. */
    for (cnt = key_len; cnt > 0; cnt >>= 1) {
        if ((cnt & 1) != 0) {
            HASH_Update(ctx, alt_result, 64);
        } else {
            HASH_Update(ctx, (const unsigned char *)key, key_len);
        }
    }

    /* Create intermediate result. */
    HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx));

    /* Start computation of P byte sequence. */
    HASH_Begin(alt_ctx);

    /* For every character in the password add the entire password. */
    for (cnt = 0; cnt < key_len; cnt++) {
        HASH_Update(alt_ctx, (const unsigned char *)key, key_len);
    }

    /* Finish the digest. */
    HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx));

    /* Create byte sequence P. */
    cp = p_bytes = alloca(key_len);
    for (cnt = key_len; cnt >= 64; cnt -= 64) {
        cp = mempcpy(cp, temp_result, 64);
    }
    memcpy(cp, temp_result, cnt);

    /* Start computation of S byte sequence. */
    HASH_Begin(alt_ctx);

    /* For every character in the password add the entire salt. */
    for (cnt = 0; cnt < 16 + alt_result[0]; cnt++) {
        HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len);
    }

    /* Finish the digest. */
    HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx));

    /* Create byte sequence S.  */
    cp = s_bytes = alloca(salt_len);
    for (cnt = salt_len; cnt >= 64; cnt -= 64) {
        cp = mempcpy(cp, temp_result, 64);
    }
    memcpy(cp, temp_result, cnt);

    /* Repeatedly run the collected hash value through SHA512 to burn CPU cycles. */
    for (cnt = 0; cnt < rounds; cnt++) {

        HASH_Begin(ctx);

        /* Add key or last result. */
        if ((cnt & 1) != 0) {
            HASH_Update(ctx, (const unsigned char *)p_bytes, key_len);
        } else {
            HASH_Update(ctx, alt_result, 64);
        }

        /* Add salt for numbers not divisible by 3. */
        if (cnt % 3 != 0) {
            HASH_Update(ctx, (const unsigned char *)s_bytes, salt_len);
        }

        /* Add key for numbers not divisible by 7. */
        if (cnt % 7 != 0) {
            HASH_Update(ctx, (const unsigned char *)p_bytes, key_len);
        }

        /* Add key or last result. */
        if ((cnt & 1) != 0) {
            HASH_Update(ctx, alt_result, 64);
        } else {
            HASH_Update(ctx, (const unsigned char *)p_bytes, key_len);
        }

        /* Create intermediate result. */
        HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx));
    }

    /* Now we can construct the result string.
     * It consists of three parts. */
    if (buflen <= SALT_PREF_SIZE) {
        ret = ERANGE;
        goto done;
    }

    cp = __stpncpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
    buflen -= SALT_PREF_SIZE;

    if (rounds_custom) {
        n = snprintf(cp, buflen, "%s%zu$",
                     sha512_rounds_prefix, rounds);
        if (n < 0 || n >= buflen) {
            ret = ERANGE;
            goto done;
        }
        cp += n;
        buflen -= n;
    }

    if (buflen <= salt_len + 1) {
        ret = ERANGE;
        goto done;
    }
    cp = __stpncpy(cp, salt, salt_len);
    *cp++ = '$';
    buflen -= salt_len + 1;

    /* fuzzyfill the base 64 string */
    p1 = 0;
    p2 = 21;
    p3 = 42;
    for (n = 0; n < 21; n++) {
        b64_from_24bit(&cp, &buflen, 4, alt_result[p1], alt_result[p2], alt_result[p3]);
        if (buflen == 0) {
            ret = ERANGE;
            goto done;
        }
        pt = p1;
        p1 = p2 + 1;
        p2 = p3 + 1;
        p3 = pt + 1;
    }
    /* 64th and last byte */
    b64_from_24bit(&cp, &buflen, 2, 0, 0, alt_result[p3]);
    if (buflen == 0) {
        ret = ERANGE;
        goto done;
    }

    *cp = '\0';
    ret = EOK;

done:
    /* Clear the buffer for the intermediate result so that people attaching
     * to processes or reading core dumps cannot get any information. We do it
     * in this way to clear correct_words[] inside the SHA512 implementation
     * as well.  */
    if (ctx) HASH_Destroy(ctx);
    if (alt_ctx) HASH_Destroy(alt_ctx);
    if (p_bytes) memset(p_bytes, '\0', key_len);
    if (s_bytes) memset(s_bytes, '\0', salt_len);
    if (copied_key) memset(copied_key, '\0', key_len);
    if (copied_salt) memset(copied_salt, '\0', salt_len);
    memset(temp_result, '\0', sizeof(temp_result));

    return ret;
}
Example #5
0
char *yahoo_crypt(const char *key, const char *salt)
{
	PurpleCipher *cipher;
	PurpleCipherContext *context1, *context2;
	guchar digest[16];
	static char *buffer = NULL;
	static int buflen = 0;
	int needed = 3 + strlen (salt) + 1 + 26 + 1;

	size_t salt_len;
	size_t key_len;
	size_t cnt;

	char *cp;

	if (buflen < needed) {
		buflen = needed;
		if ((buffer = g_realloc(buffer, buflen)) == NULL)
			return NULL;
	}

	cipher = purple_ciphers_find_cipher("md5");
	context1 = purple_cipher_context_new(cipher, NULL);
	context2 = purple_cipher_context_new(cipher, NULL);

	/* Find beginning of salt string.  The prefix should normally always
	 * be present.  Just in case it is not.
	 */
	if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
		/* Skip salt prefix.  */
		salt += sizeof (md5_salt_prefix) - 1;

	salt_len = MIN (strcspn (salt, "$"), 8);
	key_len = strlen (key);

	/* Add the key string.  */
	purple_cipher_context_append(context1, (const guchar *)key, key_len);

	/* Because the SALT argument need not always have the salt prefix we
	 * add it separately.
	 */
	purple_cipher_context_append(context1, (const guchar *)md5_salt_prefix,
							   sizeof(md5_salt_prefix) - 1);

	/* The last part is the salt string.  This must be at most 8
	 * characters and it ends at the first `$' character (for
	 * compatibility which existing solutions).
	 */
	purple_cipher_context_append(context1, (const guchar *)salt, salt_len);

	/* Compute alternate MD5 sum with input KEY, SALT, and KEY.  The
	 * final result will be added to the first context.
	 */

	/* Add key.  */
	purple_cipher_context_append(context2, (const guchar *)key, key_len);

	/* Add salt.  */
	purple_cipher_context_append(context2, (const guchar *)salt, salt_len);

	/* Add key again.  */
	purple_cipher_context_append(context2, (const guchar *)key, key_len);

	/* Now get result of this (16 bytes) and add it to the other context.  */
	purple_cipher_context_digest(context2, sizeof(digest), digest, NULL);

	/* Add for any character in the key one byte of the alternate sum.  */
	for (cnt = key_len; cnt > 16; cnt -= 16)
		purple_cipher_context_append(context1, digest, 16);
	purple_cipher_context_append(context1, digest, cnt);

	/* For the following code we need a NUL byte.  */
	digest[0] = '\0';

	/* The original implementation now does something weird: for every 1
	 * bit in the key the first 0 is added to the buffer, for every 0
	 * bit the first character of the key.  This does not seem to be
	 * what was intended but we have to follow this to be compatible.
	 */
	for (cnt = key_len; cnt > 0; cnt >>= 1)
		purple_cipher_context_append(context1,
								   (cnt & 1) != 0 ? digest : (guchar *)key, 1);

	/* Create intermediate result.  */
	purple_cipher_context_digest(context1, sizeof(digest), digest, NULL);

	/* Now comes another weirdness.  In fear of password crackers here
	 * comes a quite long loop which just processes the output of the
	 * previous round again.  We cannot ignore this here.
	 */
	for (cnt = 0; cnt < 1000; ++cnt) {
		/* New context.  */
		purple_cipher_context_reset(context2, NULL);

		/* Add key or last result.  */
		if ((cnt & 1) != 0)
			purple_cipher_context_append(context2, (const guchar *)key, key_len);
		else
			purple_cipher_context_append(context2, digest, 16);

		/* Add salt for numbers not divisible by 3.  */
		if (cnt % 3 != 0)
			purple_cipher_context_append(context2, (const guchar *)salt, salt_len);

		/* Add key for numbers not divisible by 7.  */
		if (cnt % 7 != 0)
			purple_cipher_context_append(context2, (const guchar *)key, key_len);

		/* Add key or last result.  */
		if ((cnt & 1) != 0)
			purple_cipher_context_append(context2, digest, 16);
		else
			purple_cipher_context_append(context2, (const guchar *)key, key_len);

		/* Create intermediate result.  */
		purple_cipher_context_digest(context2, sizeof(digest), digest, NULL);
	}

	/* Now we can construct the result string.  It consists of three parts. */
	strncpy(buffer, md5_salt_prefix, MAX (0, buflen));
	cp = buffer + strlen(buffer);
	buflen -= sizeof (md5_salt_prefix);

	strncpy(cp, salt, MIN ((size_t) buflen, salt_len));
	cp = cp + strlen(cp);
	buflen -= MIN ((size_t) buflen, salt_len);

	if (buflen > 0) {
		*cp++ = '$';
		--buflen;
	}

#define b64_from_24bit(B2, B1, B0, N) \
	do { \
		unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \
		int n = (N); \
		while (n-- > 0 && buflen > 0) { \
			*cp++ = b64t[w & 0x3f]; \
			--buflen; \
			w >>= 6; \
		}\
	} while (0)

	b64_from_24bit (digest[0], digest[6], digest[12], 4);
	b64_from_24bit (digest[1], digest[7], digest[13], 4);
	b64_from_24bit (digest[2], digest[8], digest[14], 4);
	b64_from_24bit (digest[3], digest[9], digest[15], 4);
	b64_from_24bit (digest[4], digest[10], digest[5], 4);
	b64_from_24bit (0, 0, digest[11], 2);
	if (buflen <= 0) {
		g_free(buffer);
		buffer = NULL;
	} else
		*cp = '\0';	/* Terminate the string.  */

	/* Clear the buffer for the intermediate result so that people
	 * attaching to processes or reading core dumps cannot get any
	 * information.  We do it in this way to clear correct_words[]
	 * inside the MD5 implementation as well.
	 */
	purple_cipher_context_reset(context1, NULL);
	purple_cipher_context_digest(context1, sizeof(digest), digest, NULL);
	purple_cipher_context_destroy(context1);
	purple_cipher_context_destroy(context2);

	return buffer;
}
Example #6
0
NOINLINE
sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data)
{
	void (*sha_begin)(void *ctx) FAST_FUNC;
	void (*sha_hash)(void *ctx, const void *buffer, size_t len) FAST_FUNC;
	void (*sha_end)(void *ctx, void *resbuf) FAST_FUNC;
	int _32or64;

	char *result, *resptr;

	/* btw, sha256 needs [32] and uint32_t only */
	struct {
		unsigned char alt_result[64];
		unsigned char temp_result[64];
		union {
			sha256_ctx_t x;
			sha512_ctx_t y;
		} ctx;
		union {
			sha256_ctx_t x;
			sha512_ctx_t y;
		} alt_ctx;
	} L __attribute__((__aligned__(__alignof__(uint64_t))));
#define alt_result  (L.alt_result )
#define temp_result (L.temp_result)
#define ctx         (L.ctx        )
#define alt_ctx     (L.alt_ctx    )
	unsigned salt_len;
	unsigned key_len;
	unsigned cnt;
	unsigned rounds;
	char *cp;
	char is_sha512;

	/* Analyze salt, construct already known part of result */
	cnt = strlen(salt_data) + 1 + 43 + 1;
	is_sha512 = salt_data[1];
	if (is_sha512 == '6')
		cnt += 43;
	result = resptr = xzalloc(cnt); /* will provide NUL terminator */
	*resptr++ = '$';
	*resptr++ = is_sha512;
	*resptr++ = '$';
	rounds = ROUNDS_DEFAULT;
	salt_data += 3;
	if (strncmp(salt_data, str_rounds, 7) == 0) {
		/* 7 == strlen("rounds=") */
		char *endp;
		cnt = bb_strtou(salt_data + 7, &endp, 10);
		if (*endp == '$') {
			salt_data = endp + 1;
			rounds = cnt;
			if (rounds < ROUNDS_MIN)
				rounds = ROUNDS_MIN;
			if (rounds > ROUNDS_MAX)
				rounds = ROUNDS_MAX;
			/* add "rounds=NNNNN$" to result */
			resptr += sprintf(resptr, str_rounds, rounds);
		}
	}
	salt_len = strchrnul(salt_data, '$') - salt_data;
	if (salt_len > SALT_LEN_MAX)
		salt_len = SALT_LEN_MAX;
	/* xstrdup assures suitable alignment; also we will use it
	   as a scratch space later. */
	salt_data = xstrndup(salt_data, salt_len);
	/* add "salt$" to result */
	strcpy(resptr, salt_data);
	resptr += salt_len;
	*resptr++ = '$';
	/* key data doesn't need much processing */
	key_len = strlen(key_data);
	key_data = xstrdup(key_data);

	/* Which flavor of SHAnnn ops to use? */
	sha_begin = (void*)sha256_begin;
	sha_hash = (void*)sha256_hash;
	sha_end = (void*)sha256_end;
	_32or64 = 32;
	if (is_sha512 == '6') {
		sha_begin = (void*)sha512_begin;
		sha_hash = (void*)sha512_hash;
		sha_end = (void*)sha512_end;
		_32or64 = 64;
	}

	/* Add KEY, SALT.  */
	sha_begin(&ctx);
	sha_hash(&ctx, key_data, key_len);
	sha_hash(&ctx, salt_data, salt_len);

	/* Compute alternate SHA sum with input KEY, SALT, and KEY.
	   The final result will be added to the first context.  */
	sha_begin(&alt_ctx);
	sha_hash(&alt_ctx, key_data, key_len);
	sha_hash(&alt_ctx, salt_data, salt_len);
	sha_hash(&alt_ctx, key_data, key_len);
	sha_end(&alt_ctx, alt_result);

	/* Add result of this to the other context.  */
	/* Add for any character in the key one byte of the alternate sum.  */
	for (cnt = key_len; cnt > _32or64; cnt -= _32or64)
		sha_hash(&ctx, alt_result, _32or64);
	sha_hash(&ctx, alt_result, cnt);

	/* Take the binary representation of the length of the key and for every
	   1 add the alternate sum, for every 0 the key.  */
	for (cnt = key_len; cnt != 0; cnt >>= 1)
		if ((cnt & 1) != 0)
			sha_hash(&ctx, alt_result, _32or64);
		else
			sha_hash(&ctx, key_data, key_len);

	/* Create intermediate result.  */
	sha_end(&ctx, alt_result);

	/* Start computation of P byte sequence.  */
	/* For every character in the password add the entire password.  */
	sha_begin(&alt_ctx);
	for (cnt = 0; cnt < key_len; ++cnt)
		sha_hash(&alt_ctx, key_data, key_len);
	sha_end(&alt_ctx, temp_result);

	/* NB: past this point, raw key_data is not used anymore */

	/* Create byte sequence P.  */
#define p_bytes key_data /* reuse the buffer as it is of the key_len size */
	cp = p_bytes; /* was: ... = alloca(key_len); */
	for (cnt = key_len; cnt >= _32or64; cnt -= _32or64) {
		cp = memcpy(cp, temp_result, _32or64);
		cp += _32or64;
	}
	memcpy(cp, temp_result, cnt);

	/* Start computation of S byte sequence.  */
	/* For every character in the password add the entire password.  */
	sha_begin(&alt_ctx);
	for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
		sha_hash(&alt_ctx, salt_data, salt_len);
	sha_end(&alt_ctx, temp_result);

	/* NB: past this point, raw salt_data is not used anymore */

	/* Create byte sequence S.  */
#define s_bytes salt_data /* reuse the buffer as it is of the salt_len size */
	cp = s_bytes; /* was: ... = alloca(salt_len); */
	for (cnt = salt_len; cnt >= _32or64; cnt -= _32or64) {
		cp = memcpy(cp, temp_result, _32or64);
		cp += _32or64;
	}
	memcpy(cp, temp_result, cnt);

	/* Repeatedly run the collected hash value through SHA to burn
	   CPU cycles.  */
	for (cnt = 0; cnt < rounds; ++cnt) {
		sha_begin(&ctx);

		/* Add key or last result.  */
		if ((cnt & 1) != 0)
			sha_hash(&ctx, p_bytes, key_len);
		else
			sha_hash(&ctx, alt_result, _32or64);
		/* Add salt for numbers not divisible by 3.  */
		if (cnt % 3 != 0)
			sha_hash(&ctx, s_bytes, salt_len);
		/* Add key for numbers not divisible by 7.  */
		if (cnt % 7 != 0)
			sha_hash(&ctx, p_bytes, key_len);
		/* Add key or last result.  */
		if ((cnt & 1) != 0)
			sha_hash(&ctx, alt_result, _32or64);
		else
			sha_hash(&ctx, p_bytes, key_len);

		sha_end(&ctx, alt_result);
	}

	/* Append encrypted password to result buffer */
//TODO: replace with something like
//	bb_uuencode(cp, src, length, bb_uuenc_tbl_XXXbase64);
#define b64_from_24bit(B2, B1, B0, N) \
do { \
	unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \
	resptr = to64(resptr, w, N); \
} while (0)
	if (is_sha512 == '5') {
		unsigned i = 0;
		while (1) {
			unsigned j = i + 10;
			unsigned k = i + 20;
			if (j >= 30) j -= 30;
			if (k >= 30) k -= 30;
			b64_from_24bit(alt_result[i], alt_result[j], alt_result[k], 4);
			if (k == 29)
				break;
			i = k + 1;
		}
		b64_from_24bit(0, alt_result[31], alt_result[30], 3);
		/* was:
		b64_from_24bit(alt_result[0], alt_result[10], alt_result[20], 4);
		b64_from_24bit(alt_result[21], alt_result[1], alt_result[11], 4);
		b64_from_24bit(alt_result[12], alt_result[22], alt_result[2], 4);
		b64_from_24bit(alt_result[3], alt_result[13], alt_result[23], 4);
		b64_from_24bit(alt_result[24], alt_result[4], alt_result[14], 4);
		b64_from_24bit(alt_result[15], alt_result[25], alt_result[5], 4);
		b64_from_24bit(alt_result[6], alt_result[16], alt_result[26], 4);
		b64_from_24bit(alt_result[27], alt_result[7], alt_result[17], 4);
		b64_from_24bit(alt_result[18], alt_result[28], alt_result[8], 4);
		b64_from_24bit(alt_result[9], alt_result[19], alt_result[29], 4);
		b64_from_24bit(0, alt_result[31], alt_result[30], 3);
		*/
	} else {
		unsigned i = 0;
		while (1) {
			unsigned j = i + 21;
			unsigned k = i + 42;
			if (j >= 63) j -= 63;
			if (k >= 63) k -= 63;
			b64_from_24bit(alt_result[i], alt_result[j], alt_result[k], 4);
			if (j == 20)
				break;
			i = j + 1;
		}
		b64_from_24bit(0, 0, alt_result[63], 2);
		/* was:
		b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4);
		b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4);
		b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4);
		b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4);
		b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4);
		b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4);
		b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4);
		b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4);
		b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4);
		b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4);
		b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4);
		b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4);
		b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4);
		b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4);
		b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4);
		b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4);
		b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4);
		b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4);
		b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4);
		b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4);
		b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4);
		b64_from_24bit(0, 0, alt_result[63], 2);
		*/
	}
	/* *resptr = '\0'; - xzalloc did it */
#undef b64_from_24bit

	/* Clear the buffer for the intermediate result so that people
	   attaching to processes or reading core dumps cannot get any
	   information.  */
	memset(&L, 0, sizeof(L)); /* [alt]_ctx and XXX_result buffers */
	memset(key_data, 0, key_len); /* also p_bytes */
	memset(salt_data, 0, salt_len); /* also s_bytes */
	free(key_data);
	free(salt_data);
#undef p_bytes
#undef s_bytes

	return result;
#undef alt_result
#undef temp_result
#undef ctx
#undef alt_ctx
}
Example #7
0
char* crypt_sha512_r(const char *key, const char *salt, size_t rounds,
                     char *buffer, int buflen)
{
    uint8_t alt_result[64], temp_result[64];
    sha4_context ctx, alt_ctx;
    size_t salt_len, key_len, cnt;
    char *cp, *copied_key, *copied_salt, *p_bytes, *s_bytes;

    copied_key = NULL;
    copied_salt = NULL;

    salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX);
    key_len = strlen(key);

    /* Prepare for the real work. */
    sha4_starts(&ctx, 0);

    /* Add the key string. */
    sha4_update(&ctx, (unsigned char*)key, key_len);

    /* The last part is the salt string. This must be at most 8
     * characters and it ends at the first `$' character (for
     * compatibility with existing implementations). */
    sha4_update(&ctx, (unsigned char*)salt, salt_len);

    /* Compute alternate SHA512 sum with input KEY, SALT, and KEY. The
     * final result will be added to the first context. */
    sha4_starts(&alt_ctx, 0);

    /* Add key. */
    sha4_update(&alt_ctx, (unsigned char*)key, key_len);

    /* Add salt. */
    sha4_update(&alt_ctx, (unsigned char*)salt, salt_len);

    /* Add key again. */
    sha4_update(&alt_ctx, (unsigned char*)key, key_len);

    /* Now get result of this (64 bytes) and add it to the other context. */
    sha4_finish(&alt_ctx, alt_result);

    /* Add for any character in the key one byte of the alternate sum. */
    for (cnt = key_len; cnt > 64; cnt -= 64)
        sha4_update(&ctx, (unsigned char*)alt_result, 64);
    sha4_update(&ctx, (unsigned char*)alt_result, cnt);

    /* Take the binary representation of the length of the key and for
     * every 1 add the alternate sum, for every 0 the key. */
    for (cnt = key_len; cnt > 0; cnt >>= 1)
        if ((cnt & 1) != 0)
            sha4_update(&ctx, (unsigned char*)alt_result, 64);
        else
            sha4_update(&ctx, (unsigned char*)key, key_len);

    /* Create intermediate result. */
    sha4_finish(&ctx, alt_result);

    /* Start computation of P byte sequence. */
    sha4_starts(&alt_ctx, 0);

    /* For every character in the password add the entire password. */
    for (cnt = 0; cnt < key_len; ++cnt)
        sha4_update(&alt_ctx, (unsigned char*)key, key_len);

    /* Finish the digest. */
    sha4_finish(&alt_ctx, temp_result);

    /* Create byte sequence P. */
    cp = p_bytes = alloca(key_len);
    for (cnt = key_len; cnt >= 64; cnt -= 64)
    {
        memcpy(cp, temp_result, 64);
        cp += 64;
    }
    memcpy(cp, temp_result, cnt);

    /* Start computation of S byte sequence. */
    sha4_starts(&alt_ctx, 0);

    /* For every character in the password add the entire password. */
    for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
        sha4_update(&alt_ctx, (unsigned char*)salt, salt_len);

    /* Finish the digest. */
    sha4_finish(&alt_ctx, temp_result);

    /* Create byte sequence S. */
    cp = s_bytes = alloca(salt_len);
    for (cnt = salt_len; cnt >= 64; cnt -= 64)
    {
        memcpy(cp, temp_result, 64);
        cp += 64;
    }
    memcpy(cp, temp_result, cnt);

    /* Repeatedly run the collected hash value through SHA512 to burn CPU
     * cycles. */
    for (cnt = 0; cnt < rounds; ++cnt)
    {
        /* New context. */
        sha4_starts(&ctx, 0);

        /* Add key or last result. */
        if ((cnt & 1) != 0)
            sha4_update(&ctx, (unsigned char*)p_bytes, key_len);
        else
            sha4_update(&ctx, (unsigned char*)alt_result, 64);

        /* Add salt for numbers not divisible by 3. */
        if (cnt % 3 != 0)
            sha4_update(&ctx, (unsigned char*)s_bytes, salt_len);

        /* Add key for numbers not divisible by 7. */
        if (cnt % 7 != 0)
            sha4_update(&ctx, (unsigned char*)p_bytes, key_len);

        /* Add key or last result. */
        if ((cnt & 1) != 0)
            sha4_update(&ctx, (unsigned char*)alt_result, 64);
        else
            sha4_update(&ctx, (unsigned char*)p_bytes, key_len);

        /* Create intermediate result. */
        sha4_finish(&ctx, alt_result);
    }

    cp = buffer;
    b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4,
                   &buflen, &cp);
    b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4,
                   &buflen, &cp);
    b64_from_24bit(0, 0, alt_result[63], 2, &buflen, &cp);

    if (buflen <= 0)
    {
        errno = ERANGE;
        buffer = NULL;
    }
    else
        *cp = '\0';

    return buffer;
}