Integrate OAEP and PSS into existing interface - #43

Merged
dignifiedquire merged 22 commits into
masterfrom
oaep-dig
Jun 11, 2020
Merged

Integrate OAEP and PSS into existing interface#43
dignifiedquire merged 22 commits into
masterfrom
oaep-dig

Conversation

@dignifiedquire

Copy link
Copy Markdown
Member

This integrates #18 and #26 by expanding the use of PaddingScheme to capture all optional values for the different schemes.

It is not ideal, but it works well and keeps in line with the existing API for now. I think we should still continue to improve on the api and think through #34 more, but in the meantime this a version that folks can start to use, and isn't too different from the existing api

This was referenced Mar 6, 2020
@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, pulling in 2462f1d from #18 goes in the opposite direction to #42. It looks like the main thing it does (remove PublicKey trait) is not present in the overall PR, and I can't find where that is undone, but I think it's in the refactor commit? GitHub isn't helping much here. There are other effects of that commit that are not undone (in particular, it makes public keys non-generic in pkcs1v15, the opposite of what I've done in #44).

How painful would it be to just drop that commit entirely? It would likely make the history clearer.

@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, the change in that commit to store an RSAPublicKey inside RSAPrivateKey does make sense to me. I'd personally alter that commit to only contain the pieces we want, but that's probably more hassle than it's worth, so just reverting changes we don't want is probably fine.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

Yeah, I changed a lot of things during the merge, which is..unfortunate. So at this point I am thinking of squashing this into two commits at the end likely (1) for oaep and (2) for pss, after doing/undoing all things we want to do.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d I made the OAEP and PSS impls generic over the Key traits now

@roblablaroblabla left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey that looks great! I have a couple suggestions

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/padding.rs
write!(f, "PaddingScheme::PKCS1v15({:?})", hash)
}
PaddingScheme::OAEP { ref label, .. } => {
// TODO: How to print the digest name?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could make it Box<dyn DynDigest + Debug> if really necessary. AFAIK all the digest crates have debug unconditionally implemented on them.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

that doesn't work, the compiler is upset about more than one non auto trait :(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ah right, it's possible to make your own trait (e.g. trait MyDynDigest: DynDigest + Debug {}) and then use that as a Box<dyn MyDynDigest>, but at this point it's too much boilerplate just for the sake of getting the digest name to show IMO.

Comment threadsrc/padding.rs Outdated
Comment threadCargo.toml Outdated
@tarcieri

Copy link
Copy Markdown
Member

Relevant to the PSS use case: final two week comment period for shipping signature 1.0: RustCrypto/traits#78

Comment threadsrc/key.rs
}
}

