【问题标题】:How to encrypt and decrypt a const char* in WinRT如何在 WinRT 中加密和解密 const char*
【发布时间】:2018-04-09 20:52:34
【问题描述】:

我一直在尝试编写加密和解密函数,其签名要求输入和输出字符串仅为void* 类型。如果输入可以指定为IBuffer^,则代码可以正常工作,但在另一种情况下,源字符串和加密->解密字符串不匹配。

CodeIBuffer^ byteArrayToIBufferPtr(byte *source, int size)
{
    Platform::ArrayReference<uint8> blobArray(source, size);
    IBuffer ^buffer = CryptographicBuffer::CreateFromByteArray(blobArray);
    return buffer;
}

byte* IBufferPtrToByteArray(IBuffer ^buffer)
{
    Array<unsigned char,1U> ^platArray = ref new Array<unsigned char,1U>(256);
    CryptographicBuffer::CopyToByteArray(buffer,&platArray);

    byte *dest = platArray->Data;
    return dest;
}

int DataEncryption::encryptData(EncryptionAlgorithm algo, int keySize, void* srcData, const unsigned int srcSize,
        void*& encData, unsigned int& encSize)
{

    LOG_D(TAG, "encryptData()");

    if(srcData == nullptr)
    {
        LOG_E(TAG,"");
        return DataEncryption::RESULT_EMPTY_DATA_ERROR;
    }
    if(srcSize == 0)
    {
        LOG_E(TAG,"");
        return DataEncryption::RESULT_SIZE_ZERO_ERROR;
    }

    IBuffer^ encrypted;
    IBuffer^ buffer;
    IBuffer^ iv = nullptr;
    String^ algName;
    bool cbc = false;

    switch (algo)
    {
    case DataEncryption::ENC_DEFAULT:
        algName = "AES_CBC";
        cbc = true;
        break;
    default:
        break;
    }

    // Open the algorithm provider for the algorithm specified on input.
    SymmetricKeyAlgorithmProvider^ Algorithm = SymmetricKeyAlgorithmProvider::OpenAlgorithm(algName);

    // Generate a symmetric key.
    IBuffer^ keymaterial = CryptographicBuffer::GenerateRandom((keySize + 7) / 8);
    CryptographicKey^ key;

    try
    {
        key = Algorithm->CreateSymmetricKey(keymaterial);
    }
    catch(InvalidArgumentException^ e)
    {
        LOG_E(TAG,"encryptData(): Could not create key.");
        return DataEncryption::RESULT_ERROR;
    }

    // CBC mode needs Initialization vector, here just random data.
    // IV property will be set on "Encrypted".
    if (cbc)
        iv = CryptographicBuffer::GenerateRandom(Algorithm->BlockLength);

    // Set the data to encrypt. 
    IBuffer ^srcDataBuffer = byteArrayToIBufferPtr(static_cast<byte*>(srcData),256);

    // Encrypt and create an authenticated tag.
    encrypted = CryptographicEngine::Encrypt(key, srcDataBuffer, iv);

    //encData = encrypted;
    byte *bb = IBufferPtrToByteArray(encrypted);
    encData = IBufferPtrToByteArray(encrypted);
    encSize = encrypted->Length;

    return DataEncryption::RESULT_SUCCESS;
}


int DataEncryption::decryptData(EncryptionAlgorithm algo, int keySize, void* encData, const unsigned int encSize,
        void*& decData, unsigned int& decSize)
{
    LOG_D(TAG, "decryptData()");

    if(encData == nullptr)
    {
        LOG_E(TAG,"");
        return DataEncryption::RESULT_EMPTY_DATA_ERROR;
    }
    if(encSize == 0)
    {
        LOG_E(TAG,"");
        return DataEncryption::RESULT_SIZE_ZERO_ERROR;
    }

    IBuffer^ encrypted;
    IBuffer^ decrypted;
    IBuffer^ iv = nullptr;
    String^ algName;
    bool cbc = false;

    switch (algo)
    {
    case DataEncryption::ENC_DEFAULT:
        algName = "AES_CBC";
        cbc = true;
        break;
    default:
        break;
    }

    // Open the algorithm provider for the algorithm specified on input.
    SymmetricKeyAlgorithmProvider^ Algorithm = SymmetricKeyAlgorithmProvider::OpenAlgorithm(algName);

    // Generate a symmetric key.
    IBuffer^ keymaterial = CryptographicBuffer::GenerateRandom((keySize + 7) / 8);
    CryptographicKey^ key;

    try
    {
        key = Algorithm->CreateSymmetricKey(keymaterial);
    }
    catch(InvalidArgumentException^ e)
    {
        LOG_E(TAG,"encryptData(): Could not create key.");
        return DataEncryption::RESULT_ERROR;
    }

    // CBC mode needs Initialization vector, here just random data.
    // IV property will be set on "Encrypted".
    if (cbc)
        iv = CryptographicBuffer::GenerateRandom(Algorithm->BlockLength);

    // Set the data to decrypt. 
    byte *cc = static_cast<byte*>(encData);
    IBuffer ^encDataBuffer = byteArrayToIBufferPtr(cc,256);
    // Decrypt and verify the authenticated tag.
    decrypted = CryptographicEngine::Decrypt(key, encDataBuffer, iv);

    byte *bb = IBufferPtrToByteArray(decrypted);
    decData = IBufferPtrToByteArray(decrypted);

    decSize = decrypted->Length;

    return DataEncryption::RESULT_SUCCESS;
}

