goldwarden/cli/browserbiometrics/crypto.go
2024-05-04 01:06:24 +02:00

119 lines
2.9 KiB
Go

package browserbiometrics
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"encoding/base64"
"errors"
"io"
)
var (
ErrInvalidBlockSize = errors.New("invalid blocksize")
ErrInvalidPKCS7Data = errors.New("invalid PKCS7 data (empty or not padded)")
ErrInvalidPKCS7Padding = errors.New("invalid padding on input")
)
func pkcs7Pad(b []byte, blocksize int) ([]byte, error) {
if blocksize <= 0 {
return nil, ErrInvalidBlockSize
}
if len(b) == 0 {
return nil, ErrInvalidPKCS7Data
}
n := blocksize - (len(b) % blocksize)
pb := make([]byte, len(b)+n)
copy(pb, b)
copy(pb[len(b):], bytes.Repeat([]byte{byte(n)}, n))
return pb, nil
}
func pkcs7Unpad(b []byte, blocksize int) ([]byte, error) {
if blocksize <= 0 {
return nil, ErrInvalidBlockSize
}
if len(b) == 0 {
return nil, ErrInvalidPKCS7Data
}
if len(b)%blocksize != 0 {
return nil, ErrInvalidPKCS7Padding
}
c := b[len(b)-1]
n := int(c)
if n == 0 || n > len(b) {
return nil, ErrInvalidPKCS7Padding
}
for i := 0; i < n; i++ {
if b[len(b)-n+i] != c {
return nil, ErrInvalidPKCS7Padding
}
}
return b[:len(b)-n], nil
}
func decryptStringSymmetric(key []byte, ivb64 string, data string) (string, error) {
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
iv, _ := base64.StdEncoding.DecodeString(ivb64)
ciphertext, _ := base64.StdEncoding.DecodeString(data)
bm := cipher.NewCBCDecrypter(block, iv)
bm.CryptBlocks(ciphertext, ciphertext)
ciphertext, _ = pkcs7Unpad(ciphertext, aes.BlockSize)
return string(ciphertext), nil
}
func encryptStringSymmetric(key []byte, data []byte) (EncryptedString, error) {
block, err := aes.NewCipher(key)
if err != nil {
return EncryptedString{}, err
}
data, _ = pkcs7Pad(data, block.BlockSize())
ciphertext := make([]byte, aes.BlockSize+len(data))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return EncryptedString{}, err
}
bm := cipher.NewCBCEncrypter(block, iv)
bm.CryptBlocks(ciphertext[aes.BlockSize:], data)
return EncryptedString{
IV: base64.StdEncoding.EncodeToString(ciphertext[:aes.BlockSize]),
Data: base64.StdEncoding.EncodeToString(ciphertext[aes.BlockSize:]),
EncType: 0,
}, nil
}
func generateTransportKey() ([]byte, error) {
key := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, key); err != nil {
return nil, err
}
return key, nil
}
func rsaEncrypt(keyB64 string, message []byte) (string, error) {
publicKey, err := base64.StdEncoding.DecodeString(keyB64)
if err != nil {
return "", err
}
test, err := x509.ParsePKIXPublicKey(publicKey)
if err != nil {
return "", err
}
rsatest := test.(*rsa.PublicKey)
oaepDigest := sha1.New()
ciphertext, _ := rsa.EncryptOAEP(oaepDigest, rand.Reader, rsatest, message, []byte{})
b64cipherText := base64.StdEncoding.EncodeToString(ciphertext)
return b64cipherText, nil
}