$state, 'header' => $header, ]; } /** $ad is authenticated but not encrypted; the archive passes the entry path so blocks cannot be moved between entries. */ public static function encrypt_chunk( string &$state, string $plain, bool $final, string $ad = '' ): string { return sodium_crypto_secretstream_xchacha20poly1305_push( $state, $plain, $ad, $final ? SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL : SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE ); } public static function decrypt_stream_init( string $key, string $header ): string { if ( SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES !== strlen( $header ) ) { throw new Mench_Migrate_Archive_Exception( 'bad_password_or_tampered', 'decrypt' ); } return sodium_crypto_secretstream_xchacha20poly1305_init_pull( $header, $key ); } /** * @return array{plain:string, final:bool} * @throws Mench_Migrate_Archive_Exception On authentication failure (wrong password or altered data). */ public static function decrypt_chunk( string &$state, string $cipher, string $ad = '' ): array { $res = sodium_crypto_secretstream_xchacha20poly1305_pull( $state, $cipher, $ad ); if ( false === $res ) { throw new Mench_Migrate_Archive_Exception( 'bad_password_or_tampered', 'decrypt' ); } return [ 'plain' => $res[0], 'final' => SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL === $res[1], ]; } /** 32-byte MAC of an archive index under a subkey of the archive key (context "MMIGidx1", id 1). */ public static function index_mac( string $key, string $index_json ): string { $subkey = sodium_crypto_kdf_derive_from_key( 32, 1, 'MMIGidx1', $key ); return sodium_crypto_generichash( $index_json, $subkey, 32 ); } /** * The same MAC computed in pieces, for an index too large to hold in memory: feed it with * sodium_crypto_generichash_update() and end with sodium_crypto_generichash_final( $state, 32 ). */ public static function index_mac_init( string $key ): string { return sodium_crypto_generichash_init( sodium_crypto_kdf_derive_from_key( 32, 1, 'MMIGidx1', $key ), 32 ); } }