domingo, 14 de junio de 2015

Tutorial: Cómo conectarse a MySQL desde Android con XAMPP


El presente tutorial tiene como objetivo explicar cómo llevar a cabo la conexión a una base de datos MySQL desde una aplicación Android. La aplicación de ejemplo va a realizar algo bastante sencillo. Al introducir el nombre de una videoconsola y el nombre del juego, va a devolver su género, valoración, PEGI y su precio.

Para ello se ha de tener acceso y privilegios de administrador de una base de datos MYSQL, para lo que en este caso se va a utilizar XAMPP. Las siglas provienen de: X para cualquier sistema operativo, A de Apache, M de MySQL, P de PHP y P de Perl. 

No se va a detallar en este tutorial la instalación de XAMPP, pero puede seguirse fácilmente aquí o aquí. XAMPP permite el uso del pc como servidor y además proporciona una base de datos MySQL que es justo lo que necesitamos.



Configuración de la base de datos


Lo primero que hemos de hacer si queremos acceder a la base de datos es crearla. Para ello hay que lanzar el servidor Apache y MySQL desde XAMPP. Puede comprobarse su funcionamiento desde el panel de control de XAMPP:


Figura 1. XAMPP Control Panel

Para poder entrar en el servidor sólo hay que poner en la barra de direcciones del buscador la dirección:

 >> http://localhost:8080/xampp

Donde como sabéis localhost puede sustituirse por la dirección 127.0.0.1 y 8080 es el puerto correspondiente al servidor Apache .Podría ser otro en función de la configuración, por lo que es importante comprobar desde el panel de control qué puerto tiene asignado.

La página de inicio de XAMPP es la siguiente:


 Figura 2. Página inicio XAMPP

En la figura 2 aparece marcado en un recuadro negro, justo debajo de tools, “phpMyAdmin”. Esta es la herramienta que permite configurar las diferentes bases de datos MySQL desde el entorno web. Por supuesto podría hacerse desde la consola, pero por simplicidad en este tutorial se va a usar phpMyAdmin.

Al pinchar en phpMyAdmin se accede a la página de configuración de bases de datos MySQL:

Figura 3. phpMyAdmin

A la izquierda de la figura 3 se tienen todas las bases de datos existentes en el servidor. En mi caso ya se tienen configuradas algunas pero se va a crear otra a modo de ejemplo. Para ello, a la derecha de phpMyAdmin aparecen una serie de pestañas. Pinchamos en “Bases de datos” y llegaremos  al siguiente menú de configuración:


 Figura 4. Bases de datos phpMyAdmin

En donde aparece claramente una caja de texto para crear una nueva base de datos. Únicamente debemos especificar el nombre y darle a “Crear”. Dejamos por defecto el otro recuadro en “Cotejamiento”. El nombre de la base de datos de este ejemplo va a ser “videoconsolas”. 
Al pinchar en “Crear” dirá que se ha creado correctamente. Ahora hay que configurarla. Pinchamos en la base de datos creada, en donde tendremos que crear una tabla por cada videoconsola que queramos tener en nuestra base de datos. En este caso se van a crear 2: New Nintendo3DS y Xbox360:

Figura 5. Creación de una tabla en la BD

El número de columnas indica el número de campos que va a tener cada videojuego. En nuestro caso serán 5 (nombre, género, valoración, PEGI y precio). Al darle a “continuar” aparece la configuración de las columnas de la tabla:


Figura 6. Configuración de la tabla

La figura 6 muestra las 5 columnas y sus tipos y longitudes asociadas. Los campo “nombre” y “genero” serán de tipo VARCHAR (cadenas de longitud variable) mientras que “valoración” y “precio” son de tipo decimal (FLOAT) y por último PEGI de tipo INT. Es importante saber qué tipo de variable tiene asociada cada columna ya que  más tarde llamaremos a un método u otro en función del tipo para acceder a la información. El resto de parámetros los dejamos por defecto y pinchamos en “Guardar”.

Lo siguiente es añadir un par de juegos con los que probar la aplicación. Desde la pestaña estructura podremos acceder ahora a la tabla. Al pinchar aparecerá un mensaje diciendo que MySQL ha devuelto un conjunto de valores vacío (lógico, aún no hemos agregado ningún juego). Para insertar una nueva entrada le damos a la pestaña “Insertar”, y llegaremos a la siguiente página:

Figura 7. Añadiendo una entrada a la tabla

En este caso se han añadido los juegos FIFA 15 y Monster Hunter 4. La figura 7 muestra cómo se puede añadir un juego, concretamente el FIFA 15. Sólo hay que indicar los valores y darle a “Continuar”. Ya se tiene el juego añadido a la tabla “new nintendo3ds” dentro de “videoconsolas”. Si ahora pinchamos en la pestaña “Examinar” aparecen las 2 entradas. 
Después de esto ya se tendría la base de datos lista.


