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)
|
|
|
|
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
|
|
}
|