Diffie-Hellman(到RC4)与Wincrypt从Python [英] Diffie-Hellman (to RC4) with Wincrypt From Python

查看:337
本文介绍了Diffie-Hellman(到RC4)与Wincrypt从Python的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用C ++编写的项目,利用CryptoAPI执行Diffie-Hellman密钥交换。我有一个麻烦让这个工作作为最终的RC4会话密钥我得到不能用于加密相同的文本在Python(使用pycrypto)。



用于执行Diffie-Hellman密钥交换的C ++代码取自 msdn ,但这里包括了后代:

  #include< tchar.h> 
#include< windows.h>
#include< wincrypt.h>
#pragma comment(lib,crypt32.lib)

//密钥大小(以位为单位)。
#define DHKEYSIZE 512

//以little-endian格式初始化。
static const BYTE g_rgbPrime [] =
{
0x91,0x02,0xc8,0x31,0xee,0x36,0x07,0xec,
0xc2,0x24,0x37,0xf8,0xfb, 0x3d,0x69,0x49,
0xac,0x7a,0xab,0x32,0xac,0xad,0xe9,0xc2,
0xaf,0x0e,0x21,0xb7,0xc5,0x2f,0x76,0xd0,
0xe5,0x82,0x78,0x0d,0x4f,0x32,0xb8,0xcb,
0xf7,0x0c,0x8d,0xfb,0x3a,0xd8,0xc0,0xea,
0xcb,0x69,0x68,0xb0,0x9b, 0x75,0x25,0x3d,
0xaa,0x76,0x22,0x49,0x94,0xa4,0xf2,0x8d
};

//小端格式的发生器。
static BYTE g_rgbGenerator [] =
{
0x02,0x88,0xd7,0xe6,0x53,0xaf,0x72,0xc5,
0x8c,0x08,0x4b,0x46,0x6f,0x9f ,0x2e,0xc4,
0x9c,0x5c,0x92,0x21,0x95,0xb7,0xe5,0x58,
0xbf,0xba,0x24,0xfa,0xe5,0x9d,0xcb,0x71,
0x2e ,0x2c,0xce,0x99,0xf3,0x10,0xff,0x3b,
0xcb,0xef,0x6c,0x95,0x22,0x55,0x9d,0x29,
0x00,0xb5,0x4c,0x5b,0xa5,0x63 ,0x31,0x41,
0x13,0x0a,0xea,0x39,0x78,0x02,0x6d,0x62
};

BYTE g_rgbData [] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};

int _tmain(int argc,_TCHAR * argv [])
{
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARameTER(argv);

BOOL fReturn;
HCRYPTPROV hProvParty1 = NULL;
HCRYPTPROV hProvParty2 = NULL;
DATA_BLOB P;
DATA_BLOB G;
HCRYPTKEY hPrivateKey1 = NULL;
HCRYPTKEY hPrivateKey2 = NULL;
PBYTE pbKeyBlob1 = NULL;
PBYTE pbKeyBlob2 = NULL;
HCRYPTKEY hSessionKey1 = NULL;
HCRYPTKEY hSessionKey2 = NULL;
PBYTE pbData = NULL;

/ ************************
构造主数据和生成器的数据BLOB。由g_rgbPrime和g_rgbGenerator数组
分别表示的P和G
值是已由两个
方同意的共享值。
************************ /
P.cbData = DHKEYSIZE / 8;
P.pbData =(BYTE *)(g_rgbPrime);

G.cbData = DHKEYSIZE / 8;
G.pbData =(BYTE *)(g_rgbGenerator);

/ ************************
为方1创建私人Diffie-Hellman密钥。
************************ /
//获取方1的提供程序句柄。
fReturn = CryptAcquireContext(
& hProvParty1,
NULL,
MS_ENH_DSS_DH_PROV,
PROV_DSS_DH,
CRYPT_VERIFYCONTEXT);
if(!fReturn)
{
goto ErrorExit;
}

//为方1创建一个临时私钥。
fReturn = CryptGenKey(
hProvParty1,
CALG_DH_EPHEM,
DHKEYSIZE< ;< 16 | CRYPT_EXPORTABLE | CRYPT_PREGEN,
& hPrivateKey1);
if(!fReturn)
{
goto ErrorExit;
}

//为Party 1的私钥设置质数。
fReturn = CryptSetKeyParam(
hPrivateKey1,
KP_P,
(PBYTE)& P,
0);
if(!fReturn)
{
goto ErrorExit;
}

//为Party 1的私钥设置生成器。
fReturn = CryptSetKeyParam(
hPrivateKey1,
KP_G,
(PBYTE)& G,
0);
if(!fReturn)
{
goto ErrorExit;
}

//生成第1方私钥的秘密值。
fReturn = CryptSetKeyParam(
hPrivateKey1,
KP_X,
NULL,
0);
if(!fReturn)
{
goto ErrorExit;
}

/ ************************
创建私有Diffie-Hellman密钥
************************ /
//获取第2方的提供程序句柄。
fReturn = CryptAcquireContext(
& hProvParty2,
NULL,
MS_ENH_DSS_DH_PROV,
PROV_DSS_DH,
CRYPT_VERIFYCONTEXT);
if(!fReturn)
{
goto ErrorExit;
}

//为方2创建一个临时私钥。
fReturn = CryptGenKey(
hProvParty2,
CALG_DH_EPHEM,
DHKEYSIZE< ;< 16 | CRYPT_EXPORTABLE | CRYPT_PREGEN,
& hPrivateKey2);
if(!fReturn)
{
goto ErrorExit;
}

//为派对2的私钥设置质数。
fReturn = CryptSetKeyParam(
hPrivateKey2,
KP_P,
(PBYTE)& P,
0);
if(!fReturn)
{
goto ErrorExit;
}

//为方2的私钥设置生成器。
fReturn = CryptSetKeyParam(
hPrivateKey2,
KP_G,
(PBYTE)& G,
0)
if(!fReturn)
{
goto ErrorExit;
}

//为第2方的私钥生成秘密值。
fReturn = CryptSetKeyParam(
hPrivateKey2,
KP_X,
NULL,
0)
如果(!fReturn)
{
goto ErrorExit;
}

/ ************************
导出Party 1的公钥。
************************ /
//计算公钥值,(G ^ X)mod P.
DWORD dwDataLen1;

//获取键BLOB的大小。
fReturn = CryptExportKey(
hPrivateKey1,
NULL,
PUBLICKEYBLOB,
0,
NULL,
& dwDataLen1);
if(!fReturn)
{
goto ErrorExit;
}

//为键BLOB分配内存。
if(!(pbKeyBlob1 =(PBYTE)malloc(dwDataLen1)))
{
goto ErrorExit;
}

//获取密钥BLOB。
fReturn = CryptExportKey(
hPrivateKey1,
0,
PUBLICKEYBLOB,
0,
pbKeyBlob1,
& dwDataLen1);
if(!fReturn)
{
goto ErrorExit;
}

/ ************************
导出Party 2的公钥。
************************ /
//计算公钥值,(G ^ X)mod P.
DWORD dwDataLen2;

//获取键BLOB的大小。
fReturn = CryptExportKey(
hPrivateKey2,
NULL,
PUBLICKEYBLOB,
0,
NULL,
& dwDataLen2);
if(!fReturn)
{
goto ErrorExit;
}

//为键BLOB分配内存。
if(!(pbKeyBlob2 =(PBYTE)malloc(dwDataLen2)))
{
goto ErrorExit;
}

//获取密钥BLOB。
fReturn = CryptExportKey(
hPrivateKey2,
0,
PUBLICKEYBLOB,
0,
pbKeyBlob2,
& dwDataLen2);
if(!fReturn)
{
goto ErrorExit;
}

/ ************************
Party 1导入第2方的公钥。
导入的密钥将包含新的共享密钥
键(Y ^ X)mod P.
******************** **** /
fReturn = CryptImportKey(
hProvParty1,
pbKeyBlob2,
dwDataLen2,
hPrivateKey1,
0,
& hSessionKey2 );
if(!fReturn)
{
goto ErrorExit;
}

/ ************************
Party 2导入第1方的公钥。
导入的密钥将包含新的共享密钥
键(Y ^ X)mod P.
******************** **** /
fReturn = CryptImportKey(
hProvParty2,
pbKeyBlob1,
dwDataLen1,
hPrivateKey2,
0,
& hSessionKey1 );
if(!fReturn)
{
goto ErrorExit;
}

/ ************************
将已同意的密钥转换为对称密钥。它们目前是
,形式为CALG_AGREEDKEY_ANY。将它们转换为CALG_RC4。
************************ /
ALG_ID Algid = CALG_RC4;

//通过设置
// ALGID来启用Party 1公共会话密钥。
fReturn = CryptSetKeyParam(
hSessionKey1,
KP_ALGID,
(PBYTE)& Algid,
0);
if(!fReturn)
{
goto ErrorExit;
}

//通过设置
// ALGID来启用第2方公共会话密钥。
fReturn = CryptSetKeyParam(
hSessionKey2,
KP_ALGID,
(PBYTE)& Algid,
0);
if(!fReturn)
{
goto ErrorExit;
}

/ ************************
使用第1方的会话密钥加密一些数据。
************************ /
//获取大小。
DWORD dwLength = sizeof(g_rgbData);
fReturn = CryptEncrypt(
hSessionKey1,
0,
TRUE,
0,
NULL,
& dwLength,
sizeof(g_rgbData));
if(!fReturn)
{
goto ErrorExit;
}

//分配缓冲区以保存加密数据。
pbData =(PBYTE)malloc(dwLength);
if(!pbData)
{
goto ErrorExit;
}

//将未加密的数据复制到缓冲区。数据将
//加密到位。
memcpy(pbData,g_rgbData,sizeof(g_rgbData));

//加密数据。
dwLength = sizeof(g_rgbData);
fReturn = CryptEncrypt(
hSessionKey1,
0,
TRUE,
0,
pbData,
& dwLength,
sizeof(g_rgbData));
if(!fReturn)
{
goto ErrorExit;
}

/ ************************
使用第2方的会话密钥解密数据。
************************ /
dwLength = sizeof(g_rgbData);
fReturn = CryptDecrypt(
hSessionKey2,
0,
TRUE,
0,
pbData,
& dwLength);
if(!fReturn)
{
goto ErrorExit;
}


ErrorExit:
if(pbData)
{
free(pbData);
pbData = NULL;
}

if(hSessionKey2)
{
CryptDestroyKey(hSessionKey2);
hSessionKey2 = NULL;
}

if(hSessionKey1)
{
CryptDestroyKey(hSessionKey1);
hSessionKey1 = NULL;
}

if(pbKeyBlob2)
{
free(pbKeyBlob2);
pbKeyBlob2 = NULL;
}

if(pbKeyBlob1)
{
free(pbKeyBlob1);
pbKeyBlob1 = NULL;
}

if(hPrivateKey2)
{
CryptDestroyKey(hPrivateKey2);
hPrivateKey2 = NULL;
}

if(hPrivateKey1)
{
CryptDestroyKey(hPrivateKey1);
hPrivateKey1 = NULL;
}

if(hProvParty2)
{
CryptReleaseContext(hProvParty2,0);
hProvParty2 = NULL;
}

if(hProvParty1)
{
CryptReleaseContext(hProvParty1,0);
hProvParty1 = NULL;
}

return 0;
}



我相信我可以在Python中完成Diffie-Hellman密钥交换我可以生成相同的公共和私有密钥没有错误。我已在此存储库上建立了Diffie-Hellman密钥交换。



我无法测试这个,但是我似乎无法获得从C ++代码导出的共享密码(类似于这个线程,从来没有令人满意地回答)。我可以得到RC4会话密钥与以下代码:

  //获取密钥长度
DWORD keylen;
CryptExportKey(
hSessionKey1,
NULL,
PLAINTEXTKEYBLOB,
0,
NULL,
& keylen);

//获取会话密钥
CryptExportKey(
hSessionKey1,
NULL,
PLAINTEXTKEYBLOB,
0,
encKey,
& keylen);

此函数的输出得到:

  08 02 00 00 01 68 00 00 10 00 00 00 75 2c 59 8c 6e e0 8c 9fed 30 17 7e 9d a5 85 2b 



我知道这里有一个12字节的标头+长度,所以我留下以下16字节RC4会话密钥:

  75 2c 59 8c 6e e0 8c 9fed 30 17 7e 9d a5 85 2b 
CryptExportKey 。我目前正试图加密上面的C ++代码中的 g_rgbData ,它设置为:

  BYTE g_rgbData [] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}; 

使用C ++代码,我得到以下加密输出:

  cc 94 aa ec 86 6e a8 26 

