Encrypted messaging app
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

193 lines
3.6 KiB

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
}