Posts Tagged ‘ios’

Si mi mente no es estática, mi tipado tampoco debería serlo…

Despues de haber leído el articulo de Fernando en Cocoa Mental, se me ocurrió retuiterarlo…y me vi inmerso en un debate con unos interlocutores a los cuales en principio no iba destinado el dardo del autor.

Fernando apuntaba a “Javeros” y “Cpluspluseros”…pero fueron en mayoria “.neteros” (hoy estoy “sembrao” con los palabros) los que se dieron por aludidos, y principalmente usuarios de C#.

Para los que no me conozcáis llevo desde los 10 años rascando código, y voy a cumplir 35 dentro de un mes, y si bien la cantidad y la calidad son los mismo que el tocino y la velocidad, os ruego que hagáis un “auto de fe” sobre lo que os quiero explicar, y al final del post saquéis vuestras propias conclusiones.

En mi día a día principalmente me peleo con .NET y con ObjC+Cocoa, aunque también tengo que entrar al trapo en otras guerras, pero estas no nos aportarían demasiado para el tema que quiero tocar aquí.

Así que, vamos a meternos en harina…

Al contrario que Fernando…veo mas similitudes que diferencias en las dos plataformas que toco, y creo que podemos extrapolar ese pensamiento a todas las plataformas actuales…ahora me explico… ;)

Todas han sido ideadas (con mayor o menor fortuna) para solucionar problemas estándar…y nos ponen en la manos unas herramientas que yendo por la línea  rápida y recta, o dando un largo rodeo…nos permiten (al menos que seamos unos patanes integrales) llegar al mismo sitio…

-Unos harán ese camino dejando suciedad por todos sitios y dando saltitos de aquí para allí mientras caminan…

-Otros irán limpiando el camino y tomando apuntes, incluso dejando miguitas de pan para los que lleguen después…

-Otros, lo harán acompañados de gente y de manera ordenada (estos irán en carreta, turnándose para tirar de la misma y conseguirán cansarse menos)

-Los hay que preferían no hacer ese camino sin consultar previamente los mapas, leerán los apuntes de algún viajero anterior…estudiaran la mejor manera de llegar y verán que con un estricto análisis se podía tomar un atajo que evite pasar una y otra vez por la misma encrucijada…

Al final todos se encuentran delante de una puerta  y pueden abrirla con una llave, o de una pedrada, pero los dos métodos te permitirán entrar

Como veis existen múltiples maneras de hacer las cosas…y eso es común para todas las plataformas…

Bien…a estas alturas del post os estaréis preguntando hacia donde os quiero llevar…seguirme, que ya queda menos… ;)

Los lenguajes y las plataformas, no dejan de evolucionar. Cada una a su ritmo…pero observándose mutuamente…

Si alguno tiene algo realmente bueno, el otro intentara asimilarlo dentro de su core, o implementara algún tipo de “parche” o invento para conseguir el mismo fin…y eso esta pasando constantemente…

Por ejemplo uno de los creadores de Java era un fanático de la plataforma NEXT y se llevo cosas de Objective-C para su nuevo lenguaje.

Un ejemplo técnico sencillo es el tema de los auto-synthetize que nos ahorra unas líneas de código en Objective-C…pues eso existía integrado desde hacia un tiempo antes en .NET, donde declarando las property de una cierta manera se nos generan “por detrás” los getters y los setters necesarios para acceder a ellas…

El otro día descubrí (buscando otra cosa) como “atacar” colecciones de datos con querys’s estilo “SQL” en Objective-C me pareció súper potente para ciertos asuntos…y profundizando en esa búsqueda,  también me di cuenta que eso mismo, se podía hacer en .NET desde la versión 4 del framework atacando los datos con LINQ y con una sintaxis también sospechosamente parecida a SQL

Muchos estaréis pensando que si, que todo muy bonito…pero que, en esencia, el tema de los tipados si que separa a las dos plataformas de manera total…o no?¿

Pues si, y no, una vez más (seguid leyendo hasta el final del post, por favor… ;) xD)…

