Skip to content

Instantly share code, notes, and snippets.

@commander-trashdin
Created June 21, 2021 18:26
Show Gist options
  • Select an option

  • Save commander-trashdin/df0c367bb8abb2512efe3f46c2b66d37 to your computer and use it in GitHub Desktop.

Select an option

Save commander-trashdin/df0c367bb8abb2512efe3f46c2b66d37 to your computer and use it in GitHub Desktop.
xorsism
/// A munger which XORs a key with some data
use std::borrow::Borrow;
#[derive(Clone)]
pub struct Xorcism<'a> {
key: &'a [u8],
position: usize,
}
pub trait Captures<'a> {}
impl<'a, T: ?Sized> Captures<'a> for T {}
impl<'a> Xorcism<'a> {
/// Create a new Xorcism munger from a key
///
/// Should accept anything which has a cheap conversion to a byte slice.
pub fn new<Key>(key: &'a Key) -> Xorcism<'a>
where
Key: AsRef<[u8]> + ?Sized + 'a,
{
let key: &'a [u8] = key.as_ref();
Self { key, position: 0 }
}
/// XOR each byte of the input buffer with a byte from the key.
///
/// Note that this is stateful: repeated calls are likely to produce different results,
/// even with identical inputs.
pub fn munge_in_place(&mut self, data: &mut [u8]) {
for c in data.iter_mut() {
*c ^= self.key[self.position];
self.position += 1;
self.position %= self.key.len()
}
}
/// XOR each byte of the data with a byte from the key.
///
/// Note that this is stateful: repeated calls are likely to produce different results,
/// even with identical inputs.
///
/// Should accept anything which has a cheap conversion to a byte iterator.
/// Shouldn't matter whether the byte iterator's values are owned or borrowed.
pub fn munge<'c, Data>(&'a mut self, data: &'c Data)
-> impl Iterator<Item = u8> + Captures<'a> + 'c
where
Data: IntoIterator,
Data::IntoIter: 'c,
Data::Item: Borrow<u8>,
{
data.into_iter().map(move |value| {
let pos = self.position;
self.position += 1;
self.position %= self.key.len();
value.borrow() ^ self.key[pos]
})
}
}
@awnion
Copy link

awnion commented Jun 21, 2021

This is 300iq:

pub trait Captures<'a> {}
impl<'a, T: ?Sized> Captures<'a> for T {}

knowing this everything else is doable:

use std::borrow::Borrow;

pub trait Captures<'a> {}
impl<'a, T: ?Sized> Captures<'a> for T {}

/// A munger which XORs a key with some data
#[derive(Clone)]
pub struct Xorcism<'a> {
    _key: Vec<&'a u8>,
    _pos: usize,
}

impl<'a> Xorcism<'a> {
    /// Create a new Xorcism munger from a key
    ///
    /// Should accept anything which has a cheap conversion to a byte slice.
    pub fn new<Key>(key: &'a Key) -> Xorcism<'a>
    where
        Key: AsRef<[u8]> + ?Sized,
    {
        Self {
            _key: key.as_ref().iter().collect::<Vec<&'a u8>>(),
            _pos: 0,
        }
    }

    // we could use trait Cycle instead but it feels like cheating here
    fn _next_cycled(&mut self) -> &u8 {
        let tmp = self._key[self._pos % self._key.len()];
        self._pos += 1;
        tmp
    }

    /// XOR each byte of the input buffer with a byte from the key.
    ///
    /// Note that this is stateful: repeated calls are likely to produce different results,
    /// even with identical inputs.
    pub fn munge_in_place(&mut self, data: &mut [u8]) {
        data.iter_mut().for_each(|item: &mut u8| {
            *item ^= self._next_cycled();
        })
    }

    /// XOR each byte of the data with a byte from the key.
    ///
    /// Note that this is stateful: repeated calls are likely to produce different results,
    /// even with identical inputs.
    ///
    /// Should accept anything which has a cheap conversion to a byte iterator.
    /// Shouldn't matter whether the byte iterator's values are owned or borrowed.
    pub fn munge<It, Data>(&mut self, data: Data)
        -> impl Iterator<Item = u8> + Captures<'a> + '_
    where
        Data: IntoIterator<Item = It>,
        Data::IntoIter: 'a,
        It: Borrow<u8>
    {
        data.into_iter().map(move |i| i.borrow() ^ self._next_cycled())
    }
}

@awnion
Copy link

awnion commented Jun 21, 2021

Using key as Vec<&u8> is probably half-cheating??

...but I could even use std::iter::Cycle instead of vec and ugly handwritten self._next_cycled()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment