Bacon's cipher: An Intro to Steganography

14

2

This little piggy went to market, this little piggy wrote some code...

Ah wait, we're not talking about that bacon, we're talking about Sir Francis Bacon! Specifically, the cipher Bacon devised in the late 1500s, as a method of hiding a message within another message, a method of steganography.

The cipher works by concealing the message in the presentation of text, rather than its content. First, the letters of your message are encoded into binary (from 0 to 25) as follows:

Note: Please use the following encoding in your code and do not worry about numbers, spaces, or other symbols in the input, though I may devise some bonus for those who include these characters in their encoding. If you do include other symbols, the letters must still occupy spaces 0-25 in the encoding.

Letter  Encoding
A       AAAAA
B       AAAAB
C       AAABA
D       AAABB
E       AABAA
F       AABAB
G       AABBA
H       AABBB
I       ABAAA
J       ABAAB
K       ABABA
L       ABABB
M       ABBAA
N       ABBAB
O       ABBBA
P       ABBBB
Q       BAAAA
R       BAAAB
S       BAABA
T       BAABB
U       BABAA
V       BABAB
W       BABBA
X       BABBB
Y       BBAAA
Z       BBAAB

Having encoded all of the letters in your message into the As and Bs above, you must now select two typefaces for your code. For this example, I will use normal text for typeface A and bold text for typeface B.

So the message

HELLOWORLD

is encoded to

AABBB AABAA ABABB ABABB ABBBA BABBA ABBBA BAAAB ABABB AAABB

And now we conceal this binary with a carrier text.

The quick brown fox jumps over the lazy dogs, gamboling in the fields where the shepherds keep watch.

It is alright if the carrier message is longer than the actual encoded message, though it cannot be shorter. Now we turn the carrier text into bold according to where the Bs are in the encoded message,

The quick brown fox jumps over the lazy dogs, gamboling in the fields where the shepherds keeps watch.

Which without Markdown reads as

Th**e** **qu**ic**k** bro**w**n **fo**x **j**u**mp**s **ove**r **t**h**e** **l**az**y** 
**do**g**s**, gam**b**o**l**i**ng** in t**he** fields where the shepherds keeps watch.

Note that I did not use the punctuation in the carrier message to encode the message, but whether the punctuation is encoded or not is up to you/.

Rules

  • Your input will be the message you to be encoded and a carrier message. If the carrier message is too short, return some sort of error message.

  • You must select two typefaces for encoding A and B, such as UPPERCASE, lowercase, italic, bold, bold italic, strikethrough, in code format and so on. You must use Stack Exchange's form of Markdown to encode these typefaces, i.e.

    UPPERCASE, lowercase, *italic*, **bold**, 
    ***bold italic***, <s>strikethrough</s>, `in code format`
    
  • Your output must be your now-encoded carrier message, either shown with Markdown or shown without, as seen in the above example.

  • You are only required to make an encoding algorithm. Any decoding algorithms you wish to provide are welcome, but at time of writing will not help or hinder your score.

  • Your code must be a program or a function.

  • This is code golf, so the smallest number of bytes wins.

As always, if the problem is unclear, please let me know. Good luck and good golfing!

Sherlock9

Posted 2015-12-08T11:50:46.200

Reputation: 11 664

3So really there's no reason not to use upper/lowercase, since everything else costs more bytes – Mego – 2015-12-08T12:30:32.737

6I think there's a typo in "we're not talking about that bacon", because surely you were talking about Kevin Bacon, so the "b" should be capitalised, right? – Martin Ender – 2015-12-08T12:31:14.217

Answers

1

Pyth, 47 bytes

