Una cadena que, si está cifrada o descifrada con la misma clave, obtiene una palabra / declaración en inglés en ambos casos

2

Estoy tratando de encontrar una cadena S que si está encriptada usando un Cifrado Vigenère con clave K, Obtiene una declaración / palabra en inglés que tiene sentido. Además, si la misma cadena S se descifra con el cifrado Vigenère y nuevamente con la misma clave K, obtiene otra declaración / palabra en inglés que también tiene sentido.

Creo que si trato de encontrar una cadena que tenga una estructura determinada, podría encontrar un caso así, ¿alguna otra sugerencia de expertos en seguridad que pueda ayudarme a encontrar una cadena y una clave?

    
pregunta Mohamed Khamis 15.10.2012 - 22:44
fuente

3 respuestas

1

Me aburrí anoche, solo toma alrededor de 1 minuto forzar la fuerza bruta en una palabra-lista de 27143 palabras.

String             |Key                |Encrypted          |Decrypted
-------------------+-------------------+-------------------+-------------------
ANAL               |PREACH             |PEEL               |PEEP
ANTS               |BEHOLD             |BRAG               |BROW
AURA               |JOKER              |JIBE               |JUTE
AWRY               |TARIFF             |TWIG               |TEAK
BLOC               |SPORADIC           |TACT               |REAP
BINS               |JAYWALK            |KILO               |ISLE
CANE               |REROUTE            |TEES               |PEEK
CANE               |ROACH              |TONG               |PONY
CARP               |RODENT             |TOUT               |POMP
CART               |FAULTED            |HALE               |DADS
CART               |FIELDED            |HIVE               |DINS
CART               |PENMANSHIP         |REEF               |NEWT
CAPE               |TETHER             |VEIL               |REED
CUED               |BURBLE             |DOVE               |ZANY
DENS               |WEAKEN             |ZINC               |TANS
DENT               |GEOLOGICAL         |JIBE               |DABS
DENT               |PEEL               |SIRE               |MARS
DEAN               |PERFECTED          |SIRS               |MARS
FADS               |WAIL               |BALD               |RAFT
FATS               |GABLE              |LAUD               |BAIT
FATS               |WAYLAID            |BARD               |RAFT
FAWN               |ROOFED             |WOKS               |MOSS
FEUD               |METHODICAL         |RINK               |HAZE
HART               |WAIL               |DAZE               |PARS
GAPE               |NOTHINGNESS        |TOIL               |HOED
GASH               |JOLLIED            |PODS               |DOTE
HIPS               |AMPLER             |HUED               |TEAT
GALA               |MARS               |SACS               |GAGS
HAUL               |YOGA               |FOAL               |ROMP
HURL               |LUMPED             |SODA               |EAVE
JELL               |BEAD               |KILO               |SAPS
LARD               |SONOROUS           |DOER               |HOWL
LASH               |COLLABORATE        |NODS               |ROTE
LATH               |RAILED             |CABS               |GAPE
LINT               |SMALLPOX           |DUNE               |HENS
LONE               |LABORATORIES       |WOOS               |AMOK
MATH               |TOLLED             |FOES               |HOSE
MATS               |HELLISH            |TEED               |VEST
MAIM               |UNSKILLED          |GNAW               |INKY
LAVA               |RAGS               |CABS               |GALS
MALT               |FIELDED            |RIPE               |TITS
MUSH               |BULLDOG            |NODS               |PATE
MAMA               |BADE               |NAPE               |PARE
MAMA               |DABS               |PANS               |RAPS
MAMA               |DISSATISFACTION    |PIES               |RIGS
MAMA               |FADS               |RAPS               |TARS
MAMA               |FUSSED             |RUES               |TUGS
MAMA               |RAPS               |DABS               |FADS
MAMA               |RODENT             |DOPE               |FORE
MAMA               |TOSSED             |FOES               |HOGS
NAPE               |POROUS             |COGS               |COCK
OUCH               |BURLAP             |POTS               |NAPE
OUST               |FOLLIES            |TIDE               |RUTS
LAIR               |COWBOY             |NOES               |ROOK
PAIL               |GELD               |VETO               |REDS
LIEU               |EMIGRANT           |PUMA               |TEEM
PANS               |SURLIER            |HUED               |DUET
PAPA               |EELS               |TEAS               |PEWS
PAPA               |HARSHER            |WAGS               |SACS
OKRA               |MONSOON            |AYES               |YEWS
PARE               |QUIVER             |FUZZ               |BURR
OXEN               |SHIFTIER           |GEMS               |EKES
MART               |FAILINGS           |RAZE               |TARS
PEPS               |HAPLESS            |WEED               |SWAT
PACT               |HECKLE             |WEED               |SEAR
MASH               |DOLL               |PODS               |ROTE
MASH               |FOLLIES            |RODS               |TOTE
PREY               |GROCER             |VISA               |RAKE
PUMA               |DUDS               |SOPS               |OARS
PUMA               |GOSSAMER           |VIES               |RUGS
QUAY               |RUNGS              |HONE               |BANI
RAYS               |CANKER             |TALC               |LAPS
PAWN               |SORRIER            |HONE               |DOVE
PAWN               |WORRISOME          |LONE               |HOVE
RUNE               |JOYOUS             |AILS               |SULK
RUNT               |QUARANTINE         |HONK               |ZANY
PEAL               |PREHISTORIC        |EVES               |ANEW
PEEK               |SERUM              |HIVE               |DANK
RUED               |SUPPER             |JOTS               |BALM
SNUB               |DRYS               |VEST               |LEER
SASH               |VOLLEY             |NODS               |DOTE
SNAP               |UNREAL             |MART               |CARP
SAUNA              |DEXTERITY          |VERGE              |LEDGE
TOOT               |HOTLY              |ACHE               |OAFS
TANS               |MEALIER            |FEND               |TENT
TUNA               |MOOS               |FIBS               |TUBS
TUNA               |WORSEN             |PIES               |DUES
TART               |MAILBOXES          |FAZE               |TARS
TOTS               |HILLBILLIES        |AWED               |OUST
TONG               |AIRY               |TWEE               |HUES
VENT               |BEFALL             |WIST               |GASH
WAXY               |LEPROSY            |HEMP               |PEST
WANE               |XENOPHOBIA         |TEAS               |BEAK
WANNA              |LAIRS              |HAVES              |PAVES
YUCK               |FUTURES            |DOVE               |HARK
VATS               |MULL               |HUED               |RUST
YARN               |FAIRIES            |DAZE               |HARE
WAFT               |HAUL               |DAZE               |LAPS

