I want to "translate" a text so that its encrypted form should be pronounceable text. Is there any crypto technique that can make encrypted text look as another language? (yet, difficult to decrypt).
-
1$\begingroup$ Not another language but look at Format Preserving Encryption, that you can spell, also, you can encode the output into base64... $\endgroup$– kelalakaCommented Sep 5, 2019 at 13:08
-
1$\begingroup$ Commercial one-part codes used pronounceable words (prior to WW1, then the telegraph rules changed), but that isn't software and wasn't secure against attack even at the time. $\endgroup$– Eugene StyerCommented Sep 5, 2019 at 14:41
-
4$\begingroup$ You mean something like this: xkcd.com/257 ? $\endgroup$– vszCommented Sep 6, 2019 at 13:38
-
1$\begingroup$ Possible duplicate of Spoken encryption $\endgroup$– dan04Commented Sep 6, 2019 at 16:38
-
1$\begingroup$ I'm voting to close this question as off-topic because encoding data into pronounceable text is not specific to cryptography in any way. $\endgroup$– forestCommented Sep 7, 2019 at 8:46
7 Answers
The best solution is out of scope for this website. Just apply an algorithm that converts binary data to human-readable pronounceable text.
A simple solution, much like base-64 or diceware, would be to download a dictionary, split binary ciphertext into chunk, and replace each chunk by selecting the nth word in the dictionary. Join the words together using spaces as separators. Punctuation can be added randomly.
The process would be reversed by removing punctuation, splitting on spaces, looking up the index of each word, then joining the binary format of the indices together.
Format preserving encryption is undesirable in this case. English prose is not a simple data format. It would be hard to convert one message to another without leaking some information about the content and/or format of the text.
Chances are also pretty good that readers wanting to implement the same kind of thing as you would roll their own format-preserving encryption algorithm which is little more than a substitution cipher. (Replacing plaintext words with pseudorandom dictionary words, for example.)
Substitution ciphers can be broken with paper and pencil. They put puzzles in newspapers next to Sudoku and comics where people are challenged to do exactly that.
The primary reason I suggest looking at reversible methods of encoding binary data as English text is because I think it's best to work to work on the process of encrypting and of formatting data as two totally independent problems.
When you use normal strong encryption (don't forget authentication), the ciphertext will be indistinguishable from a randomly generated bit sequence. It won't matter if the binary-to-text conversion reveals something about the input because the input is ciphertext. Even side channels in the conversion algorithm wouldn't be a problem if the encryption implementation isn't vulnerable to side-channel attacks.
Therefore, I think you would have better luck if you took that half of the question to StackOverflow.
You should not have high hopes for the results. Procedural generation of text is a difficult problem. It's of interest to AI researchers, spammers, news media, anyone with customer support chat, and artists. Even the most successful algorithms produce text that seems unnatural
It's really hard to generate text which can pass for something written by a real person. Luckily (or not, if you use a spam filter) it's also somewhat hard for computers to tell the difference between human-generated and computer-generated text.
As for what kind of suggestion I would give if you asked on StackOverflow...
I would take word frequency and n-gram frequency into account if the purpose of the algorithm was steganography. "To" is more likely to appear in a normal sentence than "meteorite" is. "Go to" is more likely than "jump bread".
Think of using the auto-complete function on a phone. You could write a random sentence that might look legitimate at first glance pretty easily. You could randomly select the first one or two letters of each word and select from the options given to you. An n-gram based data encoding algorithm might produce pretty similar results.
If steganography is not required (say the purpose of making ciphertext human readable was so that you could send a message over an audio channel or less-than-reliable text channel) then the simple word list encoding method is what I would try. I would make sure the word list doesn't contain homophones or even words with similar or confusing spellings.
(See one of EFF's short diceware word lists. There is one where the first three letters of a word uniquely determines which number it corresponds to and no two words have spellings which are too close to make spellcheck hard. Something like this would be more resilient to typos and misunderstandings.)
I don't know of any tools that do what you want, and so likely you'll need to develop something on your own.
I assume you want to take a plaintext and generate a 'ciphertext' which is effectively undecipherable (unless you know the key), and looks sort of like text in some unknown language (after some unspecified level of inspection - fooling an experienced linguist who studies it would be much harder than passing a casual inspection).
One overall design would be to run the plaintext through a standard cipher (e.g. AES-GCM), which produces a random looking string of bits, and then encoding that string of bits in some pseudo-language. This effectively covers the first requirement (security), as we believe that AES-GCM is secure, and the encoding process can't weaken things.
The only other question (apart from "which standard cipher") is how we encode the string.
The easiest method would be to generate a large dictionary (with, say, 4096 entries) of pseudowords; strings that are individually pronounceable, distinct, and at first glance, look like they might be words from the same language. Then, you would divide the bit string up into 12 bit sections, and for each 12 bits, output the word that corresponds to that setting of 12 bits; the decoding process is obvious.
This is not too much work; however it probably won't fool anyone who studies the text in any detail - it is likely to see that the word order really doesn't follow any particular pattern (and they will likely see repeated words on occasion; that is, the same word occurring twice in a row; that is very very unlikely to happen in a real language text[1]).
If fooling people is a goal, the next step might be to place a pseudogrammar on top of your pseudovocabulary. This is, instead of having a single dictionary, you might divide it up into 'nouns', 'verbs', 'adjectives', 'prepositions', etc; and then when you create a sentence, you randomly pick a sentence form (e.g. Article-Noun-Adjective-Verb-Adverb-Noun' might be one possibility; remember, your pseudogrammar need not follow English rules), and then for each possibility, you use bits from the bitstring to select words from the appropriate dictionary (for example, if you have defined 4 articles, you would use 2 bits from the bitstring to select from them).
This is obviously more work, but may be able to fool some observers, even after some small period of study. Things could get even more complex (real languages often conjugate and decline words, for example), but I suspect you aren't interested in doing that much work...
[1]: Yes, that was intentional...
As others have hinted at, the correct answer here depends a lot on the specifics of exactly what you are trying to achieve and why. Do you want the encrypted result to just be visually pleasing to somebody looking at it as text (aesthetics)? Do you want it to be something that somebody could read aloud to somebody else, who could then write it down and successfully decrypt it (phonetic distinctiveness)? Are you anticipating somebody would need to memorize it (mnemonic value)? Do you want it to be easily communicable between people who speak different languages? Do you want it to be something that somebody might mistake for an actual human language that they don't know (potentially very hard, depending on the savviness of the reader)? Do you want to make somebody believe that an encrypted message is actually an unencrypted message in a real language like English (very very difficult to do, and probably verging on the borders of somebody's current AI research project)? Also, how important is compactness of the output, etc?
In any case, you should not go trying to invent a new form of encryption for this. Making encryption algorithms that are secure and robust is extremely difficult, and odds are anything new will have potentially serious weaknesses. In general, always start with an established encryption algorithm that is well-used and has been rigorously reviewed by the cryptography community. The good news is that you don't have to roll your own encryption for this. As various other people have pointed out, what you can (and should) do is simply use an established encryption method to produce a binary encrypted output, then develop some methodology for converting between arbitrary binary data and a form that is "pronounceable".
As for that next step, there are several possible ways to do it, all with advantages and disadvantages:
Represent binary data as hex, or base64, etc.
This is technically "pronounceable", as it is possible for a human to read things off a digit or a letter at a time and have somebody else understand what they mean, but is probably not really what you were going for.
Benefits:
- Fairly compact (introduces a relatively low amount of size overhead compared to many other methods)
- Can be done quickly, with very little in the way of memory/storage requirements
- Lots of existing libraries/methods already exist to do this, so you wouldn't have to write your own
Drawbacks:
- Cumbersome and slow to communicate orally
- Easy to lose one's place in a sea of digits while reading/writing
- Does not really resemble a "human language"
Map binary values to dictionary words
This is effectively an old-school "code book" approach. Take the encrypted message, break it down into n-bit values, use each value to look up a word in a known dictionary, and use that word to represent those bits in the output.
Benefits:
- Looks more like real language (though not enough to fool any native speaker)
- Much easier to read aloud and understand
- Potentially easier to remember than most other methods (at least for those who speak the dictionary language)
Drawbacks:
- Not very compact (if you're using 8 bits per word, for example, and the average (English) word size is 4.7 bytes (38 bits), that's an output that's around 4.7 times the input size. Using a larger dictionary makes this better, but also potentially makes some of the other issues (below) worse.)
- Requires a large amount of shared data (the dictionary) to encode and decode
- Homonyms, compound words, regional differences (accents, etc) can all make correct communication problematic (so word choice for the dictionary may be tricky). As WhiteWinterWolf points out, there has already been a fair bit of work by various folks in the past to try to assemble "good" dictionaries for different purposes (but some that are good for one thing are not good for another).
- May pose problems for speakers who are not fluent in the dictionary's language (for example, the correct way to pronounce many English words is not necessarily obvious to many non-English speakers, whereas many English speakers would have no idea at all how to pronounce some of the characters in a Norwegian or Czech dictionary)
Construct words from pronounceable syllables
For each word, break the input into n-bit values, then map each value to a particular syllable, and string the syllables together into a word.
Benefits:
- Can be relatively compact compared to dictionary methods
- Does not require a large amount of extra data to encode/decode
- Is not biased towards any particular human languages
- Syllables can be chosen so as to minimize pronunciation ambiguities
Drawbacks:
- Not as easy to remember words
- Does not look quite as much like a "real" language (but can be surprisingly close if dressed up a bit)
This last approach is actually the one I'd probably look at myself if faced with this sort of problem, as it avoids most of the problems of trying to choose good dictionary words, etc. In fact, I know this wasn't a code challenge, but after reading your query this whole thing sorta got stuck in my head as an interesting thought experiment, and I ended up writing up an example implementation of a syllable-based encryption-and-encoding process (in Python):
https://gist.github.com/foogod/9710309d41e87d7364de74d445e6839c
In fact, you can even take the output of that program and dress it up with punctuation, capitalization, etc, to make it look more like real text. Here's an example of something encrypted and then reformatted based on the formatting of some of the text from "Pride and Prejudice" (you can decode this with passphrase "walrus"):
“Nonadana bizore Bepo Sumebomu,” hinekeya nu nude bu tafu dizu dopure, “bepu bo tuzehigo
tonisebu Mo Pido yarododi zopa tinobita moku?”
Mu Buroya hogo pebazu keguru neru madi.
“Pefuduhe hobe fugone,” muboka be; “hibahino Gupi No dipi zo sehoda betinu, re botupoji
kurube sabigeke yugu hogumeku yodiwaga.”
Do Zahina pohisumu moduhe de.
“Noyatumo pu popa ne bupenu nonumobo ze teda pasapu kiheku?” nuzu nita jigodani tize.
“_Nebu_ nisora didose jihopo di, su Sugodo sugitu dutuniwo!”
(You might notice it actually sounds a little reminescent of Japanese, which actually is not entirely accidental, as the syllable set is based off of Japanese kana)
Note: Do NOT make the output have the same formatting as the input had, as that is likely to leak a fair bit of information about the input's contents. (In this case, I picked a completely unrelated book to use as a formatting template)
"Should be pronounceable text" and "make encrypted text look as another language" are two different things, but in any case what you are dealing this in this question is the transport medium, which is a different step coming after the encryption process (which, by the way, makes your question suitable for https://security.stackexchange.com/ I guess).
In other words, you are free to use the encryption method of your choice, no matter if it produces binary files, numbers, or whatever.
Then you will have to translate this raw, encrypted data in order to transmit it :
Some well-known work has already be done for the requirement of "pronounceable text", in particular you may want to look at PGP word list and Mnemonic encoding. These are standardized processes to transmit binary data through voice in an efficient manner using carefully selected words, easy to understand while reducing any ambiguity for the recipient of your message.
The requirement of "make encrypted text look as another language" is more exotic and falls in the area of steganography. Reading the title of your question, I don't think it is really what you are after. Steganography is more about how to store an hidden message inside some apparently innocuous data, and really isn't en efficient method to transmit arbitrary data. Usually the ratio of actual information over generated data is very low for the process to remain hard to detect (for instance you would read one entire page of text in order to transmit one single hidden word). There are usually better ways, but such methods can still be used as a last resort.
It is easy. For example:
Take first 256 words from the language dictionary, like Oxford dictionary or Merriam-Webster dictionary, and for each byte of your encrypted message use a word with corresponding number.
Or take first 65536 words from the dictionary and replace each 2 bytes with corresponding word.
Or take each encrypted byte. Add a random multiple of 256, which is less than the number of words in your dictionary. E.g. if encrypted byte is 65 and random number is 194, take the word number 49729 (= 65 + 256*194). To get encrypted message from the words for each word find its number in the dictionary and take
(word number) mod 256
. E.g.49729 mod 256 = 65
.
-
$\begingroup$ Every answer starting with "It is easy" I am very sceptical of. Your approach won't produce results that come anywhere close to something that resembles real language, also the encoded text will be probably an order of magnitude longer than the input. $\endgroup$ Commented Oct 5, 2022 at 4:38
-
$\begingroup$ @TadeoHepperle: 1) It is your right to be skeptical or optimistic about anything. 2) The OP is asking about solution that produces pronounceable encryption result. My approach does provide this. 3) Also resembling any language is easy: Take any text and put at every 10th or every 100th position the encrypted word. Will it resemble the language? Sure it will. To decrypt extract the words. The positions are known. 4) There is no any requirement about the length. $\endgroup$ Commented Oct 5, 2022 at 5:25
Another idea for the "option" would be to use only alphabet and only consonants in order to create somehow "flexible" output, than to manually add vowels, spaces and punctuation to look as a text. Would that be possible?
-
$\begingroup$ This appears to be a question or comment rather than an answer to the question. If this is supposed to be an answer to the question, then please ensure it does not contain any questions. $\endgroup$ Commented Sep 10, 2019 at 14:22
I just found this thread because the same question appeared to me today. I want to add a fourth option to the three Foogod already mentioned. You could also consume 255 bits of ciphertext at a time to generate a permutation of a deck of 52 playing cards and then read out the cards. This adds some error detection in a way because if a card does not appear in a deck or a card appears twice, the recipient will know that a transmission error occurred.