📄 krnlapi.cxx
字号:
// 56bit is enabled because this was introduced in Win2k, and
// Win2k -> Win2k interops correctly.
//
#if 0
if( NegotiateFlags & NTLMSSP_NEGOTIATE_128 ) {
KeyLen = 8;
} else
#endif
if( NegotiateFlags & NTLMSSP_NEGOTIATE_56 ) {
KeyLen = 7;
//
// Put a well-known salt at the end of the key to
// limit the changing part to 56 bits.
//
Key[7] = 0xa0;
} else {
KeyLen = 5;
//
// Put a well-known salt at the end of the key to
// limit the changing part to 40 bits.
//
Key[5] = 0xe5;
Key[6] = 0x38;
Key[7] = 0xb0;
}
/// DebugLog(( SSP_SESSION_KEYS, "Non NTLMv2 session key size: %lu\n", KeyLen));
RtlCopyMemory(Key,pSessionKey,KeyLen);
rc4_key(pRc4Key, MSV1_0_LANMAN_SESSION_KEY_LENGTH, Key);
} else {
rc4_key(pRc4Key, MSV1_0_USER_SESSION_KEY_LENGTH, pSessionKey);
}
}
SECURITY_STATUS
SspSignSealHelper(
IN PNTLM_KERNEL_CONTEXT pContext,
IN eSignSealOp Op,
IN OUT PSecBufferDesc pMessage,
IN ULONG MessageSeqNo,
OUT PNTLMSSP_MESSAGE_SIGNATURE pSig,
OUT PNTLMSSP_MESSAGE_SIGNATURE * ppSig
)
/*++
RoutineDescription:
Handle signing a message
Arguments:
Return Value:
--*/
{
HMACMD5_CTX HMACMD5Context;
UCHAR TempSig[MD5DIGESTLEN];
NTLMSSP_MESSAGE_SIGNATURE Sig;
int Signature;
ULONG i;
PUCHAR pKey; // ptr to key to use for encryption
PUCHAR pSignKey; // ptr to key to use for signing
PULONG pNonce; // ptr to nonce to use
struct RC4_KEYSTRUCT * pRc4Sched; // ptr to key schedule to use
MAYBE_PAGED_CODE();
Signature = -1;
for (i = 0; i < pMessage->cBuffers; i++)
{
if ((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_TOKEN)
{
Signature = i;
break;
}
}
if (Signature == -1)
{
return(SEC_E_INVALID_TOKEN);
}
if (pMessage->pBuffers[Signature].cbBuffer < NTLMSSP_MESSAGE_SIGNATURE_SIZE)
{
return(SEC_E_INVALID_TOKEN);
}
*ppSig = (NTLMSSP_MESSAGE_SIGNATURE*)pMessage->pBuffers[Signature].pvBuffer;
//
// If sequence detect wasn't requested, put on an empty
// security token . Don't do the check if Seal/Unseal is called.
//
if (!(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN) &&
(Op == eSign || Op == eVerify))
{
RtlZeroMemory(pSig,NTLMSSP_MESSAGE_SIGNATURE_SIZE);
pSig->Version = NTLM_SIGN_VERSION;
return(SEC_E_OK);
}
// figure out which key, key schedule, and nonce to use
// depends on the op. SspAddLocalContext set up so that code on client
// and server just (un)seals with (un)seal key or key schedule, etc.
// and also sets pointers to share sending/receiving key schedule/nonce
// when in half duplex mode. Hence, this code gets to act as if it were
// always in full duplex mode.
switch (Op) {
case eSeal:
pSignKey = pContext->SignSessionKey; // if NTLM2
pKey = pContext->SealSessionKey;
pRc4Sched = pContext->pSealRc4Sched;
pNonce = pContext->pSendNonce;
break;
case eUnseal:
pSignKey = pContext->VerifySessionKey; // if NTLM2
pKey = pContext->UnsealSessionKey;
pRc4Sched = pContext->pUnsealRc4Sched;
pNonce = pContext->pRecvNonce;
break;
case eSign:
pSignKey = pContext->SignSessionKey; // if NTLM2
pKey = pContext->SealSessionKey; // might be used to encrypt the signature
pRc4Sched = pContext->pSealRc4Sched;
pNonce = pContext->pSendNonce;
break;
case eVerify:
pSignKey = pContext->VerifySessionKey; // if NTLM2
pKey = pContext->UnsealSessionKey; // might be used to decrypt the signature
pRc4Sched = pContext->pUnsealRc4Sched;
pNonce = pContext->pRecvNonce;
break;
}
//
// Either we can supply the sequence number, or
// the application can supply the message sequence number.
//
Sig.Version = NTLM_SIGN_VERSION;
// if we're doing the new NTLM2 version:
if (pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2) {
if ((pContext->NegotiateFlags & NTLMSSP_APP_SEQ) == 0)
{
Sig.Nonce = *pNonce; // use our sequence number
(*pNonce) += 1;
}
else {
if (Op == eSeal || Op == eSign || MessageSeqNo != 0)
Sig.Nonce = MessageSeqNo;
else
Sig.Nonce = (*ppSig)->Nonce;
// if using RC4, must rekey for each packet
// RC4 is used for seal, unseal; and for encrypting the HMAC hash if
// key exchange was negotiated (we use just HMAC if no key exchange,
// so that a good signing option exists with no RC4 encryption needed)
if (Op == eSeal || Op == eUnseal || pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
{
MD5_CTX Md5ContextReKey;
MD5Init(&Md5ContextReKey);
MD5Update(&Md5ContextReKey, pKey, MSV1_0_USER_SESSION_KEY_LENGTH);
MD5Update(&Md5ContextReKey, (unsigned char*)&Sig.Nonce, sizeof(Sig.Nonce));
MD5Final(&Md5ContextReKey);
ASSERT(MD5DIGESTLEN == MSV1_0_USER_SESSION_KEY_LENGTH);
SspRc4Key(pContext->NegotiateFlags, pRc4Sched, Md5ContextReKey.digest);
}
}
//
// using HMAC hash, init it with the key
//
HMACMD5Init(&HMACMD5Context, pSignKey, MSV1_0_USER_SESSION_KEY_LENGTH);
//
// include the message sequence number
//
HMACMD5Update(&HMACMD5Context, (unsigned char*)&Sig.Nonce, sizeof(Sig.Nonce));
for (i = 0; i < pMessage->cBuffers ; i++ )
{
if (((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_DATA) &&
(pMessage->pBuffers[i].cbBuffer != 0))
{
// decrypt (before checksum...) if it's not READ_ONLY
if ((Op==eUnseal)
&& !(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY)
)
{
SspEncryptBuffer(
pContext,
pRc4Sched,
pMessage->pBuffers[i].cbBuffer,
pMessage->pBuffers[i].pvBuffer
);
}
HMACMD5Update(
&HMACMD5Context,
(unsigned char*)pMessage->pBuffers[i].pvBuffer,
pMessage->pBuffers[i].cbBuffer);
//
// Encrypt if its not READ_ONLY
//
if ((Op==eSeal)
&& !(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY)
)
{
SspEncryptBuffer(
pContext,
pRc4Sched,
pMessage->pBuffers[i].cbBuffer,
pMessage->pBuffers[i].pvBuffer
);
}
}
}
HMACMD5Final(&HMACMD5Context, TempSig);
//
// use RandomPad and Checksum fields for 8 bytes of MD5 hash
//
RtlCopyMemory(&Sig.RandomPad, TempSig, 8);
//
// if we're using crypto for KEY_EXCH, may as well use it for signing too...
//
if (pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
SspEncryptBuffer(
pContext,
pRc4Sched,
8,
&Sig.RandomPad
);
}
//
// pre-NTLM2 methods
//
else {
//
// required by CRC-32 algorithm
//
Sig.CheckSum = 0xffffffff;
for (i = 0; i < pMessage->cBuffers ; i++ )
{
if (((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_DATA) &&
!(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY) &&
(pMessage->pBuffers[i].cbBuffer != 0))
{
// decrypt (before checksum...)
if (Op==eUnseal)
{
SspEncryptBuffer(
pContext,
pRc4Sched,
pMessage->pBuffers[i].cbBuffer,
pMessage->pBuffers[i].pvBuffer
);
}
SspGenCheckSum(&pMessage->pBuffers[i], &Sig);
// Encrypt
if (Op==eSeal)
{
SspEncryptBuffer(
pContext,
pRc4Sched,
pMessage->pBuffers[i].cbBuffer,
pMessage->pBuffers[i].pvBuffer
);
}
}
}
//
// Required by CRC-32 algorithm
//
Sig.CheckSum ^= 0xffffffff;
// when we encrypt 0, we will get the cipher stream for the nonce!
Sig.Nonce = 0;
SspEncryptBuffer(
pContext,
pRc4Sched,
sizeof(NTLMSSP_MESSAGE_SIGNATURE) - sizeof(ULONG),
&Sig.RandomPad
);
if ((pContext->NegotiateFlags & NTLMSSP_APP_SEQ) == 0)
{
Sig.Nonce ^= *pNonce; // use our sequence number and encrypt it
(*pNonce) += 1;
}
else if (Op == eSeal || Op == eSign || MessageSeqNo != 0)
Sig.Nonce ^= MessageSeqNo; // use caller's sequence number and encrypt it
else
Sig.Nonce = (*ppSig)->Nonce; // use sender's sequence number
//
// for SignMessage calling, does nothing (copies garbage)
// For VerifyMessage calling, allows it to compare sig block
// upon return to Verify without knowing whether its MD5 or CRC32
//
Sig.RandomPad = (*ppSig)->RandomPad;
}
pMessage->pBuffers[Signature].cbBuffer = sizeof(NTLMSSP_MESSAGE_SIGNATURE);
RtlCopyMemory(
pSig,
&Sig,
NTLMSSP_MESSAGE_SIGNATURE_SIZE
);
return(SEC_E_OK);
}
//+-------------------------------------------------------------------------
//
// Function: NtLmMakeSignature
//
// Synopsis: Signs a message buffer by calculatinga checksum over all
// the non-read only data buffers and encrypting the checksum
// along with a nonce.
//
// Effects:
//
// Arguments: KernelContextHandle - Handle of the context to use to sign the
// message.
// QualityOfProtection - Unused flags.
// MessageBuffers - Contains an array of buffers to sign and
// to store the signature.
// MessageSequenceNumber - Sequence number for this message,
// only used in datagram cases.
//
// Requires: STATUS_INVALID_HANDLE - the context could not be found or
// was not configured for message integrity.
// STATUS_INVALID_PARAMETER - the signature buffer could not
// be found.
// STATUS_BUFFER_TOO_SMALL - the signature buffer is too small
// to hold the signature
//
// Returns:
//
// Notes: This was stolen from net\svcdlls\ntlmssp\client\sign.c ,
// routine SspHandleSignMessage. It's possible that
// bugs got copied too
//
//
//--------------------------------------------------------------------------
NTSTATUS NTAPI
NtLmMakeSignature(
IN ULONG_PTR KernelContextHandle,
IN ULONG fQOP,
IN PSecBufferDesc pMessage,
IN ULONG MessageSeqNo
)
{
NTSTATUS Status = STATUS_SUCCESS;
PNTLM_KERNEL_CONTEXT pContext;
NTLMSSP_MESSAGE_SIGNATURE Sig;
NTLMSSP_MESSAGE_SIGNATURE *pSig;
MAYBE_PAGED_CODE();
DebugLog(( DEB_TRACE, "Entering NtLmMakeSignature\n" ));
UNREFERENCED_PARAMETER(fQOP);
Status = NtlmReferenceContext( KernelContextHandle, FALSE );
if ( NT_SUCCESS( Status ) )
{
pContext = (PNTLM_KERNEL_CONTEXT) KernelContextHandle ;
}
else
{
DebugLog(( DEB_ERROR,
"Bad kernel context 0x%lx\n", KernelContextHandle));
goto CleanUp_NoDeref;
}
Status = SspSignSealHelper(
pContext,
eSign,
pMessage,
MessageSeqNo,
&Sig,
&pSig
);
if( !NT_SUCCESS( Status ) )
{
DebugLog(( DEB_ERROR, "NtLmMakeSignature, SspSignSealHelper returns %lx\n", Status ));
goto CleanUp;
}
RtlCopyMemory(
pSig,
&Sig,
NTLMSSP_MESSAGE_SIGNATURE_SIZE
);
CleanUp:
NtlmDerefContext( pContext );
CleanUp_NoDeref:
DebugLog(( DEB_TRACE, "Leaving NtLmMakeSignature 0x%lx\n", Status ));
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: NtLmVerifySignature
//
// Synopsis: Verifies a signed message buffer by calculating a checksum over all
// the non-read only data buffers and encrypting the checksum
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -