| 138 | } |
| 139 | |
| 140 | BlockSplitBloomFilter DeserializeEncryptedFromStream( |
| 141 | const ReaderProperties& properties, ArrowInputStream* input, |
| 142 | std::optional<int64_t> bloom_filter_length, Decryptor* decryptor, |
| 143 | int16_t row_group_ordinal, int16_t column_ordinal) { |
| 144 | ThriftDeserializer deserializer(properties); |
| 145 | format::BloomFilterHeader header; |
| 146 | |
| 147 | // Read the length-prefixed ciphertext for the header. |
| 148 | PARQUET_ASSIGN_OR_THROW(auto length_buf, input->Read(kCiphertextLengthSize)); |
| 149 | CheckBloomFilterShortRead(kCiphertextLengthSize, length_buf->size(), |
| 150 | "Bloom filter header length"); |
| 151 | |
| 152 | const int64_t header_cipher_total_len = |
| 153 | ParseCiphertextTotalLength(length_buf->data(), length_buf->size()); |
| 154 | if (ARROW_PREDICT_FALSE(header_cipher_total_len > |
| 155 | std::numeric_limits<int32_t>::max())) { |
| 156 | throw ParquetException("Bloom filter header ciphertext length overflows int32"); |
| 157 | } |
| 158 | if (bloom_filter_length && header_cipher_total_len > *bloom_filter_length) { |
| 159 | throw ParquetException( |
| 160 | "Bloom filter length less than encrypted bloom filter header length"); |
| 161 | } |
| 162 | |
| 163 | // Read the full header ciphertext and decrypt the Thrift header. |
| 164 | auto header_cipher_buf = |
| 165 | AllocateBuffer(properties.memory_pool(), header_cipher_total_len); |
| 166 | std::memcpy(header_cipher_buf->mutable_data(), length_buf->data(), |
| 167 | kCiphertextLengthSize); |
| 168 | const int64_t header_cipher_remaining = header_cipher_total_len - kCiphertextLengthSize; |
| 169 | PARQUET_ASSIGN_OR_THROW(auto read_size, input->Read(header_cipher_remaining, |
| 170 | header_cipher_buf->mutable_data() + |
| 171 | kCiphertextLengthSize)); |
| 172 | CheckBloomFilterShortRead(header_cipher_remaining, read_size, "Bloom filter header"); |
| 173 | |
| 174 | // Bloom filter header and bitset are separate encrypted modules with different AADs. |
| 175 | UpdateDecryptor(decryptor, row_group_ordinal, column_ordinal, |
| 176 | encryption::kBloomFilterHeader); |
| 177 | auto header_cipher_len = static_cast<uint32_t>(header_cipher_total_len); |
| 178 | try { |
| 179 | deserializer.DeserializeMessage(header_cipher_buf->data(), &header_cipher_len, |
| 180 | &header, decryptor); |
| 181 | } catch (std::exception& e) { |
| 182 | std::stringstream ss; |
| 183 | ss << "Deserializing bloom filter header failed.\n" << e.what(); |
| 184 | throw ParquetException(ss.str()); |
| 185 | } |
| 186 | if (ARROW_PREDICT_FALSE(header_cipher_len != header_cipher_total_len)) { |
| 187 | std::stringstream ss; |
| 188 | ss << "Encrypted bloom filter header length mismatch: expected " |
| 189 | << header_cipher_total_len << " bytes, got " << header_cipher_len; |
| 190 | throw ParquetException(ss.str()); |
| 191 | } |
| 192 | PARQUET_THROW_NOT_OK(ValidateBloomFilterHeader(header)); |
| 193 | |
| 194 | const int32_t bloom_filter_size = header.numBytes; |
| 195 | UpdateDecryptor(decryptor, row_group_ordinal, column_ordinal, |
| 196 | encryption::kBloomFilterBitset); |
| 197 | const int32_t bitset_cipher_len = decryptor->CiphertextLength(bloom_filter_size); |
no test coverage detected