Usé english-words.35 de esta lista de palabras . También me limité a palabras de 4 letras o más. Puedes usar un diccionario más grande para obtener más resultados.

Aquí está el programa para forzar la lista bruta.

//Program.cs - Runs the Vigenere brute forcer and displays the result.
using System;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
using System.Linq;

namespace Sandbox_Console
{
    class Program
    {
        public static void Main()
        {
            Stopwatch runtime = new Stopwatch();
            runtime.Start();


            var vigenere = new Vigenere(@"C:\scowl\final\english-words.10", @"C:\scowl\final\english-words.20", @"C:\scowl\final\english-words.35",
            @"C:\scowl\final\english-words.40", @"C:\scowl\final\english-words.50", @"C:\scowl\final\english-words.55",
            @"C:\scowl\final\english-words.60", @"C:\scowl\final\american-words.10", @"C:\scowl\final\american-words.20",
            @"C:\scowl\final\american-words.35", @"C:\scowl\final\american-words.40", @"C:\scowl\final\american-words.50",
            @"C:\scowl\final\american-words.55", @"C:\scowl\final\american-words.60");

            Console.WriteLine("Wordlist size: {0:N0}", vigenere.WordListSize);

            //Console.WriteLine("{0,-19}|{1,-19}|{2,-19}|{3,-19}", "String", "Key", "Encrypted", "Decrypted");
            //Console.WriteLine("{0,-19}+{1,-19}+{2,-19}+{3,-19}", new String('-', 19), new String('-', 19), new String('-', 19), new String('-', 19));

            //vigenere.StartTest();
            vigenere.JibberishKeys();

            List<Vigenere.TwoStrings> resultsForFile = new List<Vigenere.TwoStrings>();

            foreach (var result in vigenere.Results.GetConsumingEnumerable())
            {
                //Console.WriteLine("{0,-19}|{1,-19}|{2,-19}|{3,-19}", result.Word, result.Key, Vigenere.Encrypt(result.Word, result.Key), Vigenere.Decrypt(result.Word, result.Key));
                resultsForFile.Add(result);

                ShowOnlyProgress(vigenere, resultsForFile.Count);
            }
            runtime.Stop();

            Console.WriteLine("Done in {0}", runtime.Elapsed);

            using (var sr = new StreamWriter("WordKeys.txt", false))
            {
                sr.WriteLine("Wordlist size: {0:N0}", vigenere.WordListSize);
                sr.WriteLine("Build time: {0}", runtime.Elapsed);

                sr.WriteLine("{0,-19}|{1,-19}|{2,-19}|{3,-19}", "String", "Key", "Encrypted", "Decrypted");
                sr.WriteLine("{0,-19}+{1,-19}+{2,-19}+{3,-19}", new String('-', 19), new String('-', 19), new String('-', 19), new String('-', 19));

                foreach (var result in resultsForFile.OrderBy(a => a.Word).ThenBy(a=> a.Key))
                {
                    sr.WriteLine("{0,-19}|{1,-19}|{2,-19}|{3,-19}", result.Word, result.Key, Vigenere.Encrypt(result.Word, result.Key), Vigenere.Decrypt(result.Word, result.Key));
                }
            }


            Console.ReadLine();

        }

