Skip to content

Commit

Permalink
Merge pull request #15 from lomorage/dev
Browse files Browse the repository at this point in the history
use file sha256 sum hash as salt to be able to reproduce encryption
  • Loading branch information
dwebfan authored May 19, 2024
2 parents 4119250 + ff8cf8f commit 29bc165
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 25 deletions.
74 changes: 56 additions & 18 deletions cmd/lomob/crypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (
"fmt"
"io"
"os"
"reflect"
"syscall"

"github.com/lomorage/lomo-backup/common/crypto"
lomohash "github.com/lomorage/lomo-backup/common/hash"
"github.com/urfave/cli"
"golang.org/x/term"
)
Expand All @@ -33,18 +35,21 @@ func getMasterKey() (string, error) {
return string(bytePassword1), nil
}

func genEncryptKeyAndSalt(masterKey []byte) (key []byte, salt []byte, err error) {
salt = make([]byte, aes.BlockSize)
_, err = io.ReadFull(rand.Reader, salt)
if err != nil {
return nil, nil, err
func genSalt(filename string) ([]byte, error) {
if filename == "" {
salt := make([]byte, crypto.SaltLen())
_, err := io.ReadFull(rand.Reader, salt)
return salt, err
}

// Derive key from passphrase using Argon2
// TODO: Using IV as salt for simplicity, change to different salt?
key = crypto.DeriveKeyFromMasterKey(masterKey, salt)

return
h, err := lomohash.CalculateHashFile(filename)
if err != nil {
return nil, err
}
if len(h) < crypto.SaltLen() {
return nil, fmt.Errorf("invalid hash len '%d', less than '%d'", len(h), crypto.SaltLen())
}
return h[:crypto.SaltLen()], nil
}

func encryptCmd(ctx *cli.Context) error {
Expand All @@ -60,7 +65,11 @@ func encryptCmd(ctx *cli.Context) error {
return errors.New("usage: [input filename] [[output filename]]. If output filename is not given, it will be <intput filename>.enc")
}

var err error
salt, err := genSalt(ifilename)
if err != nil {
return err
}

masterKey := ctx.String("encrypt-key")
if masterKey == "" {
masterKey, err = getMasterKey()
Expand All @@ -82,7 +91,7 @@ func encryptCmd(ctx *cli.Context) error {
defer dst.Close()

fmt.Printf("Start encrypt '%s', and save output to '%s'\n", ifilename, ofilename)
_, err = encryptLocalFile(src, dst, masterKey, true)
_, err = encryptLocalFile(src, dst, []byte(masterKey), salt, true)
if err != nil {
return err
}
Expand All @@ -92,12 +101,10 @@ func encryptCmd(ctx *cli.Context) error {
return nil
}

func encryptLocalFile(src io.ReadSeeker, dst io.Writer, masterKey string, hasHeader bool) ([]byte, error) {
encryptKey, iv, err := genEncryptKeyAndSalt([]byte(masterKey))
if err != nil {
return nil, err
}

func encryptLocalFile(src io.ReadSeeker, dst io.Writer, masterKey, iv []byte, hasHeader bool) ([]byte, error) {
// Derive key from passphrase using Argon2
// TODO: Using IV as salt for simplicity, change to different salt?
encryptKey := crypto.DeriveKeyFromMasterKey(masterKey, iv)
encryptor, err := crypto.NewEncryptor(src, encryptKey, iv, hasHeader)
if err != nil {
return nil, err
Expand Down Expand Up @@ -161,3 +168,34 @@ func decryptLocalFile(ctx *cli.Context) error {
fmt.Println("Finish decryption!")
return nil
}

func checkHeader(ctx *cli.Context) error {
if len(ctx.Args()) != 2 {
return errors.New("usage: [original file name] [encrypted file name]")
}

h, err := genSalt(ctx.Args()[0])
if err != nil {
return err
}

f, err := os.Open(ctx.Args()[1])
if err != nil {
return err
}
defer f.Close()

salt := make([]byte, crypto.SaltLen())
s, err := f.Read(salt)
if err != nil {
return err
}
if s != len(salt) {
return fmt.Errorf("expect read %d, actual read %d", len(salt), s)
}
if !reflect.DeepEqual(salt, h[:crypto.SaltLen()]) {
return errors.New("different salt detected")
}
fmt.Println("Salt is same as expected!")
return nil
}
6 changes: 6 additions & 0 deletions cmd/lomob/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,12 @@ func main() {
},
},
},
{
Name: "check-header",
Action: checkHeader,
Usage: "Check if the header of encrypt file follows the convention",
ArgsUsage: "[original file name] [encrypt file name]",
},
},
},
}
Expand Down
18 changes: 12 additions & 6 deletions cmd/lomob/upload-files.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,23 +137,25 @@ func uploadFilesToGdrive(ctx *cli.Context) error {

fullLocalPath := filepath.Join(scanRoot, f.Name)

// reuse folder ID if it is in map already
file, err := os.Open(fullLocalPath)
salt, err := genSalt(fullLocalPath)
if err != nil {
return err
}

stat, err := file.Stat()
// reuse folder ID if it is in map already
file, err := os.Open(fullLocalPath)
if err != nil {
return err
}

encryptKey, iv, err := genEncryptKeyAndSalt([]byte(masterKey))
stat, err := file.Stat()
if err != nil {
return err
}

encryptor, err := crypto.NewEncryptor(file, encryptKey, iv, true)
encryptKey := crypto.DeriveKeyFromMasterKey([]byte(masterKey), salt)

encryptor, err := crypto.NewEncryptor(file, encryptKey, salt, true)
if err != nil {
return err
}
Expand Down Expand Up @@ -308,6 +310,10 @@ func uploadRawFileToS3(cli *clients.AWSClient, bucket, storageClass, filename, c
// as PutObject requires encryption before input, thus, it has to write into one temp file or memory to get all data
// return tmp filename, and let caller delete
func uploadEncryptFileToS3(cli *clients.AWSClient, bucket, storageClass, filename, masterKey string) (string, error) {
salt, err := genSalt(filename)
if err != nil {
return "", err
}
src, err := os.Open(filename)
if err != nil {
return "", err
Expand All @@ -321,7 +327,7 @@ func uploadEncryptFileToS3(cli *clients.AWSClient, bucket, storageClass, filenam
tmpFileName := tmpFile.Name()
defer tmpFile.Close()

hash, err := encryptLocalFile(src, tmpFile, masterKey, true)
hash, err := encryptLocalFile(src, tmpFile, []byte(masterKey), salt, true)
if err != nil {
return "", err
}
Expand Down
12 changes: 11 additions & 1 deletion cmd/lomob/upload-iso.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"crypto/sha256"
"encoding/hex"
"fmt"
"hash"
"io"
Expand Down Expand Up @@ -331,6 +332,15 @@ func uploadEncryptParts(cli *clients.AWSClient, region, bucket, storageClass, is
}
defer isoFile.Close()

decoded, err := hex.DecodeString(isoInfo.HashHex)
if err != nil {
return err
}
if len(decoded) < crypto.SaltLen() {
return errors.Errorf("invalid hash length '%d', less than '%d'", len(decoded), crypto.SaltLen())
}

salt := decoded[:crypto.SaltLen()]
// iso size need add salt block size
isoInfo.Size += crypto.SaltLen()
isoInfo.HashBase64 = ""
Expand Down Expand Up @@ -383,7 +393,7 @@ func uploadEncryptParts(cli *clients.AWSClient, region, bucket, storageClass, is
defer tmpFile.Close()

prs := lomoio.NewFilePartReadSeeker(isoFile, start, end)
h, err := encryptLocalFile(prs, tmpFile, masterKey, i == 0)
h, err := encryptLocalFile(prs, tmpFile, []byte(masterKey), salt, i == 0)
if err != nil {
return err
}
Expand Down

0 comments on commit 29bc165

Please sign in to comment.