Trucos

Grabación segura de claves en Swift con la librería CryptoKit

No exponga las claves de tus usuarios de forma plana. Protégelas con solo 2 líneas en Swift.

No hay nada más inseguro y menos recomendado por los expertos en seguridad, que grabar cualquier tipo de contraseña o valor clave para nuestra app, tal cual como cadena.

Menos aún en lugares como el famoso e infame UserDefaults que solo debe ser usado para valores inocuos de nuestra app (como la configuración de color del usuario) y que siempre ha de tener una comprobación de valor y un forzado a valor por defecto. Es decir, que si grabo darkMode como un valor 1 o 0, al leerlo compruebo si tiene uno de estos valores y si no, pongo el 0 por defecto. Para evitar cualquier tipo de modificación que cree estados inciertos en mi app.

Grabación de claves en forma segura

Desde iOS 13, Apple creó una librería nativa 100% en Swift llamada CryptoKit, que nos proporciona una forma muy simple de trabajar con hashes, cifrado y firma digital. Y esto es clave para no guardar valores «en bruto», como una cadena, que puede ser observada por cualquier persona que intente comprometer nuestra app simplemente mirando la memoria de la misma desde un dispositivo comprometido (por ejemplo).

Jamás hemos de guardar ningún dato seguro o clave, tal cual. Mejor cifrado o como hash, para prevenir que pueda ser comprometido.

¿Qué grabo entonces en vez del valor String que ponga un usuario en mi app como contraseña o valor comprometido? El hash. Un hash es la firma de autenticación de un dato. Un dato concreto, sea cual sea su tamaño, solo puede dar un hash concreto, y si dicho dato cambia, el hash será distinto y sabremos que este ha sido alterado. Nada más simple.

¿Y por qué usar un hash es seguro en vez de la cadena? Porque el algoritmo de hash no permite, por cómo está creado, obtener en forma alguna el dato del que procede. Así que el hecho que alguien vea este dato en memoria no le da información alguna válida porque no puede extraer la información de la que procede.

Calculando el hash

Para hacer esto solo necesitamos importar la librería CryptoKit.

import CryptoKit

Una vez puesta, debemos transformar el dato de tipo cadena que queremos almacenar a un tipo Data del sistema. Para ello usaremos un método que ya tienen todos los tipos String (método falible u opcional) que devuelve el valor de dato en bruto o array de bytes, a partir de la cadena que tenemos.

let data = clave.data(using: .utf8)

Usaremos para ello la codificación UTF8, que es la que usa Swift para todo el lenguaje y sus datos de caracteres. Ahora, bastará con pasar dicha cadena convertida en tipo Data por el constructor del tipo Hash512, que nos ofrece un método estático llamado .hash al que pasarle este y nos devuelve el hash. Nada más simple.

let hashed = SHA512.hash(data: data)

¿Cómo extraemos el valor del hash? Nada más simple que acudir a la propiedad .description que tienen todos los tipos con representación textual en Swift, para que nos de una cadena con la que podamos trabajar.

hashed.description

Como el data es opcional, nos dará un warning, así que vamos a hacer una función que lo haga todo tal cual, gestionando los opcionales.

func hashCode(clave:String) -> String? {
    guard let data = clave.data(using: .utf8) else {
        return nil
    }
    let hashed = SHA512.hash(data: data)
    return hashed.description
}

Veremos que nos antecede la cadena SHA512 digest: justo antes del valor de cadena. Podemos usar esta cadena, así tal cual en Swift. Pero si, por algún motivo, tenemos que enviarlo fuera, deberemos transformarlo sacando solo su cadena hexadecimal en vez de esa cadena previa.

Para ello devolvemos lo siguiente en nuestra función:

return hashed.compactMap { String(format: "%02x", $0) }.joined()

Esta simple línea, recorre el valor en valor en hash devuelto, y convierte cada byte de valor en su hexadecimal como cadena. El primer compactMap transforma el array dentro de hashed byte a byte, para luego con la función joined(), devolver todo ese array como un solo valor del tipo transformado (o sea, un String).

Listo para grabar y comparar

Nada más. Ya podemos grabar el dato como cadena donde queramos. Luego, para comprobar que una clave introducida es válida, solo tendremos que llamar a nuestra función hashCode y comparar el valor que nos devuelve con el valor que hemos guardado.

En vez de comparar la clave que el usuario introduzca en nuestra app, tal cual, le hacemos el hash y lo comparamos con el anterior hash que previamente grabamos. Si son el mismo, la clave es correcta.

De esta forma, nunca propagaremos el dato en sí. Si os gustado el tutorial, dejadnos un comentario y compartidlo en redes sociales, para llegar a más gente. Y si queréis que os hablemos de algún tema más, no dudéis en propornerlo. Un saludo y Good Apple Coding.

Julio César Fernández

Analista, consultor y periodista tecnológico, desarrollador, empresario, productor audiovisual, actor de doblaje e ingeniero de vídeo y audio.

Artículos relacionados

Botón volver arriba