lamport-crypto
摘要: 数字签字和认证机构是电子商务的核心技术。数字签名作为目前Internet中电子商务重要的技术,不断地进行改进,标准化。本文从数字签名的意义出发,详细介绍了数字签名中涉及到的内容与算法,并自行结合进行改进。
关键词:Internet 公钥加密 Hash函数 电子商务 加密 数字签名
数字签名简介
我们对加解密算法已经有了一定理解,可以进一步讨论"数字签名"(注意不要与数字认证混淆)的问题了,即如何给一个计算机文件进行签字。数字签字可以用对称算法实现,也可以用公钥算法实现。但前者除了文件签字者和文件接受者双方,还需要第三方认证,较麻烦;通过公钥加密算法的实现方法,由于用秘密密钥加密的文件,需要靠公开密钥来解密,因此这可以作为数字签名,签名者用秘密密钥加密一个签名(可以包括姓名、证件号码、短信息等信息),接收人可以用公开的、自己的公开密钥来解密,如果成功,就能确保信息来自该公开密钥的所有人。
公钥密码体制实现数字签名的基本原理很简单,假设A要发送一个电子文件给B,A、B双方只需经过下面三个步骤即可:
1. A用其私钥加密文件,这便是签字过程
2. A将加密的文件送到B
3. B用A的公钥解开A送来的文件
这样的签名方法是符合可靠性原则的。即:
签字是可以被确认的,
签字是无法被伪造的,
签字是无法重复使用的,
文件被签字以后是无法被篡改的,
签字具有无可否认性,
数字签名就是通过一个单向函数对要传送的报文进行处理得到的用以认证报文来源并核实报文是否发生变化的一个字母数字串。用这几个字符串来代替书写签名或印章,起到与书写签名或印章同样的法律效用。国际社会已开始制定相应的法律、法规,把数字签名作为执法的依据。
数字签名的实现方法
实现数字签名有很多方法,目前数字签名采用较多的是公钥加密技术,如基于RSA Data Security公司的PKCS(Public Key Cryptography Standards)、DSA(Digital Signature Algorithm)、x.509、PGP(Pretty Good Privacy)。1994年美国标准与技术协会公布了数字签名标准(DSS)而使公钥加密技术广泛应用。同时应用散列算法(Hash)也是实现数字签名的一种方法。
非对称密钥密码算法进行数字签名
算法的含义:
非对称密钥密码算法使用两个密钥:公开密钥和私有密钥,分别用于对数据的加密和解密,即如果用公开密钥对数据进行加密,只有用对应的私有密钥才能进行解密;如果用私有密钥对数据进行加密,则只有用对应的公开密钥才能解密。
使用公钥密码算法进行数字签名通用的加密标准有: RSA,DSA,Diffie-Hellman等。
签名和验证过程:
发送方(甲)首先用公开的单向函数对报文进行一次变换,得到数字签名,然后利用私有密钥对数字签名进行加密后附在报文之后一同发出。
接收方(乙)用发送方的公开密钥对数字签名进行解密交换,得到一个数字签名的明文。发送方的公钥可以由一个可信赖的技术管理机构即认证中心(CA)发布的。
接收方将得到的明文通过单向函数进行计算,同样得到一个数字签名,再将两个数字签名进行对比,如果相同,则证明签名有效,否则无效。
这种方法使任何拥有发送方公开密钥的人都可以验证数字签名的正确性。由于发送方私有密钥的保密性,使得接受方既可以根据结果来拒收该报文,也能使其无法伪造报文签名及对报文进行修改,原因是数字签名是对整个报文进行的,是一组代表报文特征的定长代码,同一个人对不同的报文将产生不同的数字签名。这就解决了银行通过网络传送一张支票,而接收方可能对支票数额进行改动的问题,也避免了发送方逃避责任的可能性。
对称密钥密码算法进行数字签名
算法含义
对称密钥密码算法所用的加密密钥和解密密钥通常是相同的,即使不同也可以很容易地由其中的任意一个推导出另一个。在此算法中,加、解密双方所用的密钥都要保守秘密。由于计算机速度而广泛应用于大量数据如文件的加密过程中,如RD4和DES,用IDEA作数字签名是不提倡的。
使用分组密码算法数字签名通用的加密标准有:DES,Tripl-DES,RC2,RC4,CAST等。
签名和验证过程
Lamport发明了称为Lamport-Diffle的对称算法:利用一组长度是报文的比特数(n)两倍的密钥A,来产生对签名的验证信息,即随机选择2n个数B,由签名密钥对这2n个数B进行一次加密交换,得到另一组2n个数C。
发送方从报文分组M的第一位开始,依次检查M的第I位,若为0时,取密钥A的第i位,若为1则取密钥A的第i+1位;直至报文全部检查完毕。所选取的n个密钥位形成了最后的签名。
接受方对签名进行验证时,也是首先从第一位开始依次检查报文M,如果M的第i位为0时,它就认为签名中的第i组信息是密钥A的第i位,若为1则为密钥A的第i+1位;直至报文全部验证完毕后,就得到了n个密钥,由于接受方具有发送方的验证信息C,所以可以利用得到的n个密钥检验验证信息,从而确认报文是否是由发送方所发送。
这种方法由于它是逐位进行签名的,只有有一位被改动过,接受方就得不到正确的数字签名,因此其安全性较好,其缺点是:签名太长(对报文先进行压缩再签名,可以减少签名的长度);签名密钥及相应的验证信息不能重复使用,否则极不安全。
结合对称与非对称算法的改进
对称算法与非对称算法各有利弊,所以结合各自的优缺点进行改进,可以用下面的模块进行说明:
Hash算法进行数字签名
Hash算法也称作散列算法或报文摘要,Hash算法将在数字签名算法中详细说明。
Hash算法数字签字通用的加密标准有: SHA-1,MD5等。
数字签名算法
数字签名的算法很多,应用最为广泛的三种是: Hash签名、DSS签名、RSA签名。这三种算法可单独使用,也可综合在一起使用。数字签名是通过密码算法对数据进行加、解密变换实现的,常用的HASH算法有MD2、MD5、SHA-1,用DES算法、RSA算法都可实现数字签名。但或多或少都有缺陷,或者没有成熟的标准。
Hash签名
Hash签名是最主要的数字签名方法,也称之为数字摘要法(digital digest)、数字指纹法(digital finger print)。它与RSA数字签名是单独的签名不同,该数字签名方法是将数字签名与要发送的信息紧密联系在一起,它更适合于电子商务活动。将一个商务合同的个体内容与签名结合在一起,比合同和签名分开传递,更增加了可信度和安全性。下面我们将详细介绍Hash签名中的函数与算法。
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <time.h> 5 #include <iostream> 6 #include <string.h> 7 #include <math.h> 8 #include <algorithm> 9 #include <random> 10 11 using namespace std; 12 13 const int S = 10; 14 15 long long mult_mod(long long a, long long b, long long c) 16 { 17 a %= c; 18 b %= c; 19 long long ret = 0; 20 while (b) 21 { 22 if (b & 1) 23 { 24 ret += a; 25 ret %= c; 26 } 27 a <<= 1; 28 if (a >= c) 29 a %= c; 30 b >>= 1; 31 } 32 return ret; 33 } 34 35 //计算 ret = x^n %c 36 long long pow_mod(long long x, long long n, long long mod) //x^n%c 37 { 38 if (n == 1) 39 return x % mod; 40 x %= mod; 41 long long tmp = x; 42 long long ret = 1; 43 while (n) 44 { 45 if (n & 1) 46 ret = mult_mod(ret, tmp, mod); 47 tmp = mult_mod(tmp, tmp, mod); 48 n >>= 1; 49 } 50 return ret; 51 } 52 53 bool check(long long a, long long n, long long x, long long t) 54 { 55 long long ret = pow_mod(a, x, n); 56 long long last = ret; 57 for (int i = 1; i <= t; i++) 58 { 59 ret = mult_mod(ret, ret, n); 60 if (ret == 1 && last != 1 && last != n - 1) 61 return true; //合数 62 last = ret; 63 } 64 if (ret != 1) 65 return true; 66 return false; 67 } 68 69 bool Miller_Rabin(long long n) //Miller_Rabin算法判断素数 70 { 71 if (n < 2) 72 return false; 73 if (n == 2) 74 return true; 75 if ((n & 1) == 0) 76 return false; //偶数 77 long long x = n - 1; 78 long long t = 0; 79 while ((x & 1) == 0) 80 { 81 x >>= 1; 82 t++; 83 } 84 for (int i = 0; i < S; i++) 85 { 86 long long a = rand() % (n - 1) + 1; 87 if (check(a, n, x, t)) 88 return false; //合数 89 } 90 return true; 91 } 92 93 long long gcd(long long a, long long b) 94 { 95 if (a == 0) 96 return 1; 97 if (a < 0) 98 return gcd(-a, b); 99 while (b) 100 { 101 long long t = a % b; 102 a = b; 103 b = t; 104 } 105 return a; 106 } 107 108 bool Legendre(int a, int p) 109 { 110 int tmp = pow(a, (p - 1) / 2); 111 if (tmp % p == 1) 112 return true; 113 else 114 return false; 115 } 116 117 int main() 118 { 119 cout << "*******************************************" << endl; 120 cout << "测试数据假定 p = 7 q = 11 ,进行签名和验证" << endl; 121 cout << "*******************************************" << endl 122 << endl 123 << endl; 124 static uniform_int_distribution<unsigned> u(1000000, 1000000000); 125 static default_random_engine e(time(0)); 126 long long p = 6, q = 6; 127 128 //随机产生素数p q 129 while (!Miller_Rabin(p)) 130 p = u(e); 131 while (!Miller_Rabin(q)) 132 q = u(e); 133 134 //cout << p << " " << q << endl; 135 long long n = p * q; 136 cout << "素数p,q生成完毕!" << endl; 137 p = 7; 138 q = 11; 139 140 //签名生成 141 cout << "请输入 m 进行签名:" << endl; 142 long long m; 143 cin >> m; 144 145 if (!(Legendre(m, p) && Legendre(m, q))) 146 { 147 while (!(Legendre(m, p) && Legendre(m, q))) 148 m = m - 1; 149 } 150 151 long long s = ((long long)sqrt(m)) % n; 152 153 //签名验证 154 cout << "请输入s进行签名验证:" << endl; 155 int ss; 156 cin >> ss; 157 if (m == ss * ss % n) 158 cout << "true 验证成功!" << endl; 159 else 160 cout << "false 验证失败!" << endl; 161 162 return 0; 163 } 164 165 #if 0 166 #include <iostream> 167 #include <stdio.h> 168 #include <cmath> 169 #include <string> 170 171 using namespace std; 172 173 int quickpow(int m, int n, int k) 174 { 175 int b = 1; 176 while (n > 0) 177 { 178 if (n & 1) 179 b = (b * m) % k; 180 n = n >> 1; 181 m = (m * m) % k; 182 } 183 return b; 184 } 185 186 int main() 187 { 188 int n, MOD; 189 cin >> n >> MOD; 190 191 int y10, y11, y20, y21, y30, y31; 192 cin >> y10 >> y11 >> y20 >> y21 >> y30 >> y31; 193 194 int z10, z11, z20, z21, z30, z31; 195 196 z10 = quickpow(n, y10, MOD); 197 z11 = quickpow(n, y11, MOD); 198 z20 = quickpow(n, y20, MOD); 199 z21 = quickpow(n, y21, MOD); 200 z30 = quickpow(n, y30, MOD); 201 z31 = quickpow(n, y31, MOD); 202 203 string cl; 204 cin >> cl; 205 int len = cl.size(); 206 int Sign[100]; 207 208 if (cl[0] == '0') 209 Sign[0] = y30; 210 else 211 Sign[0] = y31; 212 if (cl[1] == '0') 213 Sign[1] = y20; 214 else 215 Sign[1] = y21; 216 if (cl[2] == '0') 217 Sign[2] = y10; 218 else 219 Sign[2] = y11; 220 221 int Sign_ans[100]; 222 223 for (int i = 0; i < 3; i++) 224 { 225 Sign_ans[i] = quickpow(n, Sign[2 - i], MOD); 226 cout << Sign_ans[i] << endl; 227 } 228 229 return 0; 230 } 231 #endif