feat: Poprawiona obsługa hasła z klawiatury
This commit is contained in:
		
							
								
								
									
										16
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								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
 | 
					## 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
 | 
					```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
 | 
					Program zapyta o nowe hasło a następnie zaszyfruje treść pliku pgpass i zapisze go do pliku pgpass.sec.
 | 
				
			||||||
a następnie zaszyfruje treść pliku pgpass i zapisze go do pliku pgpass.sec.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
> Uwaga: plik pgpass.sec zostanie napisany bez pytania.
 | 
					> 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
 | 
					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:
 | 
					Linux:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -152,6 +154,4 @@ Windows, powershell:
 | 
				
			|||||||
$env:MULTISQLPASS = "abc"
 | 
					$env:MULTISQLPASS = "abc"
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Program nigdy nie pyta o hasła, jeśli wczytał je ze zmiennej środowiskowej.
 | 
					Użycie opcji `-P` powoduje, że zmienna środowiskowa jest ignorowana.
 | 
				
			||||||
Jeśli nie podano hasła w zmiennej i nie podano
 | 
					 | 
				
			||||||
opcji `-P`, to program przerwie działanie.
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,7 +66,7 @@ Użycie:
 | 
				
			|||||||
		multisql -outdir /tmp -sqldir /data/skrypty -passfile ./hasla
 | 
							multisql -outdir /tmp -sqldir /data/skrypty -passfile ./hasla
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Użycie w trybie szyfrowania:
 | 
					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
 | 
						lub
 | 
				
			||||||
		multisql [-P] decrypt plik.źródłowy.zaszyfrowany [plik.wynikowy.jawny]
 | 
							multisql [-P] decrypt plik.źródłowy.zaszyfrowany [plik.wynikowy.jawny]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -72,8 +72,6 @@ func main() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func encryption(args []string, params cfg.Parameters) {
 | 
					func encryption(args []string, params cfg.Parameters) {
 | 
				
			||||||
	password := pass.GetMasterPass(params.AskPass)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch strings.ToLower(args[0]) {
 | 
						switch strings.ToLower(args[0]) {
 | 
				
			||||||
	case "encrypt":
 | 
						case "encrypt":
 | 
				
			||||||
		if len(args) < 3 {
 | 
							if len(args) < 3 {
 | 
				
			||||||
@@ -84,6 +82,9 @@ func encryption(args []string, params cfg.Parameters) {
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Fatalf("Błąd odczytu pliku: %v", err)
 | 
								log.Fatalf("Błąd odczytu pliku: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							password := pass.EnterMasterPass()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		err = pass.EncryptFile(password, args[1], plain)
 | 
							err = pass.EncryptFile(password, args[1], plain)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Fatalf("Błąd szyfrowania pliku: %v", err)
 | 
								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")
 | 
								log.Fatal("decryp wymaga podania pliku zaszyfrowanego")
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							password := pass.GetMasterPass(params.AskPass)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		data, err := pass.DecryptFile(password, args[1])
 | 
							data, err := pass.DecryptFile(password, args[1])
 | 
				
			||||||
		if err !=nil {
 | 
							if err !=nil {
 | 
				
			||||||
			log.Fatalf("Błąd deszyfrowania pliku: %v", err)
 | 
								log.Fatalf("Błąd deszyfrowania pliku: %v", err)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								go.mod
									
									
									
									
									
								
							@@ -2,4 +2,9 @@ module baal.ar76.eu/x/pub/multisql
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
go 1.19
 | 
					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
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							@@ -1,2 +1,6 @@
 | 
				
			|||||||
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
 | 
					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/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=
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,8 @@ import (
 | 
				
			|||||||
	"crypto/cipher"
 | 
						"crypto/cipher"
 | 
				
			||||||
	"crypto/rand"
 | 
						"crypto/rand"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"log"
 | 
					 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"baal.ar76.eu/x/pub/multisql/cfg"
 | 
					 | 
				
			||||||
	"golang.org/x/crypto/scrypt"
 | 
						"golang.org/x/crypto/scrypt"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -70,22 +68,22 @@ func Decrypt(key, data []byte) ([]byte, error) {
 | 
				
			|||||||
	return plaintext, nil
 | 
						return plaintext, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func DecryptFile(password, file string) ([]byte, error) {
 | 
					func DecryptFile(password []byte, file string) ([]byte, error) {
 | 
				
			||||||
	data, err := os.ReadFile(file)
 | 
						data, err := os.ReadFile(file)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	salt := data[:32] //
 | 
						salt := data[:32] //
 | 
				
			||||||
	data = data[32:]
 | 
						data = data[32:]
 | 
				
			||||||
	key, _, err := DeriveKey([]byte(password), salt)
 | 
						key, _, err := DeriveKey(password, salt)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return Decrypt(key, data)
 | 
						return Decrypt(key, data)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func EncryptFile(password, file string, data []byte) error {
 | 
					func EncryptFile(password []byte, file string, data []byte) error {
 | 
				
			||||||
	key, salt, err := DeriveKey([]byte(password), nil)
 | 
						key, salt, err := DeriveKey(password, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -108,17 +106,4 @@ func EncryptFile(password, file string, data []byte) error {
 | 
				
			|||||||
	return fd.Close()
 | 
						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
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,7 @@ type PassDb struct {
 | 
				
			|||||||
	cache map[string]*pgpassrow
 | 
						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)
 | 
						data, err := DecryptFile(master, file)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										55
									
								
								pass/term.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								pass/term.go
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user