## Encrypt a file using a secret key<?php$secret_key = sodium_crypto_secretstream_xchacha20poly1305_keygen();$input_file = '/tmp/example.original';$encrypted_file = '/tmp/example.enc';$chunk_size = 4096;$fd_in = fopen($input_file, 'rb');$fd_out = fopen($encrypted_file, 'wb');list($stream, $header) = sodium_crypto_secretstream_xchacha20poly1305_init_push($secret_key);fwrite($fd_out, $header);$tag = SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE;do { $chunk = fread($fd_in, $chunk_size); if (stream_get_meta_data($fd_in)['unread_bytes'] <= 0) { $tag = SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL; } $encrypted_chunk = sodium_crypto_secretstream_xchacha20poly1305_push($stream, $chunk, '', $tag); fwrite($fd_out, $encrypted_chunk);} while ($tag !== SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL);fclose($fd_out);fclose($fd_in);?>Decrypt the file:<?php$decrypted_file = '/tmp/example.dec';$fd_in = fopen($encrypted_file, 'rb');$fd_out = fopen($decrypted_file, 'wb');$header = fread($fd_in, SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES);$stream = sodium_crypto_secretstream_xchacha20poly1305_init_pull($header, $secret_key);$tag = SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE;while (stream_get_meta_data($fd_in)['unread_bytes'] > 0 && $tag !== SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL) { $chunk = fread($fd_in, $chunk_size + SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES); list($decrypted_chunk, $tag) = sodium_crypto_secretstream_xchacha20poly1305_pull($stream, $chunk); fwrite($fd_out, $decrypted_chunk);}$ok = stream_get_meta_data($fd_in)['unread_bytes'] <= 0;fclose($fd_out);fclose($fd_in);if (!$ok) { die('Invalid/corrupted input');}?>How it works:There's a little bit more code than in the previous examples.In fact, `crypto_secretbox()` would work to encrypt as file, but onlyif that file is pretty small. Since we have to provide the entirecontent as a string, it has to fit in memory.If the file is large, we can split it into small chunks, and encryptchunks individually.By doing do, we can encrypt arbitrary large files. But we need to makesure that chunks cannot be deleted, truncated, duplicated andreordered. In other words, we don't have a single "message", but astream of messages, and during the decryption process, we need a wayto check that the whole stream matches what we encrypted.So we create a new stream (`init_push`) and push a sequence of messagesinto it (`push`). Each individual message has a tag attached to it, bydefault `TAG_MESSAGE`. In order for the decryption process to knowwhere the end of the stream is, we tag the last message with the`TAG_FINAL` tag.When we consume the stream (`init_pull`, then `pull` for eachmessage), we check that they can be properly decrypted, and retrieveboth the decrypted chunks and the attached tags. If we read the lastchunk (`TAG_FINAL`) and we are at the end of the file, we know that wecompletely recovered the original stream.