Uso de OpenSSL EVP

OpenSSL EVP (Funciones de cifrado avanzadas) proporciona varias funciones de cifrado. En OpenSSL se implementan varios algoritmos simétricos, algoritmos abstractos y algoritmos de firma/verificación de firma. La función EVP encapsula estos algoritmos específicos.

EVP encapsula principalmente las siguientes funciones:

1) Se ha implementado la codificación y decodificación BIO BASE64.

2) Se ha implementado el cifrado y descifrado de información biológica; ;;

p>

3) Implementar biología abstracta

4) Implementar io confiable

5) Encapsular algoritmo de resumen

6) Encapsular algoritmo de cifrado y descifrado simétrico

7) Encapsula cifrado de clave asimétrica (clave pública), descifrado (clave privada), firma y verificación y funciones auxiliares

8) Basado; en Cifrado de contraseña (PBE);

9) Procesamiento de clave simétrica

10) Sobre digital: el sobre digital utiliza la clave pública de la otra parte para cifrar la clave simétrica; clave Cifrar datos. Al enviar a la otra parte, el texto cifrado de clave simétrica y el texto cifrado de datos se envían al mismo tiempo. El receptor primero descifra el texto cifrado clave con su propia clave privada para obtener la clave simétrica y luego la usa para descifrar los datos.

11) Otras funciones auxiliares.

Este artículo asume que tienes OpenSSL instalado y tienes una copia del código fuente de 1.1.1.

Los archivos de encabezado relacionados con EVP están en evp.h y los archivos fuente están en el directorio crypto/evp.

Debido a que las funciones de EVP son demasiado poderosas y mi energía y nivel son limitados, por el momento solo extraeré y explicaré algunas funciones.

Esta estructura define el método abstracto del algoritmo de resumen. Significado del campo principal:

El tipo NID del algoritmo abstracto.

PKEY_TYPE: clave NID asociada al algoritmo de resumen.

MD_size: tamaño de salida de los valores agregados.

Bandera - bandera interna.

Función init-inicialización.

Actualizar - Ingresar a la función de cálculo.

Función de cálculo de salida final.

Copiar: función de copia del contexto de la operación de resumen.

Función de limpieza del contexto de la operación Clean-Aggregation.

block _ size: el tamaño de agrupación de la operación de resumen.

Tamaño CTX: tamaño del búfer del paquete de operación de resumen.

MD_CTRL: resume las funciones de control del comando de operación.

Los algoritmos de resumen admitidos incluyen:

const EVP _ MD * EVP _ MD5(void);

const EVP _ MD * EVP _ sha 1(void); ;

const EVP_MD * EVP_sha 256(void);

const EVP_MD * EVP_sha 512(void);

Con EVP_md5() es un ejemplo. El valor es:

Las siguientes funciones consultan la información de atributos de md:

A veces no estamos familiarizados con el algoritmo de resumen utilizado y estas funciones son muy útiles.

EVP_MD_CTX*EVP_MD_CTX_new(void);

void EVP_MD_CTX_free(EVP_MD_CTX*CTX); p>

Estas dos funciones se utilizan para crear y liberar objetos de contexto de resumen simétricos.

int EVP _ DigestInit(EVP _ MD _ CTX * CTX, const EVP _ MD * type);

El contexto abstracto se inicializa y el tipo es una colección abstracta de algoritmos abstractos.

1 devuelve éxito, 0 devuelve fracaso.

int EVP_digest update(EVP_MD_CTX *CTX, const void *d, size_t CNT);

Ingrese un dato en la estructura de esponja calculada en el resumen.

1 devuelve éxito, 0 devuelve fracaso.

int EVP_digest final(EVP_MD_CTX *CTX, unsigned char *md, unsigned int *s);

Genera el resumen final y genera el valor y la longitud del resumen.

1 devuelve éxito, 0 devuelve fracaso.

int EVP_Digest(const void *data, size_t count, unsigned char *md, unsigned int *size, const EVP_MD *type, ENGINE *impl

Usar empaquetado una sola vez); El método calcula el resumen de un pequeño dato.

1 devuelve éxito, 0 devuelve fracaso.