Acceso a la base de datos desde la aplicación


Ahora sí, ya estamos en condiciones de obtener información de la base de datos desde nuestra aplicación. Creamos el proyecto en Android Studio al que vamos a llamar “ejemploConexionBaseDatos”. Sólo nos va a hacer falta una clase, “MainActivity”. En cuanto al layout, está disponible junto con todo el proyecto en mi repositorio de GitHub que encontraréis al final del tutorial.

Lo que se va a utilizar para realizar a cabo la conexión con la base de datos es JDBC (Java DataBase Connectivity). Es una API que permite la ejecución de operaciones sobre bases de datos desde JAVA. Para más información acerca de la misma puedes hacer click aquí. Primero hay que descargarse el .jar correspondiente a la API desde su página

Para cargar la librería en Android Studio vamos a Project > [aplicación] > libs y pegamos el .jar en ese directorio. Después tenemos que añadir la siguiente línea en Gradle Scripts > build.gradle (Module:app), en el apartado de dependencies:

 >> compile files('mysql-connector-java-3.0.17-ga-bin.jar')

NOTA: Hay que poner el nombre de .jar descargado. En el momento de hacer este tutorial yo tenía la versión 3.0.17, pero esto puede cambiar (y de hecho ha cambiado) así es importante poner el nombre correctamente.

Una vez hecho esto ya podemos acceder a los métodos que nos hacen falta para realizar la conexión, pero eso será más tarde.

Lo primero que hacemos en el método OnCreate() es buscar las referencias de los elementos del layout previamente instanciados:

etNombre = (EditText)findViewById(R.id.etNombre);
etVideoconsola = (EditText)findViewById(R.id.etVideoconsola);
tvGenero = (TextView)findViewById(R.id.tvGenero);
tvValoracion = (TextView)findViewById(R.id.tvValoracion);
tvPEGI = (TextView)findViewById(R.id.tvPEGI);
tvPrecio = (TextView)findViewById(R.id.tvPrecio);
btnConectar = (Button)findViewById(R.id.btnConectar);


Además hay que añadir el listener al botón que realiza la petición sql:

btnConectar.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {

        String videoconsola = etVideoconsola.getText().toString();
        String juego = etNombre.getText().toString();

        if (videoconsola.equals("New Nintendo3DS")){
            videoconsola = "`" + videoconsola + "`";
        }
        new ConexionDB().execute(IP,baseDatos,videoconsola,juego);
    }
});

Vamos por partes. Primero obtenemos el datos de la videoconsola y el juego elegido por el usuario. El condicional se utiliza porque, cuando se quiere hacer una petición SQL del tipo:

SELECT * FROM tabla

