Implemented encryption (#2)

This commit is contained in:
Andreas Schneider 2018-04-06 20:09:52 +02:00
parent f3cf37bdb0
commit d78809c9ee
1 changed files with 80 additions and 7 deletions

View File

@ -1,10 +1,16 @@
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh/terminal"
"io"
"log"
"os"
"strings"
"syscall"
@ -24,6 +30,9 @@ type Settings struct {
}
}
const settingsName = "calanonsync.json"
const keyName = ".calanonsync.key"
func ensurePassword(password *string, name string) {
if *password != "" {
// Nothing to do. Password already set.
@ -41,7 +50,7 @@ func ensurePassword(password *string, name string) {
}
func LoadSettings() Settings {
f, err := os.Open("calanonsync.json")
f, err := os.Open(settingsName)
if err != nil {
panic(err)
}
@ -74,19 +83,83 @@ func InitSettingsCmd() *cobra.Command {
not empty. It will generate a new "master" password and store that alongside
the settings file. This is NOT secure, it just helps to prevent
over-the-shoulder "attacks".`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Encrypt")
},
Run: runSettingsEncryption,
}
decryptCmd := &cobra.Command{
Use: "decrypt",
Short: "Decrypt a previously encrypted settings file.",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Decrypt")
},
Run: runSettingsDecryption,
}
settingsCmd.AddCommand(encryptCmd, decryptCmd)
return settingsCmd
}
func runSettingsEncryption(cmd *cobra.Command, args []string) {
s := LoadSettings()
if _, err := os.Stat(keyName); err == nil || os.IsExist(err) {
log.Fatalln("Cannot encrypt an (apparently) already encrypted settings file. If this is an error, please remove .calanonsync.key and try again.")
}
// Generate a secure 256 bit key.
key := make([]byte, 32)
if n, err := rand.Read(key); n != 32 || err != nil {
log.Fatalf("Could not get random 256 bit key: %s (%d)\n", err, n)
}
block, err := aes.NewCipher(key)
if err != nil {
log.Fatalf("Could not create cipher: %s\n", err)
}
doEncrypt := func(pwd *string) {
if *pwd != "" {
result := make([]byte, aes.BlockSize+len(*pwd))
// Prepare the initialization vector
iv := result[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(result[aes.BlockSize:], []byte(*pwd))
*pwd = base64.StdEncoding.EncodeToString(result)
}
}
doEncrypt(&s.EWS.Password)
doEncrypt(&s.CalDAV.Password)
if s.EWS.Password == "" && s.CalDAV.Password == "" {
log.Fatalf("No passwords found. Nothing to encrypt.")
}
// Rewrite the settings file.
f, err := os.OpenFile(settingsName, os.O_WRONLY|os.O_TRUNC, 0600)
if err != nil {
log.Fatalf("Could not rewrite settings: %s\n", err)
}
defer f.Close()
e := json.NewEncoder(f)
e.SetIndent("", " ")
err = e.Encode(&s)
if err != nil {
panic(err)
}
f, err = os.OpenFile(keyName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
if err != nil {
log.Fatalf("Could not write keyfile: %s\n", err)
}
defer f.Close()
ks := base64.StdEncoding.EncodeToString(key)
_, err = f.WriteString(ks)
if err != nil {
panic(err)
}
}
func runSettingsDecryption(cmd *cobra.Command, args []string) {
fmt.Println("Decrypt")
}