DES暗号プログラム



[ 簡単な説明 ]

IBM開発のDESアルゴリズムを用いたファイル暗号化/復号化プログラムです。
C++版のプログラム・ソースは、実行ファイルと共に、NIFTY-Serve に公開しました。
使用法の詳細は、後述のマニュアルと、使用例を参照して下さい。

プログラム・ソース("des.c")           top (トップに戻る)
/*		des.c		Data Encryption Standard 	*/
#include <stdio.h>
#include <ctype.h>
#include <memory.h>

/*#define		DEBUG		/* print out for debug */
#define		SC		1		/* = sizeof(char) */

typedef		unsigned int	UINT;

FILE *fp1, *fp2;
char buf[256], bufo[1024];
char *bufolast = bufo + 1016, *bufo_blen = bufo + 8;

UINT *key32[16], *key16[16];
UINT *message_IP[64];
UINT *key_L_s[16], *key_R_s[16], *temp_PC2M[48], *temp_PC2K[48];
UINT *mes_IP1[64], *mes_P1[32], *mes_P2[32], *mes_EK1[16], *mes_EK2[16];
UINT cipher[64], code[64], temp[64], mes[64];
UINT key_L[56], key_R[56];
UINT *des_in, *temp_28, *mes_32;

UINT *ini_len, *ini_len1, *xb1, *xb2;

static int mode = 1, count;
static int blen = 8, blen8 = 64, blen8a = 0, llen = 64, llen1 = 0;
static int blen8_M = 64 * sizeof(UINT), blen8a_M = 0;
static int llen_M = 64 * sizeof(UINT), llen1_M = 0;

static UINT initial[64], key[64];

static UINT x[64] =
	{1,1,1,1,1,1,1,1,  1,1,1,1,1,1,1,1,  1,1,1,1,1,1,1,1,  1,1,1,1,1,1,1,1,
	 1,1,1,1,1,1,1,1,  1,1,1,1,1,1,1,1,  1,1,1,1,1,1,1,1,  1,1,1,1,1,1,1,1 };

static UINT IP[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 };

static UINT IP1[64] =
	{	7,39,15,47,23,55,31,63,		6,38,14,46,22,54,30,62,
		5,37,13,45,21,53,29,61,		4,36,12,44,20,52,28,60,
		3,35,11,43,19,51,27,59,		2,34,10,42,18,50,26,58,
		1,33, 9,41,17,49,25,57,		0,32, 8,40,16,48,24,56 };

static UINT S[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 } } };

static UINT EK1[16] =
	{	63,36,35,40,39,44,43,48, 47,52,51,56,55,60,59,32 };

static UINT EK2[16] =
	{	31, 4, 3, 8, 7,12,11,16, 15,20,19,24,23,28,27, 0 };

static UINT PINV[32] =
	{	 8,16,22,30, 12,27, 1,17, 23,15,29, 5, 25,19, 9, 0,
		 7,13,24, 2,  3,28,10,18, 31,11,21, 6,  4,26,14,20 };

static UINT PC1[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 };

static UINT PC2M[32] =
	{	16,10,23, 0, 27,14, 5,20, 18,11, 3,25,  6,26,19,12,
		51,30,36,46, 39,50,44,32, 48,38,55,33, 41,49,35,28 };

static UINT PC2K[16] = 
	{	13, 4, 2, 9, 22, 7,15, 1, 40,54,29,47, 43,52,45,31 };

static UINT shift[16] =
	{	1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28};

#ifdef	DEBUG
char kki[16] =
	{	'0', '1', '2', '3', '4', '5', '6', '7',
		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
#endif
 
/* prototype declaration */
void init_des(), makekey(), des(), usage(), openerr();
void hex_to_code(), byte_to_code(), code_to_byte();
void address(), xor(), ini_shift(), substitute();
void ecb(), cbc_e(), cbc_d(), ofb(), cfb_e(), cfb_d();

#ifdef		DEBUG
void bprint(), cprint(), code_to_hex();

void bprint(mes1, m, n)
UINT *mes1;
int m, n;
{
	UINT *p;

	p = mes1;
	do
	{
		printf("%d", *p++);
		if(--n == 0)
		{
			printf(" ");
			n = 8;
		}
	} while(--m);
}

void cprint(code1)
UINT *code1;
{
	UINT *p;
	int i;

	p = code1;
	i = 16;
	do
	{
		putchar(kki[(((*p++ * 2) + *p++) * 2 + *p++) * 2 + *p++]);
	} while(--i);
}

void code_to_hex(code1, hex)
UINT *code1;
char *hex;
{
	UINT *q;
	char *p;
	int i;

	p = hex;
	q = code1;
	i = 16;
	do
	{
		*p++ = kki[(((*q++ * 2) + *q++) * 2 + *q++) * 2 + *q++]);
	} while(--i);
	*p = '\0';
}
#endif

void hex_to_code(hex, code1)
char *hex;
UINT *code1;
{
	UINT *q = code1;
	char *p = hex;
	int ch, i = 16;

	while(ch = tolower(*p++))
	{
		if(ch >= '0' && ch <= '9')		ch -= '0';
		else if(ch >= 'a' && ch <= 'f')	ch = ch - 'a' + 10;
		else break;
		*q++ = (ch >> 3) & 1;
		*q++ = (ch >> 2) & 1;
		*q++ = (ch >> 1) & 1;
		*q++ = ch & 1;
		if(i-- == 1)	return;
	}
	memset(q, 0, i * 4 * sizeof(UINT));
}

void byte_to_code(byte, code1, cc)
char *byte;
UINT *code1;
int cc;
{
	UINT *q = code1;
	char *p = byte;
	int ch, n;

	n = (8 - cc) * 8 * sizeof(UINT);
	do
	{
		*q++ = ((ch = *p++) >> 7) & 1;
		*q++ = (ch >> 6) & 1;
		*q++ = (ch >> 5) & 1;
		*q++ = (ch >> 4) & 1;
		*q++ = (ch >> 3) & 1;
		*q++ = (ch >> 2) & 1;
		*q++ = (ch >> 1) & 1;
		*q++ =  ch       & 1;
	} while(--cc);
	memset(q, 0, n);
}

void code_to_byte(byte, code1)
char *byte;
UINT *code1;
{
	UINT *q = code1;
	char *p = byte;
	int n = blen;

	do
	{
		*p++ = (((((((*q++*2)+*q++)*2+*q++)*2+*q++)*2+*q++)*2+*q++)*2+*q++)*2+*q++;
	} while(--n);
}

void address(add, base, index, n)
UINT **add, *base, *index;
int n;
{
	UINT **pp = add;
	UINT *p = index;

	do
	{
		*pp++ = base + *p++;
	} while(--n);
}

void xor(bufout)
char *bufout;
{
	char *p = buf, *q = bufout;
	int n = count;

	do
	{
		*q++ ^= *p++;
	} while(--n);
}

void ini_shift()
{
	UINT *p = ini_len - 1, *q = initial + 63;
	int n = llen;
	while(n--)	*q-- = *p--;
	memset(initial, 0, llen1);
}

void substitute(code1, sub, n)
UINT *code1, **sub;
int n;
{
	UINT **pp = sub;
	UINT *p = code1;

	do
	{
		*p++ = *(*pp++);
	} while(--n);
}

void init_des()
{
	UINT **pp, **pp1, **qq;
	UINT *p, *q;
	int i;

	pp = key32;
	qq = key16;
	i = 16;
	do
	{
		*pp++ = (UINT *)malloc(32 * sizeof(UINT));
		*qq++ = (UINT *)malloc(16 * sizeof(UINT));
	} while(--i);

	des_in = (mode <= 2)? code: initial;
	temp_28 = temp + 28;
	mes_32 = mes + 32;

	address(key_L_s, key_L, shift, 16);
	address(key_R_s, key_R, shift, 16);
	address(temp_PC2M, temp, PC2M, 32);
	address(temp_PC2K, temp, PC2K, 16);
	address(mes_P1, mes,    PINV, 32);
	address(mes_P2, mes_32, PINV, 32);
	address(mes_EK1, mes, EK1, 16);
	address(mes_EK2, mes, EK2, 16);
	address(mes_IP1, mes, IP1, 64);
	address(message_IP, des_in, IP, 64);
}

void makekey(edflag)
int edflag;						/* 1 : encryption, 0 : decryption */
{
	UINT **ps1 = key_L_s, **ps2 = key_R_s;
	UINT *p1, *p2, *q1, *q2;
	int i = 28, j, m = 28 * sizeof(UINT);

	p2 = (p1 = PC1) + 28;
	q1 = key_L;
	q2 = key_R;
	do
	{
		*q1++ = key[*p1++];
		*q2++ = key[*p2++];
	} while(--i);
	memcpy(key_L + 28, key_L, m);
	memcpy(key_R + 28, key_R, m);

	i = 15;
	do
	{
		memcpy(temp,    *ps1++, m);
		memcpy(temp_28, *ps2++, m);
		j = (edflag)? 15 - i: i;
		substitute(key32[j], temp_PC2M, 32);
		substitute(key16[j], temp_PC2K, 16);
	} while(--i >= 0);
}

