diff options
| author | Dave Henderson <dhenderson@gmail.com> | 2024-01-25 20:11:31 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-25 20:11:31 -0500 |
| commit | ebb97fb7367fb983cffc1935a8fb57e4b80f5249 (patch) | |
| tree | 43ef6cd01f629f60f59efe1e5b003f7c8e3a1257 /internal/funcs/crypto.go | |
| parent | f1d9158ea99abbe556251c1ff2fe970f3b460ee9 (diff) | |
Move funcs package to internal (#1977)
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
Diffstat (limited to 'internal/funcs/crypto.go')
| -rw-r--r-- | internal/funcs/crypto.go | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/internal/funcs/crypto.go b/internal/funcs/crypto.go new file mode 100644 index 00000000..e3628fad --- /dev/null +++ b/internal/funcs/crypto.go @@ -0,0 +1,399 @@ +package funcs + +import ( + "context" + gcrypto "crypto" + "crypto/elliptic" + "crypto/sha1" //nolint: gosec + "crypto/sha256" + "crypto/sha512" + "encoding/base64" + "encoding/hex" + "fmt" + "strings" + "unicode/utf8" + + "golang.org/x/crypto/bcrypt" + + "github.com/hairyhenderson/gomplate/v4/conv" + "github.com/hairyhenderson/gomplate/v4/crypto" +) + +// CryptoNS - the crypto namespace +// +// Deprecated: don't use +func CryptoNS() *CryptoFuncs { + return &CryptoFuncs{} +} + +// AddCryptoFuncs - +// +// Deprecated: use [CreateCryptoFuncs] instead +func AddCryptoFuncs(f map[string]interface{}) { + for k, v := range CreateCryptoFuncs(context.Background()) { + f[k] = v + } +} + +// CreateCryptoFuncs - +func CreateCryptoFuncs(ctx context.Context) map[string]interface{} { + f := map[string]interface{}{} + + ns := &CryptoFuncs{ctx} + + f["crypto"] = func() interface{} { return ns } + return f +} + +// CryptoFuncs - +type CryptoFuncs struct { + ctx context.Context +} + +// PBKDF2 - Run the Password-Based Key Derivation Function #2 as defined in +// RFC 2898 (PKCS #5 v2.0). This function outputs the binary result in hex +// format. +func (CryptoFuncs) PBKDF2(password, salt, iter, keylen interface{}, hashFunc ...string) (k string, err error) { + var h gcrypto.Hash + if len(hashFunc) == 0 { + h = gcrypto.SHA1 + } else { + h, err = crypto.StrToHash(hashFunc[0]) + if err != nil { + return "", err + } + } + pw := toBytes(password) + s := toBytes(salt) + i := conv.ToInt(iter) + kl := conv.ToInt(keylen) + + dk, err := crypto.PBKDF2(pw, s, i, kl, h) + return fmt.Sprintf("%02x", dk), err +} + +// WPAPSK - Convert an ASCII passphrase to WPA PSK for a given SSID +func (f CryptoFuncs) WPAPSK(ssid, password interface{}) (string, error) { + return f.PBKDF2(password, ssid, 4096, 32) +} + +// SHA1 - Note: SHA-1 is cryptographically broken and should not be used for secure applications. +func (f CryptoFuncs) SHA1(input interface{}) string { + out, _ := f.SHA1Bytes(input) + return fmt.Sprintf("%02x", out) +} + +// SHA224 - +func (f CryptoFuncs) SHA224(input interface{}) string { + out, _ := f.SHA224Bytes(input) + return fmt.Sprintf("%02x", out) +} + +// SHA256 - +func (f CryptoFuncs) SHA256(input interface{}) string { + out, _ := f.SHA256Bytes(input) + return fmt.Sprintf("%02x", out) +} + +// SHA384 - +func (f CryptoFuncs) SHA384(input interface{}) string { + out, _ := f.SHA384Bytes(input) + return fmt.Sprintf("%02x", out) +} + +// SHA512 - +func (f CryptoFuncs) SHA512(input interface{}) string { + out, _ := f.SHA512Bytes(input) + return fmt.Sprintf("%02x", out) +} + +// SHA512_224 - +// +//nolint:revive,stylecheck +func (f CryptoFuncs) SHA512_224(input interface{}) string { + out, _ := f.SHA512_224Bytes(input) + return fmt.Sprintf("%02x", out) +} + +// SHA512_256 - +// +//nolint:revive,stylecheck +func (f CryptoFuncs) SHA512_256(input interface{}) string { + out, _ := f.SHA512_256Bytes(input) + return fmt.Sprintf("%02x", out) +} + +// SHA1 - Note: SHA-1 is cryptographically broken and should not be used for secure applications. +func (CryptoFuncs) SHA1Bytes(input interface{}) ([]byte, error) { + //nolint:gosec + b := sha1.Sum(toBytes(input)) + out := make([]byte, len(b)) + copy(out, b[:]) + return out, nil +} + +// SHA224 - +func (CryptoFuncs) SHA224Bytes(input interface{}) ([]byte, error) { + b := sha256.Sum224(toBytes(input)) + out := make([]byte, len(b)) + copy(out, b[:]) + return out, nil +} + +// SHA256 - +func (CryptoFuncs) SHA256Bytes(input interface{}) ([]byte, error) { + b := sha256.Sum256(toBytes(input)) + out := make([]byte, len(b)) + copy(out, b[:]) + return out, nil +} + +// SHA384 - +func (CryptoFuncs) SHA384Bytes(input interface{}) ([]byte, error) { + b := sha512.Sum384(toBytes(input)) + out := make([]byte, len(b)) + copy(out, b[:]) + return out, nil +} + +// SHA512 - +func (CryptoFuncs) SHA512Bytes(input interface{}) ([]byte, error) { + b := sha512.Sum512(toBytes(input)) + out := make([]byte, len(b)) + copy(out, b[:]) + return out, nil +} + +// SHA512_224 - +func (CryptoFuncs) SHA512_224Bytes(input interface{}) ([]byte, error) { + b := sha512.Sum512_224(toBytes(input)) + out := make([]byte, len(b)) + copy(out, b[:]) + return out, nil +} + +// SHA512_256 - +func (CryptoFuncs) SHA512_256Bytes(input interface{}) ([]byte, error) { + b := sha512.Sum512_256(toBytes(input)) + out := make([]byte, len(b)) + copy(out, b[:]) + return out, nil +} + +// Bcrypt - +func (CryptoFuncs) Bcrypt(args ...interface{}) (string, error) { + input := "" + cost := bcrypt.DefaultCost + if len(args) == 0 { + return "", fmt.Errorf("bcrypt requires at least an 'input' value") + } + if len(args) == 1 { + input = conv.ToString(args[0]) + } + if len(args) == 2 { + cost = conv.ToInt(args[0]) + input = conv.ToString(args[1]) + } + hash, err := bcrypt.GenerateFromPassword([]byte(input), cost) + return string(hash), err +} + +// RSAEncrypt - +// Experimental! +func (f *CryptoFuncs) RSAEncrypt(key string, in interface{}) ([]byte, error) { + if err := checkExperimental(f.ctx); err != nil { + return nil, err + } + msg := toBytes(in) + return crypto.RSAEncrypt(key, msg) +} + +// RSADecrypt - +// Experimental! +func (f *CryptoFuncs) RSADecrypt(key string, in []byte) (string, error) { + if err := checkExperimental(f.ctx); err != nil { + return "", err + } + out, err := crypto.RSADecrypt(key, in) + return string(out), err +} + +// RSADecryptBytes - +// Experimental! +func (f *CryptoFuncs) RSADecryptBytes(key string, in []byte) ([]byte, error) { + if err := checkExperimental(f.ctx); err != nil { + return nil, err + } + out, err := crypto.RSADecrypt(key, in) + return out, err +} + +// RSAGenerateKey - +// Experimental! +func (f *CryptoFuncs) RSAGenerateKey(args ...interface{}) (string, error) { + if err := checkExperimental(f.ctx); err != nil { + return "", err + } + bits := 4096 + if len(args) == 1 { + bits = conv.ToInt(args[0]) + } else if len(args) > 1 { + return "", fmt.Errorf("wrong number of args: want 0 or 1, got %d", len(args)) + } + out, err := crypto.RSAGenerateKey(bits) + return string(out), err +} + +// RSADerivePublicKey - +// Experimental! +func (f *CryptoFuncs) RSADerivePublicKey(privateKey string) (string, error) { + if err := checkExperimental(f.ctx); err != nil { + return "", err + } + out, err := crypto.RSADerivePublicKey([]byte(privateKey)) + return string(out), err +} + +// ECDSAGenerateKey - +// Experimental! +func (f *CryptoFuncs) ECDSAGenerateKey(args ...interface{}) (string, error) { + if err := checkExperimental(f.ctx); err != nil { + return "", err + } + + curve := elliptic.P256() + if len(args) == 1 { + c := conv.ToString(args[0]) + c = strings.ToUpper(c) + c = strings.ReplaceAll(c, "-", "") + var ok bool + curve, ok = crypto.Curves(c) + if !ok { + return "", fmt.Errorf("unknown curve: %s", c) + } + } else if len(args) > 1 { + return "", fmt.Errorf("wrong number of args: want 0 or 1, got %d", len(args)) + } + + out, err := crypto.ECDSAGenerateKey(curve) + return string(out), err +} + +// ECDSADerivePublicKey - +// Experimental! +func (f *CryptoFuncs) ECDSADerivePublicKey(privateKey string) (string, error) { + if err := checkExperimental(f.ctx); err != nil { + return "", err + } + + out, err := crypto.ECDSADerivePublicKey([]byte(privateKey)) + return string(out), err +} + +// Ed25519GenerateKey - +// Experimental! +func (f *CryptoFuncs) Ed25519GenerateKey() (string, error) { + if err := checkExperimental(f.ctx); err != nil { + return "", err + } + out, err := crypto.Ed25519GenerateKey() + return string(out), err +} + +// Ed25519GenerateKeyFromSeed - +// Experimental! +func (f *CryptoFuncs) Ed25519GenerateKeyFromSeed(encoding, seed string) (string, error) { + if err := checkExperimental(f.ctx); err != nil { + return "", err + } + if !utf8.ValidString(seed) { + return "", fmt.Errorf("given seed is not valid UTF-8") // Don't print out seed (private). + } + var seedB []byte + var err error + switch encoding { + case "base64": + seedB, err = base64.StdEncoding.DecodeString(seed) + case "hex": + seedB, err = hex.DecodeString(seed) + default: + return "", fmt.Errorf("invalid encoding given: %s - only 'hex' or 'base64' are valid options", encoding) + } + if err != nil { + return "", fmt.Errorf("could not decode given seed: %w", err) + } + out, err := crypto.Ed25519GenerateKeyFromSeed(seedB) + return string(out), err +} + +// Ed25519DerivePublicKey - +// Experimental! +func (f *CryptoFuncs) Ed25519DerivePublicKey(privateKey string) (string, error) { + if err := checkExperimental(f.ctx); err != nil { + return "", err + } + out, err := crypto.Ed25519DerivePublicKey([]byte(privateKey)) + return string(out), err +} + +// EncryptAES - +// Experimental! +func (f *CryptoFuncs) EncryptAES(key string, args ...interface{}) ([]byte, error) { + if err := checkExperimental(f.ctx); err != nil { + return nil, err + } + + k, msg, err := parseAESArgs(key, args...) + if err != nil { + return nil, err + } + + return crypto.EncryptAESCBC(k, msg) +} + +// DecryptAES - +// Experimental! +func (f *CryptoFuncs) DecryptAES(key string, args ...interface{}) (string, error) { + if err := checkExperimental(f.ctx); err != nil { + return "", err + } + + out, err := f.DecryptAESBytes(key, args...) + return conv.ToString(out), err +} + +// DecryptAESBytes - +// Experimental! +func (f *CryptoFuncs) DecryptAESBytes(key string, args ...interface{}) ([]byte, error) { + if err := checkExperimental(f.ctx); err != nil { + return nil, err + } + + k, msg, err := parseAESArgs(key, args...) + if err != nil { + return nil, err + } + + return crypto.DecryptAESCBC(k, msg) +} + +func parseAESArgs(key string, args ...interface{}) ([]byte, []byte, error) { + keyBits := 256 // default to AES-256-CBC + + var msg []byte + + switch len(args) { + case 1: + msg = toBytes(args[0]) + case 2: + keyBits = conv.ToInt(args[0]) + msg = toBytes(args[1]) + default: + return nil, nil, fmt.Errorf("wrong number of args: want 2 or 3, got %d", len(args)) + } + + k := make([]byte, keyBits/8) + copy(k, []byte(key)) + + return k, msg, nil +} |
