コード例 #1
0
ファイル: shared.go プロジェクト: jcvernaleo/acdb
// Encrypt returns an encrypted Keys blob.  The format of the blob is
// [salt][nonce][encrypted keys]
func (k *Keys) Encrypt(password []byte, N, r, p int) ([]byte, error) {
	// encode Keys
	var keysXDR bytes.Buffer
	_, err := xdr.Marshal(&keysXDR, k)
	if err != nil {
		return nil, err
	}

	// generate a derived key
	var salt [KeySize]byte
	_, err = io.ReadFull(rand.Reader, salt[:])
	if err != nil {
		return nil, err
	}
	dk, err := scrypt.Key(password, salt[:], N, r, p, KeySize)
	if err != nil {
		return nil, err
	}
	var key [KeySize]byte
	copy(key[:], dk)
	goutil.Zero(dk)
	go func() {
		goutil.Zero(key[:])
	}()

	// encrypt KeySafe
	nonce, err := NaClNonce()
	if err != nil {
		return nil, err
	}
	ksEncrypted := secretbox.Seal(nil, keysXDR.Bytes(), nonce, &key)

	var blob bytes.Buffer
	w := bufio.NewWriter(&blob)

	// salt
	_, err = w.Write(salt[:])
	if err != nil {
		return nil, err
	}

	// nonce
	_, err = w.Write(nonce[:])
	if err != nil {
		return nil, err
	}

	// encrypted blob
	_, err = w.Write(ksEncrypted[:])
	if err != nil {
		return nil, err
	}
	w.Flush()

	return blob.Bytes(), nil
}
コード例 #2
0
ファイル: acdbackup.go プロジェクト: jcvernaleo/acdb
// uploadSecrets encrypts and uploads the secrets to acd for safe keeping.
func (a *acdb) uploadSecrets() error {
	a.Log(acd.DebugTrace, "[TRC] uploadSecrets")

	fmt.Printf("Cloud Drive does not have a copy of the secrets.  Please enter " +
		"the password to encrypt the secrets.  Loss of this password is " +
		"unrecoverable!\n")

	p, err := shared.PromptPassword(true)
	if err != nil {
		return err
	}
	defer func() {
		goutil.Zero(p)
	}()

	blob, err := a.keys.Encrypt(p, 32768, 16, 2)
	if err != nil {
		return err
	}

	asset, err := a.c.UploadJSON(a.metadataID, secretsName, blob)
	if err != nil {
		if e, ok := acd.IsCombinedError(err); ok {
			if e.StatusCode != http.StatusConflict {
				return fmt.Errorf("secrets appeared unexpectedly")
			}
		}
	}

	a.Log(acd.DebugTrace, "[TRC] uploadSecrets object: %v", asset.ID)

	return nil
}
コード例 #3
0
ファイル: shared.go プロジェクト: jcvernaleo/acdb
func CreateNewKeys(filename string) error {
	k := Keys{}

	_, err := io.ReadFull(rand.Reader, k.MD[:])
	if err != nil {
		return err
	}

	_, err = io.ReadFull(rand.Reader, k.Data[:])
	if err != nil {
		return err
	}

	_, err = io.ReadFull(rand.Reader, k.Dedup[:])
	if err != nil {
		return err
	}

	dir := path.Dir(filename)

	err = os.MkdirAll(dir, 0700)
	if err != nil {
		return err
	}

	f, err := os.OpenFile(filename, os.O_CREATE|os.O_RDWR, 0600)
	defer func() { _ = f.Close() }()

	e := json.NewEncoder(f)
	err = e.Encode(k)
	if err != nil {
		return err
	}

	goutil.Zero(k.MD[:])
	goutil.Zero(k.Data[:])
	goutil.Zero(k.Dedup[:])

	return nil
}
コード例 #4
0
ファイル: acdbackup.go プロジェクト: jcvernaleo/acdb
func (a *acdb) downloadSecrets() error {
	a.Log(acd.DebugTrace, "[TRC] downloadSecrets")

	asset, err := a.c.GetMetadataFS(metadataName + "/" + secretsName)
	if err != nil {
		if err == acd.ErrNotFound {
			return a.uploadSecrets()
		}
		return fmt.Errorf("remote object not found")
	}
	a.Log(acd.DebugTrace, "[TRC] found asset: %v -> %v\n",
		asset.ID,
		asset.Name)
	blob, err := a.c.DownloadJSON(asset.ID)
	if err != nil {
		return err
	}

	var p []byte
	defer func() {
		goutil.Zero(p)
	}()

	for {
		p, err = shared.ReadPassword()
		if err == nil {
			break
		}

		if !os.IsNotExist(err) {
			return err
		}

		fmt.Printf("There is no local password file.  Please enter " +
			"password to verify the integrity of the remote " +
			"secrets.\n")
		p, err = shared.PromptPassword(false)
		if err != nil {
			return err
		}
		err = a.verifySecrets(p, blob)
		if err != nil {
			fmt.Printf("invalid password: %v\n",
				err)
			continue
		}
		return shared.WritePassword(p)
	}

	return a.verifySecrets(p, blob)
}
コード例 #5
0
ファイル: shared.go プロジェクト: jcvernaleo/acdb
// KeysDecrypt decrypts keys from a blob.  This function relies on secretbox's
// property that it'll fail decryption due to authenticators.  As such it does
// not carry a digest to validate the contents.
func KeysDecrypt(password []byte, N, r, p int,
	blob []byte) (*Keys, error) {

	var (
		salt  [KeySize]byte
		nonce [NonceSize]byte
	)

	copy(salt[:], blob[0:KeySize])
	copy(nonce[:], blob[KeySize:KeySize+NonceSize])

	// key
	dk, err := scrypt.Key(password, salt[:], N, r, p, KeySize)
	if err != nil {
		return nil, err
	}
	var key [KeySize]byte
	copy(key[:], dk)
	goutil.Zero(dk)
	go func() {
		goutil.Zero(key[:])
	}()

	ksXDR, ok := secretbox.Open(nil, blob[KeySize+NonceSize:], &nonce, &key)
	if !ok {
		return nil, fmt.Errorf("could not decrypt")
	}

	k := Keys{}
	_, err = xdr.Unmarshal(bytes.NewReader(ksXDR), &k)
	if err != nil {
		return nil, fmt.Errorf("could not unmarshal")
	}

	return &k, nil
}
コード例 #6
0
ファイル: shared.go プロジェクト: jcvernaleo/acdb
func PromptPassword(save bool) ([]byte, error) {
	var (
		p1, p2 []byte
		err    error
	)
	defer func() {
		goutil.Zero(p2)
	}()

	for {
		fmt.Printf("Password: "******"\nAgain   : ")
		p2, err = terminal.ReadPassword(0)
		if err != nil {
			return nil, err
		}
		fmt.Printf("\n")

		if bytes.Equal(p1, p2) && len(p1) != 0 {
			break
		}
		fmt.Printf("Passwords do not match or are empty.\n")
	}

	if save {
		err = WritePassword(p1)
		if err != nil {
			return nil, err
		}
	}

	return p1, nil
}
コード例 #7
0
ファイル: acdbackup.go プロジェクト: jcvernaleo/acdb
func _main() error {
	// tar like
	create := flag.Bool("c", false, "create archive") // default *is* true
	extract := flag.Bool("x", false, "extract archive")
	lst := flag.Bool("t", false, "list archive contents")
	verbose := flag.Bool("v", false, "verbose")
	compress := flag.Bool("z", false, "enable compression (default false)")
	perms := flag.Bool("p", false, "restore ACL")
	target := flag.String("f", "-", "archive target is Cloud Drive)")
	root := flag.String("C", "", "extract path")

	// not tar like
	debugLevel := flag.Int("d", 0, "debug level: 0 off, 1 trace, 2 loud")
	debugTarget := flag.String("l", "-", "debug target file name, - is stdout")
	flag.Parse()

	args := flag.Args()

	var err error
	a := acdb{
		permList: list.New(),
		target:   *target,
		verbose:  *verbose,
		compress: *compress,
		perms:    *perms,
		root:     *root,
	}
	defer func() {
		goutil.Zero(a.keys.MD[:])
		goutil.Zero(a.keys.Data[:])
		goutil.Zero(a.keys.Dedup[:])
	}()

	// debug target
	if *debugTarget == "-" {
		a.Debugger, err = debug.NewDebugStdout()
		if err != nil {
			return err
		}
	} else {
		a.Debugger, err = debug.NewDebugFile(*debugTarget)
		if err != nil {
			return err
		}
	}

	switch *debugLevel {
	case 0:
		a.Debugger = debug.NewDebugNil()
	case 1:
		a.Debugger.Mask(acd.DebugTrace | acd.DebugHTTP | acd.DebugURL |
			debugApp)
	case 2:
		a.Debugger.Mask(acd.DebugTrace | acd.DebugHTTP | acd.DebugURL |
			acd.DebugBody | acd.DebugJSON | acd.DebugToken |
			acd.DebugLoud | debugApp)
	default:
		return fmt.Errorf("invalid debug level %v", *debugLevel)
	}

	//a.Debugger.Mask(acd.DebugTrace | acd.DebugHTTP | acd.DebugURL |
	//acd.DebugJSON | debugApp)

	a.Log(debugApp, "[APP] start of day")
	defer a.Log(debugApp, "[APP] end of times")

	// default to create
	if *create == false && *extract == false && *lst == false {
		*create = true
	}

	// determine operation
	switch {
	case *create && !(*extract || *lst):
		a.mode = modeCreate

		if len(args) == 0 {
			fmt.Printf("acdbackup <-c> [-vzf target] filenames...\n")
			flag.PrintDefaults()
			return nil
		}

		return a.archive(args)

	case *extract && !(*create || *lst):
		a.mode = modeExtract

		if a.target == "-" {
			return fmt.Errorf("must provide archive metadata file")
		}
		return a.list()

	case *lst && !(*create || *extract):
		a.mode = modeList

		if a.target == "-" {
			return fmt.Errorf("must provide archive metadata file")
		}
		return a.list()

	default:
		return fmt.Errorf("must specify only -c, -x or -t")
	}

	return nil
}
コード例 #8
0
ファイル: sfe.go プロジェクト: jcvernaleo/acdb
func _main() error {
	debugLevel := flag.Int("d", 0, "debug level: 0 off, 1 trace, 2 loud")
	debugTarget := flag.String("l", "-", "debug target file name, - is stdout")
	compress := flag.Bool("c", false, "try to compress (default = false)")
	extract := flag.Bool("e", false, "extract files")
	flag.Parse()

	args := flag.Args()
	if len(args) == 0 {
		fmt.Printf("sfe [-d][-l target] <filename> ...\n")
		flag.PrintDefaults()
		return nil
	}

	var (
		err error
	)

	s := sfe{
		compress: *compress,
	}
	defer func() {
		goutil.Zero(s.keys.MD[:])
		goutil.Zero(s.keys.Data[:])
		goutil.Zero(s.keys.Dedup[:])
	}()

	// debug target
	if *debugTarget == "-" {
		s.Debugger, err = debug.NewDebugStdout()
		if err != nil {
			return err
		}
	} else {
		s.Debugger, err = debug.NewDebugFile(*debugTarget)
		if err != nil {
			return err
		}
	}

	switch *debugLevel {
	case 0:
		s.Debugger = debug.NewDebugNil()
	case 1:
		s.Debugger.Mask(dbgTrace)
	case 2:
		s.Debugger.Mask(dbgTrace | dbgLoud)
	default:
		return fmt.Errorf("invalid debug level %v", *debugLevel)
	}

	keysFilename, err := shared.DefaultKeysFilename()
	if err != nil {
		return err
	}
	rootDir := path.Dir(keysFilename)
	err = os.MkdirAll(rootDir, 0700)
	if err != nil {
		return err
	}

	err = shared.LoadKeys(keysFilename, &s.keys)
	if err != nil {
		return err
	}

	for _, v := range args {
		if *extract {
			s.Log(dbgTrace, "decrypting: %v\n", v)
			err = s.decrypt(v)
			if err != nil {
				fmt.Fprintf(os.Stderr, "could not decrypt: %v\n",
					err)
				continue
			}
		} else {
			s.Log(dbgTrace, "encrypting: %v\n", v)
			err = s.encrypt(v)
			if err != nil {
				fmt.Fprintf(os.Stderr, "could not encrypt: %v\n",
					err)
				continue
			}
		}
	}

	return nil
}