3

基于golang常用加密解码的封装

 2 years ago
source link: https://studygolang.com/articles/35590
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

基于golang常用加密解码的封装

mange · 1天之前 · 413 次点击 · 预计阅读时间 13 分钟 · 大约8小时之前 开始浏览    

AES : 高级加密标准;AES的区块长度固定为128 比特,密钥长度则可以是128,192或256比特;

type AES interface {
    Encrypt(str, key []byte) ([]byte, error)
    Decrypt(str, key []byte) ([]byte, error)
}

DES : 数据加密标准,是一种使用密钥加密的块算法

type DES interface {
    Encrypt(str, key []byte) ([]byte, error)
    Decrypt(str, key []byte) ([]byte, error)
}

AES&DES 支持的模式: CBC 密码分组链接模式(Cipher Block Chaining (CBC))

// CBC : 密码分组链接模式(Cipher Block Chaining (CBC)) default
type cbcObj struct {
    cryptoType string
    iv []byte
}

func (cbc *cbcObj) getBlock(key []byte) (block cipher.Block, err error) {
    if cbc.cryptoType == "aes" {
        block, err = aes.NewCipher(key)
    }
    if cbc.cryptoType == "des" {
        block, err = des.NewCipher(key)
    }
    return
}

// CBC Encrypt
func (cbc *cbcObj) Encrypt(str, key []byte) ([]byte, error) {
    block, err := cbc.getBlock(key)
    if err != nil {
        Error("["+cbc.cryptoType+"-CBC] ERROR:" +err.Error())
        return []byte(""), err
    }
    blockSize := block.BlockSize()
    originData := cbc.pkcs5Padding(str, blockSize)
    blockMode := cipher.NewCBCEncrypter(block,cbc.iv)
    cryptData := make([]byte,len(originData))
    blockMode.CryptBlocks(cryptData,originData)
    P2E()
    return cryptData, nil
}

// CBC Decrypt
func (cbc *cbcObj) Decrypt(str, key []byte) ([]byte, error) {
    block, err := cbc.getBlock(key)
    if err != nil {
        Error("["+cbc.cryptoType+"-CBC] ERROR:" +err.Error())
        return []byte(""), err
    }
    blockMode := cipher.NewCBCDecrypter(block, cbc.iv)
    originStr := make([]byte,len(str))
    blockMode.CryptBlocks(originStr,str)
    P2E()
    return cbc.pkcs5UnPadding(originStr), nil
}

func (cbc *cbcObj) pkcs5Padding(ciphertext []byte, blockSize int) []byte {
    padding := blockSize - len(ciphertext)%blockSize
    padText := bytes.Repeat([]byte{byte(padding)}, padding)
    return append(ciphertext, padText...)
}

func (cbc *cbcObj) pkcs5UnPadding(origData []byte) []byte {
    length := len(origData)
    unpadDing := int(origData[length-1])
    return origData[:(length - unpadDing)]
}

AES&DES 支持的模式: ECB 电码本模式(Electronic Codebook Book (ECB))

// ECB : 电码本模式(Electronic Codebook Book (ECB))
type ecbObj struct {
    cryptoType string
}

func (ecb *ecbObj) getBlock(key []byte) (block cipher.Block, err error) {
    if ecb.cryptoType == "aes" {
        block, err = aes.NewCipher(ecb.generateKey(key))
    }
    if ecb.cryptoType == "des" {
        block, err = des.NewCipher(key)
    }
    return
}

// ECB Encrypt
func (ecb *ecbObj) Encrypt(str, key []byte) ([]byte, error) {
    block, err := ecb.getBlock(key)
    if err != nil {
        Error("["+ecb.cryptoType+"-ECB] ERROR:" +err.Error())
        return []byte(""), err
    }
    blockSize := block.BlockSize()
    if ecb.cryptoType == "aes" {
        str = ecb.pkcs5PaddingAes(str, blockSize)
    }
    if ecb.cryptoType == "des" {
        str = ecb.pkcs5PaddingDes(str, blockSize)
    }

    //返回加密结果
    encryptData := make([]byte, len(str))
    //存储每次加密的数据
    tmpData := make([]byte, blockSize)
    //分组分块加密
    for index := 0; index < len(str); index += blockSize {
        block.Encrypt(tmpData, str[index:index+blockSize])
        copy(encryptData, tmpData)
    }
    P2E()
    return encryptData, nil
}

func (ecb *ecbObj) pkcs5PaddingDes(ciphertext []byte, blockSize int) []byte {
    padding := blockSize - len(ciphertext)%blockSize
    padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    return append(ciphertext, padtext...)
}

func (ecb *ecbObj) pkcs5PaddingAes(ciphertext []byte, blockSize int) []byte {
    padding := blockSize - len(ciphertext)%blockSize
    if padding != 0 {
        ciphertext = append(ciphertext, bytes.Repeat([]byte{byte(0)}, padding)...)
    }
    return ciphertext
}

