421 lines
13 KiB
C
421 lines
13 KiB
C
/////////////////////////////////////////////////////////////////////////////
|
|
// FILE : fipslib.c //
|
|
// DESCRIPTION : FIPS 140 support code. //
|
|
// AUTHOR : //
|
|
// HISTORY : //
|
|
// Oct 20 1999 jeffspel/ramas Merge STT into default CSP //
|
|
// //
|
|
// Copyright (C) 2000 Microsoft Corporation All Rights Reserved //
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <wincrypt.h>
|
|
|
|
#ifdef KERNEL_MODE
|
|
#if WINVER == 0x0500
|
|
#include <ntos.h>
|
|
#else
|
|
#include <ntosp.h>
|
|
#endif
|
|
#endif
|
|
|
|
#include <sha.h>
|
|
#include <des.h>
|
|
#include <tripldes.h>
|
|
#include <modes.h>
|
|
|
|
// known result of an SHA-1 hash on the above buffer
|
|
static UCHAR rgbKnownSHA1[] =
|
|
{
|
|
0xe8, 0x96, 0x82, 0x85, 0xeb, 0xae, 0x01, 0x14,
|
|
0x73, 0xf9, 0x08, 0x45, 0xc0, 0x6a, 0x6d, 0x3e,
|
|
0x69, 0x80, 0x6a, 0x0c
|
|
};
|
|
|
|
// IV for all block ciphers
|
|
UCHAR rgbIV[] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF};
|
|
|
|
// known key, plaintext, and ciphertext for DES
|
|
UCHAR rgbDESKey[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
|
|
UCHAR rgbDESKnownPlaintext[] = {0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74};
|
|
UCHAR rgbDESKnownCiphertext[] = {0x3F, 0xA4, 0x0E, 0x8A, 0x98, 0x4D, 0x48, 0x15};
|
|
UCHAR rgbDESCBCCiphertext[] = {0xE5, 0xC7, 0xCD, 0xDE, 0x87, 0x2B, 0xF2, 0x7C};
|
|
|
|
// known key, plaintext, and ciphertext for 3 key 3DES
|
|
UCHAR rgb3DESKey[] =
|
|
{
|
|
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
|
|
0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01,
|
|
0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23
|
|
};
|
|
UCHAR rgb3DESKnownPlaintext[] = {0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74};
|
|
UCHAR rgb3DESKnownCiphertext[] = {0x31, 0x4F, 0x83, 0x27, 0xFA, 0x7A, 0x09, 0xA8};
|
|
UCHAR rgb3DESCBCCiphertext[] = {0xf3, 0xc0, 0xff, 0x02, 0x6c, 0x02, 0x30, 0x89};
|
|
|
|
// known key, plaintext, and ciphertext for 2 key 3DES
|
|
UCHAR rgb3DES112Key[] =
|
|
{
|
|
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
|
|
0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01
|
|
};
|
|
UCHAR rgb3DES112KnownPlaintext[] = {0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74};
|
|
UCHAR rgb3DES112KnownCiphertext[] = {0xb7, 0x83, 0x57, 0x79, 0xee, 0x26, 0xac, 0xb7};
|
|
UCHAR rgb3DES112CBCCiphertext[] = {0x13, 0x4b, 0x98, 0xf8, 0xee, 0xb3, 0xf6, 0x07};
|
|
|
|
#define MAX_BLOCKLEN 8
|
|
#define MAXKEYSTRUCTSIZE DES3_TABLESIZE // currently the max is a 3DES key structure
|
|
|
|
// Known answer test for SHA HMAC from Fips draft
|
|
UCHAR rgbHmacKey [] = {
|
|
0x01, 0x02, 0x03, 0x04, 0x05,
|
|
0x06, 0x07, 0x08, 0x09, 0x0a,
|
|
0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
|
0x10, 0x11, 0x12, 0x13, 0x14,
|
|
0x15, 0x16, 0x17, 0x18, 0x19
|
|
};
|
|
UCHAR rgbHmacData [50]; // set bytes to 0xcd
|
|
UCHAR rgbHmac [] = {
|
|
0x4c, 0x90, 0x07, 0xf4, 0x02,
|
|
0x62, 0x50, 0xc6, 0xbc, 0x84,
|
|
0x14, 0xf9, 0xbf, 0x50, 0xc8,
|
|
0x6c, 0x2d, 0x72, 0x35, 0xda
|
|
};
|
|
|
|
extern VOID FipsHmacSHAInit(
|
|
OUT A_SHA_CTX *pShaCtx,
|
|
IN UCHAR *pKey,
|
|
IN unsigned int cbKey
|
|
);
|
|
|
|
extern VOID FipsHmacSHAUpdate(
|
|
IN OUT A_SHA_CTX *pShaCtx,
|
|
IN UCHAR *pb,
|
|
IN unsigned int cb
|
|
);
|
|
|
|
extern VOID FipsHmacSHAFinal(
|
|
IN A_SHA_CTX *pShaCtx,
|
|
IN UCHAR *pKey,
|
|
IN unsigned int cbKey,
|
|
OUT UCHAR *pHash
|
|
);
|
|
|
|
//
|
|
// Function : TestSHA1
|
|
//
|
|
// Description : This function hashes the passed in message with the SHA1 hash
|
|
// algorithm and returns the resulting hash value.
|
|
//
|
|
void TestSHA1(
|
|
UCHAR *pbMsg,
|
|
ULONG cbMsg,
|
|
UCHAR *pbHash
|
|
)
|
|
{
|
|
A_SHA_CTX HashContext;
|
|
|
|
// Initialize SHA
|
|
A_SHAInit(&HashContext);
|
|
|
|
// Compute SHA
|
|
A_SHAUpdate(&HashContext, pbMsg, cbMsg);
|
|
|
|
A_SHAFinal(&HashContext, pbHash);
|
|
}
|
|
|
|
//
|
|
// Function : TestEncDec
|
|
//
|
|
// Description : This function expands the passed in key buffer for the appropriate
|
|
// algorithm, and then either encryption or decryption is performed.
|
|
// A comparison is then made to see if the ciphertext or plaintext
|
|
// matches the expected value.
|
|
// The function only uses ECB mode for block ciphers and the plaintext
|
|
// buffer must be the same length as the ciphertext buffer. The length
|
|
// of the plaintext must be either the block length of the cipher if it
|
|
// is a block cipher or less than MAX_BLOCKLEN if a stream cipher is
|
|
// being used.
|
|
//
|
|
NTSTATUS TestEncDec(
|
|
IN ALG_ID Algid,
|
|
IN UCHAR *pbKey,
|
|
IN ULONG cbKey,
|
|
IN UCHAR *pbPlaintext,
|
|
IN ULONG cbPlaintext,
|
|
IN UCHAR *pbCiphertext,
|
|
IN UCHAR *pbIV,
|
|
IN int iOperation
|
|
)
|
|
{
|
|
UCHAR rgbExpandedKey[MAXKEYSTRUCTSIZE];
|
|
UCHAR rgbBuffIn[MAX_BLOCKLEN];
|
|
UCHAR rgbBuffOut[MAX_BLOCKLEN];
|
|
ULONG i;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
RtlZeroMemory(rgbExpandedKey, sizeof(rgbExpandedKey));
|
|
RtlZeroMemory(rgbBuffIn, sizeof(rgbBuffIn));
|
|
RtlZeroMemory(rgbBuffOut, sizeof(rgbBuffOut));
|
|
|
|
// length of data to encrypt must be < MAX_BLOCKLEN
|
|
if (cbPlaintext > MAX_BLOCKLEN)
|
|
{
|
|
goto Ret;
|
|
}
|
|
|
|
// alloc for and expand the key
|
|
switch(Algid)
|
|
{
|
|
case (CALG_DES):
|
|
{
|
|
desparityonkey(pbKey, cbKey);
|
|
deskey((DESTable*)rgbExpandedKey, pbKey);
|
|
break;
|
|
}
|
|
|
|
case (CALG_3DES):
|
|
{
|
|
desparityonkey(pbKey, cbKey);
|
|
tripledes3key((PDES3TABLE)rgbExpandedKey, pbKey);
|
|
break;
|
|
}
|
|
|
|
case (CALG_3DES_112):
|
|
{
|
|
desparityonkey(pbKey, cbKey);
|
|
tripledes2key((PDES3TABLE)rgbExpandedKey, pbKey);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if encrypting and there is an IV then use it
|
|
if (ENCRYPT == iOperation)
|
|
{
|
|
memcpy(rgbBuffIn, pbPlaintext, cbPlaintext);
|
|
|
|
if (NULL != pbIV)
|
|
{
|
|
for(i = 0; i < cbPlaintext; i++)
|
|
{
|
|
rgbBuffIn[i] = rgbBuffIn[i] ^ pbIV[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
// encrypt the plaintext
|
|
switch(Algid)
|
|
{
|
|
case (CALG_DES):
|
|
{
|
|
if (ENCRYPT == iOperation)
|
|
{
|
|
des(rgbBuffOut, rgbBuffIn, rgbExpandedKey, ENCRYPT);
|
|
}
|
|
else
|
|
{
|
|
des(rgbBuffOut, pbCiphertext, rgbExpandedKey, DECRYPT);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case (CALG_3DES):
|
|
case (CALG_3DES_112):
|
|
{
|
|
if (ENCRYPT == iOperation)
|
|
{
|
|
tripledes(rgbBuffOut, rgbBuffIn, rgbExpandedKey, ENCRYPT);
|
|
}
|
|
else
|
|
{
|
|
tripledes(rgbBuffOut, pbCiphertext, rgbExpandedKey, DECRYPT);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// compare the encrypted plaintext with the passed in ciphertext
|
|
if (ENCRYPT == iOperation)
|
|
{
|
|
if (memcmp(pbCiphertext, rgbBuffOut, cbPlaintext))
|
|
{
|
|
goto Ret;
|
|
}
|
|
}
|
|
// compare the decrypted ciphertext with the passed in plaintext
|
|
else
|
|
{
|
|
// if there is an IV then use it
|
|
if (NULL != pbIV)
|
|
{
|
|
for(i = 0; i < cbPlaintext; i++)
|
|
{
|
|
rgbBuffOut[i] = rgbBuffOut[i] ^ pbIV[i];
|
|
}
|
|
}
|
|
|
|
if (memcmp(pbPlaintext, rgbBuffOut, cbPlaintext))
|
|
{
|
|
goto Ret;
|
|
}
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
Ret:
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Function : TestSymmetricAlgorithm
|
|
//
|
|
// Description : This function expands the passed in key buffer for the appropriate algorithm,
|
|
// encrypts the plaintext buffer with the same algorithm and key, and the
|
|
// compares the passed in expected ciphertext with the calculated ciphertext
|
|
// to make sure they are the same. The opposite is then done with decryption.
|
|
// The function only uses ECB mode for block ciphers and the plaintext
|
|
// buffer must be the same length as the ciphertext buffer. The length
|
|
// of the plaintext must be either the block length of the cipher if it
|
|
// is a block cipher or less than MAX_BLOCKLEN if a stream cipher is
|
|
// being used.
|
|
//
|
|
NTSTATUS TestSymmetricAlgorithm(
|
|
IN ALG_ID Algid,
|
|
IN UCHAR *pbKey,
|
|
IN ULONG cbKey,
|
|
IN UCHAR *pbPlaintext,
|
|
IN ULONG cbPlaintext,
|
|
IN UCHAR *pbCiphertext,
|
|
IN UCHAR *pbIV
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
Status = TestEncDec(Algid, pbKey, cbKey, pbPlaintext, cbPlaintext,
|
|
pbCiphertext, pbIV, ENCRYPT);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Ret;
|
|
}
|
|
|
|
Status = TestEncDec(Algid, pbKey, cbKey, pbPlaintext, cbPlaintext,
|
|
pbCiphertext, pbIV, DECRYPT);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Ret;
|
|
}
|
|
Ret:
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
// **********************************************************************
|
|
// AlgorithmCheck performs known answer tests using the algorithms
|
|
// supported by the provider.
|
|
// **********************************************************************
|
|
NTSTATUS AlgorithmCheck()
|
|
{
|
|
UCHAR rgbSHA1[A_SHA_DIGEST_LEN];
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
A_SHA_CTX ShaCtx;
|
|
ULONG ul;
|
|
|
|
RtlZeroMemory(rgbSHA1, sizeof(rgbSHA1));
|
|
|
|
// known answer test with SHA-1 (this function is found in hash.c)
|
|
TestSHA1("HashThis", 8, rgbSHA1);
|
|
if (!RtlEqualMemory(rgbSHA1, rgbKnownSHA1, sizeof(rgbSHA1)))
|
|
{
|
|
goto Ret;
|
|
}
|
|
|
|
// known answer test with DES - ECB
|
|
Status = TestSymmetricAlgorithm(CALG_DES, rgbDESKey, sizeof(rgbDESKey),
|
|
rgbDESKnownPlaintext,
|
|
sizeof(rgbDESKnownPlaintext),
|
|
rgbDESKnownCiphertext,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Ret;
|
|
}
|
|
// known answer test with DES - CBC
|
|
Status = TestSymmetricAlgorithm(CALG_DES, rgbDESKey, sizeof(rgbDESKey),
|
|
rgbDESKnownPlaintext,
|
|
sizeof(rgbDESKnownPlaintext),
|
|
rgbDESCBCCiphertext,
|
|
rgbIV);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Ret;
|
|
}
|
|
|
|
// known answer test with 3DES - ECB
|
|
Status = TestSymmetricAlgorithm(CALG_3DES, rgb3DESKey, sizeof(rgb3DESKey),
|
|
rgb3DESKnownPlaintext,
|
|
sizeof(rgb3DESKnownPlaintext),
|
|
rgb3DESKnownCiphertext,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Ret;
|
|
}
|
|
|
|
// known answer test with 3DES - CBC
|
|
Status = TestSymmetricAlgorithm(CALG_3DES, rgb3DESKey, sizeof(rgb3DESKey),
|
|
rgb3DESKnownPlaintext,
|
|
sizeof(rgb3DESKnownPlaintext),
|
|
rgb3DESCBCCiphertext,
|
|
rgbIV);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Ret;
|
|
}
|
|
|
|
// known answer test with 3DES 112 - ECB
|
|
Status = TestSymmetricAlgorithm(CALG_3DES_112, rgb3DES112Key,
|
|
sizeof(rgb3DES112Key),
|
|
rgb3DES112KnownPlaintext,
|
|
sizeof(rgb3DES112KnownPlaintext),
|
|
rgb3DES112KnownCiphertext,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Ret;
|
|
}
|
|
|
|
Status = TestSymmetricAlgorithm(CALG_3DES_112, rgb3DES112Key,
|
|
sizeof(rgb3DES112Key),
|
|
rgb3DES112KnownPlaintext,
|
|
sizeof(rgb3DES112KnownPlaintext),
|
|
rgb3DES112CBCCiphertext,
|
|
rgbIV);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Ret;
|
|
}
|
|
|
|
// Known answer test for SHA-HMAC
|
|
RtlZeroMemory(rgbSHA1, sizeof(rgbSHA1));
|
|
RtlZeroMemory(&ShaCtx, sizeof(ShaCtx));
|
|
|
|
for (ul = 0; ul < sizeof(rgbHmacData); ul++)
|
|
rgbHmacData[ul] = 0xcd;
|
|
|
|
FipsHmacSHAInit(&ShaCtx, rgbHmacKey, sizeof(rgbHmacKey));
|
|
FipsHmacSHAUpdate(&ShaCtx, rgbHmacData, sizeof(rgbHmacData));
|
|
FipsHmacSHAFinal(&ShaCtx, rgbHmacKey, sizeof(rgbHmacKey), rgbSHA1);
|
|
|
|
if (! RtlEqualMemory(rgbSHA1, rgbHmac, sizeof(rgbHmac)))
|
|
goto Ret;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
Ret:
|
|
return Status;
|
|
}
|
|
|
|
|
|
|