package Seeder // THIS FILE IS ONLY USED FOR SEEDING DATA DURING DEVELOPMENT import ( "bytes" "crypto/aes" "crypto/cipher" "crypto/hmac" "crypto/rand" "crypto/rsa" "crypto/sha256" "encoding/base64" "fmt" "hash" "golang.org/x/crypto/pbkdf2" ) type aesKey struct { Key []byte Iv []byte } func (key aesKey) encode() string { return base64.StdEncoding.EncodeToString(key.Key) } // Appends padding. func pkcs7Padding(data []byte, blocklen int) ([]byte, error) { var ( padlen int = 1 pad []byte ) if blocklen <= 0 { return nil, fmt.Errorf("invalid blocklen %d", blocklen) } for ((len(data) + padlen) % blocklen) != 0 { padlen = padlen + 1 } pad = bytes.Repeat([]byte{byte(padlen)}, padlen) return append(data, pad...), nil } // pkcs7strip remove pkcs7 padding func pkcs7strip(data []byte, blockSize int) ([]byte, error) { var ( length int padLen int ref []byte ) length = len(data) if length == 0 { return nil, fmt.Errorf("pkcs7: Data is empty") } if (length % blockSize) != 0 { return nil, fmt.Errorf("pkcs7: Data is not block-aligned") } padLen = int(data[length-1]) ref = bytes.Repeat([]byte{byte(padLen)}, padLen) if padLen > blockSize || padLen == 0 || !bytes.HasSuffix(data, ref) { return nil, fmt.Errorf("pkcs7: Invalid padding") } return data[:length-padLen], nil } func GenerateAesKey() (aesKey, error) { var ( saltBytes []byte = []byte{} password []byte seed []byte iv []byte err error ) password = make([]byte, 64) _, err = rand.Read(password) if err != nil { return aesKey{}, err } seed = make([]byte, 64) _, err = rand.Read(seed) if err != nil { return aesKey{}, err } iv = make([]byte, 16) _, err = rand.Read(iv) if err != nil { return aesKey{}, err } return aesKey{ Key: pbkdf2.Key( password, saltBytes, 1000, 32, func() hash.Hash { return hmac.New(sha256.New, seed) }, ), Iv: iv, }, nil } func (key aesKey) AesEncrypt(plaintext []byte) ([]byte, error) { var ( bPlaintext []byte ciphertext []byte block cipher.Block err error ) bPlaintext, err = pkcs7Padding(plaintext, 16) block, err = aes.NewCipher(key.Key) if err != nil { return []byte{}, err } ciphertext = make([]byte, len(bPlaintext)) mode := cipher.NewCBCEncrypter(block, key.Iv) mode.CryptBlocks(ciphertext, bPlaintext) ciphertext = append(key.Iv, ciphertext...) return ciphertext, nil } func (key aesKey) AesDecrypt(ciphertext []byte) ([]byte, error) { var ( plaintext []byte iv []byte block cipher.Block err error ) iv = ciphertext[:aes.BlockSize] plaintext = ciphertext[aes.BlockSize:] block, err = aes.NewCipher(key.Key) if err != nil { return []byte{}, err } decMode := cipher.NewCBCDecrypter(block, iv) decMode.CryptBlocks(plaintext, plaintext) plaintext, err = pkcs7strip(plaintext, 16) if err != nil { return []byte{}, err } return plaintext, nil } // EncryptWithPublicKey encrypts data with public key func EncryptWithPublicKey(msg []byte, pub *rsa.PublicKey) []byte { var ( hash hash.Hash ) hash = sha256.New() ciphertext, err := rsa.EncryptOAEP(hash, rand.Reader, pub, msg, nil) if err != nil { panic(err) } return ciphertext } // DecryptWithPrivateKey decrypts data with private key func decryptWithPrivateKey(ciphertext []byte, priv *rsa.PrivateKey) ([]byte, error) { var ( hash hash.Hash plaintext []byte err error ) hash = sha256.New() plaintext, err = rsa.DecryptOAEP(hash, rand.Reader, priv, ciphertext, nil) if err != nil { return plaintext, err } return plaintext, nil }