예제 #1
0
// RemoteHash returns the hash of the full protected file. This is an expensive
// operation, as the value is not chached.
func (h *Header) RemoteHash() (gocrypt.Hash, error) {
	f, err := os.Open(h.AbsRemotePath())
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return hash.Sha256(f)
}
예제 #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
}