由於項目的須要用到golang的一種特殊的加密解密算法AES/ECB/PKCS5,可是算法並無包含在標準庫中,通過屢次失敗的嘗試,終於解碼成功,特此分享:git
/* 描述 : golang AES/ECB/PKCS5 加密解密 date : 2016-04-08 */ package main import ( "bytes" "crypto/aes" "crypto/cipher" "encoding/base64" "fmt" "strings" ) func main() { /* *src 要加密的字符串 *key 用來加密的密鑰 密鑰長度能夠是128bit、192bit、256bit中的任意一個 *16位key對應128bit */ src := "0.56" key := "0123456789abcdef" crypted := AesEncrypt(src, key) AesDecrypt(crypted, []byte(key)) Base64URLDecode("39W7dWTd_SBOCM8UbnG6qA") } func Base64URLDecode(data string) ([]byte, error) { var missing = (4 - len(data)%4) % 4 data += strings.Repeat("=", missing) res, err := base64.URLEncoding.DecodeString(data) fmt.Println(" decodebase64urlsafe is :", string(res), err) return base64.URLEncoding.DecodeString(data) } func Base64UrlSafeEncode(source []byte) string { // Base64 Url Safe is the same as Base64 but does not contain '/' and '+' (replaced by '_' and '-') and trailing '=' are removed. bytearr := base64.StdEncoding.EncodeToString(source) safeurl := strings.Replace(string(bytearr), "/", "_", -1) safeurl = strings.Replace(safeurl, "+", "-", -1) safeurl = strings.Replace(safeurl, "=", "", -1) return safeurl } func AesDecrypt(crypted, key []byte) []byte { block, err := aes.NewCipher(key) if err != nil { fmt.Println("err is:", err) } blockMode := NewECBDecrypter(block) origData := make([]byte, len(crypted)) blockMode.CryptBlocks(origData, crypted) origData = PKCS5UnPadding(origData) fmt.Println("source is :", origData, string(origData)) return origData } func AesEncrypt(src, key string) []byte { block, err := aes.NewCipher([]byte(key)) if err != nil { fmt.Println("key error1", err) } if src == "" { fmt.Println("plain content empty") } ecb := NewECBEncrypter(block) content := []byte(src) content = PKCS5Padding(content, block.BlockSize()) crypted := make([]byte, len(content)) ecb.CryptBlocks(crypted, content) // 普通base64編碼加密 區別於urlsafe base64 fmt.Println("base64 result:", base64.StdEncoding.EncodeToString(crypted)) fmt.Println("base64UrlSafe result:", Base64UrlSafeEncode(crypted)) return crypted } func PKCS5Padding(ciphertext []byte, blockSize int) []byte { padding := blockSize - len(ciphertext)%blockSize padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(ciphertext, padtext...) } func PKCS5UnPadding(origData []byte) []byte { length := len(origData) // 去掉最後一個字節 unpadding 次 unpadding := int(origData[length-1]) return origData[:(length - unpadding)] } type ecb struct { b cipher.Block blockSize int } func newECB(b cipher.Block) *ecb { return &ecb{ b: b, blockSize: b.BlockSize(), } } type ecbEncrypter ecb // NewECBEncrypter returns a BlockMode which encrypts in electronic code book // mode, using the given Block. func NewECBEncrypter(b cipher.Block) cipher.BlockMode { return (*ecbEncrypter)(newECB(b)) } func (x *ecbEncrypter) BlockSize() int { return x.blockSize } func (x *ecbEncrypter) CryptBlocks(dst, src []byte) { if len(src)%x.blockSize != 0 { panic("crypto/cipher: input not full blocks") } if len(dst) < len(src) { panic("crypto/cipher: output smaller than input") } for len(src) > 0 { x.b.Encrypt(dst, src[:x.blockSize]) src = src[x.blockSize:] dst = dst[x.blockSize:] } } type ecbDecrypter ecb // NewECBDecrypter returns a BlockMode which decrypts in electronic code book // mode, using the given Block. func NewECBDecrypter(b cipher.Block) cipher.BlockMode { return (*ecbDecrypter)(newECB(b)) } func (x *ecbDecrypter) BlockSize() int { return x.blockSize } func (x *ecbDecrypter) CryptBlocks(dst, src []byte) { if len(src)%x.blockSize != 0 { panic("crypto/cipher: input not full blocks") } if len(dst) < len(src) { panic("crypto/cipher: output smaller than input") } for len(src) > 0 { x.b.Decrypt(dst, src[:x.blockSize]) src = src[x.blockSize:] dst = dst[x.blockSize:] } }
這是做者對多篇博客和代碼整理而成,若是您以爲本文對您有幫助,歡迎打賞一杯咖啡做爲對做者的鼓勵,謝謝!github
鳴謝:golang
Go加密解密之AES:http://blog.studygolang.com/tag/aes_encrypt/算法
yinheli: https://gist.github.com/yinheli/3370e0e901329b639be4app