Red de conocimiento informático - Material del sitio web - Cómo utilizar la clase CommonCrypto para el cifrado en Swift

Cómo utilizar la clase CommonCrypto para el cifrado en Swift

Hoy en día, muchos desarrolladores ya no necesitan implementar cifrado en sus aplicaciones. Incluso si está utilizando una API REST en un servidor remoto, la mayoría de los problemas de comunicación segura generalmente se pueden resolver usando HTTPS, y los problemas restantes se pueden resolver usando la combinación de "modo protegido" y cifrado de hardware/software proporcionada por Apple. Sin embargo, en muchos casos, aún es necesario cifrar las comunicaciones o los archivos. Tal vez esté trasladando una solución existente que involucra cifrado de archivos/información a iOS, tal vez esté creando una aplicación con requisitos de confidencialidad extremadamente altos o simplemente desee aumentar el nivel de seguridad de sus datos (y eso es algo bueno).

En cualquier caso, Cocoa (en iOS y OS X) elige CommonCrypto para hacer el trabajo. Sin embargo, la API de CommonCrypto todavía utiliza el antiguo estilo C. Esta API está desactualizada y es muy difícil de usar en Swift. Además, usar propiedades fuertemente tipadas en Swift para manejar diferentes tipos de datos en CCCrypt (la característica principal de cifrado/descifrado del marco de cifrado simétrico) no es elegante.

Primero echemos un vistazo a la definición de CCCrypt:

CCCrypt(op: CCOperation, alg: CCAlgorithm,

opciones: CCOptions,

clave: UnsafePointerlt; Voidgt;

keyLength: Int,

iv: UnsafePointerlt;Voidgt;,

dataIn: UnsafePointerlt;Voidgt;,

dataInLength : Int ,

dataOut: UnsafeMutablePointerlt; Voidgt;,

dataOutAvailable: Int,

dataOutMoved: UnsafeMutablePointerlt;)

Vamos a eche un vistazo a la declaración de función Objective-C (más precisamente, la versión C):

CCCryptorStatus CCCrypt(

CCOperation op, // operación: kCCEncrypt o kCCDecrypt

CCAlgorithm alg, // algoritmo: kCCAlgorithmAES128...

Opciones de CCOptions, // operación: kCCOptionPKCS7Padding...

const void *key, // key

size_t keyLength, // longitud de clave

const void *iv, // vector de inicialización (opcional)

const void *dataIn, // datos de entrada

size_t dataInLength, // longitud de los datos de entrada

void *dataOut, // buffer de datos de salida

size_t dataOutAvailable, // longitud de los datos de salida disponible

size_t * dataOutMoved ) // longitud real de los datos de salida generada

En Objective-C, puede simplemente usar constantes predefinidas (como "kCCAlgorithm3DES") para definir estos parámetros y luego pasar diferentes matrices y tamaños, sin tener que Preocuparse por su tipo exacto (pase una variable int para el parámetro size_t, o una variable char para el parámetro void). Este no es el mejor enfoque, pero funciona (solo requiere algún tipo de conversión).

Pero Swift elimina las partes C de Objective-C, por lo que necesitamos hacer un trabajo de preparación para usar CommonCrypto en Swift y Cocoa.

Funcionamiento, algoritmo y opciones

La codificación simétrica es la forma más sencilla de enviar y recibir datos cifrados en la aplicación. Este método tiene una sola clave, que se utiliza para las operaciones de cifrado y descifrado (a diferencia del cifrado asimétrico, que suele utilizar un par de claves pública-privada). Existen muchos algoritmos diferentes para cifrados simétricos, y todos ellos pueden tener configuraciones diferentes. Los tres conceptos principales son: operación (cifrado/descifrado), algoritmo (DES, AES, RC4...) y configuración, correspondientes a CCOperation, CCAgorithm y CCOptions de CommonCrypto.

CCOperation, CCAgorithm y CCOptions son esencialmente uint32_t (un int sin signo que ocupa 32 bits de almacenamiento), por lo que podemos construirlos a través de constantes CommonCrypto:

let Operation = CCOperation(kCCEncrypt )

let algoritmo = CCAlgorithm(kCCAlgorithmAES)

let options = CCOptions(kCCOptionPKCS7Padding | kCCOptionECBMode)

Puntero inseguro

Abstracción rápida Los punteros inseguros corresponden a punteros del lenguaje C (C-Pointers). Swift intenta abstraer todos los punteros y administradores de memoria estilo C. Generalmente no es necesario utilizarlos a menos que necesite utilizar una API de estilo antiguo (como CommonCrypto). Si tienes tanta mala suerte, necesitarás aprender a lidiar con ellos:

Hay dos tipos de punteros en Swift: los tipos UnsafePointers y UnsafeMutablePointers. El primero se usa para registros constantes y los punteros en el espacio de memoria son constantes; el segundo se usa para espacios de memoria variables. En correspondencia con el lenguaje C, el tipo UnsafePointer es un tipo de búfer de "tipo constante", y UnsafeMutablePointer es un tipo de búfer de "tipo" (la palabra "búfer" aquí es solo un nombre habitual en el pasado). El tipo específico de puntero se escribe en <> después de la declaración, por lo que si desea declarar un puntero de tipo "nulo", debe escribir: UnsafeMutablePointer. Si desea declarar un puntero del tipo de búfer "const unsigned char", debe utilizar: UnsafePointer. Aunque Apple proporciona conversión de tipos C puros a tipos Swift, debe tenerse en cuenta que tipos como CChar, CInt, CUnsignedLongLong... no se pueden usar directamente en UnsafePointers y es necesario usar tipos Swift nativos.

Esto plantea una pregunta: ¿cuándo se pueden utilizar estos tipos? Necesitamos profundizar en la definición de tipo de Swift:

typealias CShort = Int16

typealias CSignedChar = Int8

typealias CUnsignedChar = UInt8

typealias CUnsignedInt = UInt32

typealias CUnsignedLong = UInt

typealias CUnsignedLongLong = UInt64

typealias CUnsignedShort = UInt16

Afortunadamente no necesitamos Implementa la gestión de memoria de los tipos UnsafePointers y UnsafeMutablePointers (siempre que utilice objetos Cocoa como NSData). Swift los administra (y los une) automáticamente. Si necesita cifrar/descifrar datos y almacenar la clave en NSData, puede llamar a data.bytes o data.mutableBytes para obtener los punteros UnsafePointer y UnsafeMutablePointer correspondientes.

Otra forma de obtener la variable UnsafePointer es amp;. Al procesar la variable de salida (que requiere la dirección de memoria), el puntero inseguro (mutable) de tipo Int se obtiene a través del símbolo amp; Podemos usar este método en CCCrypt para pasar la dirección de la variable "Int" al último parámetro: "dataOutMoved". Nota: La variable definida por let corresponde al tipo UnsafePointer y la variable var corresponde al tipo UnsafeMutablePointer.

Ahora tenemos todos los elementos necesarios para llamar a CCCrypt.

Bridge

CommonCrypto aún no es compatible con Swift, por lo que para usarlo, necesitamos importar la forma Objective-C de CommonCrypto a través de un archivo de encabezado.

#import lt;CommonCrypto/CommonCrypto.hgt;

Clase SymmetricCryptor

Recientemente necesito hacer un proyecto de cifrado simétrico para facilitar el cifrado y descifrar datos, construí una clase SymmetricCryptor (sin importar el horrible nombre). Convierte datos al tipo CommonCrypto apropiado. Puede usarlo para cifrar o descifrar datos fácilmente.

let sc = SymmetricCryptor(algoritmo: .AES128, opciones: CCOptions(kCCOptionPKCS7Padding))

cypher.setRandomIV()

do { let cypherText = try sc .crypt(string: clearText, key: key) } catch { print("Error al cifrar: \(error)") }

CommonCrypto proporciona una variedad de algoritmos y configuraciones, pero solo quiero resolver los problemas de cifrado más comunes, simplificando así la configuración.

Por ejemplo, cuando usa RC4, puede usar una clave de 40 o 128 bits (las constantes correspondientes son RC4_40 y RC4_128). De manera similar, AES también tiene algunas constantes de uso común (128b, 256b...). Entonces definí una variable de enumeración llamada SymmetricCryptorAlgorithm, que define muchas configuraciones comunes (como AES 256), que incluyen no solo el algoritmo, sino también mucha otra información, como la longitud de la clave y el tamaño del bloque.

En la página de GitHub de SymmetricCryptor, puede ver un ejemplo de cifrado/descifrado simétrico que muestra cómo implementar el cifrado/descifrado simétrico de forma sencilla.