Estructura evp_cipher_st {

int nid

int block _ size

/*Valor predeterminado de cifrado de longitud variable/

int key _ len

int iv _ len

/Varios indicadores/

Indicador largo sin firmar;

/tecla init /

int (init) (EVP_CIPHER_CTX *ctx, const unsigned char *key,

const unsigned char iv, int enc);

/Encrypt/Decrypt data/

int(do _ CIPHER)(EVP _ CIPHER _ CTX * CTX, carácter sin firmar *salida,

const carácter sin firmar en, tamaño _ t inl);

/ cleanup ctx /

int(clean up)(EVP _ CIPHER _ CTX

/¿Qué tamaño debe tener CTX-& gt; /p>

int ctx_size

/llenar ASN1_TYPE con parámetros/

int(set_ASN 1_parameters)(EVP_CIPHER_CTX *,ASN 1_TYPE);

/Get parámetros de ASN1_TYPE/

int(get_ASN 1_parameters)(EVP_CIPHER_CTX *,ASN 1_TYPE) ;

/Operaciones varias/

int (ctrl) (EVP_CIPHER_CTX *, int type, int arg, void ptr);

/Datos de la aplicación*/

void app_data

}/EVP_CIPHER */; p>

typedef struct EVP _ CIPHER _ ST EVP _ CIPHER;

Esta estructura define un método abstracto para algoritmos de cifrado simétrico. Significado del campo principal:

NID-NID del algoritmo de cifrado.

block_size-tamaño del paquete.

key_len - longitud de la clave.

iv _ len - longitud inicial del vector.

Bandera - bandera interna.

Función init-inicialización.

función de operación intermedia do_cipher.

Limpieza-la función de operación final.

Tamaño CTX - tamaño de contexto.

Función de control Ctrl.

app_data-datos de la aplicación.

Los algoritmos de cifrado y descifrado abstractos criptográficos admitidos incluyen:

const EVP _ CIPHER * EVP _ des _ ECB(void);

const EVP _ CIPHER * EVP); _ des _ ede 3(void);

const EVP _ CIPHER * EVP _ AES _ 128 _ ECB (void);

const EVP _ CIPHER * EVP _ AES _ 128 _ CBC(void);

La siguiente función consulta la información del atributo de la contraseña:

int EVP _ CIPHER _ NID (const EVP _ CIPHER * CIPHER

<); p> int EVP _ CIPHER _ type(const EVP _ CIPHER * CTX

#Definir EVP _ CIPHER _ nombre(e)OBJ _ nid2sn(EVP _ CIPHER _ NID(e))

int EVP_CIPHER_block_size(const EVP_CIPHER * CIPHER);

int EVP_CIPHER_key_length (const EVP_CIPHER * CIPHER); _ iv _ length(const EVP _ CIPHER * CIPHER);

A veces no estamos familiarizados con el algoritmo de cifrado utilizado, estas funciones son útiles.

EVP _ CIPHER _ CTX * EVP _ CIPHER _ CTX _ nuevo(void);

void EVP _ CIPHER _ CTX _ gratis(EVP _ CIPHER _ CTX * c); /p>

Estas dos funciones se utilizan para crear y liberar objetos de contexto de cifrado y descifrado simétricos.

int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX * x, int key len);

Cuando la longitud de la clave del algoritmo simétrico es variable, establezca la longitud de la clave del algoritmo simétrico.

1 devuelve éxito, 0 devuelve fracaso.

int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX * c, int pad);

Establece el relleno del algoritmo simétrico, que a veces implica relleno.

Pad toma los valores 0 y 1. Cuando pad es 1, se utiliza relleno. La estrategia de llenado predeterminada adopta la especificación PKCS5, es decir, cuando el último paquete se llena con n bytes, su valor de llenado es n.

1 devuelve éxito, 0 devuelve fracaso.

int EVP _ encrypt init(EVP _ CIPHER _ CTX * CTX, const EVP_CIPHER *cipher, const unsigned char *key, const unsigned char * iv

Inicializar contexto de cifrado simétrico); .

Si se agrega 1 correctamente, se devolverá 0 si falla.

int EVP _ encrypt update(EVP _ CIPHER _ CTX * CTX, unsigned char *out, int *outl, const unsigned char *in, int inl

Cifrar texto sin formato); .

Si se agrega 1 correctamente, se devolverá 0 si falla. En caso de éxito, outl genera la longitud del texto cifrado.

int EVP_encrypt final(EVP_CIPHER_CTX *CTX, unsigned char *out, int *outl);

Cifre el texto plano restante.

Si se agrega 1 correctamente, se devolverá 0 si falla. En caso de éxito, outl genera la longitud del texto cifrado.

int EVP_decrypt init(EVP_CIPHER_CTX * CTX, const EVP_CIPHER *cipher, const unsigned char *key, const unsigned char * iv);

Inicializar el contexto de descifrado simétrico.

Si se agrega 1 correctamente, se devolverá 0 si falla.

int EVP _ decrypt update(EVP _ CIPHER _ CTX * CTX, unsigned char *out, int *outl, const unsigned char *in, int inl

Descifrar texto cifrado).

