Skip to content

AI生成的原理解析,感觉很多地方都有待改进 #181

Description

@1963306815

结论

这个项目实现的是一种基于 DWT–DCT–SVD 的盲水印,更准确地说,是利用奇异值余数进行量化编码。它不是加密系统,也不是不可伪造的版权证明。

存在明显的设计层面弱点:

想让原水印无法再被正确提取,相对容易;

想覆盖、伪造另一个水印,也比较容易;

默认或弱密码可以直接猜测;

强随机密码下,从单张图片完整恢复原水印和密钥不一定能“一键破解”,但密钥设计仍达不到现代密码学安全标准;

对旋转、裁剪、平移等攻击的所谓鲁棒性,很多情况下依赖先恢复原有几何位置,并非直接从攻击后的图片中提取。

因此,它适合普通防转载标记、实验和非对抗场景,不适合单独承担司法取证、版权归属或高价值内容保护。


一、它是怎么加水印的

  1. 图像变换

源码首先把图像转换成 YUV,然后对三个通道分别做 Haar 小波变换 DWT。它只处理低频近似分量 CA,再将该分量切成多个 4×4 小块。

选择低频的原因是:低频信息在 JPEG 压缩、轻微噪声、亮度变化中通常比较稳定,但修改过强也更容易产生肉眼可见的失真。

  1. 每个小块做 DCT 和 SVD

每个 4×4 小块执行:

  1. DCT;

  2. 使用 password_img 生成的排列打乱 16 个 DCT 系数;

  3. 对打乱后的矩阵做 SVD;

  4. 修改前两个奇异值;

  5. 逆 SVD、逆排列、逆 DCT。

password_img 实际只是 NumPy 随机数生成器的 seed,用它为每个小块生成一个系数排列。

  1. 水印位写入奇异值余数

项目默认量化步长是:

第一奇异值:d1 = 36

第二奇异值:d2 = 20

对于水印位 ,核心操作等价于:

s'=\left(\left\lfloor\frac{s}{d}\right\rfloor+\frac14+\frac12w\right)d

因此:

bit 0 被放到一个量化区间约 1/4 的位置;

bit 1 被放到约 3/4 的位置。

提取时判断 s % d 是否超过 d/2。第二奇异值也做相同处理,最后按约 3:1 的权重合并。

这实际上是一种类似 **QIM(量化索引调制)**的编码方式。

  1. 同一个水印被反复写入

水印位不是只写一次。代码将水印循环嵌入所有可用小块,并在三个 YUV 通道中都写入:

wm_1 = self.wm_bit[i % self.wm_size]

提取时,把三个通道及所有重复位置的结果平均,以抵抗局部遮挡、噪声和部分裁剪。

水印越短,重复次数越多,通常越鲁棒;水印越长,冗余越低。

  1. 两个所谓“密码”

password_wm:只负责打乱水印 bit 的次序;

password_img:控制每个 DCT 小块内的系数排列。

水印加密本身只是调用 RandomState(password_wm).shuffle(...),不是真正的加密算法。

提取还必须知道水印长度或二维形状 wm_shape,所以这里的“盲”仅表示不需要原始图像,不表示什么参数都不需要。


二、主要安全问题

  1. 密码不是密码学密钥

项目直接把整数传给 np.random.RandomState。NumPy 官方将 RandomState 定义为旧版、固定行为的 MT19937 伪随机生成器;整数 seed 的范围最多为 0 到 2^32-1。

问题包括:

没有 Argon2、scrypt、PBKDF2 等密钥派生;

没有盐;

没有每张图片独立的随机 nonce;

同一密码会重复生成相同的排列策略;

最大整数 seed 只有 32 位;

默认值以及官方示例都是 1。

所以:

使用 1、1234、时间戳、用户 ID 等密码,基本等于没有密码;

即使使用完整随机 32 位整数,也不属于合理的现代密码学安全级别;

两个 seed 虽然可以不同,但相关攻击通常可以分阶段验证,不能简单理解为完整的 64 位安全。

  1. 覆盖攻击可以破坏原水印

攻击者不一定要恢复原密钥。只要再次运行类似的嵌入过程,就会重新量化同一批频域特征,从而破坏原来的奇异值余数关系。

项目已有 issue 报告:在已经加水印的图片上使用不同密码再次加水印,可以提取新水印,同时旧水印可能无法恢复。

讨论中也指出,二次写入本身相当于对原频域特征实施攻击。

这意味着从攻击者角度,让原水印失效通常比破解并读出水印更容易。

  1. 几何同步非常脆弱

它依赖固定的小波网格和固定 4×4 分块。一旦发生:

平移若干像素;

裁剪;

旋转;

透视变换;

非整数比例缩放;

截图时增加边框;

提取器看到的小块边界便可能和嵌入时完全错位。这类攻击称为同步攻击。