Si “tabla” contiene espacios debe ponerse entre comillas francesas `. Por lo tanto, cuando el usuario ponga “New Nintendo3DS” se le deben añadir las comillas, en otro caso saltará una excepción SQL. Quedaría tal que así:

SELECT * FROM `New Nintendo3DS`

Además, desde el main de la interfaz de usuario no se permiten conexiones a la red, hay que hacerlo desde fuera del MainThread. Es por esto que se ha creado la clase ConexionDB que extiende a Asyntask, de modo que la acción se lleve a cabo fuera. La clase es la siguiente:

public class ConexionDB extends AsyncTask<String,Void,ResultSet>{

    @Override
    protected ResultSet doInBackground(String... strings) {

        try {
            Connection conn;
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://"+strings[0]+strings[1], "root", "");

            Statement estado = conn.createStatement();
            System.out.println("Conexion establecida");
            String peticion ="select * from " +strings[2]+" where nombre='"+strings[3]+"'";
            ResultSet result = estado.executeQuery(peticion);
            return result;
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(ResultSet result) {

        try {
            if (!result.next() ) {
                System.out.println("No data");
            }else{
                tvGenero.setText(result.getString("genero"));
                tvValoracion.setText(Float.toString(result.getFloat("valoracion")));
                tvPEGI.setText(Integer.toString(result.getInt("PEGI")));
                tvPrecio.setText(Float.toString(result.getFloat("precio")));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

}

Para el que no sepa qué es la clase Asyntask y cómo funciona, puede verlo aquí. La clase ConexiónDB recibe como parámetros un vector de Strings, que le pasa como argumento a doInBackGround. Este método a su vez devuelve ResultSet a OnPostExecute que es de tipo void. Pero vamos al funcionamiento:

- En doInBackground realizamos la conexión con la base de datos. El método Class.forName() carga la clase que recibe como argumento si no ha sido cargada previamente. Después creamos la conexión mediante el método getConnection de DriverManager. Este método recibe como argumento un primer String con el siguiente formato:

jdbc:mysql://[IP]:[puerto]/[nombre base de datos]

En este caso sería: 

jdbc:mysql://192.168.1.131:3306/videoconsolas

El segundo y tercer String hacen referencia al usuario y la contraseña para acceder a la base de datos. En este caso es el usuario y contraseña por defecto, “root” de usuario y nada (“ ”) de contraseña.

Lo siguiente es crear un “estado” que será el encargado de realizar la petición SQL. Esto se hace llamando al método createStatement() de la clase Connection.

Por último sólo queda formular la petición SQL en función de los datos introducidos por el usuario y recibir los resultados. Para ello se crea una instancia de la clase ResultSet que contiene dichos resultados.

- En el método OnPostExecute recogemos los datos devueltos y seleccionamos los que nos interesen. ResultSet contiene un listado de filas que cumplen la condición nombre=’strings[3]’, es decir, que si el nombre de un juego sólo aparece una vez el número de filas de ResultSet va a ser 1. Sin embargo, si lo que queremos es hacer un recorrido por la base de datos y no seleccionamos ningún elemento (juego) en concreto, debemos ir recorriendo el listado de filas con el método next() de ResultSet. Este método cambia el puntero de una fila a otra, de manera que si lo ejecutamos tal que asi:

While(result.next()){
//codigo a ejecutar
}

Podemos ir recorriendo cada una de las filas para obtener los datos que se deseen.

Volviendo a la aplicación, en nuestro caso sólo se tiene 1 fila en ResultSet, por lo que lo único que debemos hacer es obtener los campos género, valoración, PEGI y precio llamando a:

result.getString() // result.getInt() //….etc

y añadirlos a los diferentes TextView. El resultado final es este:


                                                                  Figura 8. Resultado

Consideraciones adicionales


1. Es necesario añadir permisos de conexión a internet en AndroidManifest para poder acceder a la base de datos. Para ello hay que añadir en ese documento la siguiente línea:

<uses-permission android:name="android.permission.INTERNET" />


2. Si se está utilizando XAMPP en una red de área local, primero hay que identificar cuál es la conexión IP del servidor. La mayoría de los routers utilizan el protocolo DHCP para proporcionar direcciones IP y NORMALMENTE asignan la misma dirección IP, dentro del rango del que disponen, cada vez que un equipo se conecta a dicha red. Sin embargo es muy posible que dicha dirección IP sea diferente si estas en una red diferente a la que habitualmente usas, por lo que es importante comprobarlo primero. 

3. Relacionado con el punto 2, si se utiliza un servidor XAMPP tienes que estar conectado a la misma red Wi-Fi que el servidor. Si, por ejemplo, se intenta utilizar la aplicación de ejemplo con la conexión de datos del móvil (no Wi-Fi) no encontrará nunca el servidor XAMPP. Esto se debe a que al utilizar la conexión de datos se asigna un rango de direcciones IP, por parte del operador de turno, diferente del rango de direcciones IP de la red local WiFi, y la red del operador no sabe qué dirección es la 192.168.x.x ya que es un rango de direcciones privadas.

4. Es posible que al intentar realizar la conexión no permita acceder a la base de datos porque faltan privilegios. En ese caso hay que ir a XAMPP > phpMyAdmin > [basededatos] > privilegios y añadir permisos para acceder desde otro host diferente al servidor que está ejecutando XAMPP.

El código y la aplicación de ejemplo pueden descargarse desde el siguiente repositorio de GitHub: repositorio GitHub

lunes, 25 de mayo de 2015

Tutorial WebView y JSOUP

   Buenas tardes, hoy voy a explicar el funcionamiento básico de un WebView y la librería JSOUP.

  A menudo es posible que se necesite obtener información de una determinada página web. Esta información puede ser en forma de texto, imágenes, referencias…por este motivo es muy útil poder recoger dicha información en HTML y llevar a cabo el “parseo” a texto legible por el usuario.
   JSOUP es una librería desarrollada con este objetivo. Dispone de métodos para obtener el texto en HTML de una página web y poder posteriormente seleccionar los elementos que se desee. Además es muy fácil de usar.
   Por otro lado, y con el fin de exponer un ejemplo de uso de JSOUP, en este tutorial se va a hacer uso de WebView para la visualización de páginas web en aplicaciones Android. 
   El funcionamiento de la aplicación de ejemplo es simple: en el primer layout se ejecuta un webview con un buscador ya cargado y pulsando el botón “obtener referencias” se obtiene a través de JSOUP todas las referencias que existan en la página que se muestre en el webview.

WEBVIEW


Para poder utilizar un WebView es necesario incluirlo en el layout:

<WebView android:id="@+id/webView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"</WebView>

Además hay que añadir en el manifest los permisos para acceder a internet:

<uses-permission android:name="android.permission.INTERNET" />

Se crea la referencia en la actividad principal:

webView = (WebView)findViewById(R.id.webView);

Un aspecto importante a tener  en cuenta para el uso de WebView es que a menudo es posible que, estando navegando dentro del mismo, se quiera acceder a otra página a través de un link. WebView por defecto está configurado para que al pulsar sobre el enlace se solicite al usuario abrir un navegador para su visualización. Para evitar esto (a menudo molesto) es necesario indicarle al WebView que haga uso de WebClient y haga uso de JavaScript de manera que sea capaz de código JavaScript dentro del propio WebView:

webView.getSettings().setJavaScriptEnabled(true);

Asimismo hay que crear la interfaz y añadirla al WebView:

webView.addJavascriptInterface(new MyJavaScriptInterface(this.getBaseContext()), "HtmlViewer");

La sentencia anterior le indica al WebView que debe utilizar la siguiente interfaz, identificada por el WebView como HtmlViewer :

private class MyJavaScriptInterface{

    private Context ctx;

    MyJavaScriptInterface(Context ctx) {
        this.ctx = ctx;
    }

    @JavascriptInterface
    public void showHTML(String html) {
        doc  = Jsoup.parse(html);  //La llamada a parse se encarga de incluir el string a tipo document

    }
}

El cliente Web que se evita que se abra el navegador por defecto del móvil:

webView.setWebViewClient(new WebViewClient(){

    //Se obtiene el codigo HTML una vez cargada la pagina
    @Override
    public void onPageFinished(WebView view, String url) {
        webView.loadUrl("javascript:window.HtmlViewer.showHTML" +
                "('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');");
    }
});

El método sobreescrito onPageFinished establece que, una vez cargada la página, se haga uso de la interfaz de javascript creada anteriormente . Como se indica arriba, el método showHTML  asigna a un objeto de tipo Document todo el código HTML devuelto por el WebView. Obtener dicho código es tan fácil como llamar al método parse de Jsoup.


JSOUP

Para poder utilizar JSOUP es necesario añadir “compile ‘org.jsoup:jsou:1.7.3’ a las dependencias Gradle del proyecto en Android Studio:


Una vez hecho esto ya se puede importar la librería de JSOUP y Document.

En esta aplicación de ejemplo se ha obtenido el html desde el WebView. Sin embargo, desde JSOUP existe un método mucho más fácil mediante el que, dada una URL, obtiene su código HTML:

Document doc = Jsoup.connect(URL).get();

En donde URL es un String con la dirección de la página web de la que obtener el html. Con esta única línea de código ya se tiene todo el código HTML cargado dentro del objeto Document. Ahora es sumamente fácil obtener las partes del documento que nos hagan falta a través de los métodos de la clase Document:

Elements links = doc.select("a");

Con la línea anterior se crea un objeto Elements que contiene todos los elementos del document con el tag “a”, como por ejemplo los que contienen los links [href]. También podrían seleccionarse otros tags como “div” o “img”.
Una vez obtenidos los Elements se puede acceder a los atributos sin más que llamar al método attr(string):

ref = new String[links.size()];
for (int i = 0; i < links.size();i++){
    ref[i] = links.get(i).attr("href").toString();

}

De esta forma tan sencilla se tiene un vector de String con todos los vínculos que contiene la página. Si se quiere obtener alguna otra información no se tiene más que jugar con el método select, attr y el resto de métodos disponibles en JSOUP.
A modo de ejemplo se incluye parte  del código utilizado en otra aplicación:

Elements metaElements = doc.select("table");
metaElements = metaElements.select("tr");

for(Element mElement: metaElements){
    if(mElement.select("th").text().contains("Autor")){
        parsedElements = mElement.select("td");
        autor = parsedElements.first().text().toString();
        int index = autor.indexOf("[");
        autor = autor.substring(0,index);
    }else if(mElement.select("th").text().contains("Fecha")){
        parsedElements = mElement.select("td");
        fecha = parsedElements.first().text().toString();
    }else if(mElement.select("th").text().contains("Publicacion")){
        parsedElements = mElement.select("td");
        editorial = parsedElements.first().text().toString();
    }
}

IMPORTANTE: siempre que se trata con temas relacionados con el parseo de código html cabe recordar que es totalmente dependiente de la forma en la que se estructura el mismo y por ello es muy posible que el cambio en la página web implique un fallo en la forma de realizar el parseo por parte de la aplicación.

El código completo de la aplicación de ejemplo puede descargarse aquí: código

martes, 14 de abril de 2015

Tutorial Bluetooth


Pese a que en la actualidad la tecnología Bluetooth no es muy usada frente a la capacidad que ofrece Internet, es importante saber cómo programar aplicaciones que la utilicen. En esta entrada se expone un breve tutorial con los pasos a realizar para que nuestra aplicación pueda usar Bluetooth. Se parte de la base de que el dispositivo bluetooth ya está vinculado con el dispositivo con el que quiere establecer la conexión.

  • Se instancia e inicializa la clase BluetoothAdapter para obtener el adaptador de Bluetooth con getDefaultAdapter().
  • Se obtienen los dispositivos vinculados con getBondedDevices(). 
  • Se establece el dispositivo de los dos va a actuar como servidor y el que va a actuar como cliente. 
  • El servidor ha de extender la clase Thread, crear un BluetoothServerSocket mediante listenUsingRfcommWithServiceRecord() y escuchar peticiones en el método run a través de bluetoothserversocket.accept(). 
  • El cliente ha de extender la clase Thread, crear un BluetoothSocket utilizando el BluetoothDevice que actúa como servidor y el UUID de la aplicación mediante el método createRfcommSocketToServiceRecord() y en el método run llamar a la clase connect().
  • Cuando el cliente se conecte al servidor, ambos dispondrán de un socket BluetoothSocket con el que manejar la conexión. Ya solo queda instanciar las clases InputStream y OutputStream.

En el siguiente enlace de Github se encuentra el respositorio con la aplicación de ejemplo y el tutorial más extenso en PDF: repositorio

Además dejo un enlace a una serie de tutoriales Bluetooth de Daniel García que me sirvieron para aprender cómo utilizar Bluetooth en Android: tutoriales Bluetooth

domingo, 12 de abril de 2015

Seguridad: Puntos de acceso Wi-Fi gratuitos

Hoy he podido encontrar una noticia, publicada por el periódico ABC, en la que se afirma que "Hasta una niña de 7 años puede robar tus datos". La noticia puede leerse aquí.


En la noticia comentan que lo fácil que es obtener información sensible de usuarios que se conectan a una red Wi-Fi gratuita como puede ser la de cualquier establecimiento o cualquier red a la que nuestro dispositivo tenga posibilidad de conectarse. Además al final de la noticia aparece cómo, efectivamente, una niña británica de 7 años fue capaz de robar información de los dispositivos que estaban a su alrededor. La pregunta es: ¿Cómo es posible esto? Existen varios factores:

1. Cuando nos conectamos a una red desconocida, ajena a la nuestra, cabe la posibilidad de que dicha red sea falsa. Un hacker es capaz de utilizar su dispositivo como pasarela a Internet, de modo que al conectarte a la red todo el tráfico que se está generando pase a través de su dispositivo. Esto es lo que en seguridad se conoce como un ataque Man in the middle. A partir de ese momento es capaz de obtener toda la información de la que dispone y más, ya que no sólo puede ver dónde estás conectado o la información de tu móvil, sino que puede obtener contraseñas y números bancarios con los que puede llevar a cabo robos de información altamente sensible.

2. Dado el caso de que no sea una red ficticia sino que, efectivamente, sea una red real del establecimiento en el que nos encontremos (por ejemplo, una cafetería), no existen los mecanismos de seguridad adecuados que protejan nuestra información. Cuando desde la red de tu casa te conectas a Internet se establecen varios mecanismos de seguridad como el uso de direcciones IP privadas y cortafuegos en los routers de salida de tu red y en puntos intermedios de la red de tu operador. Sin embargo, cuando te conectas a la red de un local no existen tales mecanismos.

Los firewall en los routers solo protegen la red del exterior

El objetivo de las direcciones privadas, aparte de ahorrar direcciones IP públicas, es la de impedir que un usuario fuera de tu red sepa tu dirección IP pública y pueda realizar un ataque directo. Al encontrarte en la misma red con un montón de usuarios desconocidos, dichos usuarios pueden acceder fácilmente a la dirección IP privada dentro de tu dispositivo y, por ende, atacarlo. Además el uso de los cortafuegos a la salida de la red no tiene ninguna validez para dispositivos dentro de la misma, ya que sólo gestiona la información que viene de Internet o va hacia Internet.

Por lo tanto para evitar disgustos y posibles robos de información, es importante seguir los siguientes consejos:

- Estar plenamente seguro de que el punto de acceso Wi-Fi es de confianza y no es falso. NUNCA se ha de establecer una conexión con una red que no necesite contraseña para acceder a ella a menos que se esté seguro de que es de confianza.

- Evitar en la medida de lo posible acceder a páginas web en la que se haga uso de información privada, como pueden ser webs bancarias o redes sociales. Pese a que la información va encriptada desde que sale de nuestro dispositivo, es mucho más "fácil" para un hacker poder desencriptarla si tiene acceso directo a través de un ataque al ordenador o móvil del que procede dicha información.

Para finalizar, aunque haya que tener cuidado con los puntos de acceso Wi-Fi gratuitos de los establecimientos, afortunada (o desafortunadamente) no mucha gente tiene conocimientos acerca de seguridad y por lo tanto acerca de cómo comprometerla.

sábado, 4 de abril de 2015

Cifrado AES en Java

Vamos pues a ver hoy cómo cifrar un mensaje en JAVA. En este caso se va utilizar el algoritmo de cifrado AES, pero existen multitud de estándares para el cifrado de la información. El cifrado AES es un esquema de cifrado por bloques en el que se utiliza una clave de 128,192 o 256 bits. Para saber más acerca de este tipo de cifrado: http://es.wikipedia.org/wiki/Advanced_Encryption_Standard y http://www.codeplanet.eu/files/flash/Rijndael_Animation_v4_eng.swf

Lo primero que se necesita para llevar a cabo el cifrado es una clave. En este caso la clave es de 128 bits, pero podría ser de 192 o 256 bits. Para generar la clave se hace uso de la clase keyGenerator.

private Cipher cifrado;    // clase Cypher para cifrado/descifrado
private byte[] iv;             // Vector de inicialización
private Cipher descifrado;  
private ByteArrayOutputStream outputStream;    //flujo de salida de datos encriptados/desencriptados

En el constructor de la clase:

KeyGenerator kgen;              //clase Keygenerator para generar la clave

kgen = KeyGenerator.getInstance("AES");      //indicamos que se quiere utilizar AES
kgen.init(128);                                                  //se indica que se quieren utilizar 128 bits
SecretKey aesKey = kgen.generateKey();       //se genera la clave

Con esto ya se tiene creada nuestra clave, "aesKey". El siguiente paso es crear una clase Cipher para el cifrado y descifrado. Para el primer caso:

cifrado = Cipher.getInstance("AES/CBC/PKCS5Padding");
cifrado.init(Cipher.ENCRYPT_MODE, aesKey);

La primera línea indica que se quiere utilizar un cifrado AES en modo de cifrado de bloque (CBC) y puesto que es un cifrado de bloque, que se requiere de "padding" (relleno). La segunda linea indica que se quiere utilizar el modo de encriptación (cifrado) y se quiere utilizar la clave generada anteriormente.

Para descifrar podríamos utilizar la misma clase Cipher indicandole ahora que se quiere el modo descifrado, pero en este ejemplo se crea otra clase para verlo un poco más claro:

descifrado = Cipher.getInstance("AES/CBC/PKCS5Padding");
iv = cifrado.getIV();
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
descifrado.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);

La diferencia ahora es que se utiliza un vector de bytes para el descifrado. Este vector iv es muy importante por motivos de seguridad, y su utilidad radica en que dada la misma clave y diferentes vectores de inicialización, el resultado es diferente. Más información aquí: http://es.wikipedia.org/wiki/Vector_de_inicializaci%C3%B3n

Ahora que ya se tienen inicializadas las clases Cipher para cifrar y descifrar, se crean dos métodos para el cifrado y descifrado:

public byte[] cifrarMensaje(String mensaje){
     
        String mensajeCifrado = null;
        byte[] BytesEncriptados = null;
     
        try {
            outputStream = new ByteArrayOutputStream();
            try (CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cifrado)) {
                cipherOutputStream.write(mensaje.getBytes());
                cipherOutputStream.flush();
            }
            BytesEncriptados = outputStream.toByteArray();
         
        } catch (IOException ex) {
            Logger.getLogger(ejemploCifrado.class.getName()).log(Level.SEVERE, null, ex);
        }
     
        return BytesEncriptados;
     
    }
 
    public String descifrarMensaje(byte[] mensaje){
     
        outputStream = new ByteArrayOutputStream();
        ByteArrayInputStream inStream = new ByteArrayInputStream(mensaje);
        CipherInputStream cipherInputStream = new CipherInputStream(inStream, descifrado);
        byte[] buf = new byte[1024];
        int bytesRead;
        try {
            while ((bytesRead = cipherInputStream.read(buf)) >= 0) {
                outputStream.write(buf, 0, bytesRead);
            }
        } catch (IOException ex) {
            Logger.getLogger(ejemploCifrado.class.getName()).log(Level.SEVERE, null, ex);
        }
     
        return new String(outputStream.toByteArray());
     
    }

La primera clase es la encargada del cifrado. Recibe el String a cifrar y devuelve un vector de bytes con el mensaje cifrado. Lo que se hace fundamentalmente es generar un ByteArrayInputStream  que será el encargado de recibir los bytes encriptados y abrir un flujo de cifrado de bytes CipherOutputStream que se encargue de convertir el mensaje a bytes, cifrarlo y pasarselo al ByteArrayInputStream. Este último convierte el flujo de bytes obtenido a un vector de bytes.

La segunda hace el camino inverso: recibe un vector de bytes cifrado y devuelve el string descifrado.

IMPORTANTE: cada algoritmo de cifrado tiene sus propias características, por lo que si se cambia alguno de los parámetros es posible que no funcione. Es importante a la hora de añadir un tipo de cifrado especifico leer primero acerca de cómo funciona.

El código completo se encuentra aquí: https://github.com/VicenteCantonPaterna/CifradoSimple

Está desarrollado en netbeans y por tanto habría que crear un proyecto para Android, pero se puede comprobar su funcionamiento fácilmente. El código no lo he implementado yo sino que estuve intentando montar este minitutorial y en una página encontré uno que no me daba demasiados errores:

http://stackoverflow.com/questions/15554296/simple-java-aes-encrypt-decrypt-example

En realidad lo único que hice fue comentarlo un poco para que se pudiera entender cómo funciona (más o menos).

Espero que os sirva de algo!

miércoles, 11 de marzo de 2015

Seguridad en las comunicaciones.- Introducción

La seguridad es un aspecto tremendamente importante en las comunicaciones y aplicaciones en la actualidad. Gran parte de la información que los usuarios de smartphones es sensible y puede ser utilizada por usuarios ilegítimos con fines maliciosos que van desde robos de credenciales bancarios o información médica, hasta sustracción de cuentas y contraseñas de redes sociales. Es por esto que he decidido hacer una serie de entradas sobre la seguridad en las comunicaciones y como proporcionar robustez en las mismas en lenguaje Java.



Esta primera entrada es introductoria acerca de los 5 pilares básicos de la seguridad en las redes. En las próximas entradas se expondrá cómo se pueden implementar en Java, orientado a Android, algunos de estos pilares. A partir de ahora se denotará una comunicación con usuarios legítimos A y B entre los que se realiza la comunicación y el usuario C malicioso que pretende acceder a la misma sin autorización. Veamos cuáles son:

- Autenticación. En una comunicación entre dos extremos, lo primero que debe hacerse es asegurar que los dos extremos son quienes dicen ser. Es decir, si el usuario A quiere mandarle un mensaje a B, ambos usuarios deben poder saber que A es A y no un usuario malicioso C que ha suplantado a A (o a B). Es lo que típicamente se realiza cuando un usuario quiere conectarse a un servidor para obtener cierta información. Por ejemplo, para acceder a la cuenta de Twitter un usuario debe proporcionar un usuario y una contraseña que solo él conoce (o debe conocer). Así mismo el usuario tiene que tener seguridad de que se está conectando verdaderamente a Twitter y no a una página con una apariencia falsa.

- Integridad. La integridad hace referencia a la autenticidad del contenido del mensaje enviado. Lo que se pretende evitar al proporcionar integridad es que el mensaje que envió el usuario A al usuario B no haya sido modificado por un usuario no autorizado. Este tipo de ataques se conocen como Man in the middle en los que el usuario malicioso intercepta el mensaje, lo lee y lo modifica antes de volver a enviarlo a B. Proporcionar integridad en las comunicaciones es evidentemente un aspecto muy importante, ya que si (por ejemplo) en mensaje que A envía a B es "¿Quieres casarte conmigo?" y el usuario malicioso C lo intercepta y lo modifica de tal manera que ahora sea: "Quiero acabar con esta relación", el resultado de la comunicación es significativamente diferente del deseado por A.

- Confidencialidad. En este caso lo que se pretende es evitar que C, que ha interceptado el mensaje de A a B, sea capaz de leer el contenido. Para evitar esto esto se utiliza el cifrado de la información por parte de A y el posterior descifrado de la información por parte de B.

- No repudio. De igual manera que se quiere proteger y velar por que la información enviada entre A y B sea autentica, íntegra y confidencial, se ha de proporcionar un servicio de no repudio mediante el cual A (o B) no pueda negar el envío de un mensaje. ¿Qué quiere decir esto? Por ejemplo, A ha decidido realizar una compra en una tienda B a través de Internet. Una vez recibido el producto decide que no le gusta y le insiste a B en que no ha realizado dicha compra. Se debe proporcionar un mecanismo que permita a B demostrar que recibió un pedido de compra que, efectivamente, era de A y no de otro usuario. Esto es lo que se conoce como no repudio,

- Disponibilidad. Por último y no menos importante, pese a que en el caso de la programación de dispositivos móviles poco podemos hacer al respecto, es la característica de disponibilidad. Hace referencia a la capacidad de los servicios en la red para ser accesibles por los usuarios legítimos. Dicho de otra manera, lo que se pretende proporcionar con este servicio es que las aplicaciones, páginas web y, en general, sistemas, no puedan ser atacados por usuarios maliciosos y dejar sin servicio a los usuarios que no lo son. El ataque más común a la disponibilidad es el de DoS (Denial of Service o Denegación de Servicio) o DDoS (Distributed DoS). Mediante este ataque lo que se pretende, generalmente, es realizar muchas peticiones a un mismo sistema de manera que se sature y no pueda servir correctamente a los clientes del sistema.


Estos son las 5 características fundamentales que deben proporcionarse en las redes y comunicaciones para que puedan considerarse seguras. Pese a cumplir estos requisitos, nunca puede obtenerse el 100% de la seguridad, pero al menos sí es posible ponerle las cosas difíciles a los mundialmente conocidos hackers.

lunes, 23 de febrero de 2015

#CampusInWatch15 Hackathon en Granada

La primera entrada del blog quiero dedicársela a una actividad muy interesante en la que he tenido el gusto de participar y que ha tenido lugar durante este pasado fin de semana en Granada.

La actividad en sí es el primer Hackathon organizado en Granada en el que han participado entorno a 40 personas. Supongo que la primera pregunta que muchos os estaréis haciendo es: ¿Qué es un Hackathon?

Desde la Wikipedia se define de la siguiente forma: "Un hackathon o hackatón, es un término usado en las comunidades hacker para referirse a un encuentro de programadores cuyo objetivo es el desarrollo colaborativo software, aunque en ocasiones puede haber también un componente de hardware. Estos eventos pueden durar entre dos días y una semana. El objetivo es doble: por un lado hacer aportes al proyecto de software libre que se desee y, por otro, aprender sin prisas."

En este caso el evento tenía una duración de 2 días, de viernes por la tarde a domingo hasta el mediodía. Los patrocinadores del mismo son Global InDevices y el periódico IDEAL.es, con la colaboración del PTS (Parque Tecnológico de la Salud), donde tuvo lugar el evento.

El viernes a las 5 de la tarde se formaron 7 equipos de entre 3 y 5 personas, con el objetivo de desarrollar una aplicación relacionada con la salud a distancia (eHealth) utilizando para ello los relojes inteligentes (SmartWatch) desarrollados por la compañía Global InDevices, concretamente el reloj InWatchZ. Las aplicaciones desarrolladas fueron de diversa índole, desde servicio de seguimiento (tracking) de personas con discapacidades mentales tales como Alzheimer, hasta una aplicación de emergencia para casos de violencia de genero, pasando por aplicaciones para dejar de fumar.

Reloj InWatchZ

Durante la tarde-noche del viernes, el sábado y la mañana del domingo los desarrolladores y programadores han dispuesto de numerosas facilidades para lograr su objetivo. Entre ellas cabe destacar la existencia de comida y bebida gratis para los participantes así como la ayuda de 5 mentores a disposición de los grupos para cualquier duda que pudiera surgirles acerca de la programación del InWatchZ.

Mi grupo de trabajo (BitsPlease), compuesto por Antonio Crespo, Borja Sáez, Amelia Villegas, Mario Lizana y yo mismo, se enfocó en una aplicación que informara a los familiares de una persona con el Alzheimer cuando dicha persona saliera de un perímetro o zona establecida por los mismo familiares. Además pretendíamos que se pudiera configurar el reloj desde una página Web, de manera que los familiares no tuvieran que acceder físicamente al reloj para configurarlo. Sin embargo, dado que la mayor parte del grupo no poseía conocimientos de programación en Java, Android o Web, sólo pudimos alcanzar el primer objetivo. La aplicación puede descargarse desde el repositorio de GitHub: https://github.com/VicenteCantonPaterna/Geo-Valla


Grupo de trabajo del grupo BitsPlease (Fuente: IDEAL.es)

El domingo a la 1 de la tarde se pusieron en marcha las exposiciones de las distintas aplicaciones, y a las 15:30 aproximadamente se dieron a conocer los ganadores. El primer premio fue para el grupo Weinstch, con la aplicación relacionada con la violencia de género. Desde los propios participantes ya sabíamos que su aplicación era la apuesta más clara, ya que entre los integrantes del grupo había 2 doctores en Informática y 3 ingenieros, todos ellos con una holgada experiencia en el desarrollo de aplicaciones.
Equipo ganador Weinstech (Fuente: IDEAL.es) 
También cabe destacar el segundo puesto para el grupo Prometheus, con la aplicación para dejar de fumar.
Grupo Prometheus (Fuente: IDEAL.es)
Por último una imagen de todos los participantes junto con los mentores y el jurado:

CampusInWatch15 (Fuente: IDEAL.es)

En mi opinión, el campus InWatch ha sido un buen evento en el que he aprendido mucho y que espero que se repita pronto. Pese a que nuestro grupo BitsPlease acabó en la 6ª posición, hemos disfrutado mucho con la experiencia, totalmente recomendable. Y vosotros, ¿qué opináis del #CampusInWatch15?