8000 feat(ciphers+fuzz): Add experimental feature to use a keyed version of SHAKE256 instead of Blake2b. by DavidNiehues · Pull Request #581 · rosenpass/rosenpass · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat(ciphers+fuzz): Add experimental feature to use a keyed version of SHAKE256 instead of Blake2b. #581

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

DavidNiehues
Copy link
Contributor

This PR adds support for using a keyed version of SHAKE256, truncated to 32 bytes, instead of the incorrect HMAC with Blake2b as the PRF for key derivation for rosenpass.

This feature is a compile time flag as of now, namely the flag "experiment_sha3".

Since there is also fuzzing for Blake2b, this PR also disables this fuzzing if the feature "experiment_sha3" is disabled.

@koraa
Copy link
Member
koraa commented Feb 4, 2025

@DavidNiehues Can you rebase the pull request? Its set to prevent me from doing so.

Copy link
Member
@koraa koraa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good for the most part, minor comments then LGTM

@@ -1,18 +1,18 @@
#![no_main]
# ![no_main]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this file needs to be renamed then. No need to do this right now, but I think it makes sense to allow both the sha3 and broken blake2b hash functions to coexist (feature flag "hash-blake2b", "hash-sha3") to allow things like fuzzing and tests to use them directly

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, at least the file name is misleading as of now.

// we append the length of the input to the end of the input.
shake256.update(&(32u32.to_be_bytes()));
shake256.finalize_xof().read(tmp.as_mut());
copy_slice(tmp.as_ref()).to(out);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get rid of the temp variable? Copy_slice needs to assert anyway so we might also use try_into to just cast the input to a &mut [u8; 32] to feed it into finalize directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure thing. Not sure why I didn't do it that way directly.

let mut tmp = Zeroizing::new([0u8; OUT_LEN]);
// Following the NIST recommendations in Appendix A.2 of the FIPS 202 standard,
// we append the length of the input to the end of the input.
shake256.update(&(32u32.to_be_bytes()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why big endian? Is this the length of the key?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the output length and thus should also use the OUT_LEN constant. The encoding in big endian is arbitrary, it could be any other reasonable encoding of the output length just as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets use little endian then; we generally use little endian in most places in rosenpass.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

shake256.update(data);

let mut tmp = Zeroizing::new([0u8; OUT_LEN]);
// Following the NIST recommendations in Appendix A.2 of the FIPS 202 standard,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good, but then I think we need to make this part of the name of the module.

Is there any particular reason for this recommendation by the way? Sounds somewhat like cruft but I do not know.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not too familiar with this scheme, but I was curious as well so I looked up the spec:

A.2 Additional Consideration for Extendable-Output Functions
[...]
if an attacker is able to induce one of the parties to use a different value for keylength,
say 168 bits, but the same value for keymaterial, then the two parties will end up with the
following keys:
SHAKE128(keymaterial, 112) = fg
SHAKE128(keymaterial, 168) = fgh,
where the bolded letters of the digest represent 56-bit strings, e.g., the parts of a Triple DES key.
Because of the structure of Triple DES, these keys are vulnerable to attack
[...]

Source: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf (pages 24/25, i.e., 32/33 in the PDF)


Technically there's no section called "appendix", so if that's the right part you could consider linking to it? Alternatively, summarizing the reason briefly might help as well. (Otherwise, disregard my comment)

Copy link
Contributor Author
@DavidNiehues DavidNiehues Feb 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why: The reason to include this is what @phildremi quoted. Since SHAKE256 is a XOF, two outputs with different lengths but the same input will be identcal up to the length of the shorter output, which can lead to related key attacks. I am not aware of any vulnerability that would be introduced by not dong this given that rosenpass does use domain separation and only uses a fixed key and output length of 32 bytes. I added it as a safeguard to make the implementation more robust with regards to future changes. If you prefer it that way, we can of course do without incorporating the output length.

Appendix A.2 Indeed, while A.x, B.x, ... usually refers to an appendix, everywhere in the standard, it is referred to as a section. I'll thus update the reference.

pub const OUT_MAX: usize = OUT_LEN;

/// Provides a keyed hash function based on SHAKE256. To work for the protocol, the output length
/// and key length are fixed to 32 bytes (also see [KEN_LEN] and [OUT_LEN]).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// and key length are fixed to 32 bytes (also see [KEN_LEN] and [OUT_LEN]).
/// and key length are fixed to 32 bytes (also see [KEY_LEN] and [OUT_LEN]).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good find!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phildremi Thank you for the help!

@DavidNiehues DavidNiehues force-pushed the dev/david/sha-3 branch 4 times, most recently from 5046a8a to 6727fa7 Compare February 5, 2025 17:40
@aparcar aparcar self-requested a review February 11, 2025 09:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0