使用pycrypto我有以下代码:

 来自Crypto.Cipher import ARC4 
key = '75 2c 59 8c 6e e0 8c 9fed 30 17 7e 9d a5 85 2b'
key = key.replace('','').decode('hex')

plaintext ='0102030405060708'
plaintext = plaintext.replace('','').decode('hex')

rc4 = ARC4.new(key)
encrypted = rc4.encrypt

print encrypted.encode('hex')

以下输出:

  00 5b 64 25 4e a5 62 e3 

这与C ++输出不匹配。我用endianess玩过,但我怀疑还有别的事情可能发生。



对不起,如果这是长时间,但它带给我两个问题:


  1. 每当从共享密钥转换到RC4时(使用 CryptSetKeyParam CALG_RC4 ),实际上在引擎盖下这里?


  2. 任何想法为什么我的RC4将不能使用的工作在任何地方,我可以在Python中实现它。相同的键和同样的明文在Python?


任何帮助将非常感谢! b

解决方案

最后有一些时间来看看你的代码。当我在本地运行代码时,我能够导出会话密钥,并且可以在pycrypto中成功使用它。我的猜测是,你不是正确地导出会话密钥(例如,你发布了你正在运行什么?)或您正在C ++中加密的数据不是相同的数据,你在Python中加密 - 双检查数据你加密也是正确的。我怀疑它可能是后者,因为你真的没有太多的你可以搞砸与你发布的 CryptExportKey


I am currently working on a project written in C++ that leverages the CryptoAPI to perform a Diffie-Hellman key exchange. I'm having a bit of trouble getting this to work as the eventual RC4 session key I get cannot be used to encrypt the same text in Python (using pycrypto).

The C++ code to perform the Diffie-Hellman key exchange was taken from msdn, but is included here for posterity:

#include <tchar.h>
#include <windows.h>
#include <wincrypt.h>
#pragma comment(lib, "crypt32.lib")

// The key size, in bits.
#define DHKEYSIZE 512

// Prime in little-endian format.
static const BYTE g_rgbPrime[] = 
{
    0x91, 0x02, 0xc8, 0x31, 0xee, 0x36, 0x07, 0xec, 
    0xc2, 0x24, 0x37, 0xf8, 0xfb, 0x3d, 0x69, 0x49, 
    0xac, 0x7a, 0xab, 0x32, 0xac, 0xad, 0xe9, 0xc2, 
    0xaf, 0x0e, 0x21, 0xb7, 0xc5, 0x2f, 0x76, 0xd0, 
    0xe5, 0x82, 0x78, 0x0d, 0x4f, 0x32, 0xb8, 0xcb,
    0xf7, 0x0c, 0x8d, 0xfb, 0x3a, 0xd8, 0xc0, 0xea, 
    0xcb, 0x69, 0x68, 0xb0, 0x9b, 0x75, 0x25, 0x3d,
    0xaa, 0x76, 0x22, 0x49, 0x94, 0xa4, 0xf2, 0x8d 
};

// Generator in little-endian format.
static BYTE g_rgbGenerator[] = 
{
    0x02, 0x88, 0xd7, 0xe6, 0x53, 0xaf, 0x72, 0xc5,
    0x8c, 0x08, 0x4b, 0x46, 0x6f, 0x9f, 0x2e, 0xc4,
    0x9c, 0x5c, 0x92, 0x21, 0x95, 0xb7, 0xe5, 0x58, 
    0xbf, 0xba, 0x24, 0xfa, 0xe5, 0x9d, 0xcb, 0x71, 
    0x2e, 0x2c, 0xce, 0x99, 0xf3, 0x10, 0xff, 0x3b,
    0xcb, 0xef, 0x6c, 0x95, 0x22, 0x55, 0x9d, 0x29,
    0x00, 0xb5, 0x4c, 0x5b, 0xa5, 0x63, 0x31, 0x41,
    0x13, 0x0a, 0xea, 0x39, 0x78, 0x02, 0x6d, 0x62
};