        static public void ShowOnlyProgress(Vigenere vigenere, int count)
        {
            Console.CursorTop = 1;
            Console.CursorLeft = 0;
            Console.WriteLine("Processed Records: {0:N0}", vigenere.ProcessedRecords);
            Console.WriteLine("Found Pairs: {0:N0}", count);

        }
    }
}

.

//Vigenere.cs - Written by Scott Chamberlain
//Brute forces a Vingenere encryption to find pairs where S, the encrypted
// and decrypted output of S are English words.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Threading;

namespace Sandbox_Console
{
    class Vigenere
    {
        public Vigenere(params string[] wordLists)
        {
            _WordList = new HashSet<string>();

            foreach(var wordList in wordLists)
            {
                using (var wordListStream = new System.IO.StreamReader(wordList))
                {
                    string line;
                    while ((line = wordListStream.ReadLine()) != null)
                    {
                        line = line.ToUpperInvariant();
                        if(line.Contains('\'') == false //No Apostrophes
                           && line.Length >= 4) // Words 4 or longer.
                            _WordList.Add(Regex.Replace(line, "[^A-Z]", "")); //Replace all non letter chars then add to wordlist.
                    }
                }
            }


            //Create the Vigenère square


            Results = new BlockingCollection<TwoStrings>();
            ResultSeen = new ConcurrentDictionary<TwoStrings, object>();

            _processedRecords = 0;
        }

        const int ALPHABIT_SIZE = 26;
        const int LETTER_OFFSET = 'A';

        HashSet<string> _WordList;

        public int WordListSize { get { return _WordList.Count; } }


        static Lazy<char[,]> _CryptTable = new Lazy<char[,]>( () =>
            {
                var tmpTable = new char[ALPHABIT_SIZE, ALPHABIT_SIZE];

                for (int i = 0; i < ALPHABIT_SIZE; i++)
                {
                    for (int j = 0; j < ALPHABIT_SIZE; j++)
                    {
                        tmpTable[i, j] = (char)(((i + j) % ALPHABIT_SIZE) + LETTER_OFFSET);
                    }
                }

                return tmpTable;
            });

        static Lazy<char[,]> _DecryptTable = new Lazy<char[,]>( () =>
            {
                var tmpTable = new char[ALPHABIT_SIZE, ALPHABIT_SIZE];

                for (int i = 0; i < ALPHABIT_SIZE; i++)
                {
                    for (int j = 0; j < ALPHABIT_SIZE; j++)
                    {
                        int result = i - j;
                        if (result < 0)
                            result = ALPHABIT_SIZE + result;
                        tmpTable[i, j] = (char)(result + LETTER_OFFSET);
                    }
                }

                return tmpTable;
            });

