Example #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
}
Example #2
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
}
Example #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
}