BYTE g_rgbData[] = {0x01, 0x02, 0x03, 0x04,    0x05, 0x06, 0x07, 0x08};

int _tmain(int argc, _TCHAR* argv[])
{
    UNREFERENCED_PARAMETER(argc);
    UNREFERENCED_PARAMETER(argv);

    BOOL fReturn;
    HCRYPTPROV hProvParty1 = NULL; 
    HCRYPTPROV hProvParty2 = NULL; 
    DATA_BLOB P;
    DATA_BLOB G;
    HCRYPTKEY hPrivateKey1 = NULL;
    HCRYPTKEY hPrivateKey2 = NULL;
    PBYTE pbKeyBlob1 = NULL;
    PBYTE pbKeyBlob2 = NULL;
    HCRYPTKEY hSessionKey1 = NULL;
    HCRYPTKEY hSessionKey2 = NULL;
    PBYTE pbData = NULL;

    /************************
    Construct data BLOBs for the prime and generator. The P and G 
    values, represented by the g_rgbPrime and g_rgbGenerator arrays 
    respectively, are shared values that have been agreed to by both 
    parties.
    ************************/
    P.cbData = DHKEYSIZE/8;
    P.pbData = (BYTE*)(g_rgbPrime);

    G.cbData = DHKEYSIZE/8;
    G.pbData = (BYTE*)(g_rgbGenerator);

    /************************
    Create the private Diffie-Hellman key for party 1. 
    ************************/
    // Acquire a provider handle for party 1.
    fReturn = CryptAcquireContext(
        &hProvParty1, 
        NULL,
        MS_ENH_DSS_DH_PROV,
        PROV_DSS_DH, 
        CRYPT_VERIFYCONTEXT);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    // Create an ephemeral private key for party 1.
    fReturn = CryptGenKey(
        hProvParty1, 
        CALG_DH_EPHEM, 
        DHKEYSIZE << 16 | CRYPT_EXPORTABLE | CRYPT_PREGEN,
        &hPrivateKey1);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    // Set the prime for party 1's private key.
    fReturn = CryptSetKeyParam(
        hPrivateKey1,
        KP_P,
        (PBYTE)&P,
        0);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    // Set the generator for party 1's private key.
    fReturn = CryptSetKeyParam(
        hPrivateKey1,
        KP_G,
        (PBYTE)&G,
        0);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    // Generate the secret values for party 1's private key.
    fReturn = CryptSetKeyParam(
        hPrivateKey1,
        KP_X,
        NULL,
        0);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    /************************
    Create the private Diffie-Hellman key for party 2. 
    ************************/
    // Acquire a provider handle for party 2.
    fReturn = CryptAcquireContext(
        &hProvParty2, 
        NULL,
        MS_ENH_DSS_DH_PROV,
        PROV_DSS_DH, 
        CRYPT_VERIFYCONTEXT);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    // Create an ephemeral private key for party 2.
    fReturn = CryptGenKey(
        hProvParty2, 
        CALG_DH_EPHEM, 
        DHKEYSIZE << 16 | CRYPT_EXPORTABLE | CRYPT_PREGEN,
        &hPrivateKey2);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    // Set the prime for party 2's private key.
    fReturn = CryptSetKeyParam(
        hPrivateKey2,
        KP_P,
        (PBYTE)&P,
        0);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    // Set the generator for party 2's private key.
    fReturn = CryptSetKeyParam(
        hPrivateKey2,
        KP_G,
        (PBYTE)&G,
        0);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    // Generate the secret values for party 2's private key.
    fReturn = CryptSetKeyParam(
        hPrivateKey2,
        KP_X,
        NULL,
        0);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    /************************
    Export Party 1's public key.
    ************************/
    // Public key value, (G^X) mod P is calculated.
    DWORD dwDataLen1;

    // Get the size for the key BLOB.
    fReturn = CryptExportKey(
        hPrivateKey1,
        NULL,
        PUBLICKEYBLOB,
        0,
        NULL,
        &dwDataLen1);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    // Allocate the memory for the key BLOB.
    if(!(pbKeyBlob1 = (PBYTE)malloc(dwDataLen1)))
    { 
        goto ErrorExit;
    }

    // Get the key BLOB.
    fReturn = CryptExportKey(
        hPrivateKey1,
        0,
        PUBLICKEYBLOB,
        0,
        pbKeyBlob1,
        &dwDataLen1);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    /************************
    Export Party 2's public key.
    ************************/
    // Public key value, (G^X) mod P is calculated.
    DWORD dwDataLen2;

    // Get the size for the key BLOB.
    fReturn = CryptExportKey(
        hPrivateKey2,
        NULL,
        PUBLICKEYBLOB,
        0,
        NULL,
        &dwDataLen2);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    // Allocate the memory for the key BLOB.
    if(!(pbKeyBlob2 = (PBYTE)malloc(dwDataLen2)))
    { 
        goto ErrorExit;
    }

    // Get the key BLOB.
    fReturn = CryptExportKey(
        hPrivateKey2,
        0,
        PUBLICKEYBLOB,
        0,
        pbKeyBlob2,
        &dwDataLen2);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    /************************
    Party 1 imports party 2's public key.
    The imported key will contain the new shared secret 
    key (Y^X) mod P. 
    ************************/
    fReturn = CryptImportKey(
        hProvParty1,
        pbKeyBlob2,
        dwDataLen2,
        hPrivateKey1,
        0,
        &hSessionKey2);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    /************************
    Party 2 imports party 1's public key.
    The imported key will contain the new shared secret 
    key (Y^X) mod P. 
    ************************/
    fReturn = CryptImportKey(
        hProvParty2,
        pbKeyBlob1,
        dwDataLen1,
        hPrivateKey2,
        0,
        &hSessionKey1);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    /************************
    Convert the agreed keys to symmetric keys. They are currently of 
    the form CALG_AGREEDKEY_ANY. Convert them to CALG_RC4.
    ************************/
    ALG_ID Algid = CALG_RC4;

    // Enable the party 1 public session key for use by setting the 
    // ALGID.
    fReturn = CryptSetKeyParam(
        hSessionKey1,
        KP_ALGID,
        (PBYTE)&Algid,
        0);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    // Enable the party 2 public session key for use by setting the 
    // ALGID.
    fReturn = CryptSetKeyParam(
        hSessionKey2,
        KP_ALGID,
        (PBYTE)&Algid,
        0);
    if(!fReturn)
    {
        goto ErrorExit;
    }

    /************************
    Encrypt some data with party 1's session key. 
    ************************/
    // Get the size.
    DWORD dwLength = sizeof(g_rgbData);
    fReturn = CryptEncrypt(
        hSessionKey1, 
        0, 
        TRUE,
        0, 
        NULL, 
        &dwLength,
        sizeof(g_rgbData));
    if(!fReturn)
    {
        goto ErrorExit;
    }

    // Allocate a buffer to hold the encrypted data.
    pbData = (PBYTE)malloc(dwLength);
    if(!pbData)
    {
        goto ErrorExit;
    }

    // Copy the unencrypted data to the buffer. The data will be 
    // encrypted in place.
    memcpy(pbData, g_rgbData, sizeof(g_rgbData)); 

    // Encrypt the data.
    dwLength = sizeof(g_rgbData);
    fReturn = CryptEncrypt(
        hSessionKey1, 
        0, 
        TRUE,
        0, 
        pbData, 
        &dwLength,
        sizeof(g_rgbData));
    if(!fReturn)
    {
        goto ErrorExit;
    }

    /************************
    Decrypt the data with party 2's session key. 
    ************************/
    dwLength = sizeof(g_rgbData);
    fReturn = CryptDecrypt(
        hSessionKey2,
        0,
        TRUE,
        0,
        pbData,
        &dwLength);
    if(!fReturn)
    {
        goto ErrorExit;
    }


ErrorExit:
    if(pbData)
    {
        free(pbData);
        pbData = NULL;
    }

    if(hSessionKey2)
    {
        CryptDestroyKey(hSessionKey2);
        hSessionKey2 = NULL;
    }

    if(hSessionKey1)
    {
        CryptDestroyKey(hSessionKey1);
        hSessionKey1 = NULL;
    }

    if(pbKeyBlob2)
    {
        free(pbKeyBlob2);
        pbKeyBlob2 = NULL;
    }

    if(pbKeyBlob1)
    {
        free(pbKeyBlob1);
        pbKeyBlob1 = NULL;
    }

    if(hPrivateKey2)
    {
        CryptDestroyKey(hPrivateKey2);
        hPrivateKey2 = NULL;
    }

    if(hPrivateKey1)
    {
        CryptDestroyKey(hPrivateKey1);
        hPrivateKey1 = NULL;
    }

    if(hProvParty2)
    {
        CryptReleaseContext(hProvParty2, 0);
        hProvParty2 = NULL;
    }

    if(hProvParty1)
    {
        CryptReleaseContext(hProvParty1, 0);
        hProvParty1 = NULL;
    }

    return 0;
}

