2012-09-28 121 views
13

我卡住了。似乎由PHP完成的AES加密无法在Windows中解密。PHP加密和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); 
} 

什么可能是错的?

+0

你怎么传递加密的字符串?即饼干,数据库等.. – solidau

+0

传递给Windows程序?通过打印并将其作为浏览器的输出。 – Michael

+3

你在哪里处理初始化向量(IV)?如果你没有设置IV,PHP会使用其所有字节设置为''\ 0''的字符;但它看起来并不像你提供给你的解密程序。尽管如此,你真的应该使用IV,否则可能会沟通CBC并使用ECB(当然是以牺牲安全为代价)。 – NullUserException

回答

9

您提供的信息是不够的,肯定地说,但我觉得你的问题是密钥长度。

在PHP代码中,您将“12345678”作为关键字。 AES128的密钥长度为128位或16字节。 PHP填充零字节的剩余部分,如mcrypt_encrypt上的文档所述。

在C++代码中,只将指向密钥缓冲区的指针传递给Decrypt函数。但你16个字节复制从它的密钥团:

aes_blob128.keySize = 16; 
memcpy(aes_blob128.bytes, key, 16); 

然后,如果你打电话给你的功能,如:

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

比碰巧驻留在内存中的“12345678之后的8个字节“常量将被复制到密钥块并传递给CryptImportKey作为实际密钥。因此,C和PHP代码中的密钥实际上是不同的,由于填充错误,解密将失败。

0

请参见下面的网址

Encrypt in PHP, Decrypt in C# (WP7/Silverlight) using AES/Rijndael

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

读它

我DROP掉了MD5屁滚尿流的PHP和C#,和他们一现在工作正常。

为防万一你在这里寻找相同的答案,这里是一个示例代码。不要忘了让自己的密钥和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++

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

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

header要求:

#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")); 
1

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

由于mcrypt函数采用任意长度的密钥并通过在密钥字符串的末尾添加\0将其转换为算法所需的长度。

请注意创建一个具有指定长度的密钥,以便在算法的两侧进行加密。

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