home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
crypl200.zip
/
LIB_DSA.C
< prev
next >
Wrap
Text File
|
1996-10-06
|
14KB
|
396 lines
/****************************************************************************
* *
* cryptlib DSA Encryption Routines *
* Copyright Peter Gutmann 1995-1996 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "crypt.h"
/****************************************************************************
* *
* DSA Self-test Routines *
* *
****************************************************************************/
/* Test the DSA implementation using the sample key from FIPS 186. Because a
lot of the high-level encryption routines don't exist yet, we cheat a bit
and set up a dummy encryption context with just enough information for the
following code to work */
typedef struct {
int pLen; BYTE p[ 64 ];
int qLen; BYTE q[ 20 ];
int gLen; BYTE g[ 64 ];
int xLen; BYTE x[ 20 ];
int yLen; BYTE y[ 64 ];
} DSA_PRIVKEY;
static DSA_PRIVKEY dsaTestKey = {
/* p */
512,
{ 0x8D, 0xF2, 0xA4, 0x94, 0x49, 0x22, 0x76, 0xAA,
0x3D, 0x25, 0x75, 0x9B, 0xB0, 0x68, 0x69, 0xCB,
0xEA, 0xC0, 0xD8, 0x3A, 0xFB, 0x8D, 0x0C, 0xF7,
0xCB, 0xB8, 0x32, 0x4F, 0x0D, 0x78, 0x82, 0xE5,
0xD0, 0x76, 0x2F, 0xC5, 0xB7, 0x21, 0x0E, 0xAF,
0xC2, 0xE9, 0xAD, 0xAC, 0x32, 0xAB, 0x7A, 0xAC,
0x49, 0x69, 0x3D, 0xFB, 0xF8, 0x37, 0x24, 0xC2,
0xEC, 0x07, 0x36, 0xEE, 0x31, 0xC8, 0x02, 0x91 },
/* q */
160,
{ 0xC7, 0x73, 0x21, 0x8C, 0x73, 0x7E, 0xC8, 0xEE,
0x99, 0x3B, 0x4F, 0x2D, 0xED, 0x30, 0xF4, 0x8E,
0xDA, 0xCE, 0x91, 0x5F },
/* g */
512,
{ 0x62, 0x6D, 0x02, 0x78, 0x39, 0xEA, 0x0A, 0x13,
0x41, 0x31, 0x63, 0xA5, 0x5B, 0x4C, 0xB5, 0x00,
0x29, 0x9D, 0x55, 0x22, 0x95, 0x6C, 0xEF, 0xCB,
0x3B, 0xFF, 0x10, 0xF3, 0x99, 0xCE, 0x2C, 0x2E,
0x71, 0xCB, 0x9D, 0xE5, 0xFA, 0x24, 0xBA, 0xBF,
0x58, 0xE5, 0xB7, 0x95, 0x21, 0x92, 0x5C, 0x9C,
0xC4, 0x2E, 0x9F, 0x6F, 0x46, 0x4B, 0x08, 0x8C,
0xC5, 0x72, 0xAF, 0x53, 0xE6, 0xD7, 0x88, 0x02 },
/* x */
160,
{ 0x20, 0x70, 0xB3, 0x22, 0x3D, 0xBA, 0x37, 0x2F,
0xDE, 0x1C, 0x0F, 0xFC, 0x7B, 0x2E, 0x3B, 0x49,
0x8B, 0x26, 0x06, 0x14 },
/* y */
512,
{ 0x19, 0x13, 0x18, 0x71, 0xD7, 0x5B, 0x16, 0x12,
0xA8, 0x19, 0xF2, 0x9D, 0x78, 0xD1, 0xB0, 0xD7,
0x34, 0x6F, 0x7A, 0xA7, 0x7B, 0xB6, 0x2A, 0x85,
0x9B, 0xFD, 0x6C, 0x56, 0x75, 0xDA, 0x9D, 0x21,
0x2D, 0x3A, 0x36, 0xEF, 0x16, 0x72, 0xEF, 0x66,
0x0B, 0x8C, 0x7C, 0x25, 0x5C, 0xC0, 0xEC, 0x74,
0x85, 0x8F, 0xBA, 0x33, 0xF4, 0x4C, 0x06, 0x69,
0x96, 0x30, 0xA7, 0x6B, 0x03, 0x0E, 0xE3, 0x33 }
};
#if 0
k = 0x35, 0x8D, 0xAD, 0x57, 0x14, 0x62, 0x71, 0x0F,
0x50, 0xE2, 0x54, 0xCF, 0x1A, 0x37, 0x6B, 0x2B,
0xDE, 0xAA, 0xDF, 0xBF
kinv =
0x0D, 0x51, 0x67, 0x29, 0x82, 0x02, 0xE4, 0x9B,
0x41, 0x16, 0xAC, 0x10, 0x4F, 0xC3, 0xF4, 0x15,
0xAE, 0x52, 0xF9, 0x17
SHA(M) =
0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A,
0xBA, 0x3E, 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C,
0x9C, 0xD0, 0xD8, 0x9D
r = 0x8B, 0xAC, 0x1A, 0xB6, 0x64, 0x10, 0x43, 0x5C,
0xB7, 0x18, 0x1F, 0x95, 0xB1, 0x6A, 0xB9, 0x7C,
0x92, 0xB3, 0x41, 0xC0
s = 0x41, 0xE2, 0x34, 0x5F, 0x1F, 0x56, 0xDF, 0x24,
0x58, 0xF4, 0x26, 0xD1, 0x55, 0xB4, 0xBA, 0x2D,
0xB6, 0xDC, 0xD8, 0xC8
w = 0x9D, 0xF4, 0xEC, 0xE5, 0x82, 0x6B, 0xE9, 0x5F,
0xED, 0x40, 0x6D, 0x41, 0xB4, 0x3E, 0xDC, 0x0B,
0x1C, 0x18, 0x84, 0x1B
u1 =
0xBF, 0x65, 0x5B, 0xD0, 0x46, 0xF0, 0xB3, 0x5E,
0xC7, 0x91, 0xB0, 0x04, 0x80, 0x4A, 0xFC, 0xBB,
0x8E, 0xF7, 0xD6, 0x9D
u2 =
0x82, 0x1A, 0x92, 0x63, 0x12, 0xE9, 0x7A, 0xDE,
0xAB, 0xCC, 0x8D, 0x08, 0x2B, 0x52, 0x78, 0x97,
0x8A, 0x2D, 0xF4, 0xB0
gu1 moD p =
0x51, 0xB1, 0xBF, 0x86, 0x78, 0x88, 0xE5, 0xF3,
0xAF, 0x6F, 0xB4, 0x76, 0x9D, 0xD0, 0x16, 0xBC,
0xFE, 0x66, 0x7A, 0x65, 0xAA, 0xFC, 0x27, 0x53,
0x90, 0x63, 0xBD, 0x3D, 0x2B, 0x13, 0x8B, 0x4C,
0xE0, 0x2C, 0xC0, 0xC0, 0x2E, 0xC6, 0x2B, 0xB6,
0x73, 0x06, 0xC6, 0x3E, 0x4D, 0xB9, 0x5B, 0xBF,
0x6F, 0x96, 0x66, 0x2A, 0x19, 0x87, 0xA2, 0x1B,
0xE4, 0xEC, 0x10, 0x71, 0x01, 0x0B, 0x60, 0x69
yu2 moD p =
0x8B, 0x51, 0x00, 0x71, 0x29, 0x57, 0xE9, 0x50,
0x50, 0xD6, 0xB8, 0xFD, 0x37, 0x6A, 0x66, 0x8E,
0x4B, 0x0D, 0x63, 0x3C, 0x1E, 0x46, 0xE6, 0x65,
0x5C, 0x61, 0x1A, 0x72, 0xE2, 0xB2, 0x84, 0x83,
0xBE, 0x52, 0xC7, 0x4D, 0x4B, 0x30, 0xDE, 0x61,
0xA6, 0x68, 0x96, 0x6E, 0xDC, 0x30, 0x7A, 0x67,
0xC1, 0x94, 0x41, 0xF4, 0x22, 0xBF, 0x3C, 0x34,
0x08, 0xAE, 0xBA, 0x1F, 0x0A, 0x4D, 0xBE, 0xC7
v = 0x8B, 0xAC, 0x1A, 0xB6, 0x64, 0x10, 0x43, 0x5C,
0xB7, 0x18, 0x1F, 0x95, 0xB1, 0x6A, 0xB9, 0x7C,
0x92, 0xB3, 0x41, 0xC0
#endif
int dsaInitKey( CRYPT_INFO *cryptInfo );
int dsaEncrypt( CRYPT_INFO *cryptInfo, BYTE *buffer, int noBytes );
int dsaDecrypt( CRYPT_INFO *cryptInfo, BYTE *buffer, int noBytes );
int dsaSelfTest( void )
{
CRYPT_INFO cryptInfo;
CRYPT_PKCINFO_DSA *dsaKey;
CAPABILITY_INFO capabilityInfo = { CRYPT_ALGO_DSA, CRYPT_MODE_PKC, 0,
NULL, NULL, CRYPT_ERROR, 64, 128, 512,
0, 0, 0, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
CRYPT_ERROR, NULL };
BYTE buffer[ 64 ];
int status;
/* Allocate room for the public-key components */
if( ( dsaKey = ( CRYPT_PKCINFO_DSA * ) malloc( sizeof( CRYPT_PKCINFO_DSA ) ) ) == NULL )
return( CRYPT_NOMEM );
/* Initialise the BigNum information and components */
memset( &cryptInfo, 0, sizeof( CRYPT_INFO ) );
bnBegin( &cryptInfo.pkcParam1 );
bnBegin( &cryptInfo.pkcParam2 );
bnBegin( &cryptInfo.pkcParam3 );
bnBegin( &cryptInfo.pkcParam4 );
bnBegin( &cryptInfo.pkcParam5 );
bnBegin( &cryptInfo.pkcParam6 );
bnBegin( &cryptInfo.pkcParam7 );
bnBegin( &cryptInfo.pkcParam8 );
cryptInfo.keyComponentsLittleEndian = FALSE;
cryptInitComponents( dsaKey, CRYPT_COMPONENTS_BIGENDIAN,
CRYPT_KEYTYPE_PRIVATE );
cryptSetComponent( dsaKey->p, dsaTestKey.p, dsaTestKey.pLen );
cryptSetComponent( dsaKey->q, dsaTestKey.q, dsaTestKey.qLen );
cryptSetComponent( dsaKey->g, dsaTestKey.g, dsaTestKey.gLen );
cryptSetComponent( dsaKey->x, dsaTestKey.x, dsaTestKey.xLen );
cryptSetComponent( dsaKey->y, dsaTestKey.y, dsaTestKey.yLen );
cryptInfo.keyComponentPtr = dsaKey;
cryptInfo.capabilityInfo = &capabilityInfo;
/* Perform the test en/decryption of a block of data */
memset( buffer, 0, 64 );
memcpy( buffer, "abcde", 5 );
dsaInitKey( &cryptInfo );
#if 0 /* Make sure noone uses us for now */
if( ( status = dsaEncrypt( &cryptInfo, buffer, CRYPT_USE_DEFAULT ) ) == CRYPT_OK )
status = dsaDecrypt( &cryptInfo, buffer, CRYPT_USE_DEFAULT );
if( status != CRYPT_OK || memcmp( buffer, "abcde", 5 ) )
#endif /* 0 */
status = CRYPT_SELFTEST;
/* Clean up */
cryptDestroyComponents( dsaKey );
bnEnd( &cryptInfo.pkcParam1 );
bnEnd( &cryptInfo.pkcParam2 );
bnEnd( &cryptInfo.pkcParam3 );
bnEnd( &cryptInfo.pkcParam4 );
bnEnd( &cryptInfo.pkcParam5 );
bnEnd( &cryptInfo.pkcParam6 );
bnEnd( &cryptInfo.pkcParam7 );
bnEnd( &cryptInfo.pkcParam8 );
zeroise( &cryptInfo, sizeof( CRYPT_INFO ) );
free( dsaKey );
return( status );
}
/****************************************************************************
* *
* Init/Shutdown Routines *
* *
****************************************************************************/
/* Not needed for the DSA routines */
/****************************************************************************
* *
* DSA En/Decryption Routines *
* *
****************************************************************************/
/* Encrypt (sign) a single block of data */
int dsaEncrypt( CRYPT_INFO *cryptInfo, BYTE *buffer, int noBytes )
{
BIGNUM *p = &cryptInfo->dsaParam_p, *q = &cryptInfo->dsaParam_q;
BIGNUM *g = &cryptInfo->dsaParam_g, *x = &cryptInfo->dsaParam_x;
BIGNUM hash, k, r, s, temp;
BYTE kBuffer[ CRYPT_MAX_PKCSIZE ];
int length = bitsToBytes( cryptInfo->keySizeBits ), i, status = CRYPT_OK;
/* The length of the encrypted data is determined by the PKC key size */
UNUSED( noBytes );
/* Initialise the bignums */
bnBegin( &hash );
bnBegin( &k );
bnBegin( &r );
bnBegin( &s );
bnBegin( &temp );
/* Generate the secret random value k */
for( i = 0; i < length; i++ )
kBuffer[ i ] = getRandomByte();
kBuffer[ 0 ] |= 0x80; /* Make the random value as big as possible */
bnInsertBigBytes( &k, kBuffer, 0, length );
bnMod( &k, &k, q ); /* Reduce k to the correct range */
zeroise( kBuffer, length );
/* Move the data from the buffer into a bignum */
bnInsertBigBytes( &hash, buffer, 0, length );
/* r = ( g ^ k mod p ) mod q */
CK( bnExpMod( &r, g, &k, p ) );
CK( bnMod( &r, &r, q ) );
/* s = k^-1 * ( hash + x * r ) mod q */
CK( bnInv( &temp, &k, q ) ); /* temp = k^-1 */
CK( bnMul( &s, x, &r ) ); /* s = x * r */
CK( bnMod( &s, &s, q ) ); /* s = s mod q */
CK( bnAdd( &s, &hash ) ); /* s = s + hash */
if( bnCmp( &s, q ) > 0 ) /* if s > q */
CK( bnSub( &s, q ) ); /* s = s - q */
CK( bnMul( &s, &s, &temp ) ); /* s = s * k^-1 */
CK( bnMod( &s, &s, q ) ); /* s = s mod q */
/* Copy the result to the output buffer and destroy sensitive data */
bnExtractBigBytes( &r, buffer, 0, length );
bnBegin( &temp );
bnBegin( &s );
bnBegin( &r );
bnBegin( &k );
bnBegin( &hash );
return( ( status == -1 ) ? CRYPT_PKCCRYPT : CRYPT_OK );
}
/* Decryption (signature check) a single block of data */
int dsaDecrypt( CRYPT_INFO *cryptInfo, BYTE *buffer, int noBytes )
{
BIGNUM *p = &cryptInfo->dsaParam_p, *q = &cryptInfo->dsaParam_q;
BIGNUM *g = &cryptInfo->dsaParam_g, *y = &cryptInfo->dsaParam_y;
BIGNUM r, s, w, u1, u2;
int length = bitsToBytes( cryptInfo->keySizeBits ), status = 0;
/* The length of the encrypted data is determined by the PKC key size */
UNUSED( noBytes );
/* Initialise the bignums */
bnBegin( &r );
bnBegin( &s );
bnBegin( &w );
bnBegin( &u1 );
bnBegin( &u2 );
bnInsertBigBytes( &r, buffer, 0, length );
/* w = s^-1 mod q */
CK( bnInv( &w, &s, q ) );
/* u1 = ( hash * w ) mod q
CK( bnMul( &u1, hash, &w ) );
CK( bnMod(&u1, &u1, q ) );
/* u2 = ( r * w ) mod q */
CK( bnMul( &u2, &r, &w ) );
CK( bnMod( &u2, &u2, q ) );
/* v = ( ( ( g^u1 ) * ( y^u2 ) ) mod p ) mod q */
CK( bnDoubleExpMod( &w, g, &u1, y, &u2, p ) );
CK( bnMod( &w, &w, q ) );
/* if( !bnCmp( r, &w ) ) => sig = OK */
/* Copy the result to the output buffer and destroy sensitive data */
bnExtractBigBytes( &w, buffer, 0, length );
bnBegin( &u2 );
bnBegin( &u1 );
bnBegin( &w );
bnBegin( &s );
bnBegin( &r );
return( ( status == -1 ) ? CRYPT_PKCCRYPT : CRYPT_OK );
}
/****************************************************************************
* *
* DSA Key Management Routines *
* *
****************************************************************************/
/* Load DSA public/private key components into an encryption context */
int dsaInitKey( CRYPT_INFO *cryptInfo )
{
CRYPT_PKCINFO_DSA *dsaKey = ( CRYPT_PKCINFO_DSA * ) cryptInfo->keyComponentPtr;
int status = CRYPT_OK;
/* Allocate storage for the external-format key components */
if( ( status = secureMalloc( &cryptInfo->pkcInfo,
sizeof( CRYPT_PKCINFO_DSA ) ) ) != CRYPT_OK )
return( status );
/* Load the key component from the external representation into the
internal BigNums */
cryptInfo->keyComponentsLittleEndian = dsaKey->endianness;
cryptInfo->isPublicKey = dsaKey->isPublicKey;
if( cryptInfo->keyComponentsLittleEndian )
{
bnInsertLittleBytes( &cryptInfo->dsaParam_p, dsaKey->p, 0,
bitsToBytes( dsaKey->pLen ) );
bnInsertLittleBytes( &cryptInfo->dsaParam_q, dsaKey->q, 0,
bitsToBytes( dsaKey->qLen ) );
bnInsertLittleBytes( &cryptInfo->dsaParam_g, dsaKey->g, 0,
bitsToBytes( dsaKey->gLen ) );
bnInsertLittleBytes( &cryptInfo->dsaParam_x, dsaKey->x, 0,
bitsToBytes( dsaKey->xLen ) );
if( !dsaKey->isPublicKey )
bnInsertLittleBytes( &cryptInfo->dsaParam_y, dsaKey->y, 0,
bitsToBytes( dsaKey->yLen ) );
}
else
{
bnInsertBigBytes( &cryptInfo->dsaParam_p, dsaKey->p, 0,
bitsToBytes( dsaKey->pLen ) );
bnInsertBigBytes( &cryptInfo->dsaParam_q, dsaKey->q, 0,
bitsToBytes( dsaKey->qLen ) );
bnInsertBigBytes( &cryptInfo->dsaParam_g, dsaKey->g, 0,
bitsToBytes( dsaKey->gLen ) );
bnInsertBigBytes( &cryptInfo->dsaParam_x, dsaKey->x, 0,
bitsToBytes( dsaKey->xLen ) );
if( !dsaKey->isPublicKey )
bnInsertBigBytes( &cryptInfo->dsaParam_y, dsaKey->y, 0,
bitsToBytes( dsaKey->yLen ) );
}
/* Load the key components into the external-format component storage */
memcpy( cryptInfo->pkcInfo, dsaKey, sizeof( CRYPT_PKCINFO_DSA ) );
/* Make sure the necessary key parameters have been initialised */
if( !bnCmpQ( &cryptInfo->dsaParam_p, 0 ) || \
!bnCmpQ( &cryptInfo->dsaParam_q, 0 ) || \
!bnCmpQ( &cryptInfo->dsaParam_g, 0 ) || \
!bnCmpQ( &cryptInfo->dsaParam_x, 0 ) )
status = CRYPT_BADPARM2;
if( !dsaKey->isPublicKey )
if( !bnCmpQ( &cryptInfo->dsaParam_y, 0 ) )
status = CRYPT_BADPARM2;
/* Set the nominal keysize in bits */
cryptInfo->keySizeBits = dsaKey->pLen;
/* Finally, generate a key ID for this key */
if( cryptStatusOK( status ) )
status = generateKeyID( CRYPT_ALGO_DSA, cryptInfo->keyID, \
&cryptInfo->keyIDlength, dsaKey );
return( status );
}