/*
Copyright (C) JAEHYUK CHO
All rights reserved.
Code by JaeHyuk Cho <mailto:minzkn@minzkn.com>
DES 알고리즘의 쉐도효과(avalanche effect)에 대한 과정확인을 위해 구현된 소스
- 질문출처 : [^https://www.facebook.com/photo.php?fbid=1122538724527526&set=gm.1420503504656848&type=3&theater]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define __hwport_peek_f(m_cast,m_base,m_offset) ((m_cast)(((unsigned char *)(m_base)) + (m_offset)))
#define __hwport_peek_const_f(m_cast,m_base,m_offset) ((m_cast)(((const unsigned char *)(m_base)) + (m_offset)))
#define def_hwport_des_block_size 8
#define def_hwport_des_user_key_size def_hwport_des_block_size
#define def_hwport_des_rounds 16
#define def_hwport_des_round_key_size (48 * def_hwport_des_rounds)
void hwport_hex_dump(const char *s_title, const void *s_data, int s_size);
void *hwport_des_block(int s_function, void *s_data, const void *s_round_key);
void *hwport_des_make_round_key(void *s_round_key, const void *s_user_key);
void des_avalanche_effect_test(unsigned char *s_user_key, unsigned char *s_data_block);
int main(void);
/* initial permutation table */
static int const __gc_hwport_des_ip_table[2][64] = {
{
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,
56, 48, 40, 32, 24, 16, 8, 0, 58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6
},
{ /* reverse */
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, 32, 0, 40, 8, 48, 16, 56, 24
}
};
/* key permutation table */
static int const __gc_hwport_des_kp_table[56] = {
56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
};
/* key left shift table */
static unsigned char const __gc_hwport_des_kls_table[16] = {
0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0
};
/* compression permutation table */
static int const __gc_hwport_des_cp_table[48] = {
13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31
};
/* expansion permutation table */
static int const __gc_hwport_des_ep_table[48] = {
31, 0, 1, 2, 3, 4, 3, 4, 5, 6, 7, 8, 7, 8, 9, 10, 11, 12, 11, 12, 13, 14, 15, 16,
15, 16, 17, 18, 19, 20, 19, 20, 21, 22, 23, 24, 23, 24, 25, 26, 27, 28, 27, 28, 29, 30, 31, 0
};
/* S-Box substitution table */
static unsigned char const __gc_hwport_des_sbox_table[8][4][16] = {
{ /* S1 */
{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}
},
{ /* S2 */
{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}
},
{ /* S3 */
{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}
},
{ /* S4 */
{ 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}
},
{ /* S5 */
{ 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}
},
{ /* S6 */
{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}
},
{ /* S7 */
{ 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}
},
{ /* S8 */
{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}
}
};
/* P-Box permutation table */
static int const __gc_hwport_des_pbox_table[32] = {
15, 6, 19, 20, 28, 11, 27, 16, 0, 14, 22, 25, 4, 17, 30, 9,
1, 7, 23, 13, 31, 26, 2, 8, 18, 12, 29, 5, 21, 10, 3, 24
};
/* inline function : bit to byte */
#define hwport_des_bit_to_byte(m_target,m_source,m_size) \
do {\
unsigned char *__sm_target__ = (unsigned char *)(m_target), __sm_byte__;\
const unsigned char *__sm_source__ = (const unsigned char *)(m_source);\
size_t __sm_size__ = ((size_t)(m_size)) << 3, __sm_offset__ = (size_t)0;\
do {\
__sm_byte__ = __sm_source__[__sm_offset__ >> 3];\
__sm_target__[__sm_offset__++] = (__sm_byte__ >> 7) & ((unsigned char)0x01);\
__sm_target__[__sm_offset__++] = (__sm_byte__ >> 6) & ((unsigned char)0x01);\
__sm_target__[__sm_offset__++] = (__sm_byte__ >> 5) & ((unsigned char)0x01);\
__sm_target__[__sm_offset__++] = (__sm_byte__ >> 4) & ((unsigned char)0x01);\
__sm_target__[__sm_offset__++] = (__sm_byte__ >> 3) & ((unsigned char)0x01);\
__sm_target__[__sm_offset__++] = (__sm_byte__ >> 2) & ((unsigned char)0x01);\
__sm_target__[__sm_offset__++] = (__sm_byte__ >> 1) & ((unsigned char)0x01);\
__sm_target__[__sm_offset__++] = (__sm_byte__ >> 0) & ((unsigned char)0x01);\
}while(__sm_offset__ < __sm_size__);\
}while(0)
/* inline function : byte to bit */
#define hwport_des_byte_to_bit(m_target,m_source,m_size) \
do {\
unsigned char *__sm_target__ = (unsigned char *)(m_target), *__sm_source__ = (unsigned char *)(m_source), __sm_byte__ = (unsigned char)0;\
size_t __sm_size__ = (size_t)(m_size), __sm_offset__ = (size_t)0;\
while(__sm_offset__ < __sm_size__) {\
__sm_byte__ = (__sm_byte__ << 1) | __sm_source__[__sm_offset__++];\
if((__sm_offset__ % ((size_t)8)) != ((size_t)0)) { continue; }\
__sm_target__[(__sm_offset__ - ((size_t)1)) >> 3] = __sm_byte__;\
}\
}while(0)
#define def_hwport_des_encrypt_function ((int)0)
#define def_hwport_des_decrypt_function ((int)1)
void hwport_hex_dump(const char *s_title, const void *s_data, int s_size)
{
int s_o,s_w,s_i;unsigned char s_b[17];
if(s_title != ((const char *)0)) { (void)printf("%s:\n", s_title); }
s_b[16]='\0';s_o=(int)0;
while(s_o<(s_size)){
s_w=((s_size)-s_o)<16?((s_size)-s_o):16;/* printf("%08X",s_o); */printf(" ");for(s_i=0;s_i<s_w;s_i++){if(s_i==8)printf(" | ");else printf(" ");
s_b[s_i]=*(((const unsigned char *)(s_data))+s_o+s_i);printf("%02X",s_b[s_i]);if((s_b[s_i]>=0x7f)||(s_b[s_i]<' '))s_b[s_i]='.';}
while(s_i<16){if(s_i==8)printf(" ");else printf(" ");s_b[s_i]=' ';s_i++;}
printf(" [%s]\n",(char *)s_b);s_o+=16;}
#if 0L
(void)printf("\n");
#endif
}
void *hwport_des_block(int s_function, void *s_data, const void *s_round_key)
{
unsigned char s_temp[64], s_ip[64], s_next_left[32], s_ep[48], *s_left, *s_right, *s_ep_ptr, s_value;
int s_index, s_round;
/* bit to byte */
hwport_des_bit_to_byte(&s_temp[0], s_data, 8);
/* initial permutation */
for(s_index = (int)0;s_index < ((int)64);s_index++) { s_ip[s_index] = s_temp[__gc_hwport_des_ip_table[0][s_index]]; }
/* left & right */
if(s_function == def_hwport_des_encrypt_function) {
s_left = (unsigned char *)(&s_ip[0]);
s_right = (unsigned char *)(&s_ip[32]);
}
else {
s_left = (unsigned char *)(&s_ip[32]);
s_right = (unsigned char *)(&s_ip[0]);
}
/* 16 round loop */
for(s_round = (int)0;s_round < ((int)def_hwport_des_rounds);s_round++) {
/* backup right(next left) */
for(s_index = (int)0;s_index < ((int)32);s_index++) { s_next_left[s_index] = s_right[s_index]; }
/* expansion permutation with xor */
if(s_function == def_hwport_des_encrypt_function) {
/* spinning direction key */
for(s_index = (int)0;s_index < ((int)48);s_index++) {
s_ep[s_index] = s_right[__gc_hwport_des_ep_table[s_index]] ^ (*__hwport_peek_const_f(const unsigned char *, s_round_key, (s_round * ((int)48)) + s_index));
}
}
else {
/* reverse direction key */
for(s_index = (int)0;s_index < ((int)48);s_index++) {
s_ep[s_index] = s_right[__gc_hwport_des_ep_table[s_index]] ^ (*__hwport_peek_const_f(const unsigned char *, s_round_key, ((((int)(def_hwport_des_rounds - 1)) - s_round) * ((int)48)) + s_index));
}
}
/* S-Box substitution */
for(s_index = (int)0;s_index < ((int)8);s_index++) {
s_ep_ptr = (unsigned char *)(&s_ep[s_index * ((int)6)]);
s_value = __gc_hwport_des_sbox_table[s_index][(s_ep_ptr[0] << 1) | s_ep_ptr[5]][(s_ep_ptr[1] << 3) | (s_ep_ptr[2] << 2) | (s_ep_ptr[3] << 1) | s_ep_ptr[4]];
s_temp[(s_index << 2) + ((int)0)] = (s_value >> 3) & ((unsigned char)0x01);
s_temp[(s_index << 2) + ((int)1)] = (s_value >> 2) & ((unsigned char)0x01);
s_temp[(s_index << 2) + ((int)2)] = (s_value >> 1) & ((unsigned char)0x01);
s_temp[(s_index << 2) + ((int)3)] = (s_value >> 0) & ((unsigned char)0x01);
}
/* P-Box permutation */
for(s_index = (int)0;s_index < ((int)32);s_index++) {
s_right[s_index] = s_temp[__gc_hwport_des_pbox_table[s_index]] ^ s_left[s_index];
s_left[s_index] = s_next_left[s_index];
}
#if 1L /* IP round dump for avalanche effect ###################### */
do {
unsigned char s_data2[ def_hwport_des_block_size ];
if(s_round == 0) { (void)printf("IP round:\n"); }
hwport_des_byte_to_bit(s_data2, &s_ip[0], 64);
hwport_hex_dump((const char *)0, s_data2, sizeof(s_data2));
}while(0);
#endif
}
/* merge left & right */
if(s_function == def_hwport_des_encrypt_function) {
for(s_index = (int)0;s_index < ((int)32);s_index++) {
s_temp[s_index] = s_left[s_index];
s_temp[s_index + ((int)32)] = s_right[s_index];
}
}
else {
for(s_index = (int)0;s_index < ((int)32);s_index++) {
s_temp[s_index] = s_right[s_index];
s_temp[s_index + ((int)32)] = s_left[s_index];
}
}
/* reverse initial permutation */
for(s_index = (int)0;s_index < ((int)64);s_index++) { s_ip[s_index] = s_temp[__gc_hwport_des_ip_table[1][s_index]]; }
/* byte to bit */
hwport_des_byte_to_bit(s_data, &s_ip[0], 64);
return(s_data);
}
void *hwport_des_make_round_key(void *s_round_key, const void *s_user_key)
{
unsigned char s_temp[64], s_key56[56];
int s_index, s_round;
/* bit to byte */
hwport_des_bit_to_byte(&s_temp[0], s_user_key, 8);
/* key permutation */
for(s_index = (int)0;s_index < ((int)56);s_index++) { s_key56[s_index] = s_temp[__gc_hwport_des_kp_table[s_index]]; }
for(s_round = (int)0;s_round < ((int)def_hwport_des_rounds);s_round++) {
if(__gc_hwport_des_kls_table[s_round] == ((unsigned char)0)) { /* left (shift) rotate 1 */
s_temp[0] = s_key56[0];
s_temp[1] = s_key56[28];
for(s_index = (int)0;s_index < ((int)27);s_index++) {
s_key56[s_index] = s_key56[s_index + ((int)1)];
s_key56[s_index + ((int)28)] = s_key56[s_index + ((int)(28 + 1))];
}
s_key56[27] = s_temp[0];
s_key56[28 + 27] = s_temp[1];
}
else { /* left (shift) rotate 2 */
s_temp[0] = s_key56[0];
s_temp[1] = s_key56[1];
s_temp[2] = s_key56[28];
s_temp[3] = s_key56[28 + 1];
for(s_index = (int)0;s_index < ((int)26);s_index++) {
s_key56[s_index] = s_key56[s_index + ((int)2)];
s_key56[s_index + ((int)28)] = s_key56[s_index + ((int)(28 + 2))];
}
s_key56[26] = s_temp[0];
s_key56[27] = s_temp[1];
s_key56[28 + 26] = s_temp[2];
s_key56[28 + 27] = s_temp[3];
}
/* compression permutation */
for(s_index = (int)0;s_index < ((int)48);s_index++) {
*__hwport_peek_f(unsigned char *, s_round_key, (s_round * ((int)48)) + s_index) = s_key56[__gc_hwport_des_cp_table[s_index]];
}
}
return(s_round_key);
}
void des_avalanche_effect_test(unsigned char *s_user_key, unsigned char *s_data_block)
{
unsigned char s_round_key[ def_hwport_des_round_key_size ]; /* (16 * 48) bytes */
hwport_hex_dump("user key", &s_user_key[0], sizeof(s_user_key));
(void)hwport_des_make_round_key(&s_round_key[0], &s_user_key[0]);
#if 0 /* show round key */
do {
int s_index0, s_index1, s_index2;
(void)printf("round key:\n");
for(s_index0 = 0;s_index0 < def_hwport_des_rounds;s_index0++) {
(void)printf("[%2d] ", s_index0);
for(s_index1 = 0;s_index1 < 48;s_index1 += 8) {
for(s_index2 = 0;s_index2 < 8;s_index2++) {
(void)printf("%d", (unsigned int)s_round_key[s_index0 + s_index1 + s_index2]);
}
(void)printf("b ");
}
(void)printf("\n");
}
(void)printf("\n");
}while(0);
#endif
hwport_hex_dump("data", &s_data_block[0], def_hwport_des_block_size);
hwport_hex_dump("encrypt",
hwport_des_block(def_hwport_des_encrypt_function, s_data_block, &s_round_key[0]),
(size_t)def_hwport_des_block_size
);
#if 0L
hwport_hex_dump("decrypt",
hwport_des_block(def_hwport_des_decrypt_function, s_data_block, &s_round_key[0]),
(size_t)def_hwport_des_block_size
);
#endif
}
int main(void)
{
unsigned char s_user_key[2][ def_hwport_des_user_key_size ] = { /* password */
{0x0f, 0x15, 0x71, 0xc9, 0x47, 0xd9, 0xe8, 0x59},
{0x1f, 0x15, 0x71, 0xc9, 0x47, 0xd9, 0xe8, 0x59}
};
char s_data_block[2][def_hwport_des_block_size] = { /* plain text */
{0x02, 0x46, 0x8a, 0xce, 0xec, 0xa8, 0x64, 0x20},
{0x02, 0x46, 0x8a, 0xce, 0xec, 0xa8, 0x64, 0x20}
};
int s_test_seq;
for(s_test_seq = 0;s_test_seq < 2;s_test_seq++) {
(void)printf("test des #%d\n~~~~~~~~~~~\n\n", s_test_seq + 1);
des_avalanche_effect_test(
(unsigned char *)(&s_user_key[s_test_seq][0]),
(unsigned char *)(&s_data_block[s_test_seq][0])
);
}
return(EXIT_SUCCESS);
}
/* vim: set expandtab: */
/* End of source */