416 lines
11 KiB
C++
416 lines
11 KiB
C++
|
//
|
||
|
// file: drctencp.cpp
|
||
|
//
|
||
|
//
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// Copyright 1997-1999 Microsoft Corporation. All Rights Reserved.
|
||
|
//
|
||
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||
|
// PARTICULAR PURPOSE.
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <wincrypt.h>
|
||
|
#include <STDIO.H>
|
||
|
#include <mq.h>
|
||
|
|
||
|
|
||
|
//
|
||
|
// Globals.
|
||
|
//
|
||
|
|
||
|
BOOL fEnhEncrypted = FALSE ;
|
||
|
QMPROPID propidPK = PROPID_QM_ENCRYPTION_PK;
|
||
|
WCHAR wszMachineName[ 128 ] = {0} ;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void Usage(char * pszProgramName)
|
||
|
{
|
||
|
fprintf(stderr, "...Usage: %s\n", pszProgramName);
|
||
|
fprintf(stderr, "\t-2 send encrypted, RC2\n") ;
|
||
|
fprintf(stderr, "\t-4 send encrypted, RC4\n") ;
|
||
|
fprintf(stderr, "\t-b <Message Body>\n") ;
|
||
|
fprintf(stderr, "\t-e Enhanced Encryption\n") ;
|
||
|
fprintf(stderr, "\t-l <Message Label>\n") ;
|
||
|
fprintf(stderr, "\t-m <Name of destination machine>\n") ;
|
||
|
fprintf(stderr, "\t-q <Queue name>\n") ;
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
BOOL getPublicKeyBlob( PBYTE* pbPbKeyxKey, DWORD* pdwPbKeyxKeyLen)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine retrieves the public key of the remote machine.
|
||
|
The key is retrieved using the MQGetMachineProperties() API which connects to the Ds to retrieve
|
||
|
the specified properties .
|
||
|
Usually when using Direct mode no DS connection is available.
|
||
|
This routine comes only as a substitute to other means of obtaining the
|
||
|
remote machine public key. (SSL protocol, via disk or file etc') .
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pbPbKeyxKey - (OUT) pointer to the Key.
|
||
|
pdwPbKeyxKeyLen - (OUT) pointer to the key length
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - if the Key was retreived .
|
||
|
FALSE - if the Key couldn't be reteived.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
if (fEnhEncrypted)
|
||
|
{
|
||
|
propidPK = PROPID_QM_ENCRYPTION_PK_ENHANCED ;
|
||
|
}
|
||
|
|
||
|
QMPROPID aQmPropId[1] ;
|
||
|
aQmPropId[0] = propidPK ;
|
||
|
#define QMPROPS (sizeof(aQmPropId) / sizeof(*aQmPropId))
|
||
|
|
||
|
MQPROPVARIANT aQmPropVar[QMPROPS];
|
||
|
HRESULT aQmStatus[QMPROPS];
|
||
|
|
||
|
MQQMPROPS QmProps = {QMPROPS, aQmPropId, aQmPropVar, aQmStatus};
|
||
|
|
||
|
aQmPropVar[0].vt = VT_NULL;
|
||
|
|
||
|
HRESULT hr = MQGetMachineProperties(wszMachineName, NULL, &QmProps);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
printf(
|
||
|
"ERROR: Could not retrieve public key of %S, hr- %lxh\n",
|
||
|
wszMachineName, hr);
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (aQmPropVar[0].vt != (VT_UI1|VT_VECTOR))
|
||
|
{
|
||
|
printf(
|
||
|
"Wrong VT after MQGetMachineProperties(), vt- %lxh, QMPROPS- %lut, hr- %lxh\n",
|
||
|
aQmPropVar[0].vt, QMPROPS, hr) ;
|
||
|
return FALSE ;
|
||
|
}
|
||
|
|
||
|
*pbPbKeyxKey = aQmPropVar[0].caub.pElems;
|
||
|
*pdwPbKeyxKeyLen = aQmPropVar[0].caub.cElems;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
|
||
|
DWORD dwEncryptAlg = CALG_RC2 ;
|
||
|
WCHAR wszQueueName[ 128 ] = {0} ;
|
||
|
WCHAR wszMsgLabel[ 128 ] = {TEXT("MessageLabel")} ;
|
||
|
WCHAR wszMsgBody[ 128 ] = {TEXT("MessageBody")} ;
|
||
|
LPSTR lpszArg = NULL ;
|
||
|
DWORD dwMsgSize = sizeof(WCHAR) * (1 + wcslen(wszMsgBody)) ;
|
||
|
DWORD dwBufferSize = sizeof(wszMsgBody) ;
|
||
|
LPWSTR pMsgBody = wszMsgBody ;
|
||
|
|
||
|
//
|
||
|
// allow the user to override settings with command line switches
|
||
|
//
|
||
|
for ( int i = 1; i < argc; i++)
|
||
|
{
|
||
|
if ((*argv[i] == '-') || (*argv[i] == '/'))
|
||
|
{
|
||
|
switch (*(argv[i]+1))
|
||
|
{
|
||
|
case '2':
|
||
|
dwEncryptAlg = CALG_RC2 ;
|
||
|
break ;
|
||
|
|
||
|
case '4':
|
||
|
dwEncryptAlg = CALG_RC4 ;
|
||
|
break ;
|
||
|
|
||
|
case 'e':
|
||
|
fEnhEncrypted = TRUE ;
|
||
|
break ;
|
||
|
|
||
|
case 'b':
|
||
|
lpszArg = argv[++i];
|
||
|
mbstowcs(wszMsgBody, lpszArg, 127) ;
|
||
|
break;
|
||
|
|
||
|
case 'l':
|
||
|
lpszArg = argv[++i];
|
||
|
mbstowcs(wszMsgLabel, lpszArg, 127) ;
|
||
|
break;
|
||
|
|
||
|
case 'm':
|
||
|
lpszArg = argv[++i];
|
||
|
mbstowcs(wszMachineName, lpszArg, 127) ;
|
||
|
break;
|
||
|
|
||
|
case 'q':
|
||
|
lpszArg = argv[++i];
|
||
|
mbstowcs(wszQueueName, lpszArg, 127) ;
|
||
|
break;
|
||
|
|
||
|
case 'h':
|
||
|
case '?':
|
||
|
default:
|
||
|
Usage(argv[0]);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Usage(argv[0]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dwMsgSize = sizeof(WCHAR) * (1 + wcslen(wszMsgBody)) ;
|
||
|
|
||
|
//
|
||
|
// Get the public key blob of the destination computer.
|
||
|
//
|
||
|
|
||
|
PBYTE pbPbKeyxKey = NULL;
|
||
|
DWORD dwPbKeyxKeyLen = 0;
|
||
|
|
||
|
if (getPublicKeyBlob( &pbPbKeyxKey, &dwPbKeyxKeyLen))
|
||
|
{
|
||
|
printf("Public key of %S retrieved successfully, len- %lut\n",
|
||
|
wszMachineName, dwPbKeyxKeyLen) ;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return -1 ;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get a handle to the default CSP.
|
||
|
//
|
||
|
LPWSTR lpwszProviderName = MS_DEF_PROV ;
|
||
|
if (fEnhEncrypted)
|
||
|
{
|
||
|
lpwszProviderName = MS_ENHANCED_PROV ;
|
||
|
}
|
||
|
HCRYPTPROV hProv = NULL;
|
||
|
|
||
|
BOOL bRet = CryptAcquireContext( &hProv,
|
||
|
NULL,
|
||
|
lpwszProviderName,
|
||
|
PROV_RSA_FULL,
|
||
|
0 ) ;
|
||
|
if (!bRet)
|
||
|
{
|
||
|
if (GetLastError() == NTE_BAD_KEYSET)
|
||
|
{
|
||
|
//
|
||
|
// The default key container does not exist yet, create it.
|
||
|
//
|
||
|
if (!CryptAcquireContext( &hProv,
|
||
|
NULL,
|
||
|
lpwszProviderName,
|
||
|
PROV_RSA_FULL,
|
||
|
CRYPT_NEWKEYSET ))
|
||
|
{
|
||
|
printf(
|
||
|
"CryptAcquireContext(%s, CRYPT_NEWKEYSET) failed, error- %lxh\n",
|
||
|
lpwszProviderName, GetLastError());
|
||
|
return -1;
|
||
|
}
|
||
|
printf("CryptAcquireContext(%s, CRYPT_NEWKEYSET) succeeded\n",
|
||
|
lpwszProviderName) ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf(
|
||
|
"CryptAcquireContext(%s) failed, error- %lxh\n",
|
||
|
lpwszProviderName, GetLastError());
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("CryptAcquireContext(%s) succeeded\n", lpwszProviderName) ;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Import the public key blob of the destination computer into the CSP.
|
||
|
//
|
||
|
HCRYPTKEY hPbKey = NULL;
|
||
|
|
||
|
if (!CryptImportKey( hProv,
|
||
|
pbPbKeyxKey,
|
||
|
dwPbKeyxKeyLen,
|
||
|
NULL,
|
||
|
0,
|
||
|
&hPbKey ))
|
||
|
{
|
||
|
printf("CryptImportKey() failed, error- %lxh\n", GetLastError());
|
||
|
return -1;
|
||
|
}
|
||
|
printf("CryptImportKey() succeeded\n") ;
|
||
|
|
||
|
//
|
||
|
// Free the public key blob of the destination computer.
|
||
|
//
|
||
|
MQFreeMemory(pbPbKeyxKey);
|
||
|
|
||
|
//
|
||
|
// Create a symmetric key.
|
||
|
//
|
||
|
HCRYPTKEY hSymmKey = NULL;
|
||
|
|
||
|
if (!CryptGenKey(hProv, dwEncryptAlg, CRYPT_EXPORTABLE, &hSymmKey))
|
||
|
{
|
||
|
printf("CryptGenKey() failed, error- %lxh\n", GetLastError());
|
||
|
return -1;
|
||
|
}
|
||
|
printf("CryptGenKey(alg- %lut) successfully created symmetric key\n",
|
||
|
dwEncryptAlg) ;
|
||
|
//
|
||
|
// Get the encrypted symmetric key blob. This blob should
|
||
|
// be passed to MQSendMessage in PROPID_M_DEST_SYMM_KEY.
|
||
|
//
|
||
|
BYTE abSymmKey[ 512 ];
|
||
|
DWORD dwSymmKeyLen = sizeof(abSymmKey);
|
||
|
|
||
|
if (!CryptExportKey( hSymmKey,
|
||
|
hPbKey,
|
||
|
SIMPLEBLOB,
|
||
|
0,
|
||
|
abSymmKey,
|
||
|
&dwSymmKeyLen ))
|
||
|
{
|
||
|
printf("CryptExportKey() failed, error- %lxh\n", GetLastError());
|
||
|
return -1;
|
||
|
}
|
||
|
printf("CryptExportKey() succeeded\n") ;
|
||
|
|
||
|
//
|
||
|
// Get a handle to the destination queue.
|
||
|
//
|
||
|
WCHAR szQueueFormat[128];
|
||
|
|
||
|
swprintf(szQueueFormat, TEXT("DIRECT=OS:%s\\%s"),
|
||
|
wszMachineName, wszQueueName);
|
||
|
|
||
|
QUEUEHANDLE hQueue = NULL;
|
||
|
|
||
|
HRESULT hr = MQOpenQueue(szQueueFormat, MQ_SEND_ACCESS, 0, &hQueue);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
printf("MQOpenQueue(%S) failed, error- %lxh\n", szQueueFormat, hr) ;
|
||
|
return -1;
|
||
|
}
|
||
|
printf("MQOpenQueue(%S) succeeded\n", szQueueFormat) ;
|
||
|
|
||
|
//
|
||
|
// Prepare the message properties.
|
||
|
//
|
||
|
GUID guid ;
|
||
|
|
||
|
MSGPROPID aMsgPropId[] = {PROPID_M_BODY,
|
||
|
PROPID_M_DEST_SYMM_KEY,
|
||
|
PROPID_M_ENCRYPTION_ALG,
|
||
|
PROPID_M_CONNECTOR_TYPE,
|
||
|
PROPID_M_LABEL,
|
||
|
PROPID_M_PRIV_LEVEL};
|
||
|
#define MSGPROPS (sizeof(aMsgPropId) / sizeof(*aMsgPropId))
|
||
|
|
||
|
MQPROPVARIANT aMsgPropVar[MSGPROPS];
|
||
|
HRESULT aMsgStatus[MSGPROPS];
|
||
|
|
||
|
MQMSGPROPS MsgProps = {MSGPROPS, aMsgPropId, aMsgPropVar, aMsgStatus};
|
||
|
|
||
|
aMsgPropVar[0].vt = VT_VECTOR | VT_UI1;
|
||
|
aMsgPropVar[0].caub.pElems = (BYTE*) pMsgBody ;
|
||
|
|
||
|
aMsgPropVar[1].vt = VT_VECTOR | VT_UI1;
|
||
|
aMsgPropVar[1].caub.cElems = dwSymmKeyLen;
|
||
|
aMsgPropVar[1].caub.pElems = abSymmKey;
|
||
|
|
||
|
aMsgPropVar[2].vt = VT_UI4;
|
||
|
aMsgPropVar[2].ulVal = dwEncryptAlg ;
|
||
|
|
||
|
aMsgPropVar[3].vt = VT_CLSID;
|
||
|
aMsgPropVar[3].puuid = &guid;
|
||
|
|
||
|
aMsgPropVar[4].vt = VT_LPWSTR;
|
||
|
aMsgPropVar[4].pwszVal = wszMsgLabel;
|
||
|
|
||
|
//
|
||
|
// The connector type (PROPID_M_CONNECTOR_TYPE) is not initialized
|
||
|
// because it is assumed that nobody will bother about it on the
|
||
|
// receiving side, otherwise it should be initialized.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Encrypt the line.
|
||
|
//
|
||
|
|
||
|
if (!CryptEncrypt( hSymmKey,
|
||
|
NULL,
|
||
|
TRUE,
|
||
|
0,
|
||
|
(BYTE*) pMsgBody,
|
||
|
&dwMsgSize,
|
||
|
dwBufferSize ))
|
||
|
{
|
||
|
printf("CryptEncrypt() failed, error- %lxh\n", GetLastError());
|
||
|
return -1;
|
||
|
}
|
||
|
printf("CryptEncrypt() succeeded\n") ;
|
||
|
|
||
|
//
|
||
|
// Update the length of the message according to the result of the
|
||
|
// encryption algorithm. RC4 may enlarge the message size. On the
|
||
|
// destination, the message will be received as clear text with the
|
||
|
// correct (original) message body size.
|
||
|
//
|
||
|
aMsgPropVar[0].caub.cElems = dwMsgSize ;
|
||
|
|
||
|
aMsgPropVar[5].vt = VT_UI4;
|
||
|
if(!fEnhEncrypted)
|
||
|
{
|
||
|
aMsgPropVar[5].ulVal= MQMSG_PRIV_LEVEL_NONE ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
aMsgPropVar[5].ulVal = MQMSG_PRIV_LEVEL_BODY_ENHANCED ;
|
||
|
}
|
||
|
MsgProps.cProp = MSGPROPS ;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Send the mesasge.
|
||
|
//
|
||
|
hr = MQSendMessage(hQueue, &MsgProps, NULL);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
printf("MQSendMessage() failed, hr- %lxh\n", hr) ;
|
||
|
return -1;
|
||
|
}
|
||
|
printf("MQSendMessage() succeeded\n") ;
|
||
|
|
||
|
//
|
||
|
// Free resources. This is actually not required here, it is just
|
||
|
// to show how it should be done, if neccessary.
|
||
|
//
|
||
|
MQCloseQueue(hQueue);
|
||
|
CryptDestroyKey(hSymmKey);
|
||
|
CryptDestroyKey(hPbKey);
|
||
|
CryptReleaseContext(hProv, 0);
|
||
|
|
||
|
return 0;
|
||
|
}
|