首页 > 其他分享 >【转】Golang base64 解码碰到的坑

【转】Golang base64 解码碰到的坑

时间:2023-03-08 16:59:14浏览次数:41  
标签:encrypt DecodeString err 解码 base64 Golang main fmt

背景
在一次调用三方API的时候,为了数据安全和三方API的请求和返回信息都用了rsa加密,由于rsa算法生成的内容是二进制的,所以需要用base64编码将二进制数据转化成64个可打印字符进行通信或者存储。在获取到三方的base64编码的返回信息后,解码碰到了各种问题,如下是日志里打印的三方的一个base64编码后的字符串

Cf1WA2nBMo3H9G2UPhlLBBVBsMDl4udWr7__e6Iy93eIqLKi3EOjGhk8TkHujL1Uj6aGfZJNBzIbVE2NfNaz4pob8uiQvGaeTZdWP-8lFmAm6J1sz8N15xQkO7ADa5bNLCCqtlQbN2z7JcNenvFuID_rZGqb_1gmr-BGubGRMiMSK7RdjQYrMHaBcHLPB0UteakzcQwgKxCW7u0ECHqPJ39ne9JUG22JBWRo1ORuX5r30J_XrW3SQcdPSxfe0kvd61y12QOYh8VlOBBdBeDNnyDXefI_tDJDBFeqTXCgKu9wFkkWIZiM7WwqogaY-bvjUisbrPO4_fjJ1c0nWDOqRA

 

解码过程
1.使用标准库的base64.StdEncoding.DecodeString
最开始是印象标准库有一个base64.StdEncoding.DecodeString方法可以解码,就直接使用了这个方法

package main
 
import(
    "encoding/base64"
    "fmt"
)
 
func main(){
    encrypt := "Cf1WA2nBMo3H9G2UPhlLBBVBsMDl4udWr7__e6Iy93eIqLKi3EOjGhk8TkHujL1Uj6aGfZJNBzIbVE2NfNaz4pob8uiQvGaeTZdWP-8lFmAm6J1sz8N15xQkO7ADa5bNLCCqtlQbN2z7JcNenvFuID_rZGqb_1gmr-BGubGRMiMSK7RdjQYrMHaBcHLPB0UteakzcQwgKxCW7u0ECHqPJ39ne9JUG22JBWRo1ORuX5r30J_XrW3SQcdPSxfe0kvd61y12QOYh8VlOBBdBeDNnyDXefI_tDJDBFeqTXCgKu9wFkkWIZiM7WwqogaY-bvjUisbrPO4_fjJ1c0nWDOqRA"
    _,err := base64.StdEncoding.DecodeString(encrypt)
    if err != nil {
        fmt.Println(err)
    }
}
————————————————
版权声明:本文为CSDN博主「只会打野怪我咯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u014270740/article/details/91038606

执行结果

illegal base64 data at input byte 34

解码报错了,根据提示意思大概能猜到是第34位的字符‘_’ base64不认识,去查了下base64的索引表

 

 

发现base64的字符集内没有我们第34位对应的字符‘_’,当时想是不是做了类似urlencode的编码,防止http传输过程中部分字符转义,继续查base64文档发现了 如下一段内容

 

可以确定是将+和/分别改成了-和_, 那我们应该做一下字符串替换把-和_改回来就行,本来想直接在代码里面写字符串替换,后来想GO标准库还没细看,里面是不是还有现成的方法之前没发现,查了下标准库发现

 

 URLEncoding和我们刚用的StdEncoding有一些区别,是用于URL和文件名,刚我们碰到的问题也是URL问题。

 

2.用base64.URLEncoding.DecodeString方法尝试
经过了上一步的测试和文档查找,感觉用这个方法应该就可以搞定问题了,赶紧写个测试看看

package main
 
import(
    "encoding/base64"
    "fmt"
)
 
