xframe/base/codec/aes.go

115 lines
2.8 KiB
Go
Executable File

package codec
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"io"
"git.wishpal.cn/wishpal_ironfan/xframe/component/logger"
)
// CfbDecrypt decrypts src with the given key.
func CfbDecrypt(cipherText string, key string) (plainText string, err error) {
if len(cipherText) == 0 || len(cipherText) < 6 || cipherText[:6] != "crypt-" {
err = errors.New("illegal ciphertext")
return
}
cipherText = string(cipherText[6:])
var block cipher.Block
keyBytes := hashBytes(key)
cipherTextBytes, _ := hex.DecodeString(cipherText)
block, err = aes.NewCipher(keyBytes)
if err != nil {
return
}
if len(cipherTextBytes) < aes.BlockSize {
err = errors.New("ciphertext too short")
return
}
iv := cipherTextBytes[:aes.BlockSize]
cipherTextBytes = cipherTextBytes[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
plainTextBytes := make([]byte, len(cipherTextBytes))
stream.XORKeyStream(plainTextBytes, cipherTextBytes)
plainText = string(plainTextBytes)
return
}
// CbcEncrypt encrypts dat with the given key.
func CbcEncrypt(key []byte, dat []byte, fixed bool) ([]byte, error) {
res := cbcPadding(dat, fixed)
iv := res[:aes.BlockSize]
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
buf := res[aes.BlockSize:]
cipher.NewCBCEncrypter(block, iv).CryptBlocks(buf, buf)
return res, nil
}
// CbcDecrypt decrypts dat with the given key.
func CbcDecrypt(key, dat []byte) ([]byte, error) {
if len(dat) < aes.BlockSize*2 {
return nil, fmt.Errorf("invalid dat")
}
iv := dat[:aes.BlockSize]
padNum := int(iv[1])
if padNum <= 0 || padNum > aes.BlockSize {
return nil, fmt.Errorf("invalid dat")
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
res := make([]byte, len(dat)-aes.BlockSize)
decrypt := cipher.NewCBCDecrypter(block, iv)
if len(dat[aes.BlockSize:])%decrypt.BlockSize() != 0 {
logger.Warnf("decrypt_post_data, key: %v, data: %v", base64.StdEncoding.EncodeToString(key),
base64.StdEncoding.EncodeToString(dat))
return nil, fmt.Errorf("crypto/cipher: input not full blocks")
}
decrypt.CryptBlocks(res, dat[aes.BlockSize:])
return res[padNum:], nil
}
func cbcPadding(dat []byte, fixed bool) []byte {
padNum := aes.BlockSize - (len(dat) % aes.BlockSize)
//iv+padding+dat
res := make([]byte, aes.BlockSize+padNum+len(dat))
iv := res[:aes.BlockSize]
if !fixed {
io.ReadFull(rand.Reader, iv)
}
iv[1] = byte(padNum)
padding := res[aes.BlockSize : aes.BlockSize+padNum]
if !fixed {
io.ReadFull(rand.Reader, padding)
}
copy(res[aes.BlockSize+padNum:], dat)
return res
}
func hashBytes(key string) (hash []byte) {
h := sha1.New()
io.WriteString(h, key)
hashStr := hex.EncodeToString(h.Sum(nil))
hash = []byte(hashStr)[:32]
return
}