PHP加密和Windows解密

14

我卡住了。看起来PHP加密的AES在Windows上无法解密。

PHP代码:

$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128,"12345678", "test", MCRYPT_MODE_CBC));

Windows代码: "s"是由上述响应从base64转换回来后创建的字符串。

bool Decrypt(char* s,char* key,char* dest)
{
// Create the crypto provider context.
HCRYPTPROV hProvider = NULL;
if (!CryptAcquireContext(&hProvider,
    NULL,  // pszContainer = no named container
    MS_ENH_RSA_AES_PROV,  // pszProvider = default provider
    PROV_RSA_AES,
    0)) 
        return false;


// Construct the blob necessary for the key generation.
aes128keyBlob aes_blob128;

aes_blob128.header.bType = PLAINTEXTKEYBLOB;
aes_blob128.header.bVersion = CUR_BLOB_VERSION;
aes_blob128.header.reserved = 0;
aes_blob128.header.aiKeyAlg = CALG_AES_128;
aes_blob128.keySize = 16;
memcpy(aes_blob128.bytes, key, 16);

HCRYPTKEY hKey = NULL;
if (!CryptImportKey(hProvider,
    (BYTE*)(&aes_blob128),
    sizeof(aes_blob128),
    NULL,  // 
    0,     // 
    &hKey)) {

        ...
    }


// Set Mode
DWORD dwMode = CRYPT_MODE_CBC;
CryptSetKeyParam( hKey, KP_MODE, (BYTE*)&dwMode, 0 );


DWORD length = 16;
BOOL X = CryptDecrypt(hKey,
    NULL,  // hHash = no hash
    TRUE,  // Final
    0,
    (BYTE*)s,
    &length);
//int le = GetLastError();
memcpy(dest,s,16);

CryptDestroyKey(hKey);
CryptReleaseContext(hProvider, 0);
}

可能出了什么问题?


你是如何传递加密字符串的?例如cookie、数据库等。 - solidau
将其传递回Windows程序?通过打印并将其作为浏览器的输出接收。 - Michael Chourdakis
3
你在哪里处理初始化向量(IV)?如果你没有设置IV,PHP会使用所有字节都设置为 '\0' 的IV;但是看起来你没有将其提供给解密例程。你真的应该使用IV,否则最好放弃CBC并使用ECB(当然会牺牲安全性)。 - NullUserException
5
你可能还需要关注的另一件事是如何处理填充。据我所知,mcrypt使用零填充;你的C++端可能使用PKCS #7或其他填充方式。 - NullUserException
1
我们不知道出了什么问题,因为您没有告诉我们它出了什么问题。您是否遇到异常?乱码文本?您是否有可以分享的输入/输出? - Maarten Bodewes
你尝试将PHP输出转换为小端序了吗?一些“Windows代码”在字节序方面可能会失败。此外,我假设在尝试解密之前,你已经删除了base64编码,对吗? - Leigh
3个回答

9
您提供的信息不足以确切地判断,但我认为您的问题是密钥长度。
在 PHP 代码中,您将"12345678"作为密钥。而 AES128 具有128位或16字节的密钥长度。 如 mcrypt_encrypt 文档所述,PHP 使用零字节填充其余部分。
在 C++ 代码中,您仅将指向密钥缓冲区的指针传递给 Decrypt 函数。但然后您从中复制16字节到密钥 BLOB 中:
aes_blob128.keySize = 16;
memcpy(aes_blob128.bytes, key, 16);

如果您像这样调用函数:

char dest[16];
bool result = Decrypt(string_from_php,"12345678",dest);

如果只复制 "12345678" 常量后面在内存中的8个字节到密钥Blob中,并将其作为实际密钥传递给 CryptImportKey,那么C语言和PHP代码中的密钥实际上会有所不同,解密就会因填充错误而失败。


1

PHP MCRYPT函数与Windows解密函数有些不同。

因为mcrypt函数接受任意长度的密钥,并通过在密钥字符串末尾添加\0来将其转换为算法所需的长度。

请注意,在两端创建具有算法所需加密长度的密钥。

对密钥使用md5,然后将其转换为算法所需的长度。


0

请查看以下网址

使用AES / Rijndael在PHP中加密,在C#(WP7 / Silverlight)中解密

http://pumka.net/2009/12/16/rsa-encryption-cplusplus-delphi-cryptoapi-php-openssl-2/

http://www.developer.nokia.com/Community/Wiki/Encrypt-Decrypt_contacts_database_entries_using_Symbian_C%2B%2B

阅读它

我从 PHP 和 C# 中删除了 MD5 废物,现在它们正常工作。

以防您在寻找相同答案时落在这里,这里有一段示例代码。别忘了制作自己的密钥和 iv(虽然下面的那些将起作用,但不建议使用!)

