none
CardGetChallenge, How To Compute Response? RRS feed

  • Question

  • Hello All,

    Can someone provide a simple code example of how to compute the response from CardGetChallenge given that the admin pin is the default 24 '0' value?  The MSDN documentation does not explain what encryption method is necessary to achieve this goal.

    - Rashad Rivera


    - Rashad Rivera www.omegusprime.com

    Sunday, April 12, 2015 3:22 AM

Answers

  • So the solution cost me $1,800 and 5 months. Nevertheless, I post it freely so everyone will know and won't have to pay a consultant for something that Microsoft should have included in their documentation:

    THIS IS A C++ CODE EXAMPLE

    HEADER.H

    #define CHECK_ERROR_MSG(X) if(X != NO_ERROR) { goto error; } 

    __declspec(dllexport) DWORD WINAPI MgScCardCalculateResponse(
    	__in_bcount(cbPin)							PBYTE       pbChallenge,
    	__in										DWORD       cbChallenge,
    	__in_bcount(cbPin)							PBYTE       pbAdminPin,
    	__in										DWORD       cbAdminPin,
    	__deref_out_bcount(*pcbChallengeData)		PBYTE		*ppbResponseData,
    	__out										PDWORD		cbResponseData) {
    
    
    	HCRYPTPROV crypt_handle = NULL;
    	DWORD dwMode = CRYPT_MODE_ECB;
    	HCRYPTKEY key_handle = 0;
    	const size_t DES_HEADER_LENGTH = 12;
    
    	HRESULT returnCode = NO_ERROR;
    	HRESULT ret;
    
    	BYTE blob[] = {
    		0x08, 0x02, 0x00, 0x00, 0x03, 0x66, 0x00, 0x00,
    		0x18, 0x00, 0x00, 0x00,
    
    		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    	};
    
    	*cbResponseData = cbChallenge;
    	*ppbResponseData = (PBYTE)_Alloc(cbChallenge);
    
    	memcpy(blob + DES_HEADER_LENGTH, pbAdminPin, cbAdminPin);
    	memcpy(*ppbResponseData, pbChallenge, sizeof(BYTE) * cbChallenge);
    
    	// Get Cryto-context
    	ret = CryptAcquireContext(&crypt_handle, NULL, L"Microsoft Enhanced Cryptographic Provider V1.0", PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
    	CHECK_ERROR_MSG(!ret);
    
    	// Import Deskey
    	ret = CryptImportKey(crypt_handle, blob, sizeof(blob), 0, 0, &key_handle);
    	CHECK_ERROR_MSG(!ret);
    
    	// Set Deskey
    	ret = CryptSetKeyParam(key_handle, KP_MODE, (BYTE *)&dwMode, 0);
    	CHECK_ERROR_MSG(!ret);
    
    	// Encrypt data
    	DWORD length = *cbResponseData;
    	ret = CryptEncrypt(key_handle, 0, FALSE, 0, *ppbResponseData, &length, length);
    	CHECK_ERROR_MSG(!ret);
    
    	goto cleanup;
    
    error:
    	returnCode = ret;
    
    cleanup:
    
    	if (key_handle)
    	{
    		CryptDestroyKey(key_handle);
    		key_handle = NULL;
    	}
    
    	if (crypt_handle)
    	{
    		CryptReleaseContext(crypt_handle, 0);
    	}
    
    	return returnCode;
    }
    CODE.CPP


    - Rashad Rivera www.omegusprime.com



    • Edited by Rashad Rivera Saturday, September 12, 2015 2:04 AM
    • Marked as answer by Rashad Rivera Saturday, September 12, 2015 2:04 AM
    Saturday, September 12, 2015 2:00 AM

All replies

  • I'm more than shocked that no one knows how to do this. Its really depressing to also see that not even Microsoft was incline to answer. Very disappointed in this community and have never seen such a poor display of support.

    - Rashad Rivera www.omegusprime.com

    Sunday, April 26, 2015 5:45 AM
  • The Microsofties are a bit busy with this little project they're working on called Windows 10. The rest of us do not get paid to answer your questions. So, cut everyone some slack. If you want guaranteed responses in a short period of time, either buy support or hire one of us as a consultant.

    First, you need to educate yourself on cryptography in general, and Windows CNG in particular. Then you need to learn about smart cards (ISO 7816, and PC/SC)). If you do these things, you'll learn that the smart card challenge/response uses 3DES in cipher block chaining mode, and that you have to encrypt the challenge data given to you. Here is an example in C# for what you have to do.

     -Brian


    Azius Developer Training www.azius.com Windows device driver, internals, security, & forensics training and consulting. Blog at www.azius.com/blog

    Sunday, April 26, 2015 9:59 PM
    Moderator
  • Brian,

    Thank you for your response.  I've been desperately struggling with this issue for over a month now. So I really appreciate your candor.  Hopefully you can take some of mine.

    1. I should point out that this forum does not strike me as a place to solicited consultants. 
    2. I've been struggling with the MS Premier Developer Support for weeks.  Filling out their page has yielded no responses.  
    3. It’s a sad state of affairs when no one answers the mail.  Granted, folks may be busy with Win10, but that business practice/attitude does little to help use solve our business needs and fosters the notion that our posts are not being taken seriously.

    Concerning your code example: I've seen that code example you provided, but wrote it off as it was exclusively for Win 8.1 and I'm using Win2008R2.   

    To All Consultants:

    I am in need of your support and ask that you please contact me at riverar _AT_ OmegusPrime.com with "CNG Consultant" in subject line to initiate a contract.

    - Rashad Rivera
    Friday, May 1, 2015 3:25 PM
  • Brian,

    After dealing with Microsoft's Developer Advisory for over a month now, I realize that your answer is not as simple as you make it out to be.  I've paid Microsoft their $1,800 shillings and had my requests closed twice with the technical routing team shut gunning my request to every queue they can find save for the right one.  I still feel this is a gross deficiency on Microsoft's part due to lack luster documentation and inadequate support which causes a nitch market in where entrepreneurs are exploited.  I don’t see poorly documented function like this in WPF, ASP.NET, MVC, ect. 

    Microsoft's only saving grace was a Windows 2008 R2 technical advisor who took the time to contact the correct team via a side channel.

    To Nithish Raja Chidambaram,

    Thank you for straightening out this bag of snakes for me and I will commend you in my letter to Microsoft's Board of directors soon.

    - Rashad Rivera


    - Rashad Rivera www.omegusprime.com

    Tuesday, June 9, 2015 4:11 AM
  • So the solution cost me $1,800 and 5 months. Nevertheless, I post it freely so everyone will know and won't have to pay a consultant for something that Microsoft should have included in their documentation:

    THIS IS A C++ CODE EXAMPLE

    HEADER.H

    #define CHECK_ERROR_MSG(X) if(X != NO_ERROR) { goto error; } 

    __declspec(dllexport) DWORD WINAPI MgScCardCalculateResponse(
    	__in_bcount(cbPin)							PBYTE       pbChallenge,
    	__in										DWORD       cbChallenge,
    	__in_bcount(cbPin)							PBYTE       pbAdminPin,
    	__in										DWORD       cbAdminPin,
    	__deref_out_bcount(*pcbChallengeData)		PBYTE		*ppbResponseData,
    	__out										PDWORD		cbResponseData) {
    
    
    	HCRYPTPROV crypt_handle = NULL;
    	DWORD dwMode = CRYPT_MODE_ECB;
    	HCRYPTKEY key_handle = 0;
    	const size_t DES_HEADER_LENGTH = 12;
    
    	HRESULT returnCode = NO_ERROR;
    	HRESULT ret;
    
    	BYTE blob[] = {
    		0x08, 0x02, 0x00, 0x00, 0x03, 0x66, 0x00, 0x00,
    		0x18, 0x00, 0x00, 0x00,
    
    		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    	};
    
    	*cbResponseData = cbChallenge;
    	*ppbResponseData = (PBYTE)_Alloc(cbChallenge);
    
    	memcpy(blob + DES_HEADER_LENGTH, pbAdminPin, cbAdminPin);
    	memcpy(*ppbResponseData, pbChallenge, sizeof(BYTE) * cbChallenge);
    
    	// Get Cryto-context
    	ret = CryptAcquireContext(&crypt_handle, NULL, L"Microsoft Enhanced Cryptographic Provider V1.0", PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
    	CHECK_ERROR_MSG(!ret);
    
    	// Import Deskey
    	ret = CryptImportKey(crypt_handle, blob, sizeof(blob), 0, 0, &key_handle);
    	CHECK_ERROR_MSG(!ret);
    
    	// Set Deskey
    	ret = CryptSetKeyParam(key_handle, KP_MODE, (BYTE *)&dwMode, 0);
    	CHECK_ERROR_MSG(!ret);
    
    	// Encrypt data
    	DWORD length = *cbResponseData;
    	ret = CryptEncrypt(key_handle, 0, FALSE, 0, *ppbResponseData, &length, length);
    	CHECK_ERROR_MSG(!ret);
    
    	goto cleanup;
    
    error:
    	returnCode = ret;
    
    cleanup:
    
    	if (key_handle)
    	{
    		CryptDestroyKey(key_handle);
    		key_handle = NULL;
    	}
    
    	if (crypt_handle)
    	{
    		CryptReleaseContext(crypt_handle, 0);
    	}
    
    	return returnCode;
    }
    CODE.CPP


    - Rashad Rivera www.omegusprime.com



    • Edited by Rashad Rivera Saturday, September 12, 2015 2:04 AM
    • Marked as answer by Rashad Rivera Saturday, September 12, 2015 2:04 AM
    Saturday, September 12, 2015 2:00 AM