【问题讨论】:

  • 加密。相当复杂的领域。你使用什么加密方法?您是否正在创建自己的加密算法?您目前遇到的问题是否与加密有关?是否只是一个 C++ 语法/语义误用问题,不用提“加密”这个词就可以解决?
  • 嗨,马克!我正在编写一个包装器来加密和解密密码库中已有的算法。以前我使用的是 openssl 第三方库;现在我需要使用 WinRT 本机 API。逻辑是: encryptData() 函数: -------------- 1. 将'const char*' 格式的源字符串转换为'IBuffer ^' 格式 2. 使用 WinRT API 加密缓冲区 3. 将编码的缓冲区转换回 'char*' 并将其安装在目标字符串中(参数)
  • decryptData() 函数: -------------------------- 1. 'const char*' 中的隐藏源字符串格式为 'IBuffer^' 格式 2. 使用 WinRT API 解密缓冲区 3. 将解码的缓冲区转换回 'char*' 并将其安装在目标字符串中(参数) 我面临的问题是,如果我将参数作为IBuffer,代码运行良好;但是当源参数和目标参数是 'void*' 时;转换的事情正在做一些奇怪的事情。源字符串和加密解密后的字符串应该是匹配的;不幸的是,这并没有发生。
  • 我假设这是您使用的 WinRT 方法,因此您使用的是 C++/CX,而不是 C++/CLI。更改了标签。

标签: c++ windows-runtime c++-cx


【解决方案1】:

我猜问题出在这个函数上:

byte* IBufferPtrToByteArray(IBuffer ^buffer)
{
    Array<unsigned char,1U> ^platArray = ref new Array<unsigned char,1U>(256);
    CryptographicBuffer::CopyToByteArray(buffer,&platArray);

    byte *dest = platArray->Data;
    return dest;
}

你正在做的是分配一个新的Platform::Array&lt;byte&gt;^ 和 1 个引用,然后获取一个指向其内部管理存储的指针,然后返回该指针——此时 Array 被取消引用并因此释放它的底层存储。因此,您返回的指针指的是已释放的内存。下一次分配可能会覆盖这些字节。

您需要做的是从CopyToByteArray() 获取按引用返回Array&lt;byte&gt;^(它创建一个新数组,可能包装输入IBuffer^ 的字节,并返回它)和复制该数组的内容

您的最终结果将类似于 Readium SDK 项目中的这个 sn-p,它采用 std::string 实例,使用 SHA-1 对其进行哈希处理,并将哈希数据复制到成员变量 uint8_t _key[KeySize]

using namespace ::Platform;
using namespace ::Windows::Foundation::Cryptography;
using namespace ::Windows::Foundation::Cryptography::Core;

auto byteArray = ArrayReference<byte>(reinterpret_cast<byte*>(const_cast<char*>(str.data())), str.length());
auto inBuf = CryptographicBuffer::CreateFromByteArray(byteArray);
auto keyBuf = HashAlgorithmProvider::OpenAlgorithm(HashAlgorithmNames::Sha1)->HashData(inBuf);

Array<byte>^ outArray = nullptr;
CryptographicBuffer::CopyToByteArray(keyBuf, &outArray);
memcpy_s(_key, KeySize, outArray->Data, outArray->Length);

步骤:

  1. 创建一个ArrayReference&lt;byte&gt;对应std::string中的字节(不复制)。
  2. 将其传递给CryptographicBuffer::CreateFromByteArray() 以获取您的IBuffer^。仍然没有复制数据。
  3. 调用您的哈希/加密函数,传递您刚刚创建的IBuffer^。你会得到另一个 IBuffer^ 作为回报,它可能使用也可能不使用完全相同的存储(我认为这真的取决于算法的实现)。
  4. 创建Array&lt;byte&gt;^ 类型的变量。不要分配一个对象,你会得到一个引用。
  5. 将该对象的地址传递到CryptographicBuffer::CopyToByteArray() 以接收您的密钥数据的副本。
  6. 虽然 Array^ 仍然有效,但将其字节复制到您的本机数组中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-04
    • 1970-01-01
    • 1970-01-01
    • 2016-06-12
    • 2012-11-01
    • 2013-02-07
    相关资源
    最近更新 更多