| |
| /* |
| * The Initial Developer of the Original Code is International |
| * Business Machines Corporation. Portions created by IBM |
| * Corporation are Copyright (C) 2005 International Business |
| * Machines Corporation. All Rights Reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the Common Public License as published by |
| * IBM Corporation; either version 1 of the License, or (at your option) |
| * any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * Common Public License for more details. |
| * |
| * You should have received a copy of the Common Public License |
| * along with this program; if not, a copy can be viewed at |
| * http://www.opensource.org/licenses/cpl1.0.php. |
| */ |
| |
| /* (C) COPYRIGHT International Business Machines Corp. 2001, 2002, 2005 */ |
| |
| |
| // File: mech_sha.c |
| // |
| // Mechanisms for SHA-1 related routines |
| // |
| // The following applies to the software SHA implementation: |
| // Written 2 September 1992, Peter C. Gutmann. |
| // This implementation placed in the public domain. |
| // |
| // Modified 1 June 1993, Colin Plumb. |
| // Modified for the new SHS based on Peter Gutmann's work, |
| // 18 July 1994, Colin Plumb. |
| // Gutmann's work. |
| // Renamed to SHA and comments updated a bit 1 November 1995, Colin Plumb. |
| // These modifications placed in the public domain. |
| // |
| // Comments to pgut1@cs.aukuni.ac.nz |
| // |
| |
| //#include <windows.h> |
| |
| #include <pthread.h> |
| #include <string.h> // for memcmp() et al |
| #include <stdlib.h> |
| #include <memory.h> |
| |
| #include "pkcs11/pkcs11types.h" |
| #include <pkcs11/stdll.h> |
| #include "defs.h" |
| #include "host_defs.h" |
| #include "h_extern.h" |
| #include "tok_spec_struct.h" |
| |
| #define SHA_HARDWARE_THRESHHOLD 128000 |
| |
| // The SHA f()-functions. The f1 and f3 functions can be optimized to |
| // save one boolean operation each - thanks to Rich Schroeppel, |
| // rcs@cs.arizona.edu for discovering this |
| // |
| #define f1(x,y,z) (z ^ (x & (y ^ z))) // Rounds 0-19 |
| #define f2(x,y,z) (x ^ y ^ z) // Rounds 20-39 |
| #define f3(x,y,z) ((x & y) | (z & (x | y))) // Rounds 40-59 |
| #define f4(x,y,z) (x ^ y ^ z) // Rounds 60-79 |
| |
| // The SHA Mysterious Constants. |
| // K1 = floor(sqrt(2) * 2^30) |
| // K2 = floor(sqrt(3) * 2^30) |
| // K3 = floor(sqrt(5) * 2^30) |
| // K4 = floor(sqrt(10) * 2^30) |
| // |
| #define K1 0x5A827999L // Rounds 0-19 |
| #define K2 0x6ED9EBA1L // Rounds 20-39 |
| #define K3 0x8F1BBCDCL // Rounds 40-59 |
| #define K4 0xCA62C1D6L // Rounds 60-79 |
| |
| // SHA initial values |
| // |
| #define h0init 0x67452301 |
| #define h1init 0xEFCDAB89 |
| #define h2init 0x98BADCFE |
| #define h3init 0x10325476 |
| #define h4init 0xC3D2E1F0 |
| |
| // |
| // Note that it may be necessary to add parentheses to these macros |
| // if they are to be called with expressions as arguments. |
| // |
| |
| // 32-bit rotate left - kludged with shifts |
| // |
| |
| #define ROTL(n,X) ((X << n) | (X >> (32-n))) |
| |
| // The initial expanding function |
| // |
| // The hash function is defined over an 80-word expanded input array W, |
| // where the first 16 are copies of the input data, and the remaining 64 |
| // are defined by W[i] = W[i-16] ^ W[i-14] ^ W[i-8] ^ W[i-3]. This |
| // implementation generates these values on the fly in a circular buffer. |
| // |
| |
| #define expand(W,i) \ |
| (W[i&15] ^= W[(i-14)&15] ^ W[(i-8)&15] ^ W[(i-3)&15], W[i&15] = ROTL(1, W[i&15])) |
| |
| // The prototype SHA sub-round |
| // |
| // The fundamental sub-round is |
| // a' = e + ROTL(5,a) + f(b, c, d) + k + data; |
| // b' = a; |
| // c' = ROTL(30,b); |
| // d' = c; |
| // e' = d; |
| // ... but this is implemented by unrolling the loop 5 times and renaming |
| // the variables (e,a,b,c,d) = (a',b',c',d',e') each iteration. |
| // |
| #define subRound(a, b, c, d, e, f, k, data) \ |
| (e += ROTL(5,a) + f(b, c, d) + k + data, b = ROTL(30, b)) |
| |
| |
| void shaInit( SHA1_CONTEXT *ctx ); |
| void shaUpdate( SHA1_CONTEXT *ctx, CK_BYTE const *buffer, CK_ULONG count); |
| void shaFinal( SHA1_CONTEXT *ctx, CK_BYTE *hash ); |
| void shaTransform( SHA1_CONTEXT *ctx ); |
| |
| // |
| // |
| CK_RV |
| sha1_hash( SESSION *sess, |
| CK_BBOOL length_only, |
| DIGEST_CONTEXT *ctx, |
| CK_BYTE *in_data, |
| CK_ULONG in_data_len, |
| CK_BYTE *out_data, |
| CK_ULONG *out_data_len ) |
| { |
| CK_RV rv; |
| |
| if (!sess || !ctx || !out_data_len){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| if (length_only == TRUE) { |
| *out_data_len = SHA1_HASH_SIZE; |
| return CKR_OK; |
| } |
| |
| if(ctx->context == NULL) |
| return CKR_HOST_MEMORY; |
| |
| if((rv = (ckm_sha1_update(ctx, in_data, in_data_len)))) |
| return rv; |
| |
| return ckm_sha1_final( ctx, out_data, out_data_len ); |
| } |
| |
| |
| // |
| // |
| CK_RV |
| sha1_hash_update( SESSION * sess, |
| DIGEST_CONTEXT * ctx, |
| CK_BYTE * in_data, |
| CK_ULONG in_data_len ) |
| { |
| if (!sess || !in_data){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| return ckm_sha1_update( ctx, in_data, in_data_len ); |
| } |
| |
| |
| // |
| // |
| CK_RV |
| sha1_hash_final( SESSION * sess, |
| CK_BYTE length_only, |
| DIGEST_CONTEXT * ctx, |
| CK_BYTE * out_data, |
| CK_ULONG * out_data_len ) |
| { |
| if (!sess || !ctx || !out_data_len){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| if (length_only == TRUE) { |
| *out_data_len = SHA1_HASH_SIZE; |
| return CKR_OK; |
| } |
| |
| return ckm_sha1_final( ctx, out_data, out_data_len ); |
| } |
| |
| |
| // this routine gets called for two mechanisms actually: |
| // CKM_SHA_1_HMAC |
| // CKM_SHA_1_HMAC_GENERAL |
| // |
| CK_RV |
| sha1_hmac_sign( SESSION * sess, |
| CK_BBOOL length_only, |
| SIGN_VERIFY_CONTEXT * ctx, |
| CK_BYTE * in_data, |
| CK_ULONG in_data_len, |
| CK_BYTE * out_data, |
| CK_ULONG * out_data_len ) |
| { |
| OBJECT * key_obj = NULL; |
| CK_ATTRIBUTE * attr = NULL; |
| CK_BYTE hash[SHA1_HASH_SIZE]; |
| DIGEST_CONTEXT digest_ctx; |
| CK_MECHANISM digest_mech; |
| CK_BYTE k_ipad[SHA1_BLOCK_SIZE]; |
| CK_BYTE k_opad[SHA1_BLOCK_SIZE]; |
| CK_ULONG key_bytes, hash_len, hmac_len; |
| CK_ULONG i; |
| CK_RV rc; |
| |
| |
| if (!sess || !ctx || !out_data_len){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| |
| if (ctx->mech.mechanism == CKM_SHA_1_HMAC_GENERAL) { |
| hmac_len = *(CK_ULONG *)ctx->mech.pParameter; |
| |
| if (hmac_len == 0) { |
| *out_data_len = 0; |
| return CKR_OK; |
| } |
| } |
| else |
| hmac_len = SHA1_HASH_SIZE; |
| |
| |
| if (length_only == TRUE) { |
| *out_data_len = hmac_len; |
| return CKR_OK; |
| } |
| |
| memset( &digest_ctx, 0x0, sizeof(DIGEST_CONTEXT) ); |
| |
| rc = object_mgr_find_in_map1( ctx->key, &key_obj ); |
| if (rc != CKR_OK){ |
| st_err_log(110, __FILE__, __LINE__); |
| return rc; |
| } |
| rc = template_attribute_find( key_obj->template, CKA_VALUE, &attr ); |
| if (rc == FALSE){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| else |
| key_bytes = attr->ulValueLen; |
| |
| |
| // build (K XOR ipad), (K XOR opad) |
| // |
| if (key_bytes > SHA1_BLOCK_SIZE) { |
| digest_mech.mechanism = CKM_SHA_1; |
| digest_mech.ulParameterLen = 0; |
| digest_mech.pParameter = NULL; |
| |
| rc = digest_mgr_init( sess, &digest_ctx, &digest_mech ); |
| if (rc != CKR_OK) { |
| digest_mgr_cleanup( &digest_ctx ); |
| st_err_log(123, __FILE__, __LINE__); |
| return rc; |
| } |
| |
| hash_len = sizeof(hash); |
| rc = digest_mgr_digest( sess, FALSE, &digest_ctx, |
| attr->pValue, |
| attr->ulValueLen, |
| hash, &hash_len ); |
| if (rc != CKR_OK) { |
| digest_mgr_cleanup( &digest_ctx ); |
| st_err_log(124, __FILE__, __LINE__); |
| return rc; |
| } |
| |
| digest_mgr_cleanup( &digest_ctx ); |
| memset( &digest_ctx, 0x0, sizeof(DIGEST_CONTEXT) ); |
| |
| for (i=0; i < hash_len; i++) { |
| k_ipad[i] = hash[i] ^ 0x36; |
| k_opad[i] = hash[i] ^ 0x5C; |
| } |
| |
| memset( &k_ipad[i], 0x36, SHA1_BLOCK_SIZE - i); |
| memset( &k_opad[i], 0x5C, SHA1_BLOCK_SIZE - i); |
| } |
| else { |
| CK_BYTE *key = attr->pValue; |
| |
| for (i=0; i < key_bytes; i++) { |
| k_ipad[i] = key[i] ^ 0x36; |
| k_opad[i] = key[i] ^ 0x5C; |
| } |
| |
| memset( &k_ipad[i], 0x36, SHA1_BLOCK_SIZE - key_bytes ); |
| memset( &k_opad[i], 0x5C, SHA1_BLOCK_SIZE - key_bytes ); |
| } |
| |
| digest_mech.mechanism = CKM_SHA_1; |
| digest_mech.ulParameterLen = 0; |
| digest_mech.pParameter = NULL; |
| |
| // inner hash |
| // |
| rc = digest_mgr_init( sess, &digest_ctx, &digest_mech ); |
| if (rc != CKR_OK) { |
| digest_mgr_cleanup( &digest_ctx ); |
| st_err_log(123, __FILE__, __LINE__); |
| return rc; |
| } |
| |
| rc = digest_mgr_digest_update( sess, &digest_ctx, k_ipad, SHA1_BLOCK_SIZE ); |
| if (rc != CKR_OK) { |
| digest_mgr_cleanup( &digest_ctx ); |
| st_err_log(123, __FILE__, __LINE__); |
| return rc; |
| } |
| |
| rc = digest_mgr_digest_update( sess, &digest_ctx, in_data, in_data_len ); |
| if (rc != CKR_OK) { |
| digest_mgr_cleanup( &digest_ctx ); |
| st_err_log(123, __FILE__, __LINE__); |
| return rc; |
| } |
| |
| hash_len = sizeof(hash); |
| rc = digest_mgr_digest_final( sess, FALSE, &digest_ctx, hash, &hash_len ); |
| if (rc != CKR_OK) { |
| digest_mgr_cleanup( &digest_ctx ); |
| st_err_log(126, __FILE__, __LINE__); |
| return rc; |
| } |
| |
| digest_mgr_cleanup( &digest_ctx ); |
| memset( &digest_ctx, 0x0, sizeof(DIGEST_CONTEXT) ); |
| |
| |
| // outer hash |
| // |
| rc = digest_mgr_init( sess, &digest_ctx, &digest_mech ); |
| if (rc != CKR_OK) { |
| digest_mgr_cleanup( &digest_ctx ); |
| st_err_log(123, __FILE__, __LINE__); |
| return rc; |
| } |
| |
| rc = digest_mgr_digest_update( sess, &digest_ctx, k_opad, SHA1_BLOCK_SIZE ); |
| if (rc != CKR_OK) { |
| digest_mgr_cleanup( &digest_ctx ); |
| st_err_log(123, __FILE__, __LINE__); |
| return rc; |
| } |
| |
| rc = digest_mgr_digest_update( sess, &digest_ctx, hash, hash_len ); |
| if (rc != CKR_OK) { |
| digest_mgr_cleanup( &digest_ctx ); |
| st_err_log(123, __FILE__, __LINE__); |
| return rc; |
| } |
| |
| hash_len = sizeof(hash); |
| rc = digest_mgr_digest_final( sess, FALSE, &digest_ctx, hash, &hash_len ); |
| if (rc != CKR_OK) { |
| digest_mgr_cleanup( &digest_ctx ); |
| st_err_log(126, __FILE__, __LINE__); |
| return rc; |
| } |
| |
| memcpy( out_data, hash, hmac_len ); |
| *out_data_len = hmac_len; |
| |
| digest_mgr_cleanup( &digest_ctx ); |
| |
| return CKR_OK; |
| } |
| |
| |
| // |
| // |
| CK_RV |
| sha1_hmac_verify( SESSION * sess, |
| SIGN_VERIFY_CONTEXT * ctx, |
| CK_BYTE * in_data, |
| CK_ULONG in_data_len, |
| CK_BYTE * signature, |
| CK_ULONG sig_len ) |
| { |
| CK_BYTE hmac[SHA1_HASH_SIZE]; |
| SIGN_VERIFY_CONTEXT hmac_ctx; |
| CK_ULONG hmac_len, len; |
| CK_RV rc; |
| |
| if (!sess || !ctx || !in_data || !signature){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| if (ctx->mech.mechanism == CKM_SHA_1_HMAC_GENERAL) |
| hmac_len = *(CK_ULONG *)ctx->mech.pParameter; |
| else |
| hmac_len = SHA1_HASH_SIZE; |
| |
| memset( &hmac_ctx, 0, sizeof(SIGN_VERIFY_CONTEXT) ); |
| |
| rc = sign_mgr_init( sess, &hmac_ctx, &ctx->mech, FALSE, ctx->key ); |
| if (rc != CKR_OK){ |
| st_err_log(127, __FILE__, __LINE__); |
| goto done; |
| } |
| len = sizeof(hmac); |
| rc = sign_mgr_sign( sess, FALSE, &hmac_ctx, |
| in_data, in_data_len, |
| hmac, &len ); |
| if (rc != CKR_OK){ |
| st_err_log(128, __FILE__, __LINE__); |
| goto done; |
| } |
| if ((len != hmac_len) || (len != sig_len)) { |
| st_err_log(46, __FILE__, __LINE__); |
| rc = CKR_SIGNATURE_LEN_RANGE; |
| goto done; |
| } |
| |
| if (memcmp(hmac, signature, hmac_len) != 0){ |
| st_err_log(47, __FILE__, __LINE__); |
| rc = CKR_SIGNATURE_INVALID; |
| } |
| done: |
| sign_mgr_cleanup( &hmac_ctx ); |
| return rc; |
| } |
| |
| |
| // |
| // CKM routines |
| // |
| |
| // |
| // |
| CK_RV |
| ckm_sha1_update( DIGEST_CONTEXT * ctx, |
| CK_BYTE * in_data, |
| CK_ULONG in_data_len ) |
| { |
| if( token_specific.t_sha_update == NULL ){ |
| if (!ctx || !in_data){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| shaUpdate( (SHA1_CONTEXT *)ctx->context, in_data, in_data_len ); |
| return CKR_OK; |
| } |
| |
| return token_specific.t_sha_update(ctx, in_data, in_data_len); |
| } |
| |
| |
| // |
| // |
| CK_RV |
| ckm_sha1_final( DIGEST_CONTEXT * ctx, |
| CK_BYTE * out_data, |
| CK_ULONG * out_data_len ) |
| { |
| if (token_specific.t_sha_final == NULL ){ |
| if (!ctx || !out_data || !out_data_len){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| if (*out_data_len < SHA1_HASH_SIZE){ |
| st_err_log(4, __FILE__, __LINE__, __FUNCTION__); |
| return CKR_FUNCTION_FAILED; |
| } |
| shaFinal( (SHA1_CONTEXT *)ctx->context, out_data ); |
| *out_data_len = SHA1_HASH_SIZE; |
| |
| return CKR_OK; |
| } |
| |
| return token_specific.t_sha_final(ctx, out_data, out_data_len); |
| } |
| |
| |
| // |
| // Software SHA-1 implementation |
| // |
| void |
| ckm_sha1_init( DIGEST_CONTEXT * ctx) |
| { |
| // Set the h-vars to their initial values |
| if (token_specific.t_sha_init == NULL ) { |
| SHA1_CONTEXT *sha1_ctx; |
| /* Allocate the context */ |
| ctx->context_len = sizeof(SHA1_CONTEXT); |
| ctx->context = (CK_BYTE *)malloc(sizeof(SHA1_CONTEXT)); |
| if( ctx->context == NULL ) |
| return; |
| |
| sha1_ctx = (SHA1_CONTEXT *)ctx->context; |
| sha1_ctx->hash_value[0] = h0init; |
| sha1_ctx->hash_value[1] = h1init; |
| sha1_ctx->hash_value[2] = h2init; |
| sha1_ctx->hash_value[3] = h3init; |
| sha1_ctx->hash_value[4] = h4init; |
| |
| // Initialise bit count |
| sha1_ctx->bits_lo = sha1_ctx->bits_hi = 0; |
| } else { |
| // SAB XXX call token specific init... the init MUST allocate it's context |
| token_specific.t_sha_init(ctx); |
| } |
| } |
| |
| |
| // Perform the SHA transformation. Note that this code, like MD5, seems to |
| // break some optimizing compilers due to the complexity of the expressions |
| // and the size of the basic block. It may be necessary to split it into |
| // sections, e.g. based on the four subrounds |
| // |
| // Note that this corrupts the sha->data area |
| // |
| void |
| shaTransform( SHA1_CONTEXT *ctx ) |
| { |
| register unsigned int A, B, C, D, E; |
| |
| // Set up first buffer |
| // |
| A = ctx->hash_value[0]; |
| B = ctx->hash_value[1]; |
| C = ctx->hash_value[2]; |
| D = ctx->hash_value[3]; |
| E = ctx->hash_value[4]; |
| |
| // Heavy mangling, in 4 sub-rounds of 20 interations each. |
| // |
| subRound( A, B, C, D, E, f1, K1, ctx->buf[ 0] ); |
| subRound( E, A, B, C, D, f1, K1, ctx->buf[ 1] ); |
| subRound( D, E, A, B, C, f1, K1, ctx->buf[ 2] ); |
| subRound( C, D, E, A, B, f1, K1, ctx->buf[ 3] ); |
| subRound( B, C, D, E, A, f1, K1, ctx->buf[ 4] ); |
| subRound( A, B, C, D, E, f1, K1, ctx->buf[ 5] ); |
| subRound( E, A, B, C, D, f1, K1, ctx->buf[ 6] ); |
| subRound( D, E, A, B, C, f1, K1, ctx->buf[ 7] ); |
| subRound( C, D, E, A, B, f1, K1, ctx->buf[ 8] ); |
| subRound( B, C, D, E, A, f1, K1, ctx->buf[ 9] ); |
| subRound( A, B, C, D, E, f1, K1, ctx->buf[10] ); |
| subRound( E, A, B, C, D, f1, K1, ctx->buf[11] ); |
| subRound( D, E, A, B, C, f1, K1, ctx->buf[12] ); |
| subRound( C, D, E, A, B, f1, K1, ctx->buf[13] ); |
| subRound( B, C, D, E, A, f1, K1, ctx->buf[14] ); |
| subRound( A, B, C, D, E, f1, K1, ctx->buf[15] ); |
| subRound( E, A, B, C, D, f1, K1, expand(ctx->buf, 16) ); |
| subRound( D, E, A, B, C, f1, K1, expand(ctx->buf, 17) ); |
| subRound( C, D, E, A, B, f1, K1, expand(ctx->buf, 18) ); |
| subRound( B, C, D, E, A, f1, K1, expand(ctx->buf, 19) ); |
| |
| subRound( A, B, C, D, E, f2, K2, expand(ctx->buf, 20) ); |
| subRound( E, A, B, C, D, f2, K2, expand(ctx->buf, 21) ); |
| subRound( D, E, A, B, C, f2, K2, expand(ctx->buf, 22) ); |
| subRound( C, D, E, A, B, f2, K2, expand(ctx->buf, 23) ); |
| subRound( B, C, D, E, A, f2, K2, expand(ctx->buf, 24) ); |
| subRound( A, B, C, D, E, f2, K2, expand(ctx->buf, 25) ); |
| subRound( E, A, B, C, D, f2, K2, expand(ctx->buf, 26) ); |
| subRound( D, E, A, B, C, f2, K2, expand(ctx->buf, 27) ); |
| subRound( C, D, E, A, B, f2, K2, expand(ctx->buf, 28) ); |
| subRound( B, C, D, E, A, f2, K2, expand(ctx->buf, 29) ); |
| subRound( A, B, C, D, E, f2, K2, expand(ctx->buf, 30) ); |
| subRound( E, A, B, C, D, f2, K2, expand(ctx->buf, 31) ); |
| subRound( D, E, A, B, C, f2, K2, expand(ctx->buf, 32) ); |
| subRound( C, D, E, A, B, f2, K2, expand(ctx->buf, 33) ); |
| subRound( B, C, D, E, A, f2, K2, expand(ctx->buf, 34) ); |
| subRound( A, B, C, D, E, f2, K2, expand(ctx->buf, 35) ); |
| subRound( E, A, B, C, D, f2, K2, expand(ctx->buf, 36) ); |
| subRound( D, E, A, B, C, f2, K2, expand(ctx->buf, 37) ); |
| subRound( C, D, E, A, B, f2, K2, expand(ctx->buf, 38) ); |
| subRound( B, C, D, E, A, f2, K2, expand(ctx->buf, 39) ); |
| |
| subRound( A, B, C, D, E, f3, K3, expand(ctx->buf, 40) ); |
| subRound( E, A, B, C, D, f3, K3, expand(ctx->buf, 41) ); |
| subRound( D, E, A, B, C, f3, K3, expand(ctx->buf, 42) ); |
| subRound( C, D, E, A, B, f3, K3, expand(ctx->buf, 43) ); |
| subRound( B, C, D, E, A, f3, K3, expand(ctx->buf, 44) ); |
| subRound( A, B, C, D, E, f3, K3, expand(ctx->buf, 45) ); |
| subRound( E, A, B, C, D, f3, K3, expand(ctx->buf, 46) ); |
| subRound( D, E, A, B, C, f3, K3, expand(ctx->buf, 47) ); |
| subRound( C, D, E, A, B, f3, K3, expand(ctx->buf, 48) ); |
| subRound( B, C, D, E, A, f3, K3, expand(ctx->buf, 49) ); |
| subRound( A, B, C, D, E, f3, K3, expand(ctx->buf, 50) ); |
| subRound( E, A, B, C, D, f3, K3, expand(ctx->buf, 51) ); |
| subRound( D, E, A, B, C, f3, K3, expand(ctx->buf, 52) ); |
| subRound( C, D, E, A, B, f3, K3, expand(ctx->buf, 53) ); |
| subRound( B, C, D, E, A, f3, K3, expand(ctx->buf, 54) ); |
| subRound( A, B, C, D, E, f3, K3, expand(ctx->buf, 55) ); |
| subRound( E, A, B, C, D, f3, K3, expand(ctx->buf, 56) ); |
| subRound( D, E, A, B, C, f3, K3, expand(ctx->buf, 57) ); |
| subRound( C, D, E, A, B, f3, K3, expand(ctx->buf, 58) ); |
| subRound( B, C, D, E, A, f3, K3, expand(ctx->buf, 59) ); |
| |
| subRound( A, B, C, D, E, f4, K4, expand(ctx->buf, 60) ); |
| subRound( E, A, B, C, D, f4, K4, expand(ctx->buf, 61) ); |
| subRound( D, E, A, B, C, f4, K4, expand(ctx->buf, 62) ); |
| subRound( C, D, E, A, B, f4, K4, expand(ctx->buf, 63) ); |
| subRound( B, C, D, E, A, f4, K4, expand(ctx->buf, 64) ); |
| subRound( A, B, C, D, E, f4, K4, expand(ctx->buf, 65) ); |
| subRound( E, A, B, C, D, f4, K4, expand(ctx->buf, 66) ); |
| subRound( D, E, A, B, C, f4, K4, expand(ctx->buf, 67) ); |
| subRound( C, D, E, A, B, f4, K4, expand(ctx->buf, 68) ); |
| subRound( B, C, D, E, A, f4, K4, expand(ctx->buf, 69) ); |
| subRound( A, B, C, D, E, f4, K4, expand(ctx->buf, 70) ); |
| subRound( E, A, B, C, D, f4, K4, expand(ctx->buf, 71) ); |
| subRound( D, E, A, B, C, f4, K4, expand(ctx->buf, 72) ); |
| subRound( C, D, E, A, B, f4, K4, expand(ctx->buf, 73) ); |
| subRound( B, C, D, E, A, f4, K4, expand(ctx->buf, 74) ); |
| subRound( A, B, C, D, E, f4, K4, expand(ctx->buf, 75) ); |
| subRound( E, A, B, C, D, f4, K4, expand(ctx->buf, 76) ); |
| subRound( D, E, A, B, C, f4, K4, expand(ctx->buf, 77) ); |
| subRound( C, D, E, A, B, f4, K4, expand(ctx->buf, 78) ); |
| subRound( B, C, D, E, A, f4, K4, expand(ctx->buf, 79) ); |
| |
| // Build message digest |
| // |
| ctx->hash_value[0] += A; |
| ctx->hash_value[1] += B; |
| ctx->hash_value[2] += C; |
| ctx->hash_value[3] += D; |
| ctx->hash_value[4] += E; |
| } |
| |
| |
| // SHA is defined in big-endian form, so this converts the buffer from |
| // bytes to words, independent of the machine's native endianness. |
| // |
| // Assuming a consistent byte ordering for the machine, this also |
| // has the magic property of being self-inverse. It is used as |
| // such. |
| // |
| static void |
| byteReverse( unsigned int *buffer, |
| unsigned int byteCount ) |
| { |
| #ifndef __BYTE_ORDER |
| #error "Endianess MUST be defined" |
| #endif |
| #if __BYTE_ORDER == __LITTLE_ENDIAN |
| CK_ULONG value, val; |
| |
| byteCount /= sizeof(CK_ULONG_32); |
| |
| while (byteCount--) { |
| val = *buffer; |
| value = ((0x000000FF & val) << 24) | |
| ((0x0000FF00 & val) << 8 ) | |
| ((0x00FF0000 & val) >> 8 ) | |
| ((0xFF000000 & val) >> 24); |
| |
| *buffer++ = value; |
| } |
| #endif |
| |
| // JRM - this code gives funky results on Linux/Intel. |
| // I assume this is a GCC issue since regression tests passed on NT |
| // |
| // byteCount /= sizeof(CK_ULONG); |
| // while ( byteCount-- ) { |
| // value = (CK_ULONG)((unsigned)((CK_BYTE *)buffer)[0] << 8 | ((CK_BYTE *)buffer)[1]) << 16 | |
| // ((unsigned)((CK_BYTE *)buffer)[2] << 8 | ((CK_BYTE *)buffer)[3]); |
| // *buffer++ = value; |
| // } |
| } |
| |
| |
| void |
| shaUpdate( SHA1_CONTEXT * ctx, |
| CK_BYTE const * buffer, |
| CK_ULONG count) |
| { |
| CK_ULONG t; |
| |
| // Update bitcount |
| // |
| t = ctx->bits_lo; |
| if ((ctx->bits_lo = t + count) < t) |
| ctx->bits_hi++; // Carry from low to high |
| |
| t &= 0x3f; // Bytes already in ctx->buf |
| |
| // Handle any leading odd-sized chunks |
| // |
| if (t) { |
| CK_BYTE *p = (CK_BYTE *)ctx->buf + t; |
| |
| t = 64-t; |
| if (count < t) { |
| memcpy(p, buffer, count); |
| return; |
| } |
| memcpy(p, buffer, t); |
| byteReverse(ctx->buf, SHA1_BLOCK_SIZE); |
| shaTransform(ctx); |
| buffer += t; |
| count -= t; |
| } |
| |
| // Process data in SHA1_BLOCK_SIZE chunks |
| // |
| while (count >= SHA1_BLOCK_SIZE) { |
| memcpy(ctx->buf, buffer, SHA1_BLOCK_SIZE); |
| byteReverse(ctx->buf, SHA1_BLOCK_SIZE); |
| shaTransform(ctx); |
| buffer += SHA1_BLOCK_SIZE; |
| count -= SHA1_BLOCK_SIZE; |
| } |
| |
| // Handle any remaining bytes of data. |
| // |
| memcpy(ctx->buf, buffer, count); |
| } |
| |
| |
| // Final wrapup - pad to 64-byte boundary with the bit pattern |
| // 1 0* (64-bit count of bits processed, MSB-first) |
| // |
| void |
| shaFinal( SHA1_CONTEXT * ctx, |
| CK_BYTE * hash ) |
| { |
| int count; |
| CK_BYTE *p; |
| |
| // Compute number of bytes mod 64 |
| // |
| count = (int)ctx->bits_lo & 0x3F; |
| |
| // Set the first char of padding to 0x80. |
| // This is safe since there is always at least one byte free |
| // |
| p = (CK_BYTE *)ctx->buf + count; |
| *p++ = 0x80; |
| |
| // Bytes of padding needed to make 64 bytes |
| // |
| count = SHA1_BLOCK_SIZE - 1 - count; |
| |
| // Pad out to 56 mod 64 |
| // |
| if (count < 8) { |
| // Two lots of padding: Pad the first block to 64 bytes |
| // |
| memset(p, 0, count); |
| byteReverse(ctx->buf, SHA1_BLOCK_SIZE); |
| shaTransform(ctx); |
| |
| // Now fill the next block with 56 bytes |
| // |
| memset(ctx->buf, 0, SHA1_BLOCK_SIZE-8); |
| } else { |
| // Pad block to 56 bytes |
| // |
| memset(p, 0, count-8); |
| } |
| byteReverse(ctx->buf, SHA1_BLOCK_SIZE-8); |
| |
| // Append length in *bits* and transform |
| // |
| ctx->buf[14] = ctx->bits_hi << 3 | ctx->bits_lo >> 29; |
| ctx->buf[15] = ctx->bits_lo << 3; |
| |
| shaTransform(ctx); |
| |
| // Store output hash in buffer |
| // |
| byteReverse(ctx->hash_value, SHA1_HASH_SIZE); |
| memcpy(hash, ctx->hash_value, SHA1_HASH_SIZE); |
| } |