Generación de Hashes en Objective-C

Actualmente dentro de los “frentes abiertos” que tengo está el de hacer un “port” de una aplicación que desarrolle para la empresa en la que trabajo de .NET a IOS.

Dicha aplicación tiene un gestor de perfiles de usuario que pueden guardar sus contraseñas y otros datos sensibles de manera segura.

Una aplicación de este tipo tiene unas particularidades con los que no me había encontrado hasta ahora en un proyecto de IOS, se trata de la generación de “Hashes” y el cifrado/descifrado de datos.

Mis ideas tenia de cómo tenia que atacar dicho proyecto, pero algunas eran un poco descabelladas…y todo por evitar tocar las clases se seguridad nativas de Objective-C que se planteaban como bastante densas…

Siguiendo los consejos de un par de cracks como Rafa Aguilar y Fernando Rodríguez encauce las búsquedas por otro lado, y decidí documentar el proceso por si a alguien podía servirle todo este meollo… ;)

En este primer post tocaremos la problemática de la generación de un Hash seguro.

La idea básica de un valor hash es que sirva para representar de una manera compacta de la cadena de entrada. Las funciones Hash se utilizan para multitud de cosas… por ejemplo para verificar que dos archivos sean exactamente iguales (el famoso CheckSum), o para lo que vamos a usarla, para comparar dos passwords uno de los cuales estará ya bajo la forma de Hash. Uno de los Hash mas utilizados en entornos web es el MD5, que ha tenido polémica últimamente a causa de una pruebas de colisiones (se dice cuando dos inputs diferentes pueden generar un mismo output) que no lo han dejado en buen lugar. Incluso existen bases de datos con hashes ya generados de listas de passwords, que mucha gente usa para hacer ataques de fuerza bruta…así que de momento vamos a olvidarnos de MD5… ;)

No olvidéis que un hash no es una función de cifrado, y no debe ser usado para “guardar datos”, por varias razones, pero lo mas importante…no es reversible…así que  lo usamos solo para comparar, ok? ;)

Nosotros este Hash tenemos pensado usarlo para acceder a la app, para el resto de datos usaremos AES (aunque eso lo tocaremos en otro post)…solo lo usaremos para comprobar si tienes autorización para acceder a la App…

La elección del Hash que os propongo es SHA512, el uso de cualquier otra versión de SHA anterior, o el uso de MD5 para estos menesteres deberá ser motivo de penitencia y auto-fustigación por el mero hecho de haberlo pensado…Existe mucha documentación de porque usar el uno o el otro, solo os resumo que actualmente el uso de SHA512 es el aconsejado para estos menesteres… ;)

Genial, tenemos la elección del algoritmo hecha, y ahora como la integramos en el proyecto?

Una opción sencilla es el uso de Categorías en Objective-C, lo que nos permite “ampliar” las posibilidades ofrecidas por una clase anterior.

Podríamos optar por una categoría de NSData, o también de NSString que es por la que me decidí…

Si necesitáis algo mas de información sobre categorías, hice una introducción en un post anterior.

Bien…pues vamos por faena…vamos a crear nuestra categoría de NSString.

Creamos un proyecto, por ejemplo usando un template de una single view, así tendremos un viewController con el que jugar…

Después añadimos un “New File” del tipo “Objective-C Categoría” (esto nos ahorra alguna líneas que typear, vaguete que es uno).

Le damos por nombre Hashes y le decimos que sea una categoría de “NSString”.

Esto nos genera dos archivos, la cabecera “NSString+Hashes.h” y el archivo el cuerpo donde implementar “NSString+Hashes.m”. Como sois muy observadores veréis la nomenclatura que adopta el nombre de la categoría “Categoría que quieres ampliar+tu categoría”. No nos tendremos que olvidar de importar esta en los controladores que lo necesiten para poder funcionar… ;)

Lo que nosotros queremos es ampliar las funcionalidades de NSString para que nos sea mas fácil transformar cadenas a Hashes así que declaramos un par de métodos en “NSString+Hashes.h”

- (NSString *)md5;
- (NSString *)sha512;

La clase importante del sistema que vamos a usar, es “CommonCrypto/CommonDigest” así que la importamos en “NSString+Hashes.m” (sino tu código empezar a fallar como una escopeta de feria).

#import <CommonCrypto/CommonDigest.h>

En este mismo archivo debemos implementar los dos métodos que hemos declarado.

Empezando por el md5 :

- (NSString *)md5
{
    NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t digest[CC_MD5_DIGEST_LENGTH];
    
    CC_MD5(data.bytes, data.length, digest);
    
    NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
    {
        [output appendFormat:@"%02x", digest[i]];
    }
    
    return output;
}

La implementación de este método es un estándar que se usa comúnmente, por ejemplo el SDK de Facebook lo usa, y es que el tema de los Hashes es el pan nuestro de cada día, sobretodo en entornos Web, o en entornos que tengan que lidiar con WebServices…

Lo que hace el método es asegurarse de que la cadena este en UTF8 (ya que el charset es una de las fuentes mas corrientes de errores con los Hash…dando problemas de incongruencias).

Después trabajamos con un array de bytes que generamos y recorremos justo después pasándolo a hexadecimal y creando un bonito churro que es nuestro Hash final…

