Generando números aleatorios en Arduino

Arduino tiene una función random que genera números pseudoaleatorios, pero si queremos generar números aleatorios de verdad hemos de recurrir a algún tipo de generador físico ya que programando nunca podremos conseguir números realmente aleatorios.

analogRead

Generalmente cuando buscas una manera de generar números aleatorios con arduino te aconsejan recurrir a leer el valor puerto analógico que no este conectado a nada El problema es que realmente los valores obtenidos no son aleatorios. Suelen oscilar en torno a un valor sin alejarse demasiado de él. Es decir si el valor es el 150 es más probable que el siguiente número sea el 151 o el 149 que el 3 (en mis pruebas nunca he visto un  salto tan grande de valor). Cómo generador de números aleatorios no solo no es ninguna maravilla, es que es peor que el generador de números pseudoaleatorios.

Cómo solución se suele proponer usar el valor leído como semilla para la función random, lo malo de esto es que acaban siendo otra vez números pseudoaleatorios.

Hay montajes electrónicos que producen valores aleatorios a partir del ruido que sufren los componentes electrónicos, pero suelen ser complicados. Además ya no sería con un arduino y tengo que justificar que el articulo este en la sección de “arduino”.

Volviendo a nuestra idea de leer valores del puerto analógico vemos que el problema es que los números que devuelven oscilan entorno a un valor así que no podemos usar ese número como aleatorio, pero si una parte pequeña de él. El bit de menor peso. Vamos a tomar solo este bit y con ocho de ellos componer un byte. Ese byte debería ser aleatorio.


byte randomAnalog(int analogInput){
  byte rnd = 0;
  for(int i = 0; i < 8; i++){
    int aux = analogRead(analogInput)%2 << i; rnd += aux;
    delay(10);
  }
  return rnd;
}

Para aumentar el ruido se puede conectar un cable suelto en el  puerto que se va a leer, contra más largo y retorcido esté mejor, Por raro que suene si se mueve el cable o el arduino los números leídos del puerto analógico aun varían más.

Combinar varias fuentes

Si te fías poco puedes usar dos fuentes de aleatoriedad obteniendo bytes de dos puertos analógicos distintos y luego combinándolos con un xor.


byte r0 = randomAnalog(A0);
byte r1 = randomAnalog(A1);

byte r = r1 ^ r0;

Puede encontrar el código en el repositorio de github de ArduTips.

Un posible mejora es asegurarse de que el generar de números aleatorio es justo, es decir produce 0 o 1 con un 50% de probabilidades. Se puede leer aquí.

Cifrado seguro en Arduino

Parece imposible cifrar de forma segura en un arduino con una potencia de cálculo equiparable a la de un despertador. Pero eso es porque siempre que se habla de cifrado se acaba hablando de complicados algoritmos matemáticos, sin embargo se puede lograr un cifrado perfectamente seguro usando operaciones matemáticas más simples. Os presento la forma de cifrado más simple.

Cifrar:

Ci = Mi xor Ki

Descifrar:

Mi = Ci xor Ki

Una simple operación xor de un byte del mensaje M con un byte de la contraseña de cifrado K. Os estaréis preguntando que si es tan seguro por qué no lo usamos en lugar de complicados algoritmos. Bueno tiene una pega, la contraseña ha de ser completamente aleatoria (o en su defecto lo más aleatoria posible) y ambos han de tener la misma longitud. Este sistema se conoce como libreta de un solo uso. Su nombre no es caprichoso, usar la misma contraseña de cifrado más de una vez para cifrar otro mensaje compromete la seguridad del sistema.


//Cifrar
C[i] = M[i] ^ K[i+j]; // j es el punto del cuaderno usado hasta la fecha.

//Descifrar
M[i] = C[i] ^ K[i+j]; // j es el punto del cuaderno usado hasta la fecha.

El problema de generar la larguísima "libreta" para cifrar lo dejo en vuestras manos. Podéis usar un generador en cualquier lenguaje, comprar números aleatorios, escribir en papelitos un montón de números tirarlos a aire y apuntarlos según se recogen...hay infinitas posibilidades y contra menos predecible sea el sistema usado, mejor. De hecho esa es su principal vulnerabilidad que la secuencia usada sea predecible.

Con esa larga secuencia de bytes usados para cifrar ya conseguida. El siguiente paso es cifrar lo que se quiera enviar. Para ello se toma un byte de datos y un byte de la "libreta", se realiza un xor entre ambos y listo. Es sencillo y el coste computacional es mínimo.  Los byte de la libreta siempre se cogen de forma secuencial sin nunca repetirlos pase lo que pase.

Por supuesto todos los dispositivos que participan en la conversación tienen que tener una copia de la contraseña. Que se les ha tenido que "entregar" de forma segura (conectadolos con un cable o con una tarjeta SD) eso significa que el acceso físico a uno de estos dispositivos compromete la seguridad del cifrado (como con casi todos los sistemas). También es necesario incluir en el mensaje un numero de secuencia que indique a partir de que punto de la "libreta" usar para descifrar.

Para intentar agotar la "libreta" lo más tarde posible hay que procurar no cifrar datos innecesarios. Por otro lado, en algunos casos es necesario cifrar algún tipo de contador para votar ataques de repetición. Es posible que en algunos casos necesitemos "libretas" grandes por lo que habrá que ampliar la capacidad de almacenamiento del dispositivo por ejemplo montando un lector de tarjetas microSD con eso podemos tener espacio para una "libreta" que nos dure siglos y sale más barato que recurrir a otro tipo de soluciones.

En caso de terminar con la "libreta" hay que evitar reutilizarla. Podemos hacer un truco para tratar de alargar su utilidad. Aunque este truco no nos asegura que el cifrado vuelva a ser completamente seguro. El truco consiste en aplicar dos tipos de operaciones a la clave:

  • Intercambiar posiciones de los caracteres
  • A cada carácter aplicarle rotaciones de bits, negaciones o xor. Mejor si se combinan varias de  ellas.

Es buena idea no realizar exactamente las mismas operaciones en cada carácter si no variarlas siguiendo un patrón lo mas grande posible carácter. Estás operaciones han de conocerse por todos los dispositivos que participan en la comunicación ya que si no obtendrán "libretas" distintas.

Con eso la libreta obtenida no es segura ni mucho menos, y lo correcto seria cambiarla, pero es mejor opción que reutilizarla directamente. Como ventaja está de nuestra parte que este tipo de dispositivos suelen transferir pocos datos así que hasta que el atacante consiga una cantidad suficiente de datos como para descifrar nuestros mensajaes puede tardar mucho tiempo. Del orden de semanas, meses o años.