Base64解码过程必须关注的问题
博客专区 > 凉皮 的博客 > 博客详情
Base64解码过程必须关注的问题
凉皮 发表于6个月前
Base64解码过程必须关注的问题
  • 发表于 6个月前
  • 阅读 598
  • 收藏 14
  • 点赞 0
  • 评论 4

腾讯云实验室 1小时搭建人工智能应用,让技术更容易入门 免费体验 >>>   

背景

这两天开发工作中,需要运用 Base64来进行数据的编解码。使用 Cryptopp库的 base64(网络上其他基于Boost 的 BIO)都会出现解码出来的字节数只是其中很少的一部分,具体编码结果如下。

原因

1/ 问题的 Base64串

有兴趣的同学可以试试,如下是出现问题的 Base64字符串:

nh5os9KdYYloLDEAAjknMc1mobYofaepkpO8VmQOLmProkitBJHeH8RN0yloaXZ6fU8DxSA6kKL1h9sAqYjd6y5oEZeUfrII2t9Wz0zZyz96QSbpjwJGXFbLWEjwolwyi+fuYnCzpWPPOspEXieuUnEtx2y7GWquGMrf7Vee/GR/ZJOqUNJzK3g59TcjfzhhEaUsm7M65bHQ+TBDC7xDB25gmeao4K/3

2/ 基于 Golang 解码

解码后有168个字节,属于正常的字符串结果。

158 30 104 179 210 157 97 137 104 44 49 0 2 57 39 49 205 102 161 182 40 125 167 169 146 147 188 86 100 14 46 99 235 162 72 173 4 145 222 31 196 77 211 41 104 105 118 122 125 79 3 197 32 58 144 162 245 135 219 0 169 136 221 235 46 104 17 151 148 126 178 8 218 223 86 207 76 217 203 63 122 65 38 233 143 2 70 92 86 203 88 72 240 162 92 50 139 231 238 98 112 179 165 99 207 58 202 68 94 39 174 82 113 45 199 108 187 25 106 174 24 202 223 237 87 158 252 100 127 100 147 170 80 210 115 43 120 57 245 55 35 127 56 97 17 165 44 155 179 58 229 177 208 249 48 67 11 188 67 7 110 96 153 230 168 224 175 247

3/ 基于C++解码

解码后的字节数有168个,但在返回的字符串中只有11个字节,问题也就出现在返回的字符串中。如下返回字符串结果值:

158 30 104 179 210 157 97 137 104 44 49 0

通过对比发现,由于第11个字节刚好被解码为'0',因此在将字节流转换成字符字符串时,理所当然的在该字节后结尾。

4/ Cryptopp 的 Base64解码

通过C++常用的加解密库 Cryptopp 实现的 Base64解码,

string DeBase64Str(const string &content, bool newLine) {
    Base64Decoder decoder;
    decoder.PutMessageEnd((const byte*)content.data(), content.size(), -1, newLine);
    if (!decoder.AnyRetrievable()) {
        return "";
    }

    auto neededLength = decoder.MaxRetrievable(); 
    char *buffer = new char [neededLength];
    decoder.Get((byte *)buffer, neededLength);
    
    std::ostringstream oss;
    oss << buffer;

    delete[] buffer;
    return oss.str();
}
  1. 获取 neededLength变量,有168个字节,库的解码正常;
  2. 获取 buffer 的大小也有168个字节,获取字节流正常;
  3. 获取 oss 大小只有11个字节,因此判断问题出现在 buffer 转 oss 时;

通过对字节输出打印可以看出,在第11个位置的'0'被转义成结尾符,导致 buffer 输出到 oss的主要原因终于找到。

着手对代码进行改进,将 buffer 中的字符一个个输出到 oss 流中,这样就可以避免 buffer 在输出到 oss 自行转义成结尾符,问题得到的解决。

string DeBase64Str(const string &content, bool newLine) {
    Base64Decoder decoder;
    decoder.PutMessageEnd((const byte*)content.data(), content.size(), -1, newLine);
    if (!decoder.AnyRetrievable()) {
        return "";
    }

    auto neededLength = decoder.MaxRetrievable(); 
    char *buffer = new char [neededLength];
    decoder.Get((byte *)buffer, neededLength);
    
    std::ostringstream oss;
    for (size_t i = 0; i < neededLength; I++) {
        oss << buffer[i];    
    }

    delete[] buffer;
    return oss.str();
}

结论

通过上面的问题我们也发现,网上大部分的 Base64解码过程中对于 buff 输出到 oss 存在着直接输出,而非一个个字节输出。

在查找该问题时,我们也在开始认为是解码库本身出现的 Bug,也试用了Boost 的 BIO 方式或者直接 Base64解码方式,得到的结果都一样,只能获取到11个字节。因此,我们排除了解码库本身的 Bug 问题。

或许,你正也在使用 Base64进行解码,刚好也碰上这样的问题,希望这篇文章对你有帮助,或者你使用的 Base64解码已经很稳定,只是未碰到该类问题,可以试试你使用的解码中是否也存在这种问题。

标签: base64 decode
共有 人打赏支持
凉皮
粉丝 4
博文 3
码字总数 1131
评论 (4)
一如当初
直接用std::string,先resize一下,再丢给它返回就行了。std::ostringstream都是多余的。自己没搞懂别到处乱甩锅。
凉皮

引用来自“一如当初”的评论

直接用std::string,先resize一下,再丢给它返回就行了。std::ostringstream都是多余的。自己没搞懂别到处乱甩锅。
是可以用 string 加 resize 逐个赋值,省去 ostringstream。但麻烦看下重点,这个关注的问题是在 buffer中存在结尾符时如何将值准确全部赋值给 string。
一如当初

引用来自“一如当初”的评论

直接用std::string,先resize一下,再丢给它返回就行了。std::ostringstream都是多余的。自己没搞懂别到处乱甩锅。

引用来自“凉皮”的评论

是可以用 string 加 resize 逐个赋值,省去 ostringstream。但麻烦看下重点,这个关注的问题是在 buffer中存在结尾符时如何将值准确全部赋值给 string。
还逐个呢。。。

std::string DeBase64Str() {
  char mock[]{ 0x31, 0x32, 0x00, 0x34, 0x35 };
  int neededLength = 5;
  return std::string(mock, neededLength);
}
RayLee
解码出来本来就是二进制,你非要把它当作字符串处理,肯定会出错。
×
凉皮
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: