in src/aes128gcm.rs [450:516]
fn next(&mut self) -> Option<Self::Item> {
let records_remaining = self.num_records - self.sequence_number;
// We stop iterating when we've produced all records.
if records_remaining == 0 {
assert!(
self.plaintext.is_empty(),
"record chunking error: the plaintext was not fully consumed"
);
assert!(
self.extra_plaintext == 0,
"record chunking error: the extra plaintext was not fully consumed"
);
assert!(
self.pad_length == 0,
"record chunking error: the padding was not fully consumed"
);
return None;
}
// Allocate a chunk of plaintext to this record.
// We target `plaintext_per_record` bytes per record, but it's a little
// more complicated than that...
let mut plaintext_share = self.plaintext_per_record;
if plaintext_share > self.plaintext.len() {
// ...because the final record is allowed to be smaller.
assert!(
records_remaining == 1,
"record chunking error: the plaintext was consumed too early"
);
plaintext_share = self.plaintext.len();
} else {
// ...because non-final records need to consume any extra plaintext.
if self.extra_plaintext > 0 {
// The extra plaintext must be distributed as evenly as possible
// amongst all but the final record.
let mut extra_share = self.extra_plaintext / (records_remaining - 1);
if self.extra_plaintext % (records_remaining - 1) != 0 {
extra_share += 1;
}
plaintext_share += extra_share;
self.extra_plaintext -= extra_share;
}
}
let plaintext = &self.plaintext[0..plaintext_share];
self.plaintext = &self.plaintext[plaintext_share..];
// Fill the rest of the record with padding.
let padding_share = std::cmp::min(self.pad_length, self.rs - plaintext_share);
self.pad_length -= padding_share;
assert!(
padding_share > 0,
"record chunking error: the padding was consumed too early"
);
// Check where we are in the iteration.
let sequence_number = self.sequence_number;
self.sequence_number += 1;
let is_final = self.sequence_number == self.num_records;
assert!(
is_final || plaintext.len() + padding_share == self.rs,
"record chunking error: non-final record is too short"
);
// That's a record!
Some(PlaintextRecord {
plaintext,
padding: padding_share,
sequence_number,
is_final,
})
}