How to Hack Time, With C2PA

How to Hack Time, With C2PA

如何利用 C2PA 破解时间

By David Buchanan (aka retr0id), 2nd October 2026 作者:David Buchanan (又名 retr0id),2026 年 10 月 2 日

The most impressive hacking stunt from cinema history comes from Kung Fury (2015), in which Hackerman hacks time itself. He uses this power to correct historic misdeeds. But what would I do with the ability to hack time? Personally I’m more afraid of the butterfly effect, so I’d just go back a few hours to tell myself the winning lottery numbers. 电影史上最令人印象深刻的黑客特技来自《功之怒》(2015 年),片中的“黑客侠”(Hackerman)破解了时间本身。他利用这种力量来纠正历史上的错误。但如果我有破解时间的能力,我会做什么呢?就我个人而言,我更担心蝴蝶效应,所以我只会回到几个小时前,告诉自己中奖彩票的号码。

As it happens, that’s exactly what I did, according to the cryptographically unforgeable C2PA metadata of this image: Yes, you can tell it’s photoshopped. I’m not trying to do actual lottery fraud here. You can verify the C2PA metadata including the timestamp at https://verify.contentauthenticity.org/ (if you’re reading this in the future, maybe they’ve introduced mitigations). You can confirm that those are the winning lottery numbers, shown hours before the draw time, at https://www.euro-millions.com/results/28-08-2026. 事实证明,我确实就是这么做的。根据这张图片中不可伪造的 C2PA 加密元数据来看:没错,你可以看出它是经过 Photoshop 处理的。我并不是真的想进行彩票欺诈。你可以在 https://verify.contentauthenticity.org/ 验证包括时间戳在内的 C2PA 元数据(如果你是在未来阅读本文,也许他们已经引入了缓解措施)。你可以在 https://www.euro-millions.com/results/28-08-2026 确认这些确实是中奖号码,且在开奖时间前数小时就已经显示出来了。

Background

背景

A typical C2PA manifest contains two signatures. The first is the “claim” signature, and in the case of a camera app the claim might be something like “this is a captured photograph, taken at these GPS coordinates, at this time” (except expressed more formally, per the C2PA spec). In my previous article I showed that the claim signature is approximately worthless, and we can sign whatever claims we like (at least, we can in the case of flagship C2PA implementations like the Google Pixel Camera app). 一个典型的 C2PA 清单包含两个签名。第一个是“声明”(claim)签名,对于相机应用来说,声明可能是类似“这是一张拍摄的照片,拍摄于此 GPS 坐标,拍摄于此时间”(根据 C2PA 规范,表达方式会更正式)。在上一篇文章中,我展示了声明签名几乎毫无价值,我们可以签署任何我们想要的声明(至少在 Google Pixel 相机应用等旗舰级 C2PA 实现中是这样)。

But there’s usually a second signature, from a Time Stamp Authority (TSA), and this one is more interesting. We don’t trust devices to tell their own time, so instead a remote server is consulted, via the RFC 3161 protocol. The server sends back a signature that asserts “yes, I saw this hash at this timestamp”, and this response is embedded into the C2PA metadata. As long as we trust that the server isn’t misbehaving, this proves that the data being signed existed at-or-before the specified timestamp. The TSA acts like an independent witness. 但通常还有第二个签名,来自时间戳授权机构(TSA),这个签名更有趣。我们不信任设备自身报告的时间,因此会通过 RFC 3161 协议咨询远程服务器。服务器会返回一个签名,断言“是的,我在这个时间戳看到了这个哈希值”,并将此响应嵌入到 C2PA 元数据中。只要我们相信服务器没有作恶,这就证明了被签名的数据在指定时间戳或之前就已经存在。TSA 就像一个独立的见证人。

For the Pixel 10, Google decided that devices can in fact be trusted to tell their own time. I have not evaluated their “on-device trusted time-stamp” implementation yet, but I’m highly sceptical of it. Despite this, in this article we will not be attacking the TSA: we assume it functions as advertised. 对于 Pixel 10,谷歌决定设备实际上是可以信任其自身时间的。我还没有评估他们的“设备端可信时间戳”实现,但我对此持高度怀疑态度。尽管如此,在本文中我们不会攻击 TSA:我们假设它按预期工作。

It’s Time-Hacking Time

是时候破解时间了

If the TSA mechanism is secure, how are we going to hack time? We’re going to use my favourite bug class: the spec footgun. The footgun is as follows: C2PA allows for arbitrary “exclusions”. These are byte ranges within the file which are excluded from signature calculations. Yup. Really. This is already known (it’s literally in the spec), but for some reason nobody’s done anything about it yet. 如果 TSA 机制是安全的,我们该如何破解时间呢?我们将使用我最喜欢的漏洞类别:规范中的“自残陷阱”(spec footgun)。这个陷阱如下:C2PA 允许任意的“排除项”(exclusions)。这些是文件中被排除在签名计算之外的字节范围。没错,真的。这一点早已为人所知(它确实写在规范里),但出于某种原因,至今没人对此采取行动。

