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

Code before:
                                                            serialized_len);

    // encrypt with nonce
    ::arrow::util::span<const uint8_t> nonce(reinterpret_cast<const uint8_t*>(signature),
                                             encryption::kNonceLength);
    auto tag = reinterpret_cast<const uint8_t*>(signature) + 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_len));
    int32_t encrypted_len = aes_encryptor->SignedFooterEncrypt(
        serialized_data_span, key.as_span(), str2span(aad), nonce,
        encrypted_buffer->mutable_span_as<uint8_t>());
    return 0 ==
           memcmp(encrypted_buffer->data() + encrypted_len - encryption::kGcmTagLength,
                  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()));

Review comment (suggestion):
I implemented this as a method of `FileMetaData` but the only member it uses is the `FileDecryptor`, so perhaps this should be moved elsewhere (or made `static`?).

Code after:
                                                            serialized_len);

    // encrypt with nonce
    ::arrow::util::span<const uint8_t> nonce(reinterpret_cast<const uint8_t*>(signature),
                                             encryption::kNonceLength);
    auto tag = reinterpret_cast<const uint8_t*>(signature) + 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_len));
    int32_t encrypted_len = aes_encryptor->SignedFooterEncrypt(
        serialized_data_span, key.as_span(), str2span(aad), nonce,
        encrypted_buffer->mutable_span_as<uint8_t>());
    return 0 ==
           memcmp(encrypted_buffer->data() + encrypted_len - encryption::kGcmTagLength,
                  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;