void des(crypt, crypt_b)
UINT *crypt;
char *crypt_b;
{
	UINT **pp1, **pp2, **qq1 = key32, **qq2 = key16;
	UINT *p1, *p2, *q1;
	int i = 8, j, m;

	substitute(mes, message_IP, 64);

	do
	{
		pp1 = mes_P1;
		pp2 = mes_EK1;
		q1 = mes_32;
		p1 = *qq1++;
		p2 = *qq2++;
		j = 0;
		do
		{
			m = S[j]
				[(*(*pp2++)^ *p2++)*2 + *(*pp2++) ^ *p2++]
				[(((*q1++ ^ *p1++)*2 + *q1++ ^ *p1++)*2 + *q1++ ^ *p1++)*2 + *q1++ ^ *p1++];
			*(*pp1) ^= ((m >> 3) & 1);
			pp1++;
			*(*pp1) ^= ((m >> 2) & 1);
			pp1++;
			*(*pp1) ^= ((m >> 1) & 1);
			pp1++;
			*(*pp1) ^= (m & 1);
			pp1++;
		} while(++j < 8);

		pp1 = mes_P2;
		pp2 = mes_EK2;
		q1 = mes;
		p1 = *qq1++;
		p2 = *qq2++;
		j = 0;
		do
		{
			m = S[j]
				[(*(*pp2++) ^ *p2++)* 2 + *(*pp2++) ^ *p2++]
				[(((*q1++ ^ *p1++)* 2 + *q1++ ^ *p1++)* 2 + *q1++ ^ *p1++)* 2 + *q1++ ^ *p1++];
			*(*pp1) ^= ((m >> 3) & 1);
			pp1++;
			*(*pp1) ^= ((m >> 2) & 1);
			pp1++;
			*(*pp1) ^= ((m >> 1) & 1);
			pp1++;
			*(*pp1) ^= (m & 1);
			pp1++;
		} while(++j < 8);
	} while(--i);

	substitute(crypt, mes_IP1, 64);
	code_to_byte(crypt_b, crypt);
}

void ecb()
{
	while(count = fread(buf, SC, blen, fp1))
	{
		byte_to_code(buf, code, count);
		des(cipher, bufo);
		fwrite(bufo, SC, blen, fp2);
	}
}

void cbc_e()
{
	code_to_byte(bufo, initial);
	while(count = fread(buf, SC, blen, fp1))
	{
		xor(bufo);
		byte_to_code(bufo, code, blen);
		des(cipher, bufo);
		fwrite(bufo, SC, blen, fp2);
	}
}

void cbc_d()
{
	char *p = bufo, *q = bufo_blen;

	code_to_byte(bufo, initial);
	while(count = fread(q, SC, blen, fp1))
	{
		byte_to_code(q, code, count);
		des(cipher, buf);
		xor(p);
		fwrite(p, SC, blen, fp2);
		if(count != blen)	return;

		if((p = q) < bufolast)	q += blen;
		else
		{
			memcpy(bufo, p, 8);
			p = bufo;
			q = bufo_blen;
		}
	}
}

void ofb()
{
	des(code, bufo);
	while(count = fread(buf, SC, blen, fp1))
	{
		xor(bufo);
		fwrite(bufo, SC, blen, fp2);
		if(count != blen)	return;

		memcpy(initial, ini_len, llen1_M);
		memcpy(ini_len1, code, llen_M);
		des(code, bufo);
	}
}

void cfb_e()
{
	ini_shift();
	des(code, bufo);
	while(count = fread(buf, SC, blen, fp1))
	{
		xor(bufo);
		fwrite(bufo, SC, blen, fp2);
		if(count != blen)	return;

		byte_to_code(bufo, cipher, blen);
		memcpy(x, xb1, blen8a_M);
		memcpy(xb2, cipher, blen8_M);
		memcpy(initial, ini_len, llen1_M);
		memcpy(ini_len1, x, llen_M);
		des(code, bufo);
	}
}

void cfb_d()
{
	ini_shift();
	des(code, bufo);
	while(count = fread(buf, SC, blen, fp1))
	{
		byte_to_code(buf, cipher, count);
		memcpy(x, xb1, blen8a_M);
		memcpy(xb2, cipher, blen8_M);
		xor(bufo);
		fwrite(bufo, SC, blen, fp2);
		if(count != blen)	return;

		memcpy(initial, ini_len, llen1_M);
		memcpy(ini_len1, x, llen_M);
		des(code, bufo);
	}
}

void usage(prog)
char *prog;
{
	fprintf(stderr, "Usage : %s [-Xn] [-Kkey] [-Finit] [-Jn] [-Ln] <-E|-D>  file1  file2\n", prog);
	fprintf(stderr, "   -X : Modes of Operations\n");
	fprintf(stderr, "        n : Mode Number (default = 1)\n");
	fprintf(stderr, "           1 = ECB(Electric CodeBook)\n");
	fprintf(stderr, "           2 = CBC(Cipher Block Chaining)\n");
	fprintf(stderr, "           3 = OFB(Output FeedBack)\n");
	fprintf(stderr, "           4 = CFB(Cipher FeedBack)\n");
	fprintf(stderr, "   -K : key file definition\n");
	fprintf(stderr, "        key : key file name\n");
	fprintf(stderr, "   -F : Initial Value of CBC,OFB,CFB mode(default = all'0')\n");
	fprintf(stderr, "        init : initial value file name\n");
	fprintf(stderr, "   -J : Block length direction\n");
	fprintf(stderr, "        n : Bleck length(1 - 8 Bytes, default = 8)\n");
	fprintf(stderr, "   -L : Key Feedback bit length direction\n");
	fprintf(stderr, "        n : Feedback length(1 - 64, default = 64)\n");
	fprintf(stderr, "   -E : Encryption mode\n");
	fprintf(stderr, "   -D : Decryption mode\n");
	fprintf(stderr, "  file1 : source file\n");
	fprintf(stderr, "  file2 : destination file\n\n");
	fprintf(stderr, "  (note 1 : file is 8byte Hexa-decimal code = 16 characters.)\n");
	exit(0);
}

void openerr(kind, file)
char *kind, *file;
{
	fprintf(stderr, "Error : %s file(%s) can't open.\n", kind, file);
	exit(-1);
}

int main(argc, argv)
int argc;
char *argv[];
{
	char *prog = argv[0];
	long tm0, tm1;
	int edflag = -1, ki = 0, kk = 0, tflag = 0;
	int k, k1;
#ifdef	DEBUG
	static char desmode[4][4] = {"ECB", "CBC", "OFB", "CFB"};

	setvbuf(stderr, (char *)NULL, _IONBF, 0);
	setvbuf(stdout, (char *)NULL, _IONBF, 0);
#endif

	if(argc < 2 || *argv[1] != '-')	usage(prog);
	k = 1;
	do
	{
		switch(tolower(*(argv[k] + 1)))
		{
		case 'x':	mode = atoi(argv[k] + 2);
					if(mode < 1 || mode > 4)	usage(prog);
					break;
		case 'k':	kk = k;
					break;
		case 'f':	ki = k;
					break;
		case 'j':	blen = atoi(argv[k] + 2);
					if(blen < 1 || blen > 8)	usage(prog);
					blen8 = blen * 8;
					blen8_M = blen8 * sizeof(UINT);
					blen8a = 64 - blen8;
					blen8a_M = blen8a * sizeof(UINT);
					break;
		case 'l':	llen = atoi(argv[k] + 2);
					if(llen < 1 || llen > 64)	usage(prog);
					llen_M = llen * sizeof(UINT);
					llen1 = 64 - llen;
					llen1_M = llen1 * sizeof(UINT);
					break;
		case 'd':	if(edflag == 1)	usage(prog);
					edflag = 0;
					break;
		case 'e':	if(edflag == 0)	usage(prog);
					edflag = 1;
					break;
		case 't':	tflag = 1;
					break;
		case 'm':	fp1 = fopen("des.man", "r");
					if(fp1 == NULL)	usage(prog);
					while(fgets(buf, 256, fp1) != NULL)
						fprintf(stderr, "%s", buf);
					exit(0);
		default:	usage(prog);
		}
	} while(*argv[++k] == '-');

	if((mode == 4 && blen8 > llen) || edflag == -1 || k >= argc)	usage(prog);
	k1 = k++;
	if(k >= argc)	usage(prog);

	init_des();

	if(kk != 0)
	{
		fp1 = fopen(argv[kk] + 2, "r");
		if(fp1 == NULL)	openerr("key", argv[kk] + 2);
		fgets(buf, 256, fp1);
		fclose(fp1);
		hex_to_code(buf, key);
	}
	if(mode >= 2)
	{
		if(ki)
		{
			fp1 = fopen(argv[ki] + 2, "r");
			if(fp1 == NULL)	openerr("initial", argv[ki] + 2);
			fgets(buf, 256, fp1);
			fclose(fp1);
			hex_to_code(buf, initial);
		}
		if(mode == 2)	bufo_blen = bufo + blen;
		if(mode >= 3)
		{
			ini_len  = initial + llen;
			ini_len1 = initial + llen1;
		}
		if(mode == 4)
		{
			xb1 = x + blen8;
			xb2 = x + blen8a;
		}
	}

	fp1 = fopen(argv[k1], "r");
	if(fp1 == NULL)	openerr("source", argv[k1]);
	fp2 = fopen(argv[k], "r");
	if(fp2 != NULL)
	{
		fprintf(stderr, "Error : destination file(%s) already exist.\n", argv[k]);
		exit(-1);
	}
	fp2 = fopen(argv[k], "w");

#ifdef	DEBUG
	if(edflag)	printf("<<< Encryption (");
	else		printf("<<< Decryprion (");
	printf("%s) >>>\n", desmode[mode - 1]);
	printf("  file1 : %s\n", argv[k1]);
	printf("  file2 : %s\n", argv[k2]);
	printf("   key  : ");
	cprint(key);
	putchar('\n');
	if(mode > 1)
	{
		printf("initial : ");
		cprint(initial);
		putchar('\n');
	}
	if(mode == 3)	printf("Block length = %d [Bytes]\n", blen);
#endif

	tm0 = clock();
	switch(mode)
	{
	case 1:	makekey(edflag);
			ecb();
			break;
	case 2:	makekey(edflag);
			if(edflag)	cbc_e();
			else		cbc_d();
			break;
	case 3:	makekey(1);
			ofb();
			break;
	case 4:	makekey(1);
			if(edflag)	cfb_e();
			else		cfb_d();
			break;
	}
	tm1 = clock();

	fclose(fp1);
	fclose(fp2);
	if(tflag)	fprintf(stderr, "lap time : %7.3f [s]\n", (double)(tm1 - tm0) * 1.e-6);

	return 0;
}

