1 // rstest_reuse template functions have unused variables
2 #![allow(unused_variables)]
3
4 use rand::{
5 self,
6 distributions::{self, Distribution as _},
7 rngs, Rng as _, SeedableRng as _,
8 };
9 use rstest::rstest;
10 use rstest_reuse::{apply, template};
11 use std::{collections, fmt};
12
13 use crate::{
14 alphabet::{Alphabet, STANDARD},
15 encode::add_padding,
16 encoded_len,
17 engine::{general_purpose, naive, Config, DecodeEstimate, DecodePaddingMode, Engine},
18 tests::{assert_encode_sanity, random_alphabet, random_config},
19 DecodeError, PAD_BYTE,
20 };
21
22 // the case::foo syntax includes the "foo" in the generated test method names
23 #[template]
24 #[rstest(engine_wrapper,
25 case::general_purpose(GeneralPurposeWrapper {}),
26 case::naive(NaiveWrapper {}),
27 )]
all_engines<E: EngineWrapper>(engine_wrapper: E)28 fn all_engines<E: EngineWrapper>(engine_wrapper: E) {}
29
30 #[apply(all_engines)]
rfc_test_vectors_std_alphabet<E: EngineWrapper>(engine_wrapper: E)31 fn rfc_test_vectors_std_alphabet<E: EngineWrapper>(engine_wrapper: E) {
32 let data = vec![
33 ("", ""),
34 ("f", "Zg=="),
35 ("fo", "Zm8="),
36 ("foo", "Zm9v"),
37 ("foob", "Zm9vYg=="),
38 ("fooba", "Zm9vYmE="),
39 ("foobar", "Zm9vYmFy"),
40 ];
41
42 let engine = E::standard();
43 let engine_no_padding = E::standard_unpadded();
44
45 for (orig, encoded) in &data {
46 let encoded_without_padding = encoded.trim_end_matches('=');
47
48 // unpadded
49 {
50 let mut encode_buf = [0_u8; 8];
51 let mut decode_buf = [0_u8; 6];
52
53 let encode_len =
54 engine_no_padding.internal_encode(orig.as_bytes(), &mut encode_buf[..]);
55 assert_eq!(
56 &encoded_without_padding,
57 &std::str::from_utf8(&encode_buf[0..encode_len]).unwrap()
58 );
59 let decode_len = engine_no_padding
60 .decode_slice_unchecked(encoded_without_padding.as_bytes(), &mut decode_buf[..])
61 .unwrap();
62 assert_eq!(orig.len(), decode_len);
63
64 assert_eq!(
65 orig,
66 &std::str::from_utf8(&decode_buf[0..decode_len]).unwrap()
67 );
68
69 // if there was any padding originally, the no padding engine won't decode it
70 if encoded.as_bytes().contains(&PAD_BYTE) {
71 assert_eq!(
72 Err(DecodeError::InvalidPadding),
73 engine_no_padding.decode(encoded)
74 )
75 }
76 }
77
78 // padded
79 {
80 let mut encode_buf = [0_u8; 8];
81 let mut decode_buf = [0_u8; 6];
82
83 let encode_len = engine.internal_encode(orig.as_bytes(), &mut encode_buf[..]);
84 assert_eq!(
85 // doesn't have padding added yet
86 &encoded_without_padding,
87 &std::str::from_utf8(&encode_buf[0..encode_len]).unwrap()
88 );
89 let pad_len = add_padding(orig.len(), &mut encode_buf[encode_len..]);
90 assert_eq!(encoded.as_bytes(), &encode_buf[..encode_len + pad_len]);
91
92 let decode_len = engine
93 .decode_slice_unchecked(encoded.as_bytes(), &mut decode_buf[..])
94 .unwrap();
95 assert_eq!(orig.len(), decode_len);
96
97 assert_eq!(
98 orig,
99 &std::str::from_utf8(&decode_buf[0..decode_len]).unwrap()
100 );
101
102 // if there was (canonical) padding, and we remove it, the standard engine won't decode
103 if encoded.as_bytes().contains(&PAD_BYTE) {
104 assert_eq!(
105 Err(DecodeError::InvalidPadding),
106 engine.decode(encoded_without_padding)
107 )
108 }
109 }
110 }
111 }
112
113 #[apply(all_engines)]
roundtrip_random<E: EngineWrapper>(engine_wrapper: E)114 fn roundtrip_random<E: EngineWrapper>(engine_wrapper: E) {
115 let mut rng = seeded_rng();
116
117 let mut orig_data = Vec::<u8>::new();
118 let mut encode_buf = Vec::<u8>::new();
119 let mut decode_buf = Vec::<u8>::new();
120
121 let len_range = distributions::Uniform::new(1, 1_000);
122
123 for _ in 0..10_000 {
124 let engine = E::random(&mut rng);
125
126 orig_data.clear();
127 encode_buf.clear();
128 decode_buf.clear();
129
130 let (orig_len, _, encoded_len) = generate_random_encoded_data(
131 &engine,
132 &mut orig_data,
133 &mut encode_buf,
134 &mut rng,
135 &len_range,
136 );
137
138 // exactly the right size
139 decode_buf.resize(orig_len, 0);
140
141 let dec_len = engine
142 .decode_slice_unchecked(&encode_buf[0..encoded_len], &mut decode_buf[..])
143 .unwrap();
144
145 assert_eq!(orig_len, dec_len);
146 assert_eq!(&orig_data[..], &decode_buf[..dec_len]);
147 }
148 }
149
150 #[apply(all_engines)]
encode_doesnt_write_extra_bytes<E: EngineWrapper>(engine_wrapper: E)151 fn encode_doesnt_write_extra_bytes<E: EngineWrapper>(engine_wrapper: E) {
152 let mut rng = seeded_rng();
153
154 let mut orig_data = Vec::<u8>::new();
155 let mut encode_buf = Vec::<u8>::new();
156 let mut encode_buf_backup = Vec::<u8>::new();
157
158 let input_len_range = distributions::Uniform::new(0, 1000);
159
160 for _ in 0..10_000 {
161 let engine = E::random(&mut rng);
162 let padded = engine.config().encode_padding();
163
164 orig_data.clear();
165 encode_buf.clear();
166 encode_buf_backup.clear();
167
168 let orig_len = fill_rand(&mut orig_data, &mut rng, &input_len_range);
169
170 let prefix_len = 1024;
171 // plenty of prefix and suffix
172 fill_rand_len(&mut encode_buf, &mut rng, prefix_len * 2 + orig_len * 2);
173 encode_buf_backup.extend_from_slice(&encode_buf[..]);
174
175 let expected_encode_len_no_pad = encoded_len(orig_len, false).unwrap();
176
177 let encoded_len_no_pad =
178 engine.internal_encode(&orig_data[..], &mut encode_buf[prefix_len..]);
179 assert_eq!(expected_encode_len_no_pad, encoded_len_no_pad);
180
181 // no writes past what it claimed to write
182 assert_eq!(&encode_buf_backup[..prefix_len], &encode_buf[..prefix_len]);
183 assert_eq!(
184 &encode_buf_backup[(prefix_len + encoded_len_no_pad)..],
185 &encode_buf[(prefix_len + encoded_len_no_pad)..]
186 );
187
188 let encoded_data = &encode_buf[prefix_len..(prefix_len + encoded_len_no_pad)];
189 assert_encode_sanity(
190 std::str::from_utf8(encoded_data).unwrap(),
191 // engines don't pad
192 false,
193 orig_len,
194 );
195
196 // pad so we can decode it in case our random engine requires padding
197 let pad_len = if padded {
198 add_padding(orig_len, &mut encode_buf[prefix_len + encoded_len_no_pad..])
199 } else {
200 0
201 };
202
203 assert_eq!(
204 orig_data,
205 engine
206 .decode(&encode_buf[prefix_len..(prefix_len + encoded_len_no_pad + pad_len)],)
207 .unwrap()
208 );
209 }
210 }
211
212 #[apply(all_engines)]
encode_engine_slice_fits_into_precisely_sized_slice<E: EngineWrapper>(engine_wrapper: E)213 fn encode_engine_slice_fits_into_precisely_sized_slice<E: EngineWrapper>(engine_wrapper: E) {
214 let mut orig_data = Vec::new();
215 let mut encoded_data = Vec::new();
216 let mut decoded = Vec::new();
217
218 let input_len_range = distributions::Uniform::new(0, 1000);
219
220 let mut rng = rngs::SmallRng::from_entropy();
221
222 for _ in 0..10_000 {
223 orig_data.clear();
224 encoded_data.clear();
225 decoded.clear();
226
227 let input_len = input_len_range.sample(&mut rng);
228
229 for _ in 0..input_len {
230 orig_data.push(rng.gen());
231 }
232
233 let engine = E::random(&mut rng);
234
235 let encoded_size = encoded_len(input_len, engine.config().encode_padding()).unwrap();
236
237 encoded_data.resize(encoded_size, 0);
238
239 assert_eq!(
240 encoded_size,
241 engine.encode_slice(&orig_data, &mut encoded_data).unwrap()
242 );
243
244 assert_encode_sanity(
245 std::str::from_utf8(&encoded_data[0..encoded_size]).unwrap(),
246 engine.config().encode_padding(),
247 input_len,
248 );
249
250 engine
251 .decode_vec(&encoded_data[0..encoded_size], &mut decoded)
252 .unwrap();
253 assert_eq!(orig_data, decoded);
254 }
255 }
256
257 #[apply(all_engines)]
decode_doesnt_write_extra_bytes<E>(engine_wrapper: E) where E: EngineWrapper, <<E as EngineWrapper>::Engine as Engine>::Config: fmt::Debug,258 fn decode_doesnt_write_extra_bytes<E>(engine_wrapper: E)
259 where
260 E: EngineWrapper,
261 <<E as EngineWrapper>::Engine as Engine>::Config: fmt::Debug,
262 {
263 let mut rng = seeded_rng();
264
265 let mut orig_data = Vec::<u8>::new();
266 let mut encode_buf = Vec::<u8>::new();
267 let mut decode_buf = Vec::<u8>::new();
268 let mut decode_buf_backup = Vec::<u8>::new();
269
270 let len_range = distributions::Uniform::new(1, 1_000);
271
272 for _ in 0..10_000 {
273 let engine = E::random(&mut rng);
274
275 orig_data.clear();
276 encode_buf.clear();
277 decode_buf.clear();
278 decode_buf_backup.clear();
279
280 let orig_len = fill_rand(&mut orig_data, &mut rng, &len_range);
281 encode_buf.resize(orig_len * 2 + 100, 0);
282
283 let encoded_len = engine
284 .encode_slice(&orig_data[..], &mut encode_buf[..])
285 .unwrap();
286 encode_buf.truncate(encoded_len);
287
288 // oversize decode buffer so we can easily tell if it writes anything more than
289 // just the decoded data
290 let prefix_len = 1024;
291 // plenty of prefix and suffix
292 fill_rand_len(&mut decode_buf, &mut rng, prefix_len * 2 + orig_len * 2);
293 decode_buf_backup.extend_from_slice(&decode_buf[..]);
294
295 let dec_len = engine
296 .decode_slice_unchecked(&encode_buf, &mut decode_buf[prefix_len..])
297 .unwrap();
298
299 assert_eq!(orig_len, dec_len);
300 assert_eq!(
301 &orig_data[..],
302 &decode_buf[prefix_len..prefix_len + dec_len]
303 );
304 assert_eq!(&decode_buf_backup[..prefix_len], &decode_buf[..prefix_len]);
305 assert_eq!(
306 &decode_buf_backup[prefix_len + dec_len..],
307 &decode_buf[prefix_len + dec_len..]
308 );
309 }
310 }
311
312 #[apply(all_engines)]
decode_detect_invalid_last_symbol<E: EngineWrapper>(engine_wrapper: E)313 fn decode_detect_invalid_last_symbol<E: EngineWrapper>(engine_wrapper: E) {
314 // 0xFF -> "/w==", so all letters > w, 0-9, and '+', '/' should get InvalidLastSymbol
315 let engine = E::standard();
316
317 assert_eq!(Ok(vec![0x89, 0x85]), engine.decode("iYU="));
318 assert_eq!(Ok(vec![0xFF]), engine.decode("/w=="));
319
320 for (suffix, offset) in vec![
321 // suffix, offset of bad byte from start of suffix
322 ("/x==", 1_usize),
323 ("/z==", 1_usize),
324 ("/0==", 1_usize),
325 ("/9==", 1_usize),
326 ("/+==", 1_usize),
327 ("//==", 1_usize),
328 // trailing 01
329 ("iYV=", 2_usize),
330 // trailing 10
331 ("iYW=", 2_usize),
332 // trailing 11
333 ("iYX=", 2_usize),
334 ] {
335 for prefix_quads in 0..256 {
336 let mut encoded = "AAAA".repeat(prefix_quads);
337 encoded.push_str(suffix);
338
339 assert_eq!(
340 Err(DecodeError::InvalidLastSymbol(
341 encoded.len() - 4 + offset,
342 suffix.as_bytes()[offset],
343 )),
344 engine.decode(encoded.as_str())
345 );
346 }
347 }
348 }
349
350 #[apply(all_engines)]
decode_detect_invalid_last_symbol_when_length_is_also_invalid<E: EngineWrapper>( engine_wrapper: E, )351 fn decode_detect_invalid_last_symbol_when_length_is_also_invalid<E: EngineWrapper>(
352 engine_wrapper: E,
353 ) {
354 let mut rng = seeded_rng();
355
356 // check across enough lengths that it would likely cover any implementation's various internal
357 // small/large input division
358 for len in (0_usize..256).map(|len| len * 4 + 1) {
359 let engine = E::random_alphabet(&mut rng, &STANDARD);
360
361 let mut input = vec![b'A'; len];
362
363 // with a valid last char, it's InvalidLength
364 assert_eq!(Err(DecodeError::InvalidLength), engine.decode(&input));
365 // after mangling the last char, it's InvalidByte
366 input[len - 1] = b'"';
367 assert_eq!(
368 Err(DecodeError::InvalidByte(len - 1, b'"')),
369 engine.decode(&input)
370 );
371 }
372 }
373
374 #[apply(all_engines)]
decode_detect_invalid_last_symbol_every_possible_two_symbols<E: EngineWrapper>( engine_wrapper: E, )375 fn decode_detect_invalid_last_symbol_every_possible_two_symbols<E: EngineWrapper>(
376 engine_wrapper: E,
377 ) {
378 let engine = E::standard();
379
380 let mut base64_to_bytes = collections::HashMap::new();
381
382 for b in 0_u8..=255 {
383 let mut b64 = vec![0_u8; 4];
384 assert_eq!(2, engine.internal_encode(&[b], &mut b64[..]));
385 let _ = add_padding(1, &mut b64[2..]);
386
387 assert!(base64_to_bytes.insert(b64, vec![b]).is_none());
388 }
389
390 // every possible combination of trailing symbols must either decode to 1 byte or get InvalidLastSymbol, with or without any leading chunks
391
392 let mut prefix = Vec::new();
393 for _ in 0..256 {
394 let mut clone = prefix.clone();
395
396 let mut symbols = [0_u8; 4];
397 for &s1 in STANDARD.symbols.iter() {
398 symbols[0] = s1;
399 for &s2 in STANDARD.symbols.iter() {
400 symbols[1] = s2;
401 symbols[2] = PAD_BYTE;
402 symbols[3] = PAD_BYTE;
403
404 // chop off previous symbols
405 clone.truncate(prefix.len());
406 clone.extend_from_slice(&symbols[..]);
407 let decoded_prefix_len = prefix.len() / 4 * 3;
408
409 match base64_to_bytes.get(&symbols[..]) {
410 Some(bytes) => {
411 let res = engine
412 .decode(&clone)
413 // remove prefix
414 .map(|decoded| decoded[decoded_prefix_len..].to_vec());
415
416 assert_eq!(Ok(bytes.clone()), res);
417 }
418 None => assert_eq!(
419 Err(DecodeError::InvalidLastSymbol(1, s2)),
420 engine.decode(&symbols[..])
421 ),
422 }
423 }
424 }
425
426 prefix.extend_from_slice(b"AAAA");
427 }
428 }
429
430 #[apply(all_engines)]
decode_detect_invalid_last_symbol_every_possible_three_symbols<E: EngineWrapper>( engine_wrapper: E, )431 fn decode_detect_invalid_last_symbol_every_possible_three_symbols<E: EngineWrapper>(
432 engine_wrapper: E,
433 ) {
434 let engine = E::standard();
435
436 let mut base64_to_bytes = collections::HashMap::new();
437
438 let mut bytes = [0_u8; 2];
439 for b1 in 0_u8..=255 {
440 bytes[0] = b1;
441 for b2 in 0_u8..=255 {
442 bytes[1] = b2;
443 let mut b64 = vec![0_u8; 4];
444 assert_eq!(3, engine.internal_encode(&bytes, &mut b64[..]));
445 let _ = add_padding(2, &mut b64[3..]);
446
447 let mut v = Vec::with_capacity(2);
448 v.extend_from_slice(&bytes[..]);
449
450 assert!(base64_to_bytes.insert(b64, v).is_none());
451 }
452 }
453
454 // every possible combination of symbols must either decode to 2 bytes or get InvalidLastSymbol, with or without any leading chunks
455
456 let mut prefix = Vec::new();
457 for _ in 0..256 {
458 let mut input = prefix.clone();
459
460 let mut symbols = [0_u8; 4];
461 for &s1 in STANDARD.symbols.iter() {
462 symbols[0] = s1;
463 for &s2 in STANDARD.symbols.iter() {
464 symbols[1] = s2;
465 for &s3 in STANDARD.symbols.iter() {
466 symbols[2] = s3;
467 symbols[3] = PAD_BYTE;
468
469 // chop off previous symbols
470 input.truncate(prefix.len());
471 input.extend_from_slice(&symbols[..]);
472 let decoded_prefix_len = prefix.len() / 4 * 3;
473
474 match base64_to_bytes.get(&symbols[..]) {
475 Some(bytes) => {
476 let res = engine
477 .decode(&input)
478 // remove prefix
479 .map(|decoded| decoded[decoded_prefix_len..].to_vec());
480
481 assert_eq!(Ok(bytes.clone()), res);
482 }
483 None => assert_eq!(
484 Err(DecodeError::InvalidLastSymbol(2, s3)),
485 engine.decode(&symbols[..])
486 ),
487 }
488 }
489 }
490 }
491 prefix.extend_from_slice(b"AAAA");
492 }
493 }
494
495 #[apply(all_engines)]
decode_invalid_trailing_bits_ignored_when_configured<E: EngineWrapper>(engine_wrapper: E)496 fn decode_invalid_trailing_bits_ignored_when_configured<E: EngineWrapper>(engine_wrapper: E) {
497 let strict = E::standard();
498 let forgiving = E::standard_allow_trailing_bits();
499
500 fn assert_tolerant_decode<E: Engine>(
501 engine: &E,
502 input: &mut String,
503 b64_prefix_len: usize,
504 expected_decode_bytes: Vec<u8>,
505 data: &str,
506 ) {
507 let prefixed = prefixed_data(input, b64_prefix_len, data);
508 let decoded = engine.decode(prefixed);
509 // prefix is always complete chunks
510 let decoded_prefix_len = b64_prefix_len / 4 * 3;
511 assert_eq!(
512 Ok(expected_decode_bytes),
513 decoded.map(|v| v[decoded_prefix_len..].to_vec())
514 );
515 }
516
517 let mut prefix = String::new();
518 for _ in 0..256 {
519 let mut input = prefix.clone();
520
521 // example from https://github.com/marshallpierce/rust-base64/issues/75
522 assert!(strict
523 .decode(prefixed_data(&mut input, prefix.len(), "/w=="))
524 .is_ok());
525 assert!(strict
526 .decode(prefixed_data(&mut input, prefix.len(), "iYU="))
527 .is_ok());
528 // trailing 01
529 assert_tolerant_decode(&forgiving, &mut input, prefix.len(), vec![255], "/x==");
530 assert_tolerant_decode(&forgiving, &mut input, prefix.len(), vec![137, 133], "iYV=");
531 // trailing 10
532 assert_tolerant_decode(&forgiving, &mut input, prefix.len(), vec![255], "/y==");
533 assert_tolerant_decode(&forgiving, &mut input, prefix.len(), vec![137, 133], "iYW=");
534 // trailing 11
535 assert_tolerant_decode(&forgiving, &mut input, prefix.len(), vec![255], "/z==");
536 assert_tolerant_decode(&forgiving, &mut input, prefix.len(), vec![137, 133], "iYX=");
537
538 prefix.push_str("AAAA");
539 }
540 }
541
542 #[apply(all_engines)]
decode_invalid_byte_error<E: EngineWrapper>(engine_wrapper: E)543 fn decode_invalid_byte_error<E: EngineWrapper>(engine_wrapper: E) {
544 let mut rng = seeded_rng();
545
546 let mut orig_data = Vec::<u8>::new();
547 let mut encode_buf = Vec::<u8>::new();
548 let mut decode_buf = Vec::<u8>::new();
549
550 let len_range = distributions::Uniform::new(1, 1_000);
551
552 for _ in 0..10_000 {
553 let alphabet = random_alphabet(&mut rng);
554 let engine = E::random_alphabet(&mut rng, alphabet);
555
556 orig_data.clear();
557 encode_buf.clear();
558 decode_buf.clear();
559
560 let (orig_len, encoded_len_just_data, encoded_len_with_padding) =
561 generate_random_encoded_data(
562 &engine,
563 &mut orig_data,
564 &mut encode_buf,
565 &mut rng,
566 &len_range,
567 );
568
569 // exactly the right size
570 decode_buf.resize(orig_len, 0);
571
572 // replace one encoded byte with an invalid byte
573 let invalid_byte: u8 = loop {
574 let byte: u8 = rng.gen();
575
576 if alphabet.symbols.contains(&byte) {
577 continue;
578 } else {
579 break byte;
580 }
581 };
582
583 let invalid_range = distributions::Uniform::new(0, orig_len);
584 let invalid_index = invalid_range.sample(&mut rng);
585 encode_buf[invalid_index] = invalid_byte;
586
587 assert_eq!(
588 Err(DecodeError::InvalidByte(invalid_index, invalid_byte)),
589 engine.decode_slice_unchecked(
590 &encode_buf[0..encoded_len_with_padding],
591 &mut decode_buf[..],
592 )
593 );
594 }
595 }
596
597 /// Any amount of padding anywhere before the final non padding character = invalid byte at first
598 /// pad byte.
599 /// From this, we know padding must extend to the end of the input.
600 #[apply(all_engines)]
decode_padding_before_final_non_padding_char_error_invalid_byte<E: EngineWrapper>( engine_wrapper: E, )601 fn decode_padding_before_final_non_padding_char_error_invalid_byte<E: EngineWrapper>(
602 engine_wrapper: E,
603 ) {
604 let mut rng = seeded_rng();
605
606 // the different amounts of proper padding, w/ offset from end for the last non-padding char
607 let suffixes = vec![("/w==", 2), ("iYu=", 1), ("zzzz", 0)];
608
609 let prefix_quads_range = distributions::Uniform::from(0..=256);
610
611 for mode in all_pad_modes() {
612 // we don't encode so we don't care about encode padding
613 let engine = E::standard_with_pad_mode(true, mode);
614
615 for _ in 0..100_000 {
616 for (suffix, offset) in suffixes.iter() {
617 let mut s = "ABCD".repeat(prefix_quads_range.sample(&mut rng));
618 s.push_str(suffix);
619 let mut encoded = s.into_bytes();
620
621 // calculate a range to write padding into that leaves at least one non padding char
622 let last_non_padding_offset = encoded.len() - 1 - offset;
623
624 // don't include last non padding char as it must stay not padding
625 let padding_end = rng.gen_range(0..last_non_padding_offset);
626
627 // don't use more than 100 bytes of padding, but also use shorter lengths when
628 // padding_end is near the start of the encoded data to avoid biasing to padding
629 // the entire prefix on short lengths
630 let padding_len = rng.gen_range(1..=usize::min(100, padding_end + 1));
631 let padding_start = padding_end.saturating_sub(padding_len);
632
633 encoded[padding_start..=padding_end].fill(PAD_BYTE);
634
635 assert_eq!(
636 Err(DecodeError::InvalidByte(padding_start, PAD_BYTE)),
637 engine.decode(&encoded),
638 );
639 }
640 }
641 }
642 }
643
644 /// Any amount of padding before final chunk that crosses over into final chunk with 1-4 bytes =
645 /// invalid byte at first pad byte (except for 1 byte suffix = invalid length).
646 /// From this we know the padding must start in the final chunk.
647 #[apply(all_engines)]
decode_padding_starts_before_final_chunk_error_invalid_byte<E: EngineWrapper>( engine_wrapper: E, )648 fn decode_padding_starts_before_final_chunk_error_invalid_byte<E: EngineWrapper>(
649 engine_wrapper: E,
650 ) {
651 let mut rng = seeded_rng();
652
653 // must have at least one prefix quad
654 let prefix_quads_range = distributions::Uniform::from(1..256);
655 // including 1 just to make sure that it really does produce invalid length
656 let suffix_pad_len_range = distributions::Uniform::from(1..=4);
657 for mode in all_pad_modes() {
658 // we don't encode so we don't care about encode padding
659 let engine = E::standard_with_pad_mode(true, mode);
660 for _ in 0..100_000 {
661 let suffix_len = suffix_pad_len_range.sample(&mut rng);
662 let mut encoded = "ABCD"
663 .repeat(prefix_quads_range.sample(&mut rng))
664 .into_bytes();
665 encoded.resize(encoded.len() + suffix_len, PAD_BYTE);
666
667 // amount of padding must be long enough to extend back from suffix into previous
668 // quads
669 let padding_len = rng.gen_range(suffix_len + 1..encoded.len());
670 // no non-padding after padding in this test, so padding goes to the end
671 let padding_start = encoded.len() - padding_len;
672 encoded[padding_start..].fill(PAD_BYTE);
673
674 if suffix_len == 1 {
675 assert_eq!(Err(DecodeError::InvalidLength), engine.decode(&encoded),);
676 } else {
677 assert_eq!(
678 Err(DecodeError::InvalidByte(padding_start, PAD_BYTE)),
679 engine.decode(&encoded),
680 );
681 }
682 }
683 }
684 }
685
686 /// 0-1 bytes of data before any amount of padding in final chunk = invalid byte, since padding
687 /// is not valid data (consistent with error for pad bytes in earlier chunks).
688 /// From this we know there must be 2-3 bytes of data before padding
689 #[apply(all_engines)]
decode_too_little_data_before_padding_error_invalid_byte<E: EngineWrapper>(engine_wrapper: E)690 fn decode_too_little_data_before_padding_error_invalid_byte<E: EngineWrapper>(engine_wrapper: E) {
691 let mut rng = seeded_rng();
692
693 // want to test no prefix quad case, so start at 0
694 let prefix_quads_range = distributions::Uniform::from(0_usize..256);
695 let suffix_data_len_range = distributions::Uniform::from(0_usize..=1);
696 for mode in all_pad_modes() {
697 // we don't encode so we don't care about encode padding
698 let engine = E::standard_with_pad_mode(true, mode);
699 for _ in 0..100_000 {
700 let suffix_data_len = suffix_data_len_range.sample(&mut rng);
701 let prefix_quad_len = prefix_quads_range.sample(&mut rng);
702
703 // ensure there is a suffix quad
704 let min_padding = usize::from(suffix_data_len == 0);
705
706 // for all possible padding lengths
707 for padding_len in min_padding..=(4 - suffix_data_len) {
708 let mut encoded = "ABCD".repeat(prefix_quad_len).into_bytes();
709 encoded.resize(encoded.len() + suffix_data_len, b'A');
710 encoded.resize(encoded.len() + padding_len, PAD_BYTE);
711
712 if suffix_data_len + padding_len == 1 {
713 assert_eq!(Err(DecodeError::InvalidLength), engine.decode(&encoded),);
714 } else {
715 assert_eq!(
716 Err(DecodeError::InvalidByte(
717 prefix_quad_len * 4 + suffix_data_len,
718 PAD_BYTE,
719 )),
720 engine.decode(&encoded),
721 "suffix data len {} pad len {}",
722 suffix_data_len,
723 padding_len
724 );
725 }
726 }
727 }
728 }
729 }
730
731 // https://eprint.iacr.org/2022/361.pdf table 2, test 1
732 #[apply(all_engines)]
decode_malleability_test_case_3_byte_suffix_valid<E: EngineWrapper>(engine_wrapper: E)733 fn decode_malleability_test_case_3_byte_suffix_valid<E: EngineWrapper>(engine_wrapper: E) {
734 assert_eq!(
735 b"Hello".as_slice(),
736 &E::standard().decode("SGVsbG8=").unwrap()
737 );
738 }
739
740 // https://eprint.iacr.org/2022/361.pdf table 2, test 2
741 #[apply(all_engines)]
decode_malleability_test_case_3_byte_suffix_invalid_trailing_symbol<E: EngineWrapper>( engine_wrapper: E, )742 fn decode_malleability_test_case_3_byte_suffix_invalid_trailing_symbol<E: EngineWrapper>(
743 engine_wrapper: E,
744 ) {
745 assert_eq!(
746 DecodeError::InvalidLastSymbol(6, 0x39),
747 E::standard().decode("SGVsbG9=").unwrap_err()
748 );
749 }
750
751 // https://eprint.iacr.org/2022/361.pdf table 2, test 3
752 #[apply(all_engines)]
decode_malleability_test_case_3_byte_suffix_no_padding<E: EngineWrapper>(engine_wrapper: E)753 fn decode_malleability_test_case_3_byte_suffix_no_padding<E: EngineWrapper>(engine_wrapper: E) {
754 assert_eq!(
755 DecodeError::InvalidPadding,
756 E::standard().decode("SGVsbG9").unwrap_err()
757 );
758 }
759
760 // https://eprint.iacr.org/2022/361.pdf table 2, test 4
761 #[apply(all_engines)]
decode_malleability_test_case_2_byte_suffix_valid_two_padding_symbols<E: EngineWrapper>( engine_wrapper: E, )762 fn decode_malleability_test_case_2_byte_suffix_valid_two_padding_symbols<E: EngineWrapper>(
763 engine_wrapper: E,
764 ) {
765 assert_eq!(
766 b"Hell".as_slice(),
767 &E::standard().decode("SGVsbA==").unwrap()
768 );
769 }
770
771 // https://eprint.iacr.org/2022/361.pdf table 2, test 5
772 #[apply(all_engines)]
decode_malleability_test_case_2_byte_suffix_short_padding<E: EngineWrapper>(engine_wrapper: E)773 fn decode_malleability_test_case_2_byte_suffix_short_padding<E: EngineWrapper>(engine_wrapper: E) {
774 assert_eq!(
775 DecodeError::InvalidPadding,
776 E::standard().decode("SGVsbA=").unwrap_err()
777 );
778 }
779
780 // https://eprint.iacr.org/2022/361.pdf table 2, test 6
781 #[apply(all_engines)]
decode_malleability_test_case_2_byte_suffix_no_padding<E: EngineWrapper>(engine_wrapper: E)782 fn decode_malleability_test_case_2_byte_suffix_no_padding<E: EngineWrapper>(engine_wrapper: E) {
783 assert_eq!(
784 DecodeError::InvalidPadding,
785 E::standard().decode("SGVsbA").unwrap_err()
786 );
787 }
788
789 // https://eprint.iacr.org/2022/361.pdf table 2, test 7
790 #[apply(all_engines)]
decode_malleability_test_case_2_byte_suffix_too_much_padding<E: EngineWrapper>( engine_wrapper: E, )791 fn decode_malleability_test_case_2_byte_suffix_too_much_padding<E: EngineWrapper>(
792 engine_wrapper: E,
793 ) {
794 assert_eq!(
795 DecodeError::InvalidByte(6, PAD_BYTE),
796 E::standard().decode("SGVsbA====").unwrap_err()
797 );
798 }
799
800 /// Requires canonical padding -> accepts 2 + 2, 3 + 1, 4 + 0 final quad configurations
801 #[apply(all_engines)]
decode_pad_mode_requires_canonical_accepts_canonical<E: EngineWrapper>(engine_wrapper: E)802 fn decode_pad_mode_requires_canonical_accepts_canonical<E: EngineWrapper>(engine_wrapper: E) {
803 assert_all_suffixes_ok(
804 E::standard_with_pad_mode(true, DecodePaddingMode::RequireCanonical),
805 vec!["/w==", "iYU=", "AAAA"],
806 );
807 }
808
809 /// Requires canonical padding -> rejects 2 + 0-1, 3 + 0 final chunk configurations
810 #[apply(all_engines)]
decode_pad_mode_requires_canonical_rejects_non_canonical<E: EngineWrapper>(engine_wrapper: E)811 fn decode_pad_mode_requires_canonical_rejects_non_canonical<E: EngineWrapper>(engine_wrapper: E) {
812 let engine = E::standard_with_pad_mode(true, DecodePaddingMode::RequireCanonical);
813
814 let suffixes = vec!["/w", "/w=", "iYU"];
815 for num_prefix_quads in 0..256 {
816 for &suffix in suffixes.iter() {
817 let mut encoded = "AAAA".repeat(num_prefix_quads);
818 encoded.push_str(suffix);
819
820 let res = engine.decode(&encoded);
821
822 assert_eq!(Err(DecodeError::InvalidPadding), res);
823 }
824 }
825 }
826
827 /// Requires no padding -> accepts 2 + 0, 3 + 0, 4 + 0 final chunk configuration
828 #[apply(all_engines)]
decode_pad_mode_requires_no_padding_accepts_no_padding<E: EngineWrapper>(engine_wrapper: E)829 fn decode_pad_mode_requires_no_padding_accepts_no_padding<E: EngineWrapper>(engine_wrapper: E) {
830 assert_all_suffixes_ok(
831 E::standard_with_pad_mode(true, DecodePaddingMode::RequireNone),
832 vec!["/w", "iYU", "AAAA"],
833 );
834 }
835
836 /// Requires no padding -> rejects 2 + 1-2, 3 + 1 final chunk configuration
837 #[apply(all_engines)]
decode_pad_mode_requires_no_padding_rejects_any_padding<E: EngineWrapper>(engine_wrapper: E)838 fn decode_pad_mode_requires_no_padding_rejects_any_padding<E: EngineWrapper>(engine_wrapper: E) {
839 let engine = E::standard_with_pad_mode(true, DecodePaddingMode::RequireNone);
840
841 let suffixes = vec!["/w=", "/w==", "iYU="];
842 for num_prefix_quads in 0..256 {
843 for &suffix in suffixes.iter() {
844 let mut encoded = "AAAA".repeat(num_prefix_quads);
845 encoded.push_str(suffix);
846
847 let res = engine.decode(&encoded);
848
849 assert_eq!(Err(DecodeError::InvalidPadding), res);
850 }
851 }
852 }
853
854 /// Indifferent padding accepts 2 + 0-2, 3 + 0-1, 4 + 0 final chunk configuration
855 #[apply(all_engines)]
decode_pad_mode_indifferent_padding_accepts_anything<E: EngineWrapper>(engine_wrapper: E)856 fn decode_pad_mode_indifferent_padding_accepts_anything<E: EngineWrapper>(engine_wrapper: E) {
857 assert_all_suffixes_ok(
858 E::standard_with_pad_mode(true, DecodePaddingMode::Indifferent),
859 vec!["/w", "/w=", "/w==", "iYU", "iYU=", "AAAA"],
860 );
861 }
862
863 //this is a MAY in the rfc: https://tools.ietf.org/html/rfc4648#section-3.3
864 #[apply(all_engines)]
decode_pad_byte_in_penultimate_quad_error<E: EngineWrapper>(engine_wrapper: E)865 fn decode_pad_byte_in_penultimate_quad_error<E: EngineWrapper>(engine_wrapper: E) {
866 for mode in all_pad_modes() {
867 // we don't encode so we don't care about encode padding
868 let engine = E::standard_with_pad_mode(true, mode);
869
870 for num_prefix_quads in 0..256 {
871 // leave room for at least one pad byte in penultimate quad
872 for num_valid_bytes_penultimate_quad in 0..4 {
873 // can't have 1 or it would be invalid length
874 for num_pad_bytes_in_final_quad in 2..=4 {
875 let mut s: String = "ABCD".repeat(num_prefix_quads);
876
877 // varying amounts of padding in the penultimate quad
878 for _ in 0..num_valid_bytes_penultimate_quad {
879 s.push('A');
880 }
881 // finish penultimate quad with padding
882 for _ in num_valid_bytes_penultimate_quad..4 {
883 s.push('=');
884 }
885 // and more padding in the final quad
886 for _ in 0..num_pad_bytes_in_final_quad {
887 s.push('=');
888 }
889
890 // padding should be an invalid byte before the final quad.
891 // Could argue that the *next* padding byte (in the next quad) is technically the first
892 // erroneous one, but reporting that accurately is more complex and probably nobody cares
893 assert_eq!(
894 DecodeError::InvalidByte(
895 num_prefix_quads * 4 + num_valid_bytes_penultimate_quad,
896 b'=',
897 ),
898 engine.decode(&s).unwrap_err()
899 );
900 }
901 }
902 }
903 }
904 }
905
906 #[apply(all_engines)]
decode_bytes_after_padding_in_final_quad_error<E: EngineWrapper>(engine_wrapper: E)907 fn decode_bytes_after_padding_in_final_quad_error<E: EngineWrapper>(engine_wrapper: E) {
908 for mode in all_pad_modes() {
909 // we don't encode so we don't care about encode padding
910 let engine = E::standard_with_pad_mode(true, mode);
911
912 for num_prefix_quads in 0..256 {
913 // leave at least one byte in the quad for padding
914 for bytes_after_padding in 1..4 {
915 let mut s: String = "ABCD".repeat(num_prefix_quads);
916
917 // every invalid padding position with a 3-byte final quad: 1 to 3 bytes after padding
918 for _ in 0..(3 - bytes_after_padding) {
919 s.push('A');
920 }
921 s.push('=');
922 for _ in 0..bytes_after_padding {
923 s.push('A');
924 }
925
926 // First (and only) padding byte is invalid.
927 assert_eq!(
928 DecodeError::InvalidByte(
929 num_prefix_quads * 4 + (3 - bytes_after_padding),
930 b'='
931 ),
932 engine.decode(&s).unwrap_err()
933 );
934 }
935 }
936 }
937 }
938
939 #[apply(all_engines)]
decode_absurd_pad_error<E: EngineWrapper>(engine_wrapper: E)940 fn decode_absurd_pad_error<E: EngineWrapper>(engine_wrapper: E) {
941 for mode in all_pad_modes() {
942 // we don't encode so we don't care about encode padding
943 let engine = E::standard_with_pad_mode(true, mode);
944
945 for num_prefix_quads in 0..256 {
946 let mut s: String = "ABCD".repeat(num_prefix_quads);
947 s.push_str("==Y=Wx===pY=2U=====");
948
949 // first padding byte
950 assert_eq!(
951 DecodeError::InvalidByte(num_prefix_quads * 4, b'='),
952 engine.decode(&s).unwrap_err()
953 );
954 }
955 }
956 }
957
958 #[apply(all_engines)]
decode_too_much_padding_returns_error<E: EngineWrapper>(engine_wrapper: E)959 fn decode_too_much_padding_returns_error<E: EngineWrapper>(engine_wrapper: E) {
960 for mode in all_pad_modes() {
961 // we don't encode so we don't care about encode padding
962 let engine = E::standard_with_pad_mode(true, mode);
963
964 for num_prefix_quads in 0..256 {
965 // add enough padding to ensure that we'll hit all decode stages at the different lengths
966 for pad_bytes in 1..=64 {
967 let mut s: String = "ABCD".repeat(num_prefix_quads);
968 let padding: String = "=".repeat(pad_bytes);
969 s.push_str(&padding);
970
971 if pad_bytes % 4 == 1 {
972 assert_eq!(DecodeError::InvalidLength, engine.decode(&s).unwrap_err());
973 } else {
974 assert_eq!(
975 DecodeError::InvalidByte(num_prefix_quads * 4, b'='),
976 engine.decode(&s).unwrap_err()
977 );
978 }
979 }
980 }
981 }
982 }
983
984 #[apply(all_engines)]
decode_padding_followed_by_non_padding_returns_error<E: EngineWrapper>(engine_wrapper: E)985 fn decode_padding_followed_by_non_padding_returns_error<E: EngineWrapper>(engine_wrapper: E) {
986 for mode in all_pad_modes() {
987 // we don't encode so we don't care about encode padding
988 let engine = E::standard_with_pad_mode(true, mode);
989
990 for num_prefix_quads in 0..256 {
991 for pad_bytes in 0..=32 {
992 let mut s: String = "ABCD".repeat(num_prefix_quads);
993 let padding: String = "=".repeat(pad_bytes);
994 s.push_str(&padding);
995 s.push('E');
996
997 if pad_bytes % 4 == 0 {
998 assert_eq!(DecodeError::InvalidLength, engine.decode(&s).unwrap_err());
999 } else {
1000 assert_eq!(
1001 DecodeError::InvalidByte(num_prefix_quads * 4, b'='),
1002 engine.decode(&s).unwrap_err()
1003 );
1004 }
1005 }
1006 }
1007 }
1008 }
1009
1010 #[apply(all_engines)]
decode_one_char_in_final_quad_with_padding_error<E: EngineWrapper>(engine_wrapper: E)1011 fn decode_one_char_in_final_quad_with_padding_error<E: EngineWrapper>(engine_wrapper: E) {
1012 for mode in all_pad_modes() {
1013 // we don't encode so we don't care about encode padding
1014 let engine = E::standard_with_pad_mode(true, mode);
1015
1016 for num_prefix_quads in 0..256 {
1017 let mut s: String = "ABCD".repeat(num_prefix_quads);
1018 s.push_str("E=");
1019
1020 assert_eq!(
1021 DecodeError::InvalidByte(num_prefix_quads * 4 + 1, b'='),
1022 engine.decode(&s).unwrap_err()
1023 );
1024
1025 // more padding doesn't change the error
1026 s.push('=');
1027 assert_eq!(
1028 DecodeError::InvalidByte(num_prefix_quads * 4 + 1, b'='),
1029 engine.decode(&s).unwrap_err()
1030 );
1031
1032 s.push('=');
1033 assert_eq!(
1034 DecodeError::InvalidByte(num_prefix_quads * 4 + 1, b'='),
1035 engine.decode(&s).unwrap_err()
1036 );
1037 }
1038 }
1039 }
1040
1041 #[apply(all_engines)]
decode_too_few_symbols_in_final_quad_error<E: EngineWrapper>(engine_wrapper: E)1042 fn decode_too_few_symbols_in_final_quad_error<E: EngineWrapper>(engine_wrapper: E) {
1043 for mode in all_pad_modes() {
1044 // we don't encode so we don't care about encode padding
1045 let engine = E::standard_with_pad_mode(true, mode);
1046
1047 for num_prefix_quads in 0..256 {
1048 // <2 is invalid
1049 for final_quad_symbols in 0..2 {
1050 for padding_symbols in 0..=(4 - final_quad_symbols) {
1051 let mut s: String = "ABCD".repeat(num_prefix_quads);
1052
1053 for _ in 0..final_quad_symbols {
1054 s.push('A');
1055 }
1056 for _ in 0..padding_symbols {
1057 s.push('=');
1058 }
1059
1060 match final_quad_symbols + padding_symbols {
1061 0 => continue,
1062 1 => {
1063 assert_eq!(DecodeError::InvalidLength, engine.decode(&s).unwrap_err());
1064 }
1065 _ => {
1066 // error reported at first padding byte
1067 assert_eq!(
1068 DecodeError::InvalidByte(
1069 num_prefix_quads * 4 + final_quad_symbols,
1070 b'=',
1071 ),
1072 engine.decode(&s).unwrap_err()
1073 );
1074 }
1075 }
1076 }
1077 }
1078 }
1079 }
1080 }
1081
1082 #[apply(all_engines)]
decode_invalid_trailing_bytes<E: EngineWrapper>(engine_wrapper: E)1083 fn decode_invalid_trailing_bytes<E: EngineWrapper>(engine_wrapper: E) {
1084 for mode in all_pad_modes() {
1085 // we don't encode so we don't care about encode padding
1086 let engine = E::standard_with_pad_mode(true, mode);
1087
1088 for num_prefix_quads in 0..256 {
1089 let mut s: String = "ABCD".repeat(num_prefix_quads);
1090 s.push_str("Cg==\n");
1091
1092 // The case of trailing newlines is common enough to warrant a test for a good error
1093 // message.
1094 assert_eq!(
1095 Err(DecodeError::InvalidByte(num_prefix_quads * 4 + 4, b'\n')),
1096 engine.decode(&s)
1097 );
1098
1099 // extra padding, however, is still InvalidLength
1100 let s = s.replace('\n', "=");
1101 assert_eq!(Err(DecodeError::InvalidLength), engine.decode(s));
1102 }
1103 }
1104 }
1105
1106 #[apply(all_engines)]
decode_wrong_length_error<E: EngineWrapper>(engine_wrapper: E)1107 fn decode_wrong_length_error<E: EngineWrapper>(engine_wrapper: E) {
1108 let engine = E::standard_with_pad_mode(true, DecodePaddingMode::Indifferent);
1109
1110 for num_prefix_quads in 0..256 {
1111 // at least one token, otherwise it wouldn't be a final quad
1112 for num_tokens_final_quad in 1..=4 {
1113 for num_padding in 0..=(4 - num_tokens_final_quad) {
1114 let mut s: String = "IIII".repeat(num_prefix_quads);
1115 for _ in 0..num_tokens_final_quad {
1116 s.push('g');
1117 }
1118 for _ in 0..num_padding {
1119 s.push('=');
1120 }
1121
1122 let res = engine.decode(&s);
1123 if num_tokens_final_quad >= 2 {
1124 assert!(res.is_ok());
1125 } else if num_tokens_final_quad == 1 && num_padding > 0 {
1126 // = is invalid if it's too early
1127 assert_eq!(
1128 Err(DecodeError::InvalidByte(
1129 num_prefix_quads * 4 + num_tokens_final_quad,
1130 61
1131 )),
1132 res
1133 );
1134 } else if num_padding > 2 {
1135 assert_eq!(Err(DecodeError::InvalidPadding), res);
1136 } else {
1137 assert_eq!(Err(DecodeError::InvalidLength), res);
1138 }
1139 }
1140 }
1141 }
1142 }
1143
1144 #[apply(all_engines)]
decode_into_slice_fits_in_precisely_sized_slice<E: EngineWrapper>(engine_wrapper: E)1145 fn decode_into_slice_fits_in_precisely_sized_slice<E: EngineWrapper>(engine_wrapper: E) {
1146 let mut orig_data = Vec::new();
1147 let mut encoded_data = String::new();
1148 let mut decode_buf = Vec::new();
1149
1150 let input_len_range = distributions::Uniform::new(0, 1000);
1151 let mut rng = rngs::SmallRng::from_entropy();
1152
1153 for _ in 0..10_000 {
1154 orig_data.clear();
1155 encoded_data.clear();
1156 decode_buf.clear();
1157
1158 let input_len = input_len_range.sample(&mut rng);
1159
1160 for _ in 0..input_len {
1161 orig_data.push(rng.gen());
1162 }
1163
1164 let engine = E::random(&mut rng);
1165 engine.encode_string(&orig_data, &mut encoded_data);
1166 assert_encode_sanity(&encoded_data, engine.config().encode_padding(), input_len);
1167
1168 decode_buf.resize(input_len, 0);
1169
1170 // decode into the non-empty buf
1171 let decode_bytes_written = engine
1172 .decode_slice_unchecked(encoded_data.as_bytes(), &mut decode_buf[..])
1173 .unwrap();
1174
1175 assert_eq!(orig_data.len(), decode_bytes_written);
1176 assert_eq!(orig_data, decode_buf);
1177 }
1178 }
1179
1180 #[apply(all_engines)]
decode_length_estimate_delta<E: EngineWrapper>(engine_wrapper: E)1181 fn decode_length_estimate_delta<E: EngineWrapper>(engine_wrapper: E) {
1182 for engine in [E::standard(), E::standard_unpadded()] {
1183 for &padding in &[true, false] {
1184 for orig_len in 0..1000 {
1185 let encoded_len = encoded_len(orig_len, padding).unwrap();
1186
1187 let decoded_estimate = engine
1188 .internal_decoded_len_estimate(encoded_len)
1189 .decoded_len_estimate();
1190 assert!(decoded_estimate >= orig_len);
1191 assert!(
1192 decoded_estimate - orig_len < 3,
1193 "estimate: {}, encoded: {}, orig: {}",
1194 decoded_estimate,
1195 encoded_len,
1196 orig_len
1197 );
1198 }
1199 }
1200 }
1201 }
1202
1203 /// Returns a tuple of the original data length, the encoded data length (just data), and the length including padding.
1204 ///
1205 /// Vecs provided should be empty.
generate_random_encoded_data<E: Engine, R: rand::Rng, D: distributions::Distribution<usize>>( engine: &E, orig_data: &mut Vec<u8>, encode_buf: &mut Vec<u8>, rng: &mut R, length_distribution: &D, ) -> (usize, usize, usize)1206 fn generate_random_encoded_data<E: Engine, R: rand::Rng, D: distributions::Distribution<usize>>(
1207 engine: &E,
1208 orig_data: &mut Vec<u8>,
1209 encode_buf: &mut Vec<u8>,
1210 rng: &mut R,
1211 length_distribution: &D,
1212 ) -> (usize, usize, usize) {
1213 let padding: bool = engine.config().encode_padding();
1214
1215 let orig_len = fill_rand(orig_data, rng, length_distribution);
1216 let expected_encoded_len = encoded_len(orig_len, padding).unwrap();
1217 encode_buf.resize(expected_encoded_len, 0);
1218
1219 let base_encoded_len = engine.internal_encode(&orig_data[..], &mut encode_buf[..]);
1220
1221 let enc_len_with_padding = if padding {
1222 base_encoded_len + add_padding(orig_len, &mut encode_buf[base_encoded_len..])
1223 } else {
1224 base_encoded_len
1225 };
1226
1227 assert_eq!(expected_encoded_len, enc_len_with_padding);
1228
1229 (orig_len, base_encoded_len, enc_len_with_padding)
1230 }
1231
1232 // fill to a random length
fill_rand<R: rand::Rng, D: distributions::Distribution<usize>>( vec: &mut Vec<u8>, rng: &mut R, length_distribution: &D, ) -> usize1233 fn fill_rand<R: rand::Rng, D: distributions::Distribution<usize>>(
1234 vec: &mut Vec<u8>,
1235 rng: &mut R,
1236 length_distribution: &D,
1237 ) -> usize {
1238 let len = length_distribution.sample(rng);
1239 for _ in 0..len {
1240 vec.push(rng.gen());
1241 }
1242
1243 len
1244 }
1245
fill_rand_len<R: rand::Rng>(vec: &mut Vec<u8>, rng: &mut R, len: usize)1246 fn fill_rand_len<R: rand::Rng>(vec: &mut Vec<u8>, rng: &mut R, len: usize) {
1247 for _ in 0..len {
1248 vec.push(rng.gen());
1249 }
1250 }
1251
prefixed_data<'i, 'd>( input_with_prefix: &'i mut String, prefix_len: usize, data: &'d str, ) -> &'i str1252 fn prefixed_data<'i, 'd>(
1253 input_with_prefix: &'i mut String,
1254 prefix_len: usize,
1255 data: &'d str,
1256 ) -> &'i str {
1257 input_with_prefix.truncate(prefix_len);
1258 input_with_prefix.push_str(data);
1259 input_with_prefix.as_str()
1260 }
1261
1262 /// A wrapper to make using engines in rstest fixtures easier.
1263 /// The functions don't need to be instance methods, but rstest does seem
1264 /// to want an instance, so instances are passed to test functions and then ignored.
1265 trait EngineWrapper {
1266 type Engine: Engine;
1267
1268 /// Return an engine configured for RFC standard base64
standard() -> Self::Engine1269 fn standard() -> Self::Engine;
1270
1271 /// Return an engine configured for RFC standard base64, except with no padding appended on
1272 /// encode, and required no padding on decode.
standard_unpadded() -> Self::Engine1273 fn standard_unpadded() -> Self::Engine;
1274
1275 /// Return an engine configured for RFC standard alphabet with the provided encode and decode
1276 /// pad settings
standard_with_pad_mode(encode_pad: bool, decode_pad_mode: DecodePaddingMode) -> Self::Engine1277 fn standard_with_pad_mode(encode_pad: bool, decode_pad_mode: DecodePaddingMode)
1278 -> Self::Engine;
1279
1280 /// Return an engine configured for RFC standard base64 that allows invalid trailing bits
standard_allow_trailing_bits() -> Self::Engine1281 fn standard_allow_trailing_bits() -> Self::Engine;
1282
1283 /// Return an engine configured with a randomized alphabet and config
random<R: rand::Rng>(rng: &mut R) -> Self::Engine1284 fn random<R: rand::Rng>(rng: &mut R) -> Self::Engine;
1285
1286 /// Return an engine configured with the specified alphabet and randomized config
random_alphabet<R: rand::Rng>(rng: &mut R, alphabet: &Alphabet) -> Self::Engine1287 fn random_alphabet<R: rand::Rng>(rng: &mut R, alphabet: &Alphabet) -> Self::Engine;
1288 }
1289
1290 struct GeneralPurposeWrapper {}
1291
1292 impl EngineWrapper for GeneralPurposeWrapper {
1293 type Engine = general_purpose::GeneralPurpose;
1294
standard() -> Self::Engine1295 fn standard() -> Self::Engine {
1296 general_purpose::GeneralPurpose::new(&STANDARD, general_purpose::PAD)
1297 }
1298
standard_unpadded() -> Self::Engine1299 fn standard_unpadded() -> Self::Engine {
1300 general_purpose::GeneralPurpose::new(&STANDARD, general_purpose::NO_PAD)
1301 }
1302
standard_with_pad_mode( encode_pad: bool, decode_pad_mode: DecodePaddingMode, ) -> Self::Engine1303 fn standard_with_pad_mode(
1304 encode_pad: bool,
1305 decode_pad_mode: DecodePaddingMode,
1306 ) -> Self::Engine {
1307 general_purpose::GeneralPurpose::new(
1308 &STANDARD,
1309 general_purpose::GeneralPurposeConfig::new()
1310 .with_encode_padding(encode_pad)
1311 .with_decode_padding_mode(decode_pad_mode),
1312 )
1313 }
1314
standard_allow_trailing_bits() -> Self::Engine1315 fn standard_allow_trailing_bits() -> Self::Engine {
1316 general_purpose::GeneralPurpose::new(
1317 &STANDARD,
1318 general_purpose::GeneralPurposeConfig::new().with_decode_allow_trailing_bits(true),
1319 )
1320 }
1321
random<R: rand::Rng>(rng: &mut R) -> Self::Engine1322 fn random<R: rand::Rng>(rng: &mut R) -> Self::Engine {
1323 let alphabet = random_alphabet(rng);
1324
1325 Self::random_alphabet(rng, alphabet)
1326 }
1327
random_alphabet<R: rand::Rng>(rng: &mut R, alphabet: &Alphabet) -> Self::Engine1328 fn random_alphabet<R: rand::Rng>(rng: &mut R, alphabet: &Alphabet) -> Self::Engine {
1329 general_purpose::GeneralPurpose::new(alphabet, random_config(rng))
1330 }
1331 }
1332
1333 struct NaiveWrapper {}
1334
1335 impl EngineWrapper for NaiveWrapper {
1336 type Engine = naive::Naive;
1337
standard() -> Self::Engine1338 fn standard() -> Self::Engine {
1339 naive::Naive::new(
1340 &STANDARD,
1341 naive::NaiveConfig {
1342 encode_padding: true,
1343 decode_allow_trailing_bits: false,
1344 decode_padding_mode: DecodePaddingMode::RequireCanonical,
1345 },
1346 )
1347 }
1348
standard_unpadded() -> Self::Engine1349 fn standard_unpadded() -> Self::Engine {
1350 naive::Naive::new(
1351 &STANDARD,
1352 naive::NaiveConfig {
1353 encode_padding: false,
1354 decode_allow_trailing_bits: false,
1355 decode_padding_mode: DecodePaddingMode::RequireNone,
1356 },
1357 )
1358 }
1359
standard_with_pad_mode( encode_pad: bool, decode_pad_mode: DecodePaddingMode, ) -> Self::Engine1360 fn standard_with_pad_mode(
1361 encode_pad: bool,
1362 decode_pad_mode: DecodePaddingMode,
1363 ) -> Self::Engine {
1364 naive::Naive::new(
1365 &STANDARD,
1366 naive::NaiveConfig {
1367 encode_padding: false,
1368 decode_allow_trailing_bits: false,
1369 decode_padding_mode: decode_pad_mode,
1370 },
1371 )
1372 }
1373
standard_allow_trailing_bits() -> Self::Engine1374 fn standard_allow_trailing_bits() -> Self::Engine {
1375 naive::Naive::new(
1376 &STANDARD,
1377 naive::NaiveConfig {
1378 encode_padding: true,
1379 decode_allow_trailing_bits: true,
1380 decode_padding_mode: DecodePaddingMode::RequireCanonical,
1381 },
1382 )
1383 }
1384
random<R: rand::Rng>(rng: &mut R) -> Self::Engine1385 fn random<R: rand::Rng>(rng: &mut R) -> Self::Engine {
1386 let alphabet = random_alphabet(rng);
1387
1388 Self::random_alphabet(rng, alphabet)
1389 }
1390
random_alphabet<R: rand::Rng>(rng: &mut R, alphabet: &Alphabet) -> Self::Engine1391 fn random_alphabet<R: rand::Rng>(rng: &mut R, alphabet: &Alphabet) -> Self::Engine {
1392 let mode = rng.gen();
1393
1394 let config = naive::NaiveConfig {
1395 encode_padding: match mode {
1396 DecodePaddingMode::Indifferent => rng.gen(),
1397 DecodePaddingMode::RequireCanonical => true,
1398 DecodePaddingMode::RequireNone => false,
1399 },
1400 decode_allow_trailing_bits: rng.gen(),
1401 decode_padding_mode: mode,
1402 };
1403
1404 naive::Naive::new(alphabet, config)
1405 }
1406 }
1407
seeded_rng() -> impl rand::Rng1408 fn seeded_rng() -> impl rand::Rng {
1409 rngs::SmallRng::from_entropy()
1410 }
1411
all_pad_modes() -> Vec<DecodePaddingMode>1412 fn all_pad_modes() -> Vec<DecodePaddingMode> {
1413 vec![
1414 DecodePaddingMode::Indifferent,
1415 DecodePaddingMode::RequireCanonical,
1416 DecodePaddingMode::RequireNone,
1417 ]
1418 }
1419
assert_all_suffixes_ok<E: Engine>(engine: E, suffixes: Vec<&str>)1420 fn assert_all_suffixes_ok<E: Engine>(engine: E, suffixes: Vec<&str>) {
1421 for num_prefix_quads in 0..256 {
1422 for &suffix in suffixes.iter() {
1423 let mut encoded = "AAAA".repeat(num_prefix_quads);
1424 encoded.push_str(suffix);
1425
1426 let res = &engine.decode(&encoded);
1427 assert!(res.is_ok());
1428 }
1429 }
1430 }
1431