code128 校验和不是加密安全的。
我认为您误解了校验和的目的。校验和旨在使检测数据读取过程中的意外损坏或错误成为可能。将数据转换为校验和,并与预期的校验和进行比较。如果两者不同,您就知道读取数据时出错了。目的是减少读取中的意外错误导致相同校验和的可能性。校验和算法本身是公开的,易于计算,比如用下面的函数,其中code128_table是一个特定的索引表(代码 A、B 或 C):
uint8_t code128_checksum(uint8_t *buf, uint32_t len)
{
uint32_t sum = *buf - 32;
while (--len)
sum += len * code128_table[*(buf + len)];
return sum % 103 + 32;
}
此校验和非常简单,仅用于在扫描过程中检测错误。这是一个“真实”的总和,这意味着它只不过是每个组成字符的表示的总和乘以权重因子。因此,总和实际上就是它所保护的数据的总和。它并非旨在为条形码提供任何类型的加密属性。它的设计方式,以下所有都是微不足道的可能,以增加计算复杂性:
- 散列- 给定一个未校验和的条形码,计算校验和。
- 碰撞- 创建两个内容不同但校验和相同的条形码。
- 第二个原像- 给定一个校验和条形码,创建另一个具有相同校验和的条形码。
- 第一个原像- 仅给定一个校验和,创建一个具有相同校验和的条形码。
它(适度)擅长的唯一一件事是确保对条形码的随机更改不会导致相同的校验和。即使这样,也不是特别好。相同摘要大小的优越(尽管仍然不是加密安全)校验和将是 CRC8,因为对于错误检测而言, CRC优于常规校验和。一个 8 位 CRC 的简单实现(其中crc8_table是精心挑选的 8 位CRC 多项式)如下所示:
uint8_t crc8(uint8_t *buf, uint32_t len)
{
uint8_t crc = ~0;
while (len--)
crc = crc8_table[crc ^ *buf++];
return crc;
}
无论您使用简单的校验和、CRC,还是更复杂且速度更慢的密码安全散列函数,如果密钥空间仅为 8 个十进制字符,并且顺序 ID 中的所有 8 个字符对公司 ID B2DS 有效,您可以,非常简单,创建所有 99,999,998 个可能的条形码,并具有匹配的关联校验和。在我自己的计算机上,一个完全未优化的实现需要 19 秒。密钥空间太小,即使使用加密安全哈希也是如此。
正如@Philipp 在评论中提到的,更好的解决方案是分发带有随机 ID 的条形码。允许每个 ID 使用有限的次数,并监控是否尝试使用具有未明确发布的 ID 的条形码。如果这样做了,那么即使在任何给定时间都有一千个有效条形码,随机条形码也只有万分之一的机会是有效的,这使得欺诈性地使用这些代码变得更加困难。