// ECB Decrypt
func (ecb *ecbObj) Decrypt(str, key []byte) ([]byte, error) {
    block, err := ecb.getBlock(key)
    if err != nil {
        Error("["+ecb.cryptoType+"-ECB] ERROR:" +err.Error())
        return []byte(""), err
    }
    blockSize := block.BlockSize()
    //返回加密结果
    decryptData := make([]byte, len(str))
    //存储每次加密的数据
    tmpData := make([]byte, blockSize)

    //分组分块加密
    for index := 0; index < len(str); index += blockSize {
        block.Decrypt(tmpData, str[index:index+blockSize])
        copy(decryptData, tmpData)
    }

    if ecb.cryptoType == "des" {
        return ecb.pkcs5UnPadding(decryptData), nil
    }
    P2E()
    return ecb.unPadding(decryptData), nil
}

func (ecb *ecbObj) generateKey(key []byte) (genKey []byte) {
    genKey = make([]byte, 16)
    copy(genKey, key)
    for i := 16; i < len(key); {
        for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
            genKey[j] ^= key[i]
        }
    }
    return genKey
}

func (ecb *ecbObj) unPadding(src []byte) []byte {
    for i := len(src) - 1; ; i-- {
        if src[i] != 0 {
            return src[:i+1]
        }
    }
}

func (ecb *ecbObj) pkcs5UnPadding(origData []byte) []byte {
    length := len(origData)
    unPadding := int(origData[length-1])
    return origData[:(length - unPadding)]
}

AES&DES 支持的模式: CFB : 密码反馈模式(Cipher FeedBack (CFB))

// 密码反馈模式(Cipher FeedBack (CFB))
type cfbObj struct {
    cryptoType string
}

func (cfb *cfbObj) getBlock(key []byte) (block cipher.Block, err error) {
    if cfb.cryptoType == "aes" {
        block, err = aes.NewCipher(key)
    }
    if cfb.cryptoType == "des" {
        block, err = des.NewCipher(key)
    }
    return
}

// CFB Encrypt
func (cfb *cfbObj) Encrypt(str, key []byte) ([]byte, error) {
    P2E()
    block, err := cfb.getBlock(key)
    if err != nil {
        Error("["+cfb.cryptoType+"-CFB] ERROR:" +err.Error())
        return nil, err
    }

    if cfb.cryptoType == "aes" {
        encrypted := make([]byte, aes.BlockSize+len(str))
        iv := encrypted[:aes.BlockSize]
        if _, err := io.ReadFull(rand.Reader, iv); err != nil {
            return nil, err
        }
        stream := cipher.NewCFBEncrypter(block, iv)
        stream.XORKeyStream(encrypted[aes.BlockSize:], str)
        return encrypted, nil
    }

    if cfb.cryptoType == "des" {
        encrypted := make([]byte, des.BlockSize+len(str))
        iv := encrypted[:des.BlockSize]
        if _, err := io.ReadFull(rand.Reader, iv); err != nil {
            return nil, err
        }
        stream := cipher.NewCFBEncrypter(block, iv)
        stream.XORKeyStream(encrypted[des.BlockSize:], str)
        return encrypted, nil
    }
    return nil, nil
}

// CFB Decrypt
func (cfb *cfbObj) Decrypt(str, key []byte) ([]byte, error) {
    P2E()
    block, err := cfb.getBlock(key)
    if err != nil {
        Error("["+cfb.cryptoType+"-CFB] ERROR:" +err.Error())
        return nil, err
    }

    iv := []byte{}
    if cfb.cryptoType == "aes" {
        if len(str) < aes.BlockSize {
            return nil, errors.New("ciphertext too short")
        }
        iv = str[:aes.BlockSize]
        str = str[aes.BlockSize:]
    }

    if cfb.cryptoType == "des" {
        if len(str) < des.BlockSize {
            return nil, errors.New("ciphertext too short")
        }
        iv = str[:des.BlockSize]
        str = str[des.BlockSize:]
    }

    stream := cipher.NewCFBDecrypter(block, iv)
    stream.XORKeyStream(str, str)
    return str, nil
}

AES&DES 支持的模式: CTR 计算器模式(Counter (CTR))

// 计算器模式(Counter (CTR))
type ctrObj struct {
    count []byte //指定计数器,长度必须等于block的块尺寸
    cryptoType string
}

func (ctr *ctrObj) getBlock(key []byte) (block cipher.Block, err error) {
    if ctr.cryptoType == "aes" {
        block, err = aes.NewCipher(key)
    }
    if ctr.cryptoType == "des" {
        block, err = des.NewCipher(key)
        if len(ctr.count) > des.BlockSize {
            ctr.count = ctr.count[0:des.BlockSize]
        }
    }
    return
}