In fact, Dr. Neal Krawertz explicitly called it out in his “Big Bulleted List” of C2PA flaws published June 2025: Large exclusion range. The manifest typically excludes a very large byte range from the signatures. Any excluded bytes can be altered without detection. The only new angle here is that a malicious signer can deliberately use a large exclusion range, rather than merely doing so incidentally. We can exclude the entire file, to produce an entirely valid signature over an empty string. This allows the file to be tampered with after the fact, without invalidating the signature, and without invalidating the TSA’s timestamp proof. 事实上,Neal Krawertz 博士在 2025 年 6 月发布的 C2PA 缺陷“大清单”中明确指出了这一点:大范围排除。清单通常会从签名中排除非常大的字节范围。任何被排除的字节都可以在不被检测到的情况下被篡改。这里唯一的新角度是,恶意签名者可以故意使用大范围排除,而不仅仅是偶然为之。我们可以排除整个文件,从而对一个空字符串生成完全有效的签名。这使得文件可以在事后被篡改,而不会使签名失效,也不会使 TSA 的时间戳证明失效。

Time status: Hacked

时间状态:已破解

So I really did take a picture of a lottery ticket, and attach a valid C2PA signature with a valid trusted timestamp. But I crafted the manifest to exclude the whole file, allowing me to photoshop it (poorly) after the numbers were announced, without invalidating any of the signatures. Using c2patool -d to dump the manifest of my PoC file, we can see the important part: 所以我确实拍了一张彩票的照片,并附上了一个带有有效可信时间戳的有效 C2PA 签名。但我精心制作了清单以排除整个文件,这让我可以在开奖号码公布后对其进行(拙劣的)Photoshop 处理,而不会使任何签名失效。使用 c2patool -d 转储我的概念验证(PoC)文件的清单,我们可以看到关键部分:

"c2pa.hash.data": {
  "exclusions": [
    {
      "start": 0,
      "length": 3995383
    }
  ],
  "name": "jumbf manifest",
  "alg": "sha256",
  "hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
  "pad": []
},

3995383 is the length of the entire file, and 47DE…uFU= is the hash of an empty string: 3995383 是整个文件的长度,而 47DE…uFU= 是空字符串的哈希值:

$ openssl sha256 -binary /dev/null | base64
47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=

The claim signature is over that hash, and the timestamp signature is over the claim signature. We’re effectively signing nothing at all, but as of today all the C2PA verification tools I can find don’t flag anything as unusual. 声明签名是针对该哈希值的,而时间戳签名是针对声明签名的。我们实际上什么都没签,但截至今日,我能找到的所有 C2PA 验证工具都没有将此标记为异常。

Can it be fixed?

这能修复吗?

Not easily! Sure, it’s trivial to detect when the entire file has been excluded and report it as invalid, but what if only a small part is excluded? How do you tell whether it’s something harmless, or something that could completely change the appearance of the image if modified? (See MD5 hash collision PoCs for examples of the latter). 不容易!当然,检测整个文件是否被排除并将其报告为无效是轻而易举的,但如果只排除了一小部分呢?你怎么判断它是无害的,还是修改后会彻底改变图像外观的内容?(参见 MD5 哈希碰撞的 PoC 以了解后者的例子)。

My first draft of this post ended here with “My recommendation is that the exclusion feature should be excluded from the C2PA spec,” but it’s not that simple! The main reason exclusions exist in the first place is that certain file formats effectively require it. For example in PNG files, each chunk has a CRC32 checksum, which needs to be corrected after the signature has been embedded into the file. This would create a circular dependency, unless the CRC32 is excluded from the signature’s coverage (ignoring clever mathematical tricks that could avoid invalidating the CRC). With that in mind I think the right solution here is to carefully and explicitly specify which parts of a file are allowed to be excluded, for each supported file format, and require that verifiers enforce these constraints. 我这篇文章的初稿到这里就结束了,结尾是“我的建议是将排除功能从 C2PA 规范中排除”,但这没那么简单!排除功能存在的首要原因是某些文件格式确实需要它。例如在 PNG 文件中,每个数据块都有一个 CRC32 校验和,在签名嵌入文件后需要对其进行修正。这会产生循环依赖,除非将 CRC32 从签名的覆盖范围中排除(忽略那些可以避免 CRC 失效的巧妙数学技巧)。考虑到这一点,我认为正确的解决方案是针对每种支持的文件格式,仔细且明确地指定允许排除文件的哪些部分,并要求验证器强制执行这些约束。