DESKey 是不是保留无效的奇偶校验位?

Posted

技术标签:

【中文标题】DESKey 是不是保留无效的奇偶校验位?【英文标题】:Does DESKey preserve invalid parity bits?DESKey 是否保留无效的奇偶校验位? 【发布时间】:2017-08-15 06:20:14 【问题描述】:

根据DES规范,密钥每个字节的最后一位用于错误检测(每个字节应该有奇校验)。因此有效的密钥长度是 56 位,而不是 64 位。

但是,在许多用例中,这些奇偶校验位不会被检查。有时它们甚至用于完全不同的目的:例如,Mifare DESFire 卡将密钥版本存储在这些位中,即使最初的纠错目的丢失了。

Java Card 实现如何处理这些位?让我们看一下这段代码:

DESKey desKey = ... //a single DES key instance
byte[] inputKey = new byte[8];
inputKey[7] = (byte) 0x03; //explicitly invalid parity bit in the last byte
desKey.setKey(inputKey, (short) 0);
byte[] outputKey = new byte[8];
desKey.getKey(outputKey, (short) 0);

是否保证inputKeyoutputKey 数组最终将包含相同的数据,即使inputKey 中的奇偶校验位无效?我对几种卡类型进行了几次实验,它们都保留了我放入那些奇偶校验位的任何数据,但我在 Java Card 规范中没有发现任何提及这种行为是可以保证的。

这条信息对我来说很重要;否则我将不得不将我的“无效奇偶校验位”与密钥实例分开存储。

【问题讨论】:

我遇到了完全相同的困境,并决定将密钥版本存储在一个单独的字段中以确保安全。我也无法在规范中找到任何保证——我敢打赌,它是未定义的,因此很危险。我的卡片也完好无损地保持了奇偶校验位......祝你好运! 【参考方案1】:

如果不在规格中,则无法保证。真的就这么简单;没有针对卡实现者的单独规范另有说明(如果有,可能会在不触及原始定义的情况下发生变化)。

在攻击方面,对键的操作可能很棘手。因此,关于保持关键数据完整且不使用通用 CPU 对关键位进行迭代,有很多话要说。此外,当对密钥数据执行其他操作时可能会很棘手,例如使用散列函数计算密钥校验值或使用相同的密钥作为 MAC 的输入(对称签名)。

当然,完全可以使用您自己的代码对密钥位执行奇偶校验操作。您可以将结果与测试向量或使用 Java SecretKeyFactory 生成的键进行比较。但是,由于奇偶校验位不会在密钥计算中使用,因此只有在您想将密钥导出设备时才需要这样做。但同样请注意,对关键数据执行额外操作是危险的,可能会破坏各种安全测试/证明/认证。

请注意,大多数 Java Card 实现(或者更确切地说,底层芯片的硬件)很可能会在所有持久性(EEPROM/闪存)内存上执行校验和。密钥也很可能受到 Java Card 实现(或底层之一)的保护。因此,关于防止数据发生不可预见的变化:我不会过分担心。您不需要 DES 奇偶校验位。


好的,我想做点小事,所以这里是用于自己设置奇偶校验的 Java Card 代码(如果你不介意的话,我会让你做 for 循环和内联等等)。这些计算应该(接近)恒定时间。

/**
 * This method takes byte value <code>b</code> and then sets or unsets the least significant bit
 * of that value in such a way that the parity of <code>b</code> is odd.
 * So this method returns either <code>b</code> or <code>b ^ 1</code>.
 * 
 * @param b the byte value
 * @return <code>b</code> with DES parity
 */
public static byte makeDESParity(final byte b) 
    byte x = b;
    // trick to calculate odd parity in the lsb of x
    x ^= x >>> 4;
    x ^= x >>> 2;
    x ^= x >>> 1;
    // but we want even parity in the lsb: ~x
    // get the least significant bit: ~x & 1
    // xor that with b: ~x & 1 ^ b
    return (byte) (~x & 1 ^ b);


/**
 * This method takes byte value <code>b</code> and returns true if and only if
 * the byte has odd parity.
 * 
 * @param b the byte value
 * @return true if <code>b</code> has DES parity
 */
public static boolean hasDESParity(byte b) 
    // trick to calculate odd parity in the lsb of b
    b ^= b >>> 4;
    b ^= b >>> 2;
    b ^= b >>> 1;
    // check if last bit has indeed been set
    return (b & 1) != 0;

【讨论】:

例如,您可以做一些可怕的事情并使用表格like MBED_TLS does。哎哟 - 你好侧通道,再见了 128 字节。 感谢您的“摆弄”。使用硬编码字节数组时,我没有看到任何侧通道,您能详细说明一下吗? (恐怕这与问题无关。但是,)正如@Shuckey所说——预先计算的256字节数组是(恕我直言)有效的方法。 hasDESParity() 可能看起来像这样:return makeDESParity(b)==b; 如果内存访问触发了缓存更新,那么它可能会泄漏信息。如果表可以在内存中移动,那么每个字节值都可以单独测试。 @MaartenBodewes:你说的很有道理。我想知道这是否是实际的想法。如果您有一些关于现实世界智能卡安全控制器缓存定时攻击的链接,我将不胜感激......

以上是关于DESKey 是不是保留无效的奇偶校验位?的主要内容,如果未能解决你的问题,请参考以下文章

使用标记/空间奇偶校验和无奇偶校验有啥区别?

奇偶校验位

奇偶校验位

奇偶校验码的特点是啥?为啥说它是可靠性代码?

奇偶效验码和海明码

奇偶校验