AES(Advanced Encryption Standard) 是一種對稱加密演算法,是比 DES 更好的對稱加密演算法類,
使用AES,在前后端之間傳送密碼等相關資料時,能簡單高效的提高安全性,
前端的 AES(javascript/typescript)
前端的加密庫一般用 crypto-js,crypto-js 支持很多加密和hash演算法,使用 AES演算法很簡單,
var CryptoJS = require("crypto-js");
var secretKey = "len16 secret key"
// Encrypt
var ciphertext = CryptoJS.AES.encrypt('mysqlpassword', secretKey).toString();
// Decrypt
var bytes = CryptoJS.AES.decrypt(ciphertext, secretKey);
var originalText = bytes.toString(CryptoJS.enc.Utf8);
console.log(originalText); // 'mysqlpassword'
注意:_secretKey_的長度是16或者16 的倍數,
后端的 AES (golang)
對于golang來說,標準庫中就有 AES 加密的演算法,
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"errors"
)
const sKey = "len16 secret key"
//pkcs7Padding 填充
func pkcs7Padding(data []byte, blockSize int) []byte {
//判斷缺少幾位長度,最少1,最多 blockSize
padding := blockSize - len(data)%blockSize
//補足位數,把切片[]byte{byte(padding)}復制padding個
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, padText...)
}
//pkcs7UnPadding 填充的反向操作
func pkcs7UnPadding(data []byte) ([]byte, error) {
length := len(data)
if length == 0 {
return nil, errors.New("加密字串錯誤!")
}
//獲取填充的個數
unPadding := int(data[length-1])
return data[:(length - unPadding)], nil
}
//AesEncrypt 加密
func AesEncrypt(data []byte) ([]byte, error) {
key := []byte(sKey)
//創建加密實體
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
//判斷加密塊的大小
blockSize := block.BlockSize()
//填充
encryptBytes := pkcs7Padding(data, blockSize)
//初始化加密資料接收切片
crypted := make([]byte, len(encryptBytes))
//使用cbc加密模式
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
//執行加密
blockMode.CryptBlocks(crypted, encryptBytes)
return crypted, nil
}
//AesDecrypt 解密
func AesDecrypt(data []byte) ([]byte, error) {
key := []byte(sKey)
//創建實體
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
//獲取塊的大小
blockSize := block.BlockSize()
//使用cbc
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
//初始化解密資料接收切片
crypted := make([]byte, len(data))
//執行解密
blockMode.CryptBlocks(crypted, data)
//去除填充
crypted, err = pkcs7UnPadding(crypted)
if err != nil {
return nil, err
}
return crypted, nil
}
測驗代碼如下:
import (
"encoding/base64"
"testing"
)
func TestCrypto(t *testing.T) {
s := []byte("mysqlpassword")
ss, err := AesEncrypt(s)
if err != nil {
t.Fatal(err)
}
mw := base64.StdEncoding.EncodeToString(ss)
t.Logf("加密后: %s\n", mw)
mwb, _ := base64.StdEncoding.DecodeString(mw)
s, err = AesDecrypt(mwb)
if err != nil {
t.Fatal(err)
}
t.Logf("解密后: %s\n", s)
}
AES 前后端互動
上面的示例,前端和后端分別運行沒有問題,
但是,前端加密,后端解密;或者后端加密,前端解密的時候,就會出現問題,
雖然同樣用的是 AES 加密演算法,上面加密和解密的程序在細節上還有些區別,
- golang在加密程序中使用了 pkcs7 來填充不足的位數,反之在解密時做了反向的填充操作,
- golang使用了CBC模式
補充:AES加密程序中一般有2種模式(ECB和CBC)
- ECB:電碼本模式(Electronic Codebook Book),將整個明文分成若干段相同的小段,然后對每一小段進行加密,
- CBC:密碼分組鏈接模式(Cipher Block Chaining),先將明文切分成若干小段,然后每一小段與初始塊或者上一段的密文段進行異或運算后,再與密鑰進行加密,
所以,將前端部分的加解密代碼封裝,改造如下:
const CryptoJS = require('crypto-js');
const sKey = CryptoJS.enc.Utf8.parse('len16 secret key');
export function EncryptAES(s: string): string {
// key 和 iv 使用同一個值
const encrypted = CryptoJS.AES.encrypt(s, sKey, {
iv: sKey,
mode: CryptoJS.mode.CBC, // CBC演算法
padding: CryptoJS.pad.Pkcs7, //使用pkcs7 進行padding 后端需要注意
});
return encrypted.toString();
}
export function DecryptAES(s: string): string {
// key 和 iv 使用同一個值
const decrypted = CryptoJS.AES.decrypt(s, sKey, {
iv: sKey,
mode: CryptoJS.mode.CBC, // CBC演算法
padding: CryptoJS.pad.Pkcs7, //使用pkcs7 進行padding 后端需要注意
});
return decrypted.toString(CryptoJS.enc.Utf8);
}
這樣改造之后,前端加密之后后端可以解密,后端加密之后,前端也可以解密,
總結
AES演算法的使用沒有什么難度,但是AES本身在加解密的程序中存在不同的引數,
因此,我們在不同的語言之間進行加解密時,一定要注意保持2種語言的AES演算法在使用時,用的是相同的引數,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/485094.html
標籤:Go
上一篇:對不起,我錯了,這代碼不好寫