Para mi el tipado estático realmente representa una carga en el desarollo, y mas cuando has probado las mieles del dinamismo

Yo lidio todos los días con .NET…y puedo trabajar como lo haría con otro lenguaje con tipado dinámico…a eso se le llama “inferencia de tipos” que permite a los lenguajes funcionales soltar lastre y no ser tan estrictos…un buen ejemplo de esto es el lenguaje F# .

En .Net, a partir del framework 4.0 usando declaraciones del tipo “dynamic” el compilador no se queja y manda la llamada necesaria al nuevo motor de ejecución DLR (Dynamic Language Runtime) en lugar del clásico CLR (Common Language Runtime). Y si nos paramos a pensar, antes usando “reflexión” también podíamos  hacer algo parecido (usando Get types), aunque eso era algo mas feote… ;) xD

Por cierto ese nuevo DLR permite cosas muy chulas como ejecutar lenguajes dinámicos como Python (o deberíamos decir Iron Python) bajo .NET y integrarlo plenamente en Visual Studio con muy buenos resultados…

Una vez mas llegamos a lo mismo pero de distinta manera…y todo eso servirá para demostrar algo al final de todo (si no me lio dentro de mis propios pensamientos) ;)

En el post del que surge todo este embolao, Fernando califico a los patrones de diseño como : “una señal de ineficiencia”…

Estoy de acuerdo con esta afirmación?¿ Pues una vez mas si y no, y el que no llegue al final del post no sabrá porque… ;) xDDD

En .NET tenemos mucha libertad para rascar código…tenemos un IDE muy chulo (me encanta Xcode, pero VS2012 esta también muy bien) que permite fácilmente ponerte directamente a crear algo…pero eso no acostumbra a ser una buena idea…Y ahí entran los patrones de diseño…que no dejan de ser una “plantillas” para que no nos descarriemos mucho por el camino…

Y en que lugar deja esto a Objective-C? No usamos con el los patrones de diseño?¿

Pues en realidad si que los usamos y mucho, en casi todo momento…usamos el MVC, el delegado, el observador constantemente…y casi no nos damos cuenta de que lo hacemos…

Simplemente Objective-C y el IDE te empujan a usarlos sin darte cuenta…

Os recomiendo un libro que os ayudara sobre este tema especifico : Pro Design patterns for IOS ;)  y este otro que os servirá para todo…un imprescindible : Design patterns : Elements of reusable object oriented software.

Y ahí es donde quería llevaros desde el principio…

Para mi, el quid de la cuestión no es tanto el tipado, ni los patrones…sino el paradigma o la esencia en si de las propias plataformas y lenguajes

No es un algo, sino el conjunto, el todo, que las hace mejor o peor para conseguir un objetivo

La curva de aprendizaje de alguien que aprende Java o .NET es ascendente…fácil al principio y difícil según se complican las cosas…

Con Objective-C es totalmente a la inversa…te llevas un mazazo al intentar adentrarte en el…y cuando superas ese muro, ya puedes empezar a hacer cosas muy vistosas o complicadas en otras plataformas, sin apenas esfuerzos

Programar con Objective-C te hace tomar decisiones para solventar problemas de manera en cierto modo inducida,  o guiada (un poco como si te llevaran de la mano).

Desarrollas de una cierta manera, cambias la manera de pensar, de enfrentarte a los problemas…usas la potencia del lenguaje dinámico, la potencia al mas alto nivel de los patrones…y puede ser que nunca hayas profundizado ni te hayas interesado en leer nada sobre ninguna de las dos cosas…y sin embargo ahí estas…

Evidentemente, os recomiendo conocer lo mejor posible la plataforma que uséis para poder sacarle rendimiento…y no hacer las cosas por inercia…

Cuanto mas conozcas sobre datos, arquitectura de software, pros, contras, fuerzas y restricciones etc…en mejor profesional te convertirás…necesitas esa información para asimilarla y aplicarla correctamente…

