blob: 21af00fd2e1b3c51a0ec1f50eda94644423378f0 [file] [edit]
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "formats/bmff/hasher.h"
#include <string>
#include "absl/status/status.h"
#include "absl/status/status_macros.h"
#include "absl/strings/str_cat.h"
#include "bindings/binding_hasher.h"
#include "bindings/bmff_binding_hasher.h"
#include "crypto/algorithms.h"
#include "proto/bmff_based_hash_assertion.pb.h"
#include "riegeli/bytes/reader.h"
namespace credentio {
BmffBasedHashAssertion GetBmffHashTemplate(HashAlgorithm alg) {
BmffBasedHashAssertion assertion;
assertion.set_name("BMFF file hash");
assertion.set_alg(absl::StrCat(alg));
std::string hash(HashSizeBytes(alg), '\0');
assertion.set_hash(hash);
// Add the required exclusions described in
// https://spec.c2pa.org/specifications/specifications/2.4/specs/C2PA_Specification.html#_exclusion_list_requirements.
assertion.add_exclusions()->set_xpath("/ftyp");
BmffRange* uuid_exclusion = assertion.add_exclusions();
uuid_exclusion->set_xpath("/uuid");
BmffData* data = uuid_exclusion->add_data();
data->set_offset(8);
// The C2PA manifest store extended box type value, which will always
// appear at offset 8 in the C2PA BMFF box
// (https://spec.c2pa.org/specifications/specifications/2.4/specs/C2PA_Specification.html#_definition).
data->set_value("\330\376\303\326\033\016H<\222\227X(\207~\304\201");
assertion.add_exclusions()->set_xpath("/mfra");
// Exclude 'free' boxes. A 'free' box is often used for a pre-allocated space
// before writing the final C2PA manifest store.
assertion.add_exclusions()->set_xpath("/free");
return assertion;
}
absl::Status DigestBmff(riegeli::Reader& input,
BmffBasedHashAssertion& assertion_template) {
StatusBindingHasherTracker tracker;
BmffBindingHasher hasher(&assertion_template, &tracker);
auto digest = hasher.Digest(input).value_or("");
ABSL_RETURN_IF_ERROR(tracker.status());
if (digest.empty()) {
return absl::InternalError("digest is empty but tracker status is OK");
}
if (digest.size() != assertion_template.hash().size()) {
return absl::InternalError("digest size mismatch");
}
assertion_template.set_hash(digest);
return absl::OkStatus();
}
} // namespace credentio