Skip to content

Commit ced530b

Browse files
authored
belt-dwp: support additional tag sizes (#694)
The specification allows tag truncation (section 5.4). Additionally, DWP can be used with a "full" 128 bit tag size without any security issues (see this [issue](bcrypto/belt#8)). While technically tag sizes bigger than 64 bits do not conform to the spec, I think it's worth to add support for them.
1 parent d829983 commit ced530b

File tree

1 file changed

+34
-21
lines changed

1 file changed

+34
-21
lines changed

belt-dwp/src/lib.rs

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,23 @@
7373
//! [`aead::Buffer`] for `arrayvec::ArrayVec` (re-exported from the [`aead`] crate as
7474
//! [`aead::arrayvec::ArrayVec`]).
7575
76-
pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser};
76+
pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser, Tag};
7777
pub use belt_block::BeltBlock;
7878

79-
use aead::consts::{U8, U16};
79+
use aead::array::ArraySize;
80+
use aead::consts::{True, U8, U16};
8081
use aead::{TagPosition, inout::InOutBuf};
8182
use belt_block::cipher::crypto_common::InnerUser;
8283
use belt_block::cipher::{Block, BlockCipherEncrypt, StreamCipher};
8384
use belt_ctr::cipher::InnerIvInit;
8485
use belt_ctr::{BeltCtr, BeltCtrCore};
86+
use core::marker::PhantomData;
8587
use universal_hash::UniversalHash;
8688
use universal_hash::crypto_common::{BlockSizeUser, InnerInit};
89+
use universal_hash::typenum::{IsLessOrEqual, NonZero};
8790

8891
/// Nonce type for [`Dwp`]
89-
pub type Nonce = aead::Nonce<Dwp>;
90-
91-
/// Tag type for [`Dwp`]
92-
pub type Tag = aead::Tag<Dwp>;
92+
pub type Nonce = aead::Nonce<BeltDwp>;
9393

9494
mod gf;
9595
mod ghash;
@@ -101,43 +101,52 @@ const T: u128 = 0xE45D_4A58_8E00_6D36_3BF5_080A_C8BA_94B1;
101101

102102
/// `belt-dwp` authenticated encryption with associated data (AEAD) cipher,
103103
/// defined in STB 34.101.31-2020.
104-
pub type BeltDwp = Dwp<BeltBlock>;
104+
pub type BeltDwp = Dwp<BeltBlock, U8>;
105105

106106
/// `belt-dwp` authenticated encryption with associated data (AEAD) cipher
107-
/// defined in STB 34.101.31-2020 generic over block cipher implementation.
108-
pub struct Dwp<C = BeltBlock>
107+
/// defined in STB 34.101.31-2020 generic over block cipher implementation
108+
/// and tag size.
109+
pub struct Dwp<C, TagSize>
109110
where
110111
C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
112+
TagSize: ArraySize + NonZero + IsLessOrEqual<U16, Output = True>,
111113
{
112114
cipher: C,
115+
_pd: PhantomData<TagSize>,
113116
}
114117

115-
impl<C> InnerUser for Dwp<C>
118+
impl<C, TagSize> InnerUser for Dwp<C, TagSize>
116119
where
117120
C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
121+
TagSize: ArraySize + NonZero + IsLessOrEqual<U16, Output = True>,
118122
{
119123
type Inner = C;
120124
}
121125

122-
impl<C> InnerInit for Dwp<C>
126+
impl<C, TagSize> InnerInit for Dwp<C, TagSize>
123127
where
124128
C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
129+
TagSize: ArraySize + NonZero + IsLessOrEqual<U16, Output = True>,
125130
{
126131
fn inner_init(cipher: Self::Inner) -> Self {
127-
Self { cipher }
132+
Self {
133+
cipher,
134+
_pd: PhantomData,
135+
}
128136
}
129137
}
130138

131-
impl<C> AeadInOut for Dwp<C>
139+
impl<C, TagSize> AeadInOut for Dwp<C, TagSize>
132140
where
133141
C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
142+
TagSize: ArraySize + NonZero + IsLessOrEqual<U16, Output = True>,
134143
{
135144
fn encrypt_inout_detached(
136145
&self,
137146
nonce: &Nonce,
138147
associated_data: &[u8],
139148
mut buffer: InOutBuf<'_, '_, u8>,
140-
) -> aead::Result<Tag> {
149+
) -> aead::Result<Tag<Self>> {
141150
let sizes_block = get_sizes_block(associated_data.len(), buffer.len());
142151

143152
// 2.1. 𝑠 ← belt-block(𝑆, 𝐾);
@@ -175,15 +184,16 @@ where
175184
let mut tag = ghash.finalize_reset();
176185
self.cipher.encrypt_block(&mut tag);
177186

178-
Ok(Tag::try_from(&tag[..8]).expect("Tag is always 8 bytes"))
187+
let tag = &tag[..TagSize::USIZE];
188+
Ok(tag.try_into().expect("Tag is always 8 bytes"))
179189
}
180190

181191
fn decrypt_inout_detached(
182192
&self,
183193
nonce: &Nonce,
184194
associated_data: &[u8],
185195
buffer: InOutBuf<'_, '_, u8>,
186-
tag: &Tag,
196+
tag: &Tag<Self>,
187197
) -> aead::Result<()> {
188198
let sizes_block = get_sizes_block(associated_data.len(), buffer.len());
189199

@@ -217,7 +227,7 @@ where
217227

218228
use subtle::ConstantTimeEq;
219229
// 7. If 𝑇 != Lo(𝑡, 64), return ⊥
220-
if tag_exact[..8].ct_eq(tag).into() {
230+
if tag_exact[..TagSize::USIZE].ct_eq(tag).into() {
221231
// 8. For 𝑖 = 1,2,...,𝑛 do:
222232
// 8.1. 𝑠 ← 𝑠 ⊞ ⟨1⟩128;
223233
// 8.2. 𝑋𝑖 ← 𝑌𝑖 ⊕ Lo(belt-block(𝑠, 𝐾), |𝑌𝑖|)
@@ -231,12 +241,13 @@ where
231241
}
232242
}
233243

234-
impl<C> AeadCore for Dwp<C>
244+
impl<C, TagSize> AeadCore for Dwp<C, TagSize>
235245
where
236246
C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
247+
TagSize: ArraySize + NonZero + IsLessOrEqual<U16, Output = True>,
237248
{
238249
type NonceSize = C::BlockSize;
239-
type TagSize = U8;
250+
type TagSize = TagSize;
240251
const TAG_POSITION: TagPosition = TagPosition::Postfix;
241252
}
242253

@@ -254,7 +265,9 @@ fn get_sizes_block(aad_len: usize, msg_len: usize) -> Block<GHash> {
254265
}
255266

256267
#[cfg(feature = "zeroize")]
257-
impl<C> zeroize::ZeroizeOnDrop for Dwp<C> where
258-
C: zeroize::ZeroizeOnDrop + BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>
268+
impl<C, TagSize> zeroize::ZeroizeOnDrop for Dwp<C, TagSize>
269+
where
270+
C: zeroize::ZeroizeOnDrop + BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
271+
TagSize: ArraySize + NonZero + IsLessOrEqual<U16, Output = True>,
259272
{
260273
}

0 commit comments

Comments
 (0)