| 170 | } |
| 171 | |
| 172 | BlockSplitBloomFilter DeserializeEncryptedFromStream( |
| 173 | const ReaderProperties& properties, ArrowInputStream* input, |
| 174 | std::optional<int64_t> bloom_filter_length, Decryptor* decryptor, |
| 175 | int16_t row_group_ordinal, int16_t column_ordinal) { |
| 176 | ThriftDeserializer deserializer(properties); |
| 177 | format::BloomFilterHeader header; |
| 178 | |
| 179 | // Read the length-prefixed ciphertext for the header. |
| 180 | PARQUET_ASSIGN_OR_THROW(auto length_buf, input->Read(kCiphertextLengthSize)); |
| 181 | CheckBloomFilterShortRead(kCiphertextLengthSize, length_buf->size(), |
| 182 | "Bloom filter header length"); |
| 183 | |
| 184 | const int64_t header_cipher_total_len = |
| 185 | ParseCiphertextTotalLength(length_buf->data(), length_buf->size()); |
| 186 | if (ARROW_PREDICT_FALSE(header_cipher_total_len > |
| 187 | std::numeric_limits<int32_t>::max())) { |
| 188 | throw ParquetException("Bloom filter header ciphertext length overflows int32"); |
| 189 | } |
| 190 | if (bloom_filter_length && header_cipher_total_len > *bloom_filter_length) { |
| 191 | throw ParquetException( |
| 192 | "Bloom filter length less than encrypted bloom filter header length"); |
| 193 | } |
| 194 | |
| 195 | // Read the full header ciphertext and decrypt the Thrift header. |
| 196 | auto header_cipher_buf = |
| 197 | AllocateBuffer(properties.memory_pool(), header_cipher_total_len); |
| 198 | std::memcpy(header_cipher_buf->mutable_data(), length_buf->data(), |
| 199 | kCiphertextLengthSize); |
| 200 | const int64_t header_cipher_remaining = header_cipher_total_len - kCiphertextLengthSize; |
| 201 | PARQUET_ASSIGN_OR_THROW(auto read_size, input->Read(header_cipher_remaining, |
| 202 | header_cipher_buf->mutable_data() + |
| 203 | kCiphertextLengthSize)); |
| 204 | CheckBloomFilterShortRead(header_cipher_remaining, read_size, "Bloom filter header"); |
| 205 | |
| 206 | // Bloom filter header and bitset are separate encrypted modules with different AADs. |
| 207 | UpdateDecryptor(decryptor, row_group_ordinal, column_ordinal, |
| 208 | encryption::kBloomFilterHeader); |
| 209 | auto header_cipher_len = static_cast<uint32_t>(header_cipher_total_len); |
| 210 | try { |
| 211 | deserializer.DeserializeMessage(header_cipher_buf->data(), &header_cipher_len, |
| 212 | &header, decryptor); |
| 213 | } catch (std::exception& e) { |
| 214 | std::stringstream ss; |
| 215 | ss << "Deserializing bloom filter header failed.\n" << e.what(); |
| 216 | throw ParquetException(ss.str()); |
| 217 | } |
| 218 | if (ARROW_PREDICT_FALSE(header_cipher_len != header_cipher_total_len)) { |
| 219 | std::stringstream ss; |
| 220 | ss << "Encrypted bloom filter header length mismatch: expected " |
| 221 | << header_cipher_total_len << " bytes, got " << header_cipher_len; |
| 222 | throw ParquetException(ss.str()); |
| 223 | } |
| 224 | PARQUET_THROW_NOT_OK(ValidateBloomFilterHeader(header)); |
| 225 | |
| 226 | const int32_t bloom_filter_size = header.numBytes; |
| 227 | UpdateDecryptor(decryptor, row_group_ordinal, column_ordinal, |
| 228 | encryption::kBloomFilterBitset); |
| 229 | const int32_t bitset_cipher_len = decryptor->CiphertextLength(bloom_filter_size); |
no test coverage detected