代码之家  ›  专栏  ›  技术社区  ›  Paulo Fernando Ozório Ferraz

如何将SecByteBlock转换为字符串?

  •  4
  • Paulo Fernando Ozório Ferraz  · 技术社区  · 9 年前

    我尝试转换时遇到问题 SecByteBlock 到字符串。 这是我的案例:

    我想用静态密钥和动态ivAES加密用户访问数据。 我的代码是这样的:

    AesKeyIvFactory aesKeyIvFactory;
    SecByteBlock key = aesKeyIvFactory.loadKey();
    SecByteBlock iv = aesKeyIvFactory.createIv();
    
    encryptionService->encode(&userAccess, key, iv);
    std::string token = std::string(iv.begin(), iv.end()) + userAccess;
    

    上面的代码应该是:

    1. 从文件加载密钥;

    2. 创建iv;

    3. 加密(AES)用户访问数据;

    4. 将iv与加密的用户数据访问连接起来,以创建“令牌”;

    多次运行测试,有时(1到10次) std::string(iv.begin(), iv.end()) 无法正常工作。似乎iv中有一个“换行符”导致转换失败。

    我尝试了很多东西,但都没有效果,而且我没有c++的经验。

    我希望有人能帮助我。

    2 回复  |  直到 9 年前
        1
  •  5
  •   jww avp    9 年前

    我在尝试将SecByteBlock转换为字符串时遇到问题

    如果问题是从 SecByteBlock 和它的 byte 数组到 std::string 和它的 char 数组,则应:

    SecByteBlock iv;
    ...
    
    // C-style cast
    std::string token = std::string((const char*)iv.data(), iv.size()) + userAccess;
    

    SecByteBlock iv;
    ...
    
    // C++-style cast
    std::string token = std::string(reinterpret_cast<const char*>(iv.data()), iv.size()) + userAccess;
    

    您也可以放弃赋值,只需初始化并稍后追加:

    SecByteBlock iv;
    ...
    
    std::string token(reinterpret_cast<const char*>(iv.data()), iv.size());
    ...
    
    std::string userAccess;
    ...
    
    token += userAccess;
    

    你可能遇到的另一个问题是 string SecByteBlock(字节块) 。您应该这样做:

    std::string str;
    ...
    
    // C-style cast
    SecByteBlock sbb((const byte*)str.data(), str.size());
    

    或:

    std::string str;
    ...
    
    // C++-style cast
    SecByteBlock sbb(reinterpret_cast<const byte*>(str.data()), str.size());
    
        2
  •  3
  •   jww avp    9 年前

    我想Eric回答了你关于如何转换 SecByteBlock std::string (包括 char* byte* ). 但你可以这样做 std::string token = std::string(iv.begin(), iv.end()) + userAccess; 问题

    string token;
    
    SecByteBlock iv(16), userAccess(16);
    OS_GenerateRandomBlock(false, iv, iv.size());
    OS_GenerateRandomBlock(false, userAccess, userAccess.size());
    
    SecByteBlock nil;
    nil.CleanNew(HMAC<SHA256>::DEFAULT_KEYLENGTH);
    
    HMAC<SHA256> hmac;
    hmac.SetKey(nil.data(), nil.size());
    
    HashFilter filter(hmac, new HexEncoder(new StringSink(token)));
    filter.Put(iv.data(), iv.size());
    filter.Put(userAccess.data(), userAccess.size());
    filter.MessageEnd();
    
    cout << token << endl;
    

    这个 SecByteBlock nil 创建一个没有内存或大小的对象。这个 nil.CleanNew(HMAC<SHA256>::DEFAULT_KEYLENGTH) 调整大小并初始化 SecByteBlock(字节块) 设置为0。否则,内存块未初始化。

    可以声明它并使用0初始化数组调整大小,但您必须熟悉源代码,因为在Crypto++5.6.2中没有Doxygen NULL 指针,但大小不是0。这是它的外观,但它非常不直观:

    SecByteBlock nil(NULL, HMAC<SHA256>::DEFAULT_KEYLENGTH);
    

    诀窍就在于此 SecBlock<T> 构造函数:

    00250    SecBlock(const T *t, size_type len)
    00251        : m_size(len)
    00252    {
    00253        m_ptr = m_alloc.allocate(len, NULL);
    00254        if (t == NULL)
    00255            memset_z(m_ptr, 0, len*sizeof(T));
    00256        else
    00257            memcpy(m_ptr, t, len*sizeof(T));
    00258    }
    

    如果可能,您应该使用 HKDF 而不是 HMAC<SHA> 用一个 nil 向量以从安全参数中提取熵。您可以找到 香港发展基金 在回购协议中 HKDF class 。这是一个独立的标头,因此它“只起作用”。


    具有随机值的程序的典型运行 iv userAccess 是:

    $ ./cryptopp-test.exe
    061CF705259058C4E01A2BF22830FC3F2A7E97F12FE605B38405B1E1B19A9E0F
    

    另一种方法是基于 SecByteBlock(字节块) operator += 。结果是二进制字符串,而不是人类可读的ASCII字符串。

    SecByteBlock result;
    
    result += iv;
    result += SecByteBlock(userAccess.data(), userAccess.size());
    
    string token(result.data(), result.size());
    

    如果您需要一个人类可读的字符串,请通过 HexEncoder :

    HexEncoder hex(new StringSink(token));
    hex.Put(result.data(), result.size());
    hex.MessageEnd();
    

    但它没有从参数中提取熵,所以我个人不太喜欢它。


    当您从 SecByteBlock(字节块) std::字符串 ,您实际上失去了安全分配器。这意味着在将数据导出到 string 对象


    这个 HexEncoder 是一个方便的项目,它允许您转储二进制字符串。

    另一个有用的可能是 Base64URLEncoder 。它使用网络安全字母表。