Buenos developers y chapuzas los hay en todas las plataformas…

Pero una de las cosas que me a enseñado la vida, es que no los reconocerás por el lenguaje que dominen, por la plataforma que usen, los reconocerás por la apertura de miras que tengan, la curiosidad que presenten o las ansias de aprender que demuestren…

Por eso quizás el titulo de este post no sea del todo correcto, o quizás si…eso ya lo decidirás tu…

Amplia horizontes, prueba, tantea, estudia, experimenta, pero sobretodo que tu mente no se quede estática… ;)

 

Share

Objective-C : Conseguir la versión de una app

Con este código podremos conseguir la versión de una app que tenemos en el .plist :

NSString*	version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
Share

Objective-C : Dar formato a una fecha

Este snippet es de los que se usan corrientemente en cuanto te toca trabajar con fechas…con el podrás darles formato :

//Dar formato a la fecha
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat: @"yyyy-MM-dd HH:mm:ss zzz"]; // 2013-02-01 21:33:33 PST
NSString *dateString = [dateFormat stringFromDate: [scoreData objectForKey: @"date"]];
Share

Objective-C : Abrir una URL en Safari

NSURL *url = [ [ NSURL alloc ] initWithString: @"http://www.google.com" ];
[[UIApplication sharedApplication] openURL:url];
Share

Objective-C : Contar numero de caracteres de una cadena

Una de las acciones comunes que se requieren al programar es la de contar los caracteres de una cadena.

Aquí os dejo un snippet en Objective-C que sirve exactamente para eso ;)

NSInteger strlength(NSString *str){
	NSRange r = [str rangeOfString:str];
	return r.length;
}
Share

Objective-C : Transiciones entre vistas en IOS

Pasar de una vista a otra de una manera mas vistosa no es muy complicado en IOS. Os dejo el siguiente Snippet que os servirá de guía.

-(IBAction) siguienteVista:(id) sender{
Vistanueva = [[pantallanueva alloc]
initWithNibName:@"Vistanueva" bundle:nil];

[UIView beginAnimations:@"flipping view" context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationTransition:
UIViewAnimationTransitionCurlUp
forView:self.view.superview cache:YES];
[self.view addSubview:Vistanueva.view];
[UIView commitAnimations];
}

Existen otros tipos de transición con los que puedes “jugar” os invito a probarlas… ;)

-UIViewAnimationTransitionNone
-UIViewAnimationTransitionFlipFromLeft
-UIViewAnimationTransitionFlipFromRight
-UIViewAnimationTransitionCurlUp
-UIViewAnimationTransitionCurlDown

Share

Objective-C : Detectar el carrier de nuestro Iphone

Si necesitáis saber con que carrier estáis conectando podéis importar “Core Telephony”

#import <CoreTelephony/CTTelephonyNetworkInfo.h>

Y usar este código para acceder a el :

CTTelephonyNetworkInfo *phoneInfo = [[CTTelephonyNetworkInfo alloc] init];
CTCarrier *phoneCarrier = [phoneInfo subscriberCellularProvider];
NSLog(@"Carrier = %@", [phoneCarrier carrierName]);
[phoneInfo release];
Share

Objective-C : Mostrar el Network Activity Indicator

Si en alguna de tus apps para Iphone necesitas interactuar con el Network Activity Indicator, lo puedes hacer de una manera muy sencilla.

Para mostrarlo :