Si se agrega 1 correctamente, se devolverá 0 si falla. Si tiene éxito, outl genera la longitud del texto sin formato.

int EVP_decrypt final(EVP_CIPHER_CTX *CTX, unsigned char *outm, int *outl);

Descifra el texto cifrado restante.

Si se agrega 1 correctamente, se devolverá 0 si falla. Si tiene éxito, outl genera la longitud del texto sin formato.

int EVP_BytesToKey(const EVP_CIPHER *tipo, const EVP_MD *md,

const unsigned char *salt,

const unsigned char * datos, int datal, int count

unsigned char *key, unsigned char * iv);

Calcular la función de clave, que se calcula en función del tipo de algoritmo, el algoritmo abstracto, la sal y los datos de entrada Una clave simétrica e inicialización vector iv. La longitud de la clave de adición.

Esta función se utiliza en la función PEM_do_header() para generar una clave basada en la contraseña.

Esta estructura define el contenedor de almacenamiento para información de claves asimétricas. Significado del campo principal:

Escriba NID del algoritmo de cifrado asimétrico.

save_type: el tipo de PKEY guardado.

PKEY: puntero PKEY guardado, como el puntero de estructura RSA.

EVP _ PKEY * EVP _ PKEY _ new(void);

void EVP _ PKEY _ free(EVP _ PKEY * PKEY); Las funciones se utilizan para crear y liberar objetos de contexto PKEY.

int EVP _ PKEY _ asignar(EVP _ PKEY * PKEY, int type, void * key);

Estructura de contexto que especifica el tipo de algoritmo para la asociación PKEY. Por ejemplo, la definición de macro asociada con RSA es la siguiente:

#Define EVP_SignInit(a, b) EVP_DigestInit(a, b)

#Define EVP_SignUpdate(a, b, c ) EVP_DigestUpdate(a, b, c)

int EVP _ sign final(EVP _ MD _ CTX * CTX, char unsigned *md, int unsigned *s,

EVP _ PKEY *PKEY );

Cálculo de firma. Como puede verse en la definición de la macro, la abstracción en realidad se calcula primero y luego se cifra con la clave privada RSA.

Si se agrega 1 correctamente, se devolverá 0 si falla.

#Definir EVP_VerifyInit(a, b) EVP_DigestInit(a, b)

#Definir EVP_VerifyUpdate(a, b, c) EVP_DigestUpdate(a, b, c)

int EVP_verify final(EVP_MD_CTX *CTX, const unsigned char *sigbuf

unsigned int siglen, EVP_PKEY *PKEY);

Comprueba y firma Calcula el resultado. Como se puede ver en la definición de la macro, el resumen se calcula primero, luego la firma se descifra con la clave pública RSA y luego se compara con el resumen.

Si se agrega 1 correctamente, se devolverá 0 si falla.

El siguiente ejemplo demuestra el proceso de cálculo abstracto utilizando dos métodos MD5.

Salida:

EVP_DigestInit() ret:[1]

EVP _ digest update() ret:[1]

EVP_DigestFinal () ret:[1]

e 380 e 88 e 8d 09 ebf 8d 8659 a 15b 0 ea 70 b 5

EVP_Digest() ret:1

e 380 e 88 e 8d 09 ebf 8d 8659 a 15b 0 ea 70 b 5

El siguiente ejemplo demuestra el proceso de cifrado y descifrado utilizando DES. Para facilitar la implementación del programa, utilice std::string como excepción.

Salida:

EVP_EncryptInit() ret:[1]

EVP_encrypt update()ret:[1]

Diablo:[ 24]

EVP _ encrypt final()ret:[1]

nCipherLen:[8]

Tamaño de contraseña:[32]

EVP_DecryptInit() ret:[1]

EVP _ decrypt update() ret:[1]

nTextLen:[24]

EVP _ decrypt final()ret:[1]

nTextLen:[2]

Tamaño del texto:[26]Texto:[abcdefghijklmnopqrstuvwxyz]

El siguiente ejemplo demuestra el Se explica el proceso de uso de SHA1 para los cálculos de firma RSA y verificación de firma.

Salida:

RSA _ generar _ clave _ ex()ret:[1]

EVP _ PKEY _ asignar _ RSA()ret:[1 ]

EVP_SignInit() retirada:[1]

EVP_SignUpdate() retirada:[1]

EVP_SignFinal() retirada:[1]

sha1 len:[64]

EVP_VerifyInit() ret:[1]

EVP _ verificar actualización()ret:[1]

EVP_VerifyFinal () retirar:[1]