// CTR Encrypt
func (ctr *ctrObj) Encrypt(str, key []byte) ([]byte, error) {
    return ctr.crypto(str, key)
}

// CTR Decrypt
func (ctr *ctrObj) Decrypt(str, key []byte) ([]byte, error) {
    return ctr.crypto(str, key)
}

func (ctr *ctrObj) crypto(str, key []byte) ([]byte, error) {
    P2E()
    block,err:=ctr.getBlock(key)
    if err != nil {
        Error("[AES-CTR] ERROR:" +err.Error())
        return []byte(""), err
    }
    //指定分组模式
    blockMode:=cipher.NewCTR(block, ctr.count)
    //执行加密、解密操作
    res:=make([]byte,len(str))
    blockMode.XORKeyStream(res,str)
    //返回明文或密文
    return res, nil
}

AES&DES 支持的模式: OFB : 输出反馈模式(Output FeedBack (OFB))

// 输出反馈模式(Output FeedBack (OFB))
type ofbObj struct {}

Hmac 是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code),HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。

func hmacFunc(h func() hash.Hash, str, key []byte) string {
    mac := hmac.New(h, key)
    mac.Write(str)
    res := base64.StdEncoding.EncodeToString(mac.Sum(nil))
    return res
}

// HmacMD5
func HmacMD5(str, key string) string {
    return hmacFunc(md5.New, []byte(str), []byte(key))
}

// HmacSHA1
func HmacSHA1(str, key string) string {
    return hmacFunc(sha1.New, []byte(str), []byte(key))
}

// HmacSHA256
func HmacSHA256(str, key string) string {
    return hmacFunc(sha256.New, []byte(str), []byte(key))
}

// HmacSHA512
func HmacSHA512(str, key string) string {
    return hmacFunc(sha512.New, []byte(str), []byte(key))
}

PBKDF2应用一个伪随机函数以导出密钥

func pbkdf2Func(h func() hash.Hash, str, salt []byte, iterations, keySize int) []byte {
    return pbkdf2.Key(str, salt, iterations, keySize, h)
}

// PBKDF2
func PBKDF2(str, salt []byte, iterations, keySize int) ([]byte) {
    return pbkdf2Func(sha256.New, str, salt, iterations, keySize)
}

JWT: JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简介的、自包含的协议格式,用于 在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。JWT可以使用HMAC算法或使用RSA的公 钥/私钥对来签名,防止被篡改。

// jwtEncrypt
func jwtEncrypt(token *jwt.Token, data map[string]interface{}, secret string) (string, error) {
    claims := make(jwt.MapClaims)
    for k, v := range data {
        claims[k] = v
    }
    token.Claims = claims
    return token.SignedString([]byte(secret))
}

// JwtEncrypt
func JwtEncrypt(data map[string]interface{}, secret, method string) (string, error){
    switch method {
    case "256":
        return jwtEncrypt(jwt.New(jwt.SigningMethodHS256), data, secret)
    case "384":
        return jwtEncrypt(jwt.New(jwt.SigningMethodHS384), data, secret)
    case "512":
        return jwtEncrypt(jwt.New(jwt.SigningMethodHS512), data, secret)
    }
    return "",fmt.Errorf("未知method; method= 256 or 384 or 512 ")
}

// JwtEncrypt256
func JwtEncrypt256(data map[string]interface{}, secret string) (string, error){
    token := jwt.New(jwt.SigningMethodHS256)
    return jwtEncrypt(token, data, secret)
}

// JwtEncrypt384
func JwtEncrypt384(data map[string]interface{}, secret string) (string, error){
    token := jwt.New(jwt.SigningMethodHS384)
    return jwtEncrypt(token, data, secret)
}

// JwtEncrypt512
func JwtEncrypt512(data map[string]interface{}, secret string) (string, error){
    token := jwt.New(jwt.SigningMethodHS512)
    return jwtEncrypt(token, data, secret)
}

// JwtDecrypt
func JwtDecrypt(tokenString, secret string) (data map[string]interface{}, err error) {
    data = make(map[string]interface{})
    var secretFunc = func() jwt.Keyfunc { //按照这样的规则解析
        return func(t *jwt.Token) (interface{}, error) {
            return []byte(secret), nil
        }
    }
    token, err := jwt.Parse(tokenString, secretFunc())
    if err != nil {
        err = fmt.Errorf("未知Token")
        return
    }
    claim, ok := token.Claims.(jwt.MapClaims)
    if !ok {
        return
    }
    if !token.Valid {
        // 令牌错误
        return
    }
    for k, v := range claim {
        data[k] =v
    }
    return
}

其它: Rabbit, RC4, RIPEMD-160, DSA, RSA

源码传送门

https://github.com/mangenotwork/gathertool/blob/main/crypto.go


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK