package generator import ( "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/hex" "errors" "io" ) const ( maxEncodeLen = 32 ) // KeyGenerator key generator type KeyGenerator struct { AESKey string } func encryptAESCFB(msg, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } ciphertext := make([]byte, aes.BlockSize+len(msg)) iv := ciphertext[:aes.BlockSize] if _, err := io.ReadFull(rand.Reader, iv); err != nil { return nil, err } stream := cipher.NewCFBEncrypter(block, iv) stream.XORKeyStream(ciphertext[aes.BlockSize:], msg) return ciphertext, nil } func decryptAESCFB(msg, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } if len(msg) < aes.BlockSize { return nil, errors.New("decrypt message too short") } iv := msg[:aes.BlockSize] msg = msg[aes.BlockSize:] stream := cipher.NewCFBDecrypter(block, iv) stream.XORKeyStream(msg, msg) return msg, nil } // NewKeyGenerator create a key generator func NewKeyGenerator(key string) (*KeyGenerator, error) { l := len(key) if l != 16 && l != 24 && l != 32 { return nil, errors.New("invalid aes key length, should be 16, 24 or 32 bytes") } return &KeyGenerator{ AESKey: key, }, nil } // GenRandomKey get random key func (g *KeyGenerator) GenRandomKey(id string) (string, error) { binkey, err := encryptAESCFB([]byte(id), []byte(g.AESKey)) if err != nil { return "", err } return hex.EncodeToString(binkey), nil } // DecodeIDFromRandomKey get id from encrypt strings func (g *KeyGenerator) DecodeIDFromRandomKey(encrypted string) (string, error) { buf, err := hex.DecodeString(encrypted) if err != nil { return "", err } raw, err := decryptAESCFB(buf, []byte(g.AESKey)) if err != nil { return "", err } return string(raw), nil }