プログラム・ソース("des.cpp")           top (トップに戻る)
//
//		des.cpp		Data Encryption Standard 
//
const char *COPYRIGHT = "by Tomy(NIFTY:SGV01401) all rights reserved.";
const char *VER = "2.1";
const char *DATE = "1994/11/10";

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <mem.h>
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>

//#define		NODISP

typedef		unsigned int		UINT;
typedef		unsigned long		ULONG;

union
{
	ULONG a;
	char b[4];
} m;
char *mb0 = m.b, *mb1 = m.b + 1, *mb2 = m.b + 2, *mb3 = m.b + 3;

const long BUFFER_SIZE = 51200;
const int U28 = 28 * sizeof(UINT);

FILE *fp;
int handle1, handle2;

ULONG bufsize, bufsize1, count, mem;
UINT mem1;

char buffer[BUFFER_SIZE], bufo[8], inibuf[16], keybuf[16];
char *blast, *bp;

UINT key32[128], key16[128], tmp[56], key_L[56], key_R[56];

#ifndef NODISP
static ULONG filesize, outsize = 0, outcount = 0;
#endif

static int blen = 8, edflag = -1, llen = 64, mode = 1, k1 = 0, k2 = 0;
int blena, lshift, rshift;

#ifndef NODISP
int blen50;
#endif

static UINT key[64] =
	{	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0 };

