Skip to main content

bacon_cipher/stega/
markdown.rs

1// Copyright 2019 astonbitecode
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::iter::FromIterator;
16
17use crate::{BaconCodec, errors, Steganographer};
18use crate::errors::BaconError;
19
20#[derive(Debug, Clone, PartialEq)]
21pub struct Marker {
22    start_marker: Option<String>,
23    end_marker: Option<String>,
24}
25
26impl Marker {
27    pub fn new(start_marker: Option<&str>, end_marker: Option<&str>) -> Marker {
28        Marker {
29            start_marker: start_marker.map(|marker| marker.to_string()),
30            end_marker: end_marker.map(|marker| marker.to_string()),
31        }
32    }
33
34    pub fn empty() -> Marker {
35        Marker {
36            start_marker: None,
37            end_marker: None,
38        }
39    }
40
41    pub fn is_empty(&self) -> bool {
42        self == &Self::empty()
43    }
44
45    pub fn start_marker(&self) -> &Option<String> {
46        &self.start_marker
47    }
48
49    pub fn end_marker(&self) -> &Option<String> {
50        &self.end_marker
51    }
52
53    pub fn start_marker_string(&self) -> String {
54        self.start_marker().clone().unwrap_or("".to_string())
55    }
56
57    pub fn end_marker_string(&self) -> String {
58        self.end_marker().clone().unwrap_or("".to_string())
59    }
60}
61
62pub struct MarkdownSteganographer {
63    a_marker: Marker,
64    b_marker: Marker,
65}
66
67impl MarkdownSteganographer {
68    pub fn new(a_marker: Marker, b_marker: Marker) -> errors::Result<MarkdownSteganographer> {
69        match (&a_marker.start_marker, &a_marker.end_marker, &b_marker.start_marker, &b_marker.end_marker) {
70            (Some(asm), Some(aem), Some(bsm), Some(bem))
71            if asm.contains(bsm) || asm.contains(bem) ||
72                aem.contains(bsm) || aem.contains(bem) ||
73                bsm.contains(asm) || bsm.contains(aem) ||
74                bem.contains(asm) || bem.contains(aem) => {
75                Err(BaconError::SteganographerError(format!("Cannot create a marker with {:?} and {:?}", a_marker, b_marker)))
76            }
77            (None, None, None, None) => {
78                Err(BaconError::SteganographerError(format!("Cannot create a marker with both A and B undefined")))
79            }
80            (Some(_), None, _, _) |
81            (None, Some(_), _, _) |
82            (_, _, Some(_), None) |
83            (_, _, None, Some(_)) => {
84                Err(BaconError::SteganographerError(format!("A marker should define both start and end")))
85            }
86            _ => {
87                Ok(MarkdownSteganographer {
88                    a_marker,
89                    b_marker,
90                })
91            }
92        }
93    }
94
95    fn find_first_occurence_of(&self, input_type: ParsedInputType, input: &str) -> Option<usize> {
96        match input_type {
97            ParsedInputType::A => {
98                self.a_marker.start_marker.as_ref()
99                    .and_then(|start| input.find(start.as_str()))
100            }
101            ParsedInputType::B => {
102                self.b_marker.start_marker.as_ref()
103                    .and_then(|start| input.find(start.as_str()))
104            }
105            _ => None
106        }
107    }
108
109    fn parse(&self, input: &str) -> Vec<ParsedInputElement> {
110        let mut input = input;
111        let mut input_elements: Vec<ParsedInputElement> = Vec::new();
112
113        // Search for either a or b start marker
114        loop {
115            // Find the first occurrence in the input
116            let a_start_index = self.find_first_occurence_of(ParsedInputType::A, input).unwrap_or(input.len());
117            let b_start_index = self.find_first_occurence_of(ParsedInputType::B, input).unwrap_or(input.len());
118
119            let (start_index, parsed_input_type) = if a_start_index < b_start_index {
120                (a_start_index, ParsedInputType::A)
121            } else if b_start_index < a_start_index {
122                (b_start_index, ParsedInputType::B)
123            } else {
124                (input.len(), ParsedInputType::Other)
125            };
126
127            let start_size = match parsed_input_type {
128                ParsedInputType::A => self.a_marker.start_marker.as_ref().unwrap().len(),
129                ParsedInputType::B => self.b_marker.start_marker.as_ref().unwrap().len(),
130                _ => 0,
131            };
132            // Remove the first occurence. From now on, work with tmp
133            let tmp: &str = &input[(start_index + start_size)..input.len()];
134            let (end_opt, end_size) = match parsed_input_type {
135                ParsedInputType::A => (self.a_marker.end_marker.as_ref(), self.a_marker.end_marker_string().len()),
136                ParsedInputType::B => (self.b_marker.end_marker.as_ref(), self.b_marker.end_marker_string().len()),
137                _ => (None, 0),
138            };
139            let end_index = (end_opt
140                .and_then(|end| tmp.find(end.as_str()))
141                // In the case the end marker is not found, return the end of the tmp, minus the end_size
142                // (in order not to have out of bounds error since we add the end_size after unwrap_or)
143                .unwrap_or(tmp.len() - end_size)) + end_size;
144            if end_index > 0 {
145                let input_element: &str = &tmp[0..(end_index - end_size)];
146                input_elements.push(ParsedInputElement::new(input_element.to_string(), parsed_input_type.clone()));
147            } else {
148                break;
149            }
150            if tmp.len() <= end_index {
151                input = "";
152            } else {
153                input = &tmp[end_index..tmp.len()];
154            }
155        }
156        input_elements
157    }
158
159
160    // If b_marker is empty, then all the characters that are not marked with a_marker, should be considered as
161    // they are marked with b_marker.
162    // Similarly, if a_marker is empty, then all the characters that are not marked with b_marker, should be considered as
163    // they are marked with a_marker.
164    // This function does exactly this: it takes the parts of `input_string`
165    // that have not be characterized as a_marker (if b_marker is None) or b_marker (if a_marker is None)
166    // and adds them to the Vec of `ParsedInputElement`s as ParsedInputType::B, or ParsedInputType::B respectively.
167    fn replace_unmarked_characters_with(input_string: String, parsed_input_elements: Vec<ParsedInputElement>, start_marker_of_parsed_input_element: &str, end_marker_of_parsed_input_element: &str, parsed_input_type: ParsedInputType) -> Vec<ParsedInputElement> {
168        let mut input_string = input_string;
169        let mut new_parsed_input_elements: Vec<ParsedInputElement> = Vec::new();
170        for pie in parsed_input_elements.into_iter() {
171            // This is the string of the ParsedInputElement that is already found
172            let parsed_input_element_string = format!("{}{}{}",
173                                                      start_marker_of_parsed_input_element,
174                                                      pie.string,
175                                                      end_marker_of_parsed_input_element);
176            // Find this string in the input_string and get its start index
177            let index = input_string.find(&parsed_input_element_string).unwrap_or(input_string.len());
178            // Get the substring of the input_string until the above index
179            let substring: &str = &input_string[0..index];
180            // For each character of the substring, create a new ParsedInputElement and push it to the Vec
181            for c in substring.chars() {
182                new_parsed_input_elements.push(ParsedInputElement::new(c.to_string(), parsed_input_type.clone()));
183            }
184            // Push the known ParsedInputElement as well to the Vec
185            new_parsed_input_elements.push(pie);
186            // Change the input string, removing part that was processed in this iteration
187            input_string = input_string.replace(&format!("{}{}", substring, parsed_input_element_string), "");
188        }
189        // Add any remaining ParsedInputElements
190        for c in input_string.chars().into_iter() {
191            new_parsed_input_elements.push(ParsedInputElement::new(c.to_string(), parsed_input_type.clone()));
192        }
193
194        new_parsed_input_elements
195    }
196}
197
198impl Steganographer for MarkdownSteganographer {
199    type T = char;
200
201    fn disguise<AB>(&self, secret: &[char], public: &[char], codec: &dyn BaconCodec<ABTYPE=AB, CONTENT=char>) -> errors::Result<Vec<char>> {
202        let encoded = codec.encode(secret);
203
204        let mut disguised = String::new();
205        let mut i = 0;
206
207        for pc in public {
208            if pc.is_alphabetic() {
209                let opt = encoded.get(i);
210                if opt.is_some() && codec.is_a(opt.unwrap()) {
211                    disguised.push_str(&format!("{}{}{}",
212                                                self.a_marker.start_marker_string(),
213                                                pc.clone(),
214                                                self.a_marker.end_marker_string()));
215                    i = i + 1;
216                } else if opt.is_some() && codec.is_b(opt.unwrap()) {
217                    disguised.push_str(&format!("{}{}{}",
218                                                self.b_marker.start_marker_string(),
219                                                pc.clone(),
220                                                self.b_marker.end_marker_string()));
221                    i = i + 1;
222                } else {
223                    disguised.push(pc.clone())
224                }
225            } else {
226                disguised.push(pc.clone())
227            }
228        }
229
230        Ok(disguised
231            .replace(&format!("{}{}", self.a_marker.end_marker_string(), self.a_marker.start_marker_string()), "")
232            .replace(&format!("{}{}", self.b_marker.end_marker_string(), self.b_marker.start_marker_string()), "")
233            .chars().collect())
234    }
235
236    fn reveal<AB>(&self, input: &[char], codec: &dyn BaconCodec<ABTYPE=AB, CONTENT=Self::T>) -> errors::Result<Vec<char>> {
237        let input_string: String = String::from_iter(input.iter());
238        let parsed_input_elements = self.parse(&input_string);
239        let new_parsed_input_elements: Vec<ParsedInputElement>;
240        if self.b_marker.is_empty() {
241            new_parsed_input_elements = Self::replace_unmarked_characters_with(input_string, parsed_input_elements, self.a_marker.start_marker.as_ref().unwrap_or(&"".to_string()), self.a_marker.end_marker.as_ref().unwrap_or(&"".to_string()), ParsedInputType::B);
242        } else if self.a_marker.is_empty() {
243            new_parsed_input_elements = Self::replace_unmarked_characters_with(input_string, parsed_input_elements, self.b_marker.start_marker.as_ref().unwrap_or(&"".to_string()), self.b_marker.end_marker.as_ref().unwrap_or(&"".to_string()), ParsedInputType::A);
244        } else {
245            new_parsed_input_elements = parsed_input_elements;
246        }
247        let encoded: Vec<AB> = new_parsed_input_elements.iter()
248            .map(|elem| {
249                if elem.tp == ParsedInputType::A {
250                    let v: Vec<AB> = elem.string.chars()
251                        .filter(|sc| sc.is_alphabetic())
252                        .map(|_| codec.a())
253                        .collect();
254                    v
255                } else {
256                    let v: Vec<AB> = elem.string.chars()
257                        .filter(|sc| sc.is_alphabetic())
258                        .map(|_| codec.b())
259                        .collect();
260                    v
261                }
262            })
263            .flat_map(|m| m)
264            .collect();
265        Ok(codec.decode(&encoded))
266    }
267}
268
269#[derive(Debug, PartialEq)]
270struct ParsedInputElement {
271    string: String,
272    tp: ParsedInputType,
273}
274
275impl ParsedInputElement {
276    fn new(string: String, tp: ParsedInputType) -> ParsedInputElement {
277        ParsedInputElement { string, tp }
278    }
279}
280
281#[derive(Clone, Debug, PartialEq)]
282enum ParsedInputType {
283    A,
284    B,
285    Other,
286}
287
288#[cfg(test)]
289mod markdown_tests {
290    use std::iter::FromIterator;
291
292    use crate::codecs::char_codec::CharCodec;
293
294    use super::*;
295
296    #[test]
297    fn markers_creation() {
298        let m1 = Marker::new(None, None);
299        assert!(m1.start_marker() == &None);
300        assert!(m1.end_marker() == &None);
301
302        let m2 = Marker::new(Some("_"), Some("_"));
303        assert!(m2.start_marker() == &Some("_".to_string()));
304        assert!(m2.end_marker() == &Some("_".to_string()));
305
306        let m3 = Marker::empty();
307        assert!(m3.start_marker() == &None);
308        assert!(m3.end_marker() == &None);
309    }
310
311    #[test]
312    fn markers_to_string() {
313        let m = Marker::new(Some("__"), Some("__"));
314        assert!(m.start_marker_string() == ("__"));
315        assert!(m.end_marker_string() == ("__"));
316    }
317
318    #[test]
319    fn steganographer_creation_failure() {
320        let res = MarkdownSteganographer::new(
321            Marker::new(
322                Some("*"),
323                Some("*")),
324            Marker::new(
325                Some("**"),
326                Some("**")));
327        assert!(res.is_err());
328        let res = MarkdownSteganographer::new(
329            Marker::new(
330                Some("*"),
331                Some("!")),
332            Marker::new(
333                Some("@"),
334                Some("**")));
335        assert!(res.is_err());
336        let res = MarkdownSteganographer::new(
337            Marker::new(
338                Some("!"),
339                Some("*")),
340            Marker::new(
341                Some("**"),
342                Some("@")));
343        assert!(res.is_err());
344        let res = MarkdownSteganographer::new(
345            Marker::new(
346                Some("**"),
347                Some("**")),
348            Marker::new(
349                Some("*"),
350                Some("*")));
351        assert!(res.is_err());
352        let res = MarkdownSteganographer::new(
353            Marker::new(
354                Some("**"),
355                Some("@")),
356            Marker::new(
357                Some("*"),
358                Some("!")));
359        assert!(res.is_err());
360        let res = MarkdownSteganographer::new(
361            Marker::new(
362                Some("@"),
363                Some("**")),
364            Marker::new(
365                Some("!"),
366                Some("*")));
367        assert!(res.is_err());
368        let res = MarkdownSteganographer::new(
369            Marker::new(
370                Some("**"),
371                Some("**")),
372            Marker::new(
373                Some("**"),
374                Some("**")));
375        assert!(res.is_err());
376        let res = MarkdownSteganographer::new(
377            Marker::empty(),
378            Marker::empty());
379        assert!(res.is_err());
380        let res = MarkdownSteganographer::new(
381            Marker::new(
382                Some("**"),
383                None),
384            Marker::new(
385                Some("**"),
386                Some("**")));
387        assert!(res.is_err());
388        let res = MarkdownSteganographer::new(
389            Marker::new(
390                None,
391                Some("**")),
392            Marker::new(
393                Some("**"),
394                Some("**")));
395        assert!(res.is_err());
396        let res = MarkdownSteganographer::new(
397            Marker::new(
398                Some("**"),
399                Some("**")),
400            Marker::new(
401                None,
402                Some("**")));
403        assert!(res.is_err());
404        let res = MarkdownSteganographer::new(
405            Marker::new(
406                Some("**"),
407                Some("**")),
408            Marker::new(
409                Some("**"),
410                None));
411        assert!(res.is_err());
412    }
413
414    #[test]
415    fn disguise_a_secret_to_a_char_array_define_b_marker() {
416        let codec = CharCodec::new('a', 'b');
417        let s = MarkdownSteganographer::new(
418            Marker::empty(),
419            Marker::new(
420                Some("*"),
421                Some("*"))).unwrap();
422
423        let public = "This is a public message that contains a secret one";
424        let output = s.disguise(
425            &['M', 'y', ' ', 's', 'e', 'c', 'r', 'e', 't'],
426            &Vec::from_iter(public.chars()),
427            &codec);
428        let string = String::from_iter(output.unwrap().iter());
429        assert!(string == "T*h*i*s* *is* a *pu*b*l*ic m*e*ss*a*ge tha*t* c*o*ntains *a* se*c*re*t* one");
430    }
431
432    #[test]
433    fn disguise_a_secret_to_a_char_array_define_a_marker() {
434        let codec = CharCodec::new('a', 'b');
435        let s = MarkdownSteganographer::new(
436            Marker::new(
437                Some("**"),
438                Some("**")),
439            Marker::empty()).unwrap();
440
441        let public = "This is a public message that contains a secret one";
442        let output = s.disguise(
443            &['M', 'y', ' ', 's', 'e', 'c', 'r', 'e', 't'],
444            &Vec::from_iter(public.chars()),
445            &codec);
446        let string = String::from_iter(output.unwrap().iter());
447        assert!(string == "**T**h**i**s is **a** pu**b**l**ic** **m**e**ss**a**ge** **tha**t **c**o**ntains** a **se**c**re**t **o**ne");
448    }
449
450    #[test]
451    fn disguise_a_secret_to_a_char_array_define_a_b_markers() {
452        let codec = CharCodec::new('a', 'b');
453        let s = MarkdownSteganographer::new(
454            Marker::new(
455                Some("*"),
456                Some("*")),
457            Marker::new(
458                Some("!"),
459                Some("!"))).unwrap();
460
461        let public = "This is a public message that contains a secret one";
462        let output = s.disguise(
463            &['M', 'y', ' ', 's', 'e', 'c', 'r', 'e', 't'],
464            &Vec::from_iter(public.chars()),
465            &codec);
466        let string = String::from_iter(output.unwrap().iter());
467        assert!(string == "*T*!h!*i*!s! !is! *a* !pu!*b*!l!*ic* *m*!e!*ss*!a!*ge* *tha*!t! *c*!o!*ntains* !a! *se*!c!*re*!t! *o*ne");
468    }
469
470    #[test]
471    fn reveal_a_secret_from_a_char_array_define_a_b_markers() {
472        let codec = CharCodec::new('a', 'b');
473        let s = MarkdownSteganographer::new(
474            Marker::new(
475                Some("*"),
476                Some("*")),
477            Marker::new(
478                Some("!"),
479                Some("!"))).unwrap();
480        let public = "*T*!h!*i*!s! !is! *a* !pu!*b*!l!*ic* *m*!e!*ss*!a!*ge* *tha*!t! *c*!o!*ntains* !a! *se*!c!*re*!t! *o*ne";
481        let output = s.reveal(
482            &Vec::from_iter(public.chars()),
483            &codec);
484        assert!(output.is_ok());
485        let string = String::from_iter(output.unwrap().iter());
486        assert!(string.starts_with("MYSECRET"));
487    }
488
489    #[test]
490    fn marker_is_empty() {
491        assert!(Marker::empty().is_empty());
492        assert!(!Marker::new(Some("*"), Some("*")).is_empty());
493    }
494
495    #[test]
496    fn reveal_a_secret_from_a_char_array_define_a_marker() {
497        let codec = CharCodec::new('a', 'b');
498        let s = MarkdownSteganographer::new(
499            Marker::new(
500                Some("**"),
501                Some("**")),
502            Marker::empty()).unwrap();
503        let public = "**T**h**i**s is **a** pu**b**l**ic** **m**e**ss**a**ge** **tha**t **c**o**ntains** a **se**c**re**t **o**ne";
504        let output = s.reveal(
505            &Vec::from_iter(public.chars()),
506            &codec);
507        assert!(output.is_ok());
508        let string = String::from_iter(output.unwrap().iter());
509        assert!(string.starts_with("MYSECRET"));
510    }
511
512    #[test]
513    fn reveal_a_secret_from_a_char_array_define_b_marker() {
514        let codec = CharCodec::new('a', 'b');
515        let s = MarkdownSteganographer::new(
516            Marker::empty(),
517            Marker::new(
518                Some("*"),
519                Some("*"))).unwrap();
520        let public = "T*h*i*s* *is* a *pu*b*l*ic m*e*ss*a*ge tha*t* c*o*ntains *a* se*c*re*t* one";
521        let output = s.reveal(
522            &Vec::from_iter(public.chars()),
523            &codec);
524        assert!(output.is_ok());
525        let string = String::from_iter(output.unwrap().iter());
526        assert!(string.starts_with("MYSECRET"));
527    }
528}