• golang AES/ECB/PKCS5 加密解密 url-safe-base64


    因为项目的需要用到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

  • 相关阅读:
    CODE[VS] 1018 单词接龙
    Linux提示BOOT空间不足问题
    CODE[VS] 1017 乘积最大
    关于printf输出结果的一些问题
    CODE[VS] 1220 数字三角形
    redux
    Promise面试题
    学习Promise笔记
    js 事件委托 事件代理
    前端通信、跨域
  • 原文地址:https://www.cnblogs.com/lavin/p/5373188.html
Copyright © 2020-2023  润新知