#!/usr/local/bin/tcc -run #include #define BUFFER 1024 // 10bit列から左から3,5,2,7,4,10,1,9,8,6bit目の順番で抽出し、10bit列へ転置 // コンピュータ上では右からbitを繰り上げていくので、10-x番目のbitを対象とする。 // 1,2,3,4,5, 6,7,8,9,10 // 3,5,2,7,4,10,1,9,8,6 #define P10(v) ( \ ((v)<<2&0x200)| ((v)<<3&0x100)| \ ((v)>>1&0x80) | ((v)<<3&0x40) | ((v)>>1&0x20) | ((v)<<4&0x10) | \ ((v)>>6&0x08) | ((v)<<1&0x04) | ((v)>>1&0x02) | ((v)>>4&0x01) \ ) // 10bit列から左から6,3,7,4,8,5,10,9bit目の順番で抽出し、8bit列へ転置 // 1,2,3,4,5,6,7,8,9,10 // 6,3,7,4,8,5,10,9 #define P8(v) ( \ ((v)<<3&0x80) | ((v)>>1&0x40) | ((v)<<2&0x20) | ((v)>>2&0x10) | \ ((v)<<1&0x08) | ((v)>>3&0x04) | ((v)<<1&0x02) | ((v)>>1&0x01) \ ) // 4bit列から左から2,4,3,1bit目の順番で抽出し、4bit列へ転置 // 1,2,3,4 // 2,4,3,1 #define P4(v) ( \ ((v)<<2&0x8) | ((v)<<2&0x4) | \ ((v) &0x2) | ((v)>>3&0x1) \ ) // 5bit用算術シフト #define LS1(v) ((((v)<<1)|((v)>>4&1)) & 0x1F) #define LS2(v) ((((v)<<2)|((v)>>3&3)) & 0x1F) // IP_1(IP(X)) = X となる転置関数(8bit) #define IP(v) ( \ ((v)<<1&0x80) | ((v)<<4&0x40) | ((v) &0x20) | ((v)>>3&0x10) | \ ((v)>>1&0x08) | ((v)<<2&0x04) | ((v)>>2&0x02) | ((v)>>1&0x01) \ ) #define IP_1(v) ( \ ((v)<<3&0x80) | ((v)>>1&0x40) | ((v) &0x20) | ((v)<<1&0x10) | \ ((v)<<2&0x08) | ((v)>>4&0x04) | ((v)<<1&0x02) | ((v)>>2&0x01) \ ) // S-Box 0 const static char S0[4][4]={ {1,0,3,2}, {3,2,1,0}, {0,2,1,3}, {3,1,3,2} }; // S-Box 1 const static char S1[4][4]={ {0,1,2,3}, {2,0,1,3}, {3,0,1,0}, {2,1,0,3} }; // E/P 4bit(1,2,3,4) => 8bit(4,1,2,3,2,3,4,1)に変換 #define EP(v) ( \ ((v)<<7&0x80) | ((v)<<3&0x40) | ((v)<<3&0x20) | ((v)<<3&0x10) | \ ((v)<<1&0x08) | ((v)<<1&0x04) | ((v)<<1&0x02) | ((v)>>3&0x01) \ ) // 左4bitと右4bitを入れ替え #define SW(v) (((v)<<4)|((v)>>4)) #define DES_ENCRYPT(a,b,c,d) _des_crypt(0,(a),(b),(c),(d)) /* 暗号化 */ #define DES_DECRYPT(a,b,c,d) _des_crypt(1,(a),(b),(c),(d)) /* 復号化 */ // S-DES // sw : 暗号化/復号化 切り替え(0:暗号化, 1:復号化) // in : 暗号化/復号化するデータ列 // out: 暗号化/復号化したデータを記録する配列 // key: 10bitキー(2byte) // len: 暗号化/復号化するデータ列の長さ void _des_crypt(char sw, const char *in, char *out, short key, int len){ register unsigned char key1, key2; // 鍵 register unsigned char tmp, tmp2; // 作業領域 // 転置P10 key = P10(key); // 10bit列を左と右5bitに分け、5bit算術左シフト(1)をし、10bit列を生成 key = LS1(key>>5)<<5|LS1(key&0x1F); // 統合 key1 = P8(key); // key1取得 // 10bit列を左と右5bitに分け、5bit算術左シフト(2)をし、10bit列を生成 key = LS2(key>>5)<<5|LS2(key&0x1F); // 統合 key2 = P8(key); // key2取得 // 復号化切り替え if(sw){ tmp=key1; key1=key2; key2=tmp; } while(len--){ // in tmp2 = IP(*in); // round 1 tmp = EP(tmp2&0xF) ^ key1; tmp = S0[(tmp>>6&2)|(tmp>>4&1)][(tmp>>5&3)]<<2 | S1[(tmp>>2&2)|(tmp&1)][(tmp>>1&3)]; // S0[14][23]<<2 | S1[14][23] // tmp = P4(tmp); // tmp = (tmp ^ (tmp2>>4)) << 4 | (tmp2&0xF); // tmp xor 左4bit | 右4bit tmp = P4(tmp) << 4 ^ tmp2; // SWAP (右4|左4) => (左4|右4) tmp2= SW(tmp); // round 2 tmp = EP(tmp2&0xF) ^ key2; tmp = S0[(tmp>>6&2)|(tmp>>4&1)][(tmp>>5&3)]<<2 | S1[(tmp>>2&2)|(tmp&1)][(tmp>>1&3)]; tmp = P4(tmp) << 4 ^ tmp2; // out *out++ = IP_1(tmp); ++in; } *out = 0; } // keyの値を2進数で出力 // key: 値 bits: bit長 void check_bit(const short key, char bits){ while(bits--) putchar(((key>>bits)&1) ? '1' : '0'); puts(""); } // データ列sの内容を16進数出力 // s: データ列 len: データ列の長さ void check_binary(const unsigned char *s, int len){ while(len--) printf("%02X ", *s++); puts(""); } // s1とs2のデータが一致しているか確認。不一致な所だけ出力し、不一致数も出力。 // s1,s2: 比較データ len: データ列の長さ void check_comp(const unsigned char *s1, const unsigned char *s2, int length){ int i=0; while(length--){ if(*s1 != *s2){ printf("%c(%02X) :", *s1, *s1), check_bit(*s1, 8); printf(" %c(%02X):", *s2, *s2), check_bit(*s2, 8); ++i; } ++s1, ++s2; } printf("hits: %d\n", i); } // 文字列長を返す int mystrlen(const char *s){ int i=0; while(*s++) ++i; return i; } void main(void){ char input[BUFFER]; // 暗号化するデータ char output[BUFFER]; // 暗号化したデータ char output2[BUFFER]; // 復号化したデータ int length; short key; printf("文字列を入力: "); fgets(input,1024, stdin); length = mystrlen(input); printf("key(16bit): "); scanf("%hd", &key); DES_ENCRYPT(input, output, key, length); DES_DECRYPT(output, output2, key, length); printf("キー : %hd\n", key); printf("入力 : " ), check_binary(input, length); printf("暗号化: "), check_binary(output,length); printf("復号化: " ), check_binary(output2, length); }