项目示例中的“抗旋转、抗裁剪”实际上常常是:

先知道旋转角度,再反向旋转;

先恢复到原始尺寸;

知道裁剪坐标,或利用原水印图片估计裁剪位置;

将裁剪区域填回原图位置后再提取。

所以 README 中的“抗旋转、裁剪”不能理解为攻击后的图片可以直接解码。

2025 年的一个独立测试 issue 也报告,直接进行 45°、180°旋转及裁剪后,提取结果出现明显错误。

  1. 转码和平台处理可以导致提取失败

实际社交平台通常会组合执行:

JPEG 重压缩;

缩放;

锐化或降噪;

色彩空间转换;

元数据和透明通道处理;

局部裁剪。

仓库 issue 中有用户报告:微信非原图传输、小红书发布以及截图后,水印无法正常解析;只有全程按原图传输才能恢复。

这说明其鲁棒性对参数、图片内容、输出格式和平台处理链高度敏感。

  1. 没有真正的“水印存在性检测”

字符串和 bit 模式提取时,代码会:

  1. 对所有位置计算一个数值;

  2. 用一维 K-means 强行分成两类;

  3. 输出 0/1 bit。

它没有:

统计显著性阈值;

相关系数门槛;

置信度;

校验和;

MAC;

数字签名;

错误检测码。

因此,给一张根本没有水印的图片,提取程序仍然会产生一串 bit。它无法严格回答:

“这张图是否确实包含由某人嵌入的水印?”

它只能回答:

“按照给定 seed 和长度,把图像特征解释成 bit 后得到什么?”

这会产生误判和选择性尝试参数的问题。

  1. 水印内容可以伪造,不能证明归属

任何人都可以把“张三版权所有”写进任意图片。算法没有私钥签名,也没有可信时间戳,更没有将水印与原始文件哈希绑定。

所以即使成功提取出某个名字,也不能单独证明:

谁先拥有图片;

谁首先嵌入;

图片是否被二次覆盖;

水印是否由权利人写入;

提取结果是否经过参数筛选。

这不是实现 bug,而是整个认证协议的缺失。

  1. 多副本合谋攻击

假如攻击者获得同一张原图的多个水印版本,例如分发给多个用户的不同编号版本,可以对这些图片逐像素或在频域中做:

平均;

中值;

差分分析;

异常值剔除。

由于该项目的嵌入是确定性的、没有每图随机化,且水印扰动集中在固定变换结构中,多副本会帮助估计无水印载体并削弱水印。

这是根据源码结构可以推导出的攻击面,不是仓库中已经证明的完整密钥恢复漏洞。


三、“破解”难度要按目标区分

攻击目标 评估

让合法提取者提取失败 较容易,二次嵌入、几何错位、转码和滤波都可能实现
覆盖成攻击者自己的水印 容易到中等
使用默认密码提取 非常容易
猜测常见整数密码 容易
从单张图片恢复强随机密码 不一定立即成功,但只有 32 位 seed,仍不符合密码学安全要求
不知道长度时恢复完整文字 难度提高,但长度不是安全密钥,可通过候选长度和文本结构测试
伪造“版权所有者”声明 容易,因为没有签名或可信登记
证明图片确实含有某个合法水印 现有接口无法提供严格统计证明

最现实的风险排序通常是:

  1. 破坏水印;

  2. 覆盖或伪造;

  3. 利用默认/弱 seed 解码;

  4. 才是完整恢复高熵 seed。


四、用于真实版权场景时怎么改

至少需要增加以下机制:

  1. 水印内容不直接写姓名
    写入随机资产 ID、版本号、时间戳、图片哈希摘要,以及这些字段的数字签名。

  2. 使用真正的密钥体系
    采用至少 128 位随机密钥;口令需经过 Argon2id 或 scrypt;通过 HKDF 派生每张图片的独立密钥。

  3. 加入每图 nonce
    避免不同图片重复使用完全相同的排列和载体位置。

  4. 加入纠错编码
    例如 BCH、LDPC 或 Reed–Solomon,加交织以抵御局部损坏。当前实现主要依靠简单重复平均。

  5. 加入同步模板或特征点配准
    在提取前使用尺度、旋转和平移不变的同步结构,而不是假设像素网格仍然对齐。

  6. 加入认证和检测分数
    输出相关性、置信度和假阳性概率;对消息验证 MAC 或数字签名,不能只是输出一串 bit。

  7. 保存外部证据链
    保存原始文件哈希、签名时间、登记记录、版本历史和分发日志。盲水印只作为辅助证据。

总体判断是:这个项目的信号处理思路合理,作为实验性鲁棒水印库有价值;但从安全工程角度,它可被移除、覆盖和伪造,密码部分也不能视为真正的加密。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions