2011-11-02 175 views
6

我需要在我的Qt/C++应用程序中执行简单的单块AES加密/解密。这是一个“保持诚实的人诚实”的实现,所以只需要一个基本的encrypt(key, data) - 我不担心初始化向量等。我的输入和密钥总是正好是16个字节。使用WinAPI进行简单的AES加密

我想真的喜欢避免另一个依赖项来编译/链接/附带我的应用程序,所以我试图使用每个平台上可用的东西。在Mac上,这是一个到CCCrypt的单线程。在Windows上,我在WinCrypt.h的API中迷路了。他们加密一个文件的例子差不多有600行。 认真吗?

我正在寻找CryptEncrypt,但在你打电话之前,我正在倒塌你必须创建的依赖关系的兔子洞。

任何人都可以提供一个使用Windows API进行AES加密的简单示例吗?当然有一种方法可以在一两行中做到这一点。假设您已经有128位密钥和128位数据进行加密。

+0

我不能提供一个简单的WinApi示例(因为可能不存在,因为你注意到),但你有没有看过OpenSSL?我已经在几个项目中使用它,它非常简单。我知道你不想添加其他依赖项,但它可能最终是一个更简单的解决方案。 – JoeFish

回答

4

这是我所能想到的最好的。欢迎提出改进建议!

static void encrypt(const QByteArray &data, 
        const QByteArray &key, 
        QByteArray *encrypted) { 
    // Create the crypto provider context. 
    HCRYPTPROV hProvider = NULL; 
    if (!CryptAcquireContext(&hProvider, 
          NULL, // pszContainer = no named container 
          NULL, // pszProvider = default provider 
          PROV_RSA_AES, 
          CRYPT_VERIFYCONTEXT)) { 
    throw std::runtime_error("Unable to create crypto provider context."); 
    } 

    // Construct the blob necessary for the key generation. 
    AesBlob128 aes_blob; 
    aes_blob.header.bType = PLAINTEXTKEYBLOB; 
    aes_blob.header.bVersion = CUR_BLOB_VERSION; 
    aes_blob.header.reserved = 0; 
    aes_blob.header.aiKeyAlg = CALG_AES_128; 
    aes_blob.key_length = kAesBytes128; 
    memcpy(aes_blob.key_bytes, key.constData(), kAesBytes128); 

    // Create the crypto key struct that Windows needs. 
    HCRYPTKEY hKey = NULL; 
    if (!CryptImportKey(hProvider, 
         reinterpret_cast<BYTE*>(&aes_blob), 
         sizeof(AesBlob128), 
         NULL, // hPubKey = not encrypted 
         0,  // dwFlags 
         &hKey)) { 
    throw std::runtime_error("Unable to create crypto key."); 
    } 

    // The CryptEncrypt method uses the *same* buffer for both the input and 
    // output (!), so we copy the data to be encrypted into the output array. 
    // Also, for some reason, the AES-128 block cipher on Windows requires twice 
    // the block size in the output buffer. So we resize it to that length and 
    // then chop off the excess after we are done. 
    encrypted->clear(); 
    encrypted->append(data); 
    encrypted->resize(kAesBytes128 * 2); 

    // This acts as both the length of bytes to be encoded (on input) and the 
    // number of bytes used in the resulting encrypted data (on output). 
    DWORD length = kAesBytes128; 
    if (!CryptEncrypt(hKey, 
        NULL, // hHash = no hash 
        true, // Final 
        0,  // dwFlags 
        reinterpret_cast<BYTE*>(encrypted->data()), 
        &length, 
        encrypted->length())) { 
    throw std::runtime_error("Encryption failed"); 
    } 

    // See comment above. 
    encrypted->chop(length - kAesBytes128); 

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

这不适用于Windows 2000;不知道这是否重要(相当过时)。如果是,这是[解决方法](http://support.microsoft.com/kb/228786)。此外,你的例外将导致句柄泄漏:) – Luke

+2

不起作用。 AesBlob128在Windows中未定义... –