bacon_cipher/lib.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
15/*!
16# bacon-cipher
17
18An implementation of the [Bacon's cipher](https://en.wikipedia.org/wiki/Bacon%27s_cipher).
19
20The crate offers codecs that _encode / decode_ and steganographers that _hide / reveal_ encoded messages.
21
22**Available codecs:**
23
24* CharCodec: A codec that encodes data of type `char`.
25
26 The encoding is done by substituting with two given elements (`elem_a` and `elem_b`) of type `T`.
27
28 The substitution is done using the __first__ version of the Bacon's cipher.
29
30* CharCodecV2: A codec that encodes data of type `char`.
31
32 The encoding is done by substituting with two given elements (`elem_a` and `elem_b`) of type `T`.
33
34 The substitution is done using the __second__ version of the Bacon's cipher.
35
36**Available steganographers:**
37
38* LetterCaseSteganographer: Applies steganography based on the case of the characters.
39
40 E.g. Lowercase for Bacon's element A, capital for Bacon's element B.
41
42* MarkdownSteganographer: Applies steganography based on Markdown tags that surround elements.
43
44 E.g. Sourround an element with `**` for Bacon's element A and the rest of the elements are considered as Bacon's element B.
45
46* SimpleTagSteganographer: Applies steganography based on HTML or XML tags that surround elements. (needs the feature `extended-steganography`)
47
48 E.g. Sourround an element with `<b>` and `</b>` for Bacon's element A and with `<i>` and `</i>` for Bacon's element B.
49
50## Encoding - Decoding
51
52### Encode a message to Bacon codes
53
54```
55use bacon_cipher::codecs::char_codec::CharCodec;
56use bacon_cipher::BaconCodec;
57use std::iter::FromIterator;
58
59// Define a Bacon Codec that encodes using the characters 'A' and 'B'
60let codec = CharCodec::new('A', 'B');
61
62// This is the secret to encode
63let secret: Vec<char> = "My secret".chars().collect();
64
65// Get the encoded chars
66let encoded_chars = codec.encode(&secret);
67let encoded_string = String::from_iter(encoded_chars.iter());
68
69assert_eq!("ABABBBABBABAAABAABAAAAABABAAAAAABAABAABA", encoded_string);
70```
71
72### Decode Bacon codes
73
74```
75use bacon_cipher::codecs::char_codec::CharCodec;
76use bacon_cipher::BaconCodec;
77use std::iter::FromIterator;
78
79// Define a Bacon Codec that encodes using the characters 'A' and 'B'
80let codec = CharCodec::new('A', 'B');
81
82// These are the encoded characters
83let encoded_chars: Vec<char> = "ABABBBABBABAAABAABAAAAABABAAAAAABAABAABA".chars().collect();
84
85// Retrieve the decoded chars
86let decoded = codec.decode(&encoded_chars);
87let string = String::from_iter(decoded.iter());
88
89assert_eq!("MYSECRET", string);
90```
91
92## Steganography
93
94### Letter case
95
96#### Disguise a hidden message into a public one
97
98```
99use bacon_cipher::codecs::char_codec::CharCodec;
100use bacon_cipher::stega::letter_case::LetterCaseSteganographer;
101use bacon_cipher::{BaconCodec, Steganographer};
102use std::iter::FromIterator;
103
104// Define a Bacon Codec that encodes using the characters 'A' and 'B'
105let codec = CharCodec::new('a', 'b');
106
107// Apply steganography based on the case of the characters
108let s = LetterCaseSteganographer::new();
109
110// This is the public message in which we want to hide the secret one.
111let public_chars: Vec<char> = "This is a public message that contains a secret one".chars().collect();
112
113// This is the message that we want to hide.
114let secret_chars: Vec<char> = "My secret".chars().collect();
115
116// This is the public message that contains the secret one
117let disguised_public = s.disguise(&secret_chars, &public_chars, &codec);
118let string = String::from_iter(disguised_public.unwrap().iter());
119
120assert!(string == "tHiS IS a PUbLic mEssAge thaT cOntains A seCreT one");
121```
122
123#### Reveal a hidden message from a public one
124
125```
126use bacon_cipher::codecs::char_codec::CharCodec;
127use bacon_cipher::stega::letter_case::LetterCaseSteganographer;
128use bacon_cipher::{BaconCodec, Steganographer};
129use std::iter::FromIterator;
130
131// Define a Bacon Codec that encodes using the characters 'A' and 'B'
132let codec = CharCodec::new('a', 'b');
133
134// Apply steganography based on the case of the characters
135let s = LetterCaseSteganographer::new();
136
137// This is the public message that contains a hidden message
138let public_chars: Vec<char> = "tHiS IS a PUbLic mEssAge thaT cOntains A seCreT one".chars().collect();
139
140// This is the hidden message
141let output = s.reveal(&public_chars, &codec);
142let hidden_message = String::from_iter(output.unwrap().iter());
143assert!(hidden_message.starts_with("MYSECRET"));
144
145```
146
147### Markdown
148
149#### Disguise a hidden message into a public one
150
151```
152use bacon_cipher::codecs::char_codec::CharCodec;
153use bacon_cipher::stega::markdown::{MarkdownSteganographer, Marker};
154use bacon_cipher::{BaconCodec, Steganographer};
155use std::iter::FromIterator;
156
157// Define a Bacon Codec that encodes using the characters 'A' and 'B'
158let codec = CharCodec::new('a', 'b');
159
160// Apply steganography based on Markdown markers
161let s = MarkdownSteganographer::new(
162 Marker::empty(),
163 Marker::new(
164 Some("*"),
165 Some("*"))).unwrap();
166
167// This is the public message in which we want to hide the secret one.
168let public = "This is a public message that contains a secret one";
169
170// This is the message that we want to hide.
171let secret_chars: Vec<char> = "My secret".chars().collect();
172
173let output = s.disguise(
174 &secret_chars,
175 &Vec::from_iter(public.chars()),
176 &codec);
177let string = String::from_iter(output.unwrap().iter());
178assert!(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");
179```
180
181#### Reveal a hidden message from a public one
182
183```
184use bacon_cipher::codecs::char_codec::CharCodec;
185use bacon_cipher::stega::markdown::{MarkdownSteganographer, Marker};
186use bacon_cipher::{BaconCodec, Steganographer};
187use std::iter::FromIterator;
188
189// Define a Bacon Codec that encodes using the characters 'A' and 'B'
190let codec = CharCodec::new('a', 'b');
191
192// Apply steganography based on Markdown markers
193let s = MarkdownSteganographer::new(
194 Marker::empty(),
195 Marker::new(
196 Some("*"),
197 Some("*"))).unwrap();
198
199// This is the public message that contains a hidden message
200let 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";
201
202// This is the hidden message
203let output = s.reveal(
204 &Vec::from_iter(public.chars()),
205 &codec);
206assert!(output.is_ok());
207let string = String::from_iter(output.unwrap().iter());
208assert!(string.starts_with("MYSECRET"));
209```
210
211## Licence
212
213At your option, under:
214
215* Apache License, Version 2.0, (http://www.apache.org/licenses/LICENSE-2.0)
216* MIT license (http://opensource.org/licenses/MIT)
217
218*/
219
220pub mod codecs;
221pub mod stega;
222pub mod errors;
223
224/// A codec that enables encoding and decoding based on the [Bacon's cipher](https://en.wikipedia.org/wiki/Bacon%27s_cipher)
225pub trait BaconCodec {
226 /// The type of the substitution characters A and B that produce a cipher output like ABABBBABBABAAABAABAAAAABABAAAAAABAABAABAABABBAABAABAAABBAAABAAAAAAABBAAABAA
227 ///
228 /// Can be char, bool or whatever
229 type ABTYPE;
230 /// The type of the content to be encoded to or decoded.
231 type CONTENT;
232
233 /// Encode an array of some type `Self::CONTENT`
234 ///
235 /// E.g. For `CONTENT=char`, `ABTYPE=char`, `a='A'` and `b='B'`, the encoding of `['M','y',' ','s','e','c','r','e','t']` is _ABABBBABBABAAABAABAAAAABABAAAAAABAABAABA_
236 fn encode(&self, input: &[Self::CONTENT]) -> Vec<Self::ABTYPE> {
237 input.iter()
238 .map(|elem| self.encode_elem(elem))
239 .flat_map(|elem| elem)
240 .collect()
241 }
242
243 /// Encodes a single emenent of `Self::CONTENT` to a Vec of `Self::ABTYPE`.
244 fn encode_elem(&self, elem: &Self::CONTENT) -> Vec<Self::ABTYPE>;
245
246 /// Decode an array of some type `Self::ABTYPE`.
247 ///
248 /// E.g. For `CONTENT=char`, `ABTYPE=char`, `a='A'` and `b='B'`, the decoding of _ABABBBABBABAAABAABAAAAABABAAAAAABAABAABA_ is `['M','Y','S','E','C','R','E','T']`
249 fn decode(&self, input: &[Self::ABTYPE]) -> Vec<Self::CONTENT> {
250 input.chunks(self.encoded_group_size())
251 .map(|elem| self.decode_elems(&elem))
252 .collect()
253 }
254
255 /// Decode an array of elements to produce one element of `Self::CΟΝΤΕΝΤ`
256 fn decode_elems(&self, elems: &[Self::ABTYPE]) -> Self::CONTENT;
257
258 /// Returns the `A` substitution element.
259 fn a(&self) -> Self::ABTYPE;
260
261 /// Returns the `B` substitution element.
262 fn b(&self) -> Self::ABTYPE;
263
264 /// Returns the the size of the group of elements that represent a content encoding.
265 ///
266 /// E.g.: For the default Bacon's cipher, this is 5.
267 fn encoded_group_size(&self) -> usize;
268
269 /// Tests whether an element equals with the `A` substitution element.
270 fn is_a(&self, elem: &Self::ABTYPE) -> bool;
271
272 /// Tests whether an element equals with the `B` substitution element.
273 fn is_b(&self, elem: &Self::ABTYPE) -> bool;
274}
275
276/// Transforms a given input of elements to / from a different form, based on a [BaconCodec](trait.BaconCodec.html).
277pub trait Steganographer {
278 /// The type of the elements to transform.
279 type T;
280
281 /// Encodes a _secret_ array of type `T`, using the a [BaconCodec](trait.BaconCodec.html) and applies the encoding
282 /// by transforming a _public_ array of type `T` accordingly.
283 ///
284 /// The result is an array of type `T` that contains the hidden _secret_
285 fn disguise<AB>(&self, secret: &[Self::T], public: &[Self::T], codec: &dyn BaconCodec<ABTYPE=AB, CONTENT=Self::T>) -> errors::Result<Vec<Self::T>>;
286
287 /// Reveals the _secret_ that is hidden in an array of type `T`, using a [BaconCodec](trait.BaconCodec.html).
288 fn reveal<AB>(&self, input: &[Self::T], codec: &dyn BaconCodec<ABTYPE=AB, CONTENT=Self::T>) -> errors::Result<Vec<Self::T>>;
289}