You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Cloak/internal/common/crypto.go

98 lines
2.0 KiB
Go

package common
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"errors"
"io"
"math/big"
"time"
log "github.com/sirupsen/logrus"
)
func AESGCMEncrypt(nonce []byte, key []byte, plaintext []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(nonce) != aesgcm.NonceSize() {
// check here so it doesn't panic
return nil, errors.New("incorrect nonce size")
}
return aesgcm.Seal(nil, nonce, plaintext, nil), nil
}
func AESGCMDecrypt(nonce []byte, key []byte, ciphertext []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(nonce) != aesgcm.NonceSize() {
// check here so it doesn't panic
return nil, errors.New("incorrect nonce size")
}
plain, err := aesgcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, err
}
return plain, nil
}
func CryptoRandRead(buf []byte) {
RandRead(rand.Reader, buf)
}
func backoff(f func() error) {
err := f()
if err == nil {
return
}
waitDur := [10]time.Duration{5 * time.Millisecond, 10 * time.Millisecond, 30 * time.Millisecond, 50 * time.Millisecond,
100 * time.Millisecond, 300 * time.Millisecond, 500 * time.Millisecond, 1 * time.Second,
3 * time.Second, 5 * time.Second}
for i := 0; i < 10; i++ {
log.Errorf("Failed to get random: %v. Retrying...", err)
err = f()
if err == nil {
return
}
time.Sleep(waitDur[i])
}
log.Fatal("Cannot get random after 10 retries")
}
func RandRead(randSource io.Reader, buf []byte) {
backoff(func() error {
_, err := randSource.Read(buf)
return err
})
}
func RandItem[T any](list []T) T {
return list[RandInt(len(list))]
}
func RandInt(n int) int {
s := new(int)
backoff(func() error {
size, err := rand.Int(rand.Reader, big.NewInt(int64(n)))
if err != nil {
return err
}
*s = int(size.Int64())
return nil
})
return *s
}