talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

pkcs5_pbkdf2.c (3800B)


      1 /* pkcs5_pbkdf2.c - Password-Based Key Derivation Function 2
      2  * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
      3  *
      4  * Modifications for Claws Mail are:
      5  * Copyright (c) 2016 the Claws Mail team
      6  *
      7  * Permission to use, copy, modify, and distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18  */
     19 
     20 #include <glib.h>
     21 #include <sys/types.h>
     22 
     23 #include <string.h>
     24 #include <stdint.h>
     25 #include <stdlib.h>
     26 #include <stdio.h>
     27 
     28 #define CHECKSUM_BLOCKLEN 64
     29 #define SHA1_DIGESTLEN 20
     30 
     31 /*
     32  * HMAC-SHA-1 (from RFC 2202).
     33  */
     34 static void
     35 hmac_sha1(const guchar *text, size_t text_len, const guchar *key,
     36     size_t key_len, guchar *digest)
     37 {
     38 	GChecksum *cksum;
     39 	gsize outlen;
     40 	guchar k_pad[CHECKSUM_BLOCKLEN];
     41 	guchar tk[SHA1_DIGESTLEN];
     42 	gint i;
     43 
     44 	if (key_len > CHECKSUM_BLOCKLEN) {
     45 		cksum = g_checksum_new(G_CHECKSUM_SHA1);
     46 		g_checksum_update(cksum, key, key_len);
     47 		outlen = SHA1_DIGESTLEN;
     48 		g_checksum_get_digest(cksum, tk, &outlen);
     49 		g_checksum_free(cksum);
     50 
     51 		key = tk;
     52 		key_len = SHA1_DIGESTLEN;
     53 	}
     54 
     55 	memset(k_pad, 0, sizeof k_pad);
     56 	memcpy(k_pad, key, key_len);
     57 	for (i = 0; i < CHECKSUM_BLOCKLEN; i++)
     58 		k_pad[i] ^= 0x36;
     59 
     60 	cksum = g_checksum_new(G_CHECKSUM_SHA1);
     61 	g_checksum_update(cksum, k_pad, CHECKSUM_BLOCKLEN);
     62 	g_checksum_update(cksum, text, text_len);
     63 	outlen = SHA1_DIGESTLEN;
     64 	g_checksum_get_digest(cksum, digest, &outlen);
     65 	g_checksum_free(cksum);
     66 
     67 	memset(k_pad, 0, sizeof k_pad);
     68 	memcpy(k_pad, key, key_len);
     69 	for (i = 0; i < CHECKSUM_BLOCKLEN; i++)
     70 		k_pad[i] ^= 0x5c;
     71 
     72 	cksum = g_checksum_new(G_CHECKSUM_SHA1);
     73 	g_checksum_update(cksum, k_pad, CHECKSUM_BLOCKLEN);
     74 	g_checksum_update(cksum, digest, SHA1_DIGESTLEN);
     75 	outlen = SHA1_DIGESTLEN;
     76 	g_checksum_get_digest(cksum, digest, &outlen);
     77 	g_checksum_free(cksum);
     78 }
     79 
     80 #undef CHECKSUM_BLOCKLEN
     81 
     82 /*
     83  * Password-Based Key Derivation Function 2 (PKCS #5 v2.0).
     84  * Code based on IEEE Std 802.11-2007, Annex H.4.2.
     85  */
     86 gint
     87 pkcs5_pbkdf2(const gchar *pass, size_t pass_len, const guchar *salt,
     88     size_t salt_len, guchar *key, size_t key_len, guint rounds)
     89 {
     90 	guchar *asalt, obuf[SHA1_DIGESTLEN];
     91 	guchar d1[SHA1_DIGESTLEN], d2[SHA1_DIGESTLEN];
     92 	guint i, j;
     93 	guint count;
     94 	size_t r;
     95 
     96 	if (pass == NULL || salt == NULL || key == NULL)
     97 		return -1;
     98 	if (rounds < 1 || key_len == 0)
     99 		return -1;
    100 	if (salt_len == 0 || salt_len > SIZE_MAX - 4)
    101 		return -1;
    102 	if ((asalt = malloc(salt_len + 4)) == NULL)
    103 		return -1;
    104 
    105 	memcpy(asalt, salt, salt_len);
    106 
    107 	for (count = 1; key_len > 0; count++) {
    108 		asalt[salt_len + 0] = (count >> 24) & 0xff;
    109 		asalt[salt_len + 1] = (count >> 16) & 0xff;
    110 		asalt[salt_len + 2] = (count >> 8) & 0xff;
    111 		asalt[salt_len + 3] = count & 0xff;
    112 		hmac_sha1(asalt, salt_len + 4, pass, pass_len, d1);
    113 		memcpy(obuf, d1, sizeof(obuf));
    114 
    115 		for (i = 1; i < rounds; i++) {
    116 			hmac_sha1(d1, sizeof(d1), pass, pass_len, d2);
    117 			memcpy(d1, d2, sizeof(d1));
    118 			for (j = 0; j < sizeof(obuf); j++)
    119 				obuf[j] ^= d1[j];
    120 		}
    121 
    122 		r = MIN(key_len, SHA1_DIGESTLEN);
    123 		memcpy(key, obuf, r);
    124 		key += r;
    125 		key_len -= r;
    126 	};
    127 	memset(asalt, 0, salt_len + 4);
    128 	free(asalt);
    129 	memset(d1, 0, sizeof(d1));
    130 	memset(d2, 0, sizeof(d2));
    131 	memset(obuf, 0, sizeof(obuf));
    132 
    133 	return 0;
    134 }
    135 
    136 #undef SHA1_DIGESTLEN