With just about everybody snooping around your emails today with the excuse of hunting the bad guys, coding to keep some resemblance of privacy is getting important. I will start out with some simple encryption examples to get this started. You are invited to give us your thoughts and codes. Hopefully, we can improve the code as time goes on.

The first example is very simplistic form of a Caesar cipher, simply increasing the ASCII values by one to encrypt and decreasing by one to decrypt. It would be easy to figure that scheme out by looking at the letter frequency. In the English language the most common letter is 'e' and suddenly it would be the next ASCII character 'f'. So, even a challenged snoop could see through that after a while.

''' encrypt101.py
simple shift ASCII value by one encryption/decryption
however simple to crack by analyzing the letter frequency pattern
'''

def encrypt101(text):
    '''
    shift ASCII values of text up by one
    '''
    return "".join(chr(ord(c) + 1) for c in text) 

def decrypt101(e_text):
    '''
    shift ASCII values of text down by one
    '''
    return "".join(chr(ord(c) - 1) for c in e_text) 

text = "Facebook or Twitter make privacy a thing of the past"

encrypted = encrypt101(text)
print("encrypted = {}".format(encrypted))

print('-'*50)

decrypted = decrypt101(encrypted)
print("decrypted = {}".format(decrypted))

''' my result ...
encrypted = Gbdfcppl!ps!Uxjuufs!nblf!qsjwbdz!b!uijoh!pg!uif!qbtu
--------------------------------------------------
decrypted = Facebook or Twitter make privacy a thing of the past
'''

This type of code does not need a password, but the user has to have this program available.

Lardmeister commented: good idea +10

Recommended Answers

All 31 Replies

This will make the use of letter frequency a little harder for the snoop ...

''' encrypt102.py
simple shift ASCII value by one encryption/decryption
make analyzing the letter frequency pattern harder via substitution
change all 'q' to '}'  then change all 'e' to 'q'
'''

def encrypt102(text):
    '''
    replace 'q' with '}' and 'e' with 'q'
    shift ASCII values of text up by one
    '''
    text = text.replace('q', '}').replace('e', 'q')
    return "".join(chr(ord(c) + 1) for c in text) 

def decrypt102(e_text):
    '''
    shift ASCII values of text down by one
    then replace 'q' with 'e' and '}' with 'q'
    '''
    q_text = "".join(chr(ord(c) - 1) for c in e_text)
    text = q_text.replace('q', 'e').replace('}', 'q')
    return text


text = "Facebook or Twitter make privacy a thing of the past"

encrypted = encrypt102(text)
print("encrypted = {}".format(encrypted))

print('-'*50)

decrypted = decrypt102(encrypted)
print("decrypted = {}".format(decrypted))

''' my result ...
encrypted = Gbdrcppl!ps!Uxjuurs!nblr!qsjwbdz!b!uijoh!pg!uir!qbtu
--------------------------------------------------
decrypted = Facebook or Twitter make privacy a thing of the past
'''

You get the drift. Make it even more difficult to crack using your imagination.
A replace character scheme can also be applied to multiline text's newline characters.

Another way to make letter frequency analysis more difficult ...

''' encrypt103.py
shift every second ASCII value by one encryption/decryption
makes cracking by analyzing the letter frequency pattern harder
'''

def encrypt103(text):
    '''
    shift every second ASCII value of text up by one
    '''
    e_text = ""
    for ix, c in enumerate(text):
        if ix % 2:
            e_text += c
        else:
            e_text += chr(ord(c) + 1)
    return e_text

def decrypt103(e_text):
    '''
    shift every second ASCII value of text down by one
    '''
    text = ""
    for ix, c in enumerate(e_text):
        if ix % 2:
            text += c
        else:
            text += chr(ord(c) - 1)
    return text

text = "Facebook or Twitter make privacy a thing of the past"

encrypted = encrypt103(text)
print("encrypted = {}".format(encrypted))

print('-'*50)

decrypted = decrypt103(encrypted)
print("decrypted = {}".format(decrypted))

''' my result ...
encrypted = Gadecopk!os Uwjtues nale!psiwady!a!tiiog!og uhf qatt
--------------------------------------------------
decrypted = Facebook or Twitter make privacy a thing of the past
'''

You can easily turn this into a skip every third character or so on.

Going one step further and alternate up and down shift ..

''' encrypt104.py
shift ASCII values by one and alternate up/down encryption/decryption
makes cracking by analyzing the letter frequency pattern even harder
special consideration given to space to make printable character
'''

