- 主题:介绍一种加密算法 (转载)
【 在 ylh1969 的大作中提到: 】
: 发信人: ylh1969 (没谱), 信区: Algorithm
: 标 题: 介绍一种加密算法
: 发信站: 水木社区 (Thu Dec 18 16:54:15 2025), 站内
: ...................
原文2楼:
*p = t2[(t3[(t1[(*p+n1)&MASK]+n2)&MASK]-n2)&MASK]-n1;
这一句,是整个加解密的核心算法。老祖宗传下来的,旋转转轮,久经考验的,一个字不敢改。
但是我自己推导只能到:
*p = t2[(t3[(t1[(*p+n1)&MASK]+n2)&MASK]-n2)&MASK];
不知道为何要-n1。
t1是编码轮,t2是t1的反查表。t3是反射轮。n1是t1的相位(转动角度),n2是t3的相位。
t1转256步t3转1步。t3转256步回到原位。共63+1K步。所以序列长度是63+1K。
t2不能转,它是t1的固定反查表。所以,在查t2的时候,必须把转动角还原回去。
里边+n1 +n2是转动,-n2是还原。从t2中查出来的,就是密文了。
明文+n1查t1,结果+n2查t3,t3的结果-n2查t2,得密文。
--
修改:ylh1969 FROM 221.221.50.*
FROM 221.221.50.*
比异或慢。
异或的破解方法,如果知道一段明文和密文。异或一下就得到密钥。
二者都是序列密码。异或要有足够长的序列,一次一密才安全。
你可以设想通信双方,客户端和服务器,一个服务器可以与许多的客户端对话。那么这么多对会话,怎样实现共享一个规模巨大的,一次一密的密码本?即使在一个会话里,怎样在无数个交互中使用一次一密?所以,异或法,不可能在广泛的通信场合中使用。
这个ENIGMA不可能从已知明文和密文猜出密钥。图灵就猜出来过(它那个密钥,就是3个字母,好猜,我们这个不是),但是这次改进了,图灵也猜不出来了。
它可以用较短的密钥,生成一个转轮机,本转轮机可以生成长达63+1K的序列(原始的ENIGMA是17576的序列)。如果明文很长,序列将被循环利用。
见原帖3楼的实例:
int main(int ac,char *av[])
{
char buf[131702];//128K,用于测试序列周期
int len,i,len1;
ENIGMA t;
ENIGMA2 egm;
struct timeval beg,end;
enigma1_init(t,"永 垂 不 朽,Enigma");//生成转轮,这就是一个测试,用汉字做密钥真不是好办法,双方不是一个字符集就瞎了
。。。。。。
在每次会话开始,双方约定一个密钥,各自生成相同的转轮,就可以在一个会话生命期内反复使用这个转轮,效率很高的算法。
这个算法,在网络通信领域很有价值。一般使用的DES,AES等等是分组密钥,加密要凑整个分组,在通信包头里要指明在整个数据包里有多少是有效字节,用于剔除填充字节。在已经应用中的包头里添加参数信息,会导致整个系统的颠覆式升级(新旧协议不兼容)。所以在一个旧系统升级加密功能,用分组密钥是不方便的。
【 在 callmebbser 的大作中提到: 】
: 与异或运算比,优点在哪?速度与异或运算比如何?
:
--
修改:ylh1969 FROM 221.221.50.*
FROM 221.221.50.*
举个例子,如果采用128bit的密钥,就是16字节,这在分组密钥中是不错的了。
异或加密一段明文。如果发现了这个明文的一部分,跟密文异或一下,就会发现16字节为周期的规律。就可以解读其它部分。如果继续使用这个密钥,就等于公开的啦!
如果采用很长很长的密钥,分发,运用和管理都很麻烦。
ENIGMA,用比较小的空间(256×3),制造了63+1K的序列。在这么长的字节序里,不存在明文密文的规律性对应关系。
而且,可以采用更短的密钥,扩散成这个768byte的转轮机。
传输,分发,管理都很方便。
enigma1_init(t,"随便一个128bit密钥");就可以生成一个转轮,具有63+1k的序列长度。而且允许使用任意长度的密钥,加密速度和安全性与密钥长度无关。明文密文间的关系,不能反推转轮,更不能反推密钥。
在一段不长的时间,如一个会话的生存期内使用,不会有明显的安全风险。
当然,它依然具有可窥测性,所以,在这个软件包里,提供了加强版。如何窥测以及如何降低其可窥测性,可以继续讨论。
【 在 callmebbser 的大作中提到: 】
: 与异或运算比,优点在哪?速度与异或运算比如何?
:
--
修改:ylh1969 FROM 221.221.50.*
FROM 221.221.50.*
太感谢啦,做了一个客观的评价。
不过,我还要几句话要说。
这个的确是商用。为的是简便快速解决一般通信过程中的加密需求,抗攻击性仅限于在会话存续期间。并非需要历史考量的战略性数据,经过一段时间,即使破译了,基本上这些信息也没啥用了。
经测试,enigma2的加密解密速度,对于128K的数据包,速度是128des的9倍,128aes的3倍。通信过程一般不会有太大的数据包。所以速度不是大问题。
【 在 hotfix 的大作中提到: 】
: 我是不太懂加密算法,看一下AI的评价吧
--
修改:ylh1969 FROM 221.221.50.*
FROM 221.221.50.*
哦,我说的是软件,openssl里的。咱们一般商用网络应用,不会去买加密卡吧?经济性问题。如果是网络应用,服务器用加密卡,客户端还是要用软件,还得保证二者兼容。具体加密软件里边会有很多细节的。
提供给一般码农做通信软件用的。
我真是希望能有一大堆数学家进行安全评估,可惜我没有那么多钱。至于反推转轮的可能性,确实需要做数学评估。
【 在 hotfix 的大作中提到: 】
: 你这个速度测试感觉不太靠谱
: AES现在都是硬件直接支持的. 很难相信你会比AES快
:
--
修改:ylh1969 FROM 221.221.50.*
FROM 221.221.50.*
【 在 hotfix 的大作中提到: 】
: 我是不太懂加密算法,看一下AI的评价吧
关于反推转轮,在ENIGMA1里,我可以给出一个办法,采用选择明文法,用那个teni.c就行。
63+1k个0X00
63+1k个0X01
。
。
。
63+1k个0XFF
把它们的密文收集起来,得到一个256列×(63+1)K行的矩阵。
如果每次步进1步,这个矩阵基本可用。
但是ENIGMA1不是每次步进1步,这个矩阵需要排排序。
根据这个矩阵反推转轮是可能的。
6楼说frenz可能倒推转轮,不是吧,它的旋转步数完全不确定,在那个矩阵里,每行的各列,旋转步数各不相同,根本就不是原表的行列关系。不知道怎么倒推。
ENIGMA2,想都不要想。
它是ENIGMA1和frenz的结合,先用frenz(从头到尾关联一次,如果两个明文只差1bit,密文中这个字节及之后的所有字节都会改变),然后倒序一次,从尾到头再关联一次。
再切一次牌。完全打破了明文密文字节一一对应的关系。
最后用ENIGMA1再加密一次。AI说的混合效率低就是通过二次加密解决的。不需要反复的混合(洗牌)。
双向关联的结果,如果两个明文只差1bit,密文将完全不同(抵抗差分分析法)。
它完全可以抵抗暴力破解。因为需要先破解ENIGMA1,但是破解时没有依据,不知道得到什么样的东西是正确的。无从判断,就算真的破解开了,结果也是一堆乱码,这种情况就是量子计算机也没辙。
AI说的很对,本软件提供3个级别的方法,要速度还是要安全,你自己选。
--
修改:ylh1969 FROM 221.221.50.*
FROM 221.221.50.*
见6楼。
【 在 hotfix 的大作中提到: 】
: 我是不太懂加密算法,看一下AI的评价吧
这个AI的评价已经相当高了。
不过,应该指出,它里边说的CRC啥的,都是在生成转轮中出现的。转轮的随机性并不完全依赖CRC,它只是随机的一个因素。
给你们的转轮生成器,只是最简单的一种,它实际上只相当于70bit,就是只能生成2^70种转轮,一般情况这就足够了。总共可以有2^2504种不同的转轮,相当于2504bit,这只使用了其中极小部分。
我自己用的是可以生成2504bit的生成器。这可不是分组密钥的128,256bit。
256!×(n=1,127)连乘积(2n+1) -> 2504bit。
--
修改:ylh1969 FROM 221.221.50.*
FROM 221.221.50.*
这个高级的生成器:
可以用来替换压缩包里的生成器,不过参数多了一个,可以支持二进制key,从1字节到512字节都可以,想暴力破解的先琢磨琢磨。个别部位要修改一下。
里边的crc32仅用于随机数的种子,与安全性关系不大。
【 在 ylh1969 的大作中提到: 】
: 见6楼。
: 这个AI的评价已经相当高了。
: 不过,应该指出,它里边说的CRC啥的,都是在生成转轮中出现的。转轮的随机性并不完全依赖CRC,它只是随机的一个因素。
: ...................
#include <string.h>
#include <crc32.h>
#include <enigma.h>
/*
* A one-rotor machine designed along the lines of Enigma
* but considerably trivialized.
*/
#define MASK 0377
/* 生成密码轮 */
void enigma_init(ENIGMA t,const char *bin_key,int len)
{
int ic, i, k,random,seed;
signed char temp,*t1,*t2,*t3;
if(!t || !bin_key) return;
if(len<=0 && !(len=strlen(bin_key))) return;
seed=(int)ssh_crc32((unsigned char *)bin_key,len);
t1=t[0]; t2=t[1]; t3=t[2];
// 设置ic,初始化的自旋
ic=seed;
for(i=0;i<len;i++) ic += bin_key[i];
ic &= MASK;
//printf("%s:len=%d,seed=%d,ic=%d\n",__FUNCTION__,len,seed,ic);
// ic,初始化的自旋
for(i=0;i<ROTORSZ;i++) {
t1[i] = (i+ic) & MASK;
t3[i] = 0;
}
if(len>ROTORSZ) {//如果密钥长于ROTORSZ,使用最后一部分
bin_key += len-ROTORSZ;
len = ROTORSZ;
}
for(i=0;i<ROTORSZ;i++) {
seed = (seed<<1) + (signed)bin_key[i%len];
random = (seed&0X7FFFFFFF) % 65529; //random(key);
// 以上生成尽可能随机的random,你有充分的自由度选择你的算法
/* 生成主编码轮 t1 */
k = ROTORSZ-1 - i;
ic = random % (k+1);
temp = t1[k]; t1[k] = t1[ic]; t1[ic] = temp;
/************************************************************************
* 生成反射轮 反射轮只要不重不漏的把各点两两连接起来即可,
************************************************************************/
if(t3[k]!=0) continue;
ic = (random&MASK) % k;
while(t3[ic]!=0) ic = (ic+1) % k;
t3[k] = ic; t3[ic] = k;
}
/* t2为t1的逆 */
for(i=0;i<ROTORSZ;i++)
t2[t1[i]&MASK] = i;
/*
char buf[200],*cp;
cp=buf;
for(i=0;i<32;i++)
cp+=sprintf(cp,"%02X ",t1[i]&255);
ShowLog(5,"%s:len=%d,t1=%s",__FUNCTION__,len,buf);
*/
}
--
修改:ylh1969 FROM 221.221.50.*
FROM 221.221.50.*
哦,我那个测试是2010年测的。现在谁有兴趣再测一下吧。
前边说过,传输加密不用分组密钥的主要原因是需要凑整组,传输的字节数与信息的不等,导致需要另外分配buf,包头信息也需要表明有多少填充字节需要剔除。这不太方便。
6楼关于大文件加密的速度问题,可以把大文件分块处理。
当然,这东西不是为文件加密设计的。但是,vi -x 用的就是这个方法。它的方法比我的还要弱。转轮初值0,0,每次转1步。那么,10楼的矩阵很容易反推出转轮。
【 在 kirbyzhou 的大作中提到: 】
: AES要加密卡干嘛
: x86这边aes-ni指令集有了得10年左右了。
: 软件方便,openssl、jdk都是支持aes-ni的。
: ...................
--
修改:ylh1969 FROM 221.221.50.*
FROM 221.221.50.*