[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

Para ocultarlo :

[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

 

Share

Cifrado simétrico bajo IOS (parte 2 : Con las manos en la masa)

Este post es la segunda parte de este otro

Hemos hablado de lo que son los cifrados simétricos y asimétricos, para que se usan y ahora tocaría implementarlos en una app IOS.

Como veréis la intención del post no es entrar a las tripas de la librería, cosa que solo os recomiendo en caso de tener mucho tiempo libre, o poca vida social…si bien es útil conocer como funciona, mi intención no es la de asustar a nadie….asi que como dice el lema K.I.S.S. (Keep it simple, stupid…) intentaremos que cualquiera pueda implementar cifrado AES en su app sin volverse loco en el intento…

Una de la maneras mas simples de poder hacerlo, es usando una vez mas las Category que tanto nos facilitan la vida…si no os suena, os dejo este otro post que hice hace un tiempo que os explicara de que se trata

Podriamos usar una Category de NSString (ya que seguro que tus primeras pruebas serán cifrando algún texto corto), aunque como AES nos permite encriptar mucho mas que simple texto, quizás lo mas juicioso seria usar una Category de NSData…y si requieres al final de un NSString pues casteo al canto y ya esta… ;)

Ahora debemos crear una category de NSData a la que en un alarde de ingenio llamaremos AES256.

Al crearla obtendremos una par de archivos el NSData+AES256.h y el NSData+AES256.m. En el archivo .m deberemos hacer un

#import <CommonCrypto/CommonCryptor.h>

para poder usar las funcionalidades que requeriremos en unos momentos…

Implementaremos básicamente 2 métodos que serán los que nos ayudaran a cifrar y descifrar datos.

En el .h los definiremos como con cualquier otro método…

- (NSData *)AES256EncryptWithKey:(NSString *)key;
- (NSData *)AES256DecryptWithKey:(NSString *)key;

Y en el .m su implementación (que es relativamente estándar…aquí he tirado de la documentación oficial de Apple, que es amplia…)

Aquí el que servirá para cifrar :

- (NSData *)AES256EncryptWithKey:(NSString *)key {

	// 'key' should be 32 bytes for AES256, will be null-padded otherwise
	char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
	bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

	// fetch key data
	[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

	NSUInteger dataLength = [self length];

	//See the doc: For block ciphers, the output size will always be less than or
	//equal to the input size plus the size of one block.
	//That's why we need to add the size of one block here
	size_t bufferSize = dataLength + kCCBlockSizeAES128;
	void *buffer = malloc(bufferSize);

	size_t numBytesEncrypted = 0;
	CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES256,
                                          NULL /* initialization vector (optional) */,
                                          [self bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesEncrypted);
	if (cryptStatus == kCCSuccess) {
		//the returned NSData takes ownership of the buffer and will free it on deallocation
		return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
	}

	free(buffer); //free the buffer;
	return nil;
}

Aquí el que usaremos para descifrar :

- (NSData *)AES256DecryptWithKey:(NSString *)key {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
	char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
	bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

	// fetch key data
	[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

	NSUInteger dataLength = [self length];

	//See the doc: For block ciphers, the output size will always be less than or
	//equal to the input size plus the size of one block.
	//That's why we need to add the size of one block here
	size_t bufferSize = dataLength + kCCBlockSizeAES128;
	void *buffer = malloc(bufferSize);

	size_t numBytesDecrypted = 0;
	CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES256,
                                          NULL /* initialization vector (optional) */,
                                          [self bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesDecrypted);

	if (cryptStatus == kCCSuccess) {
		//the returned NSData takes ownership of the buffer and will free it on deallocation
		return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
	}

	free(buffer); //free the buffer;
	return nil;
}

A partir de la documentación veréis que no es difícil adaptar el algoritmo que necesitéis 3DES, DES, Blowfish etc…a estos dos métodos, tendréis que vigilar ciertas especificidad de cada uno (por ejemplo AES256 trabajo con 32 bytes para la key) pero nada que sea realmente dificil de conseguir…

Ahora os dejo una lineas de código para que veáis funcionando todo esto…

Primero no os olvidéis de hacer un import de la Category que habéis creado…

#import "NSData+AES256.h"

Y después usáis esto en el viewController que queráis usar :

    NSString *key = @"este es mi password";
    NSString *secret = @"Este es el texto que queremos cifrar...";

    NSData *plain = [secret dataUsingEncoding:NSUTF8StringEncoding];
    NSData *cipher = [plain AES256EncryptWithKey:key];

    NSLog(@"%s\n",[[cipher description] UTF8String]);

    plain = [cipher AES256DecryptWithKey:key];
    NSLog(@"%s\n",[[plain description] UTF8String]);    
    NSLog(@"%s\n",[[[NSString alloc] initWithData:plain encoding:NSUTF8StringEncoding] UTF8String]);

Con esto veréis en la consola que el cifrado/descifrado funciona…pero eso no significa que sea todo lo correcto que tendría que ser…

Y es que debemos tocar un tema espinoso, el del mal llamado “Idioten Vecktor“. Con el “Idioten Vektor” se están refiriendo al vector de inicialización que se usa para conseguir una mayor complejidad en AES…es decir, no solo usamos nuestro password para cifrar, sino que aplicamos este vector para conseguir que dos “outputs” cifrados con la misma contraseña sean diferentes, pero al descifrarlos podamos volver al estado inicial (espero haberme explicado bien)…

Pues bien, por defecto Common Crypto acepta como parámetro NULL con CCCrypt…en realidad internamente según explican lo llenan de ceros…

Y os preguntareis, y a mi que…y teneis razón en cierta manera, lo que hace Apple es ofrecer un vector de inicialización, del que tu no te tienes que ocupar, y por lo tanto cifras lo que quieras y te olvidas, y al descifrar con la contraseña ya vale…

Entonces porque estoy tocando las narices con esto?¿ Pues porque muchos (vale me incluyo entre los quisquillosos) insisten en que tienes que variar ese vector para conseguir que el hash que sacas sea realmente seguro.

Para que lo entendáis, se trata de dar “menos pistas” a un posible “hacker” que quiera reventar vuestro “cifrado”…

Pues me diréis que fácil, generamos un vector de inicio diferente a cada vez y solucionado…y en cierta manera volvéis a tener razón ya que con esto el cifrado esta solucionado…pero para descifrar también necesitáis ese vector, lo que significa que debéis “conseguirlo” en el momento de descifrar algo…y si bien vuestra contraseña es (o debería ser) “secreta”, vuestro vector tendría que ser como poco “discreto”…y eso implica que tendréis que romperos el coco para transportarlo de manera segura…guardarlo en algún lugar para recuperarlo cuando lo necesitéis etc…Y ese vector no acostumbra a ser algo que puedas “recordar” facilmente…

Y es precisamente porque eso “complica” todo un poco, por lo que Apple ha aceptado como NULL ese parámetro…y es que AES sin vector de inicialización sigue siendo extremadamente seguro…pero evidentemente menos que usándolo… ;)

Como complemento al mismo, estoy acabando de crear (dejarme tiempo…que voy loco últimamente xD) un set de Category’s que quiero que funcionen como un Toolbox para Hashes y cifrado…cuando este todo cerrado lo subo a GitHub;)

Si sois de los que empezáis a preocuparos por la seguridad de vuestros datos bajo IOS espero que este post haya sido de ayuda…se aceptan todo tipo de criticas, consejos etc… ;)