I believe that I can complete the Diffie-Hellman key exchange in Python, as I can generate the same public and private keys without error. I've based my Diffie-Hellman key exchange on this repository.

I haven't been able to test this, however as I can't seem to get the shared secret exported from the C++ code (similar to this thread, that was never satisfactorily answered). I can however get the RC4 session key with the following code:

// Get the key length
DWORD keylen;
CryptExportKey(   
    hSessionKey1,
    NULL,    
    PLAINTEXTKEYBLOB,
    0,
    NULL,
    &keylen);

// Get the session key
CryptExportKey(   
    hSessionKey1,
    NULL,     
    PLAINTEXTKEYBLOB,   
    0,  
    encKey,    
    &keylen);

The output from this function gets me:

08 02 00 00 01 68 00 00 10 00 00 00 75 2c 59 8c 6e e0 8c 9f ed 30 17 7e 9d a5 85 2b

I know there is a 12 byte header+length on this, so that leaves me with the following 16 byte RC4 session key:

75 2c 59 8c 6e e0 8c 9f ed 30 17 7e 9d a5 85 2b

So I am currently trying to validate that I can encrypt the same plaintext using the RC4 that I have acquired from the CryptExportKey. I am currently trying to encrypt g_rgbData from the C++ code above, which is set to:

BYTE g_rgbData[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};