Vsm.[05jxGd2r~zw0#I}Jr@z~Z+1Z0GBpJ)p?NrJ1J;>zZ

Try it here.

Explanation:

             ~zw                               - Get the first line of input and 
                                               - set z to the next line
            r   0                              - Turn it to lower case
  m                                            - Map each character
        xGd                                    - Get it's position in the alphabet
       j   2                                   - Turn it to base 2
   .[05                                        - Pad the start with 0's
 s                                             - Turn it to a 1d-array (flatten it)
V                                        ;     - For N in above array:
                 #                )            - While 1:
                      @z~Z+1Z                  - Get the current position in the 
                                               - second line and increment the position
                    Jr       0                 - Set J to it lowercased
                  I}          GB               - If it's a letter, break
                                pJ             - Otherwise, print it
                                    ?N         - Is the character code
                                               - (the current 1d-array) 1
                                      rJ1      - Get the current char uppered
                                         J     - Leave it lowered
                                   p           - Print the character
                                           >zZ - Print out the rest of the second input

Blue

Posted 2015-12-08T11:50:46.200

Reputation: 26 661

1

Python 3, 216 211 231 225 207 bytes

This is a solution that uses normal text and Markdown-style italics for its two typefaces. And it encodes everything in the carrier message except the spaces.

Edit: Had to fix the code so that the result would print correctly and added examples below the code.

Edit: Edited the code to previously worse uppercase/lowercase solution, due to problems in printing the italics correctly.

def g(s,c):
 c=c.lower();w=[h.upper()for h in s if h.isalpha()];t=''.join("{:05b}".format(ord(i)-65)for i in w);r='';j=m=0
 while t[j:]:a=c[m];x=a!=" ";r+=[a,a.upper()][x*int(t[j])];j+=x;m+=1
 return r+c[m:]

Examples

>>> g('HELLOWORLD', 'The quick brown fox jumps over the lazy dogs, gamboling in the fields 
where the shepherds keep watch')
'thE QUicK broWn FOx JuMPs OVEr ThE LazY DOgS, gaMbOlINg in THe fields where the shepherds keep watch'

Ungolfed:

def bacon(message, carrier):
    # Lowers the case of the carrier message
    carrier = carrier.lower()
    # Removing all non-alphabetic characters and making the rest uppercase
    words = ""
    for char in message:
        if char.isalpha():
            words += char.upper()
    # Encoding the message
    binary = ""
    for letter in words:
        encode = ord(letter) - 65
        binary += "{:05b}".format(encode)
    # Encoding the carrier message
    result = ""
    bin_index = 0
    char_index = 0
    while bin_index < len(binary):
        letter = carrier[char_index]
        # If letter isn't a space and it needs to be encoded
        if letter != " " and int(binary[bin_index]): 
            letter = letter.upper()
        result += type + letter + type
        # The encoding only proceeds if letter wasn't a space
        bin_index += letter != " "
        # char_index increments whether or not letter was alphabetical
        char_index += 1
    # Return the encoded text and any leftover characters from the carrier message
    return result + carrier[char_index : ]

Sherlock9

Posted 2015-12-08T11:50:46.200

Reputation: 11 664

0

C, 124 bytes

This requires the arguments to be in an ASCII-compatible encoding (e.g. ISO-8859.1 or UTF-8). It modifies the carrier in-place, and returns 0 on success, or non-zero otherwise. The encoding is A==lower-case and B==upper-case. Unused carrier letters are set to upper.

int f(char*p,char*s){int m=16;do{if(isalpha(*s)){*s|=32;*s-=(*p-1)&m?32:0;if(!(m/=2)){m=16;p+=!!*p;}}}while(*++s);return*p;}

Explanation

Including a test program. Pass the letters to encode as the first argument, and the carrier string as the second.

#include <stdio.h>
#include <ctype.h>

/* ASCII or compatible encoding assumed */
int f(char *p, char *s)         /* plaintext, carrier */
{
    int m=16;                   /* mask */
    do {
        if (isalpha(*s)) {
            *s |= 32;
            *s -= (*p-1)&m ? 32 : 0;
            if (!(m/=2)) {
                /* reset mask and advance unless we reached the end */
                m=16;
                p+=!!*p;
            }
        }
    } while (*++s);

    /* 0 (success) if we finished p, else non-zero */
    return *p;
}

int main(int argc, char **argv)
{
    int r = argc < 3 || f(argv[1], argv[2]);
    if (r)
        puts("~!^%&$+++NO CARRIER+++");
    else
        puts(argv[2]);
    return r;
}

Test output:

$ ./66019 "HELLOWORLD" "The quick brown fox jumps over the lazy dogs, gamboling in the fields where the shepherds keep watch."  
thE QUicK broWn FOx JuMPs OVEr ThE LazY DOgS, gamBoLiNG in tHE FIELDS WHERE THE SHEPHERDS KEEP WATCH.

Toby Speight

Posted 2015-12-08T11:50:46.200

Reputation: 5 058