Skip to content

Commit

Permalink
Fix the Base 64 symbol converter. (#212)
Browse files Browse the repository at this point in the history
This PR fixes util::base64::SymbolConverter to also include the final group
in the output if there is padding.
  • Loading branch information
partim authored Sep 18, 2023
1 parent 500930e commit a6fef8f
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 30 deletions.
4 changes: 2 additions & 2 deletions src/rdata/dnssec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2437,10 +2437,10 @@ mod test {

#[test]
fn dnskey_compose_parse_scan() {
let rdata = Dnskey::new(10, 11, SecAlg::RsaSha1, b"key").unwrap();
let rdata = Dnskey::new(10, 11, SecAlg::RsaSha1, b"key0").unwrap();
test_rdlen(&rdata);
test_compose_parse(&rdata, |parser| Dnskey::parse(parser));
test_scan(&["10", "11", "RSASHA1", "a2V5"], Dnskey::scan, &rdata);
test_scan(&["10", "11", "RSASHA1", "a2V5MA=="], Dnskey::scan, &rdata);
}

//--- Rrsig
Expand Down
102 changes: 74 additions & 28 deletions src/utils/base64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ impl SymbolConverter {
&mut self,
ch: char,
) -> Result<Option<&[u8]>, Error> {
if self.next == 0xF0 {
if self.next == EOF_MARKER {
return Err(Error::custom("trailing Base 64 data"));
}

Expand All @@ -352,7 +352,7 @@ impl SymbolConverter {
if self.next < 2 {
return Err(Error::custom("illegal Base 64 data"));
}
0x80 // Acts as a marker later on.
PAD_MARKER // Acts as a marker later on.
} else {
if ch > (127 as char) {
return Err(Error::custom("illegal Base 64 data"));
Expand All @@ -368,19 +368,29 @@ impl SymbolConverter {

if self.next == 4 {
self.output[0] = self.input[0] << 2 | self.input[1] >> 4;
if self.input[2] != 0x80 {
self.output[1] = self.input[1] << 4 | self.input[2] >> 2;
}
if self.input[3] != 0x80 {
if self.input[2] == 0x80 {
return Err(Error::custom("trailing Base 64 data"));

if self.input[2] == PAD_MARKER {
// The second to last character is padding. The last one
// needs to be, too.
if self.input[3] == PAD_MARKER {
self.next = EOF_MARKER;
Ok(Some(&self.output[..1]))
} else {
Err(Error::custom("illegal Base 64 data"))
}
self.output[2] = (self.input[2] << 6) | self.input[3];
self.next = 0
} else {
self.next = 0xF0
self.output[1] = self.input[1] << 4 | self.input[2] >> 2;

if self.input[3] == PAD_MARKER {
// The last characters is padding.
self.next = EOF_MARKER;
Ok(Some(&self.output[..2]))
} else {
self.output[2] = (self.input[2] << 6) | self.input[3];
self.next = 0;
Ok(Some(&self.output))
}
}
Ok(Some(&self.output))
} else {
Ok(None)
}
Expand Down Expand Up @@ -500,26 +510,39 @@ const ENCODE_ALPHABET: [char; 64] = [
/// The padding character
const PAD: char = '=';

/// The marker for padding.
const PAD_MARKER: u8 = 0x80;

/// The marker for complete data.
const EOF_MARKER: usize = 0xF0;

//============ Test ==========================================================

#[cfg(test)]
mod test {
use super::*;

Check warning on line 523 in src/utils/base64.rs

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 1.67.0)

unused import: `super::*`

Check warning on line 523 in src/utils/base64.rs

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, stable)

unused import: `super::*`

Check warning on line 523 in src/utils/base64.rs

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, beta)

unused import: `super::*`

Check warning on line 523 in src/utils/base64.rs

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, nightly)

unused import: `super::*`

Check warning on line 523 in src/utils/base64.rs

View workflow job for this annotation

GitHub Actions / test (windows-latest, 1.67.0)

unused import: `super::*`

Check warning on line 523 in src/utils/base64.rs

View workflow job for this annotation

GitHub Actions / test (windows-latest, stable)

unused import: `super::*`

Check warning on line 523 in src/utils/base64.rs

View workflow job for this annotation

GitHub Actions / test (windows-latest, beta)

unused import: `super::*`

Check warning on line 523 in src/utils/base64.rs

View workflow job for this annotation

GitHub Actions / test (windows-latest, nightly)

unused import: `super::*`

Check warning on line 523 in src/utils/base64.rs

View workflow job for this annotation

GitHub Actions / test (macOS-latest, 1.67.0)

unused import: `super::*`

Check warning on line 523 in src/utils/base64.rs

View workflow job for this annotation

GitHub Actions / test (macOS-latest, stable)

unused import: `super::*`

Check warning on line 523 in src/utils/base64.rs

View workflow job for this annotation

GitHub Actions / test (macOS-latest, beta)

unused import: `super::*`

Check warning on line 523 in src/utils/base64.rs

View workflow job for this annotation

GitHub Actions / test (macOS-latest, nightly)

unused import: `super::*`

#[allow(dead_code)]
const HAPPY_CASES: &[(&[u8], &str)] = &[
(b"", ""),
(b"f", "Zg=="),
(b"fo", "Zm8="),
(b"foo", "Zm9v"),
(b"foob", "Zm9vYg=="),
(b"fooba", "Zm9vYmE="),
(b"foobar", "Zm9vYmFy"),
];

#[cfg(feature = "std")]
#[test]
fn decode_str() {
use super::DecodeError;

fn decode(s: &str) -> Result<std::vec::Vec<u8>, DecodeError> {
super::decode(s)
}

assert_eq!(&decode("").unwrap(), b"");
assert_eq!(&decode("Zg==").unwrap(), b"f");
assert_eq!(&decode("Zm8=").unwrap(), b"fo");
assert_eq!(&decode("Zm9v").unwrap(), b"foo");
assert_eq!(&decode("Zm9vYg==").unwrap(), b"foob");
assert_eq!(&decode("Zm9vYmE=").unwrap(), b"fooba");
assert_eq!(&decode("Zm9vYmFy").unwrap(), b"foobar");
for (bin, text) in HAPPY_CASES {
assert_eq!(&decode(text).unwrap(), bin, "decode {}", text)
}

assert_eq!(decode("FPucA").unwrap_err(), DecodeError::ShortInput);
assert_eq!(
Expand All @@ -537,6 +560,33 @@ mod test {
);
}

#[cfg(feature = "std")]
#[test]
fn symbol_converter() {
use crate::base::scan::Symbols;
use std::vec::Vec;

fn decode(s: &str) -> Result<Vec<u8>, std::io::Error> {
let mut convert = SymbolConverter::new();
let convert: &mut dyn ConvertSymbols<_, std::io::Error> =
&mut convert;
let mut res = Vec::new();
for sym in Symbols::new(s.chars()) {
if let Some(octs) = convert.process_symbol(sym)? {
res.extend_from_slice(octs);
}
}
if let Some(octs) = convert.process_tail()? {
res.extend_from_slice(octs);
}
Ok(res)
}

for (bin, text) in HAPPY_CASES {
assert_eq!(&decode(text).unwrap(), bin, "convert {}", text)
}
}

#[test]
#[cfg(feature = "std")]
fn display_bytes() {
Expand All @@ -548,12 +598,8 @@ mod test {
out
}

assert_eq!(fmt(b""), "");
assert_eq!(fmt(b"f"), "Zg==");
assert_eq!(fmt(b"fo"), "Zm8=");
assert_eq!(fmt(b"foo"), "Zm9v");
assert_eq!(fmt(b"foob"), "Zm9vYg==");
assert_eq!(fmt(b"fooba"), "Zm9vYmE=");
assert_eq!(fmt(b"foobar"), "Zm9vYmFy");
for (bin, text) in HAPPY_CASES {
assert_eq!(&fmt(bin), text, "fmt {}", text);
}
}
}

0 comments on commit a6fef8f

Please sign in to comment.