        public BlockingCollection<TwoStrings> Results { get; private set; }

        public class TwoStrings : IEquatable<TwoStrings>
        {
            public TwoStrings(string word, string key)
            {
                this.Word = word;
                this.Key = key;
            }

            public string Word {get; private set;}
            public string Key {get; private set;}

            public bool Equals(TwoStrings other)
            {
                if (other == null)
                    return false;
                if (this.Word == other.Word)
                {
                    if (this.Key == other.Key)
                        return true;
                    else
                    {
                        //If the word is shorter than the key, only compare keys up to the length of the word.
                        var thisLen = this.Word.Length;
                        if (thisLen > this.Key.Length)
                            thisLen = this.Key.Length;

                        var otherLen = other.Word.Length;
                        if (otherLen > other.Word.Length)
                            otherLen = other.Key.Length;

                        return this.Key.Substring(0, thisLen) == other.Key.Substring(0, otherLen);
                    }
                }
                else
                {
                    return false;
                }
            }

            private int TrimmedKeyHashCode()
            {
                if (this.Key.Length <= this.Word.Length)
                    return this.Key.GetHashCode();
                else
                    return this.Key.Substring(0, this.Word.Length).GetHashCode();
            }

            public override bool  Equals(object obj)
            {
                return this.Equals(obj as TwoStrings);
            }

            public override int GetHashCode()
            {
                //Use unchecked to suppress arithmetic overflow exceptions
                unchecked
                {
                    return 7 +
                        (this.Word.GetHashCode() * 11) +
                        (TrimmedKeyHashCode() * 13);
                }
            }
}

        public ConcurrentDictionary<TwoStrings, object> ResultSeen;

        private int _processedRecords;

        public int ProcessedRecords { get { return _processedRecords; } }

        public void StartTest()
        {
            Task.Factory.StartNew(() =>
                {
                    Parallel.ForEach(_WordList, TestWord);
                    Results.CompleteAdding();
                }, TaskCreationOptions.LongRunning);

        }

        private void TestWord(string word)
        {
            foreach (string key in _WordList)
            {
                if (_WordList.Contains(Encrypt(word, key)) && 
                    _WordList.Contains(Decrypt(word, key)))
                {
                    var testResult = new TwoStrings(word, key);
                    if(ResultSeen.TryAdd(testResult, null) == true) //Check that we don't have a similar key already.
                        Results.Add(testResult);
                }
            }
            Interlocked.Increment(ref _processedRecords);
        }
        public static string Encrypt(string word, string key)
        {
            int keyLength = key.Length;
            StringBuilder sb = new StringBuilder(word);
            for (int i = 0; i < sb.Length; i++)
            {
                sb[i] = _CryptTable.Value[key[i % keyLength] - LETTER_OFFSET, sb[i] - LETTER_OFFSET];
            }
            return sb.ToString();
        }

        public static string Decrypt(string word, string key)
        {
            int keyLength = key.Length;
            StringBuilder sb = new StringBuilder(word);
            for (int i = 0; i < sb.Length; i++)
            {
                sb[i] = _DecryptTable.Value[key[i % keyLength] - LETTER_OFFSET, sb[i] - LETTER_OFFSET];
            }
            return sb.ToString();
        }


        //does the same as TestWord but the key does not need to be in the dictionary.
        public void JibberishKeys()
        {
            Task.Factory.StartNew(() =>
            {
                Parallel.ForEach(_WordList, TestJibberish);
                Results.CompleteAdding();
            }, TaskCreationOptions.LongRunning);
        }