def encrypt104(text):
    '''
    alternate shifts of ASCII value of text up/down by one
    '''
    # replace space with '}' to give printable character
    space = ' '
    text = text.replace(space , '}')
    e_text = ""
    for ix, c in enumerate(text):
        if ix % 2:
            e_text += chr(ord(c) - 1)
        else:
            e_text += chr(ord(c) + 1)
    return e_text

def decrypt104(e_text):
    '''
    alternate shifts of ASCII value of e_text up/down by one
    '''
    text = ""
    for ix, c in enumerate(e_text):
        if ix % 2:
            text += chr(ord(c) + 1)
        else:
            text += chr(ord(c) - 1)
    space = ' '
    text = text.replace('}', space)
    return text

text = "Facebook or Twitter make privacy a thing of the past"

encrypted = encrypt104(text)
print("encrypted = {}".format(encrypted))

print('-'*50)

decrypted = decrypt104(encrypted)
print("decrypted = {}".format(decrypted))

''' my result ...
encrypted = G`ddcnpj~ns|Uvjsuds|n`ld~oshw`dx~`~sihof~ng|ugf|q`ts
--------------------------------------------------
decrypted = Facebook or Twitter make privacy a thing of the past
'''

If you have multiline code, then the newline character can be dealt with similar to the space character. Explore this option.

import string,sys
def reverse(s):
    return s[::-1]
encode = {' ':' '}
for l,revl in zip(string.letters,reverse(string.letters)):
    encode[l]=revl
decode = {' ':' '}
for l,revl in zip(string.letters,reverse(string.letters)):
    decode[l]=revl
while True:
    what = raw_input("Decode or encode").lower()
    if what == "decode":
        current = decode
    elif what == "encode":
        current = encode
    else:
        print "What?"
        continue
    c = raw_input("What message would you like to decode/encode?")
    for i in c:
        try:
            sys.stdout.write(current[i])
        except KeyError:
            sys.stdout.write(i)
    sys.stdout.write('\n')
    sys.stdout.flush()

