Ola Java ke ases? -Aleatorio!!!

Publicado por Pedro C. el 14-03-2013

Vamos a descubrir el "bonito mundo" de Java bajo plataformas con Microsoft© Windows (aunque funciona perfectamente en cualquier otro Sistema Operativo) que tan de moda se encuentra con unos pequeños programas "sorprendentes" que seguro que os harán reir un buen rato y demostrarán que "no es oro todo lo que reluce" en cuanto a los números aleatorios.

Introducción

Lo primero, podremos contar con un bonito IDE (Integrated Development Environment) que nos facilitará las cosas como netBeans, el devorador Eclipse o cualquier otro, pero aquí somos muy masocas como ya sabeis y lo vamos a hacer desde la línea de comandos.

Ejecutaremos el comando CMD y veremos si tenemos el "JDK" (Java SE Development Kit) instalado que actualmente es la versión "7u17". Comprobaremos si se encuentra instalado:

c:\users\s4ur0n>dir "c:\Program Files\Java"				
				

Debemos ver un directorio denominado jdkversion-revisión (de la forma jdk1.7.0_17)

En caso de no encontrar un directorio similar, deberemos descargar el Java SE Development Kit en la versión adecuada para nuestro Sistema Operativo y procesador. Su instalación es trivial.

Primer "Ola ke ases"

Vamos a crear nuestro primer programa para lo que pondremos (ojo minúsculas y mayúsculas):

c:\users\s4ur0n>notepad PrimeraClase.java				
				

Y pondremos el siguiente código (ojo que el lenguaje distingue de minúsculas y Mayúsculas):

public class PrimeraClase { 
 public static void main (String[] args) { 
  System.out.println("Ola MADESYP ke ase?"); 
 } 
}				
				

Fácil, no??? Vamos a ejecutarlo. Pero primero, tenemos que compilar nuestro primer programa...

c:\users\s4ur0n>"c:\Program Files\Java\jdk1.7.0_17\bin\javac.exe" PrimeraClase.java				
				

Si todo ha sido correcto, debe volver al prompt del Sistema Operativo y tendremos un nuevo fichero llamado PrimeraClase.class

En caso contrario, debemos revisar la sintaxis y recordar que siempre la primera clase debe ir escrita su primera letra en Mayúsculas y el fichero debe llamarse igual que el nombre de la primera clase con la extensión .java

c:\users\s4ur0n>dir PrimeraClase.class

 El volumen de la unidad C es MADESYP
 El número de serie del volumen es: AB02-002C

 Directorio de C:\Users\s4ur0n

 11/03/2013   20:19                 437 PrimeraClase.class
                 1 Archivo(s)            430 bytes
                 0 dirs 140.066.123.456.789 bytes libres				
				

Ejecutemos ahora el programa (el nombre de la Clase que hemos creado):

c:\users\s4ur0n>java PrimeraClase
Ola MADESYP ke ase?
				

Demasiado fácil para ser verdad... Y funciona y todo!!!

Los números "aleatorios"

Aunque no es el momento de "aprender Java", vamos a probar con el siguiente código generar unos cuántos números "aleatorios" como comprobaremos al final de la entrada. De momento para quien no entienda el código, que copie y pegue literalmente:

c:\users\s4ur0n>notepad Programa2.java

import java.lang.*;
import java.util.Random;

public class Programa2
{
    public static void main(String args[]) 
    {
        System.out.println("\nA jugar!!!\n");
        Random random = new Random(441287210);
        for(int i=0;i<10;i++){
            System.out.print(random.nextInt(10)+" ");
        }
    }
}				
				

Lo compilamos y ejecutamos:

c:\users\s4ur0n>"c:\Program Files\Java\jdk1.7.0_17\bin\javac.exe" Programa2.java

c:\users\s4ur0n>java Programa2

A jugar!!!

1 1 1 1 1 1 1 1 1 1				
				

¿Qué ha ocurrido? ¿No era una secuencia de números aleatorios?

Modifiquemos ahora el valor con el que inicializamos el generador Random con el valor -6732303926L para observar su comportamiento:

c:\users\s4ur0n>copy Programa2.java Programa3.java
c:\users\s4ur0n>notepad Programa3.java

import java.lang.*;
import java.util.Random;

public class Programa3
{
    public static void main(String args[]) 
    {
        System.out.println("\nA jugar!!!\n");
        Random random = new Random(-6732303926L);
        for(int i=0;i<10;i++){
            System.out.print(random.nextInt(10)+" ");
        }
    }
}				
				

Lo compilamos y ejecutamos:

c:\users\s4ur0n>"c:\Program Files\Java\jdk1.7.0_17\bin\javac.exe" Programa3.java

c:\users\s4ur0n>java Programa3

A jugar!!!

0 1 2 3 4 5 6 7 8 9				
				

