Hiding secrets in public view

Some time ago, I got intrigued by an article on the Register, finding out about the Baconian cipher.

As cited in wikipedia:

Bacon’s cipher is a method of message encoding devised by Francis Bacon in 1605. A message is concealed in the presentation of text, rather than its content.

So I started writing some code, initially implementing Baconian cipher codecs, which encode text to As and Bs and decode it back to text.

This was not enough, though, so I thought of implementing a steganographer, which would help hiding these As and Bs into text, mapping As to lowercase characters and Bs to uppercase characters.

After that, I was able to hide rust InsidE thE LInux KErnEl

:)

The public message is: inside the linux kernel.

The secret message is: rust.

The public message that contains the secret one becomes: InsidE thE LInux KErnEl.

Here is how:

use bacon_cipher::codecs::char_codec::CharCodec;
use bacon_cipher::stega::letter_case::LetterCaseSteganographer;
use bacon_cipher::{BaconCodec, Steganographer};
use std::iter::FromIterator;

// Define a Bacon Codec that encodes using the characters 'A' and 'B'
let codec = CharCodec::new('a', 'b');

// Apply steganography based on the case of the characters
let s = LetterCaseSteganographer::new();

// This is the public message in which we want to hide the secret one.
let public_chars: Vec<char> = "inside the linux kernel".chars().collect();

// This is the message that we want to hide.
let secret_chars: Vec<char> = "rust".chars().collect();

// This is the public message that contains the secret one
let disguised_public = s.disguise(&secret_chars, &public_chars, &codec);
let string = String::from_iter(disguised_public.unwrap().iter());

assert!(string == "InsidE thE LInux KErnEl");

And here is how to reveal the hidden message:

let public_chars: Vec<char> = "InsidE thE LInux KErnEl".chars().collect();
let output = s.reveal(&public_chars, &codec);
let hidden_message = String::from_iter(output.unwrap().iter());
assert!(hidden_message == "RUST");

More steganography

I went along and implemented more steganographers:

  • A MarkdownSteganographer allowed hiding rust in the following markdown:

    **i**nsid**e** th**e** **li**nux **ke**rn**e**l

    rendering into:

    inside the linux kernel

  • A SimpleTagSteganographer allowed hiding rust in the following HTML code:

    <b style="color: red;">i</b>nsid<b style="color: red;">e</b> th<b style="color: red;">e</b> <b style="color: red;">li</b>nux <b style="color: red;">ke</b>rn<b style="color: red;">e</b>l

    rendering into:

    inside the linux kernel

No limits…

Encoding and Steganography are two separate processes and they can be combined in any way.

The BaconCodec is a trait and accepts two associated types:

  • The ABTYPE is the type of the substitution characters A and B. For the CharCodec, this is a char, but we could implement codecs with bool, isize or whatever, even a custom struct or trait.

  • The CONTENT associated type is the type of the content that we want to encode or decode. The CharCodec defines a char, but again, this could be implemented into anything.

Someone could implement any kind of Steganographer and hide messages in images, or even in the code itself (maybe code obfuscation works like this?).

Moreover, the secret message can be further encoded, or even encrypted, so that we could have encrypted secret messages hidden in public.

Next steps

One thing that can definately be done, is to create codecs that do encryption during encoding and decryption during decoding. Other than that, more steganographers can be implemented for processing images, or sound, or…

One day…


If someone is interested, the code is on Github and the crate is called bacon-cipher.

ThaNks fOR ReaDing aNd haVE a nice DAy!