package seks import ( "crypto/rand" "encoding/base64" "encoding/hex" "errors" "golang.org/x/crypto/nacl/box" "strings" ) func KeyGen() (string, string) { pub, priv, err := box.GenerateKey(rand.Reader) if err != nil { return "", "" } pubs := "public-key-" + hex.EncodeToString(pub[:]) privs := "SECRET-KEY-" + strings.ToUpper(hex.EncodeToString(priv[:])) return pubs, privs } func ReadKey(s string) ([32]byte, error) { s = strings.ToLower(s) s = strings.TrimPrefix(s, "public-key-") s = strings.TrimPrefix(s, "secret-key-") b, err := hex.DecodeString(s) if err != nil { return [32]byte{}, errors.New("invalid key") } return [32]byte(b[0:32]), nil } func ran() [24]byte { var b [24]byte _, err := rand.Reader.Read(b[:]) if err != nil { panic(err) } return b } const seksHeader = "-----BEGIN SOME ENCRYPTION KEY STUFF-----\n\n" const seksFooter = "\n------END SOME ENCRYPTION KEY STUFF------" func armour(b []byte) string { var s string s = base64.StdEncoding.EncodeToString(b) for i := 64; i < len(s); i += 64 { s = s[:i] + "\n" + s[i:] } return seksHeader + s + seksFooter } func unArmour(s string) ([]byte, error) { start := strings.Index(s, seksHeader) + len(seksHeader) end := strings.Index(s, seksFooter) s = s[start:end] s = strings.ReplaceAll(s, "\n", "") s = strings.ReplaceAll(s, " ", "") return base64.StdEncoding.DecodeString(s) } func EncryptString(data string, toPubKey string, fromPrivKey string) (string, error) { b, err := EncryptBytes([]byte(data), toPubKey, fromPrivKey) if err != nil { return "", err } return armour(b), nil } func EncryptArmour(b []byte, toPubKey string, fromPrivKey string) ([]byte, error) { b, err := EncryptBytes(b, toPubKey, fromPrivKey) if err != nil { return nil, err } return []byte(armour(b)), nil } func EncryptBytes(data []byte, toPubKey string, fromPrivKey string) ([]byte, error) { var nonce = ran() pubKey, err := ReadKey(toPubKey) if err != nil { return nil, err } privKey, err := ReadKey(fromPrivKey) if err != nil { return nil, err } var out []byte = nonce[:] return box.Seal(out, data, &nonce, &pubKey, &privKey), nil } func DecryptString(data string, fromPubKey string, toPrivKey string) (string, error) { b, err := unArmour(data) if err != nil { return "", err } out, err := DecryptBytes(b, fromPubKey, toPrivKey) if err != nil { return "", err } return string(out), nil } func DecryptBytes(data []byte, fromPubKey string, toPrivKey string) ([]byte, error) { nonce := [24]byte(data[0:24]) pubKey, err := ReadKey(fromPubKey) if err != nil { return nil, err } privKey, err := ReadKey(toPrivKey) if err != nil { return nil, err } out, ok := box.Open(nil, data[24:], &nonce, &pubKey, &privKey) if !ok { return nil, errors.New("decryption failed") } return out, nil } func DecryptArmour(data []byte, fromPubKey string, toPrivKey string) ([]byte, error) { b, err := unArmour(string(data)) if err != nil { return nil, err } out, err := DecryptBytes(b, fromPubKey, toPrivKey) if err != nil { return nil, err } return out, nil }