pretty much unbreakable.(I don't know how, It was an accident!)

Decode or encodeencode
What message would you like to decode/encode?The quick brown fox jumps over the lazy dog
ëÝà ÓÏÜâÚ ãÒÕÍÖ ßÕÌ ÛÏØÔÑ ÕÎàÒ ÐÝà ÙäÊË áÕÞ
Decode or encodedecode
What message would you like to decode/encode?ëÝà ÓÏÜâÚ ãÒÕÍÖ ßÕÌ ÛÏØÔÑ ÕÎàÒ ÐÝà ÙäÊË áÕÞ
The quick brown fox jumps over the lazy dog
Decode or encode
def main():
    import string,sys,encrypt104
    def reverse(s):
        return s[::-1]
    encode = {' ':' '}
    for l,revl in zip(string.letters,reverse(string.letters)):
        encode[l]=revl
    decode = {' ':' '}
    for l,revl in zip(string.letters,reverse(string.letters)):
        decode[l]=revl
    while True:
        what = raw_input("Decode or encode").lower()
        if what == "decode":
            current = decode
            curfunc = encrypt104.decrypt104
        elif what == "encode":
            current = encode
            curfunc = encrypt104.encrypt104
        else:
            print "What?"
            continue
        c = raw_input("What message would you like to decode/encode?")
        m = ""
        for i in c:
            try:
                m = m+ current[i]
            except KeyError:
                m =m + i
        m = m+ "\n"
        m = curfunc(m)
        print m
main()

FUSE YOURS IN!!!!!!!!

Very nice effort, here is the modernized code ...

# -*- coding: cp1252 -*-
''' encrypt105.py
modified code from james.lu.75491856 (James Lu)
'''

# needs to be at beginning of program code
# allows Python27 to use PYthon3 print() options
from __future__ import print_function
import string

def crypt(text, code):
    ''' encodes or decodes '''
    e_text = ""
    for c in text:
        e_text += code.get(c, c)
    return e_text    

# establish letter code dictionary
code = dict(zip(string.letters, string.letters[::-1]))

text = '''\
Man who run in front of car, get tired.
Man who run behind car, get exhausted.
'''

encrypted = crypt(text, code)
print("encrypted:\n{}".format(encrypted))

print('-'*50)

decrypted = crypt(encrypted, code)
print("decrypted:\n{}".format(decrypted))

''' my result ...
encrypted:
òäÖ ÍÝÕ ÒÏÖ ÜÖ ßÒÕÖÐ Õß âäÒ, ÞàÐ ÐÜÒàá.
òäÖ ÍÝÕ ÒÏÖ ãàÝÜÖá âäÒ, ÞàÐ àÌÝäÏÑÐàá.

--------------------------------------------------
decrypted:
Man who run in front of car, get tired.
Man who run behind car, get exhausted.
'''

Just a hint, don't use little l for names it looks too much like a one.

Another simple way to decode a text that can be send via email. The receiving party has to have the same program ...

''' encrypt106.py
using the Python module base64 to encode and decode text
or any binary data like images/pictures
tested with Python27
'''

import base64

def encrypt106(text):
    '''
    use base64 encoding
    '''
    return base64.encodestring(text)

def decrypt106(e_text):
    '''
    use base64 decoding
    '''
    return base64.decodestring(e_text)

text = '''\
I keep pressing the Home button on my
smartphone, but I am still stuck at work.'''

encrypted = encrypt106(text)
print("encrypted:\n{}".format(encrypted))

print('-'*50)

decrypted = decrypt106(encrypted)
print("decrypted:\n{}".format(decrypted))

''' my result ...
encrypted:
SSBrZWVwIHByZXNzaW5nIHRoZSBIb21lIGJ1dHRvbiBvbiBteQpzbWFydHBob25lLCBidXQgSSBh
bSBzdGlsbCBzdHVjayBhdCB3b3JrLg==

--------------------------------------------------
decrypted:
I keep pressing the Home button on my
smartphone, but I am still stuck at work.
'''

For added security we can employ a password ...

''' encrypt107.py
using the Python module base64 to encode and decode text
also added XOR crypting against a password
tested with Python27
'''

import base64
import io
import operator

def encrypt107(text, password):
    '''
    use base64 encoding
    '''
    x_text = XOR_crypt(text, password)
    return base64.encodestring(x_text)

def decrypt107(e_text, password):
    '''
    use base64 decoding
    '''
    b64_text = base64.decodestring(e_text)
    return XOR_crypt(unicode(b64_text), password)

def XOR_crypt(text, password):
    # create two streams in memory the size of the text
    # stream sr to read the text from and
    # stream sw to write XOR crypted bytes to
    sr = io.StringIO(text)
    sw = io.StringIO(text)
    # make sure to start both streams at start position
    sr.seek(0)
    sw.seek(0)
    n = 0
    for k in range(len(text)):
        # loop through password start to end and repeat
        if n >= len(password) - 1:
            n = 0
        p = ord(password[n])
        n += 1
        # read one character from stream sr
        c = sr.read(1)
        b = ord(c)
        # xor byte with password byte
        t = operator.xor(b, p)
        z = chr(t)
        # advance position to k in stream sw then write one character
        sw.seek(k)
        sw.write(unicode(z))
    # reset stream sw to beginning
    sw.seek(0)
    # read all the bytes in stream sw
    text_out = sw.read()
    sr.close()
    sw.close()
    return text_out

# unicode string needed for Python27
text = u'''\
It has been a rough day. I got up this morning and put on my
shirt and a button fell off. I picked up my briefcase and
the handle came off. Now I am afraid to go to the bathroom.'''

# pick a password you like (don't forget it!)
password = 'ford75'

encrypted = encrypt107(text, password)
print("encrypted:\n{}".format(encrypted))

print('-'*50)

decrypted = decrypt107(encrypted, password)
print("decrypted:\n{}".format(decrypted))

''' my result ...
LxtSDFYVTxABUghPE0RFCRoVDBcCDgtKFy9PFQtDRhoCREMOBgFEWgkdHA1ZAU8TClNGHwcQFwkB
UglObBwaDUUSTxMKU0YOUgZCEhsdChcACh4IFwkJFEoXL08CDVQNChZEQhZPHx0XBB0bAVEFDgEB
FwcBFm5DDgpSDFYICx4BFwUOHwEXCQkUShcoAAVEfkYOH0RWAB0TDVNGGx1EUAlPBgsXEgcXRFUH
GxoWWAkCXA==

--------------------------------------------------
decrypted:
It has been a rough day. I got up this morning and put on my
shirt and a button fell off. I picked up my briefcase and
the handle came off. Now I am afraid to go to the bathroom.
'''

The next step might be to use a GUI toolkit so you can use select/copy from a text field and paste the coded text.
I also need to get this to work with Python3.
For a more streamlined variant see ...
http://www.daniweb.com/software-development/python/code/460271/make-e-mail-text-more-secure-python

This very much resembles a snippet I once wrote in C#!
Good work on your part here!
Some tips:
1)I should make the password with unique chars, it would diminish the detection of double chars like the oo in "book".
2) The longer the password, the better. You could manipulate the password and make it longer, one out of many schemes would be the password + it's reverse etc.
eg. if the password is ABC, use ABCCBA to encrypt and decrypt
Keep up the good work!

