[Dovecot] SHA256 password patch
Hi, I made a patch against branch-1.0 for SHA256 password hashing support for Dovecot. Courier Authlib supports this hashing scheme and in order to migrate from Courier to Dovecot, I've added SHA256 support to Dovecot. The attached patch is based on BSD licensed code from Olivier Gay (http://www.ouah.org/ogay/sha2/). Changes made by me in Olivier's sha2{.h,.c} code: - Prototype for sha256_transf is added to sha2.h - sha256_get_digest() is added to sha2{.h,.c} - Code for UNROLL_LOOPS is removed - Support for SHA224,SHA384,SHA512 was removed - Functions are renamed to match those in sha1{.h,.c} - SHA256_DIGEST_SIZE is renamed to SHA256_RESULTLEN I can add safe_memset calls if requested. Patch is attached and can also be found at http://www.malochia.nl/dovecot/sha256.patch Kind regards, Jasper diff -r -u -N --exclude=Makefile.in --exclude=.deps --exclude=Makefile src/auth/password-scheme.c auth/password-scheme.c --- src/auth/password-scheme.c 2007-02-21 13:30:38.756711250 +0100 +++ auth/password-scheme.c 2007-02-21 14:18:49.645380500 +0100 @@ -10,6 +10,7 @@ #include "mycrypt.h" #include "randgen.h" #include "sha1.h" +#include "sha2.h" #include "str.h" #include "password-scheme.h" @@ -153,6 +154,17 @@ return str_c(str); } +static const char *sha256_generate(const char *plaintext, + const char *user __attr_unused__) +{ + unsigned char digest[SHA256_RESULTLEN]; + string_t *str; + sha256_get_digest(plaintext, strlen(plaintext), digest); + str = t_str_new(MAX_BASE64_ENCODED_SIZE(sizeof(digest)+1)); + base64_encode(digest, sizeof(digest), str); + return str_c(str); +} + static const void * password_decode(const char *password, unsigned int result_len) { @@ -196,6 +208,23 @@ return memcmp(sha1_digest, data, SHA1_RESULTLEN) == 0; } +static bool sha256_verify(const char *plaintext, const char *password, + const char *user) +{ + unsigned char sha256_digest[SHA256_RESULTLEN]; + const char *data; + + sha256_get_digest(plaintext, strlen(plaintext), sha256_digest); + + data = password_decode(password, SHA256_RESULTLEN); + if (data == NULL) { + i_error("sha256_verify(%s): Invalid password encoding", user); + return 0; + } + + return memcmp(sha256_digest, data, SHA256_RESULTLEN) == 0; +} + static const char *ssha_generate(const char *plaintext, const char *user __attr_unused__) { @@ -466,6 +495,7 @@ { "MD5-CRYPT", md5_crypt_verify, md5_crypt_generate }, { "SHA", sha1_verify, sha1_generate }, { "SHA1", sha1_verify, sha1_generate }, + { "SHA256", sha256_verify, sha256_generate }, { "SMD5", smd5_verify, smd5_generate }, { "SSHA", ssha_verify, ssha_generate }, { "PLAIN", plain_verify, plain_generate }, diff -r -u -N --exclude=Makefile.in --exclude=.deps --exclude=Makefile src/lib/Makefile.am lib/Makefile.am --- src/lib/Makefile.am 2007-02-21 13:30:38.792713500 +0100 +++ lib/Makefile.am 2007-02-21 14:21:59.437241750 +0100 @@ -73,6 +73,7 @@ sendfile-util.c \ seq-range-array.c \ sha1.c \ + sha2.c \ str.c \ str-sanitize.c \ strescape.c \ @@ -146,6 +147,7 @@ sendfile-util.h \ seq-range-array.h \ sha1.h \ + sha2.h \ str.h \ str-sanitize.h \ strescape.h \ diff -r -u -N --exclude=Makefile.in --exclude=.deps --exclude=Makefile src/lib/sha2.c lib/sha2.c --- src/lib/sha2.c 1970-01-01 01:00:00.000000000 +0100 +++ lib/sha2.c 2007-02-23 14:03:46.857739818 +0100 @@ -0,0 +1,257 @@ +/* + * FIPS 180-2 SHA-224/256/384/512 implementation + * Last update: 02/02/2007 + * Issue date: 04/30/2005 + * + * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <string.h> + +#include "sha2.h" + +#define SHFR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) +#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) +#define CH(x, y, z) ((x & y) ^ (~x & z)) +#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) + +#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) +#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) + +#define UNPACK32(x, str) \ +{ \ + *((str) + 3) = (uint8) ((x) ); \ + *((str) + 2) = (uint8) ((x) >> 8); \ + *((str) + 1) = (uint8) ((x) >> 16); \ + *((str) + 0) = (uint8) ((x) >> 24); \ +} + +#define PACK32(str, x) \ +{ \ + *(x) = ((uint32) *((str) + 3) ) \ + | ((uint32) *((str) + 2) << 8) \ + | ((uint32) *((str) + 1) << 16) \ + | ((uint32) *((str) + 0) << 24); \ +} + +#define UNPACK64(x, str) \ +{ \ + *((str) + 7) = (uint8) ((x) ); \ + *((str) + 6) = (uint8) ((x) >> 8); \ + *((str) + 5) = (uint8) ((x) >> 16); \ + *((str) + 4) = (uint8) ((x) >> 24); \ + *((str) + 3) = (uint8) ((x) >> 32); \ + *((str) + 2) = (uint8) ((x) >> 40); \ + *((str) + 1) = (uint8) ((x) >> 48); \ + *((str) + 0) = (uint8) ((x) >> 56); \ +} + +#define PACK64(str, x) \ +{ \ + *(x) = ((uint64) *((str) + 7) ) \ + | ((uint64) *((str) + 6) << 8) \ + | ((uint64) *((str) + 5) << 16) \ + | ((uint64) *((str) + 4) << 24) \ + | ((uint64) *((str) + 3) << 32) \ + | ((uint64) *((str) + 2) << 40) \ + | ((uint64) *((str) + 1) << 48) \ + | ((uint64) *((str) + 0) << 56); \ +} + +/* Macros used for loops unrolling */ + +#define SHA256_SCR(i) \ +{ \ + w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \ + + SHA256_F3(w[i - 15]) + w[i - 16]; \ +} + + + +uint32 sha256_h0[8] = + {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + + +uint32 sha256_k[64] = + {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + + +/* SHA-256 functions */ + +void sha256_transf(sha256_ctx *ctx, const unsigned char *message, + unsigned int block_nb) +{ + uint32 w[64]; + uint32 wv[8]; + uint32 t1, t2; + const unsigned char *sub_block; + int i,j; + + + for (i = 0; i < (int) block_nb; i++) { + sub_block = message + (i << 6); + + for (j = 0; j < 16; j++) { + PACK32(&sub_block[j << 2], &w[j]); + } + + for (j = 16; j < 64; j++) { + SHA256_SCR(j); + } + + for (j = 0; j < 8; j++) { + wv[j] = ctx->h[j]; + } + + for (j = 0; j < 64; j++) { + t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + + sha256_k[j] + w[j]; + t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); + wv[7] = wv[6]; + wv[6] = wv[5]; + wv[5] = wv[4]; + wv[4] = wv[3] + t1; + wv[3] = wv[2]; + wv[2] = wv[1]; + wv[1] = wv[0]; + wv[0] = t1 + t2; + } + + for (j = 0; j < 8; j++) { + ctx->h[j] += wv[j]; + } + } +} + +void sha256(const unsigned char *message, unsigned int len, unsigned char *digest) +{ + sha256_ctx ctx; + + sha256_init(&ctx); + sha256_loop(&ctx, message, len); + sha256_result(&ctx, digest); +} + +void sha256_init(sha256_ctx *ctx) +{ + int i; + for (i = 0; i < 8; i++) { + ctx->h[i] = sha256_h0[i]; + } + + ctx->len = 0; + ctx->tot_len = 0; +} + +void sha256_loop(sha256_ctx *ctx, const unsigned char *message, + unsigned int len) +{ + unsigned int block_nb; + unsigned int new_len, rem_len, tmp_len; + const unsigned char *shifted_message; + + tmp_len = SHA256_BLOCK_SIZE - ctx->len; + rem_len = len < tmp_len ? len : tmp_len; + + memcpy(&ctx->block[ctx->len], message, rem_len); + + if (ctx->len + len < SHA256_BLOCK_SIZE) { + ctx->len += len; + return; + } + + new_len = len - rem_len; + block_nb = new_len / SHA256_BLOCK_SIZE; + + shifted_message = message + rem_len; + + sha256_transf(ctx, ctx->block, 1); + sha256_transf(ctx, shifted_message, block_nb); + + rem_len = new_len % SHA256_BLOCK_SIZE; + + memcpy(ctx->block, &shifted_message[block_nb << 6], + rem_len); + + ctx->len = rem_len; + ctx->tot_len += (block_nb + 1) << 6; +} + +void sha256_result(sha256_ctx *ctx, unsigned char *digest) +{ + unsigned int block_nb; + unsigned int pm_len; + unsigned int len_b; + int i; + + block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) + < (ctx->len % SHA256_BLOCK_SIZE))); + + len_b = (ctx->tot_len + ctx->len) << 3; + pm_len = block_nb << 6; + + memset(ctx->block + ctx->len, 0, pm_len - ctx->len); + ctx->block[ctx->len] = 0x80; + UNPACK32(len_b, ctx->block + pm_len - 4); + + sha256_transf(ctx, ctx->block, block_nb); + + for (i = 0 ; i < 8; i++) { + UNPACK32(ctx->h[i], &digest[i << 2]); + } +} + +void sha256_get_digest(const void *data, size_t size, + unsigned char result[SHA256_RESULTLEN]) +{ + sha256_ctx ctx; + + sha256_init(&ctx); + sha256_loop(&ctx, data, size); + sha256_result(&ctx, result); +} + diff -r -u -N --exclude=Makefile.in --exclude=.deps --exclude=Makefile src/lib/sha2.h lib/sha2.h --- src/lib/sha2.h 1970-01-01 01:00:00.000000000 +0100 +++ lib/sha2.h 2007-02-23 14:22:32.952116316 +0100 @@ -0,0 +1,72 @@ +/* + * FIPS 180-2 SHA-224/256/384/512 implementation + * Last update: 02/02/2007 + * Issue date: 04/30/2005 + * + * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef SHA2_H +#define SHA2_H + +#define SHA256_RESULTLEN ( 256 / 8) + +#define SHA256_BLOCK_SIZE ( 512 / 8) + +#ifndef SHA2_TYPES +#define SHA2_TYPES +typedef unsigned char uint8; +typedef unsigned int uint32; +typedef unsigned long long uint64; +#endif + + +typedef struct { + unsigned int tot_len; + unsigned int len; + unsigned char block[2 * SHA256_BLOCK_SIZE]; + uint32 h[8]; +} sha256_ctx; + +void sha256_transf(sha256_ctx *ctx, const unsigned char *message, + unsigned int block_nb); + + +void sha256_init(sha256_ctx * ctx); +void sha256_loop(sha256_ctx *ctx, const unsigned char *message, + unsigned int len); +void sha256_result(sha256_ctx *ctx, unsigned char *digest); +void sha256(const unsigned char *message, unsigned int len, + unsigned char *digest); +void sha256_get_digest(const void *data, size_t size, + unsigned char result[SHA256_RESULTLEN]); + + + +#endif /* !SHA2_H */ +
On 055, 02 24, 2007 at 03:58:35PM +0100, Jasper Slits wrote:
Hi,
I made a patch against branch-1.0 for SHA256 password hashing support for Dovecot. Courier Authlib supports this hashing scheme and in order to migrate from Courier to Dovecot, I've added SHA256 support to Dovecot.
The attached patch is based on BSD licensed code from Olivier Gay (http://www.ouah.org/ogay/sha2/).
Changes made by me in Olivier's sha2{.h,.c} code: - Prototype for sha256_transf is added to sha2.h - sha256_get_digest() is added to sha2{.h,.c} - Code for UNROLL_LOOPS is removed - Support for SHA224,SHA384,SHA512 was removed - Functions are renamed to match those in sha1{.h,.c} - SHA256_DIGEST_SIZE is renamed to SHA256_RESULTLEN
I can add safe_memset calls if requested.
Patch is attached and can also be found at http://www.malochia.nl/dovecot/sha256.patch
Kind regards,
Jasper
diff -r -u -N --exclude=Makefile.in --exclude=.deps --exclude=Makefile src/auth/password-scheme.c auth/password-scheme.c --- src/auth/password-scheme.c 2007-02-21 13:30:38.756711250 +0100 +++ auth/password-scheme.c 2007-02-21 14:18:49.645380500 +0100 @@ -10,6 +10,7 @@ #include "mycrypt.h" #include "randgen.h" #include "sha1.h" +#include "sha2.h" #include "str.h" #include "password-scheme.h"
@@ -153,6 +154,17 @@ return str_c(str); }
+static const char *sha256_generate(const char *plaintext, + const char *user __attr_unused__) +{ + unsigned char digest[SHA256_RESULTLEN]; + string_t *str; + sha256_get_digest(plaintext, strlen(plaintext), digest); + str = t_str_new(MAX_BASE64_ENCODED_SIZE(sizeof(digest)+1)); + base64_encode(digest, sizeof(digest), str); + return str_c(str); +} + static const void * password_decode(const char *password, unsigned int result_len) { @@ -196,6 +208,23 @@ return memcmp(sha1_digest, data, SHA1_RESULTLEN) == 0; }
+static bool sha256_verify(const char *plaintext, const char *password, + const char *user) +{ + unsigned char sha256_digest[SHA256_RESULTLEN]; + const char *data; + + sha256_get_digest(plaintext, strlen(plaintext), sha256_digest); + + data = password_decode(password, SHA256_RESULTLEN); + if (data == NULL) { + i_error("sha256_verify(%s): Invalid password encoding", user); + return 0; + } + + return memcmp(sha256_digest, data, SHA256_RESULTLEN) == 0; +} + static const char *ssha_generate(const char *plaintext, const char *user __attr_unused__) { @@ -466,6 +495,7 @@ { "MD5-CRYPT", md5_crypt_verify, md5_crypt_generate }, { "SHA", sha1_verify, sha1_generate }, { "SHA1", sha1_verify, sha1_generate }, + { "SHA256", sha256_verify, sha256_generate }, { "SMD5", smd5_verify, smd5_generate }, { "SSHA", ssha_verify, ssha_generate }, { "PLAIN", plain_verify, plain_generate }, diff -r -u -N --exclude=Makefile.in --exclude=.deps --exclude=Makefile src/lib/Makefile.am lib/Makefile.am --- src/lib/Makefile.am 2007-02-21 13:30:38.792713500 +0100 +++ lib/Makefile.am 2007-02-21 14:21:59.437241750 +0100 @@ -73,6 +73,7 @@ sendfile-util.c \ seq-range-array.c \ sha1.c \ + sha2.c \ str.c \ str-sanitize.c \ strescape.c \ @@ -146,6 +147,7 @@ sendfile-util.h \ seq-range-array.h \ sha1.h \ + sha2.h \ str.h \ str-sanitize.h \ strescape.h \ diff -r -u -N --exclude=Makefile.in --exclude=.deps --exclude=Makefile src/lib/sha2.c lib/sha2.c --- src/lib/sha2.c 1970-01-01 01:00:00.000000000 +0100 +++ lib/sha2.c 2007-02-23 14:03:46.857739818 +0100 @@ -0,0 +1,257 @@ +/* + * FIPS 180-2 SHA-224/256/384/512 implementation + * Last update: 02/02/2007 + * Issue date: 04/30/2005 + * + * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <string.h> + +#include "sha2.h" + +#define SHFR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) +#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) +#define CH(x, y, z) ((x & y) ^ (~x & z)) +#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) + +#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) +#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) + +#define UNPACK32(x, str) \ +{ \ + *((str) + 3) = (uint8) ((x) ); \ + *((str) + 2) = (uint8) ((x) >> 8); \ + *((str) + 1) = (uint8) ((x) >> 16); \ + *((str) + 0) = (uint8) ((x) >> 24); \ +} + +#define PACK32(str, x) \ +{ \ + *(x) = ((uint32) *((str) + 3) ) \ + | ((uint32) *((str) + 2) << 8) \ + | ((uint32) *((str) + 1) << 16) \ + | ((uint32) *((str) + 0) << 24); \ +} + +#define UNPACK64(x, str) \ +{ \ + *((str) + 7) = (uint8) ((x) ); \ + *((str) + 6) = (uint8) ((x) >> 8); \ + *((str) + 5) = (uint8) ((x) >> 16); \ + *((str) + 4) = (uint8) ((x) >> 24); \ + *((str) + 3) = (uint8) ((x) >> 32); \ + *((str) + 2) = (uint8) ((x) >> 40); \ + *((str) + 1) = (uint8) ((x) >> 48); \ + *((str) + 0) = (uint8) ((x) >> 56); \ +} + +#define PACK64(str, x) \ +{ \ + *(x) = ((uint64) *((str) + 7) ) \ + | ((uint64) *((str) + 6) << 8) \ + | ((uint64) *((str) + 5) << 16) \ + | ((uint64) *((str) + 4) << 24) \ + | ((uint64) *((str) + 3) << 32) \ + | ((uint64) *((str) + 2) << 40) \ + | ((uint64) *((str) + 1) << 48) \ + | ((uint64) *((str) + 0) << 56); \ +} + +/* Macros used for loops unrolling */ + +#define SHA256_SCR(i) \ +{ \ + w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \ + + SHA256_F3(w[i - 15]) + w[i - 16]; \ +} + + + +uint32 sha256_h0[8] =
static const missing here.
+ {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + + +uint32 sha256_k[64] =
Here too.
+ {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + + +/* SHA-256 functions */ + +void sha256_transf(sha256_ctx *ctx, const unsigned char *message, + unsigned int block_nb) +{ + uint32 w[64]; + uint32 wv[8]; + uint32 t1, t2; + const unsigned char *sub_block; + int i,j; + + + for (i = 0; i < (int) block_nb; i++) { + sub_block = message + (i << 6); + + for (j = 0; j < 16; j++) { + PACK32(&sub_block[j << 2], &w[j]); + } + + for (j = 16; j < 64; j++) { + SHA256_SCR(j); + } + + for (j = 0; j < 8; j++) { + wv[j] = ctx->h[j]; + } + + for (j = 0; j < 64; j++) { + t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + + sha256_k[j] + w[j]; + t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); + wv[7] = wv[6]; + wv[6] = wv[5]; + wv[5] = wv[4]; + wv[4] = wv[3] + t1; + wv[3] = wv[2]; + wv[2] = wv[1]; + wv[1] = wv[0]; + wv[0] = t1 + t2; + } + + for (j = 0; j < 8; j++) { + ctx->h[j] += wv[j]; + } + } +} + +void sha256(const unsigned char *message, unsigned int len, unsigned char *digest) +{ + sha256_ctx ctx; + + sha256_init(&ctx); + sha256_loop(&ctx, message, len); + sha256_result(&ctx, digest); +} + +void sha256_init(sha256_ctx *ctx) +{ + int i; + for (i = 0; i < 8; i++) { + ctx->h[i] = sha256_h0[i]; + } + + ctx->len = 0; + ctx->tot_len = 0; +} + +void sha256_loop(sha256_ctx *ctx, const unsigned char *message, + unsigned int len) +{ + unsigned int block_nb; + unsigned int new_len, rem_len, tmp_len; + const unsigned char *shifted_message; + + tmp_len = SHA256_BLOCK_SIZE - ctx->len; + rem_len = len < tmp_len ? len : tmp_len; + + memcpy(&ctx->block[ctx->len], message, rem_len); + + if (ctx->len + len < SHA256_BLOCK_SIZE) { + ctx->len += len; + return; + } + + new_len = len - rem_len; + block_nb = new_len / SHA256_BLOCK_SIZE; + + shifted_message = message + rem_len; + + sha256_transf(ctx, ctx->block, 1); + sha256_transf(ctx, shifted_message, block_nb); + + rem_len = new_len % SHA256_BLOCK_SIZE; + + memcpy(ctx->block, &shifted_message[block_nb << 6], + rem_len); + + ctx->len = rem_len; + ctx->tot_len += (block_nb + 1) << 6; +} + +void sha256_result(sha256_ctx *ctx, unsigned char *digest) +{ + unsigned int block_nb; + unsigned int pm_len; + unsigned int len_b; + int i; + + block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) + < (ctx->len % SHA256_BLOCK_SIZE))); + + len_b = (ctx->tot_len + ctx->len) << 3; + pm_len = block_nb << 6; + + memset(ctx->block + ctx->len, 0, pm_len - ctx->len); + ctx->block[ctx->len] = 0x80; + UNPACK32(len_b, ctx->block + pm_len - 4); + + sha256_transf(ctx, ctx->block, block_nb); + + for (i = 0 ; i < 8; i++) { + UNPACK32(ctx->h[i], &digest[i << 2]); + } +} + +void sha256_get_digest(const void *data, size_t size, + unsigned char result[SHA256_RESULTLEN]) +{ + sha256_ctx ctx; + + sha256_init(&ctx); + sha256_loop(&ctx, data, size); + sha256_result(&ctx, result); +} + diff -r -u -N --exclude=Makefile.in --exclude=.deps --exclude=Makefile src/lib/sha2.h lib/sha2.h --- src/lib/sha2.h 1970-01-01 01:00:00.000000000 +0100 +++ lib/sha2.h 2007-02-23 14:22:32.952116316 +0100 @@ -0,0 +1,72 @@ +/* + * FIPS 180-2 SHA-224/256/384/512 implementation + * Last update: 02/02/2007 + * Issue date: 04/30/2005 + * + * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef SHA2_H +#define SHA2_H + +#define SHA256_RESULTLEN ( 256 / 8) + +#define SHA256_BLOCK_SIZE ( 512 / 8) + +#ifndef SHA2_TYPES +#define SHA2_TYPES +typedef unsigned char uint8; +typedef unsigned int uint32; +typedef unsigned long long uint64; +#endif
IMHO it's better to drop these defines and just use stdint.h
+typedef struct { + unsigned int tot_len; + unsigned int len; + unsigned char block[2 * SHA256_BLOCK_SIZE]; + uint32 h[8]; +} sha256_ctx;
Other digest implementations do not use typedef for context structure. It's better drop it for consistency.
+void sha256_transf(sha256_ctx *ctx, const unsigned char *message, + unsigned int block_nb); + + +void sha256_init(sha256_ctx * ctx); +void sha256_loop(sha256_ctx *ctx, const unsigned char *message, + unsigned int len); +void sha256_result(sha256_ctx *ctx, unsigned char *digest); +void sha256(const unsigned char *message, unsigned int len, + unsigned char *digest); +void sha256_get_digest(const void *data, size_t size, + unsigned char result[SHA256_RESULTLEN]); + + + +#endif /* !SHA2_H */ +
-- Andrey Panin | Linux and UNIX system administrator pazke@donpac.ru | PGP key: wwwkeys.pgp.net
On Sat, 2007-02-24 at 15:58 +0100, Jasper Slits wrote:
I made a patch against branch-1.0 for SHA256 password hashing support for Dovecot.
I finally got around to committing this. http://hg.dovecot.org/dovecot/rev/2cba4c0f3b4f
Changes made by me in Olivier's sha2{.h,.c} code:
- Prototype for sha256_transf is added to sha2.h
Why? I made it static instead.
- Support for SHA224,SHA384,SHA512 was removed
Would it be useful to support these too? I guess I don't bother until someone asks.
participants (3)
-
Andrey Panin
-
Jasper Slits
-
Timo Sirainen