Otra practica bastante extendida sobretodo si tenemos que pasar esa Hash como parámetro a web o tratar con un Webservice es convertir este churro hexadecimal a Base64…si hay interés también explicare en otro post como podemos hacer esto…

- (NSString *)sha512
{
    NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t digest[CC_SHA512_DIGEST_LENGTH];
    
    CC_SHA512(data.bytes, data.length, digest);
    
    NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA512_DIGEST_LENGTH * 2];
    
    for (int i = 0; i < CC_SHA512_DIGEST_LENGTH; i++)
    {
        [output appendFormat:@"%02x", digest[i]];
    }
    
    return output;
}

Como veréis las diferencias saltan a los ojos, y simplemente leyendo la documentación podremos cambiar el algoritmo fácilmente y usar SHA1, SHA256 etc…aunque los mas corrientes siguen siendo MD5 (a pesar de su mala fama es quizás el mas usado) y SHA512 que esta cogiendo mucha fuerza…

Bueno ahora solo nos queda hacer algo con esto para ver si funciona…

Como hemos creado el proyecto con una plantilla “Single View” tenemos que tener por ahí un ViewController.m ya creado.

Importamos la categoría creada

#import “NSString+Hashes.h”

Y creamos el viewWillAppear (acostumbraros, que dicen que los Load, Unload etc…van a desaparecer dentro de no mucho) para poder poner algo de código en el…

-(void)viewWillAppear:(BOOL)animated{

    NSString *churro = @"Churro Patatero";
    
    NSLog(@"MD5 : %@",[churro md5]);

}

Y con al ejecutar el código se nos retorna este estupendo churro… : “MD5 : 2176861a0ed7f1146549e39c28a3f002″

En teoría la primera vez que se le pide al usuario la contraseña se convierte en un Hash y esta se guarda.

Al volverle a pedir la contraseña convertimos la cadena en un Hash que comparamos con el Hash guardado…eso nos dará acceso o no a la aplicación (o no). Si la app nos concede acceso, usaremos esa cadena para cifrar/descifrar datos…nunca el hash que tenemos ahí…

El Hash te concederá acceso a la app, pero en caso de que alguien accediese a los datos guardados sin la “cadena original” no podrá revertir el proceso…que es lo que esperamos… ;)

Pero de eso hablaremos en otro Post, ya que AES tiene también bastante chicha, y algún que otro problemilla (os presentare al “Apple idioten Vector” xD) bajo IOS que intentare ayudaros a solventar… ;)

Espero que este post haya podido ser de ayuda, es el primero de una lista que tengo preparada así que igual aun tengo que cogerle el tono a como presentar las cosas, como explicarlas, donde recortar y donde explayarme mas…así que ser buenos y criticar de forma constructiva… ;)

Share

Posts relacionados:

  1. Categorias en Objective-C

8 comentarios to “Generación de Hashes en Objective-C”

  1. julio,28th 2012 at 5:03 pm

    Rafael Aguilar says:

    Me ha gustado mucho!!!! Espero que escribas muchos más!!!! Por cierto me ha hecho ilusión la mención :)

  2. julio,28th 2012 at 5:06 pm

    Josep Rivas says:

    Que menos…eres uno de los instigadores de que empezara a compartir este tipo de Post…una vez más muchas gracias crack!!! ;)

  3. julio,30th 2012 at 9:21 am

    Cómo generar hashes en Objective C: ¡los padawans están que se salen! | Cocoa Mental says:

    [...] bien, ¡hay un artículo para eso! Mi padawan @jrivasdu acaba de escribir un artículo sobre cómo generar hashes en Objective C, usando una categoría sobre [...]

  4. julio,30th 2012 at 9:31 am

    Grzegorz Adam Hankiewicz says:

    ¿Por qué para portar una aplicación de .NET a iOS no usáis http://xamarin.com/monotouch/ ?

  5. julio,30th 2012 at 9:38 am

    Josep Rivas says:

    Me han hablado genial de MonoTouch, segun me han dicho puedes trabajar perfectamente con Interface Builder, y las clases en C#. No lo he usado hasta ahora por no haber trasteado con la herramienta con anterioridad, pero no descarto meterle mano para algún proyecto…

    Muchas gracias por la aportación GrzeGor… ;)

  6. agosto,21st 2012 at 4:02 pm

    DBSnippets » Blog Archive » Java: Calcular hash says:

    [...] ya nos instruyó Josep Rivas en un post anterior Generación de Hashes en Objective-C, el concepto de Hash debe de usarse para comprobaciones y no para almacenar datos por los motivos [...]

  7. agosto,27th 2012 at 9:36 pm

    Calcular Hashes | Kyuden Akomachi says:

    [...] Primero Josep Rivas introdujo el tema, aprovechando un proyecto en iOS, y nos mostró como generar hashes en Objective C (ver post). [...]

  8. septiembre,30th 2012 at 8:51 pm

    DBSnippets » Blog Archive » Cifrado simétrico bajo IOS (parte 1 : Teoríca) says:

    [...] Este post vendría en cierta manera a completar el de Generación de Hashes en Objective-C. [...]

Leave a Reply