static char initial[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
static char x[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
char *xb1, *xb2;

char *initial4 = initial + 4;

static int kk[16][4] =
	{	{0,0,0,0},	{0,0,0,1},	{0,0,1,0},	{0,0,1,1},
		{0,1,0,0},	{0,1,0,1},	{0,1,1,0},	{0,1,1,1},
		{1,0,0,0},	{1,0,0,1},	{1,0,1,0},	{1,0,1,1},
		{1,1,0,0},	{1,1,0,1},	{1,1,1,0},	{1,1,1,1}};

static int *S0[4][16] =
	{	{kk[14], kk[ 4], kk[13], kk[ 1], kk[  2], kk[15], kk[11], kk[ 8],
		 kk[ 3], kk[10], kk[ 6], kk[12], kk[  5], kk[ 9], kk[ 0], kk[ 7] },
		{kk[ 0], kk[15], kk[ 7], kk[ 4], kk[ 14], kk[ 2], kk[13], kk[ 1],
		 kk[10], kk[ 6], kk[12], kk[11], kk[  9], kk[ 5], kk[ 3], kk[ 8] },
		{kk[ 4], kk[ 1], kk[14], kk[ 8], kk[ 13], kk[ 6], kk[ 2], kk[11],
		 kk[15], kk[12], kk[ 9], kk[ 7], kk[  3], kk[10], kk[ 5], kk[ 0] },
		{kk[15], kk[12], kk[ 8], kk[ 2], kk[  4], kk[ 9], kk[ 1], kk[ 7],
		 kk[ 5], kk[11], kk[ 3], kk[14], kk[ 10], kk[ 0], kk[ 6], kk[13] } };
static int *S1[4][16] =
	{	{kk[15], kk[ 1], kk[ 8], kk[14], kk[  6], kk[11], kk[ 3], kk[ 4],
		 kk[ 9], kk[ 7], kk[ 2], kk[13], kk[ 12], kk[ 0], kk[ 5], kk[10] },
		{kk[ 3], kk[13], kk[ 4], kk[ 7], kk[ 15], kk[ 2], kk[ 8], kk[14],
		 kk[12], kk[ 0], kk[ 1], kk[10], kk[  6], kk[ 9], kk[11], kk[ 5] },
		{kk[ 0], kk[14], kk[ 7], kk[11], kk[ 10], kk[ 4], kk[13], kk[ 1],
		 kk[ 5], kk[ 8], kk[12], kk[ 6], kk[  9], kk[ 3], kk[ 2], kk[15] },
		{kk[13], kk[ 8], kk[10], kk[ 1], kk[  3], kk[15], kk[ 4], kk[ 2],
		 kk[11], kk[ 6], kk[ 7], kk[12], kk[  0], kk[ 5], kk[14], kk[ 9] } };
static int *S2[4][16] =
	{	{kk[10], kk[ 0], kk[ 9], kk[14], kk[  6], kk[ 3], kk[15], kk[ 5],
		 kk[ 1], kk[13], kk[12], kk[ 7], kk[ 11], kk[ 4], kk[ 2], kk[ 8] },
		{kk[13], kk[ 7], kk[ 0], kk[ 9], kk[  3], kk[ 4], kk[ 6], kk[10],
		 kk[ 2], kk[ 8], kk[ 5], kk[14], kk[ 12], kk[11], kk[15], kk[ 1] },
		{kk[13], kk[ 6], kk[ 4], kk[ 9], kk[  8], kk[15], kk[ 3], kk[ 0],
		 kk[11], kk[ 1], kk[ 2], kk[12], kk[  5], kk[10], kk[14], kk[ 7] },
		{kk[ 1], kk[10], kk[13], kk[ 0], kk[  6], kk[ 9], kk[ 8], kk[ 7],
		 kk[ 4], kk[15], kk[14], kk[ 3], kk[ 11], kk[ 5], kk[ 2], kk[12] } };
static int *S3[4][16] =
	{	{kk[ 7], kk[13], kk[14], kk[ 3], kk[  0], kk[ 6], kk[ 9], kk[10],
		 kk[ 1], kk[ 2], kk[ 8], kk[ 5], kk[ 11], kk[12], kk[ 4], kk[15] },
		{kk[13], kk[ 8], kk[11], kk[ 5], kk[  6], kk[15], kk[ 0], kk[ 3],
		 kk[ 4], kk[ 7], kk[ 2], kk[12], kk[  1], kk[10], kk[14], kk[ 9] },
		{kk[10], kk[ 6], kk[ 9], kk[ 0], kk[ 12], kk[11], kk[ 7], kk[13],
		 kk[15], kk[ 1], kk[ 3], kk[14], kk[  5], kk[ 2], kk[ 8], kk[ 4] },
		{kk[ 3], kk[15], kk[ 0], kk[ 6], kk[ 10], kk[ 1], kk[13], kk[ 8],
		 kk[ 9], kk[ 4], kk[ 5], kk[11], kk[ 12], kk[ 7], kk[ 2], kk[14] } };
static int *S4[4][16] =
	{	{kk[ 2], kk[12], kk[ 4], kk[ 1], kk[  7], kk[10], kk[11], kk[ 6],
		 kk[ 8], kk[ 5], kk[ 3], kk[15], kk[ 13], kk[ 0], kk[14], kk[ 9] },
		{kk[14], kk[11], kk[ 2], kk[12], kk[  4], kk[ 7], kk[13], kk[ 1],
		 kk[ 5], kk[ 0], kk[15], kk[10], kk[  3], kk[ 9], kk[ 8], kk[ 6] },
		{kk[ 4], kk[ 2], kk[ 1], kk[11], kk[ 10], kk[13], kk[ 7], kk[ 8],
		 kk[15], kk[ 9], kk[12], kk[ 5], kk[  6], kk[ 3], kk[ 0], kk[14] },
		{kk[11], kk[ 8], kk[12], kk[ 7], kk[  1], kk[14], kk[ 2], kk[13],
		 kk[ 6], kk[15], kk[ 0], kk[ 9], kk[ 10], kk[ 4], kk[ 5], kk[ 3] } };
static int *S5[4][16] =
	{	{kk[12], kk[ 1], kk[10], kk[15], kk[  9], kk[ 2], kk[ 6], kk[ 8],
		 kk[ 0], kk[13], kk[ 3], kk[ 4], kk[ 14], kk[ 7], kk[ 5], kk[11] },
		{kk[10], kk[15], kk[ 4], kk[ 2], kk[  7], kk[12], kk[ 9], kk[ 5],
		 kk[ 6], kk[ 1], kk[13], kk[14], kk[  0], kk[11], kk[ 3], kk[ 8] },
		{kk[ 9], kk[14], kk[15], kk[ 5], kk[  2], kk[ 8], kk[12], kk[ 3],
		 kk[ 7], kk[ 0], kk[ 4], kk[10], kk[  1], kk[13], kk[11], kk[ 6] },
		{kk[ 4], kk[ 3], kk[ 2], kk[12], kk[  9], kk[ 5], kk[15], kk[10],
		 kk[11], kk[14], kk[ 1], kk[ 7], kk[  6], kk[ 0], kk[ 8], kk[13] } };
static int *S6[4][16] =
	{	{kk[ 4], kk[11], kk[ 2], kk[14], kk[ 15], kk[ 0], kk[ 8], kk[13],
		 kk[ 3], kk[12], kk[ 9], kk[ 7], kk[  5], kk[10], kk[ 6], kk[ 1] },
		{kk[13], kk[ 0], kk[11], kk[ 7], kk[  4], kk[ 9], kk[ 1], kk[10],
		 kk[14], kk[ 3], kk[ 5], kk[12], kk[  2], kk[15], kk[ 8], kk[ 6] },
		{kk[ 1], kk[ 4], kk[11], kk[13], kk[ 12], kk[ 3], kk[ 7], kk[14],
		 kk[10], kk[15], kk[ 6], kk[ 8], kk[  0], kk[ 5], kk[ 9], kk[ 2] },
		{kk[ 6], kk[11], kk[13], kk[ 8], kk[  1], kk[ 4], kk[10], kk[ 7],
		 kk[ 9], kk[ 5], kk[ 0], kk[15], kk[ 14], kk[ 2], kk[ 3], kk[12] } };
static int *S7[4][16] =
	{	{kk[13], kk[ 2], kk[ 8], kk[ 4], kk[  6], kk[15], kk[11], kk[ 1],
		 kk[10], kk[ 9], kk[ 3], kk[14], kk[  5], kk[ 0], kk[12], kk[ 7] },
		{kk[ 1], kk[15], kk[13], kk[ 8], kk[ 10], kk[ 3], kk[ 7], kk[ 4],
		 kk[12], kk[ 5], kk[ 6], kk[11], kk[  0], kk[14], kk[ 9], kk[ 2] },
		{kk[ 7], kk[11], kk[ 4], kk[ 1], kk[  9], kk[12], kk[14], kk[ 2],
		 kk[ 0], kk[ 6], kk[10], kk[13], kk[ 15], kk[ 3], kk[ 5], kk[ 8] },
		{kk[ 2], kk[ 1], kk[14], kk[ 7], kk[  4], kk[10], kk[ 8], kk[13],
		 kk[15], kk[12], kk[ 9], kk[ 0], kk[  3], kk[ 5], kk[ 6], kk[11] } };

static UINT *key_Lp1[16] =
	{	&key_L[ 1],	&key_L[ 2],	&key_L[ 4],	&key_L[ 6],
		&key_L[ 8],	&key_L[10],	&key_L[12],	&key_L[14],
		&key_L[15],	&key_L[17],	&key_L[19],	&key_L[21],
		&key_L[23],	&key_L[25],	&key_L[27],	&key_L[28] };

static UINT *key_Rp1[16] =
	{	&key_R[ 1],	&key_R[ 2],	&key_R[ 4],	&key_R[ 6],
		&key_R[ 8],	&key_R[10],	&key_R[12],	&key_R[14],
		&key_R[15],	&key_R[17],	&key_R[19],	&key_R[21],
		&key_R[23],	&key_R[25],	&key_R[27],	&key_R[28] };

static UINT *key_Lp2[16] =
	{	&key_L[28],	&key_L[27],	&key_L[25],	&key_L[23],
		&key_L[21],	&key_L[19],	&key_L[17],	&key_L[15],
		&key_L[14],	&key_L[12],	&key_L[10],	&key_L[ 8],
		&key_L[ 6],	&key_L[ 4],	&key_L[ 2],	&key_L[ 1] };

static UINT *key_Rp2[16] =
	{	&key_R[28],	&key_R[27],	&key_R[25],	&key_R[23],
		&key_R[21],	&key_R[19],	&key_R[17],	&key_R[15],
		&key_R[14],	&key_R[12],	&key_R[10],	&key_R[ 8],
		&key_R[ 6],	&key_R[ 4],	&key_R[ 2],	&key_R[ 1] };

UINT *key_L28 = key_L + 28, *key_R28 = key_R + 28;

UINT *tmp0  = tmp,      *tmp1  = tmp + 1,  *tmp2  = tmp + 2,  *tmp3  = tmp + 3;
UINT *tmp4  = tmp + 4,  *tmp5  = tmp + 5,  *tmp6  = tmp + 6,  *tmp7  = tmp + 7;
UINT *tmp9  = tmp + 9,  *tmp10 = tmp + 10, *tmp11 = tmp + 11, *tmp12 = tmp + 12;
UINT *tmp13 = tmp + 13, *tmp14 = tmp + 14, *tmp15 = tmp + 15, *tmp16 = tmp + 16;
UINT *tmp18 = tmp + 18, *tmp19 = tmp + 19, *tmp20 = tmp + 20, *tmp22 = tmp + 22;
UINT *tmp23 = tmp + 23, *tmp25 = tmp + 25, *tmp26 = tmp + 26, *tmp27 = tmp + 27;
UINT *tmp28 = tmp + 28, *tmp29 = tmp + 29, *tmp30 = tmp + 30, *tmp31 = tmp + 31;
UINT *tmp32 = tmp + 32, *tmp33 = tmp + 33, *tmp35 = tmp + 35, *tmp36 = tmp + 36;
UINT *tmp38 = tmp + 38, *tmp39 = tmp + 39, *tmp40 = tmp + 40, *tmp41 = tmp + 41;
UINT *tmp43 = tmp + 43, *tmp44 = tmp + 44, *tmp45 = tmp + 45, *tmp46 = tmp + 46;
UINT *tmp47 = tmp + 47, *tmp48 = tmp + 48, *tmp49 = tmp + 49, *tmp50 = tmp + 50;
UINT *tmp51 = tmp + 51, *tmp52 = tmp + 52, *tmp54 = tmp + 54, *tmp55 = tmp + 55;

//	prototype declaration
void (*ini_s)();
void (*rot_i)(char *set);
void (*xor)(char *code1, char *code2);

int hexcode(char a);
void iniset(void);
void keyset(void);
void xor1(char *code1, char *code2);
void xor2(char *code1, char *code2);
void xor3(char *code1, char *code2);
void xor4(char *code1, char *code2);
void xor5(char *code1, char *code2);
void xor6(char *code1, char *code2);
void xor7(char *code1, char *code2);
void xor8(char *code1, char *code2);
ULONG char_to_long(char *a);
void long_to_char(ULONG m1, ULONG m2);
void rot_initial1(char *set);
void rot_initial2(char *set);
void rot_initial3(char *set);
void rot_initial4(char *set);
void ini_shift1(void);
void ini_shift2(void);
void ini_shift3(void);
void ini_shift4(void);
void makekey(int flag);
void des(char *in, char *out);
void ecb(void);
void cbc(void);
void ofb(void);
void cfb(void);
void openerr(char *kind, char *file);
void usage(char *prog);

int hexcode(char a)
{
	if(a >= '0' && a <= '9')	return a - '0';
	else if(a >= 'A' && a <= 'F')	return a - 'A' + 10;
	else if(a >= 'a' && a <= 'f')	return a - 'a' + 10;
	else return a & 0x0f;
}

void iniset(void)
{
	char *p = inibuf, *q = initial;
	register int ch, i = 16;
	while(*p != '\0')
	{
		*p = hexcode(*p);
		p++;
		if(--i == 0)	break;
	}
	while(i--)	*p++ = 0;

	p = inibuf;
	i = 8;
	do
	{
		*q++ = *p * 16 + *(p + 1);
		p += 2;
	} while(--i);
}

void keyset(void)
{
	char *p = keybuf;
	UINT *q = key;
	register int i = 16;
	while(*p != '\0')
	{
		register int ch = hexcode(*p++);
		*q++ = (ch >> 3) & 1;
		*q++ = (ch >> 2) & 1;
		*q++ = (ch >> 1) & 1;
		*q++ = ch & 1;
		if(--i == 0)	return;
	}
}

void xor1(char *code1, char *code2)
{
	code2[0] ^= code1[0];
}

void xor2(char *code1, char *code2)
{
	code2[0] ^= code1[0];
	code2[1] ^= code1[1];
}

void xor3(char *code1, char *code2)
{
	code2[0] ^= code1[0];
	code2[1] ^= code1[1];
	code2[2] ^= code1[2];
}

void xor4(char *code1, char *code2)
{
	code2[0] ^= code1[0];
	code2[1] ^= code1[1];
	code2[2] ^= code1[2];
	code2[3] ^= code1[3];
}

void xor5(char *code1, char *code2)
{
	code2[0] ^= code1[0];
	code2[1] ^= code1[1];
	code2[2] ^= code1[2];
	code2[3] ^= code1[3];
	code2[4] ^= code1[4];
}

void xor6(char *code1, char *code2)
{
	code2[0] ^= code1[0];
	code2[1] ^= code1[1];
	code2[2] ^= code1[2];
	code2[3] ^= code1[3];
	code2[4] ^= code1[4];
	code2[5] ^= code1[5];
}

void xor7(char *code1, char *code2)
{
	code2[0] ^= code1[0];
	code2[1] ^= code1[1];
	code2[2] ^= code1[2];
	code2[3] ^= code1[3];
	code2[4] ^= code1[4];
	code2[5] ^= code1[5];
	code2[6] ^= code1[6];
}

void xor8(char *code1, char *code2)
{
	code2[0] ^= code1[0];
	code2[1] ^= code1[1];
	code2[2] ^= code1[2];
	code2[3] ^= code1[3];
	code2[4] ^= code1[4];
	code2[5] ^= code1[5];
	code2[6] ^= code1[6];
	code2[7] ^= code1[7];
}

ULONG char_to_long(char *a)
{
	*mb3 = a[0];
	*mb2 = a[1];
	*mb1 = a[2];
	*mb0 = a[3];
	return m.a;
}

void long_to_char(ULONG m1, ULONG m2)
{
	m.a = m1;
	initial[0] = *mb3;
	initial[1] = *mb2;
	initial[2] = *mb1;
	initial[3] = *mb0;
	m.a = m2;
	initial[4] = *mb3;
	initial[5] = *mb2;
	initial[6] = *mb1;
	initial[7] = *mb0;
}

void rot_initial1(char *set)
{
	memcpy(initial, initial4, 4);
	memcpy(initial4, set, 4);
}

void rot_initial2(char *set)
{
	memcpy(initial, set, 8);
}

void rot_initial3(char *set)
{
	ULONG m2 = char_to_long(initial4);
	long_to_char((char_to_long(initial) << lshift) | (m2 >> rshift),
				 (m2 << lshift) | (char_to_long(set) >> rshift));
}

void rot_initial4(char *set)
{
	ULONG s1 = char_to_long(set);
	long_to_char((char_to_long(initial4) << lshift) | (s1 >> rshift),
				 (s1 << lshift) | (char_to_long(set + 4) >> rshift));
}

void ini_shift1(void)
{
	memcpy(initial4, initial, 4);
	setmem(initial, 4, 0);
}

void ini_shift2(void)
{
	setmem(initial, 8, 0);
}

void ini_shift3(void)
{
	setmem(initial, 4, 0);
	m.a = char_to_long(initial) >> rshift;
	initial[4] = *mb3;
	initial[5] = *mb2;
	initial[6] = *mb1;
	initial[7] = *mb0;
}

void ini_shift4(void)
{
	ULONG m1 = char_to_long(initial);
	long_to_char((m1 >> rshift),
				 ((m1 << lshift) | (char_to_long(initial4) >> rshift)));
}

void makekey(int flag)
{
	key_L[ 0] = key[56];	key_L[14] = key[ 9];
	key_L[ 1] = key[48];	key_L[15] = key[ 1];
	key_L[ 2] = key[40];	key_L[16] = key[58];
	key_L[ 3] = key[32];	key_L[17] = key[50];
	key_L[ 4] = key[24];	key_L[18] = key[42];
	key_L[ 5] = key[16];	key_L[19] = key[34];
	key_L[ 6] = key[ 8];	key_L[20] = key[26];
	key_L[ 7] = key[ 0];	key_L[21] = key[18];
	key_L[ 8] = key[57];	key_L[22] = key[10];
	key_L[ 9] = key[49];	key_L[23] = key[ 2];
	key_L[10] = key[41];	key_L[24] = key[59];
	key_L[11] = key[33];	key_L[25] = key[51];
	key_L[12] = key[25];	key_L[26] = key[43];
	key_L[13] = key[17];	key_L[27] = key[35];

	key_R[ 0] = key[62];	key_R[14] = key[13];
	key_R[ 1] = key[54];	key_R[15] = key[ 5];
	key_R[ 2] = key[46];	key_R[16] = key[60];
	key_R[ 3] = key[38];	key_R[17] = key[52];
	key_R[ 4] = key[30];	key_R[18] = key[44];
	key_R[ 5] = key[22];	key_R[19] = key[36];
	key_R[ 6] = key[14];	key_R[20] = key[28];
	key_R[ 7] = key[ 6];	key_R[21] = key[20];
	key_R[ 8] = key[61];	key_R[22] = key[12];
	key_R[ 9] = key[53];	key_R[23] = key[ 4];
	key_R[10] = key[45];	key_R[24] = key[27];
	key_R[11] = key[37];	key_R[25] = key[19];
	key_R[12] = key[29];	key_R[26] = key[11];
	key_R[13] = key[21];	key_R[27] = key[ 3];

	memcpy(key_L28, key_L, U28);
	memcpy(key_R28, key_R, U28);

	UINT **ps1 = (flag)? key_Lp1: key_Lp2;
	UINT **ps2 = (flag)? key_Rp1: key_Rp2;
	UINT *p1 = key32;
	UINT *p2 = key16;

	register int i = 8;
	do
	{
		register int k = 2;
		do
		{
			memcpy(tmp0,  *ps1++, U28);
			memcpy(tmp28, *ps2++, U28);

			*p1++ = ((*tmp16 * 2 + *tmp10) * 2 + *tmp23) * 2 + *tmp0;
			*p1++ = ((*tmp27 * 2 + *tmp14) * 2 + *tmp5)  * 2 + *tmp20;
			*p1++ = ((*tmp18 * 2 + *tmp11) * 2 + *tmp3)  * 2 + *tmp25;
			*p1++ = ((*tmp6  * 2 + *tmp26) * 2 + *tmp19) * 2 + *tmp12;
			*p1++ = ((*tmp51 * 2 + *tmp30) * 2 + *tmp36) * 2 + *tmp46;
			*p1++ = ((*tmp39 * 2 + *tmp50) * 2 + *tmp44) * 2 + *tmp32;
			*p1++ = ((*tmp48 * 2 + *tmp38) * 2 + *tmp55) * 2 + *tmp33;
			*p1++ = ((*tmp41 * 2 + *tmp49) * 2 + *tmp35) * 2 + *tmp28;

			*p2++ = *tmp13 * 2 + *tmp4;
			*p2++ = *tmp2  * 2 + *tmp9;
			*p2++ = *tmp22 * 2 + *tmp7;
			*p2++ = *tmp15 * 2 + *tmp1;
			*p2++ = *tmp40 * 2 + *tmp54;
			*p2++ = *tmp29 * 2 + *tmp47;
			*p2++ = *tmp43 * 2 + *tmp52;
			*p2++ = *tmp45 * 2 + *tmp31;
		} while(--k);
	} while(--i);
}

void des(char *in, char *out)
{
	register int m = in[0];
	int m39 = (m >> 7) & 1;
	int m7  = (m >> 6) & 1;
	int m47 = (m >> 5) & 1;
	int m15 = (m >> 4) & 1;
	int m55 = (m >> 3) & 1;
	int m23 = (m >> 2) & 1;
	int m63 = (m >> 1) & 1;
	int m31 =  m       & 1;

	int m30 = (m = in[1]) & 1;
	int m38 = (m >> 7) & 1;
	int m6  = (m >> 6) & 1;
	int m46 = (m >> 5) & 1;
	int m14 = (m >> 4) & 1;
	int m54 = (m >> 3) & 1;
	int m22 = (m >> 2) & 1;
	int m62 = (m >> 1) & 1;

	int m29 = (m = in[2]) & 1;
	int m37 = (m >> 7) & 1;
	int m5  = (m >> 6) & 1;
	int m45 = (m >> 5) & 1;
	int m13 = (m >> 4) & 1;
	int m53 = (m >> 3) & 1;
	int m21 = (m >> 2) & 1;
	int m61 = (m >> 1) & 1;

	int m28 = (m = in[3]) & 1;
	int m36 = (m >> 7) & 1;
	int m4  = (m >> 6) & 1;
	int m44 = (m >> 5) & 1;
	int m12 = (m >> 4) & 1;
	int m52 = (m >> 3) & 1;
	int m20 = (m >> 2) & 1;
	int m60 = (m >> 1) & 1;

	int m27 = (m = in[4]) & 1;
	int m35 = (m >> 7) & 1;
	int m3  = (m >> 6) & 1;
	int m43 = (m >> 5) & 1;
	int m11 = (m >> 4) & 1;
	int m51 = (m >> 3) & 1;
	int m19 = (m >> 2) & 1;
	int m59 = (m >> 1) & 1;

	int m26 = (m = in[5]) & 1;
	int m34 = (m >> 7) & 1;
	int m2  = (m >> 6) & 1;
	int m42 = (m >> 5) & 1;
	int m10 = (m >> 4) & 1;
	int m50 = (m >> 3) & 1;
	int m18 = (m >> 2) & 1;
	int m58 = (m >> 1) & 1;

	int m25 = (m = in[6]) & 1;
	int m33 = (m >> 7) & 1;
	int m1  = (m >> 6) & 1;
	int m41 = (m >> 5) & 1;
	int m9  = (m >> 4) & 1;
	int m49 = (m >> 3) & 1;
	int m17 = (m >> 2) & 1;
	int m57 = (m >> 1) & 1;

	int m24 = (m = in[7]) & 1;
	int m32 = (m >> 7) & 1;
	int m0  = (m >> 6) & 1;
	int m40 = (m >> 5) & 1;
	int m8  = (m >> 4) & 1;
	int m48 = (m >> 3) & 1;
	int m16 = (m >> 2) & 1;
	int m56 = (m >> 1) & 1;

	UINT *p1 = key32, *p2 = key16;
	register int i = 8;
	do
	{
		int *q = S0[(m63*2+m36)^*p2++][(((m32*2+m33)*2+m34)*2+m35)^*p1++];
		m8  ^= *q;
		m16 ^= *(q + 1);
		m22 ^= *(q + 2);
		m30 ^= *(q + 3);

		q = S1[(m35*2+m40)^*p2++][(((m36*2+m37)*2+m38)*2+m39)^*p1++];
		m12 ^= *q;
		m27 ^= *(q + 1);
		m1  ^= *(q + 2);
		m17 ^= *(q + 3);

		q = S2[(m39*2+m44)^*p2++][(((m40*2+m41)*2+m42)*2+m43)^*p1++];
		m23 ^= *q;
		m15 ^= *(q + 1);
		m29 ^= *(q + 2);
		m5  ^= *(q + 3);

		q = S3[(m43*2+m48)^*p2++][(((m44*2+m45)*2+m46)*2+m47)^*p1++];
		m25 ^= *q;
		m19 ^= *(q + 1);
		m9  ^= *(q + 2);
		m0  ^= *(q + 3);

		q = S4[(m47*2+m52)^*p2++][(((m48*2+m49)*2+m50)*2+m51)^*p1++];
		m7  ^= *q;
		m13 ^= *(q + 1);
		m24 ^= *(q + 2);
		m2  ^= *(q + 3);

		q = S5[(m51*2+m56)^*p2++][(((m52*2+m53)*2+m54)*2+m55)^*p1++];
		m3  ^= *q;
		m28 ^= *(q + 1);
		m10 ^= *(q + 2);
		m18 ^= *(q + 3);

		q = S6[(m55*2+m60)^*p2++][(((m56*2+m57)*2+m58)*2+m59)^*p1++];
		m31 ^= *q;
		m11 ^= *(q + 1);
		m21 ^= *(q + 2);
		m6  ^= *(q + 3);

		q = S7[(m59*2+m32)^*p2++][(((m60*2+m61)*2+m62)*2+m63)^*p1++];
		m4  ^= *q;
		m26 ^= *(q + 1);
		m14 ^= *(q + 2);
		m20 ^= *(q + 3);

		q = S0[(m31*2+m4)^*p2++][(((m0*2+m1)*2+m2)*2+m3)^*p1++];
		m40 ^= *q;
		m48 ^= *(q + 1);
		m54 ^= *(q + 2);
		m62 ^= *(q + 3);

		q = S1[(m3*2+m8)^*p2++][(((m4*2+m5)*2+m6)*2+m7)^*p1++];
		m44 ^= *q;
		m59 ^= *(q + 1);
		m33 ^= *(q + 2);
		m49 ^= *(q + 3);

		q = S2[(m7*2+m12)^*p2++][(((m8*2+m9)*2+m10)*2+m11)^*p1++];
		m55 ^= *q;
		m47 ^= *(q + 1);
		m61 ^= *(q + 2);
		m37 ^= *(q + 3);

		q = S3[(m11*2+m16)^*p2++][(((m12*2+m13)*2+m14)*2+m15)^*p1++];
		m57 ^= *q;
		m51 ^= *(q + 1);
		m41 ^= *(q + 2);
		m32 ^= *(q + 3);

		q = S4[(m15*2+m20)^*p2++][(((m16*2+m17)*2+m18)*2+m19)^*p1++];
		m39 ^= *q;
		m45 ^= *(q + 1);
		m56 ^= *(q + 2);
		m34 ^= *(q + 3);

		q = S5[(m19*2+m24)^*p2++][(((m20*2+m21)*2+m22)*2+m23)^*p1++];
		m35 ^= *q;
		m60 ^= *(q + 1);
		m42 ^= *(q + 2);
		m50 ^= *(q + 3);

		q = S6[(m23*2+m28)^*p2++][(((m24*2+m25)*2+m26)*2+m27)^*p1++];
		m63 ^= *q;
		m43 ^= *(q + 1);
		m53 ^= *(q + 2);
		m38 ^= *(q + 3);

		q = S7[(m27*2+m0)^*p2++][(((m28*2+m29)*2+m30)*2+m31)^*p1++];
		m36 ^= *q;
		m58 ^= *(q + 1);
		m46 ^= *(q + 2);
		m52 ^= *(q + 3);
	} while(--i);

	out[0] = ((((((m7*2+m39)*2+m15)*2+m47)*2+m23)*2+m55)*2+m31)*2+m63;
	out[1] = ((((((m6*2+m38)*2+m14)*2+m46)*2+m22)*2+m54)*2+m30)*2+m62;
	out[2] = ((((((m5*2+m37)*2+m13)*2+m45)*2+m21)*2+m53)*2+m29)*2+m61;
	out[3] = ((((((m4*2+m36)*2+m12)*2+m44)*2+m20)*2+m52)*2+m28)*2+m60;
	out[4] = ((((((m3*2+m35)*2+m11)*2+m43)*2+m19)*2+m51)*2+m27)*2+m59;
	out[5] = ((((((m2*2+m34)*2+m10)*2+m42)*2+m18)*2+m50)*2+m26)*2+m58;
	out[6] = ((((((m1*2+m33)*2+m9 )*2+m41)*2+m17)*2+m49)*2+m25)*2+m57;
	out[7] = ((((((m0*2+m32)*2+m8 )*2+m40)*2+m16)*2+m48)*2+m24)*2+m56;
}

void ecb(void)
{
	while((count = read(handle1, buffer, bufsize)) != 0)
	{
		mem1 = bufsize1;
		if(count != bufsize)
		{
			mem1 = (count + 7) / 8;
			mem = mem1 * 8;
			setmem(buffer + count, mem - count, 0);
		}

		char *p = buffer;
		do
		{
			des(p, p);
			p += 8;
#ifndef NODISP
			if((outsize += blen50) >= outcount)
			{
				fputc('.', stderr);
				outcount += filesize;
			}
#endif
		} while(--mem1);
		write(handle2, buffer, mem);
	}
}

void cbc(void)
{
	while((count = read(handle1, buffer, bufsize)) != 0)
	{
		mem1 = bufsize1;
		if(count != bufsize)
		{
			mem1 = (count + 7) / 8;
			mem = mem1 * 8;
			setmem(buffer + count, mem - count, 0);
		}

		char *p = buffer;
		if(edflag)
		{
			do
			{
				xor8(initial, p);
				des(p, initial);
				memcpy(p, initial, 8);
				p += 8;
#ifndef NODISP
				if((outsize += blen50) >= outcount)
				{
					fputc('.', stderr);
					outcount += filesize;
				}
#endif
			} while(--mem1);
		}
		else
		{
			do
			{
				des(p, bufo);
				xor8(initial, bufo);
				memcpy(initial, p, 8);
				memcpy(p, bufo, 8);
				p += 8;
#ifndef NODISP
				if((outsize += blen50) >= outcount)
				{
					fputc('.', stderr);
					outcount += filesize;
				}
#endif
			} while(--mem1);
		}
		write(handle2, buffer, mem);
	}
}

void ofb(void)
{
	while((count = read(handle1, buffer, bufsize)) != 0)
	{
		mem1 = bufsize1;
		if(count != bufsize)
		{
			mem1 = (count + blen - 1) / blen;
			mem = mem1 * blen;
			setmem(buffer + count, mem - count, 0);
		}

		char *p = buffer;
		do
		{
			des(initial, bufo);
			xor(bufo, p);
			rot_i(bufo);
			p += blen;
#ifndef NODISP
			if((outsize += blen50) >= outcount)
			{
				fputc('.', stderr);
				outcount += filesize;
			}
#endif
		} while(--mem1);
		write(handle2, buffer, mem);
	}
}

void cfb(void)
{
	ini_s();

	while((count = read(handle1, buffer, bufsize)) != 0)
	{
		mem1 = bufsize1;
		if(count != bufsize)
		{
			mem1 = (count + blen - 1) / blen;
			mem = mem1 * blen;
			setmem(buffer + count, mem - count, 0);
		}

		char *p = buffer;
		if(edflag)
		{
			do
			{
				des(initial, bufo);
				xor(bufo, p);
				memcpy(x, xb1, blena);
				memcpy(xb2, p, blen);
				rot_i(x);
				p += blen;
#ifndef NODISP
				if((outsize += blen50) >= outcount)
				{
					fputc('.', stderr);
					outcount += filesize;
				}
#endif
			} while(--mem1);
		}
		else
		{
			do
			{
				des(initial, bufo);
				memcpy(x, xb1, blena);
				memcpy(xb2, p, blen);
				rot_i(x);
				xor(bufo, p);
				p += blen;
#ifndef NODISP
				if((outsize += blen50) >= outcount)
				{
					fputc('.', stderr);
					outcount += filesize;
				}
#endif
			} while(--mem1);
		}
		write(handle2, buffer, mem);
	}
}

void openerr(char *kind, char *file)
{
	fprintf(stderr, "Error : %s file(%s) can't open.\n", kind, file);
	exit(-1);
}

void usage(char *prog)
{
	fprintf(stderr, "Usage : %s [-Xn] [-Kkey] [-Finit] [-Bn] [-Ln] <-E|-D>  file1  file2\n", prog);
	fprintf(stderr, "   -X : Modes of Operations\n");
	fprintf(stderr, "        n : Mode Number (default = 1)\n");
	fprintf(stderr, "           1 = ECB(Electric CodeBook)\n");
	fprintf(stderr, "           2 = CBC(Cipher Block Chaining)\n");
	fprintf(stderr, "           3 = OFB(Output FeedBack)\n");
	fprintf(stderr, "           4 = CFB(Cipher FeedBack)\n");
	fprintf(stderr, "   -K : key file definition\n");
	fprintf(stderr, "        key  : key file name\n");
	fprintf(stderr, "   -F : Initial Value of CBC,OFB,CFB mode(default = all'0'\n");
	fprintf(stderr, "        init : initial value file name\n");
	fprintf(stderr, "   -B : Block length direction\n");
	fprintf(stderr, "        n : Bleck length(1 - 8 Bytes, default = 8)\n");
	fprintf(stderr, "   -L : Key Feedback bit length direction\n");
	fprintf(stderr, "        n : Feedback length(1 - 64, default = 64)\n");
	fprintf(stderr, "   -E : Encryption mode\n");
	fprintf(stderr, "   -D : Decryption mode\n");
	fprintf(stderr, "  file1 : source file\n");
	fprintf(stderr, "  file2 : destination file\n\n");
	fprintf(stderr, "  (note 1 : file is 8byte Hexa-decimal code = 16 characters.)\n");
	exit(0);
}

int main(int argc, char *argv[])
{
	int fi = 0, fk = 0;

	if(argc < 2 || *argv[1] != '-')	usage(argv[0]);
	register int k = 1;
	do
	{
		switch(tolower(*(argv[k] + 1)))
		{
		case 'x':	mode = atoi(argv[k] + 2);
					if(mode < 1 || mode > 4)	usage(argv[0]);
					break;
		case 'k':	fk = k;
					break;
		case 'f':	fi = k;
					break;
		case 'b':	blen = atoi(argv[k] + 2);
					if(blen < 1 || blen > 8)	usage(argv[0]);
					break;
		case 'l':	llen = atoi(argv[k] + 2);
					if(llen < 1 || llen > 64)	usage(argv[0]);
					break;
		case 'd':	if(edflag == 1)	usage(argv[0]);
					edflag = 0;
					break;
		case 'e':	if(edflag == 0)	usage(argv[0]);
					edflag = 1;
					break;
		case 'm':	fp = fopen("des.man", "rt");
					if(fp == NULL)	openerr("Document", "des.man");
					while(fgets(buffer, 256, fp) != NULL)
						fprintf(stderr, "%s", buffer);
					fclose(fp);
					exit(0);
		case '?':	usage(argv[0]);
		default:	fprintf(stderr, "Error : illegal option.\n");
					usage(argv[0]);
		}
	} while(*argv[++k] == '-');

	if(mode <= 2)	blen = 8;
	blena = 8 - blen;

#ifndef NODISP
	blen50 = blen * 50;
#endif

	if((mode == 4 && blen * 8 > llen) || edflag == -1)	usage(argv[0]);

	if(k < argc)
	{
		k1 = k++;
		if(k < argc)	k2 = k;
	}
	if(k1 == 0 || k2 == 0)	usage(argv[0]);

	if(fk != 0)
	{
		handle1 = open(argv[fk] + 2, O_RDONLY | O_BINARY);
		if(handle1 == -1)	openerr("key", argv[fk] + 2);
		read(handle1, keybuf, 16);
		keyset();
		close(handle1);
	}

	if(mode >= 2 && fi != 0)
	{
		handle1 = open(argv[fi] + 2, O_RDONLY | O_BINARY);
		if(handle1 == -1)	openerr("initial", argv[fi] + 2);
		read(handle1, inibuf, 16);
		iniset();
		close(handle1);
	}

	handle1 = open(argv[k1], O_RDONLY | O_BINARY);
	if(handle1 == -1)	openerr("source", argv[k1]);
	fp = fopen(argv[k2], "rb");
	if(fp != NULL)
	{
		fprintf(stderr, "Error : destination file(%s) already exist.\n",
			argv[k2]);
		exit(-1);
	}
	handle2 = open(argv[k2], O_WRONLY | O_CREAT | O_BINARY, S_IREAD | S_IWRITE);

#ifndef NODISP
	outcount = filesize = filelength(handle1);

	fprintf(stderr, "\nDES%s (Ver.%s)     ( %s --> %s )\n",
		(edflag)? "暗号化": "復号化", VER, argv[k1], argv[k2]);
	fprintf(stderr, "  Copyright(C) %s %s\n         ----+----!----+----!----+----!----+----!----+----!\n処理進行 ",
		DATE, COPYRIGHT);
#endif

	bp = buffer;
	bufsize1 = BUFFER_SIZE / blen;
	mem = bufsize = bufsize1 * blen;

	if(mode >= 3)
	{
		switch(blen)
		{
		case 1:	xor = xor1;		break;
		case 2:	xor = xor2;		break;
		case 3:	xor = xor3;		break;
		case 4:	xor = xor4;		break;
		case 5:	xor = xor5;		break;
		case 6:	xor = xor6;		break;
		case 7:	xor = xor7;		break;
		case 8:	xor = xor8;		break;
		}

		if(mode == 4)
		{
			xb1 = x + blen;
			xb2 = x + blena;
		}
		if(llen == 32)
		{
			ini_s = ini_shift1;
			rot_i = rot_initial1;
		}
		else if(llen == 64)
		{
			ini_s = ini_shift2;
			rot_i = rot_initial2;
		}
		else if(llen < 32)
		{
			ini_s = ini_shift3;
			rot_i = rot_initial3;
			lshift = llen;
			rshift = 32 - lshift;
		}
		else
		{
			ini_s = ini_shift4;
			rot_i = rot_initial4;
			lshift = llen - 32;
			rshift = 32 - lshift;
		}
	}

	makekey((mode <= 2)? edflag: 1);

	switch(mode)
	{
	case 1:	ecb();		break;
	case 2:	cbc();		break;
	case 3:	ofb();		break;
	case 4:	cfb();		break;
	}
#ifndef NODISP
	fputc('\n', stderr);
#endif
	close(handle1);
	close(handle2);
	return 0;
}

使用例           top (トップに戻る)


下記、コマンド群を処理した例を示します。
des コマンドの様々なオプション使用方法を紹介しています。
( bmatch コマンドは、2つのファイルのバイナリレベルの一致を検査する機能があります。)
また、あらかじめ、初期値および暗号鍵を記述したファイル initial、key を準備しています。
	des -e -kkey des.man dummy1
	des -d -kkey dummy1 dummy1m
	bmatch dummy1m des.man
	des -x2 -finitial -e -kkey des.man dummy2
	des -x2 -finitial -d -kkey dummy2 dummy2m
	bmatch dummy2m des.man
	des -x3 -finitial -b6 -e -kkey des.man dummy3
	des -x3 -finitial -b6 -d -kkey dummy3 dummy3m
	bmatch dummy3m des.man
	des -x4 -finitial -b6 -l50 -e -kkey des.man dummy4
	des -x4 -finitial -b6 -l50 -d -kkey dummy4 dummy4m
	bmatch dummy4m des.man

DES暗号化 (Ver.2.0)     ( des.man --> dummy1 )
  Copyright(C) 1994/11/05 by Tomy(NIFTY:SGV01401) all rights reserved.
         ----+----!----+----!----+----!----+----!----+----!
処理進行 ..................................................

DES復号化 (Ver.2.0)     ( dummy1 --> dummy1m )
  Copyright(C) 1994/11/05 by Tomy(NIFTY:SGV01401) all rights reserved.
         ----+----!----+----!----+----!----+----!----+----!
処理進行 ..................................................
file1(dummy1m) & file2(des.man) matched in 5052 byte.

DES暗号化 (Ver.2.0)     ( des.man --> dummy2 )
  Copyright(C) 1994/11/05 by Tomy(NIFTY:SGV01401) all rights reserved.
         ----+----!----+----!----+----!----+----!----+----!
処理進行 ..................................................

DES復号化 (Ver.2.0)     ( dummy2 --> dummy2m )
  Copyright(C) 1994/11/05 by Tomy(NIFTY:SGV01401) all rights reserved.
         ----+----!----+----!----+----!----+----!----+----!
処理進行 ..................................................
file1(dummy2m) & file2(des.man) matched in 5052 byte.

DES暗号化 (Ver.2.0)     ( des.man --> dummy3 )
  Copyright(C) 1994/11/05 by Tomy(NIFTY:SGV01401) all rights reserved.
         ----+----!----+----!----+----!----+----!----+----!
処理進行 ..................................................

DES復号化 (Ver.2.0)     ( dummy3 --> dummy3m )
  Copyright(C) 1994/11/05 by Tomy(NIFTY:SGV01401) all rights reserved.
         ----+----!----+----!----+----!----+----!----+----!
処理進行 ..................................................
file1(dummy3m) & file2(des.man) matched in 5052 byte.

DES暗号化 (Ver.2.0)     ( des.man --> dummy4 )
  Copyright(C) 1994/11/05 by Tomy(NIFTY:SGV01401) all rights reserved.
         ----+----!----+----!----+----!----+----!----+----!
処理進行 ..................................................

DES復号化 (Ver.2.0)     ( dummy4 --> dummy4m )
  Copyright(C) 1994/11/05 by Tomy(NIFTY:SGV01401) all rights reserved.
         ----+----!----+----!----+----!----+----!----+----!
処理進行 ..................................................
file1(dummy4m) & file2(des.man) matched in 5052 byte.

マニュアル           top (トップに戻る)

高速DES処理プログラム
  (DES : Data Encryption Standard : データ暗合化規格)

  1. 使用法
    DES [-Xn] [-Kkey] [-Finit] [-Bn] [-Ln] <-E|-D> file1 file2

    [オプション説明]
          
    • -X はDESの利用モードを指定する場合に使用するオプションで,下記番号で指定する。
      デフォルトは1である。(3項参照)
              
      1. : ECB(Electric CodeBook)
      2. : CBC(Cipher Block Chaining)
      3. : OFB(Output FeedBack)
      4. : CFB(Cipher FeedBack)

    • -K は暗合化および複合化を行うキーの定義ファイル名 key を指定する。
      複号時には,暗合化時と同じキーを定義したファイル名を指定せねばならない。
      キーは,8バイトの16進コード(0-9,A-F:16文字)で設定する。
      -K オプションは省略可能であるが,省略時は all'0'のキーを設定する。

    • 利用モード 1 以外の利用オプションを指定する場合には,初期値を指示する必要があり,
      -Fに続き初期値を定義したファイル名を指定する。
      初期値は,8バイトの16進コード(0-9,A-F:16文字)で設定する。
      初期値は省略可能であるが,省略時は all'0'が指定されたものとみなす。

    • -K 及び -F オプションでは、任意のファイル指定可(バイナリファイルも可)。
      先頭の16バイトをデータと見なす。16進テキストコード以外の場合は、0x0f との
      ANDをとって4ビットのデータに変換している。

    • 利用モード 3,4 は,DES を乱数キーとして使用する逐次暗合であり,1回で処理する
      ブロック長を -B オプションにて指定する。(1〜8 バイト,デフォルトは8)

    • 利用モード 4 では,さらに暗合文フィードバックのビット数を指定する。
      これは,-L オプションを用い 1〜64 で指定するが,-B オプション指定のブロック長
      以上でなければならない。(デフォルトはブロック長と同じ。)

    • -E(暗合化)または -D(複号化)のどちらかのオプションを必ず指定する。
      オプション指定により,file1 を暗合化または複号化し,file2 を生成する。
    なお,-X,-K,-F,-B,-L,-E,-D の各オプションは,小文字でも大文字でも良い。
  2. 利用モード説明
    米国商務省標準局(NBS)及び国際標準化機構(ISO)で提案されている
    DESの利用モード4種にほぼ対応した。
    (1) ECB(Electric CodeBook)モード

    DESをそのまま用いた8バイトのブロック暗合方式。DESアルゴリズムの暗合キーを
    パラメータとして与える。この方法では,下記のような問題がある。
          
    • (最終)ブロックが8バイトに充たない場合,0その他の固定ダミービットを挿入する為,
      平文の内容に偏りが生じ,暗合解読の手掛かりを与える。
      特にデータベース等の暗合化に際し,フィールド長が8バイト未満の場合,問題となる。

    • 同一の暗合キーの下では平文8バイトと暗合文8バイトが1対1に対応するため
      既知平文攻撃に対して弱い。

    • ブロック単位で暗合文を改ざんされてもそれが判らない。
    (2) CBC(Cipher Block Chaining)モード

    暗合文ブロック連鎖方式。
    DESアルゴリズムの暗合キーとブロック連鎖の初期値をパラメータとして与える。
    暗合文8バイトと次の平文8バイトの排他的論理和を次の暗合化の入力とする。
    この方法では,ビット誤りが2つのブロックに伝播する欠点がある。
    (3) OFB(Output FeedBack)モード

    出力フィードバックによる同期式逐次暗合方式。
    DESアルゴリズムの暗合キー,乱数キー生成用初期値,逐次暗合ブロック長を
    パラメータとして与える。
    任意バイト長(1〜8)のブロック毎に異なる(乱数)キーで暗合化(平文との排他的論理和)を行う。
    この乱数キーの生成にDESアルゴリズムを利用する。
    乱数キーを次のブロックの暗合化を行うための乱数キー生成の入力とする。
    この方式は暗合文のビット消滅が発生した場合,その後のすべての暗合文に対する
    同期が外れる。
    (4) CFB(Cipher FeedBack)モード

    暗合文フィードバックによる自己同期式逐次暗合方式。
    DESアルゴリズムの暗合キー,乱数キー生成用初期値,逐次暗合ブロック長,
    暗合文フィードバックビット長をパラメータとして与える。
    乱数キー生成のフィードバックにおいて暗合文の一部をフィードバックする。
    この方式は暗合文のビット消滅が発生した場合,後続のLビットの暗合文に影響を与える。

  3. 参考文献
    1)現代暗号理論  池野伸一,小山謙二 共著  電子通信学会編
    2)ネットワーク・セキュリティ  D.W.Davies,W.L.Price 共著 上園忠弘 監訳  日経マグロウヒル社

  4. 開発環境
      
    • コンパイラ  Turbo C++ Ver1.0
    • 動作確認機種 PC9801NA

  5. その他
      
    • DESのプログラムに関しては、既に渡辺 雅彦氏(MAG44 : NIFTY-Serve HDA00765)が
      発表されている(NIFTY-Serve,FGALST,LIB6,#263)ので、わざわざ同じものを発表する
      必要はないと思ったが、高速処理と利用モード他を選択できるオプション対応を特長と
      するので、何か役立ててくれる人がいるかも知れないと思い直し、発表することとした。