Share

Cifrado simétrico bajo IOS (parte 1 : Teórica)

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

Cuando lo escribía vi que el post se convertía en algo demasiado largo, y siendo sincero, un pelín tedioso…así que he decidido cortarlo en dos.

Otro de los puntos importante es que mucha gente requiere de usar datos cifrados, ya sea para guardarlos en el propio terminal, para pasarlo como parámetros hacia una API o para mil cosas más, pero se asustan ante algo que parece mas complicado de lo que en realidad es…

Apple para variar te lo pone fácil, y existe unas librerías (las Common Crypto) que te permiten hacer todas esas cosas sin volverte loco…quizás no acabes entendiendo del todo como funcionan sus tripas…pero siguiendo ciertas reglas a rajatabla tus datos estarán seguros…o mucho más seguros que si no usas esto…:P ;)

En este primer post encontrareis una parta mas teórica, y en el segundo entraremos a cortar el bacalao… ;)

Bueno, pues vamos por faena…y empezaremos por el cifrado asimétrico.

La criptograma asimétrica :

-Que es, y para que nos puede servir…solo así podemos entender el otro, el simétrico que es el que nos interesa en esta serie de posts…

-Que conocemos como cifrado asimétrico?

La criptografia asimétrica también es conocida como “cifrado de clave publica” o “cifrado de dos llaves” (lo que nos da una pista de por donde van los tiros).

Con esta técnica usamos dos claves creadas por nosotros, para “cifrar” algo, un mensaje, un documento, un archivo etc…

Una de las dos claves creadas es publica y esta se puede “entregar” a la persona que en teoría debe descifrar ese mensaje (existen muchas vías para que esa persona obtenga la clave publica, aunque ese merecería un post solo para eso), la otra clave es “privada” y solo nosotros debemos conocerla, guardarla etc…nadie mas debe tener acceso a la misma.

Ese “par” de claves se obtienen mediante unos algoritmos que aseguran que solo pueden ser creadas una vez y nadie mas podría obtener ese mismo par de claves de manera casual…

Y que conseguimos con eso…?¿ Pues algo realmente interesante…si yo quiero enviarte una información cifrada, y conozco tu llave publica, puedo cifrar algo, y tu y solo tu (usando tu llave privada) podrás descifrarla…

Y si usas tu clave privada para cifrar algo, cualquiera podrá descifrarla usando tu clave publica…Y que conseguimos con esto otro?¿ Pues ademas de cifrar, nos aseguramos de que la persona que ha cifrado el mensaje es realmente quien es…

Y esa es por ejemplo una de las bases de la famosa firma electrónica, cifrado+seguridad del origen del usuario que ha cifrado la información… ;)

La criptografia simétrica :

La criptografía simétrica es también conocida como criptografía de clave secreta…y es la mas común, es por ejemplo la que usamos cada día para loguearnos en una pagina web…

Se dice que el secreto de un buen cifrado simétrico debe residir en la llave y no en el algoritmo…es decir que aunque sepamos/descubramos como están cifrados estos datos, si no conocemos la clave no podremos conseguir el bote de miel… ;)

Los algoritmos han ido mejorando su complejidad con el tiempo pero actualmente los ordenadores permiten descifrar claves con mayor rapidez…es por ello que la complejidad de las claves acaba estando regido por su tamaño…a mas tamaño, mas tiempo necesita el ordenador para “probar” las combinaciones necesarias para conseguir su objetivo…

Por ejemplo uno de los algoritmos que mas se usaban hasta no hace demasiado era DES que usaba una clave de 56 bits o lo que es lo mismo 2 elevado a 56 combinaciones posibles…y eso que puede parecernos una clave muy larga…actualmente no aguantaría un ataque de fuerza bruta (probar automáticamente todas las combinaciones posibles) con un ordenador normal mas que unos días…

Es por ello que ahora los standards mas usado son de 128 bits o 256 que incorporan los algoritmos como 3DES o Blowfish o AES/Rijndael…y según dicen las malas lenguas (y la wikipedia) juntando todos los ordenadores del planeta y trabajando como un enorme cluster, se necesitaría mas tiempo que la propia edad del universo para conseguir descifrar la citada clave…y eso para nuestros menesteres es ya suficientemente seguro… ;)

Este primer post solo quería sobrevolar un poco el mundo del cifrado sin entrar realmente en detalles ya que entiendo que muchos de vosotros solo necesitáis implementar unos métodos que funcionen, y realmente las tripas, el funcionamiento de los mismos tampoco es lo que mas os interesa…

Es por ello que tras este, os he preparado otro post que os permitira implementar en vuestras apps de manera sencilla un cifrado AES, simplemente añadiendo una Category al mismo y llamando a un par de métodos…

También haremos hincapié en el peliagudo tema de lo que algunos denominan el “Idioten Vektor“, una pequeña “laguna se seguridad” (que muchos no consideran como tal) que viene de serie con los metodos de las librerías Common Crypto de IOS…pero todo esto será en el próximo post;)

Share