You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In this implementation, some test vectors have wrong inner key padding. This can be seen by looking at the decrypted data before unpadding, or even by inspecting the ciphertext (an example below). Unfortunately, I am not referring to the already malformed test vectors, but to other ones deemed valid.
It appears some implementations (for instance, Thales payShield 10k) are generating bad TR-31 cryptograms, and this implementation is not detecting this.
Perhaps a conscious decision was made in this implementation to sacrifice key length obfuscation to pass these test vectors. Or perhaps this restriction was relaxed in some paywalled document. In the former case, I suggest to document this. In the latter, I request for guidance.
Context
According to the spec [1] (Sec. 6.1 bullet 3):
If one is wrapping a 128-bit (a.k.a. 112-bit) TDEA key it SHALL be padded to 192 bits.
If one is wrapping a 128-bit or 192-bit AES key, it SHALL be padded to 256 bits.
The purpose of this, according to the standard, is to obfuscate the true length of short keys. E.g., after encryption, an attacker should not be able to tell by looking at the ciphertext whether the inner AES key is 128/192/256 bits.
Note that this does not relate to the cipher block padding (added on top of that) or the optional block padding (added in the header).
Cause
Some implementations are padding key data including the two leading length bytes as key material. This is wrong and violates the obfuscation; the attacker can deduce that this key has less than 192 bits.
This affects both wrapping of AES and TDEA keys. For instance, the 128-bit TDEA key
0102030405060708090A0B0C0D0E0F
will be padded by some implementations to 24 (2 + 22) bytes as
0080 0102030405060708090A0B0C0D0E0F XXXXXXXXXXXX
where the leading length (0x0080 = 128) was added and 6 bytes of random pading.
To achieve obfuscation it should be padded to 2 + 24 + 6 as
The attacker knows this by trimming the header B0080K0TN00N0000 and the tag F6751088F9F1C228.
Now, the attacker also knows that the decrypted data starts with 2 bytes of length, XXXX indicating the hidden length of the key. This leaves 22 bytes to fit a TDEA key, therefore it must have less than 24 bytes of key material, e.g., it is a 128-bit TDEA key.
Indeed, after decrypting this example with the given KBPK, we have
e.g., the 128-bit TDEA key 5DB50B454F8389ADCE573BE50861F2BF.
Affected test vectors
My implementation says
Skipping 'Thales payShield 10k HSM - format A' (reason: Inner TDEA key has bad padding (it is padded to 22 bytes))
Skipping 'Thales payShield 10k HSM - format B' (reason: Inner TDEA key has bad padding (it is padded to 22 bytes))
Skipping 'Thales payShield 10k HSM - format C' (reason: Inner TDEA key has bad padding (it is padded to 22 bytes))
Skipping 'TR-31:2018, A.7.2.1' (reason: Inner TDEA key has bad padding (it is padded to 22 bytes))
Skipping 'TR-31:2018, A.7.2.2' (reason: Inner TDEA key has bad padding (it is padded to 22 bytes))
Skipping 'TR-31:2018, A.7.3.1' (reason: Inner TDEA key has bad padding (it is padded to 22 bytes))
Skipping 'TR-31:2018, A.7.3.2' (reason: Inner TDEA key has bad padding (it is padded to 22 bytes))
Skipping 'TR-31:2018, A.7.4' (reason: Inner AES key has bad padding (it is padded to 30 bytes))
Thank you for taking an interest in this project and thank you for your very detailed question. My apologies for taking so long to respond.
Firstly, I would love to know more about your implementation. Can you share a URL to your implementation?
I will gladly share some thoughts regarding your questions. And I think it's worth looking at the decoding/import and the encoding/export aspects separately.
This implementation intentionally does not reject key blocks during decoding/import if there is insufficient key length obfuscation. This is because key length obfuscation is only mandatory for ANSI X9.143, but not for ASC X9 TR-31 or ISO 20038. Therefore:
It appears some implementations (for instance, Thales payShield 10k) are generating bad TR-31 cryptograms, and this implementation is not detecting this.
This is because the Thales payShield 10k generates key blocks that comply with ASC X9 TR-31, and not key blocks that comply with ANSI X9.143. I imagine that this will hopefully change in the not too distant future because the latest publications and notices about PCI PIN requirement 18-3 now refer to ANSI X9.143 where they previously referred to ASC X9 TR-31.
This is also why the test vectors that you identified as having insufficient key length obfuscation are all either from the Thales payShield 10k or from TR-31:2018.
The implementation itself also comments on why this is not strictly enforced here:
This implementation does apply the key length obfuscation separately from the cipher block padding as you indicate in your explanation. Specifically, the key length obfuscation is applied before adding the two byte length field, and the resulting length is then used to apply the cipher block padding. This can be seen here: https://github.com/openemv/tr31/blob/master/src/tr31.c#L3092
Note however that this implementation only applies key length obfuscation and not cipher block padding for format version E, in accordance with ISO 20038, because it uses an AES-CTR stream cipher instead of a block cipher.
Thank you again for your detailed question and please let me know if you found any inaccuracies or deficiencies in my implementation. I look forward to seeing your implementation as well.
Issue
In this implementation, some test vectors have wrong inner key padding. This can be seen by looking at the decrypted data before unpadding, or even by inspecting the ciphertext (an example below). Unfortunately, I am not referring to the already malformed test vectors, but to other ones deemed valid.
It appears some implementations (for instance, Thales payShield 10k) are generating bad TR-31 cryptograms, and this implementation is not detecting this.
Perhaps a conscious decision was made in this implementation to sacrifice key length obfuscation to pass these test vectors. Or perhaps this restriction was relaxed in some paywalled document. In the former case, I suggest to document this. In the latter, I request for guidance.
Context
According to the spec [1] (Sec. 6.1 bullet 3):
The purpose of this, according to the standard, is to obfuscate the true length of short keys. E.g., after encryption, an attacker should not be able to tell by looking at the ciphertext whether the inner AES key is 128/192/256 bits.
Note that this does not relate to the cipher block padding (added on top of that) or the optional block padding (added in the header).
Cause
Some implementations are padding key data including the two leading length bytes as key material. This is wrong and violates the obfuscation; the attacker can deduce that this key has less than 192 bits.
This affects both wrapping of AES and TDEA keys. For instance, the 128-bit TDEA key
will be padded by some implementations to 24 (2 + 22) bytes as
where the leading length (0x0080 = 128) was added and 6 bytes of random pading.
To achieve obfuscation it should be padded to 2 + 24 + 6 as
the intuition being, it should look like a 24-byte TDEA key padded.
Example:
Take the following cryptogram, generated by Thales payShield 10k and included in the test vectors:
By the header
However, the ciphertext before decryption is
The attacker knows this by trimming the header
B0080K0TN00N0000
and the tagF6751088F9F1C228
.Now, the attacker also knows that the decrypted data starts with 2 bytes of length,
XXXX
indicating the hidden length of the key. This leaves 22 bytes to fit a TDEA key, therefore it must have less than 24 bytes of key material, e.g., it is a 128-bit TDEA key.Indeed, after decrypting this example with the given KBPK, we have
e.g., the 128-bit TDEA key
5DB50B454F8389ADCE573BE50861F2BF
.Affected test vectors
My implementation says
[1]: ANSI X9.143-2022 - Interoperable Secure Key Block Specification
The text was updated successfully, but these errors were encountered: