ENIGMA是一种复式替换序列密码体系,所谓序列密码,是指加密不分组,加密后的信息与加密前是等长的,简化了对通信buf的处理。它的强度并非很高。在商业通信中,完全不加密是危险的,过于复杂的加密也没必要。就像我们家庭,没必要像国库的安全级别,但也不能不锁门,我们通常使用的弹子锁,就是一种经济简便的安全措施。。
直到第一次世界大战结束为止,所有密码都是使用手工来编码的。直接了当地说,就是铅笔加纸的方式。在我国,邮电局电报编码和译码直到很晚(大概是上个世纪八十年代初)还在使用这种手工方法。手工编码的方式给使用密码的一方带来很多的不便。首先,这使得发送信息的效率极其低下。明文(就是没有经过加密的原始文本)必须由加密员人工一个一个字母地转换为密文。考虑到不能多次重复同一种明文到密文的转换方式(这很容易使敌人猜出这种转换方式),和民用的电报编码解码不同,加密人员并不能把转换方式牢记于心。转换通常是采用查表的方法,所查表又每日不同,所以解码速度极慢。而接收密码一方又要用同样的方式将密文转为明文。其次,这种效率的低下的手工操作也使得许多复杂的保密性能更好的加密方法不能被实际应用,而简单的加密方法根本不能抵挡解密学的威力。
解密一方当时正值春风得意之时,几百年来被认为坚不可破的维吉耐尔(Vigenere)密码和它的变种也被破解。而无线电报的发明,使得截获密文易如反掌。无论是军事方面还是民用商业方面都需要一种可靠而又有效的方法来保证通讯的安全。
1918年,德国发明家亚瑟·谢尔比乌斯(ArthurScherbius)和他的朋友理查德·里特(RichardRitter)创办了谢尔比乌斯和里特公司。这是一家专营把新技术转化为应用方面的企业,很象现在的高新技术公司,利润不小,可是风险也很大。谢尔比乌斯负责研究和开发方面,紧追当时的新潮流。他曾在汉诺威和慕尼黑研究过电气应用,他的一个想法就是要用二十世纪的电气技术来取代那种过时的铅笔加纸的加密方法。
谢尔比乌斯发明的加密电子机械名叫ENIGMA,在以后的年代里,它将被证明是有史以来最为可靠的加密系统之一,而对这种可靠性的盲目乐观,又使它的使用者遭到了灭顶之灾。这是后话,暂且不提。
ENIGMA看起来是一个装满了复杂而精致的元件的盒子。不过要是我们把它打开来,就可以看到它可以被分解成相当简单的几部分。下面的图是它的最基本部分的示意图,我们可以看见它的三个部分:键盘、转子和显示器。
在上面ENIGMA的照片上,我们看见水平面板的下面部分就是键盘,一共有26个键,键盘排列接近我们现在使用的计算机键盘。为了使消息尽量地短和更难以破译,空格和标点符号都被省略。在示意图中我们只画了六个键。实物照片中,键盘上方就是显示器,它由标示了同样字母的26个小灯组成,当键盘上的某个键被按下时,和此字母被加密后的密文相对应的小灯就在显示器上亮起来。同样地,在示意图上我们只画了六个小灯。在显示器的上方是三个转子,它们的主要部分隐藏在面板之下,在示意图中我们暂时只画了一个转子。
键盘、转子和显示器由电线相连,转子本身也集成了6条线路(在实物中是26条),把键盘的信号对应到显示器不同的小灯上去。在示意图中我们可以看到,如果按下a键,那么灯B就会亮,这意味着a被加密成了B。同样地我们看到,b被加密成了A,c被加密成了D,d被加密成了F,e被加密成了E,f被加密成了C。于是如果我们在键盘上依次键入cafe(咖啡),显示器上就会依次显示DBCE。这是最简单的加密方法之一,把每一个字母都按一一对应的方法替换为另一个字母,这样的加密方式叫做“简单替换密码” 。
1 cat enigma1.c 2 3 #include <stdio.h> 4 5 #include <netcom.h> 6 7 #include <crc32.h> 8 9 /* 10 11 * A one-rotor machine designed along the lines of Enigma 12 13 * but considerably trivialized. 14 15 */ 16 17 char *des_fcrypt(); 18 19 char *crypt(); 20 21 #define ECHO 010 22 23 #include <stdio.h> 24 25 #define MASK 0377 26 27 28 29 30 31 /* 生成密码轮 */ 32 33 static enigma1_setup(pw,salt,conn) 34 35 char *pw,*salt; 36 37 struct crypt_s *conn; 38 39 { 40 41 int ic, i, k, temp; 42 43 unsigned random,seed; 44 45 char *buf,buf1[20]; 46 47 char *t1; 48 49 char *t2; 50 51 char *t3; 52 53 54 55 t1=conn->t1; 56 57 t2=conn->t2; 58 59 t3=conn->t3; 60 61 seed=ssh_crc32(pw,strlen(pw)); // seed=123; 62 63 64 65 buf=des_fcrypt(pw,salt,buf1); 66 67 for (i=0; i<13; i++) 68 69 seed = seed*buf[i] + i; 70 71 for(i=0;i<ROTORSZ;i++) { 72 73 t1[i] = i; 74 75 t3[i] = 0; 76 77 } 78 79 for(i=0;i<ROTORSZ;i++) { 80 81 seed = 5*seed + buf[i%13]; 82 83 random = seed % 65521; //random(key); 84 85 /* 生成主编码轮 t1 */ 86 87 k = ROTORSZ-1 - i; 88 89 ic = (random&MASK)%(k+1); 90 91 92 93 temp = t1[k]; 94 95 t1[k] = t1[ic]; 96 97 t1[ic] = temp; 98 99 /************************************************************************ 100 101 * 生成反射板 反射板只要不重不漏的把各点两两连接起来? 102 103 * 可以随机的 104 105 ************************************************************************/ 106 107 if(t3[k]!=0) continue; 108 109 random >>= 8; 110 111 ic = (random&MASK) % k; 112 113 while(t3[ic]!=0) ic = (ic+1) % k; 114 115 t3[k] = ic; 116 117 t3[ic] = k; 118 119 } 120 121 /* t2为t1的逆 */ 122 123 for(i=0;i<ROTORSZ;i++) 124 125 t2[t1[i]&MASK] = i; 126 127 } 128 129 130 131 void enigma1(pass, salt,string,len,conn) 132 133 char *pass,*string,*salt; 134 135 int len; 136 137 struct crypt_s *conn; 138 139 { 140 141 register char *p; 142 143 register int k; 144 145 int n1; 146 147 int n2; 148 149 char *t1,*t2,*t3; 150 151 152 153 if(!conn->pw||strncmp(conn->pw,pass,strlen(conn->pw))||strncmp(conn->salt,salt,2)) { 154 155 strncpy(conn->pw,pass,PWLEN); 156 157 strncpy(conn->salt,salt,SALTLEN); 158 159 conn->pw[PWLEN]=0; 160 161 conn->salt[SALTLEN]=0; 162 163 enigma1_setup(conn->pw,conn->salt,conn); 164 165 } 166 167 n2=n1 = 0; 168 169 p=string; 170 171 t1=conn->t1; 172 173 t2=conn->t2; 174 175 t3=conn->t3; 176 177 178 179 for(k=0;k<len;k++){ 180 181 *p++ = t2[(t3[(t1[(*p+n1)&MASK]+n2)&MASK]-n2)&MASK]-n1; 182 183 if(++n1==ROTORSZ) { 184 185 n1 = 0; 186 187 if(++n2==ROTORSZ) n2 = 0; 188 189 } 190 191 } 192 193 } 194 195 其中netcom.h中所需的内容: 196 197 #define ROTORSZ 256 198 199 #define PWLEN 16 200 201 #define SALTLEN 2 202 203 struct crypt_s { 204 205 char pw[PWLEN+1]; 206 207 char salt[SALTLEN+1]; 208 209 char t1[ROTORSZ]; /* pass.c: ROTORSZ*/ 210 211 char t2[ROTORSZ]; 212 213 char t3[ROTORSZ]; 214 215 }; 216 217 218 219 Demo程序: 220 221 #include <stdio.h> 222 223 #include<netcom.h> 224 225 226 227 extern void enigma1(char *key,char *salt,char *string,int len,struct crypt_s *enigma_s); 228 229 230 231 int main(int ac,char *av[]) 232 233 { 234 235 char buf[131702]; 236 237 char *key="agh57Dsar_~3C"; 238 239 int len,i,len1; 240 241 struct crypt_s enis; 242 243 244 245 *enis.salt=0; 246 247 memset(buf,‘A‘,sizeof(buf)); 248 249 buf[sizeof(buf)-1]=0; 250 251 while(!ferror(stdin)) { 252 253 fgets(buf,sizeof(buf),stdin); 254 255 if(feof(stdin)) break; 256 257 TRIM(buf); 258 259 len=strlen(buf); 260 261 enigma1(key+2,key,buf,len,&enis); 262 263 len1=len>30?30:len; 264 265 for(i=0;i<len1;i++) printf("%02X ",buf[i]&255); 266 267 printf("\n"); 268 269 enigma1(key+2,key,buf,len,&enis); 270 271 printf("%.100s\n",buf); 272 273 274 275 } 276 277 return 0; 278 279 } 280 281
这是一个单轮带反射器的ENIGMA加密/解密机。256个位置的转轮,可加密二进制字节信息。反射器可以转动,等价一个编码轮,或称为反射轮。它的序列长度为64K,比ENIGMA的17576长。ENIGMA之所以被破解,源于它只有3个转轮,敌方得到了这3个转轮,又得知每次3个转轮的排列、起始位置、插线板设置,就完全破解了。
我们在SDBC中的使用,每次连接时动态生成密钥,密钥是非常随机的,等于有无数个转轮。如果要破解此密码,可以设法再生t1码轮和t3反射轮(这可是相当于长达512字节的密钥),这似乎是比较困难的。再有就是对密钥的强力攻击了,这个程序是采用crypt密钥生成转轮的,强度等同于crypt。当然,也可以采用强度更高的算法生成转轮。这个算法是否应该再增加一些转轮来提高强度?我认为没必要。它主要用于网络通信,数据包通常都不会超过64K,增加转轮不过是增加序列长度,超过64K的序列并无意义,却要大幅度增加开销。
SDBC使用这个程序,基本都属于短时效数据,经过长时间破解了,已经没有意义。对于长时效数据,用户应该采用其他方法自行加密。而SDBC是支持二进制数据传输的。