数学形式:
https://en.wikipedia.org/wiki/Data_Encryption_Standard
总体结构
定义常用运算
定义常用函数,分别用于将字符串分割,合并,按位异或,置换,文件读写
/*tool.h*/
#ifndef _tool_h_
#define _tool_h_
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void dividegroup(char *c, char *l, char *r, int num);
void mergegroup(char *l, char *r, char *c, int num);
void xor(char* c1, char* c2, char* c,int num);
void permutation(char*x, char*y, const char*f, int size);
void lshift(char * source, char * destination, unsigned int len, unsigned int num);
void rshift(char * source, char * destination, unsigned int len, unsigned int num);
/**
* @description: load hex string from file and convert it to bin string
* @param {FILE} *file
* @param {char} *bin
* @param {int} len: length of bin string
* @return {0: success 1: no more data need te be read -1: error}
*/
int hexfile_to_bin(FILE *file, char *bin, int len);
/**
* @description: convert bin string to hex and save it to file
*/
bool bin_to_hexfile(char *bin, FILE *file, int len);
#define ASSERT(condition) \
if (!condition) \
{ \
printf("Assertion failed: line %d file %s", __LINE__, __FILE__); \
exit(1); \
}
# endif
/*tool.c*/
#include "tool.h"
// divide c to l and r
void dividegroup(char *c, char *l, char *r, int num)
{
strncpy(l, c, num / 2);
strncpy(r, c + num / 2, num / 2);
}
void mergegroup(char *l, char *r, char *c, int num)
{
strncpy(c, l, num / 2);
strncpy(c + num / 2, r, num / 2);
}
void xor (char *c1, char *c2, char *c, int num) {
for (int i = 0; i < num; i++)
{
c[i] = (c1[i] - '0' + c2[i] - '0') % 2 + '0';
}
}
void permutation(char *x, char *y, const char *f, int size)
{
for (int i = 0; i < size; i++)
{
y[i] = x[f[i] - 1];
}
}
void lshift(char *source, char *destination, unsigned int len, unsigned int num)
{
char *c = (char *)malloc(sizeof(char) * len);
for (int i = 0; i < len; i++)
{
c[i] = source[(i + num) % len];
}
strncpy(destination, c, len);
free(c);
}
void rshift(char *source, char *destination, unsigned int len, unsigned int num)
{
char *c = (char *)malloc(sizeof(char) * len);
for (int i = 0; i < len; i++)
{
c[i] = source[(i - num) % len];
}
strncpy(destination, c, len);
free(c);
}
/**
* @description: load hex string from file and convert it to bin string
* @param {FILE} *file
* @param {char} *bin
* @param {int} len: length of bin string
* @return {0: success 1: no more data need te be read -1: error}
*/
int hexfile_to_bin(FILE *file, char *bin, int len)
{
bool eof = false;
if (len % 4 != 0)
{
printf("binary length argument error\n");
return -1;
}
char hex;
for (int i = 0; i < len / 4; i++)
{
int num = 0;
hex = fgetc(file);
if (i == 0 && hex == -1)
{
return 1;
}
if ('0' <= hex && hex <= '9')
{
num = hex - '0';
}
else if ('a' <= hex && hex <= 'f')
{
num = hex - 'a' + 10;
}
else if ('A' <= hex && hex <= 'F')
{
num = hex - 'A' + 10;
}
else if (hex == 0 || hex == -1)
{
num = 0;
}
else
{
printf("unknown hex char\n");
return -1;
}
for (int j = 3; j >= 0; j--)
{
bin[i * 4 + j] = (num % 2 == 0 ? '0' : '1');
num /= 2;
}
}
return 0;
}
/**
* @description: convert bin string to hex and save it to file
*/
bool bin_to_hexfile(char *bin, FILE *file, int len)
{
if (len % 4 != 0)
{
printf("binary length argument error\n");
return -1;
}
for (int i = 0; i < len / 4; i++)
{
int num = 0;
for (int j = 0; j < 4; j++)
{
switch (bin[i * 4 + j])
{
case '1':
num = num * 2 + 1;
break;
case '0':
num = num * 2;
break;
default:
printf("bin to hex error\n");
return false;
}
}
if (0 <= num && num <= 9)
{
fputc(num + '0', file);
}
else if (10 <= num && num <= 15)
{
fputc(num - 10 + 'A', file);
}
else
{
printf("hex number is out of range\n");
return false;
}
}
return true;
}
DES计算
DES加密计算
f函数计算:
/*des.h*/
void encrypt(char *m, char *c, char *k);
/*des.c*/
#include "des_t.h"
typedef char ki[48];
void f(char *r, char *k)
{
char tmp[48];
permutation(r, tmp, E, 48);
xor(tmp, k, tmp, 48);
char s_p[32]; // s盒的2进制输出
for (int i = 0; i < 8; i++)
{
int row = ((tmp[i * 6] - '0') << 1) + (tmp[i * 6 + 5] - '0'); //第1,6位组成行号
int col = ((tmp[i * 6 + 1] - '0') << 3) + ((tmp[i * 6 + 2] - '0') << 2) + ((tmp[i * 6 + 3] - '0') << 1) + (tmp[i * 6 + 4] - '0');
int s = S_Box[i][row][col]; // s盒的十进制输出
for (int j = 0; j < 4; j++)
{
s_p[i * 4 + j] = ((s >> (3 - j)) & 1u) + '0';
}
}
permutation(s_p, r, P, 32);
}
void encrypt(char *m, char *c, char *k)
{
char *l = (char *)malloc(sizeof(char) * 32);
char *r = (char *)malloc(sizeof(char) * 32);
char *l1 = (char *)malloc(sizeof(char) * 32);
char *r1 = (char *)malloc(sizeof(char) * 32);
// key
ki *sk = (ki *)malloc(sizeof(ki) * 16);
subkey(k, sk);
// IP
permutation(m, c, IP, 64);
// 16轮
dividegroup(c, l, r, 64);
int round = 0;
while (round < 16)
{
strncpy(l1, r, 32);
f(r, sk[round]);
xor(l, r, r1, 32);
round++;
strncpy(l, r1, 32);
f(r1, sk[round]);
xor(l1, r1, r, 32);
round++;
}
// IP-1
char tmp[64];
mergegroup(r, l, tmp, 64);
permutation(tmp, c, FP, 64);
}
计算表
/*des_t.h*/
#include "tool.h"
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
typedef char ki[48];
void subkey(char *k, ki *sk);
const char 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};
const char 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};
const char 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};
const char S_Box[8][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},
},
{
{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},
},
{
{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},
},
{
{ 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},
},
{
{ 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},
},
{
{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},
},
{
{ 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},
},
{
{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},
},
};
const char 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};
轮密钥生成
/*subkey.c*/
#include "subkey.h"
void ls(char *c, int shift)
{
char tmp[28];
strncpy(tmp, c, 28);
for (int i = 0; i < 28; i++)
{
c[i] = tmp[(28 + i + shift) % 28];
}
}
void subkey(char *k, ki *sk)
{
char cd[56];
char c[28];
char d[28];
// PC1
permutation(k, cd, PC1, 56);
dividegroup(cd, c, d, 56);
for (int r = 0; r < 16; r++)
{
ls(c, SHIFTS[r]);
ls(d, SHIFTS[r]);
mergegroup(c, d, cd, 56);
permutation(cd, sk[r], PC2, 48);
}
}
计算表
/*subkey.h*/
#include "tool.h"
#include <string.h>
typedef char ki[48];
char 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};
char 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};
char SHIFTS[] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
Block cipher mode of operation
/*blockCipher.h*/
#ifndef _blockCipher_h_
#define _blockCipher_h_
#include <stdbool.h>
char* ecb(char* m, char* k, unsigned int len);
char *cbc(char* IV, char *m, char *k, unsigned int len);
char *cfb(char *IV, char *m, char *k, int s, unsigned int len);
char *ofb(char *IV, char *m, char *k, unsigned int len);
// using ECB block cipher mode
// encrypt hex message from m_fp and save it into cipher_fp
bool ecb_file(FILE* m_fp, FILE* k_fp, FILE* cipher_fp);
// using CBC block cipher mode
// encrypt hex message from m_fp and save it into cipher_fp
bool cbc_file(FILE* iv_fp, FILE *m_fp, FILE *k_fp, FILE* cipher_fp);
// using CFB block cipher mode
// encrypt hex message from m_fp and save it into cipher_fp
bool cfb_file(FILE *iv_fp, FILE *m_fp, FILE *k_fp, FILE *cipher_fp, int s);
// using OFB block cipher mode
// encrypt hex message from m_fp and save it into cipher_fp
bool ofb_file(FILE *iv_fp, FILE *m_fp, FILE *k_fp, FILE* cipher_fp, int s);
#endif
/*blockCipher.c*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "des.h"
#include "tool.h"
#include "blockCipher.h"
// return padded group
char *padding(char *m, unsigned int len, int group_size)
{
int group = len / group_size;
// int last_group_len = len % group_size;
// padding
if (len % group_size != 0)
{
group += 1;
char *m_padding = (char *)malloc(sizeof(char) * group * group_size + 1);
strncpy(m_padding, m, len);
for (int i = len; i < group * group_size; i++)
{
m_padding[i] = '0';
}
m_padding[group * group_size] = '\0';
m = m_padding;
}
else if (m[len] != '\0') //添加截至符
{
char *m_padding = (char *)malloc(sizeof(char) * len + 1);
strncpy(m_padding, m, len);
m_padding[group * group_size] = '\0';
m = m_padding;
}
return m;
}
char *ecb(char *m, char *k, unsigned int len)
{
const int group_size = 64;
m = padding(m, len, group_size);
ASSERT((strlen(m) % group_size == 0))
int group = strlen(m) / group_size;
char *c = (char *)malloc(sizeof(char) * group * group_size + 1);
char mi[65];
char ci[65];
for (int i = 0; i < group; i++)
{
strncpy(mi, m + i * group_size, group_size);
mi[64] = '\0';
encrypt(mi, ci, k);
strncpy(c + i * group_size, ci, group_size);
}
c[group * group_size] = '\0';
return c;
}
bool ecb_file(FILE *m_fp, FILE *k_fp, FILE *cipher_fp)
{
char m[64];
char c[64];
char k[64];
hexfile_to_bin(k_fp, k, 64);
while (true)
{
int eof = hexfile_to_bin(m_fp, m, 64);
if (eof == 1)
{
break;
}
if (eof == -1)
{
return false;
}
encrypt(m, c, k);
if (!bin_to_hexfile(c, cipher_fp, 64))
{
return false;
}
}
return true;
}
char *cbc(char *IV, char *m, char *k, unsigned int len)
{
const int group_size = 64;
m = padding(m, len, group_size);
ASSERT((strlen(m) % group_size == 0))
int group = strlen(m) / group_size;
char *c = (char *)malloc(sizeof(char) * strlen(m) + 1);
char mi[65];
char ci[65];
strncpy(ci, IV, 64);
ci[64] = '\0';
for (int i = 0; i < strlen(m) / group_size; i++)
{
strncpy(mi, m + i * group_size, group_size);
xor(mi, ci, mi, 64);
mi[64] = '\0';
encrypt(mi, ci, k);
strncpy(c + i * group_size, ci, group_size);
}
c[group * group_size] = '\0';
return c;
}
bool cbc_file(FILE *iv_fp, FILE *m_fp, FILE *k_fp, FILE *cipher_fp)
{
char iv[64];
char plain[64];
char key[64];
hexfile_to_bin(iv_fp, iv, 64);
hexfile_to_bin(k_fp, key, 64);
while (true)
{
int eof = hexfile_to_bin(m_fp, plain, 64);
if (eof == 1)
{
break;
}
else if (eof == -1)
{
return false;
}
else
{
xor(iv, plain, plain, 64);
encrypt(plain, iv, key);
bin_to_hexfile(iv, cipher_fp, 64);
}
}
return true;
}
char *cfb(char *IV, char *m, char *k, int s, unsigned int len)
{
char shift_reg[64];
char ci[64];
char *c = (char *)malloc(sizeof(char) * strlen(m) + 1);
m = padding(m, len, s);
ASSERT((strlen(m) % s == 0))
strncpy(shift_reg, IV, 64);
encrypt(shift_reg, ci, k);
xor(m, ci, ci, s);
strncpy(c, ci, s);
for (int i = 1; i < strlen(m) / s; i++)
{
lshift(shift_reg, shift_reg, 64, s);
for (int i = 0; i < s; i++)
{
shift_reg[i + (64 - s)] = ci[i];
}
encrypt(shift_reg, ci, k);
xor(m, ci, ci, s);
strncpy(c + i * s, ci, s);
}
c[strlen(m)] = '\0';
return c;
}
bool cfb_file(FILE *iv_fp, FILE *m_fp, FILE *k_fp, FILE *cipher_fp, int s)
{
char shift_reg[64];
char c[64];
char key[64];
char plain[s];
hexfile_to_bin(m_fp, plain, s);
hexfile_to_bin(k_fp, key, 64);
hexfile_to_bin(iv_fp, shift_reg, 64);
encrypt(shift_reg, c, key);
xor(plain, c, c, s);
bin_to_hexfile(c, cipher_fp, s);
while (true)
{
int eof = hexfile_to_bin(m_fp, plain, s);
if (eof == 1)
{
break;
}
else if (eof == -1)
{
return false;
}
else
{
lshift(shift_reg, shift_reg, 64, s);
for (int i = 0; i < s; i++)
{
shift_reg[i + (64 - s)] = c[i];
}
encrypt(shift_reg, c, key);
xor(plain, c, c, s);
bin_to_hexfile(c, cipher_fp, s);
}
}
return true;
}
char *ofb(char *IV, char *m, char *k, unsigned int len)
{
const int group_size = 64;
m = padding(m, len, group_size);
ASSERT((strlen(m) % group_size == 0))
char *c = (char *)malloc(sizeof(char) * strlen(m) + 1);
char reg0[64];
char reg1[64];
strncpy(reg0, IV, 64);
for (int i = 0; i < strlen(m) / group_size; i++)
{
encrypt(reg0, reg1, k);
strncpy(reg0, reg1, 64);
xor(reg1, m + i * group_size, reg1, 64);
strncpy(c + i * group_size, reg1, group_size);
}
c[strlen(m)] = '\0';
return c;
}
bool ofb_file(FILE *iv_fp, FILE *m_fp, FILE *k_fp, FILE *cipher_fp, int s)
{
char shift_reg[64];
char c[64];
char key[64];
char plain[s];
hexfile_to_bin(m_fp, plain, s);
hexfile_to_bin(k_fp, key, 64);
hexfile_to_bin(iv_fp, shift_reg, 64);
encrypt(shift_reg, c, key);
lshift(shift_reg, shift_reg, 64, s);
for (int i = 0; i < s; i++)
{
shift_reg[i + (64 - s)] = c[i];
}
xor(plain, c, c, s);
bin_to_hexfile(c, cipher_fp, s);
while (true)
{
int eof = hexfile_to_bin(m_fp, plain, s);
if (eof == 1)
{
break;
}
else if (eof == -1)
{
return false;
}
else
{
encrypt(shift_reg, c, key);
lshift(shift_reg, shift_reg, 64, s);
for (int i = 0; i < s; i++)
{
shift_reg[i + (64 - s)] = c[i];
}
xor(plain, c, c, s);
bin_to_hexfile(c, cipher_fp, s);
}
}
return true;
}
DES算法
测试DES算法
/*main.c*/
#include <stdio.h>
#include "des.h"
int main()
{
char m[64] = "1111111011011100101110101001100001110110010101000011001000010000";
char k[64] = "0100100000110010000110101011111110000010100101010011110010111110";
char c[65];
encrypt(m, c, k);
c[64] = '\0';
puts(c);
return 0;
}
基于文件与命令行实现
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "blockCipher.h"
int main(int argc, char *argv[])
{
// arg processing
char *plainfile = NULL;
char *keyfile = NULL;
char *ivfile = NULL;
char *mode = NULL;
char *cipherfile = NULL;
for (int i = 1; i < argc; i++)
{
if (strcmp(argv[i], "-p") == 0)
{
plainfile = argv[++i];
}
else if (strcmp(argv[i], "-k") == 0)
{
keyfile = argv[++i];
}
else if (strcmp(argv[i], "-v") == 0)
{
ivfile = argv[++i];
}
else if (strcmp(argv[i], "-m") == 0)
{
mode = argv[++i];
}
else if (strcmp(argv[i], "-c") == 0)
{
cipherfile = argv[++i];
}
else
{
printf("-p plainfile 指定明文文件的位置和名称\n");
printf("-k keyfile 指定密钥文件的位置和名称\n");
printf("-v vifile 指定初始化向量文件的位置和名称\n");
printf("-m mode 指定加密的操作模式\n");
printf("-c cipherfile 指定密文文件的位置和名称\n");
return 1;
}
}
// open file
FILE *plain_fp = fopen(plainfile, "r");
if (plain_fp == NULL)
{
printf("Unable to open %s\n", plainfile);
return 1;
}
FILE *key_fp = fopen(keyfile, "r");
if (key_fp == NULL)
{
printf("Unable to open %s\n", keyfile);
return 1;
}
FILE *cipher_fp = fopen(cipherfile, "w");
if (cipher_fp == NULL)
{
printf("Unable to open %s\n", cipherfile);
return 1;
}
clock_t t = clock();
if (strcmp(mode, "ECB") == 0)
{
printf("Using ECB mode\n");
ecb_file(plain_fp, key_fp, cipher_fp);
}
else
{
FILE *iv_fp = fopen(ivfile, "r");
if (iv_fp == NULL)
{
printf("Unable to open %s\n", ivfile);
return 1;
}
if (strcmp(mode, "CBC") == 0)
{
printf("Using CBC mode\n");
cbc_file(iv_fp, plain_fp, key_fp, cipher_fp);
}
else if (strcmp(mode, "CFB") == 0)
{
printf("Using CFB mode\n");
cfb_file(iv_fp, plain_fp, key_fp, cipher_fp, 32);
}
else if (strcmp(mode, "OFB") == 0)
{
printf("Using OFB mode\n");
ofb_file(iv_fp, plain_fp, key_fp, cipher_fp, 32);
}
}
printf("%fs", (float)(clock() - t) / CLOCKS_PER_SEC);
return 0;
}