因为项目的需要用到golang的一种特殊的加密解密算法AES/ECB/PKCS5,但是算法并没有包含在标准库中,经过多次失败的尝试,终于解码成功,特此分享:
/* 描述 : 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:] } }
这是作者对多篇博客和代码整理而成,如果您觉得本文对您有帮助,欢迎打赏一杯咖啡作为对作者的鼓励,谢谢!
鸣谢:
Go加密解密之AES:http://blog.studygolang.com/tag/aes_encrypt/
yinheli: https://gist.github.com/yinheli/3370e0e901329b639be4