Entonces, enviamos a los agentes súper secretos Alice y Bob a un país enemigo encubierto. Durante la misión, deberán contactar y trabajar juntos, intercambiar información, asuntos de espionaje ordinarios. Por supuesto, todo esto debe hacerse de acuerdo con todas las reglas y procedimientos de seguridad posibles.
De hecho, en el último turno, queremos revelarlos: tanto la misión misma como los agentes mismos y toda la seguridad nacional están en riesgo. Por lo tanto, nos interesa brindar a los espías la información mínima necesaria. En particular, cuanto menos sepan unos de otros y las técnicas de comunicación, mejor.
Pero, ¿cómo identificarán entonces a su camarada de la sede?

TL; DR: inventar un mecanismo de autenticación de usuarios utilizando esteganografía para una agencia imaginaria de tres caracteres de un país inexistente.
Sobre lobos y pieles de oveja
Una tapa es una tapa, por lo que ni Alice ni Bob deberían despertar sospechas por ninguna de sus acciones. La planificación adecuada implica paranoia sobre el monitoreo constante de ellos en todos los niveles posibles. Esta publicación no abordará la tarea del intercambio directo de información (merece su propia serie separada), sino solo una forma de asegurarse de que sea transmitida por quienes la necesitan a quien la necesita.
Lo más probable es que ambos espías tengan una historia en el formato de ciudadanos comunes, además, de ninguna manera conectados entre sí. Por lo tanto, debe vetar de inmediato el uso de herramientas criptográficas clásicas y canales seguros: cada agente de contrainteligencia sabe que las personas honestas que no tienen una relación cercana no tienen nada que ocultar.
Que hacer
Por supuesto, tal tarea no es nueva, felizmente existió y se resolvió mucho antes del advenimiento de estos de su Internet. Y no solo se ha decidido, sino que algunas decisiones se han fortalecido en la cultura y todavía se encuentran en libros, películas y juegos.
Veamos una escena así: dos personas con abrigos largos convergen en un lugar público e intercambian frases muy extrañas. Si la frase inicial y la respuesta son correctas, la autenticación fue exitosa y las personas intercambian carpetas marcadas como "Top Secret" y divergen en direcciones desconocidas.
El inconveniente de tal esquema es inmediatamente obvio: las frases deben mantenerse en secreto y a menudo cambiarse , lo que no es muy simple en territorio enemigo. Al mismo tiempo, para no ser pronunciados por casualidad y no conducir al caso de KDPV, se vuelven bastante prominentes y aleatorios, lo que significa que pueden entregar agentes que los pronuncian.

A nosotros, en la era de la tecnología digital, no nos gusta este método. Especialmente si recuerdas que casi todos los canales de comunicación están controlados por alguien y se aprovechan tanto por motivos buenos como malos. Y no importa lo que nos aseguren, no se debe confiar en la vida de las personas en la política de privacidad de ningún Facebook.