With the C++ code I get the following encrypted output:

cc 94 aa ec 86 6e a8 26

Using pycrypto I have the following code:

from Crypto.Cipher import ARC4
key = '75 2c 59 8c 6e e0 8c 9f ed 30 17 7e 9d a5 85 2b'
key = key.replace(' ', '').decode('hex')

plaintext = '0102030405060708'
plaintext = plaintext.replace(' ', '').decode('hex')

rc4 = ARC4.new(key)
encrypted = rc4.encrypt(plaintext)

print encrypted.encode('hex')

This results in the following output:

00 5b 64 25 4e a5 62 e3

Which doesn't match the C++ output. I've played around with endianess, but I suspect something else might be going on.

Sorry if this is long winded, but it brings me to my two questions:

  1. Whenever you transition from the shared key to RC4 (using CryptSetKeyParam with CALG_RC4), what is actually going on under the hood here? I can't seem to find any information about this process anywhere so that I can implement it in Python.

  2. Any idea why my RC4 will not work with the same key and the same plaintext in Python?

Any help would be greatly appreciated!

解决方案

Finally had some time to look over your code. When I run your code locally, I am able to export the session key and can use it successfully in pycrypto. My guess is that you are either not exporting the session key correctly (e.g. is what you posted what you are running?) or the data you are encrypting in C++ is not the same data that you are encrypting in Python - double check that the data you are encrypting is also correct. I suspect that it's probably the latter, as there isn't really much you can screw up with the CryptExportKey you've posted.

这篇关于Diffie-Hellman(到RC4)与Wincrypt从Python的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