func main(){
    encrypt := "Cf1WA2nBMo3H9G2UPhlLBBVBsMDl4udWr7__e6Iy93eIqLKi3EOjGhk8TkHujL1Uj6aGfZJNBzIbVE2NfNaz4pob8uiQvGaeTZdWP-8lFmAm6J1sz8N15xQkO7ADa5bNLCCqtlQbN2z7JcNenvFuID_rZGqb_1gmr-BGubGRMiMSK7RdjQYrMHaBcHLPB0UteakzcQwgKxCW7u0ECHqPJ39ne9JUG22JBWRo1ORuX5r30J_XrW3SQcdPSxfe0kvd61y12QOYh8VlOBBdBeDNnyDXefI_tDJDBFeqTXCgKu9wFkkWIZiM7WwqogaY-bvjUisbrPO4_fjJ1c0nWDOqRA"
    _,err := base64.URLEncoding.DecodeString(encrypt)
    if err != nil {
        fmt.Println(err)
    }
}

————————————————
版权声明:本文为CSDN博主「只会打野怪我咯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u014270740/article/details/91038606

执行一下 又报错了,心累,看了下错误信息illegal base64 data at input byte 340,跟第一步报错的大致一样只是最后的位置变到了340,说明我们前面转义的问题用这个方法还是解决了,但是执行到最后的时候又有不标准字符了,继续查base64的文档,又有新发现,如图

 

  

大致意思是,如果编码的时候字节不足会在最后加一到两个=号,但看我们的字符串最后没有=,解码的时候解到最后又报错了,赶紧给字符串手动加个等号试试

package main
 
import(
    "encoding/base64"
    "fmt"
)
 
func main(){
    encrypt := "Cf1WA2nBMo3H9G2UPhlLBBVBsMDl4udWr7__e6Iy93eIqLKi3EOjGhk8TkHujL1Uj6aGfZJNBzIbVE2NfNaz4pob8uiQvGaeTZdWP-8lFmAm6J1sz8N15xQkO7ADa5bNLCCqtlQbN2z7JcNenvFuID_rZGqb_1gmr-BGubGRMiMSK7RdjQYrMHaBcHLPB0UteakzcQwgKxCW7u0ECHqPJ39ne9JUG22JBWRo1ORuX5r30J_XrW3SQcdPSxfe0kvd61y12QOYh8VlOBBdBeDNnyDXefI_tDJDBFeqTXCgKu9wFkkWIZiM7WwqogaY-bvjUisbrPO4_fjJ1c0nWDOqRA"
    //为了不修改原字符串,没有直接在原字符串上追加
    encrypt = fmt.Sprint(encrypt,"==")
    _,err := base64.URLEncoding.DecodeString(encrypt)
    if err != nil {
        fmt.Println(err)
    }
}
————————————————
版权声明:本文为CSDN博主「只会打野怪我咯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u014270740/article/details/91038606

加了两个等号,居然解码成功了,太不容易了,但是这问题也来了, 这追加的等号也不是固定的,如果在代码里面判断增加也很不方便啊,刚尝到查GO文档的好处了,带着问题找一个可以忽略最后等号的方法,看下GO文档里有没有,

 

3.使用base64.RawURLEncondig.DecodeString
前一个步骤我们得到的结论要在GO文档中找一个可以将-_还原成base64字符的同时可以让我们忽略末尾=号的,嗯 还真找到了一个base64.RawURLEncoding.DecodeString,赶紧试下

package main
 
import(
    "encoding/base64"
    "fmt"
)
 
func main(){
    encrypt := "Cf1WA2nBMo3H9G2UPhlLBBVBsMDl4udWr7__e6Iy93eIqLKi3EOjGhk8TkHujL1Uj6aGfZJNBzIbVE2NfNaz4pob8uiQvGaeTZdWP-8lFmAm6J1sz8N15xQkO7ADa5bNLCCqtlQbN2z7JcNenvFuID_rZGqb_1gmr-BGubGRMiMSK7RdjQYrMHaBcHLPB0UteakzcQwgKxCW7u0ECHqPJ39ne9JUG22JBWRo1ORuX5r30J_XrW3SQcdPSxfe0kvd61y12QOYh8VlOBBdBeDNnyDXefI_tDJDBFeqTXCgKu9wFkkWIZiM7WwqogaY-bvjUisbrPO4_fjJ1c0nWDOqRA"
    _,err := base64.RawURLEncoding.DecodeString(encrypt)
    if err != nil {
        fmt.Println(err)
    }
}
————————————————
版权声明:本文为CSDN博主「只会打野怪我咯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u014270740/article/details/91038606

