aes - skynocover/Wiki-for-GoLang GitHub Wiki

AES

Base

  • Key: 32
  • IV: 16

Code

// AES+XOR加密
package encoding

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/sha256"
	"errors"
	"fmt"
	"strconv"
	"time"
)

// Taes 結構體
type Taes struct {
	key       []byte //AES的key
	iv        []byte //AES的iv
	Plaintext []byte //尚未加密的資料
	Blacktext []byte //具有XOR過的key,data,iv的RawData
}

// XOR 工具,一般用不到
func (taes *Taes) XOR(input []byte, key []byte) []byte {
	output := make([]byte, len(input))
	for i := range input {
		output[i] = input[i] ^ key[i%len(key)]
	}
	return output
}

// Init 產生key及iv
func (taes *Taes) Init() {
	time := time.Now().UnixNano()
	sum := sha256.Sum256([]byte(strconv.FormatInt(time, 10)))
	checksum := fmt.Sprintf("%x", sum)

	taes.key = []byte(checksum[:32])
	taes.iv = []byte(checksum[32:48])
}

// GenKey 單純產生key
func GenKey() []byte {
	time := time.Now().UnixNano()
	sum := sha256.Sum256([]byte(strconv.FormatInt(time, 10)))
	checksum := fmt.Sprintf("%x", sum)

	return []byte(checksum[:32])
}

// GenIV 單純產生IV
func GenIV() []byte {
	time := time.Now().UnixNano()
	sum := sha256.Sum256([]byte(strconv.FormatInt(time, 10)))
	checksum := fmt.Sprintf("%x", sum)

	return []byte(checksum[:16])
}

// Decrypt 解密用
//
// 如果長度<48會報錯,因為key+iv長度就48
func (taes *Taes) Decrypt() ([]byte, error) {
	if len(taes.Blacktext) < 48 {
		return nil, errors.New("The Decrypt input is wrong")
	}

	key := taes.Blacktext[:32]
	data := taes.Blacktext[32 : len(taes.Blacktext)-16]
	taes.iv = taes.Blacktext[len(taes.Blacktext)-16:]

	taes.key = taes.XOR(key, taes.iv)

	return AesDecryptCFB(taes.XOR(data, taes.key), taes.key, taes.iv), nil
}

// Encrypt 加密用
//
// 明碼Plaintext必須直接設定
// eg: (&ase.Taes{Plaintext: msg}).Encrypt()
//
// 加密過的資料回被key XOR
// key會被iv XOR
func (taes *Taes) Encrypt() (result []byte) {
	taes.Init()
	aesdata := AesEncryptCFB(taes.Plaintext, taes.key, taes.iv)

	newkey := taes.XOR(taes.key, taes.iv)
	newdata := taes.XOR(aesdata, taes.key)

	result = append(newkey, newdata...)
	result = append(result, taes.iv...)
	return
}

////////////////////////////////////////////////////////

// IVEncrypt 加密後加入IV
func IVEncrypt(origData []byte, key []byte) (encrypted []byte, err error) {
	var block cipher.Block
	block, err = aes.NewCipher(key)
	if err != nil {
		return
	}
	iv := GenIV()

	encrypted = make([]byte, len(origData))
	stream := cipher.NewCFBEncrypter(block, iv)
	stream.XORKeyStream(encrypted[:], origData)
	encrypted = append(iv, encrypted...)
	return encrypted, nil
}

// IVDecrypt 解開IV後解密
func IVDecrypt(encrypted []byte, key []byte) (decrypted []byte, err error) {
	if len(encrypted) < 16 {
		err = errors.New("encrypted too short")
		return
	}
	iv := encrypted[:16]
	encrypted = encrypted[16:]
	var block cipher.Block
	block, err = aes.NewCipher(key)
	if err != nil {
		return
	}
	if len(encrypted) < 0 {
		err = errors.New("ciphertext too short")
		return
	}

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

////////////////////////////////////////////////////////

// AesEncryptCFB 傳統加密
func AesEncryptCFB(origData []byte, key []byte, iv []byte) (encrypted []byte) {
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}
	/*
		encrypted = make([]byte, aes.BlockSize+len(origData))
		stream := cipher.NewCFBEncrypter(block, iv)
		stream.XORKeyStream(encrypted[aes.BlockSize:], origData)
	*/
	encrypted = make([]byte, len(origData))
	stream := cipher.NewCFBEncrypter(block, iv)
	stream.XORKeyStream(encrypted[:], origData)
	return encrypted
}

// AesDecryptCFB 傳統解密
func AesDecryptCFB(encrypted []byte, key []byte, iv []byte) (decrypted []byte) {
	/*
		block, _ := aes.NewCipher(key)
		if len(encrypted) < aes.BlockSize {
			panic("ciphertext too short")
		}
		encrypted = encrypted[aes.BlockSize:]

		stream := cipher.NewCFBDecrypter(block, iv)
		stream.XORKeyStream(encrypted, encrypted)
	*/
	block, _ := aes.NewCipher(key)
	if len(encrypted) < 0 {
		panic("ciphertext too short")
	}
	encrypted = encrypted[0:]

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