// TestEncryptingFromMiddle tests that Encrypting when the source is NOT // at the beginning of the stream works properly func TestEncryptingFromMiddle(t *testing.T) { actualBytes := []byte("abcdefghijklmnopqrstuvwxyz") actualStart := 10 orig := memstream.NewCapacity(30) orig.Write(actualBytes) // Jump part way in and encrypt orig.Seek(int64(actualStart), 0) encrypted := memstream.NewCapacity(50) _, _, err := Encrypt(orig, encrypted, keys) if err != nil { t.Errorf("Unable to encrypt: %v", err) return } // Decrypt encrypted.Seek(0, 0) decrypted := memstream.NewCapacity(30) _, _, err = Decrypt(encrypted, decrypted, keys) if err != nil { t.Errorf("Unable to decrypt: %v", err) return } if !bytes.Equal(actualBytes[actualStart:], decrypted.Bytes()) { t.Errorf("Decrypted bytes (%v) do not match original (%v)", decrypted.Bytes(), actualBytes) fmt.Println(decrypted.Bytes()) fmt.Println(actualBytes[actualStart:]) return } }
// 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 }