Si uno llama random() no sirve, ya que el (pseudo) azar, da siempre la misma secuencia. Eso en sí no está mal, si uno está haciendo un juego o una simulación y quiere testear componentes que usen azar, lo bueno sería que ese azar sea el mismo en cada ejecución de un mismo unit test.
Luego en producción, hay que darle una semilla para que arranque en algún lugar distinto de la secuencia.
En basic creo recordar (no pienso mirar en google) que era randomize(). En opencobol, que es justo con lo que estaba haciendo las pruebas es random(valor) para cambiar la semilla y random() para obtener el valor al azar.
Esa semilla suele ser tomada de la fecha/hora, lo cual no es muy bueno:
A lo largo de todo el año hay 365x24x60x1000 = 31.536.000.000, ok.
Pero como más o menos se puede saber el día y quizas la hora se reduce a 60x60x1000=3.600.000, no tan ok.
Y si más o menos sabés el minuto 2x60x1000=120.000, mucho menos ok.
Dependiendo del escenario, algunos ataques serían factibles. Por lo general los online no, ya que hay otras medidas de control, por ejemplo no aceptar más que un cierto número de conexiones en un lapso determinado desde una misma IP.
Si a eso se le suma que el token tiene un tiempo de vida y está correctamente calculado según el número de conexiones y el tiempo por IP, está mitigado.
Pero si el ataque es offline o no disponemos de mecanismos adicionales, estamos en el horno.
Podemos agregar un "secreto" a este número y recuperamos la fortaleza inicial, ¿no? Salvo que ese secreto forma parte del código y aunque no compartimos ni descuidamos el código, damos por sentado que está comprometido.
A falta de un mainframe, he aquí una implementación en linux con opencobol que usa los "milisegundos" como semilla.
IDENTIFICATION DIVISION. PROGRAM-ID. principal. ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. 01 SEED PIC 9(08). 01 WS-TIME. 03 DUMMY PIC 9(06). 03 MILLISECONDS PIC 99. 01 IDX PIC 9. 01 RVALUE PIC 9(09) COMP-3. PROCEDURE DIVISION. PROGRAM-BEGIN. DISPLAY "Generando random sin seed...". PERFORM VARYING IDX FROM 1 BY 1 UNTIL IDX = 5 COMPUTE RVALUE = FUNCTION RANDOM * 1000000000 DISPLAY RVALUE END-PERFORM. DISPLAY "Generando random con seed...". ACCEPT WS-TIME FROM TIME. MOVE MILLISECONDS TO SEED(1:2). ACCEPT WS-TIME FROM TIME. MOVE MILLISECONDS TO SEED(3:2). ACCEPT WS-TIME FROM TIME. MOVE MILLISECONDS TO SEED(5:2). ACCEPT WS-TIME FROM TIME. MOVE MILLISECONDS TO SEED(7:2). COMPUTE RVALUE = FUNCTION RANDOM(SEED). PERFORM VARYING IDX FROM 1 BY 1 UNTIL IDX = 5 COMPUTE RVALUE = FUNCTION RANDOM * 1000000000 DISPLAY RVALUE END-PERFORM. PROGRAM-DONE. STOP RUN.
Ejemplo de ejecuciones sucesivas, obsérvese el patrón de repeticiones en amarillo:
?> make && ./principal Generando random sin seed... 180428938 846930886 168169277 171463691 Generando random con seed... 146627632 119773096 977866279 695807865 ?>./principal Generando random sin seed... 180428938 846930886 168169277 171463691 Generando random con seed... 169097225 730835526 213552898 116350005 ?> ./principal Generando random sin seed... 180428938 846930886 168169277 171463691 Generando random con seed... 395357036 623986740 139161360 104338109
La mejor solución es un auténtico random, que en cobol en mainframe se obtiene accediendo a la placa criptográfica, si la hay.
Como poder usar un mainframe no suele ser sencillo, ¿qué tal un microcontrolador? Es más barato y entra en una mano.
Hay un juego muy simpático, que consiste en ir poniendo manos y pies en unos círculos de colores, terminando los participantes muy enredados. El problema que tiene es que tiene una ruleta que tiene que manipular una persona externa al juego, que suele ser algún progenitor.
Para evitar mi responsabilidad como progenitor, lo que hice fué este simpático muñeco, que mediante leds de colores indica a los jugadores donde poner sus extremidades, al azar, claro, si no no lo mencionaría en este post.
Frente |
Espalda |
El código está en github, una versión baremetal sin azar y una arduino con azar, ambas se queman con USBasp.
El código es bastante sencillo:
- En baremetal main() / arduino setup() se configuran los puertos como salidas.
- fullBlink() prende y apaga todo.
- heartbeat() invierte todo.
- set() dependiendo de la posición a mostrar, lo mapea a uno de los pines.
- main() hace un poco de circo de comienzo y luego alterna entre elegir y la extremidad/color.
Lo que importa es obtener el seed, para lo cual tuve horribles sufrimientos.
Primero pensé en utilizar un micrófono, pero mi ignorancia analógica me lo impidió. Luego quise leer un fotorreceptor infrarrojo, pero no sé que falló. Por último decidí medir el tiempo hasta que alguien oprimiera un botón y eventuales rebotes, con el ruido del ADC ni hace falta apretar el botón, que está conectado a A0.
Velo en ejecución:
Ah, me olvidaba, para los tokens, estas son algunas medidas útiles:
Composición | Rango de valores | Valores posibles en cada posición | Posiciones necesarias segun bits | ||
---|---|---|---|---|---|
100 | 128 | 256 | |||
Hexadecimal | 0-9 | 10 | 30 | 39 | 77 |
Números | 0-9A-F | 16 | 25 | 32 | 64 |
Letras | A-Z | 26 | 21 | 27 | 54 |
Letras y números | 0-9A-Z | 36 | 19 | 25 | 50 |
Todas la letras y números | 0-9A-Za-z | 52 | 17 | 21 | 43 |
Los números salen de acá, pegar en una hoja de cálculo como fórmula:
C | D | E | F | |
3 | 100 | 128 | 256 | |
4 | 10 | =LOG(POTENCIA(2;D$3);$C4) | =LOG(POTENCIA(2;E$3);$C4) | =LOG(POTENCIA(2;F$3);$C4) |
5 | 16 | =LOG(POTENCIA(2;D$3);$C5) | =LOG(POTENCIA(2;E$3);$C5) | =LOG(POTENCIA(2;F$3);$C5) |
6 | 26 | =LOG(POTENCIA(2;D$3);$C6) | =LOG(POTENCIA(2;E$3);$C6) | =LOG(POTENCIA(2;F$3);$C6) |
7 | 36 | =LOG(POTENCIA(2;D$3);$C7) | =LOG(POTENCIA(2;E$3);$C7) | =LOG(POTENCIA(2;F$3);$C7) |
8 | 52 | =LOG(POTENCIA(2;D$3);$C8) | =LOG(POTENCIA(2;E$3);$C8) | =LOG(POTENCIA(2;F$3);$C8) |
Y acá un caso concreto de wordpress del 2015, lo primero que encontré.
Si notás una cierta falta de ritmo en esta entrada, puede ser debido a que la hice en 2017, no pude hacer funcionar el azar bien rápido y algo me distrajo. Luego, con #quedateencasa me puse a hacer cosas y tuve que programar con USBasp y esté era el único ejemplo que tenía, así que lo reviví y acá está.
No hay comentarios:
Publicar un comentario