4

According to DES specification, the last bit of each byte of the secret key is used for error detection (each byte should have odd parity). Hence the effective key length is 56 bits, not 64 bits.

However, in many use cases these parity bits are not checked. Sometimes they are even used for a completely different purpose: Mifare DESFire cards store the key version in those bits, for example, even though the original error correction purpose gets lost.

How do Java Card implementations handle these bits? Let us have a look at this code:

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);

Is it guaranteed that inputKey and outputKey arrays will contain the same data in the end, even with invalid parity bits in the inputKey? I performed several experiments with a few card types and they all preserve any data I put in those parity bits, but I didn't find any mention in Java Card specification that this behaviour is guaranteed.

This piece of information is very important to me; otherwise I would have to store my "invalid parity bits" separated from the key instance.

vojta
  • 5,591
  • 2
  • 24
  • 64
  • 2
    I had exactly the same dilemma and decided to store key version in a separate field just to be sure. I was unable to find any guarantees in the specifications too -- my bet is that it is undefined, thus dangerous. My cards kept the parity bits intact too...Good luck! – vlp Aug 15 '17 at 15:43

1 Answers1

3

If it is not in the specifications then it is not guaranteed. It's really that simple; there isn't a separate specification for card implementers that says otherwise (and if there was, that might change without touching the original definition).

Operations on keys can be tricky with regard to attacks. So there is a lot to be said about keeping the key data intact and not iterate over the key bits using the generic CPU. Also, it might be tricky when other operations are performed over the key data such as calculating a Key Check Value using a hash function or for using the same key as input to a MAC (symmetric signature).

It's of course perfectly possible to perform the parity operation on the key bits using your own code. You can compare your result with test vectors or with keys generated using the Java SecretKeyFactory. However, since the parity bits don't get used in the key calculations, this would only be needed if you want to export the key out of the device. But again, note that performing additional operations on key data is dangerous and may break all kinds of security tests/proofs/certifications.

Note that most Java Card implementations (or rather, the hardware of the underlying chip) will very likely perform checksums over all the persistent (EEPROM/flash) memory anyway. It's also very likely that the keys are protected by the Java Card implementation (or one of the underlying layers). So with regards to protection against unforeseen alterations of the data: I wouldn't worry overly much. You don't need the DES parity bits for that.


OK, I felt like doing some bit fiddling, so here's the Java Card code to set the parity yourself (I'll let you do the for loop and the inlining and stuff, if you don't mind). These calculations should be (near) constant time.

/**
 * 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;
}
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • For instance, you can do something horrible and use a table [like MBED_TLS does](https://www.google.cz/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0ahUKEwjMgeTditrVAhUBthoKHYsJAkQQFggzMAE&url=https%3A%2F%2Ftls.mbed.org%2Fapi%2Fdes_8c_source.html&usg=AFQjCNFC5Um5PfILYbTQSCs9ZOdlBVGPIw). Ouch - hello side channel, bye 128 bytes for nothin'. – Maarten Bodewes Aug 15 '17 at 20:36
  • 1
    Thank you for your "bit fiddling". I do not see any side channel when using a hardcoded byte array, can you please elaborate? – Shuckey Aug 17 '17 at 11:57
  • (I am afraid this is irrelevant to the question. But,) as @Shuckey says -- pre-computed 256 byte array is (IMHO) the effective way to go. And hasDESParity() might look like this: `return makeDESParity(b)==b;` – vlp Aug 17 '17 at 13:33
  • 1
    If memory access triggers a cache update then it could leak info. If the table can be moved in memory then each byte value can be tested individually. – Maarten Bodewes Aug 17 '17 at 15:09
  • @MaartenBodewes: what you say makes sense. I wonder if this would be practical thought. If you had some link regarding some real world smart card secure controller cache timing attack I would be very grateful... – vlp Aug 17 '17 at 17:32
  • It's a common trick that is used to attack passwords and PIN values which I learned as early as the first year at university, from prof. Andy Tanenbaum no less. It's one of the reasons that Java Card has an OwnerPIN object, because it seems simple to create this functionality yourself, but it really isnt – Maarten Bodewes Aug 17 '17 at 23:14