执行下,终于完美成功了。

 

总结
base64编码过程有两部特殊操作

url safe 将+/字符串转化成_-
no padding is add 末尾不增加=号

ps: 作者遇到的问题其实是稳定的前端输入,如果我们的前端输入可能带来不同的 encode 方式,那么我们可能并无法只兼容最后一种可能就可以,而是需要每种解析都遍历到,留下没有 error 的结果即可。

func ParseB64String(b64String string) ([]byte, error) {
    missingPadding := len(b64String) % 4
    if missingPadding != 0 {
        b64String = b64String + strings.Repeat("=", missingPadding)
    }
    decodedBytes, err := base64.RawURLEncoding.DecodeString(b64String)
    if err != nil {
        decodedBytes, err = base64.URLEncoding.DecodeString(b64String)
        if err != nil {
            decodedBytes, err = base64.StdEncoding.DecodeString(b64String)
            if err != nil {
                logs.Warning.Println("decode base64 fail:", err.Error())
                return []byte{}, err
            }
        }
    }

    return decodedBytes, nil
}

 

 

Reference:

https://blog.csdn.net/u014270740/article/details/91038606

 

标签:encrypt,DecodeString,err,解码,base64,Golang,main,fmt
From: https://www.cnblogs.com/piperck/p/17192596.html

相关文章

  • (转)Golang中time包用法及一些注意事项
    原文:https://blog.csdn.net/wade3015/article/details/109328485在我们日常软件开发过程中,经常会用到与时间相关的各种业务需求,下面来介绍golang中有关时间的一些基本用......
  • (转)Golang中log日志包的使用
    原文:https://juejin.cn/post/69872042995330580781.前言作为后端开发人员,日志文件记录了发生在操作系统或其他软件运行时的事件或状态。技术人员可以通过日志记录进而......
  • (转)Golang使用系列---- Go Net 协议层
    原文:https://kingjcy.github.io/post/golang/go-net/Golang使用系列----GoNet协议层网络编程是go语言使用的一个核心模块。golang的网络封装使用对于底层socket或者......
  • (转)Golang网络开发系列(二)—— net包
    原文:https://zhuanlan.zhihu.com/p/575280551这篇文章我们将开始学习net包。因为我们大多是从net.Listen开始写一个tcpserver的,这篇文章我们就从上到下去分析,直到遇到int......
  • 基于DDD的golang实现
    女主宣言今天小编为大家分享基于DDD的golang实现,DDD即领域驱动设计,该模式也算是比较热门的话题了。希望通过本篇文章,大家能够掌握DDD模式,能对大家有所帮助。PS:丰富的一线......
  • 在 Java 中解码 Base64 数据
    我有一个Base64编码的图像。在Java中解码它的最佳方法是什么?希望只使用SunJava6中包含的库。解答http://www.stackoverflow.ink/posts/zai-java-zhong-......
  • golang 方法( method )
    1.方法的定义方法总是绑定对象实例,并隐式的将实例作为第一实参(receiver),receiver可以是基础类型,也可以是指针类型,这会关系到是否需要有可以修改对象实例的能力。2.......
  • golang 结构体(struct)
    1.结构体定义Golang没有类(class),Go语言的结构体(struct)和其它编程语言的类(class)有同等的地位,你可以理解Gelang是基于struct来实现OOP特性的。结构体由一系列命名的......
  • Golang+Gin+ Redis Cluster
    最近用redisshake做redis数据迁移,由于redis提供的客户端没有用于查看集群的工具,且我部署的redis集群是基于k8s来构建的,没有使用ingress做转发,所以只能在k8s内部访问集群,于......
  • golang 升级 1.16.3 之后,编译报错 missing go.sum entry for module providing packag
    问题现象在开发机上升级到了最新golang1.16.3版本,在为一个基于golang1.13的历史项目添加excel依赖包后gogetgithub.com/360EntSecGroup-Skylar/excelize/v2......