Ufff... se ve que no funciona "demasiado bien" el generador, o mejor dicho, el algoritmo del desarrollador... Nos preguntamos si es posible obtener valores "aleatorios precalculados" como intentaremos realizar a continuación...

Valores "aleatorios precalculados"

Vamos a crear un nuevo código en Java:

c:\users\s4ur0n>notepad Programa4.java

import java.lang.*;
import java.util.Random;

public class Programa4
{
    public static void main(String args[]) 
    {
        System.out.println(randomString(-229985452)+' '+randomString(-147909649));
    }
	
	public static String randomString(int seed) {
		Random rand = new Random(seed);
		StringBuilder sb = new StringBuilder();
		for(int i=0;;i++) {
			int n = rand.nextInt(27);
			if (n == 0) break;
			sb.append((char) ('`' + n));
		}
    return sb.toString();
    }
}				
				

De la misma forma anterior, compilamos y ejecutamos:

c:\users\s4ur0n>"c:\Program Files\Java\jdk1.7.0_17\bin\javac.exe" Programa4.java

c:\users\s4ur0n>java Programa4
hello world
				

Un "Hola Mundo" en condiciones con un par!!! Seguimos preguntándonos qué ha podido ocurrir con los "números aleatorios"...

Comenzaremos por afirmar que para la semilla particularmente empleada funciona a la perfección ya que los números aleatorios no son realmente aleatorios sino pseudoaleatorios y por tanto, podemos jugar con las semillas empleadas para generarlos alterando el comportamiento previsto inicialmente.

En realidad, new Random(-229985452).nextInt(27) genera la secuencia:

8
5
12
12
15
0				
				

Y new Random(-147909649).nextInt(27) genera la secuencia:

23
15
18
12
4
0				
				

Simplemente añadiendo la conversión del carácter base "`" empleado (que es 96) obtenemos:

8  + 96 = 104 --> h
5  + 96 = 101 --> e
12 + 96 = 108 --> l
12 + 96 = 108 --> l
15 + 96 = 111 --> o

23 + 96 = 119 --> w
15 + 96 = 111 --> o
18 + 96 = 114 --> r
12 + 96 = 108 --> l
4  + 96 = 100 --> d				
				

Tal y como se ha definido en la función "aleatoria"...

Por eso, podemos afirmar que la mayoría de generadores de números aleatorios, son en realidad pseudo-aleatorios por depender de un Generador Lineal Congruente (Linear Congruential Generator ó LCG) como podeis comprobar en la Wikipedia (LCG) y son muy predecibles dada una semilla. Básicamente, se emplea una semilla que nos devuelve la primera letra y se continua generando el "siguiente carácter" del tipo entero o real hasta obtener la secuencia completa.

Vamos a crear un último programa para demostrar dicha afirmación donde jugaremos con dichas secuencias, pero empleando para el generador estándard de Java enteros largos y con otras bases como carácter a "sumar" para poder jugar completamente:

c:\users\s4ur0n>notepad Programa5.java

import java.lang.*;
import java.util.Random;

public class Programa5
{
    public static void main(String args[]) 
    {
        System.out.println(randomString(-9223372036756766062L));
    }
	
	public static String randomString(long seed) {
		Random rand = new Random(seed);
		StringBuilder sb = new StringBuilder();
		for(int i=0;;i++) {
			int n = rand.nextInt(27);
			if (n == 0) break;
			sb.append((char) ('[' + n));
		}
    return sb.toString();
    }
}

c:\users\s4ur0n>"c:\Program Files\Java\jdk1.7.0_17\bin\javac.exe" Programa5.java

c:\users\s4ur0n>java Programa5
pedro
				

Podeis probar cambiando el anterior programa con otros valores de semilla como "-9223372036854613447L" y base "U", "-9223372036842541804L" y base "^", "-9223372036823269614L" y base "\" y por no hacernos más pesados ya que podemos generar cualquier palabra con "-9223372036815508915L" con base "Y"... ¿Qué significan esos números aleatorios? Esperamos vuestras respuestas por correo electrónico!!!

Por tanto, hablaremos de un Pseudorandom Number Generator (PRNG) o nos montaremos nuestro propio generador. Si buscais en Internet, podreis encontrar ésta y mucha más información para poder "jugar" a "predecir el futuro" hasta que nos damos cuenta que dichos generadores "por defecto pueden fallar" cuando se emplean para generar contraseñas, números de secuencias en paquetes, etc... o incluso nos pueden servir perfectamente para ofuscar código malicioso en nuestros códigos... ¿Estamos vendidos por los números aleatorios?

Para aquellos que no quieren compilar o copiar los programas, os los dejamos en nuestro repositorio maligno para vuestras pruebas y experimentación.

Recordaros que en los Cursos especializados de Seguridad Informática y Administración de Sistemas que ofrecemos en Academia MADESYP realizamos y establecemos las contramedidas con todo esto y mucho más...

Ser buenos y no hagáis maldades!