in src/aes128gcm.rs [368:419]
fn split_into_records(
plaintext: &[u8],
pad_length: usize,
rs: usize,
) -> Result<PlaintextRecordIterator<'_>> {
// Adjust for encryption overhead.
if rs < ECE_AES128GCM_MIN_RS as usize {
return Err(Error::InvalidRecordSize);
}
let rs = rs - ECE_TAG_LENGTH;
// Ensure we have enough padding to give at least one byte of it to each record.
// This is the only reason why we might expand the padding beyond what was requested.
let mut min_num_records = plaintext.len() / (rs - 1);
if plaintext.len() % (rs - 1) != 0 {
min_num_records += 1;
}
let pad_length = std::cmp::max(pad_length, min_num_records);
// Knowing the total data size, determines the number of records.
let total_size = plaintext.len() + pad_length;
let mut num_records = total_size / rs;
let size_of_final_record = total_size % rs;
if size_of_final_record > 0 {
num_records += 1;
}
assert!(
num_records >= min_num_records,
"record chunking error: we miscalculated the minimum number of records ({} < {})",
num_records,
min_num_records,
);
// Evenly distribute the plaintext between that many records.
// There may of course be some leftover that won't distribute evenly.
let plaintext_per_record = plaintext.len() / num_records;
let mut extra_plaintext = plaintext.len() % num_records;
// If the final record is very small, we might not be able to fit
// the recommended number of plaintext bytes, so redistribute them.
// (Remember, the final block must contain at least one padding byte).
if size_of_final_record > 0 && plaintext_per_record > size_of_final_record - 1 {
extra_plaintext += plaintext_per_record - (size_of_final_record - 1)
}
// And now we can iterate!
Ok(PlaintextRecordIterator {
plaintext,
pad_length,
plaintext_per_record,
extra_plaintext,
rs,
sequence_number: 0,
num_records,
total_size,
})
}