继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

BASE64编码原理与Golang代码调用

holdtom
关注TA
已关注
手记 1885
粉丝 240
获赞 992


一.概念简介

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2^6=64,所以每6个比特为一个单元,对应某个可打印字符。3个字节有24个比特,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。它可用来作为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。

Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据

二.代码调用

在Golang中提供了代码库可以供我们直接调用,用于实现Base64的编码与解码,其提供了对两种格式的数据进行编码(与解码)

const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"

来自golang源码base64.go

1.标准数据(encodeStd)

    msg := "Mac"

    //编码

    base64EncodedString := base64.StdEncoding.EncodeToString([]byte(msg))

    fmt.Println("Base64编码后:", base64EncodedString)

    //解码

    base64DecodedByte, err := base64.StdEncoding.DecodeString(base64EncodedString)

    if err != nil {

        log.Panic(err)

    }

    fmt.Println("Base64解码后的字节数组:", base64DecodedByte)

    fmt.Println("Base64解码后:", string(base64DecodedByte))

返回打印结果

Base64编码后: TWFj

Base64解码后的字节数组: [77 97 99]

Base64解码后: Mac

2.URL数据(encodeURL)

msgUrl :="http://www.google.com"

    base64UrlEncodedString :=base64.URLEncoding.EncodeToString([]byte(msgUrl))

    fmt.Println("Base64编码后:", base64UrlEncodedString)

    base64UrlDecodedByte,err := base64.URLEncoding.DecodeString(base64UrlEncodedString)

    if err !=nil {

        log.Panic(err)

    }

    fmt.Println("Base64解码后的字节数组:", base64UrlDecodedByte)

    fmt.Println("Base64解码后:", string(base64UrlDecodedByte))

返回打印结果

Base64编码后: aHR0cDovL3d3dy5nb29nbGUuY29t

Base64解码后的字节数组: [104 116 116 112 58 47 47 119 119 119 46 103 111 111 103 108 101 46 99 111 109]

Base64解码后: http://www.google.com

三.编码原理

1.将每个字符转成ASCII编码(10进制)

fmt.Println([]byte(msg)) //[77 97 99]

2.将10进制编码转成2进制编码

fmt.Printf("%b",[]byte(msg)) 

//[1001101 1100001 1100011] 

补齐8位为:

[01001101 01100001 01100011] 

3.将2进制编码按照6位一组进行平分

010011 010110 000101 100011

4.转成10进制数

010011 ==> 1x2^0 + 1x2^1 + 0 + 0 + 1x2^4 = 19

010110 ==> 0 + 1x2^1 + 1x2^2 + 0 + 1x2^4 = 22

000101 ==> 1x2^0 + 0 + 1 x 2^2 + 0 + 0 + 0 = 5

100011 ==> 1x2^0 + 1x2^1 + 0 + 0 + 0 + 1x2^5 = 35

5.将十进制数作为索引,从Base64编码表中查找字符

BASE64编码原理与Golang代码调用

19 对应 T

22 对应 W

5  对应 F

35 对应 j (注意是小写)

注意

若文本为3个字符,则刚好编码为4个字符长度(3 8 = 4 6)

若文本为2个字符,则编码为3个字符,尾部用一个"="补齐

若文本为1个字符,则编码为2个字符,尾部用两个"="补齐

四.Base58代码实现

Base58是用于Bitcoin中使用的一种独特的编码方式,主要用于产生Bitcoin的钱包地址。

相比Base64,Base58不使用数字"0",字母大写"O",字母大写"I",和字母小写"l",以及"+"和"/"符号。

设计Base58主要的目的是:

避免混淆。在某些字体下,数字0和字母大写O,以及字母大写I和字母小写l会非常相似。

不使用"+"和"/"的原因是非字母或数字的字符串作为帐号较难被接受。

没有标点符号,通常不会被从中间分行。

大部分的软件支持双击选择整个字符串。

但是这个base58的计算量比base64的计算量多了很多。因为58不是2的整数倍,需要不断用除法去计算。

而且长度也比base64稍微多了一点。

附上golang的代码实现

package main

import (

    "math/big"

    "bytes"

    "fmt"

)

func main() {

    /*

    测试Base58

     */

    //1.原始数据

    data1 := []byte{10, 20, 30, 40, 50, 60}

    data1 = append([]byte{0},data1...) //前缀+数据

    fmt.Println("原始数据:",data1)

    //Base58编码

    encode:=Base58Encode(data1)

    fmt.Println("Base58编码后:",encode) //[]byte

    fmt.Println(string(encode))

    //Base58解码

    decode:=Base58Decode(encode)

    fmt.Println("Base58解码后:",decode)

    //测试数据

    data2:="wangergou"

    encode2:=Base58Encode([]byte(data2))

    fmt.Println(encode2)

    fmt.Println(string(encode2))

    decode2:=Base58Decode(encode2)

    fmt.Println(decode2)

    fmt.Println(string(decode2))

    fmt.Println(string(decode2[1:])) //wangergou

}

//base64

/*

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

0(零),O(大写的o),I(大写的i),l(小写的L),+,/

 */

var b58Alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")

//字节数组转Base58,加密

func Base58Encode(input []byte) []byte {

    var result [] byte

    x := big.NewInt(0).SetBytes(input)

    //fmt.Println("x:",x)

    base := big.NewInt(int64(len(b58Alphabet)))//58

    //fmt.Println("base:",base)

    zero := big.NewInt(0)

    mod := &big.Int{}

    for x.Cmp(zero) != 0 {

        x.DivMod(x, base, mod)

        //fmt.Println("x:",x,",mod:",mod) //0-57

        result = append(result, b58Alphabet[mod.Int64()])

        //fmt.Println("result:",string(result))

    }

    //将得到result中的数据进行反转

    ReverseBytes(result)

    for b := range input { //遍历input数组:index,value

        if b == 0x00 {

            result = append([]byte{b58Alphabet[0]}, result...)

        } else {

            break

        }

    }

    //1 result

    return result

}

//Base58转字节数组,解密

func Base58Decode(input [] byte) []byte {

    result := big.NewInt(0)

    zeroBytes := 0

    for b := range input {

        if b == 0x00 {

            zeroBytes++

        }

    }

    fmt.Println("zeroBytes:",zeroBytes)

    payload := input[zeroBytes:]

    for _, b := range payload {

        charIndex := bytes.IndexByte(b58Alphabet, b)

        result.Mul(result, big.NewInt(58))

        result.Add(result, big.NewInt(int64(charIndex)))

    }

    decoded := result.Bytes()

    decoded = append(bytes.Repeat([]byte{byte(0x00)}, zeroBytes), decoded...)

    return decoded

}

//字节数组反转

func ReverseBytes(data []byte) {

    for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {

        data[i], data[j] = data[j], data[i]

    }

}

©著作权归作者所有:来自51CTO博客作者暗黑魔君的原创作品,如需转载,请注明出处,否则将追究法律责任


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP