⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 krnlapi.cxx

📁 安全支持提供器接口(SSPI)源码
💻 CXX
📖 第 1 页 / 共 5 页
字号:
        // 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 + -