Para aclarar las explicaciones, supongamos que se trata de algún tipo de almacenamiento distribuido donde un mensaje sería
"¿Quién tiene el archivo A? Por favor, envíamelo. "
y el nodo con archivo lo enviaría al remitente. Desea proteger el mensaje para que los dispositivos fuera de su red no puedan recuperar el contenido de su red o alterarlo.
La marca de tiempo no es una solución completa por sí misma, ya que, por definición, habrá una ventana (aunque sea pequeña) en la que se debe aceptar el mensaje. Los otros nodos deben verificar que "ahora" no sea posterior a X tiempo después de su generación, pero X será distinto de cero (para que pueda llegar el mensaje real).
[Hay otro tipo de problemas para mantener los relojes sincronizados en una red distribuida, lo que requerirá un margen adicional en el campo]
El mensaje con marca de tiempo sería “Es $ DATE. ¿Quién tiene el archivo A? Por favor, envíamelo. ”Simplemente agregar un HMAC al mensaje no lo protegería realmente.
Dentro de esa pequeña ventana de tiempo, otro nodo también podría enviar
"Es $ FECHA. ¿Quién tiene el archivo A? Por favor, envíamelo. "
(copiando el mismo HMAC), así que claramente no es suficiente.
Sin embargo, si está incluyendo quién está en el cálculo, es diferente (podría agregarse implícitamente, o simplemente declararlo en el mensaje): "Es $ DATE. Estoy 10.10.10.10. ¿Quién tiene el archivo A? Por favor, envíelo al 10.10.10.10 en el puerto 9000. "
Aún así, también debes proteger la respuesta para que tu respuesta provenga de un nodo malvado. Por ejemplo, la comunicación en el puerto 9000 podría comenzar con:
“Tengo 10.10.10.12 conectando a 10.10.10.10. Tengo el archivo A que pidió a $ DATE. Tiene 123 bytes de largo y tiene SHA256 aabbccdd ... "|| HMAC
Si el nodo no solicitó el archivo A a las $ DATE, o el contenido del archivo no coincide con el hash dado, debería descartar lo que recibió.
Un atacante podría duplicar la solicitud (o la red podría duplicarla), lo que podría hacer que 10.10.10.12 envíe la misma información a 10.10.10.10 muchas veces. Podría filtrarlo según el encabezado de solicitud que se muestra arriba, pero es mejor proporcionar un identificador para diferenciar las respuestas duplicadas, para responder a una consulta repetida (por ejemplo, el nodo de consulta puede leer el mismo archivo continuamente, porque cambiará en breve ).
“Esta es la consulta 987654 en $ DATE. Estoy 10.10.10.10. ¿Quién tiene el archivo A? Por favor, envíelo al 10.10.10.10 en el puerto 9000. "|| HMAC
El nodo de consulta simplemente necesitaría recordar las consultas enviadas en el último período de tiempo de 2 * X aproximadamente, y marcar como En curso / Completado según sea necesario. Cualquier respuesta que no coincida con una consulta pendiente podría ser descartada.
(Preferiblemente, el identificador sería aleatorio, aunque el HMAC lo protege de la falsificación de respuestas)
En este punto, la integridad de los mensajes está protegida por el secreto HMAC, y usted está protegido contra las repeticiones, puede enviar las consultas en transmisión con bastante confianza.
Sin embargo, debo tener en cuenta que su red se basa en un secreto compartido entre los nodos. ¿Qué pasaría si uno de ellos estuviera comprometido?
Un enfoque más robusto sería usar claves asimétricas en cada nodo. Básicamente, usted crea claves para cada nodo y una CA local que firma cada uno de ellos. Almacene en los nodos una copia de la clave pública de la CA y una lista de revocación, inicialmente vacía.
Modifique los mensajes anteriores para reemplazar la operación HMAC(message, secret)
con SIGN(message) || MyPublicKey
, y haga que sus nodos confíen en el mensaje si viene firmado correctamente por una clave firmada por su CA local, y no en la lista de revocaciones.
(Puede ignorar la lista de revocaciones si prefiere reemplazar la CA, y las claves públicas firmadas por ella, en caso de que se haya comprometido una clave)