1 /* pkcs5_pbkdf2.c - Password-Based Key Derivation Function 2
2 * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
4 * Modifications for Claws Mail are:
5 * Copyright (c) 2016 the Claws Mail team
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.
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.
23 #include <sys/types.h>
30 #define CHECKSUM_BLOCKLEN 64
31 #define SHA1_DIGESTLEN 20
34 * HMAC-SHA-1 (from RFC 2202).
37 hmac_sha1(const guchar
*text
, size_t text_len
, const guchar
*key
,
38 size_t key_len
, guchar
*digest
)
42 guchar k_pad
[CHECKSUM_BLOCKLEN
];
43 guchar tk
[SHA1_DIGESTLEN
];
46 if (key_len
> CHECKSUM_BLOCKLEN
) {
47 cksum
= g_checksum_new(G_CHECKSUM_SHA1
);
48 g_checksum_update(cksum
, key
, key_len
);
49 outlen
= SHA1_DIGESTLEN
;
50 g_checksum_get_digest(cksum
, tk
, &outlen
);
51 g_checksum_free(cksum
);
54 key_len
= SHA1_DIGESTLEN
;
57 memset(k_pad
, 0, sizeof k_pad
);
58 memcpy(k_pad
, key
, key_len
);
59 for (i
= 0; i
< CHECKSUM_BLOCKLEN
; i
++)
62 cksum
= g_checksum_new(G_CHECKSUM_SHA1
);
63 g_checksum_update(cksum
, k_pad
, CHECKSUM_BLOCKLEN
);
64 g_checksum_update(cksum
, text
, text_len
);
65 outlen
= SHA1_DIGESTLEN
;
66 g_checksum_get_digest(cksum
, digest
, &outlen
);
67 g_checksum_free(cksum
);
69 memset(k_pad
, 0, sizeof k_pad
);
70 memcpy(k_pad
, key
, key_len
);
71 for (i
= 0; i
< CHECKSUM_BLOCKLEN
; i
++)
74 cksum
= g_checksum_new(G_CHECKSUM_SHA1
);
75 g_checksum_update(cksum
, k_pad
, CHECKSUM_BLOCKLEN
);
76 g_checksum_update(cksum
, digest
, SHA1_DIGESTLEN
);
77 outlen
= SHA1_DIGESTLEN
;
78 g_checksum_get_digest(cksum
, digest
, &outlen
);
79 g_checksum_free(cksum
);
82 #undef CHECKSUM_BLOCKLEN
85 * Password-Based Key Derivation Function 2 (PKCS #5 v2.0).
86 * Code based on IEEE Std 802.11-2007, Annex H.4.2.
89 pkcs5_pbkdf2(const gchar
*pass
, size_t pass_len
, const guchar
*salt
,
90 size_t salt_len
, guchar
*key
, size_t key_len
, guint rounds
)
92 guchar
*asalt
, obuf
[SHA1_DIGESTLEN
];
93 guchar d1
[SHA1_DIGESTLEN
], d2
[SHA1_DIGESTLEN
];
98 if (pass
== NULL
|| salt
== NULL
|| key
== NULL
)
100 if (rounds
< 1 || key_len
== 0)
102 if (salt_len
== 0 || salt_len
> SIZE_MAX
- 4)
104 if ((asalt
= malloc(salt_len
+ 4)) == NULL
)
107 memcpy(asalt
, salt
, salt_len
);
109 for (count
= 1; key_len
> 0; count
++) {
110 asalt
[salt_len
+ 0] = (count
>> 24) & 0xff;
111 asalt
[salt_len
+ 1] = (count
>> 16) & 0xff;
112 asalt
[salt_len
+ 2] = (count
>> 8) & 0xff;
113 asalt
[salt_len
+ 3] = count
& 0xff;
114 hmac_sha1(asalt
, salt_len
+ 4, pass
, pass_len
, d1
);
115 memcpy(obuf
, d1
, sizeof(obuf
));
117 for (i
= 1; i
< rounds
; i
++) {
118 hmac_sha1(d1
, sizeof(d1
), pass
, pass_len
, d2
);
119 memcpy(d1
, d2
, sizeof(d1
));
120 for (j
= 0; j
< sizeof(obuf
); j
++)
124 r
= MIN(key_len
, SHA1_DIGESTLEN
);
125 memcpy(key
, obuf
, r
);
129 memset(asalt
, 0, salt_len
+ 4);
131 memset(d1
, 0, sizeof(d1
));
132 memset(d2
, 0, sizeof(d2
));
133 memset(obuf
, 0, sizeof(obuf
));
138 #undef SHA1_DIGESTLEN