diff --git a/go.mod b/go.mod index 91bcfd6..4bd73de 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module baal.ar76.eu/x/pub/multisql go 1.19 + +require golang.org/x/crypto v0.3.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..f747132 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= diff --git a/pass/crypt.go b/pass/crypt.go new file mode 100644 index 0000000..435d733 --- /dev/null +++ b/pass/crypt.go @@ -0,0 +1,124 @@ +package pass + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "fmt" + "log" + "os" + + "baal.ar76.eu/x/pub/multisql/cfg" + "golang.org/x/crypto/scrypt" +) + +func DeriveKey(password, salt []byte) ([]byte, []byte, error) { + if salt == nil { + salt = make([]byte, 32) + if _, err := rand.Read(salt); err != nil { + return nil, nil, err + } + } + + key, err := scrypt.Key(password, salt, 32768, 8, 1, 32) + if err != nil { + return nil, nil, fmt.Errorf("błąd generowania klucza: %w", err) + } + + return key, salt, nil +} + +func Encrypt(key, data []byte) ([]byte, error) { + blockCipher, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(blockCipher) + if err != nil { + return nil, err + } + + nonce := make([]byte, gcm.NonceSize()) + if _, err = rand.Read(nonce); err != nil { + return nil, err + } + + ciphertext := gcm.Seal(nonce, nonce, data, nil) + + return ciphertext, nil +} + +func Decrypt(key, data []byte) ([]byte, error) { + blockCipher, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(blockCipher) + if err != nil { + return nil, err + } + + nonce, ciphertext := data[:gcm.NonceSize()], data[gcm.NonceSize():] + + plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + return nil, err + } + + return plaintext, nil +} + +func DecryptFile(password, file string) ([]byte, error) { + data, err := os.ReadFile(file) + if err != nil { + return nil, err + } + salt := data[:32] // + data = data[32:] + key, _, err := DeriveKey([]byte(password), salt) + if err != nil { + return nil, err + } + return Decrypt(key, data) +} + +func EncryptFile(password, file string, data []byte) error { + key, salt, err := DeriveKey([]byte(password), nil) + if err != nil { + return err + } + encrypted, err := Encrypt(key, data) + if err != nil { + return err + } + fd, err := os.Create(file) + if err != nil { + return err + } + _, err = fd.Write(salt) + if err != nil { + return err + } + _, err = fd.Write(encrypted) + if err != nil { + return err + } + return fd.Close() +} + +func GetMasterPass(askPass bool) string { + password := os.Getenv(cfg.MULTISQLPASS) + if password == "" { + if !askPass { + log.Fatalf("Nieustalone hasło. Użyj flagi -P lub ustaw hasło w zmiennej %s", cfg.MULTISQLPASS) + } + fmt.Fprintf(os.Stderr, "Podaj hasło: ") + n, e := fmt.Scanln(&password) + if n == 0 || e != nil { + log.Fatalln("Nie udało się wczytać hasła z konsoli") + } + } + return password +}