sha.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Cylink Corporation � 1998
*
* This software is licensed by Cylink to the Internet Software Consortium to
* promote implementation of royalty free public key cryptography within IETF
* standards. Cylink wishes to expressly thank the contributions of Dr.
* Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
* their contributions to Internet Security. In accordance with the terms of
* this license, ISC is authorized to distribute and sublicense this software
* for the practice of IETF standards.
*
* The software includes BigNum, written by Colin Plumb and licensed by Philip
* R. Zimmermann for royalty free use and distribution with Cylink's
* software. Use of BigNum as a stand alone product or component is
* specifically prohibited.
*
* Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
* WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
* PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
* MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
* PURPOSE.
*
* Cylink or its representatives shall not be liable for tort, indirect,
* special or consequential damages such as loss of profits or loss of
* goodwill from the use or inability to use the software for any purpose or
* for any reason whatsoever.
*
* EXPORT LAW: Export of the Foundations Suite may be subject to compliance
* with the rules and regulations promulgated from time to time by the Bureau
* of Export Administration, United States Department of Commerce, which
* restrict the export and re-export of certain products and technical data.
* If the export of the Foundations Suite is controlled under such rules and
* regulations, then the Foundations Suite shall not be exported or
* re-exported, directly or indirectly, (a) without all export or re-export
* licenses and governmental approvals required by any applicable laws, or (b)
* in violation of any applicable prohibition against the export or re-export
* of any part of the Foundations Suite. All export licenses for software
* containing the Foundations Suite are the sole responsibility of the licensee.
*/
/****************************************************************************
* FILENAME: cencrint.c PRODUCT NAME: CRYPTOGRAPHIC TOOLKIT
*
* FILE STATUS:
*
* DESCRIPTION: Cryptographic Toolkit Internal Functions File
*
* PRIVATE FUNCTIONS:
*
*
* void shaTransform( u_int32_t *state, uchar *block )
* void SHAInitK( SHA_context *hash_context )
* int MySHA( uchar *message, u_int16_t message_bytes,
* uchar *hash_result )
* int MySHAFinal( SHA_context *hash_context, uchar *hash_result )
*
*
* Copyright (c) Cylink Corporation 1994. All rights reserved.
*
* REVISION HISTORY:
*
*
* 24 Sep 94 KPZ Initial release
* 10 Oct 94 KPZ Fixed bugs in Add(), DivRem()
* 12 Oct 94 KPZ Modified shaTransform()
* 14 Oct 94 GKL Second version (big endian support)
* 26 Oct 94 GKL (alignment for big endian support & ERR_ALLOC)
* 08 Nov 94 GKL Added input parameters check to Inverse
* 08 Dec 94 GKL Added YIELD_context to Expo, VerPrime and GenPrime
*
****************************************************************************/
#pragma ident "%Z%%M% %I% %E% SMI"
/****************************************************************************
* INCLUDE FILES
****************************************************************************/
#include "port_before.h"
#include <sys/types.h>
/* system files */
#ifdef VXD
#include <vtoolsc.h>
#else
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#endif
/* program files */
#include "cylink.h"
#include "ctk_endian.h"
#include "toolkit.h"
#include "cencrint.h"
#include "sha.h"
#include "port_after.h"
extern u_int16_t DataOrder;
/****************************************************************************
* NAME: int SHA( uchar *message,
* u_int16_t message_bytes,
* uchar *hash_result )
*
* DESCRIPTION: Compute a Secure Hash Function.
*
* INPUTS:
* PARAMETERS:
* uchar *message Pointer to message
* u_int16_t message_bytes Number of bytes in message
* uchar *hash_result Pointer to message digest
*
* OUTPUT:
* PARAMETERS:
* uchar *hash_result Message digest
*
* RETURN:
* SUCCESS No errors
* ERR_INPUT_LEN Invalid length for input data(zero bytes)
* REVISION HISTORY:
*
* 24 Sep 94 KPZ Initial release
*
****************************************************************************/
int SHA( uchar *message,
u_int16_t message_bytes,
uchar *hash_result )
{
SHA_context hash_context; /* SHA context structure */
int status = SUCCESS; /* function return status */
if (message_bytes == 0 )
{
status = ERR_INPUT_LEN;
return status; /* invalid length for input data */
}
SHAInit ( &hash_context ); /* initialize SHA */
if ( (status = SHAUpdate( &hash_context, message, message_bytes ))
!= SUCCESS )
{
return status; /* error */
}
if ((status=SHAFinal (&hash_context, hash_result)) != SUCCESS )
{
return status; /* error */
}
return status;
}
/****************************************************************************
* PRIVATE FUNCTIONS DEFINITIONS
****************************************************************************/
/****************************************************************************
* NAME: void shaTransform( u_int32_t *state,
* uchar *block )
*
* DESCRIPTION: Perform SHS transformation.
*
* INPUTS:
* PARAMETERS:
* SHA_context *hash_context Pointer to SHA_context structure
* OUTPUT:
*
* SHA_context *hash_context Pointer to SHA_context structure
* (updated)
* REVISION HISTORY:
*
* 24 sep 94 KPZ Initial release
* 12 Oct 94 KPZ Modified buffers copy
* 14 Oct 94 GKL Second version (big endian support)
* 1 Sep 95 AAB Speedup the function
****************************************************************************/
void shaTransform( u_int32_t *state,
const uchar *block )
{
u_int32_t W[80];
u_int32_t A,B,C,D,E; /*,temp;*/
memcpy( W, block, 64); /*TKL00201*/
#ifdef CTK_LITTLE_ENDIAN /*TKL00201*/
ByteSwap32( (uchar *)W, 64); /*TKL00201*/
#endif /*TKL00201*/
/* Expand the 16 words into 80 words */
expand(16);expand(17);expand(18);expand(19);expand(20);expand(21);
expand(22);expand(23);expand(24);expand(25);expand(26);expand(27);
expand(28);expand(29);expand(30);expand(31);expand(32);expand(33);
expand(34);expand(35);expand(36);expand(37);expand(38);expand(39);
expand(40);expand(41);expand(42);expand(43);expand(44);expand(45);
expand(46);expand(47);expand(48);expand(49);expand(50);expand(51);
expand(52);expand(53);expand(54);expand(55);expand(56);expand(57);
expand(58);expand(59);expand(60);expand(61);expand(62);expand(63);
expand(64);expand(65);expand(66);expand(67);expand(68);expand(69);
expand(70);expand(71);expand(72);expand(73);expand(74);expand(75);
expand(76);expand(77);expand(78);expand(79);
/*Set up first buffer*/
A = state[0];
B = state[1];
C = state[2];
D = state[3];
E = state[4];
/* Heavy mangling, in 4 sub-rounds of 20 iterations each. */
subRound( A, B, C, D, E, f1, k1SHA, W[ 0] );
subRound( E, A, B, C, D, f1, k1SHA, W[ 1] );
subRound( D, E, A, B, C, f1, k1SHA, W[ 2] );
subRound( C, D, E, A, B, f1, k1SHA, W[ 3] );
subRound( B, C, D, E, A, f1, k1SHA, W[ 4] );
subRound( A, B, C, D, E, f1, k1SHA, W[ 5] );
subRound( E, A, B, C, D, f1, k1SHA, W[ 6] );
subRound( D, E, A, B, C, f1, k1SHA, W[ 7] );
subRound( C, D, E, A, B, f1, k1SHA, W[ 8] );
subRound( B, C, D, E, A, f1, k1SHA, W[ 9] );
subRound( A, B, C, D, E, f1, k1SHA, W[10] );
subRound( E, A, B, C, D, f1, k1SHA, W[11] );
subRound( D, E, A, B, C, f1, k1SHA, W[12] );
subRound( C, D, E, A, B, f1, k1SHA, W[13] );
subRound( B, C, D, E, A, f1, k1SHA, W[14] );
subRound( A, B, C, D, E, f1, k1SHA, W[15] );
subRound( E, A, B, C, D, f1, k1SHA, W[16] );
subRound( D, E, A, B, C, f1, k1SHA, W[17] );
subRound( C, D, E, A, B, f1, k1SHA, W[18] );
subRound( B, C, D, E, A, f1, k1SHA, W[19] );
subRound( A, B, C, D, E, f2, k2SHA, W[20]);
subRound( E, A, B, C, D, f2, k2SHA, W[21]);
subRound( D, E, A, B, C, f2, k2SHA, W[22]);
subRound( C, D, E, A, B, f2, k2SHA, W[23]);
subRound( B, C, D, E, A, f2, k2SHA, W[24]);
subRound( A, B, C, D, E, f2, k2SHA, W[25]);
subRound( E, A, B, C, D, f2, k2SHA, W[26]);
subRound( D, E, A, B, C, f2, k2SHA, W[27]);
subRound( C, D, E, A, B, f2, k2SHA, W[28]);
subRound( B, C, D, E, A, f2, k2SHA, W[29]);
subRound( A, B, C, D, E, f2, k2SHA, W[30]);
subRound( E, A, B, C, D, f2, k2SHA, W[31]);
subRound( D, E, A, B, C, f2, k2SHA, W[32]);
subRound( C, D, E, A, B, f2, k2SHA, W[33]);
subRound( B, C, D, E, A, f2, k2SHA, W[34]);
subRound( A, B, C, D, E, f2, k2SHA, W[35]);
subRound( E, A, B, C, D, f2, k2SHA, W[36]);
subRound( D, E, A, B, C, f2, k2SHA, W[37]);
subRound( C, D, E, A, B, f2, k2SHA, W[38]);
subRound( B, C, D, E, A, f2, k2SHA, W[39]);
subRound( A, B, C, D, E, f3, k3SHA, W[40]);
subRound( E, A, B, C, D, f3, k3SHA, W[41]);
subRound( D, E, A, B, C, f3, k3SHA, W[42]);
subRound( C, D, E, A, B, f3, k3SHA, W[43]);
subRound( B, C, D, E, A, f3, k3SHA, W[44]);
subRound( A, B, C, D, E, f3, k3SHA, W[45]);
subRound( E, A, B, C, D, f3, k3SHA, W[46]);
subRound( D, E, A, B, C, f3, k3SHA, W[47]);
subRound( C, D, E, A, B, f3, k3SHA, W[48]);
subRound( B, C, D, E, A, f3, k3SHA, W[49]);
subRound( A, B, C, D, E, f3, k3SHA, W[50]);
subRound( E, A, B, C, D, f3, k3SHA, W[51]);
subRound( D, E, A, B, C, f3, k3SHA, W[52]);
subRound( C, D, E, A, B, f3, k3SHA, W[53]);
subRound( B, C, D, E, A, f3, k3SHA, W[54]);
subRound( A, B, C, D, E, f3, k3SHA, W[55]);
subRound( E, A, B, C, D, f3, k3SHA, W[56]);
subRound( D, E, A, B, C, f3, k3SHA, W[57]);
subRound( C, D, E, A, B, f3, k3SHA, W[58]);
subRound( B, C, D, E, A, f3, k3SHA, W[59]);
subRound( A, B, C, D, E, f4, k4SHA, W[60]);
subRound( E, A, B, C, D, f4, k4SHA, W[61]);
subRound( D, E, A, B, C, f4, k4SHA, W[62]);
subRound( C, D, E, A, B, f4, k4SHA, W[63]);
subRound( B, C, D, E, A, f4, k4SHA, W[64]);
subRound( A, B, C, D, E, f4, k4SHA, W[65]);
subRound( E, A, B, C, D, f4, k4SHA, W[66]);
subRound( D, E, A, B, C, f4, k4SHA, W[67]);
subRound( C, D, E, A, B, f4, k4SHA, W[68]);
subRound( B, C, D, E, A, f4, k4SHA, W[69]);
subRound( A, B, C, D, E, f4, k4SHA, W[70]);
subRound( E, A, B, C, D, f4, k4SHA, W[71]);
subRound( D, E, A, B, C, f4, k4SHA, W[72]);
subRound( C, D, E, A, B, f4, k4SHA, W[73]);
subRound( B, C, D, E, A, f4, k4SHA, W[74]);
subRound( A, B, C, D, E, f4, k4SHA, W[75]);
subRound( E, A, B, C, D, f4, k4SHA, W[76]);
subRound( D, E, A, B, C, f4, k4SHA, W[77]);
subRound( C, D, E, A, B, f4, k4SHA, W[78]);
subRound( B, C, D, E, A, f4, k4SHA, W[79]);
state[0] += A;
state[1] += B;
state[2] += C;
state[3] += D;
state[4] += E;
}
/****************************************************************************
* NAME: void SHAInitK( SHA_context *hash_context )
*
* DESCRIPTION: Initialize Secure Hash Function for generate
* random number for DSS.
*
* INPUTS:
* PARAMETERS:
* SHA_context *hash_context SHA context structure
* OUTPUT:
* PARAMETERS:
* SHA_context *hash_context Initialized SHA context structure
*
* RETURN:
*
* REVISION HISTORY:
*
* 24 Sep 94 KPZ Initial release
* 14 Oct 94 GKL Second version (big endian support)
*
****************************************************************************/
void SHAInitK( SHA_context *hash_context )
{
/*Set up first buffer*/
/* on28 port: silence compiler warnings by changing 0x...L to 0x...U */
hash_context->state[0] = 0xEFCDAB89U;
hash_context->state[1] = 0x98BADCFEU;
hash_context->state[2] = 0x10325476U;
hash_context->state[3] = 0xC3D2E1F0U;
hash_context->state[4] = 0x67452301U;
/*Initialise buffer */
memset( hash_context->buffer, 0, sizeof(hash_context->buffer));
memset( hash_context->count, 0, sizeof(hash_context->count));
}
/****************************************************************************
* NAME: int MySHA( uchar *message,
* u_int16_t message_bytes,
* uchar *hash_result )
*
* DESCRIPTION: Compute a Secure Hash Function.
*
* INPUTS:
* PARAMETERS:
* uchar *message Pointer to message
* u_int16_t message_bytes Number of bytes in message
* uchar *hash_result Pointer to message digest
*
* OUTPUT:
* PARAMETERS:
* uchar *hash_result Message digest
*
* RETURN:
* SUCCESS No errors
* ERR_INPUT_LEN Invalid length for input data(zero bytes)
* REVISION HISTORY:
*
* 24 Sep 94 KPZ Initial release
*
****************************************************************************/
int MySHA( uchar *message,
u_int16_t message_bytes,
uchar *hash_result )
{
SHA_context hash_context; /* SHA context structure */
int status = SUCCESS; /* function return status */
if (message_bytes == 0 )
{
status = ERR_INPUT_LEN;
return status; /* invalid length for input data */
}
SHAInit ( &hash_context ); /* initialize SHA */
#ifdef CTK_BIG_ENDIAN
ByteSwap(message,message_bytes);
#endif
status = SHAUpdate( &hash_context, message, message_bytes );
#ifdef CTK_BIG_ENDIAN
ByteSwap(message,message_bytes);
#endif
if ( status != SUCCESS )
{
return status; /* error */
}
if ((status=MySHAFinal (&hash_context, hash_result)) != SUCCESS )
{
return status; /* error */
}
return status;
}
/****************************************************************************
* NAME: int MySHAFinal( SHA_context *hash_context,
* uchar *hash_result )
* DESCRIPTION: Finalize Secure Hash Function
*
* INPUTS:
* PARAMETERS:
* SHA_context *hash_context SHA context structure
* uchar *hash_result Pointer to hash
* OUTPUT:
* PARAMETERS:
* uchar *hash_result Final value
* RETURN:
* SUCCESS No errors
* ERR_INPUT_LEN Invalid length for input data (zero bytes)
* REVISION HISTORY:
*
* 24 Sep 94 KPZ Initial release
* 10 Oct 94 KPZ Modified for arbitrary message length
* 14 Oct 94 GKL Second version (big endian support)
*
****************************************************************************/
int MySHAFinal( SHA_context *hash_context,
uchar *hash_result )
{
int status = SUCCESS; /* function return status */
uchar bits[8];
u_int16_t index, padLen;
u_int32_t ex;
uchar PADDING[64] = { /* padding string */
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
if ( hash_context->count[0] == 0 && hash_context->count[1] == 0 )
{
status= ERR_INPUT_LEN;
return status;
}
/* Save number of bits */
LongByte( &hash_context->count[1] , 4, bits );
LongByte( &hash_context->count[0] , 4, bits + 4 );
ByteSwap32( bits, 8 );
/* Pad out to 56 mod 64.*/
index = (u_int16_t )((hash_context->count[0] >> 3) & 0x3f);
padLen = (u_int16_t) ((index < 56) ? (56 - index) : (120 - index));
SHAUpdate( hash_context, PADDING, padLen );
/* Append length (before padding) */
SHAUpdate (hash_context, bits, 8);
/* Set order of hash_context */
ex = hash_context->state[0];
hash_context->state[0] = hash_context->state[4];
hash_context->state[4] = ex;
ex = hash_context->state[1];
hash_context->state[1] = hash_context->state[3];
hash_context->state[3] = ex;
/* Store state in digest */
memcpy(hash_result,hash_context->state,SHA_LENGTH);
/* Zeroize sensitive information.*/
memset( hash_context, 0, sizeof(hash_context) );
#if defined ( ORD_16 ) && defined( CTK_BIG_ENDIAN )
WordSwap(hash_result,SHA_LENGTH);
#endif
return status;
}
/****************************************************************************
* NAME: int SHAUpdate( SHA_context *hash_context,
* uchar *message,
* u_int16_t message_bytes )
* DESCRIPTION: Update Secure Hash Function
*
* INPUTS:
* PARAMETERS:
* SHA_context *hash_context SHA context structure
* uchar *message Pointer to message
* u_int16_t message_bytes Number of bytes
* OUTPUT:
* PARAMETERS:
* SHA_context *hash_context Updated SHA context structure
*
* RETURN:
* SUCCESS No errors
* ERR_INPUT_LEN Invalid length for input data (zero bytes)
* REVISION HISTORY:
*
* 24 Sep 94 KPZ Initial release
* 10 Oct 94 KPZ Modified for arbitrary message length
*
****************************************************************************/
int SHAUpdate( SHA_context *hash_context,
const uchar *message,
u_int16_t message_bytes )
{
int status = SUCCESS; /* function return status */
u_int16_t i, index, partLen;
if ( message_bytes == 0 )
{
status = ERR_INPUT_LEN; /*invalid length for input data (zero bytes)*/
return status;
}
/* Compute number of bytes mod 64 */
index = (u_int16_t)((hash_context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ( (hash_context->count[0] += ((u_int32_t )message_bytes << 3))
< ((u_int32_t )message_bytes << 3) )
{
hash_context->count[1]++;
}
hash_context->count[1] += ((u_int32_t )message_bytes >> 29);
partLen = (u_int16_t) (64 - index);
/* Transform as many times as possible.*/
if ( message_bytes >= partLen )
{
memcpy( &hash_context->buffer[index], message, partLen );
shaTransform( hash_context->state, hash_context->buffer );
for ( i = partLen; (u_int16_t)(i + 63) < message_bytes; i += 64 )
{
shaTransform ( hash_context->state, &message[i] );
}
index = 0;
}
else
{
i = 0;
}
/* Buffer remaining input */
memcpy( &hash_context->buffer[index], &message[i],
message_bytes - i );
return status;
}
/****************************************************************************
* NAME: void SHAInit( SHA_context *hash_context )
*
* DESCRIPTION: Initialize Secure Hash Function
*
* INPUTS:
* PARAMETERS:
* SHA_context *hash_context SHA context structure
* OUTPUT:
* PARAMETERS:
* SHA_context *hash_context Initialized SHA context structure
*
* RETURN:
*
* REVISION HISTORY:
*
* 24 Sep 94 KPZ Initial release
*
****************************************************************************/
void SHAInit( SHA_context *hash_context )
{
/*Set up first buffer*/
hash_context->state[0] = h0SHA;
hash_context->state[1] = h1SHA;
hash_context->state[2] = h2SHA;
hash_context->state[3] = h3SHA;
hash_context->state[4] = h4SHA;
/* Initialise buffer */
memset( hash_context->buffer, 0, sizeof(hash_context->buffer));
/*Initialize bit count*/
hash_context->count[0] = hash_context->count[1] = 0;
}
/****************************************************************************
* NAME: int SHAFinal( SHA_context *hash_context,
* uchar *hash_result )
* DESCRIPTION: Finalize Secure Hash Function
*
* INPUTS:
* PARAMETERS:
* SHA_context *hash_context SHA context structure
* uchar *hash_result Pointer to hash
* OUTPUT:
* PARAMETERS:
* uchar *hash_result Final value
* RETURN:
* SUCCESS No errors
* ERR_INPUT_LEN Invalid length for input data (zero bytes)
* REVISION HISTORY:
*
* 24 Sep 94 KPZ Initial release
* 10 Oct 94 KPZ Modified for arbitrary message length
* 14 Oct 94 GKL Second version (big endian support)
*
****************************************************************************/
int SHAFinal( SHA_context *hash_context,
uchar *hash_result )
{
int status = SUCCESS; /* function return status */
status = MySHAFinal( hash_context, hash_result );
#ifdef CTK_BIG_ENDIAN
if (status == SUCCESS)
{
ByteSwap(hash_result, SHA_LENGTH);
}
#endif
if (DataOrder)
{
BigSwap(hash_result, SHA_LENGTH);
}
return status;
}
/****************************************************************************
* NAME: int GetPasswordKeySHA( u_int16_t Password_bytes,
* uchar *Password,
* uchar *salt,
* u_int16_t Count,
* uchar *K,
* uchar *IV )
*
* DESCRIPTION: Get Password-Based DES/KAPPA Key by SHA
*
* INPUTS:
* PARAMETERS:
* u_int16_t Password_bytes Number of bytes in password
* uchar *Password Pointer to password
* uchar *salt Pointer to salt(8-byte)
* u_int16_t Count Number of iteration
* OUTPUT:
* PARAMETERS:
* uchar *K Pointer to DES/KAPPA key
* uchar *IV Pointer to initialization vector
* RETURN:
* SUCCESS No errors
* ERR_COUNT Invalid iteration count (zero)
* ERR_INPUT_LEN Invalid length for input data(zero bytes)
* ERR_ALLOC Insufficient memory
* REVISION HISTORY:
*
* 24 Sep 94 KPZ Initial release
* 26 Oct 94 GKL (ERR_ALLOC)
*
****************************************************************************/
int GetPasswordKeySHA( u_int16_t Password_bytes,
uchar *Password,
uchar *salt,
u_int16_t Count,
uchar *K,
uchar *IV )
{
int status = SUCCESS; /* function return status */
uchar digest[SHA_LENGTH];
uchar *buf;
if ( Count == 0 ) /* invalid iteration count (zero) */
{
status = ERR_COUNT;
return status;
}
CALLOC(buf,uchar,Password_bytes + 8);
if ( status != SUCCESS )
{
return status; /* ERR_ALLOC insufficient memory */
}
if ( Password_bytes != 0 ) /* if number of bytes password non equals zero */
{
memcpy( buf, Password, Password_bytes );
}
memcpy( buf + Password_bytes, salt, 8);
/* Compute message digest */
status = SHA( buf, (u_int16_t)(Password_bytes + 8), digest);
if (!DataOrder)
{
BigSwap(digest, SHA_LENGTH);
}
if ( status != SUCCESS )
{
free ( buf );
return status;
}
Count --; /* decrement Count */
/* Count times compute message digest */
while ( Count != 0 )
{
if ( (status = SHA( digest, SHA_LENGTH, digest)) != SUCCESS )
{
free ( buf );
return status;
}
if (!DataOrder)
{
BigSwap(digest, SHA_LENGTH);
}
Count --;
}
memcpy( K, digest, 8 );
memcpy( IV, digest + SHA_LENGTH -8, 8 );
free ( buf );
return status;
}