        private void TestJibberish(string word)
        {
            HashSet<string> keyList = new HashSet<string>();

            //Build the list of all possible keys;
            foreach (var keyGenWord in _WordList)
            {
                //Prevent a key of "AAAAA"
                if (keyGenWord != word)
                {
                    //Due to the behavior of the table
                    //"word == Decrypt(encryptedWord, key)" and "key == Decrypt(word, EncryptedWord)" are both true.
                    keyList.Add(Decrypt(word, keyGenWord));
                }
            }

            foreach (string key in keyList)
            {
                //We don't need to check the wordlist for the encrypted version as that word is what generated
                // the key in the first place.
                if (_WordList.Contains(Decrypt(word, key)))
                {
                    var testResult = new TwoStrings(word, key);
                    if (ResultSeen.TryAdd(testResult, null) == true) //Check that we don't have a similar key already.
                        Results.Add(testResult);
                }
            }

            Interlocked.Increment(ref _processedRecords);
        }

    }
}
    
respondido por el Scott Chamberlain 16.10.2012 - 16:21
fuente
2

Si está buscando una forma simple y novedosa de hacer esto, ¿por qué no asigna un valor entero a cada palabra w , y cada palabra m en el mensaje un valor entero, luego las asigna en función del ¿llave? Siempre que su mapeo w <==> m no exceda los límites de los grupos de palabras (por ejemplo, sustantivos, pronombres, verbos, adjetivos, etc., se asignen al mismo grupo) y sus conjuntivos estén mapeados adecuadamente, es posible que pueda producir oraciones semi legibles como su texto cifrado. La asignación podría generarse fácilmente si se agrega un PRNG con su valor clave.

Suponiendo que no te importa filtrar la estructura gramatical de tu texto sin formato, y que tu mapeo w <==> m es uniforme y aleatorio dentro de los grupos, en realidad tienes un nivel de seguridad razonable para grandes plaintexts.

Desde luego, no usaría esa cifra para nada importante, pero sería muy interesante ver los tipos de texto cifrado que podrías producir.

    
respondido por el Polynomial 16.10.2012 - 01:22
fuente
1

Hay una solución trivial de usar una clave que es todo As. Como una A en el cifrado Vigenère sustituye cada letra por sí misma, esto simplemente le dará la misma cadena S sin importar cuántas veces descifre o cifre. Pero supongo que eso no es lo que estás buscando.

El primer problema ("una cadena S que, si se cifra con un cifrado Vigenère con clave K, obtiene una declaración / palabra en inglés que tiene sentido") es fácil de resolver. Si usa una cadena S que tiene la misma longitud o es más corta que su clave K, entonces para cualquier S y texto cifrado C puede calcular fácilmente una K para la cual la S cifrada es C. Por ejemplo, digamos que su S es PERSONAS y su C es CIPHER, entonces puede elegir K = JEBSSV. Esto se hace simplemente invirtiendo el cifrado Vigenère.

El segundo problema ("si la misma cadena S se descifra con el cifrado Vigenère y nuevamente con la misma clave K, obtiene otra declaración / palabra en inglés que también tiene sentido") también es fácil de resolver por sí mismo, por elegir dos cadenas inglesas para las cuales el Alfabeto distancia entre la letra en una cadena y la letra equivalente en otra cadena es par (por ejemplo, 'A' y 'C' pero no 'A' y 'D') y construir una clave que sea La mitad de la distancia entre las letras. Puede hacerlo fácilmente usando solo letras impares (es decir, A, C, E, G, I, K, etc.). Por lo tanto, si S está ENFERMO y desea que la cadena descifrada dos veces sea MICE, obtendrá una clave de DAAD.

Resolver ambos problemas para el mismo K es menos trivial. Creo que la mejor manera de hacer esto sería la fuerza bruta. En otras palabras, elija alguna palabra / frase en inglés como S, elija Ks al azar y pruebe para cada K si el S cifrado y el S dos veces descifrado son frases en inglés. Para cadenas cortas S esto debería ser bastante rápido: alrededor del uno por ciento de las posibles cadenas de cuatro letras son palabras en inglés, por lo que en promedio encontrará una buena K después de haber intentado diez mil Ks. Cuanto más larga sea la cadena, más Ks necesitarás probar.

    
respondido por el David Wachtfogel 16.10.2012 - 10:01
fuente

Lea otras preguntas en las etiquetas