PHP:

function encrypt128($message) {

    $vector = "0000000000000000";
    $key = "00000000000000000000000000000000";

    $block = mcrypt_get_block_size('rijndael_128', 'cbc');
    $pad = $block - (strlen($message) % $block);
    $message .= str_repeat(chr($pad), $pad);

    $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'cbc', '');
    mcrypt_generic_init($cipher, $key, $vector);
    $result = mcrypt_generic($cipher, $message);
    mcrypt_generic_deinit($cipher);

    return base64_encode($result);
}

C++

使用Symbian C++加密解密联系人数据库条目

http://www.developer.nokia.com/Community/Wiki/Encrypt-Decrypt_contacts_database_entries_using_Symbian_C%2B%2B

需要的头部信息:

#include <cntdb.h> // CContactDatabse, 
#include <cntitem.h> //CContactItem,CContactItemFieldSet

http://www.developer.nokia.com/Community/Wiki/Encrypt-Decrypt_contacts_database_entries_using_Symbian_C%2B%2B

加密联系人字段

void CEncryptContactContainer::EncryptAll()
{
    CContactDatabase *contactDB = CContactDatabase::OpenL();
    CleanupStack::PushL(contactDB);

    TContactIter iter(*contactDB);
    TContactItemId aContactId;

//Developer can take Heap based descriptor for large/unknown size of contact items.
    TBuf16<70> aValue; 

    const CContactIdArray* contactArray = contactDB->SortedItemsL();

    TInt cnt=contactArray->Count();

    for(TInt i=0;i<cnt;i++)
    {
        CContactItem* contactItem=NULL;

        contactItem= contactDB->OpenContactL((*contactArray)[i]);
        CleanupStack::PushL(contactItem);

        CContactItemFieldSet& fieldSet= contactItem->CardFields();
        TInt fieldCount=fieldSet.Count(); // This will give number of contact fields.

        for(TInt index=0; index < fieldCount; index++)
        {
            CContactItemField& field = fieldSet[index];
            const CContentType& type = field.ContentType();
            if(!(type.ContainsFieldType(KUidContactFieldBirthday)))
            {
                TPtrC name = contactItem->CardFields()[index].TextStorage()->Text();
                aValue.Copy(name);
                Encrypt(aValue); // Call real encyption here
                contactItem->CardFields()[index].TextStorage()->SetTextL(aValue);
            }
        } //Inner for loop ends here
        contactDB->CommitContactL(*contactItem);
        CleanupStack::PopAndDestroy(contactItem);
    } //Outer for loop ends here
    CleanupStack::PopAndDestroy(contactDB);
}

void CEncryptContactContainer:: Encrypt (TDes& aValue)
{
    for(TInt iCount=0; iCount< aValue.Length();iCount++)
    {
        aValue[iCount]+=3;
    }
}

解密联系人字段

void CEncryptContactContainer::DecryptAll()
{
    CContactDatabase *contactDB = CContactDatabase::OpenL();
    CleanupStack::PushL(contactDB);

    TContactIter iter(*contactDB);
    TContactItemId aContactId;
    TBuf16<70> aValue;

    const CContactIdArray* contactArray = contactDB->SortedItemsL();

    TInt cnt=contactArray->Count();

    for(TInt i=0;i<cnt;i++)
    {
        CContactItem* contactItem=NULL;

        contactItem= contactDB->OpenContactL((*contactArray)[i]);
        CleanupStack::PushL(contactItem);

        CContactItemFieldSet& fieldSet= contactItem->CardFields();
        TInt fieldCount=fieldSet.Count(); // This will give number of contact fields.

        for(TInt index=0; index < fieldCount; index++)
        {
            CContactItemField& field = fieldSet[index];
            const CContentType& type = field.ContentType();
            if(!(type.ContainsFieldType(KUidContactFieldBirthday)))
            {
                TPtrC name = contactItem->CardFields()[index].TextStorage()->Text();
                aValue.Copy(name);
                Decrypt(aValue);
                contactItem->CardFields()[index].TextStorage()->SetTextL(aValue);
            }
        } //Inner for loop ends here
        contactDB->CommitContactL(*contactItem);
        CleanupStack::PopAndDestroy(contactItem);
    } //Outer for loop ends here
    CleanupStack::PopAndDestroy(contactDB);
}

void CEncryptContactContainer:: Decrypt (TDes& aValue)
{
    for(TInt iCount=0; iCount< aValue.Length();iCount++)
    {
        aValue[iCount]-=3;
    }
}

C#:

byte[] cripted = EncryptStringToBytes("Test", System.Text.Encoding.UTF8.GetBytes("00000000000000000000000000000000"), System.Text.Encoding.UTF8.GetBytes("0000000000000000"));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接