// 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 }
func bytesToInt64(b []byte) int64 { return int64(gocrypt.BytesToUint64(b)) }