From 03e759b1fde76d2a51b1de3e891536fe82683647 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Fri, 24 Jun 2022 08:42:38 -0400 Subject: [PATCH] Fix DigestTranscript to be secure Collisions were possible depending on static label substrings. Now, labels are prefixed by their length to prevent this from being possible. All variables are also flagged by their type, preventing other potential conflicts. --- crypto/transcript/src/lib.rs | 43 +++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/crypto/transcript/src/lib.rs b/crypto/transcript/src/lib.rs index b324cc31..d5e4aa14 100644 --- a/crypto/transcript/src/lib.rs +++ b/crypto/transcript/src/lib.rs @@ -14,6 +14,26 @@ pub trait Transcript { fn rng_seed(&mut self, label: &'static [u8]) -> [u8; 32]; } +enum DigestTranscriptMember { + Name, + Domain, + Label, + Value, + Challenge +} + +impl DigestTranscriptMember { + fn as_u8(&self) -> u8 { + match self { + DigestTranscriptMember::Name => 0, + DigestTranscriptMember::Domain => 1, + DigestTranscriptMember::Label => 2, + DigestTranscriptMember::Value => 3, + DigestTranscriptMember::Challenge => 4 + } + } +} + #[derive(Clone, Debug)] pub struct DigestTranscript(Vec, PhantomData); @@ -24,25 +44,32 @@ impl PartialEq for DigestTranscript { } impl DigestTranscript { - pub fn new(label: &'static [u8]) -> Self { - DigestTranscript(label.to_vec(), PhantomData) + fn append(&mut self, kind: DigestTranscriptMember, value: &[u8]) { + self.0.push(kind.as_u8()); + // Assumes messages don't exceed 16 exabytes + self.0.extend(u64::try_from(value.len()).unwrap().to_le_bytes()); + self.0.extend(value); + } + + pub fn new(name: &'static [u8]) -> Self { + let mut res = DigestTranscript(vec![], PhantomData); + res.append(DigestTranscriptMember::Name, name); + res } } impl Transcript for DigestTranscript { fn domain_separate(&mut self, label: &[u8]) { - self.append_message(b"domain", label); + self.append(DigestTranscriptMember::Domain, label); } fn append_message(&mut self, label: &'static [u8], message: &[u8]) { - self.0.extend(label); - // Assumes messages don't exceed 16 exabytes - self.0.extend(u64::try_from(message.len()).unwrap().to_le_bytes()); - self.0.extend(message); + self.append(DigestTranscriptMember::Label, label); + self.append(DigestTranscriptMember::Value, message); } fn challenge(&mut self, label: &'static [u8]) -> Vec { - self.0.extend(label); + self.append(DigestTranscriptMember::Challenge, label); D::new().chain_update(&self.0).finalize().to_vec() }