Repository: apache/arrow
File: cpp/src/parquet/metadata.cc (C++)

Code before:
                  tag, encryption::kGcmTagLength);
  }

  bool VerifySignature(std::span<const uint8_t> serialized_metadata,
                       std::span<const uint8_t> signature) {
    // Verify decryption properties are set
    if (file_decryptor_ == nullptr) {
      throw ParquetException("Decryption not set properly. cannot verify signature");
    }

    if (signature.size() != encryption::kGcmTagLength + encryption::kNonceLength) {
      throw ParquetInvalidOrCorruptedFileException(
          "Invalid footer encryption signature (expected ",
          encryption::kGcmTagLength + encryption::kNonceLength, " bytes, got ",
          signature.size(), ")");
    }

    // Encrypt plaintext serialized metadata so as to compute its signature
    auto nonce = signature.subspan(0, encryption::kNonceLength);
    auto tag = signature.subspan(encryption::kNonceLength);
    const SecureString& key = file_decryptor_->GetFooterKey();
    const std::string& aad = encryption::CreateFooterAad(file_decryptor_->file_aad());

    auto aes_encryptor = encryption::AesEncryptor::Make(file_decryptor_->algorithm(),
                                                        static_cast<int>(key.size()),
                                                        true, false /*write_length*/);

    std::shared_ptr<Buffer> encrypted_buffer =
        AllocateBuffer(file_decryptor_->pool(),
                       aes_encryptor->CiphertextLength(serialized_metadata.size()));
    int32_t encrypted_len = aes_encryptor->SignedFooterEncrypt(
        serialized_metadata, key.as_span(), str2span(aad), nonce,
        encrypted_buffer->mutable_span_as<uint8_t>());
    DCHECK_EQ(encrypted_len, encrypted_buffer->size());
    // Check computed signature against expected
    return 0 ==
           memcmp(encrypted_buffer->data() + encrypted_len - encryption::kGcmTagLength,
                  tag.data(), encryption::kGcmTagLength);
  }

  inline uint32_t size() const { return metadata_len_; }
  inline int num_columns() const { return schema_.num_columns(); }
  inline int64_t num_rows() const { return metadata_->num_rows; }
  inline int num_row_groups() const {
    return static_cast<int>(metadata_->row_groups.size());
  }
  inline int32_t version() const { return metadata_->version; }
  inline const std::string& created_by() const { return metadata_->created_by; }
  inline int num_schema_elements() const {
    return static_cast<int>(metadata_->schema.size());
  }

Review comment (suggestion):
```suggestion
                                                        /*metadata=*/true, /*write_length=*/false);
```

Code after:
                  tag, encryption::kGcmTagLength);
  }

  inline uint32_t size() const { return metadata_len_; }
  inline int num_columns() const { return schema_.num_columns(); }
  inline int64_t num_rows() const { return metadata_->num_rows; }
  inline int num_row_groups() const {
    return static_cast<int>(metadata_->row_groups.size());
  }
  inline int32_t version() const { return metadata_->version; }
  inline const std::string& created_by() const { return metadata_->created_by; }
  inline int num_schema_elements() const {
    return static_cast<int>(metadata_->schema.size());
  }

  inline bool is_encryption_algorithm_set() const {
    return metadata_->__isset.encryption_algorithm;
  }
  inline EncryptionAlgorithm encryption_algorithm() {
    return FromThrift(metadata_->encryption_algorithm);
  }
  inline const std::string& footer_signing_key_metadata() {
    return metadata_->footer_signing_key_metadata;
  }

  const ApplicationVersion& writer_version() const { return writer_version_; }

  void WriteTo(::arrow::io::OutputStream* dst,
               const std::shared_ptr<Encryptor>& encryptor) const {
    ThriftSerializer serializer;
    // Only in encrypted files with plaintext footers the
    // encryption_algorithm is set in footer
    if (is_encryption_algorithm_set()) {
      uint8_t* serialized_data;
      uint32_t serialized_len;
      serializer.SerializeToBuffer(metadata_.get(), &serialized_len, &serialized_data);
      ::arrow::util::span<const uint8_t> serialized_data_span(serialized_data,
                                                              serialized_len);

      // encrypt the footer key
      std::vector<uint8_t> encrypted_data(encryptor->CiphertextLength(serialized_len));
      int32_t encrypted_len = encryptor->Encrypt(serialized_data_span, encrypted_data);

      // write unencrypted footer
      PARQUET_THROW_NOT_OK(dst->Write(serialized_data, serialized_len));
      // Write signature (nonce and tag)
      PARQUET_THROW_NOT_OK(
          dst->Write(encrypted_data.data() + 4, encryption::kNonceLength));
      PARQUET_THROW_NOT_OK(
          dst->Write(encrypted_data.data() + encrypted_len - encryption::kGcmTagLength,
                     encryption::kGcmTagLength));