Ejemplo n.º 1
0
// ImportKeys imports the keys from the given file, replacing the current keys for this sync
func (s *SyncInfo) ImportKeys(inPath, pw string) error {
	encoded, err := ioutil.ReadFile(inPath)
	if err != nil {
		return &ErrSync{"Unable to open key file", err}
	}

	encrypted, err := gocrypt.BytesFromB64(string(encoded))
	if err != nil {
		return &ErrSync{"Unable to decode key file", err}
	}

	salt := encrypted[:aes.KeyLength]
	exportKeys := generatePbkdf2KeyCombo(pw, salt)

	decrypted := memstream.New()
	_, cnt, err := aes.Decrypt(bytes.NewBuffer(encrypted[aes.KeyLength:]), decrypted, exportKeys)
	if err != nil {
		return &ErrSync{"Unable to decrypt keys", err}
	}

	if cnt != int64(aes.KeyLength*2) {
		return &ErrSync{"Keys read, but do not appear to be the correct format", nil}
	}

	decrypted.Rewind()

	cryptoKey := gocrypt.Key(make([]byte, aes.KeyLength))
	var read int
	if read, err = decrypted.Read(cryptoKey); err != nil && err != io.EOF {
		return &ErrSync{"Failed to read crypto key", err}
	}
	cryptoKey = cryptoKey[:read]

	authKey := gocrypt.Key(make([]byte, aes.KeyLength))
	if read, err = decrypted.Read(authKey); err != nil && err != io.EOF {
		return &ErrSync{"Failed to read auth key", err}
	}
	authKey = authKey[:read]

	if len(cryptoKey) != aes.KeyLength || len(authKey) != aes.KeyLength {
		return &ErrSync{"Keys read, but they do not appear to be long enough", nil}
	}

	s.Set(cryptoKeyKey, cryptoKey.String())
	s.Set(authKeyKey, authKey.String())

	return nil
}
Ejemplo n.º 2
0
// ExtractContents decrypts the contents of the protected file onto the local path
func (h *Header) ExtractContents() error {
	// Skip to contents
	protFile, err := os.Open(h.AbsRemotePath())
	if err != nil {
		return &ErrProtectedFile{"Unable to open protected file", err}
	}
	defer protFile.Close()

	_, err = protFile.Seek(int64(h.headerLen), 0)
	if err != nil {
		return &ErrProtectedFile{"Unable to skip to contents", err}
	}

	// Decrypt to temp
	tempFile, err := ioutil.TempFile("", "syncerdecryptedcontents")
	if err != nil {
		return &ErrProtectedFile{"Unable to create temp file", err}
	}
	defer func() {
		tempFile.Close()
		os.Remove(tempFile.Name())
	}()

	_, _, err = aes.Decrypt(protFile, tempFile, h.contentKeys)
	if err != nil {
		return &ErrProtectedFile{"Error during decryption", err}
	}

	// Move to final location
	tempFile.Close()
	err = moveFile(tempFile.Name(), h.AbsLocalPath())
	if err != nil {
		return &ErrProtectedFile{"Failed to move decrypted file to local", err}
	}

	return nil
}
Ejemplo n.º 3
0
// OpenProtectedFile reads the header of the given protected file and returns the data
// needed to work further with that file.
func OpenProtectedFile(sync *SyncInfo, protFilePath string) (*Header, error) {
	f, err := os.Open(filepath.Join(sync.RemoteBase(), protFilePath))
	if err != nil {
		return nil, err
	}
	defer f.Close()

	// Decrypt header
	headBytes := memstream.New()
	keys := sync.Keys()
	encHeadLen, _, err := aes.Decrypt(f, headBytes, &keys)
	if err != nil {
		return nil, err
	}

	header := new(Header)
	header.sync = sync
	header.headerLen = int(encHeadLen)
	header.remotePath = protFilePath
	header.contentKeys = new(gocrypt.KeyCombo)

	// Interpret
	headBytes.Rewind()
	buf := bufio.NewReader(headBytes)

	version, err := buf.ReadByte()
	if err != nil {
		return nil, &ErrProtectedFile{"Unable to read header version", err}
	}

	switch version {
	case 1:
		// Format:
		// 1 - version (currently at version 1)
		// 16 - crypto key for contents
		// 16 - auth key
		// 32 - hash of DECRYPTED contents
		// 8 - length of Path
		// <Variable> - local relative path
		header.contentKeys.CryptoKey, err = readKey(buf)
		if err != nil {
			return nil, &ErrProtectedFile{"Unable to read crypto key", err}
		}

		header.contentKeys.AuthKey, err = readKey(buf)
		if err != nil {
			return nil, &ErrProtectedFile{"Unable to read auth key", err}
		}

		header.contentHash, err = readFixedSize(buf, hash.Sha256Size)
		if err != nil {
			return nil, &ErrProtectedFile{"Unable to read content hash", err}
		}

		lenBytes, err := readFixedSize(buf, 8)
		pathLen := gocrypt.BytesToUint64(lenBytes)
		if err != nil {
			return nil, &ErrProtectedFile{"Unable to read path length", err}
		}

		pathBytes, err := readFixedSize(buf, int(pathLen))
		header.localPath = string(pathBytes)
		if err != nil {
			return nil, &ErrProtectedFile{"Unable to read path", err}
		}

	default:
		return nil, &ErrProtectedFile{fmt.Sprintf("Version %v of header is not recognized", version), nil}
	}

	return header, nil
}