Skip to content

Commit

Permalink
add key derivation
Browse files Browse the repository at this point in the history
  • Loading branch information
Biptaste committed Jun 8, 2022
1 parent 34e3acd commit 3c9928d
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 35 deletions.
4 changes: 1 addition & 3 deletions actions/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,7 @@ func BackupActionHandler(ctx domain.ExecutionContext, backupFilesOpt *bool, back
return fmt.Errorf("Unable to create the encrypted file: %s\n", err)
}

aesKey := []byte(*key)
hmacKey := aesKey
err = utils.Encrypt(infile, outfile, aesKey, hmacKey)
err = utils.Encrypt(infile, outfile, []byte(*key))
if err != nil {
return fmt.Errorf("Unable to encrypt file: %s\n", err)
}
Expand Down
6 changes: 2 additions & 4 deletions actions/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,13 @@ func decrypt(encryptedFile string, decryptedFile string, key *string) error {
log.Fatal(err)
}

aesKey := []byte(*key)
hmacKey := aesKey
err = utils.Decrypt(infile, outfile, aesKey, hmacKey)
err = utils.Decrypt(infile, outfile, []byte(*key))
infile.Close()
outfile.Close()

if err != nil {
removeDecryptedFile(decryptedFile)
return fmt.Errorf("Unable to decrypt the file %s\n%s\n", decryptedFile, err)
return fmt.Errorf("Unable to decrypt the file %s\n%s\n", encryptedFile, err)
}
fmt.Printf("\n %s %s decrypted\n", color.GreenString("✓"), encryptedFile)

Expand Down
20 changes: 2 additions & 18 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,11 +294,9 @@ func main() {
backupDB := cmd.BoolOpt("db", false, "Indicates if DB will be backup")

outputFilename := cmd.StringOpt("o output", "", "Set the filename of the tar.gz")
key := cmd.StringOpt("k", "", "the encryption password (length must be 16, 24 or 32 characters for a key of 128, 192 or 256 bits)")
key := cmd.StringOpt("k", "", "the encryption password")

cmd.Action = func() {
checkKeyLength(key)

if *quiet == false {
backupFiles = nil
backupDB = nil
Expand All @@ -320,13 +318,11 @@ func main() {
restoreConfigFiles := cmd.BoolOpt("config-files", false, "Indicates if config files will be restored")
restoreFiles := cmd.BoolOpt("files", false, "Indicates if files will be restored")
restoreDB := cmd.BoolOpt("db", false, "Indicates if DB will be restored")
key := cmd.StringOpt("k", "", "the encryption password (length must be 16, 24 or 32 characters for a key of 128, 192 or 256 bits)")
key := cmd.StringOpt("k", "", "the encryption password")

file := cmd.StringArg("FILE", "", "A pliz backup file (tar.gz)")

cmd.Action = func() {
checkKeyLength(key)

if *quiet == false {
restoreConfigFiles = nil
restoreFiles = nil
Expand Down Expand Up @@ -428,15 +424,3 @@ func parseAndCheckConfig() {
return
}
}

func checkKeyLength(key *string) {
if key == nil {
return
}

length := len(*key)
if length != 16 && length != 24 && length != 32 {
fmt.Printf(" %s The key length must be 16, 24 or 32 \n", color.RedString("✗"))
cli.Exit(1)
}
}
75 changes: 65 additions & 10 deletions utils/crypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,30 @@ import (
"encoding/binary"
"errors"
"io"

"golang.org/x/crypto/scrypt"
)

// hmacSize must be less to BUFFER_SIZE
const BUFFER_SIZE int = 16 * 1024
const IV_SIZE int = 16
const SALT_SIZE int = 32
const V1 byte = 0x1
const hmacSize = sha512.Size

// ErrInvalidHMAC for authentication failure
var ErrInvalidHMAC = errors.New("Invalid HMAC")

// Encrypt the stream using the given AES-CTR and SHA512-HMAC key
func Encrypt(in io.Reader, out io.Writer, keyAes, keyHmac []byte) (err error) {
func Encrypt(in io.Reader, out io.Writer, key []byte) (err error) {
keyAes, saltAes, err := DeriveKey(key, nil)
if err != nil {
return err
}
keyHmac, saltHmac, err := DeriveKey(key, nil)
if err != nil {
return err
}

iv := make([]byte, IV_SIZE)
_, err = rand.Read(iv)
Expand All @@ -46,14 +57,22 @@ func Encrypt(in io.Reader, out io.Writer, keyAes, keyHmac []byte) (err error) {
// Version
_, err = out.Write([]byte{V1})
if err != nil {
return
return err
}

w := io.MultiWriter(out, HMAC)

_, err = w.Write(iv)
if err != nil {
return
return err
}
_, err = w.Write(saltAes)
if err != nil {
return err
}
_, err = w.Write(saltHmac)
if err != nil {
return err
}

buf := make([]byte, BUFFER_SIZE)
Expand Down Expand Up @@ -85,29 +104,49 @@ func Encrypt(in io.Reader, out io.Writer, keyAes, keyHmac []byte) (err error) {
// Decrypt the stream and verify HMAC using the given AES-CTR and SHA512-HMAC key
// Do not trust the out io.Writer contents until the function returns the result
// of validating the ending HMAC hash.
func Decrypt(in io.Reader, out io.Writer, keyAes, keyHmac []byte) (err error) {
func Decrypt(in io.Reader, out io.Writer, key []byte) (err error) {

// Read version (up to 0-255)
var version int8
err = binary.Read(in, binary.LittleEndian, &version)
if err != nil {
return
return err
}

iv := make([]byte, IV_SIZE)
_, err = io.ReadFull(in, iv)
if err != nil {
return
return err
}
saltAes := make([]byte, SALT_SIZE)
_, err = io.ReadFull(in, saltAes)
if err != nil {
return err
}
saltHmac := make([]byte, SALT_SIZE)
_, err = io.ReadFull(in, saltHmac)
if err != nil {
return err
}
keyAes, _, err := DeriveKey(key, saltAes)
if err != nil {
return err
}
keyHmac, _, err := DeriveKey(key, saltHmac)
if err != nil {
return err
}

AES, err := aes.NewCipher(keyAes)
if err != nil {
return
return err
}

ctr := cipher.NewCTR(AES, iv)
h := hmac.New(sha512.New, keyHmac)
h.Write(iv)
h.Write(saltAes)
h.Write(saltHmac)
mac := make([]byte, hmacSize)

w := out
Expand All @@ -118,7 +157,7 @@ func Decrypt(in io.Reader, out io.Writer, keyAes, keyHmac []byte) (err error) {
for {
b, err = buf.Peek(BUFFER_SIZE)
if err != nil && err != io.EOF {
return
return err
}

limit = len(b) - hmacSize
Expand All @@ -145,12 +184,12 @@ func Decrypt(in io.Reader, out io.Writer, keyAes, keyHmac []byte) (err error) {
outBuf := make([]byte, int64(limit))
_, err = buf.Read(b[:limit])
if err != nil {
return
return err
}
ctr.XORKeyStream(outBuf, b[:limit])
_, err = w.Write(outBuf)
if err != nil {
return
return err
}

if err == io.EOF {
Expand All @@ -164,3 +203,19 @@ func Decrypt(in io.Reader, out io.Writer, keyAes, keyHmac []byte) (err error) {

return nil
}

func DeriveKey(password, salt []byte) ([]byte, []byte, error) {
if salt == nil {
salt = make([]byte, SALT_SIZE)
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, err
}

return key, salt, nil
}

0 comments on commit 3c9928d

Please sign in to comment.