摘要

在项目开发过程中,当操作一些用户的隐私信息,诸如密码,帐户密钥等数据时,往往需要加密后可以在网上传输.这时,需要一些高效地,简单易用的加密算法加密数据,然后把加密后的数据存入数据库或进行其他操作;当需要读取数据时,把加密后的数据取出来,再通过算法解密.

1. 关于加密解密

当前我们项目中常用的加解密的方式无非三种.

  • 对称加密, 加解密都使用的是同一个密钥, 其中的代表就是AES,DES
  • 非对加解密, 加解密使用不同的密钥, 其中的代表就是RSA
  • 签名算法, 如MD5,SHA1,HMAC等, 主要用于验证,防止信息被修改, 如:文件校验,数字签名,鉴权协议

1.1. Base64不是加密算法

它是一种数据编码方式,虽然是可逆的,但是它的编码方式是公开的,无所谓加密.本文也对Base64编码方式做了简要介绍.

2. AES

AES,即高级加密标准(Advanced Encryption Standard),是一个对称分组密码算法,旨在取代DES成为广泛使用的标准.AES中常见的有三种解决方案,分别为AES-128,AES-192和AES-256. AES加密过程涉及到4种操作:字节替代(SubBytes),行移位(ShiftRows),列混淆(MixColumns)和轮密钥加(AddRoundKey).解密过程分别为对应的逆操作.由于每一步操作都是可逆的,按照相反的顺序进行解密即可恢复明文.加解密中每轮的密钥分别由初始密钥扩展得到.算法中16字节的明文,密文和轮密钥都以一个4x4的矩阵表示. AES 有五种加密模式:电码本模式(Electronic Codebook Book (ECB)),密码分组链接模式(Cipher Block Chaining (CBC)),计算器模式(Counter (CTR)),密码反馈模式(Cipher FeedBack (CFB))和输出反馈模式(Output FeedBack (OFB))

import (
    "bytes"
    "crypto/aes"
    "fmt"
    "crypto/cipher"
    "encoding/base64"
)

func main() {
    orig := "hello world"
    key := "123456781234567812345678"
    fmt.Println("原文:", orig)

    encryptCode := AesEncrypt(orig, key)
    fmt.Println("密文:" , encryptCode)

    decryptCode := AesDecrypt(encryptCode, key)
    fmt.Println("解密结果:", decryptCode)
}

func AesEncrypt(orig string, key string) string {
    // 转成字节数组
    origData := []byte(orig)
    k := []byte(key)

	// 分组秘钥
	block, err := aes.NewCipher(k)
	if err != nil {
		panic(fmt.Sprintf("key 长度必须 16/24/32长度: %s", err.Error()))
	}
    // 获取秘钥块的长度
    blockSize := block.BlockSize()
    // 补全码
    origData = PKCS7Padding(origData, blockSize)
    // 加密模式
    blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
    // 创建数组
    cryted := make([]byte, len(origData))
    // 加密
    blockMode.CryptBlocks(cryted, origData)
    //使用RawURLEncoding 不要使用StdEncoding
    //不要使用StdEncoding  放在url参数中回导致错误
    return base64.RawURLEncoding.EncodeToString(cryted)

}

func AesDecrypt(cryted string, key string) string {
    //使用RawURLEncoding 不要使用StdEncoding
    //不要使用StdEncoding  放在url参数中回导致错误
    crytedByte, _ := base64.RawURLEncoding.DecodeString(cryted)
    k := []byte(key)

	// 分组秘钥
	block, err := aes.NewCipher(k)
	if err != nil {
		panic(fmt.Sprintf("key 长度必须 16/24/32长度: %s", err.Error()))
	}
    // 获取秘钥块的长度
    blockSize := block.