impl Deref for RSAPrivateKey {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Now that we have PrivateKey: PublicKeyParts, this impl Deref should be removed.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Not quite, removing this, removes the ability to call .verify on a private key

Comment threadsrc/key.rs Outdated
Comment threadsrc/raw.rs
Comment on lines +31 to +33
if pad_size < ciphertext.len() {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this check also be in raw_decryption_primitive?

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d thanks for the review, I think I addressed all important things

Comment threadsrc/padding.rs
/// Encryption and Decryption using PKCS1v15 padding.
PKCS1v15Encrypt,
/// Sign and Verify using PKCS1v15 padding.
PKCS1v15Sign { hash: Option<Hash> },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The hash: None case appears to still be necessary for unpadded signatures (at least, that's what the test case in src/pkcs1v15.rs leads me to believe).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, which is why it is still an Option, not sure what you mean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I was just noting this because it wasn't immediately obvious during review that the Option<Hash> was necessary besides enabling the prior encryption case to specify None.

Comment threadsrc/algorithms.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSAES-OAEP implementation, comparing it against RFC 8017 section 7.1.

Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
dignifiedquireand others added 2 commits April 11, 2020 14:35
Co-Authored-By: str4d <thestr4d@gmail.com>
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d applied the new round of CR

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These are causing the current CI failure.

Comment threadbenches/key.rs Outdated
Comment threadbenches/key.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSASSA-PSS implementation. The relevant sections of RFC 8017 were already inlined as comments.

Comment threadsrc/pss.rs
Comment on lines +193 to +201
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {
(Some(i), _) => Ok(Some(i)),
(_, 1) => Ok(Some(i)),
(_, 0) => Ok(None),
_ => Err(Error::Verification),
})?
.ok_or(Error::Verification)?,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for detecting the salt length? I know it is possible due to the structure of DB, but there is no mention of doing so in RFC 8017. I can't read the IEEE documents that reference different possible salt lengths, which maybe discusses this. As is, we never exercise the explicit-salt-length case below.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I don't know @roblabla I believe you wrote this code initially, do you have any answer to this?

Comment threadsrc/pss.rs
salt_len: Option<usize>,
digest: &mut dyn DynDigest,
) -> Result<Vec<u8>> {
let salt_len = salt_len.unwrap_or_else(|| priv_key.size() - 2 - digest.output_size());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for this default salt length? The RFC mentions that common choices are digest.output_size() and 0, while this is selecting the salt to be as large as could fit. I can't read the IEEE documents that reference different possible salt lengths. In any case, I don't think there's a problem with this, given that we are detecting the salt length in verify.

Comment threadsrc/pss.rs
Comment on lines +78 to +80
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "message too
// long" and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs
Comment on lines +149 to +151
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "inconsistent"
// and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs Outdated
// 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
// let H be the next hLen octets.
let (db, h) = em.split_at_mut(em_len - h_len - 1);
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This would be clearer (and closer to the spec):

Suggested change
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];
let h = &mut h[..h_len];

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +193 to +195
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match(state, db[em_len - h_len - i - 2]){
None => (0..em_len - h_len - 1)
.try_fold(None, |state, i| match(state, db[i]){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

this change results in failures, haven't debugged why, gonna leave the logic as is for now

Comment threadsrc/pss.rs Outdated
Comment on lines +207 to +214
for e in &db[..em_len - h_len - s_len - 2] {
if *e != 0x00 {
return Err(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01 {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
for e in&db[..em_len - h_len - s_len - 2]{
if*e != 0x00{
returnErr(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01{
returnErr(Error::Verification);
}
let(zeroes, rest) = db.split_at(em_len - h_len - s_len - 2);
if zeroes.iter().any(|e| *e != 0x00) || rest[0] != 0x01{
returnErr(Error::Verification);
}

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
let h0 = hash.result_reset();

// 14. If H = H', output "consistent." Otherwise, output "inconsistent."
if Into::<bool>::into(h0.ct_eq(h)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
ifInto::<bool>::into(h0.ct_eq(h)){
if h0.ct_eq(h).into(){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
return Err(Error::Internal);
}

let (db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
let(db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);
let(db, h) = em.split_at_mut(em_len - h_len - 1);

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +122 to +125
// 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
// emLen - hLen - 1.
db[em_len - s_len - h_len - 2] = 0x01;
db[em_len - s_len - h_len - 1..].copy_from_slice(salt);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're assuming here that the em buffer passed into emsa_pss_encode is already zeroed. This happens to be the case, but given that emsa_pss_encode is only called from one place, and this PR isn't attempting to be no-std compatible, it would be clearer if em was constructed and returned from this function. Non-blocking.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

@str4dstr4d mentioned this pull request Jun 10, 2020
@dignifiedquire
dignifiedquire merged commit 3bd9795 into masterJun 11, 2020
@dignifiedquire
dignifiedquire deleted the oaep-dig branch June 11, 2020 11:58
takumi-earth pushed a commit to earthlings-dev/RSA that referenced this pull request Jan 27, 2026
Sign up for freeto 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.

5 participants

@dignifiedquire@str4d@tarcieri@roblabla@lucdew
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Integrate OAEP and PSS into existing interface - #43

Merged
dignifiedquire merged 22 commits into
masterfrom
oaep-dig
Jun 11, 2020
Merged

Integrate OAEP and PSS into existing interface#43
dignifiedquire merged 22 commits into
masterfrom
oaep-dig

Conversation

@dignifiedquire

Copy link
Copy Markdown
Member

This integrates #18 and #26 by expanding the use of PaddingScheme to capture all optional values for the different schemes.

It is not ideal, but it works well and keeps in line with the existing API for now. I think we should still continue to improve on the api and think through #34 more, but in the meantime this a version that folks can start to use, and isn't too different from the existing api

This was referenced Mar 6, 2020
@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, pulling in 2462f1d from #18 goes in the opposite direction to #42. It looks like the main thing it does (remove PublicKey trait) is not present in the overall PR, and I can't find where that is undone, but I think it's in the refactor commit? GitHub isn't helping much here. There are other effects of that commit that are not undone (in particular, it makes public keys non-generic in pkcs1v15, the opposite of what I've done in #44).

How painful would it be to just drop that commit entirely? It would likely make the history clearer.

@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, the change in that commit to store an RSAPublicKey inside RSAPrivateKey does make sense to me. I'd personally alter that commit to only contain the pieces we want, but that's probably more hassle than it's worth, so just reverting changes we don't want is probably fine.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

Yeah, I changed a lot of things during the merge, which is..unfortunate. So at this point I am thinking of squashing this into two commits at the end likely (1) for oaep and (2) for pss, after doing/undoing all things we want to do.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d I made the OAEP and PSS impls generic over the Key traits now

@roblablaroblabla left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey that looks great! I have a couple suggestions

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/padding.rs
write!(f, "PaddingScheme::PKCS1v15({:?})", hash)
}
PaddingScheme::OAEP { ref label, .. } => {
// TODO: How to print the digest name?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could make it Box<dyn DynDigest + Debug> if really necessary. AFAIK all the digest crates have debug unconditionally implemented on them.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

that doesn't work, the compiler is upset about more than one non auto trait :(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ah right, it's possible to make your own trait (e.g. trait MyDynDigest: DynDigest + Debug {}) and then use that as a Box<dyn MyDynDigest>, but at this point it's too much boilerplate just for the sake of getting the digest name to show IMO.

Comment threadsrc/padding.rs Outdated
Comment threadCargo.toml Outdated
@tarcieri

Copy link
Copy Markdown
Member

Relevant to the PSS use case: final two week comment period for shipping signature 1.0: RustCrypto/traits#78

Comment threadsrc/key.rs
}
}

impl Deref for RSAPrivateKey {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Now that we have PrivateKey: PublicKeyParts, this impl Deref should be removed.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Not quite, removing this, removes the ability to call .verify on a private key

Comment threadsrc/key.rs Outdated
Comment threadsrc/raw.rs
Comment on lines +31 to +33
if pad_size < ciphertext.len() {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this check also be in raw_decryption_primitive?

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d thanks for the review, I think I addressed all important things

Comment threadsrc/padding.rs
/// Encryption and Decryption using PKCS1v15 padding.
PKCS1v15Encrypt,
/// Sign and Verify using PKCS1v15 padding.
PKCS1v15Sign { hash: Option<Hash> },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The hash: None case appears to still be necessary for unpadded signatures (at least, that's what the test case in src/pkcs1v15.rs leads me to believe).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, which is why it is still an Option, not sure what you mean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I was just noting this because it wasn't immediately obvious during review that the Option<Hash> was necessary besides enabling the prior encryption case to specify None.

Comment threadsrc/algorithms.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSAES-OAEP implementation, comparing it against RFC 8017 section 7.1.

Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
dignifiedquireand others added 2 commits April 11, 2020 14:35
Co-Authored-By: str4d <thestr4d@gmail.com>
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d applied the new round of CR

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These are causing the current CI failure.

Comment threadbenches/key.rs Outdated
Comment threadbenches/key.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSASSA-PSS implementation. The relevant sections of RFC 8017 were already inlined as comments.

Comment threadsrc/pss.rs
Comment on lines +193 to +201
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {
(Some(i), _) => Ok(Some(i)),
(_, 1) => Ok(Some(i)),
(_, 0) => Ok(None),
_ => Err(Error::Verification),
})?
.ok_or(Error::Verification)?,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for detecting the salt length? I know it is possible due to the structure of DB, but there is no mention of doing so in RFC 8017. I can't read the IEEE documents that reference different possible salt lengths, which maybe discusses this. As is, we never exercise the explicit-salt-length case below.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I don't know @roblabla I believe you wrote this code initially, do you have any answer to this?

Comment threadsrc/pss.rs
salt_len: Option<usize>,
digest: &mut dyn DynDigest,
) -> Result<Vec<u8>> {
let salt_len = salt_len.unwrap_or_else(|| priv_key.size() - 2 - digest.output_size());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for this default salt length? The RFC mentions that common choices are digest.output_size() and 0, while this is selecting the salt to be as large as could fit. I can't read the IEEE documents that reference different possible salt lengths. In any case, I don't think there's a problem with this, given that we are detecting the salt length in verify.

Comment threadsrc/pss.rs
Comment on lines +78 to +80
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "message too
// long" and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs
Comment on lines +149 to +151
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "inconsistent"
// and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs Outdated
// 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
// let H be the next hLen octets.
let (db, h) = em.split_at_mut(em_len - h_len - 1);
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This would be clearer (and closer to the spec):

Suggested change
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];
let h = &mut h[..h_len];

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +193 to +195
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match(state, db[em_len - h_len - i - 2]){
None => (0..em_len - h_len - 1)
.try_fold(None, |state, i| match(state, db[i]){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

this change results in failures, haven't debugged why, gonna leave the logic as is for now

Comment threadsrc/pss.rs Outdated
Comment on lines +207 to +214
for e in &db[..em_len - h_len - s_len - 2] {
if *e != 0x00 {
return Err(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01 {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
for e in&db[..em_len - h_len - s_len - 2]{
if*e != 0x00{
returnErr(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01{
returnErr(Error::Verification);
}
let(zeroes, rest) = db.split_at(em_len - h_len - s_len - 2);
if zeroes.iter().any(|e| *e != 0x00) || rest[0] != 0x01{
returnErr(Error::Verification);
}

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
let h0 = hash.result_reset();

// 14. If H = H', output "consistent." Otherwise, output "inconsistent."
if Into::<bool>::into(h0.ct_eq(h)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
ifInto::<bool>::into(h0.ct_eq(h)){
if h0.ct_eq(h).into(){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
return Err(Error::Internal);
}

let (db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
let(db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);
let(db, h) = em.split_at_mut(em_len - h_len - 1);

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +122 to +125
// 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
// emLen - hLen - 1.
db[em_len - s_len - h_len - 2] = 0x01;
db[em_len - s_len - h_len - 1..].copy_from_slice(salt);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're assuming here that the em buffer passed into emsa_pss_encode is already zeroed. This happens to be the case, but given that emsa_pss_encode is only called from one place, and this PR isn't attempting to be no-std compatible, it would be clearer if em was constructed and returned from this function. Non-blocking.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

@str4dstr4d mentioned this pull request Jun 10, 2020
@dignifiedquire
dignifiedquire merged commit 3bd9795 into masterJun 11, 2020
@dignifiedquire
dignifiedquire deleted the oaep-dig branch June 11, 2020 11:58
takumi-earth pushed a commit to earthlings-dev/RSA that referenced this pull request Jan 27, 2026
Sign up for freeto 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.

5 participants

@dignifiedquire@str4d@tarcieri@roblabla@lucdew
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Integrate OAEP and PSS into existing interface - #43

Merged
dignifiedquire merged 22 commits into
masterfrom
oaep-dig
Jun 11, 2020
Merged

Integrate OAEP and PSS into existing interface#43
dignifiedquire merged 22 commits into
masterfrom
oaep-dig

Conversation

@dignifiedquire

Copy link
Copy Markdown
Member

This integrates #18 and #26 by expanding the use of PaddingScheme to capture all optional values for the different schemes.

It is not ideal, but it works well and keeps in line with the existing API for now. I think we should still continue to improve on the api and think through #34 more, but in the meantime this a version that folks can start to use, and isn't too different from the existing api

This was referenced Mar 6, 2020
@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, pulling in 2462f1d from #18 goes in the opposite direction to #42. It looks like the main thing it does (remove PublicKey trait) is not present in the overall PR, and I can't find where that is undone, but I think it's in the refactor commit? GitHub isn't helping much here. There are other effects of that commit that are not undone (in particular, it makes public keys non-generic in pkcs1v15, the opposite of what I've done in #44).

How painful would it be to just drop that commit entirely? It would likely make the history clearer.

@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, the change in that commit to store an RSAPublicKey inside RSAPrivateKey does make sense to me. I'd personally alter that commit to only contain the pieces we want, but that's probably more hassle than it's worth, so just reverting changes we don't want is probably fine.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

Yeah, I changed a lot of things during the merge, which is..unfortunate. So at this point I am thinking of squashing this into two commits at the end likely (1) for oaep and (2) for pss, after doing/undoing all things we want to do.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d I made the OAEP and PSS impls generic over the Key traits now

@roblablaroblabla left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey that looks great! I have a couple suggestions

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/padding.rs
write!(f, "PaddingScheme::PKCS1v15({:?})", hash)
}
PaddingScheme::OAEP { ref label, .. } => {
// TODO: How to print the digest name?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could make it Box<dyn DynDigest + Debug> if really necessary. AFAIK all the digest crates have debug unconditionally implemented on them.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

that doesn't work, the compiler is upset about more than one non auto trait :(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ah right, it's possible to make your own trait (e.g. trait MyDynDigest: DynDigest + Debug {}) and then use that as a Box<dyn MyDynDigest>, but at this point it's too much boilerplate just for the sake of getting the digest name to show IMO.

Comment threadsrc/padding.rs Outdated
Comment threadCargo.toml Outdated
@tarcieri

Copy link
Copy Markdown
Member

Relevant to the PSS use case: final two week comment period for shipping signature 1.0: RustCrypto/traits#78

Comment threadsrc/key.rs
}
}

impl Deref for RSAPrivateKey {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Now that we have PrivateKey: PublicKeyParts, this impl Deref should be removed.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Not quite, removing this, removes the ability to call .verify on a private key

Comment threadsrc/key.rs Outdated
Comment threadsrc/raw.rs
Comment on lines +31 to +33
if pad_size < ciphertext.len() {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this check also be in raw_decryption_primitive?

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d thanks for the review, I think I addressed all important things

Comment threadsrc/padding.rs
/// Encryption and Decryption using PKCS1v15 padding.
PKCS1v15Encrypt,
/// Sign and Verify using PKCS1v15 padding.
PKCS1v15Sign { hash: Option<Hash> },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The hash: None case appears to still be necessary for unpadded signatures (at least, that's what the test case in src/pkcs1v15.rs leads me to believe).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, which is why it is still an Option, not sure what you mean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I was just noting this because it wasn't immediately obvious during review that the Option<Hash> was necessary besides enabling the prior encryption case to specify None.

Comment threadsrc/algorithms.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSAES-OAEP implementation, comparing it against RFC 8017 section 7.1.

Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
dignifiedquireand others added 2 commits April 11, 2020 14:35
Co-Authored-By: str4d <thestr4d@gmail.com>
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d applied the new round of CR

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These are causing the current CI failure.

Comment threadbenches/key.rs Outdated
Comment threadbenches/key.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSASSA-PSS implementation. The relevant sections of RFC 8017 were already inlined as comments.

Comment threadsrc/pss.rs
Comment on lines +193 to +201
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {
(Some(i), _) => Ok(Some(i)),
(_, 1) => Ok(Some(i)),
(_, 0) => Ok(None),
_ => Err(Error::Verification),
})?
.ok_or(Error::Verification)?,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for detecting the salt length? I know it is possible due to the structure of DB, but there is no mention of doing so in RFC 8017. I can't read the IEEE documents that reference different possible salt lengths, which maybe discusses this. As is, we never exercise the explicit-salt-length case below.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I don't know @roblabla I believe you wrote this code initially, do you have any answer to this?

Comment threadsrc/pss.rs
salt_len: Option<usize>,
digest: &mut dyn DynDigest,
) -> Result<Vec<u8>> {
let salt_len = salt_len.unwrap_or_else(|| priv_key.size() - 2 - digest.output_size());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for this default salt length? The RFC mentions that common choices are digest.output_size() and 0, while this is selecting the salt to be as large as could fit. I can't read the IEEE documents that reference different possible salt lengths. In any case, I don't think there's a problem with this, given that we are detecting the salt length in verify.

Comment threadsrc/pss.rs
Comment on lines +78 to +80
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "message too
// long" and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs
Comment on lines +149 to +151
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "inconsistent"
// and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs Outdated
// 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
// let H be the next hLen octets.
let (db, h) = em.split_at_mut(em_len - h_len - 1);
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This would be clearer (and closer to the spec):

Suggested change
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];
let h = &mut h[..h_len];

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +193 to +195
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match(state, db[em_len - h_len - i - 2]){
None => (0..em_len - h_len - 1)
.try_fold(None, |state, i| match(state, db[i]){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

this change results in failures, haven't debugged why, gonna leave the logic as is for now

Comment threadsrc/pss.rs Outdated
Comment on lines +207 to +214
for e in &db[..em_len - h_len - s_len - 2] {
if *e != 0x00 {
return Err(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01 {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
for e in&db[..em_len - h_len - s_len - 2]{
if*e != 0x00{
returnErr(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01{
returnErr(Error::Verification);
}
let(zeroes, rest) = db.split_at(em_len - h_len - s_len - 2);
if zeroes.iter().any(|e| *e != 0x00) || rest[0] != 0x01{
returnErr(Error::Verification);
}

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
let h0 = hash.result_reset();

// 14. If H = H', output "consistent." Otherwise, output "inconsistent."
if Into::<bool>::into(h0.ct_eq(h)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
ifInto::<bool>::into(h0.ct_eq(h)){
if h0.ct_eq(h).into(){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
return Err(Error::Internal);
}

let (db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
let(db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);
let(db, h) = em.split_at_mut(em_len - h_len - 1);

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +122 to +125
// 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
// emLen - hLen - 1.
db[em_len - s_len - h_len - 2] = 0x01;
db[em_len - s_len - h_len - 1..].copy_from_slice(salt);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're assuming here that the em buffer passed into emsa_pss_encode is already zeroed. This happens to be the case, but given that emsa_pss_encode is only called from one place, and this PR isn't attempting to be no-std compatible, it would be clearer if em was constructed and returned from this function. Non-blocking.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

@str4dstr4d mentioned this pull request Jun 10, 2020
@dignifiedquire
dignifiedquire merged commit 3bd9795 into masterJun 11, 2020
@dignifiedquire
dignifiedquire deleted the oaep-dig branch June 11, 2020 11:58
takumi-earth pushed a commit to earthlings-dev/RSA that referenced this pull request Jan 27, 2026
Sign up for freeto 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.

5 participants

@dignifiedquire@str4d@tarcieri@roblabla@lucdew
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Integrate OAEP and PSS into existing interface - #43

Merged
dignifiedquire merged 22 commits into
masterfrom
oaep-dig
Jun 11, 2020
Merged

Integrate OAEP and PSS into existing interface#43
dignifiedquire merged 22 commits into
masterfrom
oaep-dig

Conversation

@dignifiedquire

Copy link
Copy Markdown
Member

This integrates #18 and #26 by expanding the use of PaddingScheme to capture all optional values for the different schemes.

It is not ideal, but it works well and keeps in line with the existing API for now. I think we should still continue to improve on the api and think through #34 more, but in the meantime this a version that folks can start to use, and isn't too different from the existing api

This was referenced Mar 6, 2020
@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, pulling in 2462f1d from #18 goes in the opposite direction to #42. It looks like the main thing it does (remove PublicKey trait) is not present in the overall PR, and I can't find where that is undone, but I think it's in the refactor commit? GitHub isn't helping much here. There are other effects of that commit that are not undone (in particular, it makes public keys non-generic in pkcs1v15, the opposite of what I've done in #44).

How painful would it be to just drop that commit entirely? It would likely make the history clearer.

@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, the change in that commit to store an RSAPublicKey inside RSAPrivateKey does make sense to me. I'd personally alter that commit to only contain the pieces we want, but that's probably more hassle than it's worth, so just reverting changes we don't want is probably fine.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

Yeah, I changed a lot of things during the merge, which is..unfortunate. So at this point I am thinking of squashing this into two commits at the end likely (1) for oaep and (2) for pss, after doing/undoing all things we want to do.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d I made the OAEP and PSS impls generic over the Key traits now

@roblablaroblabla left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey that looks great! I have a couple suggestions

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/padding.rs
write!(f, "PaddingScheme::PKCS1v15({:?})", hash)
}
PaddingScheme::OAEP { ref label, .. } => {
// TODO: How to print the digest name?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could make it Box<dyn DynDigest + Debug> if really necessary. AFAIK all the digest crates have debug unconditionally implemented on them.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

that doesn't work, the compiler is upset about more than one non auto trait :(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ah right, it's possible to make your own trait (e.g. trait MyDynDigest: DynDigest + Debug {}) and then use that as a Box<dyn MyDynDigest>, but at this point it's too much boilerplate just for the sake of getting the digest name to show IMO.

Comment threadsrc/padding.rs Outdated
Comment threadCargo.toml Outdated
@tarcieri

Copy link
Copy Markdown
Member

Relevant to the PSS use case: final two week comment period for shipping signature 1.0: RustCrypto/traits#78

Comment threadsrc/key.rs
}
}

impl Deref for RSAPrivateKey {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Now that we have PrivateKey: PublicKeyParts, this impl Deref should be removed.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Not quite, removing this, removes the ability to call .verify on a private key

Comment threadsrc/key.rs Outdated
Comment threadsrc/raw.rs
Comment on lines +31 to +33
if pad_size < ciphertext.len() {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this check also be in raw_decryption_primitive?

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d thanks for the review, I think I addressed all important things

Comment threadsrc/padding.rs
/// Encryption and Decryption using PKCS1v15 padding.
PKCS1v15Encrypt,
/// Sign and Verify using PKCS1v15 padding.
PKCS1v15Sign { hash: Option<Hash> },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The hash: None case appears to still be necessary for unpadded signatures (at least, that's what the test case in src/pkcs1v15.rs leads me to believe).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, which is why it is still an Option, not sure what you mean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I was just noting this because it wasn't immediately obvious during review that the Option<Hash> was necessary besides enabling the prior encryption case to specify None.

Comment threadsrc/algorithms.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSAES-OAEP implementation, comparing it against RFC 8017 section 7.1.

Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
dignifiedquireand others added 2 commits April 11, 2020 14:35
Co-Authored-By: str4d <thestr4d@gmail.com>
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d applied the new round of CR

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These are causing the current CI failure.

Comment threadbenches/key.rs Outdated
Comment threadbenches/key.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSASSA-PSS implementation. The relevant sections of RFC 8017 were already inlined as comments.

Comment threadsrc/pss.rs
Comment on lines +193 to +201
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {
(Some(i), _) => Ok(Some(i)),
(_, 1) => Ok(Some(i)),
(_, 0) => Ok(None),
_ => Err(Error::Verification),
})?
.ok_or(Error::Verification)?,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for detecting the salt length? I know it is possible due to the structure of DB, but there is no mention of doing so in RFC 8017. I can't read the IEEE documents that reference different possible salt lengths, which maybe discusses this. As is, we never exercise the explicit-salt-length case below.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I don't know @roblabla I believe you wrote this code initially, do you have any answer to this?

Comment threadsrc/pss.rs
salt_len: Option<usize>,
digest: &mut dyn DynDigest,
) -> Result<Vec<u8>> {
let salt_len = salt_len.unwrap_or_else(|| priv_key.size() - 2 - digest.output_size());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for this default salt length? The RFC mentions that common choices are digest.output_size() and 0, while this is selecting the salt to be as large as could fit. I can't read the IEEE documents that reference different possible salt lengths. In any case, I don't think there's a problem with this, given that we are detecting the salt length in verify.

Comment threadsrc/pss.rs
Comment on lines +78 to +80
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "message too
// long" and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs
Comment on lines +149 to +151
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "inconsistent"
// and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs Outdated
// 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
// let H be the next hLen octets.
let (db, h) = em.split_at_mut(em_len - h_len - 1);
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This would be clearer (and closer to the spec):

Suggested change
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];
let h = &mut h[..h_len];

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +193 to +195
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match(state, db[em_len - h_len - i - 2]){
None => (0..em_len - h_len - 1)
.try_fold(None, |state, i| match(state, db[i]){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

this change results in failures, haven't debugged why, gonna leave the logic as is for now

Comment threadsrc/pss.rs Outdated
Comment on lines +207 to +214
for e in &db[..em_len - h_len - s_len - 2] {
if *e != 0x00 {
return Err(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01 {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
for e in&db[..em_len - h_len - s_len - 2]{
if*e != 0x00{
returnErr(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01{
returnErr(Error::Verification);
}
let(zeroes, rest) = db.split_at(em_len - h_len - s_len - 2);
if zeroes.iter().any(|e| *e != 0x00) || rest[0] != 0x01{
returnErr(Error::Verification);
}

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
let h0 = hash.result_reset();

// 14. If H = H', output "consistent." Otherwise, output "inconsistent."
if Into::<bool>::into(h0.ct_eq(h)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
ifInto::<bool>::into(h0.ct_eq(h)){
if h0.ct_eq(h).into(){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
return Err(Error::Internal);
}

let (db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
let(db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);
let(db, h) = em.split_at_mut(em_len - h_len - 1);

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +122 to +125
// 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
// emLen - hLen - 1.
db[em_len - s_len - h_len - 2] = 0x01;
db[em_len - s_len - h_len - 1..].copy_from_slice(salt);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're assuming here that the em buffer passed into emsa_pss_encode is already zeroed. This happens to be the case, but given that emsa_pss_encode is only called from one place, and this PR isn't attempting to be no-std compatible, it would be clearer if em was constructed and returned from this function. Non-blocking.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

@str4dstr4d mentioned this pull request Jun 10, 2020
@dignifiedquire
dignifiedquire merged commit 3bd9795 into masterJun 11, 2020
@dignifiedquire
dignifiedquire deleted the oaep-dig branch June 11, 2020 11:58
takumi-earth pushed a commit to earthlings-dev/RSA that referenced this pull request Jan 27, 2026
Sign up for freeto 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.

5 participants

@dignifiedquire@str4d@tarcieri@roblabla@lucdew
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Integrate OAEP and PSS into existing interface - #43

Merged
dignifiedquire merged 22 commits into
masterfrom
oaep-dig
Jun 11, 2020
Merged

Integrate OAEP and PSS into existing interface#43
dignifiedquire merged 22 commits into
masterfrom
oaep-dig

Conversation

@dignifiedquire

Copy link
Copy Markdown
Member

This integrates #18 and #26 by expanding the use of PaddingScheme to capture all optional values for the different schemes.

It is not ideal, but it works well and keeps in line with the existing API for now. I think we should still continue to improve on the api and think through #34 more, but in the meantime this a version that folks can start to use, and isn't too different from the existing api

This was referenced Mar 6, 2020
@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, pulling in 2462f1d from #18 goes in the opposite direction to #42. It looks like the main thing it does (remove PublicKey trait) is not present in the overall PR, and I can't find where that is undone, but I think it's in the refactor commit? GitHub isn't helping much here. There are other effects of that commit that are not undone (in particular, it makes public keys non-generic in pkcs1v15, the opposite of what I've done in #44).

How painful would it be to just drop that commit entirely? It would likely make the history clearer.

@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, the change in that commit to store an RSAPublicKey inside RSAPrivateKey does make sense to me. I'd personally alter that commit to only contain the pieces we want, but that's probably more hassle than it's worth, so just reverting changes we don't want is probably fine.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

Yeah, I changed a lot of things during the merge, which is..unfortunate. So at this point I am thinking of squashing this into two commits at the end likely (1) for oaep and (2) for pss, after doing/undoing all things we want to do.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d I made the OAEP and PSS impls generic over the Key traits now

@roblablaroblabla left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey that looks great! I have a couple suggestions

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/padding.rs
write!(f, "PaddingScheme::PKCS1v15({:?})", hash)
}
PaddingScheme::OAEP { ref label, .. } => {
// TODO: How to print the digest name?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could make it Box<dyn DynDigest + Debug> if really necessary. AFAIK all the digest crates have debug unconditionally implemented on them.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

that doesn't work, the compiler is upset about more than one non auto trait :(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ah right, it's possible to make your own trait (e.g. trait MyDynDigest: DynDigest + Debug {}) and then use that as a Box<dyn MyDynDigest>, but at this point it's too much boilerplate just for the sake of getting the digest name to show IMO.

Comment threadsrc/padding.rs Outdated
Comment threadCargo.toml Outdated
@tarcieri

Copy link
Copy Markdown
Member

Relevant to the PSS use case: final two week comment period for shipping signature 1.0: RustCrypto/traits#78

Comment threadsrc/key.rs
}
}

impl Deref for RSAPrivateKey {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Now that we have PrivateKey: PublicKeyParts, this impl Deref should be removed.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Not quite, removing this, removes the ability to call .verify on a private key

Comment threadsrc/key.rs Outdated
Comment threadsrc/raw.rs
Comment on lines +31 to +33
if pad_size < ciphertext.len() {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this check also be in raw_decryption_primitive?

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d thanks for the review, I think I addressed all important things

Comment threadsrc/padding.rs
/// Encryption and Decryption using PKCS1v15 padding.
PKCS1v15Encrypt,
/// Sign and Verify using PKCS1v15 padding.
PKCS1v15Sign { hash: Option<Hash> },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The hash: None case appears to still be necessary for unpadded signatures (at least, that's what the test case in src/pkcs1v15.rs leads me to believe).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, which is why it is still an Option, not sure what you mean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I was just noting this because it wasn't immediately obvious during review that the Option<Hash> was necessary besides enabling the prior encryption case to specify None.

Comment threadsrc/algorithms.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSAES-OAEP implementation, comparing it against RFC 8017 section 7.1.

Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
dignifiedquireand others added 2 commits April 11, 2020 14:35
Co-Authored-By: str4d <thestr4d@gmail.com>
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d applied the new round of CR

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These are causing the current CI failure.

Comment threadbenches/key.rs Outdated
Comment threadbenches/key.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSASSA-PSS implementation. The relevant sections of RFC 8017 were already inlined as comments.

Comment threadsrc/pss.rs
Comment on lines +193 to +201
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {
(Some(i), _) => Ok(Some(i)),
(_, 1) => Ok(Some(i)),
(_, 0) => Ok(None),
_ => Err(Error::Verification),
})?
.ok_or(Error::Verification)?,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for detecting the salt length? I know it is possible due to the structure of DB, but there is no mention of doing so in RFC 8017. I can't read the IEEE documents that reference different possible salt lengths, which maybe discusses this. As is, we never exercise the explicit-salt-length case below.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I don't know @roblabla I believe you wrote this code initially, do you have any answer to this?

Comment threadsrc/pss.rs
salt_len: Option<usize>,
digest: &mut dyn DynDigest,
) -> Result<Vec<u8>> {
let salt_len = salt_len.unwrap_or_else(|| priv_key.size() - 2 - digest.output_size());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for this default salt length? The RFC mentions that common choices are digest.output_size() and 0, while this is selecting the salt to be as large as could fit. I can't read the IEEE documents that reference different possible salt lengths. In any case, I don't think there's a problem with this, given that we are detecting the salt length in verify.

Comment threadsrc/pss.rs
Comment on lines +78 to +80
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "message too
// long" and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs
Comment on lines +149 to +151
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "inconsistent"
// and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs Outdated
// 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
// let H be the next hLen octets.
let (db, h) = em.split_at_mut(em_len - h_len - 1);
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This would be clearer (and closer to the spec):

Suggested change
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];
let h = &mut h[..h_len];

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +193 to +195
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match(state, db[em_len - h_len - i - 2]){
None => (0..em_len - h_len - 1)
.try_fold(None, |state, i| match(state, db[i]){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

this change results in failures, haven't debugged why, gonna leave the logic as is for now

Comment threadsrc/pss.rs Outdated
Comment on lines +207 to +214
for e in &db[..em_len - h_len - s_len - 2] {
if *e != 0x00 {
return Err(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01 {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
for e in&db[..em_len - h_len - s_len - 2]{
if*e != 0x00{
returnErr(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01{
returnErr(Error::Verification);
}
let(zeroes, rest) = db.split_at(em_len - h_len - s_len - 2);
if zeroes.iter().any(|e| *e != 0x00) || rest[0] != 0x01{
returnErr(Error::Verification);
}

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
let h0 = hash.result_reset();

// 14. If H = H', output "consistent." Otherwise, output "inconsistent."
if Into::<bool>::into(h0.ct_eq(h)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
ifInto::<bool>::into(h0.ct_eq(h)){
if h0.ct_eq(h).into(){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
return Err(Error::Internal);
}

let (db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
let(db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);
let(db, h) = em.split_at_mut(em_len - h_len - 1);

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +122 to +125
// 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
// emLen - hLen - 1.
db[em_len - s_len - h_len - 2] = 0x01;
db[em_len - s_len - h_len - 1..].copy_from_slice(salt);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're assuming here that the em buffer passed into emsa_pss_encode is already zeroed. This happens to be the case, but given that emsa_pss_encode is only called from one place, and this PR isn't attempting to be no-std compatible, it would be clearer if em was constructed and returned from this function. Non-blocking.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

@str4dstr4d mentioned this pull request Jun 10, 2020
@dignifiedquire
dignifiedquire merged commit 3bd9795 into masterJun 11, 2020
@dignifiedquire
dignifiedquire deleted the oaep-dig branch June 11, 2020 11:58
takumi-earth pushed a commit to earthlings-dev/RSA that referenced this pull request Jan 27, 2026
Sign up for freeto 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.

5 participants

@dignifiedquire@str4d@tarcieri@roblabla@lucdew
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Integrate OAEP and PSS into existing interface - #43

Merged
dignifiedquire merged 22 commits into
masterfrom
oaep-dig
Jun 11, 2020
Merged

Integrate OAEP and PSS into existing interface#43
dignifiedquire merged 22 commits into
masterfrom
oaep-dig

Conversation

@dignifiedquire

Copy link
Copy Markdown
Member

This integrates #18 and #26 by expanding the use of PaddingScheme to capture all optional values for the different schemes.

It is not ideal, but it works well and keeps in line with the existing API for now. I think we should still continue to improve on the api and think through #34 more, but in the meantime this a version that folks can start to use, and isn't too different from the existing api

This was referenced Mar 6, 2020
@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, pulling in 2462f1d from #18 goes in the opposite direction to #42. It looks like the main thing it does (remove PublicKey trait) is not present in the overall PR, and I can't find where that is undone, but I think it's in the refactor commit? GitHub isn't helping much here. There are other effects of that commit that are not undone (in particular, it makes public keys non-generic in pkcs1v15, the opposite of what I've done in #44).

How painful would it be to just drop that commit entirely? It would likely make the history clearer.

@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, the change in that commit to store an RSAPublicKey inside RSAPrivateKey does make sense to me. I'd personally alter that commit to only contain the pieces we want, but that's probably more hassle than it's worth, so just reverting changes we don't want is probably fine.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

Yeah, I changed a lot of things during the merge, which is..unfortunate. So at this point I am thinking of squashing this into two commits at the end likely (1) for oaep and (2) for pss, after doing/undoing all things we want to do.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d I made the OAEP and PSS impls generic over the Key traits now

@roblablaroblabla left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey that looks great! I have a couple suggestions

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/padding.rs
write!(f, "PaddingScheme::PKCS1v15({:?})", hash)
}
PaddingScheme::OAEP { ref label, .. } => {
// TODO: How to print the digest name?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could make it Box<dyn DynDigest + Debug> if really necessary. AFAIK all the digest crates have debug unconditionally implemented on them.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

that doesn't work, the compiler is upset about more than one non auto trait :(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ah right, it's possible to make your own trait (e.g. trait MyDynDigest: DynDigest + Debug {}) and then use that as a Box<dyn MyDynDigest>, but at this point it's too much boilerplate just for the sake of getting the digest name to show IMO.

Comment threadsrc/padding.rs Outdated
Comment threadCargo.toml Outdated
@tarcieri

Copy link
Copy Markdown
Member

Relevant to the PSS use case: final two week comment period for shipping signature 1.0: RustCrypto/traits#78

Comment threadsrc/key.rs
}
}

impl Deref for RSAPrivateKey {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Now that we have PrivateKey: PublicKeyParts, this impl Deref should be removed.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Not quite, removing this, removes the ability to call .verify on a private key

Comment threadsrc/key.rs Outdated
Comment threadsrc/raw.rs
Comment on lines +31 to +33
if pad_size < ciphertext.len() {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this check also be in raw_decryption_primitive?

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d thanks for the review, I think I addressed all important things

Comment threadsrc/padding.rs
/// Encryption and Decryption using PKCS1v15 padding.
PKCS1v15Encrypt,
/// Sign and Verify using PKCS1v15 padding.
PKCS1v15Sign { hash: Option<Hash> },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The hash: None case appears to still be necessary for unpadded signatures (at least, that's what the test case in src/pkcs1v15.rs leads me to believe).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, which is why it is still an Option, not sure what you mean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I was just noting this because it wasn't immediately obvious during review that the Option<Hash> was necessary besides enabling the prior encryption case to specify None.

Comment threadsrc/algorithms.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSAES-OAEP implementation, comparing it against RFC 8017 section 7.1.

Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
dignifiedquireand others added 2 commits April 11, 2020 14:35
Co-Authored-By: str4d <thestr4d@gmail.com>
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d applied the new round of CR

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These are causing the current CI failure.

Comment threadbenches/key.rs Outdated
Comment threadbenches/key.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSASSA-PSS implementation. The relevant sections of RFC 8017 were already inlined as comments.

Comment threadsrc/pss.rs
Comment on lines +193 to +201
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {
(Some(i), _) => Ok(Some(i)),
(_, 1) => Ok(Some(i)),
(_, 0) => Ok(None),
_ => Err(Error::Verification),
})?
.ok_or(Error::Verification)?,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for detecting the salt length? I know it is possible due to the structure of DB, but there is no mention of doing so in RFC 8017. I can't read the IEEE documents that reference different possible salt lengths, which maybe discusses this. As is, we never exercise the explicit-salt-length case below.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I don't know @roblabla I believe you wrote this code initially, do you have any answer to this?

Comment threadsrc/pss.rs
salt_len: Option<usize>,
digest: &mut dyn DynDigest,
) -> Result<Vec<u8>> {
let salt_len = salt_len.unwrap_or_else(|| priv_key.size() - 2 - digest.output_size());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for this default salt length? The RFC mentions that common choices are digest.output_size() and 0, while this is selecting the salt to be as large as could fit. I can't read the IEEE documents that reference different possible salt lengths. In any case, I don't think there's a problem with this, given that we are detecting the salt length in verify.

Comment threadsrc/pss.rs
Comment on lines +78 to +80
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "message too
// long" and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs
Comment on lines +149 to +151
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "inconsistent"
// and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs Outdated
// 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
// let H be the next hLen octets.
let (db, h) = em.split_at_mut(em_len - h_len - 1);
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This would be clearer (and closer to the spec):

Suggested change
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];
let h = &mut h[..h_len];

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +193 to +195
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match(state, db[em_len - h_len - i - 2]){
None => (0..em_len - h_len - 1)
.try_fold(None, |state, i| match(state, db[i]){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

this change results in failures, haven't debugged why, gonna leave the logic as is for now

Comment threadsrc/pss.rs Outdated
Comment on lines +207 to +214
for e in &db[..em_len - h_len - s_len - 2] {
if *e != 0x00 {
return Err(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01 {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
for e in&db[..em_len - h_len - s_len - 2]{
if*e != 0x00{
returnErr(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01{
returnErr(Error::Verification);
}
let(zeroes, rest) = db.split_at(em_len - h_len - s_len - 2);
if zeroes.iter().any(|e| *e != 0x00) || rest[0] != 0x01{
returnErr(Error::Verification);
}

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
let h0 = hash.result_reset();

// 14. If H = H', output "consistent." Otherwise, output "inconsistent."
if Into::<bool>::into(h0.ct_eq(h)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
ifInto::<bool>::into(h0.ct_eq(h)){
if h0.ct_eq(h).into(){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
return Err(Error::Internal);
}

let (db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
let(db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);
let(db, h) = em.split_at_mut(em_len - h_len - 1);

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +122 to +125
// 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
// emLen - hLen - 1.
db[em_len - s_len - h_len - 2] = 0x01;
db[em_len - s_len - h_len - 1..].copy_from_slice(salt);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're assuming here that the em buffer passed into emsa_pss_encode is already zeroed. This happens to be the case, but given that emsa_pss_encode is only called from one place, and this PR isn't attempting to be no-std compatible, it would be clearer if em was constructed and returned from this function. Non-blocking.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

@str4dstr4d mentioned this pull request Jun 10, 2020
@dignifiedquire
dignifiedquire merged commit 3bd9795 into masterJun 11, 2020
@dignifiedquire
dignifiedquire deleted the oaep-dig branch June 11, 2020 11:58
takumi-earth pushed a commit to earthlings-dev/RSA that referenced this pull request Jan 27, 2026
Sign up for freeto 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.

5 participants

@dignifiedquire@str4d@tarcieri@roblabla@lucdew
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Integrate OAEP and PSS into existing interface - #43

Merged
dignifiedquire merged 22 commits into
masterfrom
oaep-dig
Jun 11, 2020
Merged

Integrate OAEP and PSS into existing interface#43
dignifiedquire merged 22 commits into
masterfrom
oaep-dig

Conversation

@dignifiedquire

Copy link
Copy Markdown
Member

This integrates #18 and #26 by expanding the use of PaddingScheme to capture all optional values for the different schemes.

It is not ideal, but it works well and keeps in line with the existing API for now. I think we should still continue to improve on the api and think through #34 more, but in the meantime this a version that folks can start to use, and isn't too different from the existing api

This was referenced Mar 6, 2020
@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, pulling in 2462f1d from #18 goes in the opposite direction to #42. It looks like the main thing it does (remove PublicKey trait) is not present in the overall PR, and I can't find where that is undone, but I think it's in the refactor commit? GitHub isn't helping much here. There are other effects of that commit that are not undone (in particular, it makes public keys non-generic in pkcs1v15, the opposite of what I've done in #44).

How painful would it be to just drop that commit entirely? It would likely make the history clearer.

@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, the change in that commit to store an RSAPublicKey inside RSAPrivateKey does make sense to me. I'd personally alter that commit to only contain the pieces we want, but that's probably more hassle than it's worth, so just reverting changes we don't want is probably fine.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

Yeah, I changed a lot of things during the merge, which is..unfortunate. So at this point I am thinking of squashing this into two commits at the end likely (1) for oaep and (2) for pss, after doing/undoing all things we want to do.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d I made the OAEP and PSS impls generic over the Key traits now

@roblablaroblabla left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey that looks great! I have a couple suggestions

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/padding.rs
write!(f, "PaddingScheme::PKCS1v15({:?})", hash)
}
PaddingScheme::OAEP { ref label, .. } => {
// TODO: How to print the digest name?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could make it Box<dyn DynDigest + Debug> if really necessary. AFAIK all the digest crates have debug unconditionally implemented on them.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

that doesn't work, the compiler is upset about more than one non auto trait :(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ah right, it's possible to make your own trait (e.g. trait MyDynDigest: DynDigest + Debug {}) and then use that as a Box<dyn MyDynDigest>, but at this point it's too much boilerplate just for the sake of getting the digest name to show IMO.

Comment threadsrc/padding.rs Outdated
Comment threadCargo.toml Outdated
@tarcieri

Copy link
Copy Markdown
Member

Relevant to the PSS use case: final two week comment period for shipping signature 1.0: RustCrypto/traits#78

Comment threadsrc/key.rs
}
}

impl Deref for RSAPrivateKey {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Now that we have PrivateKey: PublicKeyParts, this impl Deref should be removed.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Not quite, removing this, removes the ability to call .verify on a private key

Comment threadsrc/key.rs Outdated
Comment threadsrc/raw.rs
Comment on lines +31 to +33
if pad_size < ciphertext.len() {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this check also be in raw_decryption_primitive?

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d thanks for the review, I think I addressed all important things

Comment threadsrc/padding.rs
/// Encryption and Decryption using PKCS1v15 padding.
PKCS1v15Encrypt,
/// Sign and Verify using PKCS1v15 padding.
PKCS1v15Sign { hash: Option<Hash> },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The hash: None case appears to still be necessary for unpadded signatures (at least, that's what the test case in src/pkcs1v15.rs leads me to believe).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, which is why it is still an Option, not sure what you mean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I was just noting this because it wasn't immediately obvious during review that the Option<Hash> was necessary besides enabling the prior encryption case to specify None.

Comment threadsrc/algorithms.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSAES-OAEP implementation, comparing it against RFC 8017 section 7.1.

Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
dignifiedquireand others added 2 commits April 11, 2020 14:35
Co-Authored-By: str4d <thestr4d@gmail.com>
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d applied the new round of CR

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These are causing the current CI failure.

Comment threadbenches/key.rs Outdated
Comment threadbenches/key.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSASSA-PSS implementation. The relevant sections of RFC 8017 were already inlined as comments.

Comment threadsrc/pss.rs
Comment on lines +193 to +201
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {
(Some(i), _) => Ok(Some(i)),
(_, 1) => Ok(Some(i)),
(_, 0) => Ok(None),
_ => Err(Error::Verification),
})?
.ok_or(Error::Verification)?,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for detecting the salt length? I know it is possible due to the structure of DB, but there is no mention of doing so in RFC 8017. I can't read the IEEE documents that reference different possible salt lengths, which maybe discusses this. As is, we never exercise the explicit-salt-length case below.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I don't know @roblabla I believe you wrote this code initially, do you have any answer to this?

Comment threadsrc/pss.rs
salt_len: Option<usize>,
digest: &mut dyn DynDigest,
) -> Result<Vec<u8>> {
let salt_len = salt_len.unwrap_or_else(|| priv_key.size() - 2 - digest.output_size());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for this default salt length? The RFC mentions that common choices are digest.output_size() and 0, while this is selecting the salt to be as large as could fit. I can't read the IEEE documents that reference different possible salt lengths. In any case, I don't think there's a problem with this, given that we are detecting the salt length in verify.

Comment threadsrc/pss.rs
Comment on lines +78 to +80
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "message too
// long" and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs
Comment on lines +149 to +151
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "inconsistent"
// and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs Outdated
// 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
// let H be the next hLen octets.
let (db, h) = em.split_at_mut(em_len - h_len - 1);
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This would be clearer (and closer to the spec):

Suggested change
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];
let h = &mut h[..h_len];

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +193 to +195
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match(state, db[em_len - h_len - i - 2]){
None => (0..em_len - h_len - 1)
.try_fold(None, |state, i| match(state, db[i]){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

this change results in failures, haven't debugged why, gonna leave the logic as is for now

Comment threadsrc/pss.rs Outdated
Comment on lines +207 to +214
for e in &db[..em_len - h_len - s_len - 2] {
if *e != 0x00 {
return Err(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01 {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
for e in&db[..em_len - h_len - s_len - 2]{
if*e != 0x00{
returnErr(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01{
returnErr(Error::Verification);
}
let(zeroes, rest) = db.split_at(em_len - h_len - s_len - 2);
if zeroes.iter().any(|e| *e != 0x00) || rest[0] != 0x01{
returnErr(Error::Verification);
}

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
let h0 = hash.result_reset();

// 14. If H = H', output "consistent." Otherwise, output "inconsistent."
if Into::<bool>::into(h0.ct_eq(h)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
ifInto::<bool>::into(h0.ct_eq(h)){
if h0.ct_eq(h).into(){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
return Err(Error::Internal);
}

let (db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
let(db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);
let(db, h) = em.split_at_mut(em_len - h_len - 1);

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +122 to +125
// 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
// emLen - hLen - 1.
db[em_len - s_len - h_len - 2] = 0x01;
db[em_len - s_len - h_len - 1..].copy_from_slice(salt);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're assuming here that the em buffer passed into emsa_pss_encode is already zeroed. This happens to be the case, but given that emsa_pss_encode is only called from one place, and this PR isn't attempting to be no-std compatible, it would be clearer if em was constructed and returned from this function. Non-blocking.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

@str4dstr4d mentioned this pull request Jun 10, 2020
@dignifiedquire
dignifiedquire merged commit 3bd9795 into masterJun 11, 2020
@dignifiedquire
dignifiedquire deleted the oaep-dig branch June 11, 2020 11:58
takumi-earth pushed a commit to earthlings-dev/RSA that referenced this pull request Jan 27, 2026
Sign up for freeto 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.

5 participants

@dignifiedquire@str4d@tarcieri@roblabla@lucdew
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Integrate OAEP and PSS into existing interface - #43

Merged
dignifiedquire merged 22 commits into
masterfrom
oaep-dig
Jun 11, 2020
Merged

Integrate OAEP and PSS into existing interface#43
dignifiedquire merged 22 commits into
masterfrom
oaep-dig

Conversation

@dignifiedquire

Copy link
Copy Markdown
Member

This integrates #18 and #26 by expanding the use of PaddingScheme to capture all optional values for the different schemes.

It is not ideal, but it works well and keeps in line with the existing API for now. I think we should still continue to improve on the api and think through #34 more, but in the meantime this a version that folks can start to use, and isn't too different from the existing api

This was referenced Mar 6, 2020
@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, pulling in 2462f1d from #18 goes in the opposite direction to #42. It looks like the main thing it does (remove PublicKey trait) is not present in the overall PR, and I can't find where that is undone, but I think it's in the refactor commit? GitHub isn't helping much here. There are other effects of that commit that are not undone (in particular, it makes public keys non-generic in pkcs1v15, the opposite of what I've done in #44).

How painful would it be to just drop that commit entirely? It would likely make the history clearer.

@str4d

str4d commented Mar 6, 2020

Copy link
Copy Markdown
Contributor

Hmm, the change in that commit to store an RSAPublicKey inside RSAPrivateKey does make sense to me. I'd personally alter that commit to only contain the pieces we want, but that's probably more hassle than it's worth, so just reverting changes we don't want is probably fine.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

Yeah, I changed a lot of things during the merge, which is..unfortunate. So at this point I am thinking of squashing this into two commits at the end likely (1) for oaep and (2) for pss, after doing/undoing all things we want to do.

@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d I made the OAEP and PSS impls generic over the Key traits now

@roblablaroblabla left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey that looks great! I have a couple suggestions

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/padding.rs
write!(f, "PaddingScheme::PKCS1v15({:?})", hash)
}
PaddingScheme::OAEP { ref label, .. } => {
// TODO: How to print the digest name?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could make it Box<dyn DynDigest + Debug> if really necessary. AFAIK all the digest crates have debug unconditionally implemented on them.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

that doesn't work, the compiler is upset about more than one non auto trait :(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ah right, it's possible to make your own trait (e.g. trait MyDynDigest: DynDigest + Debug {}) and then use that as a Box<dyn MyDynDigest>, but at this point it's too much boilerplate just for the sake of getting the digest name to show IMO.

Comment threadsrc/padding.rs Outdated
Comment threadCargo.toml Outdated
@tarcieri

Copy link
Copy Markdown
Member

Relevant to the PSS use case: final two week comment period for shipping signature 1.0: RustCrypto/traits#78

Comment threadsrc/key.rs
}
}

impl Deref for RSAPrivateKey {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Now that we have PrivateKey: PublicKeyParts, this impl Deref should be removed.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Not quite, removing this, removes the ability to call .verify on a private key

Comment threadsrc/key.rs Outdated
Comment threadsrc/raw.rs
Comment on lines +31 to +33
if pad_size < ciphertext.len() {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this check also be in raw_decryption_primitive?

Comment threadsrc/key.rs Outdated
Comment threadsrc/key.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
Comment threadsrc/pss.rs Outdated
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d thanks for the review, I think I addressed all important things

Comment threadsrc/padding.rs
/// Encryption and Decryption using PKCS1v15 padding.
PKCS1v15Encrypt,
/// Sign and Verify using PKCS1v15 padding.
PKCS1v15Sign { hash: Option<Hash> },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The hash: None case appears to still be necessary for unpadded signatures (at least, that's what the test case in src/pkcs1v15.rs leads me to believe).

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, which is why it is still an Option, not sure what you mean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I was just noting this because it wasn't immediately obvious during review that the Option<Hash> was necessary besides enabling the prior encryption case to specify None.

Comment threadsrc/algorithms.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSAES-OAEP implementation, comparing it against RFC 8017 section 7.1.

Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
Comment threadsrc/oaep.rs Outdated
dignifiedquireand others added 2 commits April 11, 2020 14:35
Co-Authored-By: str4d <thestr4d@gmail.com>
@dignifiedquire

Copy link
Copy Markdown
MemberAuthor

@str4d applied the new round of CR

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These are causing the current CI failure.

Comment threadbenches/key.rs Outdated
Comment threadbenches/key.rs Outdated

@str4dstr4d left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made a close review pass over the RSASSA-PSS implementation. The relevant sections of RFC 8017 were already inlined as comments.

Comment threadsrc/pss.rs
Comment on lines +193 to +201
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {
(Some(i), _) => Ok(Some(i)),
(_, 1) => Ok(Some(i)),
(_, 0) => Ok(None),
_ => Err(Error::Verification),
})?
.ok_or(Error::Verification)?,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for detecting the salt length? I know it is possible due to the structure of DB, but there is no mention of doing so in RFC 8017. I can't read the IEEE documents that reference different possible salt lengths, which maybe discusses this. As is, we never exercise the explicit-salt-length case below.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I don't know @roblabla I believe you wrote this code initially, do you have any answer to this?

Comment threadsrc/pss.rs
salt_len: Option<usize>,
digest: &mut dyn DynDigest,
) -> Result<Vec<u8>> {
let salt_len = salt_len.unwrap_or_else(|| priv_key.size() - 2 - digest.output_size());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there precedent for this default salt length? The RFC mentions that common choices are digest.output_size() and 0, while this is selecting the salt to be as large as could fit. I can't read the IEEE documents that reference different possible salt lengths. In any case, I don't think there's a problem with this, given that we are detecting the salt length in verify.

Comment threadsrc/pss.rs
Comment on lines +78 to +80
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "message too
// long" and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs
Comment on lines +149 to +151
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "inconsistent"
// and stop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Length is not checked, but with the current API we never actually see the message.

Comment threadsrc/pss.rs Outdated
// 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
// let H be the next hLen octets.
let (db, h) = em.split_at_mut(em_len - h_len - 1);
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This would be clearer (and closer to the spec):

Suggested change
let h = &mut h[..(em_len - 1) - (em_len - h_len - 1)];
let h = &mut h[..h_len];

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +193 to +195
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match (state, db[em_len - h_len - i - 2]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
None => (0..=em_len - (h_len + 2))
.rev()
.try_fold(None, |state, i| match(state, db[em_len - h_len - i - 2]){
None => (0..em_len - h_len - 1)
.try_fold(None, |state, i| match(state, db[i]){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

this change results in failures, haven't debugged why, gonna leave the logic as is for now

Comment threadsrc/pss.rs Outdated
Comment on lines +207 to +214
for e in &db[..em_len - h_len - s_len - 2] {
if *e != 0x00 {
return Err(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01 {
return Err(Error::Verification);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
for e in&db[..em_len - h_len - s_len - 2]{
if*e != 0x00{
returnErr(Error::Verification);
}
}
if db[em_len - h_len - s_len - 2] != 0x01{
returnErr(Error::Verification);
}
let(zeroes, rest) = db.split_at(em_len - h_len - s_len - 2);
if zeroes.iter().any(|e| *e != 0x00) || rest[0] != 0x01{
returnErr(Error::Verification);
}

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
let h0 = hash.result_reset();

// 14. If H = H', output "consistent." Otherwise, output "inconsistent."
if Into::<bool>::into(h0.ct_eq(h)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
ifInto::<bool>::into(h0.ct_eq(h)){
if h0.ct_eq(h).into(){

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs Outdated
return Err(Error::Internal);
}

let (db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
let(db, h) = em.split_at_mut(em_len - s_len - h_len - 2 + 1 + s_len);
let(db, h) = em.split_at_mut(em_len - h_len - 1);

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

Comment threadsrc/pss.rs
Comment on lines +122 to +125
// 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
// emLen - hLen - 1.
db[em_len - s_len - h_len - 2] = 0x01;
db[em_len - s_len - h_len - 1..].copy_from_slice(salt);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We're assuming here that the em buffer passed into emsa_pss_encode is already zeroed. This happens to be the case, but given that emsa_pss_encode is only called from one place, and this PR isn't attempting to be no-std compatible, it would be clearer if em was constructed and returned from this function. Non-blocking.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed

@str4dstr4d mentioned this pull request Jun 10, 2020
@dignifiedquire
dignifiedquire merged commit 3bd9795 into masterJun 11, 2020
@dignifiedquire
dignifiedquire deleted the oaep-dig branch June 11, 2020 11:58
takumi-earth pushed a commit to earthlings-dev/RSA that referenced this pull request Jan 27, 2026
Sign up for freeto 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.

5 participants

@dignifiedquire@str4d@tarcieri@roblabla@lucdew