¿Cómo se usa la biblioteca de criptas en C para el cifrado DES? (setkey, cifrar, cripta, etc.)

StackOverflow https://stackoverflow.com/questions/1418846

  •  07-07-2019
  •  | 
  •  

Pregunta

Necesito hacer un simple cifrado DES en C para interactuar con algún código antiguo. Por lo que entiendo, puedes usar la "cripta" biblioteca para esto, con las funciones setkey, encrypt, crypt, etc. He estado jugando con él y no puedo hacerlo bien. Falta el ejemplo en la página de manual para setkey / encrypt.

Quiero obtener el mismo resultado que podría obtener con un código Java (ver más abajo).

Entonces, digamos que tengo dos matrices de caracteres en C.

char *message = "hellothe";
char *key = "iamakey0";

¿Alguien puede dar un ejemplo de cómo cifrarlos con setkey / encrypt y obtener el mismo resultado que obtendría del código java? Me doy cuenta de que tiene que poner el mensaje y la clave en una matriz de 64 bytes donde cada carácter representa un poco, pero algo de eso también es confuso. Al parecer, ¿también tienes que tener la paridad de bits correcta o algo así?

public static byte[] encryptDES(byte[] message, byte[] key) {
    byte[] encrypted = new byte[0];
    try{
        Cipher c = Cipher.getInstance("DES");
        c.init(Cipher.ENCRYPT_MODE,new SecretKeySpec(key,"DES"));
        encrypted = c.doFinal(message);
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    return encrypted;
}
¿Fue útil?

Solución

Debido a que está llamando a Cipher.getInstance con solo la cadena " DES " , no está especificando un modo de cifrado o método de relleno. Esto significa que obtiene los valores predeterminados, que dependen del proveedor de criptografía de Java que esté utilizando; debe saber exactamente qué son para escribir C compatible (realmente debería especificarlos en lugar de confiar en los valores predeterminados).

Si está utilizando el proveedor SunJCE, los valores predeterminados para DES son el modo ECB y el relleno PKCS # 5. Probablemente, la mejor manera de hacerlo es utilizar OpenSSL u otra biblioteca criptográfica carnosa, pero si desea utilizar funciones que generalmente se encuentran en la biblioteca C estándar en plataformas tipo UNIX, la familia ecb_crypt de será mucho más fácil trabajar con las funciones que con la familia setkey / encrypt .

Deberá agregar el relleno PKCS # 5 al cifrar, y verificarlo (y descartarlo) al descifrar). La siguiente función ecb_pkcs5_encrypt debería hacer el equivalente aproximado del código Java anterior usando esas funciones.

/* Returns a newly-allocated buffer containing the contents of `data',
 * padded out to a multiple of 8 bytes using PKCS #5 style padding.
 *
 * If `padded_len` is non-NULL, the value it points to is updated to
 * the size of the padded output data.
 *
 * Returns NULL on error.
 */
char *pad_pkcs5(const char *data, size_t data_len, size_t *padded_len)
{
    char *padded_data;
    unsigned padding_len = 8 - (data_len % 8);
    const char padding = padding_len;
    char *pad_ptr;

    /* check for length overflow */
    if (data_len + padding_len < data_len)
        return NULL;

    /* Copy data into a new buffer and pad it out */
    padded_data = malloc(data_len + padding_len);

    if (!padded_data)
        return NULL;

    memcpy(padded_data, data, data_len);

    if (*padded_len)
    {
        *padded_len = data_len + padding_len;
    }

    /* Add the padding bytes */
    pad_ptr = padded_data + data_len;
    while (padding_len--)
    {
        *pad_ptr++ = padding;
    }

    return padded_data;
}

/* Returns a newly-allocated buffer containing the contents of `data',
 * encrypted with `key' using DES/ECB/PKCS5.
 *
 * If `out_len` is non-NULL, the value it points to is updated to
 * the size of the encrypted output data (which will always be a
 * multiple of 8).
 *
 * Returns NULL on error.
 */
char *ecb_pkcs5_encrypt(const char *key, const char *data, size_t data_len, size_t *out_len)
{
    char des_key[8];
    char *padded_data;
    size_t padded_len;
    int status;

    /* One of the few cases where strncpy() is exactly what we want! */
    strncpy(des_key, key, sizeof des_key);
    des_setparity(des_key);

    padded_data = pad_pkcs5(data, data_len, &padded_len);

    if (!padded_data)
        return NULL;

    status = ecb_crypt(des_key, padded_data, padded_len, DES_ENCRYPT);

    if (DES_FAILED(status))
        return NULL;

    if (out_len)
        *out_len = padded_len;

    return padded_data;
}

Otros consejos

No uses crypt (). Utiliza algún algoritmo no estándar, por lo que será muy difícil interoperar con otros sistemas. Además, DES no es seguro de todos modos.

Le sugiero que use OpenSSL en C. La mayoría de sus cifrados son compatibles con JCE.

Si realmente tiene que usar cripta, Sun's JRE viene con una clase para manejar cripta,

   com.sun.security.auth.module.Crypt

Esta es una clase interna, por lo que la documentación no está allí. Simplemente lea el código fuente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top