Ejemplo n.º 1
0
// ExportKeys exports this sync's keys to the given path, protecting them with
// the given password.
func (s *SyncInfo) ExportKeys(outPath, pw string) error {
	salt, err := gocrypt.SecureBytes(aes.KeyLength)
	if err != nil {
		return &ErrSync{"Unable to get salt for export", err}
	}

	exportKeys := generatePbkdf2KeyCombo(pw, salt)

	origBuf := memstream.New()
	origBuf.Write(s.Keys().CryptoKey)
	origBuf.Write(s.Keys().AuthKey)
	origBuf.Rewind()

	encryptedBuf := memstream.New()
	encryptedBuf.Write(salt)
	_, _, err = aes.Encrypt(origBuf, encryptedBuf, exportKeys)
	if err != nil {
		return &ErrSync{"Unable to encrypt keys", err}
	}

	encoded := gocrypt.BytesToB64(encryptedBuf.Bytes())
	err = ioutil.WriteFile(outPath, []byte(encoded), 0770)
	if err != nil {
		return &ErrSync{"Unable to open key file", err}
	}

	return nil
}
Ejemplo n.º 2
0
// Write rebuilds the protected file on disk, ensuring the contents and header
// are current with the local file
func (h *Header) Write() error {
	// Get data from local file for header
	localFile, err := os.Open(h.AbsLocalPath())
	if err != nil {
		return &ErrProtectedFile{"Unable to open local file", err}
	}
	defer localFile.Close()

	h.contentHash, err = hash.Sha256(localFile)
	if err != nil {
		return &ErrProtectedFile{"Unable to get local file hash", err}
	}

	// Keys
	h.contentKeys, err = aes.NewKeyCombo()
	if err != nil {
		return &ErrProtectedFile{"Failed to generate keys for file", err}
	}

	// Write header to temp file
	headerBytes := memstream.NewCapacity(1024)
	writer := bufio.NewWriter(headerBytes)
	err = writer.WriteByte(1) // Version
	if err != nil {
		return &ErrProtectedFile{"Unable to write version", err}
	}

	_, err = writer.Write(h.contentKeys.CryptoKey)
	if err != nil {
		return &ErrProtectedFile{"Unable to write crypto key", err}
	}
	_, err = writer.Write(h.contentKeys.AuthKey)
	if err != nil {
		return &ErrProtectedFile{"Unable to write auth key", err}
	}
	_, err = writer.Write(h.contentHash)
	if err != nil {
		return &ErrProtectedFile{"Unable to write hash", err}
	}

	localLenBytes := gocrypt.Uint64ToBytes(uint64(len(h.LocalPath())))
	_, err = writer.Write(localLenBytes)
	if err != nil {
		return &ErrProtectedFile{"Unable to write path length", err}
	}

	_, err = writer.Write([]byte(h.LocalPath()))
	if err != nil {
		return &ErrProtectedFile{"Unable to write local path", err}
	}

	if err = writer.Flush(); err != nil {
		return &ErrProtectedFile{"Flushing header failed", err}
	}

	// Encrypt and write header to temp file
	protFile, err := ioutil.TempFile("", "syncerprotfile")
	if err != nil {
		return &ErrProtectedFile{"Unable to create temp protected file", err}
	}
	defer func() {
		protFile.Close()
		os.Remove(protFile.Name())
	}()

	headerBytes.Rewind()
	metakeys := h.sync.Keys()
	_, _, err = aes.Encrypt(headerBytes, protFile, &metakeys)
	if err != nil {
		return &ErrProtectedFile{"Unable to encrypt header", err}
	}

	// Update length of header. Not in file, just used internally for extracting
	headLen, err := protFile.Seek(0, 1)
	h.headerLen = int(headLen)
	if err != nil {
		return &ErrProtectedFile{"Unable to determine length of header", err}
	}

	// Encrypt and append contents
	_, err = localFile.Seek(0, 0)
	if err != nil {
		return &ErrProtectedFile{"Unable to return to beginning of local file", err}
	}

	_, _, err = aes.Encrypt(localFile, protFile, h.contentKeys)
	if err != nil {
		return &ErrProtectedFile{"Unable to encrypt contents", err}
	}

	// Move file to final location
	// TODO create any needed directories?
	protFile.Close()
	err = moveFile(protFile.Name(), h.AbsRemotePath())
	if err != nil {
		return &ErrProtectedFile{"Failed to move final protected file", err}
	}

	return nil
}