Probando Triple DES implementación en lenguaje C en GNU/Linux.
Probando Triple DES como método de encriptado
El otro día uno de nuestros colaboradores (K) estuvo revisando el algoritmo de encriptación Triple DES*. Después de hacer una búsqueda rápida en emacs-w3m encontró esta pagina web:
https://www.techiedelight.com/3-des-implementation-c/
Eso le permitió muy rápidamente cambiar el código un poco, para evitar usar archivos:
// cc -o out.bin base64.c 3des.c -lm -g3 -Wall -O0 //{weird worked with clang but no with gcc} #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <math.h> #include <time.h> #include "base64.h" #define THREEDES_BUFFER_SIZE 4096 int IP[] = { 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 }; int E[] = { 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 }; int P[] = { 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 }; int FP[] = { 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 }; int S1[4][16] = { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 }; int S2[4][16] = { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 }; int S3[4][16] = { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 }; int S4[4][16] = { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 }; int S5[4][16] = { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 }; int S6[4][16] = { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 }; int S7[4][16]= { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 }; int S8[4][16]= { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 }; int PC1[] = { 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 }; int PC2[] = { 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 }; int SHIFTS[] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; int LEFT[17][32], RIGHT[17][32]; int IPtext[64]; int EXPtext[48]; int XORtext[48]; int X[8][6]; int X2[32]; int R[32]; int g_key56bit[56]; int g_key48bit[17][48]; int CIPHER[64]; int ENCRYPTED[64]; void expansion_function(int pos, int text) { for (int i = 0; i < 48; i++) if(E[i] == pos + 1) EXPtext[i] = text; } int initial_permutation(int pos, int text) { int i; for (i = 0; i < 64; i++) if(IP[i] == pos + 1) break; IPtext[i] = text; return 0; } int threedes_f1(int i) { int r, c, b[6]; for (int j = 0; j < 6; j++) b[j] = X[i][j]; r = b[0] * 2 + b[5]; c = 8 * b[1] + 4 * b[2] + 2 * b[3] + b[4]; if(i == 0) return S1[r][c]; else if(i == 1) return S2[r][c]; else if(i == 2) return S3[r][c]; else if(i == 3) return S4[r][c]; else if(i == 4) return S5[r][c]; else if(i == 5) return S6[r][c]; else if(i == 6) return S7[r][c]; else if(i == 7) return S8[r][c]; return 0; } int threedes_XOR(int a, int b) { return (a ^ b); } int threedes_to_bits(int value) { int k, j, m; static int i; if(i % 32 == 0) i = 0; for (j = 3; j >= 0; j--) { m = 1 << j; k = value & m; if(k == 0) X2[3 - j + i] = '0' - 48; else X2[3 - j + i] = '1' - 48; } i = i + 4; return 0; } int threedes_s_box(int XORtext[]) { int k = 0; int value; for (int i = 0; i < 8; i++) for (int j = 0; j < 6; j++) X[i][j] = XORtext[k++]; for (int i = 0; i < 8; i++) { value = threedes_f1(i); threedes_to_bits(value); } return 0; } int threedes_p_box(int pos, int text) { int i; for (i = 0; i < 32; i++) if(P[i] == pos + 1) break; R[i] = text; return 0; } void threedes_cipher(int Round, int mode) { for (int i = 0; i < 32; i++) expansion_function(i, RIGHT[Round - 1][i]); for (int i = 0; i < 48; i++) { if(mode == 0) XORtext[i] = threedes_XOR(EXPtext[i], g_key48bit[Round][i]); else XORtext[i] = threedes_XOR(EXPtext[i], g_key48bit[17 - Round][i]); } threedes_s_box(XORtext); for (int i = 0; i < 32; i++) threedes_p_box(i, X2[i]); for (int i = 0; i < 32; i++) RIGHT[Round][i] = threedes_XOR(LEFT[Round - 1][i], R[i]); } void final_permutation(int pos, int text) { int i; for (i = 0; i < 64; i++) if(FP[i] == pos + 1) break; ENCRYPTED[i] = text; } void convert_to_binary(int n, char _uno[]) { int k, m; for (int i = 7; i >= 0; i--) { m = 1 << i; k = n & m; _uno[ strlen((const char*)_uno) ] = ((k == 0)?48:49); } } int convert_char_to_bit(long int _n, const char *_plain_text, char _uno[]) { char ch; int i = 0; int n = _n * 8; while (i< n) { ch = _plain_text[i]; if((int)ch == -1) break; i++; convert_to_binary(ch, _uno); } return 0; } void convert_array_to_bits(int ch[], int _out_len, char *_array_out_block) { int value = 0; char *myblock; myblock = _array_out_block; for (int i = 7; i >= 0; i--) { value += (int)pow(2, i) * ch[7 - i]; } myblock[ _out_len ] = (char)value; } int bit_to_char(char *_array_out_block) { int j; j = 0; for (int i = 0; i < 64; i = i + 8) { convert_array_to_bits(&ENCRYPTED[i], j, _array_out_block); j++; } return 0; } void threedes_key56to48(int round, int pos, int text) { int i; for (i = 0; i < 56; i++) if(PC2[i] == pos + 1) break; g_key48bit[round][i] = text; } int threedes_key64to56(int pos, int text) { int i; for (i = 0; i < 56; i++) if(PC1[i] == pos + 1) break; g_key56bit[i] = text; return 0; } void threedes_key64to48(unsigned int key[]) { int k, backup[17][2]; int CD[17][56]; int C[17][28], D[17][28]; for (int i = 0; i < 64; i++) threedes_key64to56(i, key[i]); for (int i = 0; i < 56; i++) if(i < 28) C[0][i] = g_key56bit[i]; else D[0][i - 28] = g_key56bit[i]; for (int x = 1; x < 17; x++) { int shift = SHIFTS[x - 1]; for (int i = 0; i < shift; i++) backup[x - 1][i] = C[x - 1][i]; for (int i = 0; i < (28 - shift); i++) C[x][i] = C[x - 1][i + shift]; k = 0; for (int i = 28 - shift; i < 28; i++) C[x][i] = backup[x - 1][k++]; for (int i = 0; i < shift; i++) backup[x - 1][i] = D[x - 1][i]; for (int i = 0; i < (28 - shift); i++) D[x][i] = D[x - 1][i + shift]; k = 0; for (int i = 28 - shift; i < 28; i++) D[x][i] = backup[x - 1][k++]; } for (int j = 0; j < 17; j++) { for (int i = 0; i < 28; i++) CD[j][i] = C[j][i]; for (int i = 28; i < 56; i++) CD[j][i] = D[j][i - 28]; } for (int j = 1; j < 17; j++) for (int i = 0; i < 56; i++) threedes_key56to48(j, i, CD[j][i]); } void threedes_encryption(long int plain[], char _out[]) { for (int i = 0; i < 64; i++) initial_permutation(i, plain[i]); for (int i = 0; i < 32; i++) LEFT[0][i] = IPtext[i]; for (int i = 32; i < 64; i++) RIGHT[0][i - 32] = IPtext[i]; for (int k = 1; k < 17; k++) { threedes_cipher(k, 0); for (int i = 0; i < 32; i++) LEFT[k][i] = RIGHT[k - 1][i]; } for (int i = 0; i < 64; i++) { if(i < 32) CIPHER[i] = RIGHT[16][i]; else CIPHER[i] = LEFT[16][i - 32]; final_permutation(i, CIPHER[i]); } for (int i = 0; i < 64; i++) { _out[i] = ENCRYPTED[i] ==1 ?'1':'0'; } } void threedes_decryption(long int plain[], char *_out) { for (int i = 0; i < 64; i++) initial_permutation(i, plain[i]); for (int i = 0; i < 32; i++) LEFT[0][i] = IPtext[i]; for (int i = 32; i < 64; i++) RIGHT[0][i - 32] = IPtext[i]; for (int k = 1; k < 17; k++) { threedes_cipher(k, 1); for (int i = 0; i < 32; i++) LEFT[k][i] = RIGHT[k - 1][i]; } for (int i = 0; i < 64; i++) { if(i < 32) CIPHER[i] = RIGHT[16][i]; else CIPHER[i] = LEFT[16][i - 32]; final_permutation(i, CIPHER[i]); } for (int i = 0; i < 64; i++) { _out[i] = (ENCRYPTED[i] == 1)?'1':'0'; } } void decrypt_with_key(long int n, const char *_str_to_decrypt, char _out[], char *_array_out_block ) { // destroy contents of these files (from previous runs) {_out, _array_out_block} long int plain[n * 64]; int i = -1; int count; char ch; count = strlen(_str_to_decrypt); while (i < count) { ch = _str_to_decrypt[i+1]; plain[++i] = ch - 48; } for (int i = 0; i < n; i++) { threedes_decryption(plain + i * 64, _out); // dos.txt bit_to_char(_array_out_block); // result.txt } } void encrypt_with_key(long int n, const char *_str_to_encrypt, char _out[]) { memset(_out, 0, THREEDES_BUFFER_SIZE); long int plain[n * 64]; int i = -1; int count; char ch; count = strlen(_str_to_encrypt); while (i < count) { ch = _str_to_encrypt[i+1]; plain[++i] = ch - 48; } for (int i = 0; i < n; i++) { threedes_encryption(plain + 64 * i, _out); // 2.txt } } // key could be on a database or file as it was originally; K1= first 64 chars on the array void fill_and_adapt_key(unsigned int _key[]) { int i = 0, ch; unsigned int key_char[192] = { '0', '1', '1', '0', '0', '0', '1', '0', '0', '1', '1', '0', '0', '0', '0', '1', '0', '1', '1', '0', '1', '1', '0', '0', '0', '1', '1', '1', '0', '1', '0', '0', '0', '1', '1', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '0', '1', '0', '0', '1', '1', '0', '0', '0', '0', '1', '0', '1', '1', '1', '0', '0', '1', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0', '1', '1', '1', '0', '0', '1', '0', '0', '1', '1', '0', '0', '0', '0', '1', '0', '1', '1', '0', '1', '1', '1', '0', '0', '1', '1', '0', '0', '0', '1', '1', '0', '1', '1', '0', '1', '0', '0', '1', '0', '1', '1', '1', '0', '0', '1', '1', '0', '1', '1', '0', '0', '0', '1', '1', '0', '1', '1', '0', '1', '0', '1', '0', '0', '1', '1', '0', '0', '1', '0', '1', '0', '1', '1', '1', '0', '0', '1', '0', '0', '1', '1', '0', '0', '1', '0', '1', '0', '1', '1', '0', '1', '1', '0', '1', '0', '1', '1', '0', '1', '0', '0', '1', '0', '1', '1', '0', '0', '0', '0', '1', '0', '1', '1', '1', '0', '0', '1', '1' }; while (i < 192) { ch = key_char[i]; _key[i++] = ch - 48; } } const char *encrypt_entry(const char *_input_for_encryption, char _encrypt_block[]) { unsigned char myunotxt[THREEDES_BUFFER_SIZE]; unsigned char mydostxt[THREEDES_BUFFER_SIZE]; unsigned char myresulttxt[THREEDES_BUFFER_SIZE]; unsigned int key[192]; size_t ret_code; long int n; fill_and_adapt_key(key); memset(myunotxt, 0, THREEDES_BUFFER_SIZE); memset(mydostxt, 0, THREEDES_BUFFER_SIZE); memset(myresulttxt, 0, THREEDES_BUFFER_SIZE); n = strlen(_input_for_encryption) / 8; // @minimun 8 convert_char_to_bit(n, _input_for_encryption, (char*)myunotxt); // convert _input_for_encryption to bit // Encryption starts // DES encrypt with K1, DES decrypt with K2, then DES encrypt with K3. threedes_key64to48(key); encrypt_with_key(n, (const char*)myunotxt, (char*)mydostxt); // convert using K1 threedes_key64to48(key + 64); decrypt_with_key(n, (const char*)mydostxt, (char*)myunotxt, (char*)myresulttxt); // convert using K2 threedes_key64to48(key + 128); encrypt_with_key(n, (const char*)myunotxt, (char*)mydostxt); // convert using K3 memset(myresulttxt, 0, THREEDES_BUFFER_SIZE); // clean before calling bit_to_char bit_to_char((char*)myresulttxt); ret_code = base64_encode((char*)_encrypt_block, THREEDES_BUFFER_SIZE, (const char*)myresulttxt, strlen((const char*)myresulttxt)); memset(myunotxt, 0, THREEDES_BUFFER_SIZE); memset(mydostxt, 0, THREEDES_BUFFER_SIZE); memset(myresulttxt, 0, THREEDES_BUFFER_SIZE); return (ret_code != -1)?_encrypt_block:NULL; } const char *decrypt_entry(const char *_input_for_decryption, int _n_value, char _decrypt_block[]) { unsigned char myunotxt[THREEDES_BUFFER_SIZE]; unsigned char mydostxt[THREEDES_BUFFER_SIZE]; unsigned char myresulttxt[THREEDES_BUFFER_SIZE]; unsigned int key[192]; size_t ret_code; fill_and_adapt_key(key); memset(myunotxt, 0, THREEDES_BUFFER_SIZE); memset(mydostxt, 0, THREEDES_BUFFER_SIZE); memset(myresulttxt, 0, THREEDES_BUFFER_SIZE); ret_code = base64_decode(_decrypt_block, base64_decoded_length(strlen(_input_for_decryption)), _input_for_decryption, strlen(_input_for_decryption)); if (ret_code == -1) { fprintf(stderr, "my_new_decrpyt Err when decoding base64\n"); } convert_char_to_bit(_n_value, _decrypt_block, (char*)myunotxt); strcpy((char*)mydostxt, (const char*)myunotxt); // uno to dos memset(myunotxt, 0, THREEDES_BUFFER_SIZE); memset(_decrypt_block, 0, THREEDES_BUFFER_SIZE); // threedes_decryption starts (reverse of threedes_encryption) // decrypt with K3, encrypt with K2, then decrypt with K1. threedes_key64to48(key + 128); decrypt_with_key(_n_value, (const char*)mydostxt, (char*)myunotxt, (char*)myresulttxt); // convert using K3 threedes_key64to48(key + 64); encrypt_with_key(_n_value, (const char*)myunotxt, (char*)mydostxt); // convert using K2 threedes_key64to48(key); decrypt_with_key(_n_value, (const char*)mydostxt, (char*)myunotxt, (char*)myresulttxt); // convert using K3 {also put the content on result} strcpy(_decrypt_block, (const char*)myresulttxt); // result to block memset(myunotxt, 0, THREEDES_BUFFER_SIZE); memset(mydostxt, 0, THREEDES_BUFFER_SIZE); memset(myresulttxt, 0, THREEDES_BUFFER_SIZE); return (ret_code != -1)?_decrypt_block:NULL; } int main() { const char *input_for_encryption = "kipuamut"; const char *encryption_output; const char *input_for_decryption = "W5i6FPHcSwk="; const char *decryption_output; char encrypt_block[THREEDES_BUFFER_SIZE]; char decrypt_block[THREEDES_BUFFER_SIZE]; memset(encrypt_block, 0, THREEDES_BUFFER_SIZE); memset(decrypt_block, 0, THREEDES_BUFFER_SIZE); encryption_output = encrypt_entry(input_for_encryption, encrypt_block); if (encryption_output) { fprintf(stdout, "mymain base64-encoded=%s\n", encryption_output); } // n_value (second parameter) could need to be stored on database perhaps {YMMV} decryption_output = decrypt_entry(input_for_decryption, (strlen(input_for_encryption) / 8), decrypt_block); if (decryption_output) { fprintf(stdout, "mymain desencriptado=%s\n", decryption_output); } memset(encrypt_block, 0, THREEDES_BUFFER_SIZE); memset(decrypt_block, 0, THREEDES_BUFFER_SIZE); return 0; }
Al terminar de codificar, nuestro colaborador se dio cuenta que el código le arrojaba un 'segmentation fault'. Tardo un poco en recompilarlo con clang y en el clang el código se ejecuta como deberia.
La fecha de este articulo es 2021-01-25.
En este caso la versión del gcc es:
,—- [ ]
> | cc (GCC) 10.2.0 |
> | Copyright (C) 2020 Free Software Foundation, Inc. |
> | This is free software; see the source for copying conditions. There is NO |
> | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
`—-
la versión del clang es:
,—- [ ]
> | clang version 11.0.1 |
`—-
Si alguien tiene una idea de como resolver este problema 'segmentation fault' que presenta el gcc, nos lo hace saber por correo electrónico dirigido a:
—8<—————cut here—————start————->8—
c
o
n
t
a
c
t
o
@kipuamutay.com
—8<—————cut here—————end—————>8—
Los otros 2 archivos base64.c y base64.h pueden ser descargados del ccan:
https://ccodearchive.net/list.html
Disfruten codificando.
Last change: 26.01.2021 14:18 |