I am not sure if a password like ABCCBA having a double character like CC would be a good idea.

HiHe, you are right. But it was just a matter of speaking. I could also have used &é@#"t(§çio<%£ as an example, if you rather like that.

The code from james.lu.75491856 (James Lu) can easily be cracked with character frequency analysis, since the most common characters in the English language (or any other language) will still be assigned the same sub characters.

Password expansion is a good idea. Here is one way to do it:

''' password_expand.py
a longer password is more secure, so expand it this way
'''

def password_expand(pw):
    s1 = pw
    s2 = "".join(chr(ord(c) + 1) for c in pw)
    s3 = "".join(chr(ord(c) - 1) for c in pw)
    return s1 + s2 + s3

# the user enters this password
pw = 'Nixon'

# program uses this password
pw2 = password_expand(pw)

# test
print(pw)
print('-'*30)
print(pw2)

''' my output -->
Nixon
------------------------------
NixonOjypoMhwnm
'''

Python3 has modernized the language and has thrown some roadblocks too when it comes to unicode ...

''' encrypt106_py23.py
using the Python module base64 to encode and decode text
or any binary data like images
modified to work with Python2/3
tested with Python27, Python33 and IronPython273
'''

import base64

def encrypt106(text):
    '''
    use base64 encoding
    '''
    try:
        # Python2
        return base64.encodestring(text)
    except TypeError:
        # Python3
        return base64.encodestring(text.encode("utf8")).decode("utf8")

def decrypt106(e_text):
    '''
    use base64 decoding
    '''
    try:
        # Python2
        return base64.decodestring(e_text)
    except TypeError:
        # Python3
        return base64.decodestring(e_text.encode("utf8")).decode("utf8")

text = '''\
I keep pressing the Home button on my
smartphone, but I am still stuck at work.'''

encrypted = encrypt106(text)
print("encrypted:\n{}".format(encrypted))

print('-'*50)

decrypted = decrypt106(encrypted)
print("decrypted:\n{}".format(decrypted))

''' my result ...
encrypted:
SSBrZWVwIHByZXNzaW5nIHRoZSBIb21lIGJ1dHRvbiBvbiBteQpzbWFydHBob25lLCBidXQgSSBh
bSBzdGlsbCBzdHVjayBhdCB3b3JrLg==

--------------------------------------------------
decrypted:
I keep pressing the Home button on my
smartphone, but I am still stuck at work.
'''

