diff --git a/README.md b/README.md index f4fdf1d..affdf68 100644 --- a/README.md +++ b/README.md @@ -111,14 +111,13 @@ W efekcie, jeśli warunek jest spełniony, w katalogu wynikowym działania skryp ## Obsługa plików szyfrowanych -Od wersji 0.2.0 plik z hasłami (pgpass) musi być zaszyforwany. Szyfrowanie można wykonać następującym poleceniem +Od wersji 0.2.1 plik z hasłami (pgpass) musi być zaszyforwany. Szyfrowanie można wykonać następującym poleceniem: ```sh -multisql -P encrypt pgpass.sec pgpass +multisql encrypt pgpass.sec pgpass ``` -Jeśli nie jest ustawiona zmienna środowiskowa MULTISQLPASS, to opcja -P powoduje, że program zapyta o hasło -a następnie zaszyfruje treść pliku pgpass i zapisze go do pliku pgpass.sec. +Program zapyta o nowe hasło a następnie zaszyfruje treść pliku pgpass i zapisze go do pliku pgpass.sec. > Uwaga: plik pgpass.sec zostanie napisany bez pytania. @@ -132,7 +131,10 @@ multisql -P decrypt pgpass.sec # po udanym odszyfrowaniu wyświetli treść pli multisql -P decryp pgpass.sec newpgpass # w tym wariancie odszyfrowana treść zostanie zapisana do newpgpass ``` -Żeby nie podawać hasła z klawiatury, należy ustawić je w zmiennej środowiskowej: +Opcja `-P` powoduje, że program pyta o hasło. Jeśli nie podano tej opcji, program +próbuje użyć hasła ustawionego w zmiennej środowiskowej `MULTISQLPASS`. + +Zmienną można ustawić w następujący sposób: Linux: @@ -152,6 +154,4 @@ Windows, powershell: $env:MULTISQLPASS = "abc" ``` -Program nigdy nie pyta o hasła, jeśli wczytał je ze zmiennej środowiskowej. -Jeśli nie podano hasła w zmiennej i nie podano -opcji `-P`, to program przerwie działanie. +Użycie opcji `-P` powoduje, że zmienna środowiskowa jest ignorowana. diff --git a/cfg/params.go b/cfg/params.go index 883068b..ef504d2 100644 --- a/cfg/params.go +++ b/cfg/params.go @@ -66,7 +66,7 @@ Użycie: multisql -outdir /tmp -sqldir /data/skrypty -passfile ./hasla Użycie w trybie szyfrowania: - multisql [-P] encrypt plik.wynikowy.zaszyfrowany plik.zródłowy + multisql encrypt plik.wynikowy.zaszyfrowany plik.zródłowy lub multisql [-P] decrypt plik.źródłowy.zaszyfrowany [plik.wynikowy.jawny] diff --git a/cmd/multisql/multisql.go b/cmd/multisql/multisql.go index 47ebb8b..f862f3d 100644 --- a/cmd/multisql/multisql.go +++ b/cmd/multisql/multisql.go @@ -72,8 +72,6 @@ func main() { } func encryption(args []string, params cfg.Parameters) { - password := pass.GetMasterPass(params.AskPass) - switch strings.ToLower(args[0]) { case "encrypt": if len(args) < 3 { @@ -84,6 +82,9 @@ func encryption(args []string, params cfg.Parameters) { if err != nil { log.Fatalf("Błąd odczytu pliku: %v", err) } + + password := pass.EnterMasterPass() + err = pass.EncryptFile(password, args[1], plain) if err != nil { log.Fatalf("Błąd szyfrowania pliku: %v", err) @@ -93,6 +94,8 @@ func encryption(args []string, params cfg.Parameters) { log.Fatal("decryp wymaga podania pliku zaszyfrowanego") return } + password := pass.GetMasterPass(params.AskPass) + data, err := pass.DecryptFile(password, args[1]) if err !=nil { log.Fatalf("Błąd deszyfrowania pliku: %v", err) diff --git a/go.mod b/go.mod index 4bd73de..112e615 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,9 @@ module baal.ar76.eu/x/pub/multisql go 1.19 -require golang.org/x/crypto v0.3.0 // indirect +require ( + golang.org/x/crypto v0.3.0 + golang.org/x/term v0.2.0 +) + +require golang.org/x/sys v0.2.0 // indirect diff --git a/go.sum b/go.sum index f747132..c907071 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,6 @@ golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= diff --git a/pass/crypt.go b/pass/crypt.go index 435d733..9c39588 100644 --- a/pass/crypt.go +++ b/pass/crypt.go @@ -5,10 +5,8 @@ import ( "crypto/cipher" "crypto/rand" "fmt" - "log" "os" - "baal.ar76.eu/x/pub/multisql/cfg" "golang.org/x/crypto/scrypt" ) @@ -70,22 +68,22 @@ func Decrypt(key, data []byte) ([]byte, error) { return plaintext, nil } -func DecryptFile(password, file string) ([]byte, error) { +func DecryptFile(password []byte, 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) + key, _, err := DeriveKey(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) +func EncryptFile(password []byte, file string, data []byte) error { + key, salt, err := DeriveKey(password, nil) if err != nil { return err } @@ -108,17 +106,4 @@ func EncryptFile(password, file string, data []byte) error { 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 -} + diff --git a/pass/pass.go b/pass/pass.go index 4e6749e..42d7962 100644 --- a/pass/pass.go +++ b/pass/pass.go @@ -18,7 +18,7 @@ type PassDb struct { cache map[string]*pgpassrow } -func Load(file string, master string) (*PassDb, error) { +func Load(file string, master []byte) (*PassDb, error) { data, err := DecryptFile(master, file) if err != nil { diff --git a/pass/term.go b/pass/term.go new file mode 100644 index 0000000..9d396e5 --- /dev/null +++ b/pass/term.go @@ -0,0 +1,55 @@ +package pass + +import ( + "bytes" + "fmt" + "log" + "os" + + "baal.ar76.eu/x/pub/multisql/cfg" + "golang.org/x/term" +) + +func GetMasterPass(askPass bool) []byte { + if askPass { + res, err := termGetPassword("Podaj hasło") + if err != nil { + log.Fatalln("Nie udało się wczytać hasła z konsoli") + } + return res + } + password := os.Getenv(cfg.MULTISQLPASS) + + if password != "" { + return []byte(password) + } + + log.Fatalf("Nieustalone hasło. Użyj flagi -P lub ustaw hasło w zmiennej %s", cfg.MULTISQLPASS) + return nil +} + +func EnterMasterPass() []byte { + p1, err := termGetPassword("Podaj nowe hasło (min 8 znaków)") + if err != nil { + log.Fatalf("Błąd wczytywania hasła: %v", err) + } + if len(p1) < 8 { + log.Fatalf("podano zbyt krótkie hasło") + } + p2, err := termGetPassword("Powtórz nowe hasło") + if err != nil { + log.Fatalf("Błąd wczytywania hasła: %v", err) + } + if !bytes.Equal(p1, p2) { + log.Fatalf("podane hasła są różne") + } + + return p1 +} + +func termGetPassword(prompt string) ([]byte, error) { + fmt.Fprintf(os.Stderr, "%s: ", prompt) + passwd, err := term.ReadPassword(int(os.Stdin.Fd())) + fmt.Fprintln(os.Stderr) + return passwd, err +}