Closed DavidBuchanan314 closed 4 months ago
It looks to me like both int_to_bytes
and KBKDF should be rejecting
length=0. Would you be interested in sending a PR for that?
On Thu, Jun 27, 2024 at 7:48 AM David Buchanan @.***> wrote:
Using cryptography version 41.0.7, installed via system package manager ( python3-cryptography on Fedora 39).
I am trying to implement the XAES-256-GCM construction, as specified here: https://github.com/C2SP/C2SP/blob/main/XAES-256-GCM.md (it combines the NIST SP 800-108r1 KDF, and AES-GCM)
As permitted by NIST SP 800-108r1, XAES-256-GCM specifies that the L field is omitted from the CMAC input. My first attempt at implementing this was to use KBKDFCMAC with llen=None. That gave me a ValueError: Please specify an llen, so then I tried llen=0, which returned a result, but not the result I was expecting:
from cryptography.hazmat.primitives.ciphers import algorithmsfrom cryptography.hazmat.primitives.kdf.kbkdf import ( CounterLocation, KBKDFCMAC, Mode )
first test vector input from https://github.com/C2SP/C2SP/blob/main/XAES-256-GCM.mdK = bytes.fromhex("0101010101010101010101010101010101010101010101010101010101010101")N = b"ABCDEFGHIJKLMNOPQRSTUVWX"
Invocation 1:# llen=0 (produces unexpected result)kdf = KBKDFCMAC(
algorithm=algorithms.AES256, mode=Mode.CounterMode, length=32, rlen=2, llen=0, location=CounterLocation.BeforeFixed, label=b"X", context=N[:12], fixed=None, )print(kdf.derive(K).hex()) # 0ac2f1727f8b128bb0b991c2ceaa600aea8128eab77a227f44c54ec235b330b0
Invocation 2:# llen=2 (produces same result as above)kdf = KBKDFCMAC(
algorithm=algorithms.AES256, mode=Mode.CounterMode, length=32, rlen=2, llen=2, location=CounterLocation.BeforeFixed, label=b"X", context=N[:12], fixed=None, )print(kdf.derive(K).hex()) # 0ac2f1727f8b128bb0b991c2ceaa600aea8128eab77a227f44c54ec235b330b0
Invocation 3:# fixed (produces expected result)kdf = KBKDFCMAC(
algorithm=algorithms.AES256, mode=Mode.CounterMode, length=32, rlen=2, llen=None, location=CounterLocation.BeforeFixed, label=None, context=None, fixed=b"X\x00" + N[:12], )print(kdf.derive(K).hex()) # c8612c9ed53fe43e8e005b828a1631a0bbcb6ab2f46514ec4f439fcfd0fa969b
I'm able to solve my problem by using the fixed parameter (as shown in "invocation 3" above), but I think the behaviour when llen=0 is unexpected/buggy.
It happens because utils.int_to_bytes is used to construct the L value, which has auto-sizing behaviour when the requested length is 0. For length=32, this produces equivalent results to passing llen=2 (as shown in "invocation 2" above)
IMHO, better behaviour would be to raise an exception when llen=0, rather than invoking this auto-sizing (I think switching from utils.int_to_bytes to regular int.to_bytes would achieve this). Technically this would be a breaking change, but I'd hope nobody is relying on it intentionally.
And, as an enhancement, it would be convenient if passing llen=None resulted in the L field being omitted entirely, as required by the XAES-256-GCM spec. This ought to be a non-breaking change, although the convenience it brings is relatively minor compared to just using the fixed parameter.
i.e.
kdf = KBKDFCMAC( algorithm=algorithms.AES256, mode=Mode.CounterMode, length=32, rlen=2, llen=None, location=CounterLocation.BeforeFixed, label=b"X", context=N[:12], fixed=None, )# current behaviour: ValueError: Please specify an llen# desired behaviour: Equivalent to "invocation 3" above
— Reply to this email directly, view it on GitHub https://github.com/pyca/cryptography/issues/11172, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAAGBAYGWANAEXCVAMX67TZJP32FAVCNFSM6AAAAABJ7YF5GCVHI2DSMVQWIX3LMV43ASLTON2WKOZSGM3TOOJTGI3DQNY . You are receiving this because you are subscribed to this thread.Message ID: @.***>
-- All that is necessary for evil to succeed is for good people to do nothing.
Would you be interested in sending a PR for that?
Yup!
Awesome!
On Thu, Jun 27, 2024 at 7:58 AM David Buchanan @.***> wrote:
Would you be interested in sending a PR for that?
Yup!
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>
-- All that is necessary for evil to succeed is for good people to do nothing.
Using
cryptography
version41.0.7
, installed via system package manager (python3-cryptography
on Fedora 39).I am trying to implement the
XAES-256-GCM
construction, as specified here: https://github.com/C2SP/C2SP/blob/main/XAES-256-GCM.md (it combines the NIST SP 800-108r1 KDF, and AES-GCM)As permitted by NIST SP 800-108r1,
XAES-256-GCM
specifies that theL
field is omitted from the CMAC input. My first attempt at implementing this was to useKBKDFCMAC
withllen=None
. That gave me aValueError: Please specify an llen
, so then I triedllen=0
, which returned a result, but not the result I was expecting:I'm able to solve my problem by using the
fixed
parameter (as shown in "invocation 3" above), but I think the behaviour whenllen=0
is unexpected/buggy.It happens because
utils.int_to_bytes
is used to construct theL
value, which has auto-sizing behaviour when the requested length is 0. Forlength=32
, this produces equivalent results to passingllen=2
(as shown in "invocation 2" above)https://github.com/pyca/cryptography/blob/986a6c22231bc5f587e9aab89d5a564b0aa80c63/src/cryptography/hazmat/primitives/kdf/kbkdf.py#L168-L174
IMHO, better behaviour would be to raise an exception when
llen=0
, rather than invoking this auto-sizing (I think switching fromutils.int_to_bytes
to regularint.to_bytes
would achieve this). Technically this would be a breaking change, but I'd hope nobody is relying on it intentionally.And, as an enhancement, it would be convenient if passing
llen=None
resulted in theL
field being omitted entirely, as required by theXAES-256-GCM
spec (and as permitted by NIST SP 800-108r1). This ought to be a non-breaking change, although the convenience it brings is relatively minor compared to just using thefixed
parameter.i.e.