Esteganografía (¿otra vez?)
Erizo, está claro que la capacidad de esconderse el uno al otro en tal situación parece más atractiva que nunca. Y, de hecho, incluso el método descrito es su subespecie: las frases de código se pueden considerar como contenedores con solo un poco de información dentro.
El mismo mamífero del destacamento insectívoro entiende que esto no se trata simplemente de lanzar stegocontainers entre sí. Tal intercambio causará casi más sospechas que algunos cifrados PGP comunes, por lo que no estamos interesados.
¿Qué hay de entonces?
A diferencia de los criptogramas, los stegocontenedores tienen una ventaja obvia: el contexto de la aplicación. Cualquier texto, imagen, archivo de audio, etc., además del contenido obvio, también conlleva la posibilidad de su discusión natural y puede enviarse no solo desde la bahía, sino en el proceso de un diálogo que no causa sospechas.
Armados con tales ideas, ya podemos elaborar un protocolo de autenticación esteganográfica simple basado en una clave común:
- A -> B: un bonito mensaje que solicita un contenedor esteganográfico de ciertos parámetros;
- B: selecciona el contenedor C que coincide con el contexto y los parámetros solicitados;
- B: de manera similar crea un mensaje M ;
- B -> A: C '= Incrustar (C, M, K) ;
- A: Verifica que C ' cumpla con los parámetros establecidos;
- A -> B: M '= Extracto (C', K) ;
- B: Comprueba si M y M ' coinciden.
Tal protocolo tiene inconvenientes obvios: Alice y Bob deben tener una clave común y funciones de incrustación y extracción. Su compromiso puede llevar a la posibilidad de un análisis detallado del método de autenticación del enemigo y poner en peligro tanto a otros usuarios como a la sede. Algo necesita ser arreglado.
El artista no es un error.
Si el lector fue a la escuela después del advenimiento de las clases de computación, entonces debería recordar haber aprendido los conceptos básicos de la algoritmización utilizando el personaje de una tortuga, una hormiga y similares. Su idea era demostrar las posibilidades de optimizar una gran cantidad de acciones individuales manuales mediante la creación de programas simples. Para resolver nuestro problema, debemos ir en la dirección opuesta.

Dado que podemos simplificar la escritura del algoritmo final desde la secuencia de pasos hasta su descripción de procedimiento de acuerdo con los parámetros dados, podemos llevar a cabo el proceso inverso. Si imagina un contenedor como una matriz de algunos de sus componentes, la incrustación de un mensaje por clave puede escribirse como una secuencia ordenada de operaciones en elementos del contenedor en índices específicos con varios parámetros constantes.
Aquí es donde comienza la no matemática, así que les pido a los tímidos que simplemente hojeen los párrafos difíciles de ver a la sección de operaciones o incluso un poco más. Nada terrible sucederá, lo prometo.
Para incrustar los datos, necesitamos una secuencia de la forma: (f1, S1, i, D1), (f2, S2, j, D2) ... , donde:
- Di - alguna parte de los datos incrustados;
- i, j son los índices de los elementos del contenedor;
- fi: (Estado, Elemento, D) -> (Estado, Elemento) - función de inserción;
- Si es un cierto estado, el contexto de la operación, (El ', S [i + 1]) = fi (Si, El, Di) .
Para extraerlo, no necesita almacenar partes de los datos (K.O.), por lo tanto, hay suficientes triples: (g1, S1, I1), (g2, S2, I2) ... con los mismos valores, solo gi: (Estado, Elemento) -> (Estado, D) .
Todo esto puede ser representado por el siguiente diagrama simétrico. Si por alguna razón no logré alcanzar la claridad, entonces no da miedo, solo sigue leyendo.

Se puede ver que la función de incrustación tiene un mayor número de grados de libertad. A diferencia de su hermana, ella modifica el contenedor, mientras lo hace sobre la base de dos elementos independientes: los datos incrustados y el elemento. Gracias o, más precisamente, debido a esto, son posibles dos enfoques globales para la implementación del algoritmo de esteganografía por parte de dicho sistema:
- Elija los índices más apropiados de los elementos para cambiar de acuerdo con la función de incrustación (menos notable o que no lo requiera) y transfiera la secuencia formada vinculada a un contenedor específico. Con este enfoque, deben aislarse unos de otros antes de que surja la necesidad de incorporarlos utilizando métodos clásicos como el cifrado y otros medios seguros;
- Encuentre un método para dividir el contenedor en elementos y la función de incrustación para que cualquier cambio esperado sea igualmente invisible. En este caso, la secuencia es independiente del contenedor y puede crearse incluso mediante un generador completamente aleatorio. Menos flexibilidad y falta de control del peor de los casos. Por otro lado, este enfoque es más simple y más conveniente cuando se aplica en el campo, por lo que a continuación lo usaré.
Si el algoritmo no requiere el estado, todo lo anterior sigue siendo válido, simplemente sin una sola letra y bloque en el diagrama. Sin ella, es incluso más fácil, en realidad.
¿Y por qué lo necesitamos?
Ahora, si sabe de antemano qué contenedores con qué mensajes y claves se utilizarán, en lugar de revelar completamente las partes del algoritmo, puede generar y dar agentes para usar solo tales secuencias y un intérprete para ellas. Bueno, ok, no solo dando, por supuesto, sino más sobre eso más tarde.
Añadir asimetría
Incluso un artista de tortugas puede dibujar un cuadrado de cientos de formas diferentes, simplemente cambiando el orden de las operaciones y agregando otras nuevas. Esto significa que nadie nos molesta y hace lo mismo con las secuencias descritas para los datos de entrada fijos.
Es decir, podemos tomar la secuencia de incrustación, agregar nuevas operaciones, mezclar todo y así el resultado sigue siendo el mismo. A menos que, en presencia de un estado, sea necesario rastrearlo y agregar por separado los cambios necesarios a la secuencia. Por eso sin eso es más fácil, sí.
De una forma u otra, después de tal amasado y ruidoso, incluso el mismo integrador ya no podrá entender lo que realmente está incorporando: ¡cualquier secuencia de N operaciones representará N! mensajes potencialmente incrustados: uno para cada permutación de las partes incrustadas. Al mismo tiempo, N en sí es una gran pregunta. Por lo tanto, uno puede llamar a tales secuencias abiertas: no proporcionan ninguna información sobre el mensaje incrustado, ni sobre el algoritmo y la clave utilizados.
Al extraer información, es muy importante para nosotros tanto el orden (restaurar el mismo mensaje correcto de todos los posibles) como el número de partes a extraer, para que las secuencias de extracción permanezcan sin cambios desde el momento del nacimiento. Dado que implícitamente contienen información sobre la clave, el generador y el algoritmo utilizados, ellos, como los animales del libro rojo, deben almacenarse y protegerse. Y mantenlo en secreto.
¿Qué tiene que ver la asimetría con ella? El hecho es que ahora cada secuencia de extracción está asociada con un número infinito de integradores. Y restaurar uno del otro es, en el caso general, una tarea insoluble.
Estamos operando
Nos olvidamos de cualquier matemática cercana y volvemos a la tarea original: ¿cómo podemos enviar a Alice y Bob al territorio enemigo para:
- no se conocían las caras
- no tenía algoritmos secretos a mano
- pero, ¿podrían verificarse mutuamente mientras se comunican en un canal abierto?
Bueno, con el primer párrafo todo está claro, simplemente no les damos ninguna información explícita el uno del otro, ni claves compartidas. Para el segundo, debe recordar la descripción del protocolo anterior. Ahora podemos excluir directamente los algoritmos de Incrustar y Extraer que representan posibles secretos de estado y todo eso. Y, teniendo esto en cuenta, para el tercero es posible elaborar el siguiente protocolo de dos etapas.
Generación de información de autenticación antes del inicio de la misión con la sede como parte confiable de Trent:
- T: selecciona el algoritmo secreto y la clave secreta K, crea con su ayuda:
- Extraer secuencia Ex ;
- adecuado para autenticación (abajo) contexto Ctx ;
- T -> A: Ctx, Ex ;
- T: usando Ex y el contexto creado, genera:
- mensaje M no utilizado previamente para los agentes seleccionados entre las partes | Ex | ;
- una secuencia única de Em , que se abre como se describe anteriormente;
- T -> B: Em, h (M) , si lo desea, crea conjuntos adicionales.
Por lo tanto, Alice solo tiene una secuencia para todas las ocasiones y el contexto de contacto futuro, y Bob se convierte en el feliz propietario de un conjunto de secuencias únicas y mensajes hash que incrustan.
El protocolo de autenticación ya durante la misión se ve así:
- A -> B: un mensaje de MI de inicio basado en el contexto Ctx con una descripción del contenedor;
- B: selecciona el C ~ IM apropiado;
- B -> A: C '= Em (C) ;
- A: verifica el cumplimiento de C '~ IM (dado que los cambios son invisibles, debe guardarse);
- A -> B: M '= Ex (C') , marca M 'como se usa;
- B: controles, h (M ') == h (M) , destruye Em, h (M) .
Un lector atento notará que antes del protocolo, Alice y Bob tienen solo un conjunto de información, que en sí mismo no significa nada para ellos, ni para un posible adversario, y solo durante el "juego con los colores".
Cada conjunto abierto de Bob se usa solo una vez, que está controlado por el penúltimo paso de Alice. Cuando se encuentra con una M previamente utilizada (y, por lo tanto, Em invisible por ella) por otra persona, se da cuenta de que uno de sus "asociados" es falso.
La reutilización por parte de la misma persona le dice que ella no está al tanto de las complejidades del protocolo y que ciertamente no es con quien necesitaba ponerse en contacto. Bueno, más vale tarde que nunca.

De acuerdo, así es como todo parece demasiado complicado e incomprensible. ¿Alguien ha llegado aquí?
Vamos a demostrarlo mejor en la práctica, porque incluso los propios espías no necesitan conocer los detalles del protocolo para su uso, y mucho menos para los lectores pobres. Solo al principio un poco sobre cómo se implementó todo.
Alta tecnología
Por lo tanto, solo queda escribir todo lo necesario para el protocolo. Bueno, no haces todo con tus manos (aunque puedes). Y hoy la víctima de mi código será ... girando la rueda de la fortuna ... ¿Java? Bueno, está bien, al mismo tiempo que todo en STL estará, no tendrás que buscar nada.
Comencemos con la API requerida. Para trabajar, solo necesita determinar la clase de la matriz de elementos contenedores con la capacidad de recibir y cambiar elementos por índice:
class MyContainer implements StegoContainer<MyElement> { public MyElement get(int i) {
El uso adicional se reduce a crear una envoltura de un autómata esteganográfico sobre el contenedor necesario y proporcionar las funciones de incrustar y extraer a su entrada:
StegoMachine<MyState, MyElement> myMachine = new StegoMachine( initialState, new MyContainer<MyElement>() ); final StegoEmbed myEmbed = (st, el, dp) -> {
Las clases con el sufijo Sin estado se usan de la misma manera, si la implementación del algoritmo no requiere mantener el estado interno.
Los generadores de secuencia pueden funcionar como desee y no tienen una API común. En el caso general, cualquier cosa puede ser parte de los datos en general, desde bits solitarios hasta arte rupestre en una codificación separada.
Ejemplo de implementación
Acerca de Método
Como ejemplo de implementación, utilizando las interfaces creadas, implementé un algoritmo simple de la familia LSB para imágenes de mapa de bits con compresión sin pérdidas. Sus elementos son píxeles que no tienen vecinos en el bit menos significativo de todos los componentes RGB. La función de incrustación funciona con bits individuales de los datos de origen y simplemente cambia el bit de orden inferior del valor de uno de los componentes (a qué índice apuntará).
Es bastante simple, pero es excelente para implementar el protocolo, ya que cambiar cualquier elemento es igualmente imperceptible según su elección, por lo que los índices de los elementos que se van a cambiar se generan utilizando un generador aleatorio. En el caso de Java, usando SecureRandom , pero si lo desea, cambia fácilmente a su fuente de entropía.
Sin embargo, este es un método muy simple, no recomiendo usarlo para espías reales.
Sobre hashes
Dado que el texto tiende a distorsionarse dependiendo de la personalidad simulada del agente (algunos no ponen letras mayúsculas, a otros les gusta poner emoticones, etc., otros generalmente son analfabetos), sugiero usar sha256 para calcular el hash, pero solo a partir de palabras impresas en minúsculas:
h("Hello world?...") == h("hello, world!11")
Acerca de la interfaz
El paquete de software consta de dos partes: una para generar secuencias y otras funciones hash para Trent, la otra para incrustar y verificar el cumplimiento de los mensajes recibidos.
El trabajo con ambos ocurre desde la línea de comandos a través de sus argumentos y flujos de entrada-salida; no se entregaron otras interfaces (miedo y horror). Aún así, ser ese empleado de la sede, que el espía significa tener algún tipo de calificación. Bueno, si no, aún mostraré un ejemplo.
¿Qué hacen todos?
Para empezar, Trent en la sede central necesita obtener información de autenticación. En particular, pensar de antemano una situación en la que los agentes trabajarán.
Por ejemplo, deje que Bob sea un profesional independiente de gráficos y Alice su cliente. La autenticación se realizará bajo la apariencia de una orden para crear gráficos / diseño / algo más.
Reportamos esta información útil a ambos y volvemos al protocolo en sí. Prepararemos un mensaje incrustado M.txt adecuado de antemano , minimizando la cantidad de caracteres que contiene : "me conviene dónde transferir dinero". Genere Em y Ex usando la utilidad para Trent:
Trent@HQWorkstation:~$ java -jar HQUtil.jar -ex $(stat -c%s "M.txt") 4096 > Ex.txt Trent@HQWorkstation:~$ cat Ex.txt | java -jar HQUtil.jar -em "$(cat M.txt)" 0.25 4096 > Em.txt Trent@HQWorkstation:~$ cat M.txt | java -jar HQUtil.jar -h > hash.bin
Aquí $(stat -c%s "M.txt")
devuelve el tamaño del mensaje en bytes, y 4096 - la restricción en el rango de índices generados (para permitir el uso de contenedores más pequeños). De manera similar, $(cat M.txt)
usa para pasar el mensaje al parámetro de la línea de comando. En principio, puede prescindir de la fiesta, utilizando su propio trabajo manual, pero para quién es más conveniente.
Ex.txt se pasa a Alice, Em.txt y hash.bin a Bob. Ahora imagine que los agentes se han desplegado con éxito y desean comunicarse entre sí; procedemos a la ejecución del protocolo. Bob coloca su currículum u oferta de trabajo en algún intercambio, y Alice comienza a comunicarse:
: , %_% : , . ? : ,
Bob busca la imagen de un paraguas, tal vez incluso la dibuja él mismo, si el alma es creativa, comprime / impone un poco una marca de agua (o lo que los freelancers están haciendo allí ahora) y hace:
Bob@PC:~$ cat Em.txt | java -jar SpyUtil.jar -e umbrella.png
Después de esperar un tiempo, pretendiendo trabajar, si en realidad no lo hizo, le envía a Alice el contenedor recibido, naturalmente, teniendo en cuenta el contexto:
: , ,
Transmite un paraguas con un mensaje, 670kb Eso, a su vez, recupera el mensaje almacenado internamente:
Alice@PC:~$ cat Ex.txt | java -jar SpyUtil.jar -e umbrella.png
Convierte un conjunto de palabras en una oración normal y se lo envía a Bob:
: , , ?
Comprueba la precisión del mensaje:
Bob@PC:~$ java -jar SpyUtil.jar -c hash.bin ", , ?" , , ? - Correct
Y continúa la comunicación fácil, si todo está bien. Todo el diálogo por parte del observador se ve así:
Está claro que la contrainteligencia no encontrará nada sospechoso en todo esto interceptado. De hecho, incluso los métodos de estegoanálisis en este caso no siempre se aplicarán; bueno, alguien ordenó una imagen de un paraguas por 5 dólares y encontraron algo con lo que sorprender Internet. Los recursos informáticos y las personas no son infinitos para verificar cada situación. La autenticación fue exitosa, el telón.
-> github