Mine could mix up the dictiionary according to a raandom seed. (Python has the merseene twist(the best) in it's random module)

The us gov is stealing our emails, so we could make an app to send emails with encryption.
We can use all the formats, but have a code telling us witch one, so it would be weird.

@James.Lu
How would you mix up a dictionary with a random seed?

like say we have this:d = {5:3,2:4,9:3}
we generate a seed and set it:random.seed(random.randint(1,20))
get the keys and values:

keys =d.keys()
values=d.values()

shuffle:

random.shuffle(values)

recreate: dict([k,v for k,v in zip(keys,values)])

It might be important to hide numbers, this code does not:

# -*- coding: cp1252 -*-
''' encrypt105.py
modified code from james.lu.75491856 (James Lu)
'''

# needs to be at beginning of program code
# allows Python27 to use PYthon3 print() options
from __future__ import print_function
import string

def crypt(text, code):
    ''' encodes or decodes '''
    e_text = ""
    for c in text:
        e_text += code.get(c, c)
    return e_text    

# establish letter code dictionary
code = dict(zip(string.letters, string.letters[::-1]))

text = '''\
will pay $3,250,000 for the 98 diamonds
'''

encrypted = crypt(text, code)
print("encrypted:\n{}".format(encrypted))

print('-'*50)

decrypted = crypt(encrypted, code)
print("decrypted:\n{}".format(decrypted))

''' my result ...
encrypted:
ÍÜÙÙ ÔäË $3,250,000 ßÕÒ ÐÝà 98 áÜäØÕÖáÑ

--------------------------------------------------
decrypted:
will pay $3,250,000 for the 98 diamonds
'''

Something else to play around with is a decoyed message ...

''' decoy_crypt101.py
create decoy crypted data that matches typical
English text letter frequency then replace every nth character
with a character of your message
you send out the decoyed message text and "nth info" separately
'''

import random

random.seed()

def create_decoy(mydict, size=1):
    '''
    create random decoy string that has English text letter frequency
    '''
    decoy_str = ""
    for letter, count in mydict.items():
        decoy_str += letter*count*size
    # convert string to list
    decoy_list = list(decoy_str)
    # random shuffle the list elements
    random.shuffle(decoy_list)
    # replace every 72nd element with a newline
    new_list = []
    for ix, item in enumerate(decoy_list):
        if ix % 72 == 0:
            new_list.append('\n')
        else:
            new_list.append(item)
    # join list to form a string, eliminate leading newline
    return "".join(new_list)[1:]

def embed_message(decoy_str, my_message, terminator='*'):
    '''
    use a random decoy string to embed a message
    here you replace every 7th character
    '''
    my_message = my_message.lower() + terminator
    new_list = []
    n = 0
    for ix, letter in enumerate(list(decoy_str)):
        # replace every 7th character
        # do not replace newline
        if ix % 7 == 0 and ix != 0 and \
            letter != '\n' and n < len(my_message):
            new_list.append(my_message[n])
            n += 1
        else:
            new_list.append(letter)
    return "".join(new_list)

def extract_msg(decoyed_str, terminator='*'):
    '''
    use a decoyed string and extract the embedded message
    '''
    new_str = ""
    for ix, letter in enumerate(list(decoyed_str)):
        # the message is hidden in every 7th character
        # exclude newline
        if ix % 7 == 0 and ix != 0 and letter != '\n':
            if letter == terminator:
                break
            new_str += letter
    return new_str

my_message = "Meet me at four thirty PM at the dog park elm tree"

# a dictionary of typical English text normalized to 'z' = 1
# that contains letters a - z, spaces and hyphens
letter_norm_count_eng = \
{' ': 312,
 '-': 7,
 'a': 115,
 'b': 21,
 'c': 38,
 'd': 61,
 'e': 171,
 'f': 32,
 'g': 28,
 'h': 84,
 'i': 104,
 'j': 1,
 'k': 9,
 'l': 56,
 'm': 37,
 'n': 98,
 'o': 109,
 'p': 25,
 'q': 1,
 'r': 85,
 's': 89,
 't': 129,
 'u': 40,
 'v': 15,
 'w': 29,
 'x': 2,
 'y': 30,
 'z': 1}

decoy_str = create_decoy(letter_norm_count_eng)

print("decoy_str = \n{}".format(decoy_str))

print('-'*72)

decoyed_msg = embed_message(decoy_str, my_message)

print("decoyed_msg = \n{}".format(decoyed_msg))

print('-'*72)

msg = extract_msg(decoyed_msg)

print("hidden message = \n{}".format(msg))


''' possible result ...
decoy_str =
otlhr aa  - hoatdt-so  soh s uime aido  ttu prari  ntheesgnot aettorstc
eeo u  indib  eet esr iprermie ip emoehidabchjnr ewnh tpvt resyiash gil
ux   nny feeeimiihoetusl yntflend - l rafryeee msyacortneccfhhcrr nhd i
e  fd  r eni n rhe y oroairwarw uronie t tmn uld oatt todernehenas hva
npra rdrt  ousnbooaaghvsdt ip ln   ee eimr tug mltn ne ehabo yetr  ts r
eoteuhtumepekiioareehgoiotiientmae i e omv lo enoad omotv eetc et  ofof
rc u oecd yrei  sgdleswhochr mof essies ca l  ha  th e satiladsrv nsorl
nic rmiplfveo ddatedseiudulaiocos is hwdadsadeay  nio naueetbetdh ase a
rhesooa e  t tn r    olsfdr uhai eeinhbsu pntnthaieefb saotdieoe wt ssi
imrf eitwsnggraaiotutwanentpt ett dtio kytl ghs sydaah  bo r obuhicenwp
lesdiu ytrnrhifwhagc nk tlc mstf  eegneetsn iohchyn ttcoh n -noslt hmos
tesiee tllblhiseaw ofdiplhversue a rbosd hdi anm ei eeu oc t iiaosea o
s lilunrd tt   s nt ghreeneommatnntd  ut r eaemeedes vldrhs tnnwoe et r
f ohpilrnrcxdtoo a eassa iahf a  e rnrte    bsocekh te gihefn setrin-th
  reioc pgmlu awie ginao aw   dinhnew ednhtausosgpdllgg  rheistassodp a
totpnescah nhhnttoyoim di anlcesnoaneaiut emt vtsltn  neuvdesehewlrdsys
a saas  anc tll o gtwhh r  ghgp  tcuele ooyclshu tuhvkoe hooode ed omak
rl lamahfecehofdb of sgmlnds  gcinbmt aecylsir nlegln iha mo lsbb a wuh
tr ientr i  st emohtoeemidibahtgrefseiaaypwr raeo kietera  o m eo tea
 a tcofaemmono thy u evrrny-whiatfd rpi heifn  nstsaeeidadueeepi sar i
ttatewohaca tbhoyaeaaec rhl insaaayy dw  dtrihhnpnaip itstdadoe detfyni
loyirbr raln svrc oaunaserosiyei cawkny ssi  sz ii of whrdoina ceh n
  v n roitam ete trotab a aylwui danrnerl  a ltt tegkguptp t tdhafetmsr
ti hth fulloilllca e uaeirsehntfehtgawwdniaotwtstf iye he b oo eoi nren

------------------------------------------------------------------------
decoyed_msg =
otlhr am  - hoetdt-soe soh stuime a do  ttm prarie nthee gnot aattorstt
eeo u  indibf eet eor ipreumie ipremoehi abchjnt ewnh hpvt reiyiash ril
ux t nny fyeeimii oetuslpyntflemd - l  afryeea msyactrtnecc hhcrr thd i
eh fd  reeni n  he y odoairwaow uronge t tm  uld optt todarnehenrs hva
npra rkrt  ou nbooaaehvsdt lp ln  mee eim  tug mttn ne rhabo yetr  tser
eote*htumepekiioareehgoiotiientmae i e omv lo enoad omotv eetc et  ofof
rc u oecd yrei  sgdleswhochr mof essies ca l  ha  th e satiladsrv nsorl
nic rmiplfveo ddatedseiudulaiocos is hwdadsadeay  nio naueetbetdh ase a
rhesooa e  t tn r    olsfdr uhai eeinhbsu pntnthaieefb saotdieoe wt ssi
imrf eitwsnggraaiotutwanentpt ett dtio kytl ghs sydaah  bo r obuhicenwp
lesdiu ytrnrhifwhagc nk tlc mstf  eegneetsn iohchyn ttcoh n -noslt hmos
tesiee tllblhiseaw ofdiplhversue a rbosd hdi anm ei eeu oc t iiaosea o
s lilunrd tt   s nt ghreeneommatnntd  ut r eaemeedes vldrhs tnnwoe et r
f ohpilrnrcxdtoo a eassa iahf a  e rnrte    bsocekh te gihefn setrin-th
  reioc pgmlu awie ginao aw   dinhnew ednhtausosgpdllgg  rheistassodp a
totpnescah nhhnttoyoim di anlcesnoaneaiut emt vtsltn  neuvdesehewlrdsys
a saas  anc tll o gtwhh r  ghgp  tcuele ooyclshu tuhvkoe hooode ed omak
rl lamahfecehofdb of sgmlnds  gcinbmt aecylsir nlegln iha mo lsbb a wuh
tr ientr i  st emohtoeemidibahtgrefseiaaypwr raeo kietera  o m eo tea
 a tcofaemmono thy u evrrny-whiatfd rpi heifn  nstsaeeidadueeepi sar i
ttatewohaca tbhoyaeaaec rhl insaaayy dw  dtrihhnpnaip itstdadoe detfyni
loyirbr raln svrc oaunaserosiyei cawkny ssi  sz ii of whrdoina ceh n
  v n roitam ete trotab a aylwui danrnerl  a ltt tegkguptp t tdhafetmsr
ti hth fulloilllca e uaeirsehntfehtgawwdniaotwtstf iye he b oo eoi nren

------------------------------------------------------------------------
hidden message =
meet me at four thirty pm at the dog park elm tree
'''

Note: Instead of every 7th character you could cycle through every 3rd, 5th, 7th character. That should make it harder on Grandma to figure it out.

The next approach looks more innocent. First you send a normal looking text and later you send a string of numbers, where each number is an index in the normal text that rebuilds your message ...

''' xmas_letter_crypt101.py
hide a message in a boring lengthy xmas letter
first you send the xmas letter, later you send an index
string where each indexed character in the xmas letter
matches a message character (all lower case)
'''

import pprint
import random

def create_index_dict(text):
    '''
    return a character:index_list dictionary of a given text
    replace newlines with '~~'
    '''
    text = text.lower()
    index_dict = {}
    for ix, letter in enumerate(text):
        index_dict.setdefault(letter, []).append(ix)
    return index_dict

def index_message(index_dict, my_message):
    '''
    create the index string you can send
    each index matches a message char in the xmas letter
    '''
    # convert to lower case
    my_message = my_message.lower()
    index_str = ""
    n = 1
    for ix, c in enumerate(my_message):
        index_list = index_dict[c]
        # shuffle the index_list
        # and pick the first element
        # adds some randomness to index_str
        random.shuffle(index_list)
        index = index_list[0]
        # add a newline char after 10 indices
        # else add a space
        if n % 10 == 0:
            index_str += str(index) + '\n'
        else:
            index_str += str(index) + ' '
        n += 1
    return index_str

my_message = "Meet me at four thirty PM at the dog park elm tree"

# a typical xmas letter you can receive if you are unlucky
# make sure it has all your potential message characters in it
xmas_letter = '''\
Dear friends,
it is a great pleasure to let you all know what we did in the past year.
We are quite sure you are just waiting with high anticipation to read
this.

In January Zoey and Bruce went with us to see Aunt Lulu in Park City Utah.
Should we quickly e-mail you all the interesting slides we took?

In August we went to visit Blair and Karen at their new home in zany
Texas.  That place has five bedrooms and seven bathrooms. One of their
children fell off the bike, and we took little Freddy to the local
child-clinic!

Bob Quackenbush went to the doctor to have the wart on his nose removed.
He looks real good now!  Attracting the amorous attention of Nancy Trotter
who had a heart attack in May, but they fixed her and she survived.

We hope you are all very healthy and have a merry Christmas and a
prosperous New Year.  Greetings to all,

Mark, Rita and dog Pluto
'''

index_dict = create_index_dict(xmas_letter)

#pprint.pprint(index_dict)  # test

# display content of index dictionary
# lists shortened to 10 elements, '``' subs for newline
print("Prettified content of the index dictionary:")
for key, val in sorted(index_dict.items()):
    # limit list to 10 elements to print nicely
    print("{}: {}".format(repr(key), val[:10]))

print('-'*72)

index_str = index_message(index_dict, my_message)

print("Potential index_str = \n{}".format(index_str))

print('-'*72)

# convert index_str to an index list
index_list = [int(index) for index in index_str.split()]

#pprint.pprint(index_list)  # test

# now apply the index list to the lowercase xmas letter
msg = "".join(xmas_letter.lower()[index] for index in index_list)

print("Hidden message = \n{}".format(msg))

'''
# optional character frequency count information
print('-'*72)
print('')

from collections import Counter
cntr = Counter(xmas_letter.lower())
# print sorted by count (default)
pprint.pprint(cntr.most_common())
'''

''' result ...
Prettified content of the index dictionary:
'\n': [13, 86, 156, 162, 163, 238, 303, 304, 373, 444]
' ': [4, 16, 19, 21, 27, 36, 39, 43, 47, 51]
'!': [524, 622]
',': [12, 471, 704, 848, 855]
'-': [258, 517]
'.': [85, 161, 237, 379, 430, 598, 741, 829]
'?': [302]
'a': [2, 20, 25, 31, 48, 59, 77, 83, 90, 109]
'b': [184, 332, 402, 421, 467, 527, 529, 538, 706]
'c': [140, 187, 228, 252, 390, 445, 508, 512, 518, 523]
'd': [0, 10, 65, 67, 155, 182, 244, 291, 340, 404]
'e': [1, 8, 24, 30, 35, 41, 63, 74, 82, 88]
'f': [5, 397, 437, 454, 460, 461, 492, 659, 715]
'g': [22, 124, 133, 286, 310, 614, 634, 832, 839, 868]
'h': [58, 73, 129, 131, 134, 158, 198, 236, 240, 273]
'i': [7, 14, 17, 66, 69, 96, 120, 122, 127, 132]
'j': [113, 167]
'k': [52, 226, 253, 301, 342, 469, 483, 535, 606, 696]
'l': [29, 40, 49, 50, 215, 217, 243, 254, 262, 269]
'm': [259, 363, 408, 428, 593, 641, 701, 788, 800, 851]
'n': [9, 53, 70, 123, 137, 147, 165, 169, 181, 192]
'o': [38, 45, 54, 106, 146, 150, 176, 204, 241, 265]
'p': [28, 76, 142, 223, 387, 749, 810, 814, 870]
'q': [94, 249, 531]
'r': [3, 6, 23, 34, 84, 91, 102, 110, 152, 172]
's': [11, 18, 32, 78, 100, 115, 160, 201, 206, 239]
't': [15, 26, 37, 42, 60, 72, 79, 97, 116, 121]
'u': [33, 46, 95, 101, 107, 114, 170, 186, 200, 211]
'v': [326, 399, 417, 567, 595, 736, 738, 764, 783]
'w': [55, 57, 62, 87, 118, 126, 190, 195, 246, 295]
'x': [376, 717]
'y': [44, 81, 105, 173, 178, 231, 255, 264, 372, 497]
'z': [175, 369]
------------------------------------------------------------------------
Potential index_str = 
701 74 24 577 803 408 822 458 171 671
16 492 812 309 688 27 116 383 522 405
502 775 547 814 851 71 629 203 337 636
541 281 21 617 54 286 787 749 384 609
52 484 319 519 851 728 546 405 758 478

------------------------------------------------------------------------
Hidden message = 
meet me at four thirty pm at the dog park elm tree
'''

This is an old post, but I didn't see any translation tables in here. So here you go, a less secure encryption method for low-risk data:

rot13 = str.maketrans(
    'ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz',
    'NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm')
encrypted = 'This is encrypted'.translate(rot13)
print(encrypted)
decrypted = encrypted.translate(rot13)
print(decrypted)

You can make the translation tables almost anything you want. I used rot13 as an example. I wouldn't recommend something like this for high-risk data.

Python2 has a 'rot13' built in ...

''' rot13_encode2.py
example of simple encoding/decoding using Python's 'rot13'
alphabet is shifted by 13 positions to nopqrstuvwxyzabcdefghijklm
so original 'a' becomes 'n'
conversely 'A' becomes 'N'
(non-alpha characters are not affected)
Python2 only!
'''

text = "Peanuts-88"
print("original = " + text)

encoded = text.encode('rot13')
print("encoded  = " + encoded)

decoded = encoded.encode('rot13')
print("decoded  = " + decoded)

''' my result ...
original = Peanuts-88
encoded  = Crnahgf-88
decoded  = Peanuts-88
'''

Expanding from chriswelborn's code ...

''' crypt_table101.py
encrypt and decrypt using tables
'''

import string

''' make the from and to string
s_from = string.ascii_uppercase + string.ascii_lowercase
import random
q = list(s_from)
random.shuffle(q)
s_to = "".join(q)
print(s_from)
print(s_to)
'''

# strings have to be same length
# and contain all the characters
s_from = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
s_to   = "GhtUJdEcnbRFLiaguOQIPTYDpwNeqWrHZjfVsBXklxyoKAvzCSmM"

trans_table_encrypt = string.maketrans(s_from, s_to)
trans_table_decrypt = string.maketrans(s_to, s_from)

text = "Meet me at four thirty PM at the dog park elm tree"

encrypted = text.translate(trans_table_encrypt)
print(encrypted)

decrypted = encrypted.translate(trans_table_decrypt)
print(decrypted)

''' my result ...
LrrA Xr NA Hlvo AjfoAm gL NA Ajr WlZ xNos rBX Aorr
Meet me at four thirty PM at the dog park elm tree
'''

More of a game!

An interesting possibility ...

''' secret_message101.py
explore secret messages with Python
'''

def make_length_even(text):
    '''
    if the text character count is an odd number,
    pad the text with a period to make it even
    '''
    if len(text) & 1:
        text = text + '.'
    return text

def split_odd_even(text):
    '''
    split a text string into a string that contains
    all the even indexed characters and a string
    that contains all the odd indexed characters
    '''
    even_str = ""
    odd_str = ""
    odd = 1
    even = 0
    for k in range(len(text)/2):
        even_str += text[even]
        odd_str += text[odd]
        odd += 2
        even += 2
    return even_str, odd_str

def combine_strings(even_str, odd_str):
    text = ""
    for c1, c2 in zip(even_str, odd_str):
        text += c1 + c2
    return text

text = "see you at seventeen hours in the park"

text = make_length_even(text)
print(text)  # test

even_str, odd_str = split_odd_even(text)

print(even_str)  # seyua eete or ntepr
print(odd_str)  # e o tsvnenhusi h ak

# now this would give you your original text back
text2 = combine_strings(even_str, odd_str)

print(text2)   # see you at seventeen hours in the park

# now comes the trick, combine the two string in reverse order
# and you get one secret string that you could send out
text_rev = combine_strings(odd_str, even_str)

print(text_rev)  # es eoy utas veneetneh uosri  nht eapkr


# reverse your process to get the original text back
# from the secret string ...
even_s, odd_s = split_odd_even(text_rev)
print(even_s)
print(odd_s)
# keep arguments in reverse order
text3 = combine_strings(odd_s, even_s)
print(text3)

... just to get your mind going.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.