1703 lines
37 KiB
C
1703 lines
37 KiB
C
//+-----------------------------------------------------------------------
|
|
//
|
|
// File: DESWRAP.C
|
|
//
|
|
// Contents: CryptoSystem wrapper functions for DES
|
|
//
|
|
//
|
|
// History: 06-Sep-1996 MikeSw Created
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
//
|
|
// Portions of this code (the key generation code) were taken from the
|
|
// MIT kerberos distribution.
|
|
//
|
|
|
|
/*
|
|
*
|
|
* Copyright 1989,1990 by the Massachusetts Institute of Technology.
|
|
* All Rights Reserved.
|
|
*
|
|
* Export of this software from the United States of America may
|
|
* require a specific license from the United States Government.
|
|
* It is the responsibility of any person or organization contemplating
|
|
* export to obtain such a license before exporting.
|
|
*
|
|
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
|
* distribute this software and its documentation for any purpose and
|
|
* without fee is hereby granted, provided that the above copyright
|
|
* notice appear in all copies and that both that copyright notice and
|
|
* this permission notice appear in supporting documentation, and that
|
|
* the name of M.I.T. not be used in advertising or publicity pertaining
|
|
* to distribution of the software without specific, written prior
|
|
* permission. M.I.T. makes no representations about the suitability of
|
|
* this software for any purpose. It is provided "as is" without express
|
|
* or implied warranty.
|
|
*
|
|
*
|
|
* Under U.S. law, this software may not be exported outside the US
|
|
* without license from the U.S. Commerce department.
|
|
*
|
|
* These routines form the library interface to the DES facilities.
|
|
*
|
|
* Originally written 8/85 by Steve Miller, MIT Project Athena.
|
|
*/
|
|
|
|
/* des.c - Routines for implementing the FIPS Data Encryption Standard (DES).
|
|
*
|
|
* Allan Bjorklund, University of Michigan, ITD/RS/DD.
|
|
* July 24, 1993.
|
|
*
|
|
* Revisions for PC memory model portability, July 11, 1994.
|
|
*
|
|
* Removed model portability header and added Win95 DLL
|
|
* declarations, May 31, 1995.
|
|
*
|
|
* Made all declarations Win95 and NT specific, September 18, 1995.
|
|
*
|
|
* Added quad_cksum, October 9, 1995.
|
|
*
|
|
* Copyright (c) 1995,1996 Regents of The University of Michigan.
|
|
* All Rights Reserved.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software and
|
|
* its documentation for any purpose and without fee is hereby granted,
|
|
* provided that the above copyright notice appears in all copies and
|
|
* that both that copyright notice and this permission notice appear
|
|
* in supporting documentation, and that the name of The University
|
|
* of Michigan not be used in advertising or publicity pertaining to
|
|
* distribution of the software without specific, written prior
|
|
* permission. This software is supplied as is without expressed or
|
|
* implied warranties of any kind.
|
|
*
|
|
* Research Systems Unix Group
|
|
* The University of Michigan
|
|
* c/o Allan Bjorklund
|
|
* 535 W. William Street
|
|
* Ann Arbor, Michigan
|
|
* kerb95@umich.edu
|
|
*/
|
|
|
|
#ifndef KERNEL_MODE
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
|
|
#else
|
|
|
|
#include <ntifs.h>
|
|
#include <winerror.h>
|
|
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
#include <align.h>
|
|
|
|
#include <kerbcon.h>
|
|
#include <security.h>
|
|
#include <cryptdll.h>
|
|
#ifdef WIN32_CHICAGO
|
|
#include <assert.h>
|
|
#undef ASSERT
|
|
#define ASSERT(x) assert(x)
|
|
VOID MyRtlFreeOemString( POEM_STRING OemString );
|
|
#define RtlFreeOemString(x) MyRtlFreeOemString(x)
|
|
NTSTATUS MyRtlUnicodeStringToOemString(
|
|
OUT POEM_STRING DestinationString,
|
|
IN PUNICODE_STRING SourceString,
|
|
IN BOOLEAN AllocateDestinationString
|
|
);
|
|
#define RtlUnicodeStringToOemString(x, y, z) MyRtlUnicodeStringToOemString(x, y, z)
|
|
#endif // WIN32_CHICAGO
|
|
|
|
#include "modes.h"
|
|
#include "des.h"
|
|
#include "md5.h"
|
|
|
|
BOOLEAN
|
|
md5Hmac(
|
|
IN PUCHAR pbKeyMaterial,
|
|
IN ULONG cbKeyMaterial,
|
|
IN PUCHAR pbData,
|
|
IN ULONG cbData,
|
|
IN PUCHAR pbData2,
|
|
IN ULONG cbData2,
|
|
OUT PUCHAR HmacData
|
|
);
|
|
|
|
#define DES_CONFOUNDER_LEN 8
|
|
|
|
typedef struct _DES_HEADER {
|
|
UCHAR Confounder[DES_CONFOUNDER_LEN];
|
|
UCHAR Checksum[MD5_LEN];
|
|
} DES_HEADER, *PDES_HEADER;
|
|
|
|
|
|
|
|
typedef struct _DES_STATE_BUFFER {
|
|
PCHECKSUM_FUNCTION ChecksumFunction;
|
|
DESTable KeyTable;
|
|
UCHAR InitializationVector[DES_BLOCKLEN];
|
|
} DES_STATE_BUFFER, *PDES_STATE_BUFFER;
|
|
|
|
typedef struct _DES_MAC_STATE_BUFFER {
|
|
DESTable KeyTable;
|
|
UCHAR Confounder[DES_BLOCKLEN];
|
|
UCHAR InitializationVector[DES_BLOCKLEN];
|
|
} DES_MAC_STATE_BUFFER, *PDES_MAC_STATE_BUFFER;
|
|
|
|
typedef struct _DES_MAC_1510_STATE_BUFFER {
|
|
DESTable KeyTable;
|
|
UCHAR InitializationVector[DES_BLOCKLEN];
|
|
UCHAR Confounder[DES_BLOCKLEN];
|
|
DESTable FinalKeyTable;
|
|
} DES_MAC_1510_STATE_BUFFER, *PDES_MAC_1510_STATE_BUFFER;
|
|
|
|
NTSTATUS NTAPI desPlainInitialize(PUCHAR, ULONG, ULONG, PCRYPT_STATE_BUFFER *);
|
|
NTSTATUS NTAPI desPlainExpInitialize(PUCHAR, ULONG, ULONG, PCRYPT_STATE_BUFFER *);
|
|
NTSTATUS NTAPI desMd5Initialize(PUCHAR, ULONG, ULONG, PCRYPT_STATE_BUFFER *);
|
|
NTSTATUS NTAPI desMd5ExpInitialize(PUCHAR, ULONG, ULONG, PCRYPT_STATE_BUFFER *);
|
|
NTSTATUS NTAPI desCrc32Initialize(PUCHAR, ULONG, ULONG, PCRYPT_STATE_BUFFER *);
|
|
NTSTATUS NTAPI desEncrypt(PCRYPT_STATE_BUFFER, PUCHAR, ULONG, PUCHAR, PULONG);
|
|
NTSTATUS NTAPI desDecrypt(PCRYPT_STATE_BUFFER, PUCHAR, ULONG, PUCHAR, PULONG);
|
|
NTSTATUS NTAPI desFinish(PCRYPT_STATE_BUFFER *);
|
|
NTSTATUS NTAPI desHashPassword(PSECURITY_STRING, PUCHAR);
|
|
NTSTATUS NTAPI desInitRandom(ULONG);
|
|
NTSTATUS NTAPI desRandomKey(PUCHAR, ULONG, PUCHAR);
|
|
NTSTATUS NTAPI desFinishRandom(void);
|
|
NTSTATUS NTAPI desControl(ULONG, PCRYPT_STATE_BUFFER, PUCHAR, ULONG);
|
|
|
|
NTSTATUS NTAPI desMacGeneralInitializeEx(PUCHAR, ULONG, PUCHAR, ULONG, PCHECKSUM_BUFFER *);
|
|
|
|
NTSTATUS NTAPI desMacInitialize(ULONG, PCHECKSUM_BUFFER *);
|
|
NTSTATUS NTAPI desMacInitializeEx(PUCHAR,ULONG, ULONG, PCHECKSUM_BUFFER *);
|
|
|
|
NTSTATUS NTAPI desMacKInitializeEx(PUCHAR,ULONG, ULONG, PCHECKSUM_BUFFER *);
|
|
|
|
NTSTATUS NTAPI desMac1510Initialize(ULONG, PCHECKSUM_BUFFER *);
|
|
NTSTATUS NTAPI desMac1510InitializeEx(PUCHAR,ULONG, ULONG, PCHECKSUM_BUFFER *);
|
|
NTSTATUS NTAPI desMac1510InitializeEx2(PUCHAR,ULONG, PUCHAR, ULONG, PCHECKSUM_BUFFER *);
|
|
NTSTATUS NTAPI desMac1510Finalize(PCHECKSUM_BUFFER, PUCHAR);
|
|
NTSTATUS NTAPI desMacSum(PCHECKSUM_BUFFER, ULONG, PUCHAR);
|
|
NTSTATUS NTAPI desMacFinalize(PCHECKSUM_BUFFER, PUCHAR);
|
|
NTSTATUS NTAPI desMacFinish(PCHECKSUM_BUFFER *);
|
|
|
|
#ifdef KERNEL_MODE
|
|
#pragma alloc_text( PAGEMSG, desPlainInitialize )
|
|
#pragma alloc_text( PAGEMSG, desPlainExpInitialize )
|
|
#pragma alloc_text( PAGEMSG, desMd5Initialize )
|
|
#pragma alloc_text( PAGEMSG, desMd5ExpInitialize )
|
|
#pragma alloc_text( PAGEMSG, desCrc32Initialize )
|
|
#pragma alloc_text( PAGEMSG, desEncrypt )
|
|
#pragma alloc_text( PAGEMSG, desDecrypt )
|
|
#pragma alloc_text( PAGEMSG, desFinish )
|
|
#pragma alloc_text( PAGEMSG, desHashPassword )
|
|
#pragma alloc_text( PAGEMSG, desInitRandom )
|
|
#pragma alloc_text( PAGEMSG, desRandomKey )
|
|
#pragma alloc_text( PAGEMSG, desFinishRandom )
|
|
#pragma alloc_text( PAGEMSG, desControl )
|
|
#pragma alloc_text( PAGEMSG, desMacInitialize )
|
|
#pragma alloc_text( PAGEMSG, desMacInitializeEx )
|
|
#pragma alloc_text( PAGEMSG, desMacSum )
|
|
#pragma alloc_text( PAGEMSG, desMacFinalize )
|
|
#pragma alloc_text( PAGEMSG, desMacFinish )
|
|
#pragma alloc_text( PAGEMSG, desMacGeneralInitializeEx )
|
|
#pragma alloc_text( PAGEMSG, desMacKInitializeEx )
|
|
#pragma alloc_text( PAGEMSG, desMac1510Initialize )
|
|
#pragma alloc_text( PAGEMSG, desMac1510InitializeEx )
|
|
#pragma alloc_text( PAGEMSG, desMac1510InitializeEx2 )
|
|
#pragma alloc_text( PAGEMSG, desMac1510Finalize )
|
|
#endif
|
|
|
|
|
|
CRYPTO_SYSTEM csDES_MD5 = {
|
|
KERB_ETYPE_DES_CBC_MD5, // Etype
|
|
DES_BLOCKLEN, // Blocksize
|
|
KERB_ETYPE_DES_CBC_MD5, // exportable version
|
|
DES_KEYSIZE, // Key size, in bytes
|
|
sizeof(DES_HEADER), // header size
|
|
KERB_CHECKSUM_MD5, // Preferred Checksum
|
|
CSYSTEM_USE_PRINCIPAL_NAME |
|
|
CSYSTEM_INTEGRITY_PROTECTED |
|
|
CSYSTEM_EXPORT_STRENGTH, // Attributes
|
|
L"Kerberos DES-CBC-MD5", // Text name
|
|
desMd5Initialize,
|
|
desEncrypt,
|
|
desDecrypt,
|
|
desFinish,
|
|
desHashPassword,
|
|
desRandomKey,
|
|
desControl
|
|
};
|
|
|
|
|
|
CRYPTO_SYSTEM csDES_CRC32 = {
|
|
KERB_ETYPE_DES_CBC_CRC, // Etype
|
|
DES_BLOCKLEN, // Blocksize (stream)
|
|
KERB_ETYPE_DES_CBC_CRC, // exportable version
|
|
DES_KEYSIZE, // Key size, in bytes
|
|
sizeof(DES_HEADER), // header size
|
|
KERB_CHECKSUM_CRC32, // Preferred Checksum
|
|
CSYSTEM_USE_PRINCIPAL_NAME |
|
|
CSYSTEM_INTEGRITY_PROTECTED |
|
|
CSYSTEM_EXPORT_STRENGTH, // Attributes
|
|
L"Kerberos DES-CBC-CRC", // Text name
|
|
desCrc32Initialize,
|
|
desEncrypt,
|
|
desDecrypt,
|
|
desFinish,
|
|
desHashPassword,
|
|
desRandomKey,
|
|
desControl
|
|
};
|
|
|
|
CRYPTO_SYSTEM csDES_PLAIN = {
|
|
KERB_ETYPE_DES_PLAIN, // Etype
|
|
DES_BLOCKLEN, // Blocksize
|
|
KERB_ETYPE_DES_PLAIN, // exportable version
|
|
DES_KEYSIZE, // Key size, in bytes
|
|
0, // header size
|
|
KERB_CHECKSUM_CRC32, // Preferred Checksum
|
|
CSYSTEM_USE_PRINCIPAL_NAME | CSYSTEM_EXPORT_STRENGTH, // Attributes
|
|
L"Kerberos DES-Plain", // Text name
|
|
desPlainInitialize,
|
|
desEncrypt,
|
|
desDecrypt,
|
|
desFinish,
|
|
desHashPassword,
|
|
desRandomKey,
|
|
desControl
|
|
};
|
|
|
|
|
|
|
|
CHECKSUM_FUNCTION csfDesMac = {
|
|
KERB_CHECKSUM_DES_MAC, // Checksum type
|
|
DES_BLOCKLEN, // Checksum length
|
|
CKSUM_KEYED,
|
|
desMacInitialize,
|
|
desMacSum,
|
|
desMacFinalize,
|
|
desMacFinish,
|
|
desMacInitializeEx,
|
|
NULL};
|
|
|
|
CHECKSUM_FUNCTION csfDesMacK = {
|
|
KERB_CHECKSUM_KRB_DES_MAC_K, // Checksum type
|
|
DES_BLOCKLEN, // Checksum length
|
|
CKSUM_KEYED,
|
|
desMacInitialize,
|
|
desMacSum,
|
|
desMacFinalize,
|
|
desMacFinish,
|
|
desMacKInitializeEx,
|
|
NULL};
|
|
|
|
CHECKSUM_FUNCTION csfDesMac1510 = {
|
|
KERB_CHECKSUM_KRB_DES_MAC, // Checksum type
|
|
DES_BLOCKLEN * 2, // Checksum length
|
|
CKSUM_KEYED,
|
|
desMac1510Initialize,
|
|
desMacSum,
|
|
desMac1510Finalize,
|
|
desMacFinish, // just frees the buffer
|
|
desMac1510InitializeEx,
|
|
desMac1510InitializeEx2};
|
|
|
|
|
|
#define SMASK(step) ((1<<step)-1)
|
|
#define PSTEP(x,step) (((x)&SMASK(step))^(((x)>>step)&SMASK(step)))
|
|
#define PARITY_CHAR(x, y) \
|
|
{\
|
|
UCHAR _tmp1_, _tmp2_; \
|
|
_tmp1_ = (UCHAR) PSTEP((x),4); \
|
|
_tmp2_ = (UCHAR) PSTEP(_tmp1_,2); \
|
|
*(y) = (UCHAR) PSTEP(_tmp2_, 1); \
|
|
} \
|
|
|
|
|
|
VOID
|
|
desFixupKeyParity(
|
|
PUCHAR Key
|
|
)
|
|
{
|
|
ULONG Index;
|
|
UCHAR TempChar;
|
|
for (Index=0; Index < DES_BLOCKLEN; Index++)
|
|
{
|
|
Key[Index] &= 0xfe;
|
|
PARITY_CHAR(Key[Index], &TempChar);
|
|
Key[Index] |= 1 ^ TempChar;
|
|
}
|
|
|
|
}
|
|
|
|
typedef UCHAR DES_KEYBLOCK[8];
|
|
|
|
DES_KEYBLOCK desWeakKeys[] = {
|
|
/* weak keys */
|
|
{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
|
|
{0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe},
|
|
{0x1f,0x1f,0x1f,0x1f,0x0e,0x0e,0x0e,0x0e},
|
|
{0xe0,0xe0,0xe0,0xe0,0xf1,0xf1,0xf1,0xf1},
|
|
|
|
/* semi-weak */
|
|
{0x01,0xfe,0x01,0xfe,0x01,0xfe,0x01,0xfe},
|
|
{0xfe,0x01,0xfe,0x01,0xfe,0x01,0xfe,0x01},
|
|
|
|
{0x1f,0xe0,0x1f,0xe0,0x0e,0xf1,0x0e,0xf1},
|
|
{0xe0,0x1f,0xe0,0x1f,0xf1,0x0e,0xf1,0x0e},
|
|
|
|
{0x01,0xe0,0x01,0xe0,0x01,0xf1,0x01,0xf1},
|
|
{0xe0,0x01,0xe0,0x01,0xf1,0x01,0xf1,0x01},
|
|
|
|
{0x1f,0xfe,0x1f,0xfe,0x0e,0xfe,0x0e,0xfe},
|
|
{0xfe,0x1f,0xfe,0x1f,0xfe,0x0e,0xfe,0x0e},
|
|
|
|
{0x01,0x1f,0x01,0x1f,0x01,0x0e,0x01,0x0e},
|
|
{0x1f,0x01,0x1f,0x01,0x0e,0x01,0x0e,0x01},
|
|
|
|
{0xe0,0xfe,0xe0,0xfe,0xf1,0xfe,0xf1,0xfe},
|
|
{0xfe,0xe0,0xfe,0xe0,0xfe,0xf1,0xfe,0xf1}
|
|
};
|
|
|
|
/*
|
|
* mit_des_is_weak_key: returns true iff key is a [semi-]weak des key.
|
|
*
|
|
* Requires: key has correct odd parity.
|
|
*/
|
|
|
|
BOOLEAN
|
|
desIsWeakKey(
|
|
PUCHAR Key
|
|
)
|
|
{
|
|
ULONG Index;
|
|
DES_KEYBLOCK * WeakKey = desWeakKeys;
|
|
|
|
for (Index = 0; Index < sizeof(desWeakKeys)/DES_BLOCKLEN; Index++) {
|
|
if (RtlEqualMemory(
|
|
WeakKey++,
|
|
Key,
|
|
DES_BLOCKLEN
|
|
))
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
desInitialize( PUCHAR pbKey,
|
|
ULONG KeySize,
|
|
ULONG MessageType,
|
|
ULONG Checksum,
|
|
PCRYPT_STATE_BUFFER * psbBuffer)
|
|
{
|
|
NTSTATUS Status;
|
|
UCHAR LocalKey[DES_KEYSIZE];
|
|
PDES_STATE_BUFFER DesKey = NULL;
|
|
PCHECKSUM_FUNCTION ChecksumFunction = NULL;
|
|
|
|
//
|
|
// Make sure we were passed an appropriate keytable
|
|
//
|
|
|
|
|
|
if (KeySize != DES_KEYSIZE)
|
|
{
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
LocalKey,
|
|
pbKey,
|
|
KeySize
|
|
);
|
|
|
|
//
|
|
// Get the appropriate checksum here.
|
|
//
|
|
|
|
if (Checksum != 0)
|
|
{
|
|
Status = CDLocateCheckSum(
|
|
Checksum,
|
|
&ChecksumFunction
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return(Status);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
ChecksumFunction = NULL;
|
|
}
|
|
|
|
//
|
|
// Create the key buffer
|
|
//
|
|
|
|
|
|
#ifdef KERNEL_MODE
|
|
DesKey = ExAllocatePool (NonPagedPool, sizeof(DES_STATE_BUFFER));
|
|
#else
|
|
DesKey = LocalAlloc(0, sizeof(DES_STATE_BUFFER));
|
|
#endif
|
|
if (DesKey == NULL)
|
|
{
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
|
|
|
|
deskey(&DesKey->KeyTable, LocalKey);
|
|
|
|
|
|
//
|
|
// Initialize the checksum function
|
|
//
|
|
|
|
DesKey->ChecksumFunction = ChecksumFunction;
|
|
|
|
//
|
|
// DES-CBC-CRC uses the key as the ivec, MD5 and MD4 user zero
|
|
//
|
|
|
|
if (Checksum == KERB_CHECKSUM_CRC32)
|
|
{
|
|
RtlCopyMemory(
|
|
DesKey->InitializationVector,
|
|
LocalKey,
|
|
DES_BLOCKLEN
|
|
);
|
|
}
|
|
else
|
|
{
|
|
RtlZeroMemory(
|
|
DesKey->InitializationVector,
|
|
DES_BLOCKLEN
|
|
);
|
|
|
|
}
|
|
|
|
|
|
*psbBuffer = (PCRYPT_STATE_BUFFER) DesKey;
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
#if DBG
|
|
void
|
|
DumpBuf(
|
|
IN PUCHAR Buf,
|
|
IN ULONG BufSize
|
|
)
|
|
{
|
|
ULONG Index;
|
|
for (Index = 0; Index < BufSize ;Index++ )
|
|
{
|
|
DbgPrint("%0.2x ",Buf[Index]);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
NTSTATUS NTAPI
|
|
desMd5Initialize(
|
|
IN PUCHAR pbKey,
|
|
IN ULONG KeySize,
|
|
IN ULONG MessageType,
|
|
OUT PCRYPT_STATE_BUFFER * psbBuffer
|
|
)
|
|
{
|
|
return(desInitialize(
|
|
pbKey,
|
|
KeySize,
|
|
MessageType,
|
|
KERB_CHECKSUM_MD5,
|
|
psbBuffer
|
|
));
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
desCrc32Initialize(
|
|
IN PUCHAR pbKey,
|
|
IN ULONG KeySize,
|
|
IN ULONG MessageType,
|
|
OUT PCRYPT_STATE_BUFFER * psbBuffer
|
|
)
|
|
{
|
|
return(desInitialize(
|
|
pbKey,
|
|
KeySize,
|
|
MessageType,
|
|
KERB_CHECKSUM_CRC32,
|
|
psbBuffer
|
|
));
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
desPlainInitialize(
|
|
IN PUCHAR pbKey,
|
|
IN ULONG KeySize,
|
|
IN ULONG MessageType,
|
|
OUT PCRYPT_STATE_BUFFER * psbBuffer
|
|
)
|
|
{
|
|
return(desInitialize(
|
|
pbKey,
|
|
KeySize,
|
|
MessageType,
|
|
0, // no checksum
|
|
psbBuffer
|
|
));
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: BlockDecrypt
|
|
//
|
|
// Synopsis: Encrypts a data buffer using DES
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes: stolen from windows\base\ntcyrpto\scp\nt_crypt.c
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
NTSTATUS
|
|
BlockEncrypt(
|
|
IN PDES_STATE_BUFFER pKey,
|
|
IN PUCHAR pbData,
|
|
OUT PULONG pdwDataLen,
|
|
IN ULONG dwBufLen
|
|
)
|
|
{
|
|
ULONG cbPartial, dwPadVal, dwDataLen;
|
|
UCHAR pbBuf[DES_BLOCKLEN];
|
|
UCHAR FeedBack[DES_BLOCKLEN];
|
|
|
|
dwDataLen = *pdwDataLen;
|
|
|
|
//
|
|
// Initialize the feedback buffer to the initialization vector
|
|
//
|
|
|
|
memcpy(
|
|
FeedBack,
|
|
pKey->InitializationVector,
|
|
DES_BLOCKLEN
|
|
);
|
|
|
|
//
|
|
// check length of the buffer and calculate the pad
|
|
// (if multiple of DES_BLOCKLEN, do a full block of pad)
|
|
//
|
|
|
|
cbPartial = (dwDataLen % DES_BLOCKLEN);
|
|
|
|
//
|
|
// The original code here put in 8 bytes of padding
|
|
// on an aligned buffer. That is a waste.
|
|
//
|
|
|
|
if (cbPartial != 0)
|
|
{
|
|
dwPadVal = DES_BLOCKLEN - cbPartial;
|
|
}
|
|
else
|
|
{
|
|
dwPadVal = 0;
|
|
}
|
|
|
|
if (pbData == NULL || dwBufLen < dwDataLen + dwPadVal)
|
|
{
|
|
//
|
|
// set what we need
|
|
//
|
|
|
|
*pdwDataLen = dwDataLen + dwPadVal;
|
|
if (pbData == NULL)
|
|
{
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
return(STATUS_BUFFER_OVERFLOW);
|
|
}
|
|
|
|
//
|
|
// allocate memory for a temporary buffer
|
|
//
|
|
|
|
|
|
//
|
|
// Will this cause MIT clients/servers to flail? The caller
|
|
// should pass in only buffers that are already padded to
|
|
// make MIT clients work.
|
|
//
|
|
|
|
if (dwPadVal)
|
|
{
|
|
// Fill the pad with a value equal to the
|
|
// length of the padding, so decrypt will
|
|
// know the length of the original data
|
|
// and as a simple integrity check.
|
|
|
|
memset(
|
|
pbData + dwDataLen,
|
|
dwPadVal,
|
|
dwPadVal
|
|
);
|
|
}
|
|
|
|
dwDataLen += dwPadVal;
|
|
*pdwDataLen = dwDataLen;
|
|
|
|
ASSERT((dwDataLen % DES_BLOCKLEN) == 0);
|
|
|
|
//
|
|
// pump the full blocks of data through
|
|
//
|
|
while (dwDataLen)
|
|
{
|
|
ASSERT(dwDataLen >= DES_BLOCKLEN);
|
|
|
|
//
|
|
// put the plaintext into a temporary
|
|
// buffer, then encrypt the data
|
|
// back into the caller's buffer
|
|
//
|
|
|
|
memcpy(pbBuf, pbData, DES_BLOCKLEN);
|
|
|
|
CBC( des,
|
|
DES_BLOCKLEN,
|
|
pbData,
|
|
pbBuf,
|
|
&pKey->KeyTable,
|
|
ENCRYPT,
|
|
FeedBack
|
|
);
|
|
|
|
|
|
pbData += DES_BLOCKLEN;
|
|
dwDataLen -= DES_BLOCKLEN;
|
|
}
|
|
memcpy(
|
|
pKey->InitializationVector,
|
|
pbData - DES_BLOCKLEN,
|
|
DES_BLOCKLEN
|
|
);
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: BlockDecrypt
|
|
//
|
|
// Synopsis: Decrypt a block of data encrypted with BlockEncrypt
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
NTSTATUS
|
|
BlockDecrypt(
|
|
IN PDES_STATE_BUFFER pKey,
|
|
IN OUT PUCHAR pbData,
|
|
IN OUT PULONG pdwDataLen
|
|
)
|
|
{
|
|
UCHAR pbBuf[DES_BLOCKLEN];
|
|
ULONG dwDataLen, BytePos;
|
|
UCHAR FeedBack[DES_BLOCKLEN];
|
|
|
|
dwDataLen = *pdwDataLen;
|
|
|
|
//
|
|
// Check to see if we are decrypting something already
|
|
//
|
|
|
|
memcpy(
|
|
FeedBack,
|
|
pKey->InitializationVector,
|
|
DES_BLOCKLEN
|
|
);
|
|
|
|
//
|
|
// The data length must be a multiple of the algorithm
|
|
// pad size.
|
|
//
|
|
if (dwDataLen % DES_BLOCKLEN)
|
|
{
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
|
|
//
|
|
// pump the data through the decryption, including padding
|
|
// NOTE: the total length is a multiple of DES_BLOCKLEN
|
|
//
|
|
|
|
for (BytePos = 0; (BytePos + DES_BLOCKLEN) <= dwDataLen; BytePos += DES_BLOCKLEN)
|
|
{
|
|
//
|
|
// put the encrypted text into a temp buffer
|
|
//
|
|
|
|
memcpy (pbBuf, pbData + BytePos, DES_BLOCKLEN);
|
|
|
|
|
|
CBC(
|
|
des,
|
|
DES_BLOCKLEN,
|
|
pbData + BytePos,
|
|
pbBuf,
|
|
&pKey->KeyTable,
|
|
DECRYPT,
|
|
FeedBack
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
memcpy(
|
|
pKey->InitializationVector,
|
|
pbBuf,
|
|
DES_BLOCKLEN
|
|
);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
desEncrypt(
|
|
IN PCRYPT_STATE_BUFFER psbBuffer,
|
|
IN PUCHAR pbInput,
|
|
IN ULONG cbInput,
|
|
OUT PUCHAR OutputBuffer,
|
|
OUT PULONG OutputLength
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PDES_STATE_BUFFER StateBuffer = (PDES_STATE_BUFFER) psbBuffer;
|
|
PDES_HEADER CryptHeader = (PDES_HEADER) OutputBuffer;
|
|
PCHECKSUM_BUFFER SumBuffer = NULL;
|
|
ULONG LocalOutputLength;
|
|
|
|
//
|
|
// If we aren't doing raw DES, prepare a header structure
|
|
//
|
|
|
|
if (StateBuffer->ChecksumFunction != NULL)
|
|
{
|
|
//
|
|
// Relocate the buffer and inserat the header
|
|
//
|
|
|
|
RtlMoveMemory(
|
|
OutputBuffer + DES_CONFOUNDER_LEN + StateBuffer->ChecksumFunction->CheckSumSize,
|
|
pbInput,
|
|
cbInput
|
|
);
|
|
LocalOutputLength = cbInput + DES_CONFOUNDER_LEN + StateBuffer->ChecksumFunction->CheckSumSize;
|
|
|
|
|
|
//
|
|
// Zero fill the padding space
|
|
//
|
|
|
|
RtlZeroMemory(
|
|
OutputBuffer+LocalOutputLength,
|
|
ROUND_UP_COUNT(LocalOutputLength,DES_BLOCKLEN) - LocalOutputLength
|
|
);
|
|
|
|
LocalOutputLength = ROUND_UP_COUNT(LocalOutputLength,DES_BLOCKLEN);
|
|
|
|
|
|
RtlZeroMemory(
|
|
CryptHeader->Checksum,
|
|
StateBuffer->ChecksumFunction->CheckSumSize
|
|
);
|
|
|
|
CDGenerateRandomBits(
|
|
CryptHeader->Confounder,
|
|
DES_CONFOUNDER_LEN
|
|
);
|
|
|
|
|
|
//
|
|
// Checksum the buffer.
|
|
//
|
|
|
|
Status = StateBuffer->ChecksumFunction->Initialize(0, &SumBuffer);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
StateBuffer->ChecksumFunction->Sum(
|
|
SumBuffer,
|
|
LocalOutputLength,
|
|
OutputBuffer
|
|
);
|
|
StateBuffer->ChecksumFunction->Finalize(
|
|
SumBuffer,
|
|
CryptHeader->Checksum
|
|
);
|
|
StateBuffer->ChecksumFunction->Finish(
|
|
&SumBuffer
|
|
);
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Just copy the buffer
|
|
//
|
|
|
|
RtlCopyMemory(
|
|
OutputBuffer,
|
|
pbInput,
|
|
cbInput
|
|
);
|
|
|
|
LocalOutputLength = ROUND_UP_COUNT(cbInput,DES_BLOCKLEN);
|
|
|
|
//
|
|
// Zero fill the padding space
|
|
//
|
|
|
|
RtlZeroMemory(
|
|
OutputBuffer+cbInput,
|
|
LocalOutputLength - cbInput
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Encrypt the buffer.
|
|
//
|
|
|
|
|
|
*OutputLength = LocalOutputLength;
|
|
|
|
Status = BlockEncrypt(
|
|
StateBuffer,
|
|
OutputBuffer,
|
|
OutputLength,
|
|
LocalOutputLength
|
|
);
|
|
|
|
|
|
Cleanup:
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
desDecrypt( PCRYPT_STATE_BUFFER psbBuffer,
|
|
PUCHAR pbInput,
|
|
ULONG cbInput,
|
|
PUCHAR pbOutput,
|
|
PULONG cbOutput)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PDES_STATE_BUFFER StateBuffer = (PDES_STATE_BUFFER) psbBuffer;
|
|
PDES_HEADER CryptHeader;
|
|
UCHAR Checksum[MD5_LEN];
|
|
PCHECKSUM_BUFFER SumBuffer = NULL;
|
|
|
|
//
|
|
// First decrypt the whole buffer
|
|
//
|
|
|
|
if (*cbOutput < cbInput)
|
|
{
|
|
*cbOutput = cbInput;
|
|
return(STATUS_BUFFER_TOO_SMALL);
|
|
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
pbOutput,
|
|
pbInput,
|
|
cbInput
|
|
);
|
|
Status = BlockDecrypt(
|
|
StateBuffer,
|
|
pbOutput,
|
|
&cbInput
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (StateBuffer->ChecksumFunction != NULL)
|
|
{
|
|
//
|
|
// Now verify the checksum
|
|
//
|
|
|
|
CryptHeader = (PDES_HEADER) pbOutput;
|
|
RtlCopyMemory(
|
|
Checksum,
|
|
CryptHeader->Checksum,
|
|
MD5_LEN
|
|
);
|
|
|
|
//
|
|
// Zero the checksum field before computing the checksum of the buffer
|
|
//
|
|
|
|
RtlZeroMemory(
|
|
CryptHeader->Checksum,
|
|
StateBuffer->ChecksumFunction->CheckSumSize
|
|
);
|
|
|
|
//
|
|
// Checksum the buffer.
|
|
//
|
|
|
|
Status = StateBuffer->ChecksumFunction->Initialize(0, &SumBuffer);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
StateBuffer->ChecksumFunction->Sum(
|
|
SumBuffer,
|
|
cbInput,
|
|
pbOutput
|
|
);
|
|
StateBuffer->ChecksumFunction->Finalize(
|
|
SumBuffer,
|
|
CryptHeader->Checksum
|
|
);
|
|
StateBuffer->ChecksumFunction->Finish(
|
|
&SumBuffer
|
|
);
|
|
|
|
|
|
if (!RtlEqualMemory(
|
|
CryptHeader->Checksum,
|
|
Checksum,
|
|
StateBuffer->ChecksumFunction->CheckSumSize
|
|
))
|
|
{
|
|
Status = SEC_E_MESSAGE_ALTERED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Copy the input to the output without the header
|
|
|
|
*cbOutput = cbInput - (DES_CONFOUNDER_LEN + StateBuffer->ChecksumFunction->CheckSumSize);
|
|
|
|
|
|
RtlMoveMemory(
|
|
pbOutput,
|
|
pbOutput + DES_CONFOUNDER_LEN + StateBuffer->ChecksumFunction->CheckSumSize,
|
|
*cbOutput
|
|
);
|
|
|
|
}
|
|
else
|
|
{
|
|
*cbOutput = cbInput;
|
|
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
desFinish( PCRYPT_STATE_BUFFER * psbBuffer)
|
|
{
|
|
PDES_STATE_BUFFER StateBuffer = (PDES_STATE_BUFFER) *psbBuffer;
|
|
|
|
|
|
#ifdef KERNEL_MODE
|
|
ExFreePool(StateBuffer);
|
|
#else
|
|
LocalFree(StateBuffer);
|
|
#endif
|
|
*psbBuffer = NULL;
|
|
return(S_OK);
|
|
}
|
|
|
|
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
|
|
|
|
#define XORBLOCK(x,y) \
|
|
{ \
|
|
PULONG tx = (PULONG) x; \
|
|
PULONG ty = (PULONG) y; \
|
|
*tx++ ^= *ty++; \
|
|
*tx++ ^= *ty++; \
|
|
}
|
|
|
|
VOID
|
|
desCbcChecksum(
|
|
IN PUCHAR Password,
|
|
IN ULONG PasswordLength,
|
|
IN PUCHAR InitialVector,
|
|
IN DESTable * KeyTable,
|
|
OUT PUCHAR OutputKey
|
|
)
|
|
{
|
|
ULONG Offset;
|
|
UCHAR Feedback[DES_BLOCKLEN];
|
|
UCHAR Block[DES_BLOCKLEN];
|
|
|
|
RtlCopyMemory(
|
|
Feedback,
|
|
InitialVector,
|
|
DES_BLOCKLEN
|
|
);
|
|
|
|
for (Offset = 0; Offset < PasswordLength ; Offset+= 8 )
|
|
{
|
|
RtlZeroMemory(
|
|
Block,
|
|
DES_BLOCKLEN
|
|
);
|
|
|
|
RtlCopyMemory(
|
|
Block,
|
|
Password+Offset,
|
|
MIN(DES_BLOCKLEN, PasswordLength - Offset)
|
|
);
|
|
|
|
XORBLOCK(Block, Feedback);
|
|
des(
|
|
Feedback,
|
|
Block,
|
|
KeyTable,
|
|
ENCRYPT
|
|
);
|
|
|
|
|
|
}
|
|
RtlCopyMemory(
|
|
OutputKey,
|
|
Feedback,
|
|
DES_BLOCKLEN
|
|
);
|
|
|
|
}
|
|
|
|
#define BITREVERSE(c) ((UCHAR)((((c & 0x01) ? 0x80 : 0x00)\
|
|
|((c & 0x02) ? 0x40 : 0x00)\
|
|
|((c & 0x04) ? 0x20 : 0x00)\
|
|
|((c & 0x08) ? 0x10 : 0x00)\
|
|
|((c & 0x10) ? 0x08 : 0x00)\
|
|
|((c & 0x20) ? 0x04 : 0x00)\
|
|
|((c & 0x40) ? 0x02 : 0x00))\
|
|
& 0xFE))
|
|
|
|
//
|
|
// This is the core routine that converts a buffer into a key. It is called
|
|
// by desHashPassword and desRandomKey
|
|
//
|
|
|
|
VOID
|
|
desHashBuffer(
|
|
IN PUCHAR LocalPassword,
|
|
IN ULONG PasswordLength,
|
|
IN OUT PUCHAR Key
|
|
)
|
|
{
|
|
ULONG Index;
|
|
BOOLEAN Forward;
|
|
PUCHAR KeyPointer = Key;
|
|
DESTable KeyTable;
|
|
|
|
RtlZeroMemory(
|
|
Key,
|
|
DES_BLOCKLEN
|
|
);
|
|
|
|
//
|
|
// Initialize our temporary parity vector
|
|
//
|
|
|
|
//
|
|
// Start fanfolding the bytes into the key
|
|
//
|
|
|
|
Forward = TRUE;
|
|
KeyPointer = Key;
|
|
for (Index = 0; Index < PasswordLength ; Index++ )
|
|
{
|
|
|
|
if (!Forward)
|
|
{
|
|
*(--KeyPointer) ^= BITREVERSE(LocalPassword[Index] & 0x7F);
|
|
}
|
|
else
|
|
{
|
|
*KeyPointer++ ^= (LocalPassword[Index] & 0x7F) << 1;
|
|
}
|
|
if (((Index+1) & 0x07) == 0) /* When MOD 8 equals 0 */
|
|
{
|
|
Forward = !Forward; /* Change direction. */
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Fix key parity
|
|
//
|
|
|
|
desFixupKeyParity(Key);
|
|
|
|
//
|
|
// Check for weak keys.
|
|
//
|
|
|
|
if (desIsWeakKey(Key))
|
|
{
|
|
Key[7] ^= 0xf0;
|
|
}
|
|
|
|
//
|
|
// Now calculate the des-cbc-mac of the original string
|
|
//
|
|
|
|
deskey(&KeyTable, Key);
|
|
|
|
//
|
|
// Now compute the CBC checksum of the string
|
|
//
|
|
|
|
desCbcChecksum(
|
|
LocalPassword,
|
|
PasswordLength,
|
|
Key, // initial vector
|
|
&KeyTable,
|
|
Key // output key
|
|
);
|
|
|
|
//
|
|
// Fix key parity
|
|
//
|
|
|
|
desFixupKeyParity(Key);
|
|
|
|
//
|
|
// Check for weak keys.
|
|
//
|
|
|
|
if (desIsWeakKey(Key))
|
|
{
|
|
Key[7] ^= 0xf0;
|
|
}
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
desHashPassword(
|
|
IN PSECURITY_STRING Password,
|
|
OUT PUCHAR Key
|
|
)
|
|
{
|
|
|
|
PUCHAR LocalPassword = NULL;
|
|
ULONG PasswordLength;
|
|
OEM_STRING OemPassword;
|
|
NTSTATUS Status;
|
|
|
|
|
|
//
|
|
// First convert the UNICODE string to an OEM string
|
|
//
|
|
|
|
|
|
|
|
Status = RtlUnicodeStringToOemString(
|
|
&OemPassword,
|
|
Password,
|
|
TRUE // allocate destination
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// We hash the password according to RFC1510
|
|
//
|
|
// This code is derived from the MIT Kerberos code in string2key.c
|
|
//
|
|
|
|
|
|
PasswordLength = ROUND_UP_COUNT(OemPassword.Length,8);
|
|
#ifdef KERNEL_MODE
|
|
LocalPassword = (PUCHAR) ExAllocatePool(NonPagedPool, PasswordLength);
|
|
#else
|
|
LocalPassword = (PUCHAR) LocalAlloc(0, PasswordLength);
|
|
#endif
|
|
if (LocalPassword == NULL)
|
|
{
|
|
RtlFreeOemString( &OemPassword );
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
LocalPassword,
|
|
OemPassword.Buffer,
|
|
OemPassword.Length
|
|
);
|
|
|
|
//
|
|
// Zero extend the password
|
|
//
|
|
|
|
RtlZeroMemory(
|
|
LocalPassword + OemPassword.Length,
|
|
PasswordLength - OemPassword.Length
|
|
);
|
|
|
|
|
|
//
|
|
// Initialize our temporary parity vector
|
|
//
|
|
desHashBuffer(
|
|
LocalPassword,
|
|
PasswordLength,
|
|
Key
|
|
);
|
|
RtlFreeOemString( &OemPassword );
|
|
#ifdef KERNEL_MODE
|
|
ExFreePool(LocalPassword);
|
|
#else
|
|
LocalFree(LocalPassword);
|
|
#endif
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
desRandomKey(
|
|
IN OPTIONAL PUCHAR Seed,
|
|
IN ULONG SeedLength,
|
|
OUT PUCHAR pbKey)
|
|
{
|
|
UCHAR Buffer[16];
|
|
do
|
|
{
|
|
CDGenerateRandomBits(Buffer,16);
|
|
|
|
desHashBuffer(
|
|
Buffer,
|
|
16,
|
|
pbKey
|
|
);
|
|
|
|
} while (desIsWeakKey(pbKey));
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
desControl(
|
|
IN ULONG Function,
|
|
IN PCRYPT_STATE_BUFFER StateBuffer,
|
|
IN PUCHAR InputBuffer,
|
|
IN ULONG InputBufferSize
|
|
)
|
|
{
|
|
PDES_STATE_BUFFER DesStateBuffer = (PDES_STATE_BUFFER) StateBuffer;
|
|
|
|
if (Function != CRYPT_CONTROL_SET_INIT_VECT)
|
|
{
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
if (InputBufferSize != DES_BLOCKLEN)
|
|
{
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
memcpy(
|
|
DesStateBuffer->InitializationVector,
|
|
InputBuffer,
|
|
DES_BLOCKLEN
|
|
);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
NTSTATUS NTAPI
|
|
desMacGeneralInitializeEx(
|
|
PUCHAR Key,
|
|
ULONG KeySize,
|
|
PUCHAR IV,
|
|
ULONG MessageType,
|
|
PCHECKSUM_BUFFER * ppcsBuffer
|
|
)
|
|
{
|
|
PDES_MAC_STATE_BUFFER DesKey = NULL;
|
|
|
|
//
|
|
// Make sure we were passed an appropriate keytable
|
|
//
|
|
|
|
|
|
if (KeySize != DES_KEYSIZE)
|
|
{
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
|
|
#ifdef KERNEL_MODE
|
|
DesKey = ExAllocatePool(NonPagedPool, sizeof(DES_MAC_STATE_BUFFER));
|
|
#else
|
|
DesKey = LocalAlloc(0, sizeof(DES_MAC_STATE_BUFFER));
|
|
#endif
|
|
if (DesKey == NULL)
|
|
{
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
//
|
|
// Create the key buffer
|
|
//
|
|
|
|
|
|
deskey(&DesKey->KeyTable, Key);
|
|
|
|
|
|
RtlCopyMemory(
|
|
DesKey->InitializationVector,
|
|
IV,
|
|
DES_BLOCKLEN
|
|
);
|
|
|
|
*ppcsBuffer = (PCHECKSUM_BUFFER) DesKey;
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
desMacInitializeEx(
|
|
PUCHAR Key,
|
|
ULONG KeySize,
|
|
ULONG MessageType,
|
|
PCHECKSUM_BUFFER * ppcsBuffer
|
|
)
|
|
{
|
|
UCHAR IV[DES_BLOCKLEN];
|
|
|
|
RtlZeroMemory(
|
|
IV,
|
|
DES_BLOCKLEN
|
|
);
|
|
|
|
return desMacGeneralInitializeEx(
|
|
Key,
|
|
KeySize,
|
|
IV,
|
|
MessageType,
|
|
ppcsBuffer
|
|
);
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
desMacKInitializeEx(
|
|
PUCHAR Key,
|
|
ULONG KeySize,
|
|
ULONG MessageType,
|
|
PCHECKSUM_BUFFER * ppcsBuffer
|
|
)
|
|
{
|
|
return desMacGeneralInitializeEx(
|
|
Key,
|
|
KeySize,
|
|
Key,
|
|
MessageType,
|
|
ppcsBuffer
|
|
);
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
desMacInitialize(ULONG dwSeed,
|
|
PCHECKSUM_BUFFER * ppcsBuffer)
|
|
{
|
|
return(STATUS_NOT_IMPLEMENTED);
|
|
}
|
|
|
|
//
|
|
// NOTE - This function is used with both DES_MAC_STATE_BUFFER and
|
|
// DES_MAC_1510_STATE_BUFFER as the pcsBuffer parameter, since the
|
|
// DES_MAC_1510_STATE_BUFFER is the same as DES_MAC_STATE_BUFFER
|
|
// except with an added confounder this should be OK.
|
|
//
|
|
NTSTATUS NTAPI
|
|
desMacSum(
|
|
PCHECKSUM_BUFFER pcsBuffer,
|
|
ULONG cbData,
|
|
PUCHAR pbData)
|
|
{
|
|
PDES_MAC_STATE_BUFFER DesKey = (PDES_MAC_STATE_BUFFER) pcsBuffer;
|
|
UCHAR FeedBack[DES_BLOCKLEN];
|
|
UCHAR TempBuffer[DES_BLOCKLEN];
|
|
UCHAR OutputBuffer[DES_BLOCKLEN];
|
|
ULONG Index;
|
|
|
|
//
|
|
// Set up the IV for this round - it may be zero or the output of
|
|
// a previous MAC
|
|
//
|
|
|
|
memcpy(
|
|
FeedBack,
|
|
DesKey->InitializationVector,
|
|
DES_BLOCKLEN
|
|
);
|
|
|
|
for (Index = 0; Index < cbData ; Index += DES_BLOCKLEN )
|
|
{
|
|
//
|
|
// Compute the input buffer, with padding
|
|
//
|
|
|
|
if (Index+DES_BLOCKLEN > cbData)
|
|
{
|
|
memset(
|
|
TempBuffer,
|
|
0,
|
|
DES_BLOCKLEN
|
|
);
|
|
memcpy(
|
|
TempBuffer,
|
|
pbData,
|
|
Index & (DES_BLOCKLEN-1)
|
|
);
|
|
|
|
}
|
|
else
|
|
{
|
|
memcpy(
|
|
TempBuffer,
|
|
pbData+Index,
|
|
DES_BLOCKLEN
|
|
);
|
|
}
|
|
|
|
|
|
CBC( des,
|
|
DES_BLOCKLEN,
|
|
TempBuffer,
|
|
OutputBuffer,
|
|
&DesKey->KeyTable,
|
|
ENCRYPT,
|
|
FeedBack
|
|
);
|
|
}
|
|
|
|
//
|
|
// Copy the feedback back into the IV for the next round
|
|
//
|
|
|
|
memcpy(
|
|
DesKey->InitializationVector,
|
|
FeedBack,
|
|
DES_BLOCKLEN
|
|
);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
desMacFinalize(
|
|
PCHECKSUM_BUFFER pcsBuffer,
|
|
PUCHAR pbSum)
|
|
{
|
|
PDES_MAC_STATE_BUFFER DesKey = (PDES_MAC_STATE_BUFFER) pcsBuffer;
|
|
|
|
memcpy(pbSum, DesKey->InitializationVector, DES_BLOCKLEN);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
desMacFinish( PCHECKSUM_BUFFER * ppcsBuffer)
|
|
{
|
|
#ifdef KERNEL_MODE
|
|
ExFreePool(*ppcsBuffer);
|
|
#else
|
|
LocalFree(*ppcsBuffer);
|
|
#endif
|
|
*ppcsBuffer = 0;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
desMac1510Initialize(ULONG dwSeed,
|
|
PCHECKSUM_BUFFER * ppcsBuffer)
|
|
{
|
|
return(STATUS_NOT_IMPLEMENTED);
|
|
}
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
desMac1510InitializeEx(
|
|
PUCHAR Key,
|
|
ULONG KeySize,
|
|
ULONG MessageType,
|
|
PCHECKSUM_BUFFER * ppcsBuffer
|
|
)
|
|
{
|
|
return(STATUS_NOT_IMPLEMENTED);
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
desMac1510InitializeEx2(
|
|
PUCHAR Key,
|
|
ULONG KeySize,
|
|
PUCHAR ChecksumToVerify,
|
|
ULONG MessageType,
|
|
PCHECKSUM_BUFFER * ppcsBuffer
|
|
)
|
|
{
|
|
ULONG *pul;
|
|
ULONG *pul2;
|
|
UCHAR FinalKey[DES_KEYSIZE];
|
|
PDES_MAC_1510_STATE_BUFFER DesKey = NULL;
|
|
|
|
//
|
|
// Make sure we were passed an appropriate keytable
|
|
//
|
|
|
|
|
|
if (KeySize != DES_KEYSIZE)
|
|
{
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
|
|
#ifdef KERNEL_MODE
|
|
DesKey = ExAllocatePool(NonPagedPool, sizeof(DES_MAC_1510_STATE_BUFFER));
|
|
#else
|
|
DesKey = LocalAlloc(0, sizeof(DES_MAC_1510_STATE_BUFFER));
|
|
#endif
|
|
if (DesKey == NULL)
|
|
{
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
//
|
|
// create the final key table
|
|
//
|
|
pul = (ULONG*)FinalKey;
|
|
pul2 = (ULONG*)Key;
|
|
*pul = *pul2 ^ 0xf0f0f0f0;
|
|
pul = (ULONG*)(FinalKey + sizeof(ULONG));
|
|
pul2 = (ULONG*)(Key + sizeof(ULONG));
|
|
*pul = *pul2 ^ 0xf0f0f0f0;
|
|
|
|
deskey(&DesKey->FinalKeyTable, FinalKey);
|
|
|
|
//
|
|
// Checksum was not passed in so generate a confounder
|
|
//
|
|
if (NULL == ChecksumToVerify)
|
|
{
|
|
CDGenerateRandomBits(DesKey->Confounder,DES_BLOCKLEN);
|
|
}
|
|
else
|
|
{
|
|
// the IV is all zero so no need to use CBC on first block
|
|
des(DesKey->Confounder, ChecksumToVerify, &DesKey->FinalKeyTable, DECRYPT);
|
|
}
|
|
|
|
//
|
|
// Create the key buffer
|
|
//
|
|
deskey(&DesKey->KeyTable, Key);
|
|
|
|
|
|
// the IV is all zero so no need to use CBC on first block, but the
|
|
// ecncrypted confounder becomes the next IV
|
|
des(DesKey->InitializationVector, DesKey->Confounder, &DesKey->KeyTable, ENCRYPT);
|
|
|
|
*ppcsBuffer = (PCHECKSUM_BUFFER) DesKey;
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
desMac1510Finalize(
|
|
PCHECKSUM_BUFFER pcsBuffer,
|
|
PUCHAR pbSum)
|
|
{
|
|
UCHAR Feedback[DES_BLOCKLEN];
|
|
PDES_MAC_1510_STATE_BUFFER DesKey = (PDES_MAC_1510_STATE_BUFFER) pcsBuffer;
|
|
|
|
// the IV is all zero so no need to use CBC on first block
|
|
des(Feedback, DesKey->Confounder, &DesKey->FinalKeyTable, ENCRYPT);
|
|
|
|
memcpy(pbSum, Feedback, DES_BLOCKLEN);
|
|
|
|
// use CBC on second block
|
|
CBC( des,
|
|
DES_BLOCKLEN,
|
|
pbSum + DES_BLOCKLEN,
|
|
DesKey->InitializationVector,
|
|
&DesKey->FinalKeyTable,
|
|
ENCRYPT,
|
|
Feedback
|
|
);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|