url编码
import (
"fmt"
"net/url"
)
func main() {
pathCode()
queryCode()
}
// 不会对特殊字符进行特殊编码
func pathCode() {
pathEncode:=url.PathEscape("!@#$%^&*()_+-= ")
fmt.Println("pathEncode====="+pathEncode)
// 不会吧+变成空格
PathUnescape,_ := url.PathUnescape(pathEncode)
fmt.Println("Pathdecode====="+PathUnescape)
}
// 会对特殊字符进行编码
func queryCode() {
quryEncode:=url.QueryEscape("!@#$%^&*()_+-= ")
fmt.Println("quryEncode====="+quryEncode)
// 会将+转成空格
quryUnescape,_ := url.QueryUnescape(quryEncode)
fmt.Println("qurydecode====="+quryUnescape)
}
base64编码
工作中碰到url与base64配合加解密的问题,base64编码后的字符串中可能含有特殊字符比如+,在url后的参数必然会经过url解码后会变成空格。解决方法为先将字符串url编码后再进行base64编码。
可以参考的文档base64中文参考文档
base64加解密
// base64解密byte数组
func DecodeToByte(data []byte) ([]byte, error) {
enc := base64.StdEncoding
dbuf := make([]byte, enc.DecodedLen(len(data)))
n, err := enc.Decode(dbuf, data)
return dbuf[:n], err
}
// base64解密字符串
func DecodeToString(data []byte) (string, error) {
enc := base64.StdEncoding
dbuf := make([]byte, enc.DecodedLen(len(data)))
n, err := enc.Decode(dbuf, data)
return string(dbuf[:n]), err
}
// 加密为byte数组
func EncodeToByte(src []byte) []byte {
enc := base64.StdEncoding
buf := make([]byte, enc.EncodedLen(len(src)))
enc.Encode(buf, src)
return buf
}
// base64加密为字符串
func EncodeToString(data []byte) (string) {
return base64.StdEncoding.EncodeToString(data)
}
文件处理
base对文件的处理其实就是对文件的加解密处理,然后再使用相应的文件读写操作。
根据base64字符串计算图片大小
Base64编码要求把3个8位字节(38=24)转化为4个6位的字节(46=24),之后在6位的前面补两个0,形成8位一个字节的形式。 如果剩下的字符不足3个字节,则用0填充,输出字符使用’=’,因此编码后输出的文本末尾可能会出现1或2个’=’(相当于多了一个或两个字节)
ff, _ := ioutil.ReadFile("image/19155559_E3nk.jpg") //我还是喜欢用这个快速读文件
fmt.Println("编码前图片大小=====",len(ff))
buf_store:=EncodeToByte( ff) // 文件转base64
_ = ioutil.WriteFile("image/output2.jpg.txt", buf_store, 0666) //直接写入到文件就ok完活了。
fmt.Println("编码后base64大小=====",len(buf_store))
count:=strings.Count(string(buf_store), "=")
noeq:=string(buf_store)[0:strings.Index(string(buf_store), "=")]
fmt.Println("去掉等号后的大小=====",len(noeq))
fmt.Println("两者相除=====",float32(len(noeq))/float32(len(ff)))
fmt.Println("base64求得原图片大小=====",int(float32(len(buf_store))*3/4)-count)
AES加解密
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
)
/*CBC加密 按照golang标准库的例子代码
不过里面没有填充的部分,所以补上
*/
//使用PKCS7进行填充,IOS也是7
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext) % blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS7UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
//aes加密,填充秘钥key的16位,24,32分别对应AES-128, AES-192, or AES-256.
func AesCBCEncrypt(rawData,key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
//填充原文
blockSize := block.BlockSize()
rawData = PKCS7Padding(rawData, blockSize)
//初始向量IV必须是唯一,但不需要保密
cipherText := make([]byte,blockSize+len(rawData))
//block大小 16
iv := cipherText[:blockSize]
if _, err := io.ReadFull(rand.Reader,iv); err != nil {
panic(err)
}
//block大小和初始向量大小一定要一致
mode := cipher.NewCBCEncrypter(block,iv)
mode.CryptBlocks(cipherText[blockSize:],rawData)
return cipherText, nil
}
func AesCBCDncrypt(encryptData, key []byte) ([]byte,error) {
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
blockSize := block.BlockSize()
if len(encryptData) < blockSize {
panic("ciphertext too short")
}
iv := encryptData[:blockSize]
encryptData = encryptData[blockSize:]
// CBC mode always works in whole blocks.
if len(encryptData)%blockSize != 0 {
panic("ciphertext is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
// CryptBlocks can work in-place if the two arguments are the same.
mode.CryptBlocks(encryptData, encryptData)
//解填充
encryptData = PKCS7UnPadding(encryptData)
return encryptData,nil
}
func Encrypt(rawData,key []byte) ([]byte,error) {
data, err:= AesCBCEncrypt(rawData,key)
if err != nil {
return nil,err
}
return data,nil
}
func Dncrypt(rawData ,key []byte) ([]byte,error) {
dnData,err := AesCBCDncrypt(rawData,key)
if err != nil {
return nil,err
}
return dnData,nil
}
TEST
import (
"fmt"
"testing"
)
func TestAesCBCDncrypt(t *testing.T) {
// key : 长度为:16,24,32
var aeskey = []byte("321423u9y8d2fwfl")
pass := []byte("vdncloud123456")
xpass, err := Encrypt(pass, aeskey)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("xpass=====",string(xpass))
tpass, err := Dncrypt(xpass, aeskey)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("tpass=====",string(tpass))
fmt.Printf("解密后:%s\n", tpass)
}
DES加解密
import (
"bytes"
"crypto/cipher"
"crypto/des"
)
//去除补码
func PKCS5UnPadding(origData []byte) []byte {
length := len(origData)
// 去掉最后一个字节 unpadding 次
unpadding := int(origData[length-1])
//解密去补码时需取最后一个字节,值为m,则从数据尾部删除m个字节,剩余数据即为加密前的原文
return origData[:(length - unpadding)]
}
//加密
func DesEncrypt(origData, key []byte) ([]byte, error) {
block, err := des.NewCipher(key)
if err != nil {
return nil, err
}
origData = PKCS5Padding(origData, block.BlockSize())
// origData = ZeroPadding(origData, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, key)
crypted := make([]byte, len(origData))
// 根据CryptBlocks方法的说明,如下方式初始化crypted也可以
// crypted := origData
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
// 解密
func DesDecrypt(crypted, key []byte) ([]byte, error) {
block, err := des.NewCipher(key)
if err != nil {
return nil, err
}
blockMode := cipher.NewCBCDecrypter(block, key)
origData := make([]byte, len(crypted))
// origData := crypted
blockMode.CryptBlocks(origData, crypted)
origData = PKCS5UnPadding(origData)
// origData = ZeroUnPadding(origData)
return origData, nil
}
//func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
// padding := blockSize - len(ciphertext)%blockSize
// padtext := bytes.Repeat([]byte{byte(padding)}, padding)
// return append(ciphertext, padtext...)
//}
//实现明文的补码
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
//计算出需要补多少位
padding := blockSize - len(ciphertext)%blockSize
//Repeat()函数的功能是把参数一 切片复制 参数二count个,然后合成一个新的字节切片返回
// 需要补padding位的padding值
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
//把补充的内容拼接到明文后面
return append(ciphertext, padtext...)
}
// 3DES加密
func TripleDesEncrypt(origData, key []byte) ([]byte, error) {
block, err := des.NewTripleDESCipher(key)
if err != nil {
return nil, err
}
origData = PKCS5Padding(origData, block.BlockSize())
// origData = ZeroPadding(origData, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, key[:8])
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
// 3DES解密
func TripleDesDecrypt(crypted, key []byte) ([]byte, error) {
block, err := des.NewTripleDESCipher(key)
if err != nil {
return nil, err
}
blockMode := cipher.NewCBCDecrypter(block, key[:8])
origData := make([]byte, len(crypted))
// origData := crypted
blockMode.CryptBlocks(origData, crypted)
origData = PKCS5UnPadding(origData)
// origData = ZeroUnPadding(origData)
return origData, nil
}
TEST
import (
"fmt"
"testing"
)
func TestDesEncrypt(t *testing.T) {
//定义明文
data := []byte("hello world")
//密钥 8位
key := []byte("12345678")
//加密
des, err:=DesEncrypt(data, key)
fmt.Println(string(des),err)
//解密
dec,err:=DesDecrypt(des, key)
fmt.Println(string(dec),err)
}
func TestTripleDesEncrypt(t *testing.T) {
//定义明文
data := []byte("hello world")
//密钥 24位
key := []byte("012345678901234567891234")
//加密
des, err:=TripleDesEncrypt(data, key)
fmt.Println(string(des),err)
//解密
dec,err:=TripleDesDecrypt(des, key)
fmt.Println(string(dec),err)
}