前言:
在互联网中,由于它联结的是全世界范围的企业和个人,所以会面临很多需要对数据进行加密处理的情况。举例来说,在网店购物时用户输入的信用卡卡号,就是应该被加密传输的代表性数据。假设卡号未经加密就被发送出去,那么就会面临卡号被同样接入互联网的某人盗取,信用卡被其用来肆意购物的危险。因此像这种网店页面的 URL,通常都是以 https:// 开头,表示数据正在使用加密的方式进行传输。
一、先来明确一下什么是加密
在作为加密对象的数据中,蕴含着文本、图像等各种形式的信息。但是,由于计算机会把所有的数据都用数字表示,所以即便数据有各种展现形式,对其加密的技术却是基本相同的。因此我们就假设加密的对象仅限于文本数据。
文本数据可以由各种各样的字符构成。其中每个字符都被分配了一个数字,我们称之为“字符编码”。定义了应该把哪个编码分配给哪个字符的字符编码体系叫作字符集。字符集分为 ASCII 字符集、JIS 字 符集、Shift-JIS 字符集,EUC 字符集、Unicode 字符集等若干种。
在图1中,以十进制数字列出了大写拉丁字母(A 至 Z)的 ASCII 编码。计算机会把文本数据处理成数字序列,例如在使用了 ASCII 编码的计算机中,就会把 NIKKEI 处理成“78 73 75 75 69 73”。可是只要把这一串数字转换为对应的字符显示在屏幕上,就又变成了人们 所认识的 NIKKEI 了。通常把这种未经加密的文本数据称为“明文”。
数据一旦以明文的方式在网络中传输,就会有被盗取滥用的危险, 因此要对明文进行加密,将它转换成为“密文”。当然密文也仅仅是一串数字,但是如果是把密文显示在屏幕上,那么在人类看来显示的也只不过是读不懂、没有意义的字符序列罢了。
虽然存在各种各样的加密技术,但是其中的基本手段无外乎还是字符编码的变换,即将构成明文的每个字符的编码分别变换成其他的数值。通过反转这种变换过程,加密后的文本数据就可以还原。通常把密文还原成明文的过程(即解读密码的过程)称为“解密”。
二、错开字符编码的加密方式
代码清单1 中,列出了一段用于加密的示例程序。在该程序中,使用了如下加密方法:将文本数据中每个字符所对 应的字符编码一律向后错三个,即给原字符编码的值加上 3。运行这段程序,在最初弹出的窗口中输入要加密的文本数据(明文),例如就输入 NIKKEI,然后单击 OK 按钮。在接下来弹出的窗口中会显示出加密后的文本数据(密文)。因为每个字符的编码都向后错了三个,所以得到的是 QLNNHL。这样的话,即便是被人偷偷地看到了,那个人也无法理解这个字符串的意义。
// 代码清单1 用给字符编码加上 3 的方法加密
plaintext = InputBox("请输入明文。")
cipher = ""
For i = 1 To Len(plaintext)
letter = Mid(plaintext, i, 1)
cipher = cipher & Chr(Asc(letter) + 3)
Next
MsgBox cipher
因为加密时使用的是将字符编码向后错三个的方法,所以只要再将字符编码向前挪三个就可以实现解密。代码清单 10.2 中就是解密程序。与进行加密的程序相反,解密使用的是从字符编码中减去 3 的方 法。在最初弹出的窗口中输入密文,我们就输入刚刚得到的 QLNNHL,然后单击 OK 按钮。在接下来弹出的窗口中就会显示出解密后的明文 NIKKEI。
// 代码清单2 用把字符编码减去 3 的方法解密
cipher = InputBox("请输入密文。")
plaintext = ""
For i = 1 To Len(cipher)
letter = Mid(cipher, i, 1)
plaintext = plaintext & Chr(Asc(letter) - 3)
Next
MsgBox plaintext
也就是说,加上 3 就是加密,减去 3 就是解密。因此通常把像 3 这样用于加密和解密的数字称为“密钥”。如果事先就把 3 这个密钥作 为只有数据的发送者和接受者才知道的秘密,那么不知道这个密钥的 人,就无法对加密过的数据进行解密。
下面再试着编写一个加密程序吧。这次让密钥的值也可以由用户指定吧。该程序通过把每一个字符的编码与密钥做 XOR 运算 (eXclusive OR,逻辑异或运算),将明文转换成密文(如代码清单3 所示)。XOR 运算的有趣之处在于,用 XOR 运算加密后的密文,可以通过相同的 XOR 运算解密。也就是说,一个程序既可用于加密又可用于解密,很方便。
// 代码清单3 通过 XOR 运算进行加密和解密
k = InputBox("请输入密钥。")
key = CInt(k)
text1 = InputBox("请输入明文或密文。")
text2 = ""
For i = 1 To Len(text1)
letter = Mid(text1, i, 1)
text2 = text2 & Chr(Asc(letter) Xor key)
Next
MsgBox text2
XOR 运算的法则是把两个数据先分别用二进制表示,然后当一个 数据中的某一位与另一个数据中的 1 相对时,就将这一位反转(若这一位是 0 就变成 1,是 1 就变成 0)。因为是靠翻转数字实现的加密,所以只要再翻转一次就可以解密。下图中展示了密钥 3(用二进制表 示是 00000011)和字母 N(其字符编码用二进制表示是 01001110)做 XOR 运算的结果,请诸位确认通过翻转和再翻转还原出字母 N 的过 程:N 的字符编码先和 3 做 XOR 运算,结果是字母 M 的字符编码。M 的字符编码再和 3 做 XOR 运算,结果就又回到了 N 的字符编码。
三、密钥越长,解密越困难
在互联网等环境中,会有很多不固定的人群相互收发经过加密处理的数据。一般情况下,会将所使用的加密方式公开,而只对密钥的值保密。但是令人感到遗憾的是,这个世界上还是有坏人的。有些人会盗取那些并不是发送给他们的加密数据,企图破解后用于不可告人的目的。尽管这些人并不知道密钥的值,但是他们会利用计算机强大的计算能力,用密钥所有可能的取值去试着破解。例如,要想破解用 XOR 运算加密得到的密文 MJHHFJ,程序只要把 0 到 9 这几个值分别作为密钥都尝试一遍就能做到(如代码清单4所示)。
// 代码清单4 通过 XOR 运算破解密文的程序
cipher = InputBox("请输入密文。")
plaintext = ""
For key = 0 To 9
plaintext = plaintext & "密钥" & CStr(key) & ":"
For i = 1 To Len(cipher)
letter = Mid(cipher, i, 1)
plaintext = plaintext & Chr(Asc(letter) Xor key)
Next
plaintext = plaintext & Chr(&HD)
Next
MsgBox plaintext
在互联网上经过加密的数据也难免被盗,因此就要先设法做到即使数据被盗了,其内容也难以被破解。为此可以把密钥设成多位数而不仅仅是一位数。下面,我们就丢弃一位数的 3,试着以三位数的 345 为密钥,通过 XOR 运算来试着进行加密(如代码清单5 所示)。将 明文中的第一个字母与 3 做 XOR 运算、第二个字母与 4 做 XOR 运算、第三个字母与 5 做 XOR 运算。从第四个字母开始,还是以三个字母为一组依次与 3、4、5 做 XOR 运算,依此类推。
// 代码清单5 通过与三位数的密钥进行 XOR 运算实现加密和解密
Dim key(2)
key(0) = 3
key(1) = 4
key(2) = 5
text1 = InputBox("请输入明文或密文。")
text2 = ""
For i = 1 To Len(text1)
letter = Mid(text1, i, 1)
text2 = text2 & Chr(Asc(letter) Xor key((i - 1) Mod 3))
Next
MsgBox text2
如果仅用一位数作为密钥,那么只需要从 0 到 9 尝试十次就能破 解密文。但是如果是用三位数的密钥,那么就有从 000 到 999 的 1000 种可能。如果更进一步把密钥的位数增长到十位,结果会怎样呢?那样的话,破解者就需要尝试 10 的 10 次方 = 100 亿次。就算使用了一秒钟可以进行 100 万次尝试的计算机,破解密文也还是需要花费 100 亿 ÷100 万次 / 秒 = 10000 秒 ≈ 2.78 小时,坏人说不定就会因此放弃破解。 密钥每增长一位,破解所花费的时间就会翻 10 倍。密钥再进一步增长到 16 位的话,破解时间就是 2.78 小时 ×1000000 ≈ 317 年,从所需的时间上来看,可以说破解是不可能的。
四、适用于互联网的公开密钥加密技术
前面所讲解的加密技术都属于“对称密钥加密技术”,也称作 “秘密密钥加密技术” (如下图)。这种加密技术的特征是在加密和解密的过程中使用数值相同的密钥。因此,要使用这种技术,就必须事先把密钥的值作为只有发送者和接收者才知道的秘密保护好。虽然随着密钥位数的增加,破解难度也会增大,但是 事先仍不得不考虑一个问题:发送者如何才能把密钥悄悄地告诉接收者呢?用挂号信吗?要是那样的话,假设有 100 名接收者,那么发送者 就要寄出 100 封挂号信,非常麻烦,而且这样也无法防止通信双方以外的其他人知道密钥。再说寄送密钥也要花费时间。互联网的存在应该意味着用户可以实时地与世界各地的人们交换信息。因此对称密钥加密技术不适合在互联网中使用。
但是世界上不乏善于解决问题的能人。他们想到只要让解密时的 密钥不同于加密时的密钥,就可以克服对称密钥加密技术的缺点。(“会有这样的技术吗?”也许诸位不禁会发出这样的疑问,稍后笔者将展示具体的例子)。而这种加密技术就被称为“公开密钥加密技术”。
在公开密钥加密技术中,用于加密的密钥可以公开给全世界,因此称为“公钥”,而用于解密的密钥是只有自己才知道的秘密,因此称 为“私钥”。举例来说,假设笔者的公钥是 3,私钥是 5(实际中会把位数更多的两个数作为一对儿密钥使用)。笔者会通过互联网向全世界宣布“我的公钥是 3 哦”。这之后当诸位要向笔者发送数据的时候,就可以用这个公钥 3 加密数据了。这样就算加密后的密文被人盗取了,只要他还不知道笔者的私钥就不可能对其解密,从而保证了数据的安全性。而收到了密文的笔者,则可以使用只有笔者自己才知道的私钥 5 对其解密。
可用于实现公开密钥加密技术的算法有若干种,这里笔者将介绍目前广泛应用于互联网中的 RSA 算法。RSA 这个名字是由三位发明者 Ronald Rivest、Adi Shamir 和 Leonard Adleman 姓氏的首字母拼在一起 组成的。美国的 RSA 信息安全公司对 RSA 的专利权一直持有到 2000 年 9 月 20 日。使用 RSA 创建公钥和私钥的步骤如下图所示。无论是公钥还是私钥都包含着两个数值,两个数值组成的数对儿才是一个完整的密钥。
上图的步骤可以得出: 323 和 11 是公钥,323 和 131 是私钥,的确是两个值都不相同的密钥。在使用这对儿密钥进行加密和解密时,需要对每个字符执行如下图所示的运算。这里参与运算的对象是字母 N(字符编码为 78)。用公钥对 N 进行加密得到 224,用私钥对 224 进行解密可使其还原为 78。
乍一看会以为只要了解了 RSA 算法,就可以通过公钥 c = 323、 e = 11 推算出私钥 c = 323,f = 131 了。但是为了求解私钥中的 f,就不得不对 c 进行因子分解,分解为两个素数 a、b。在本例中 c 的位数很短,而在实际应用公开密钥加密时,建议将 c 的位数(用二进制数表示时)扩充为 1024 位(相当于 128 字节)。要把这样的天文数字分解为两个素数,就算计算机的速度再快,也还是要花费不可估量的时间,时间可能长到不得不放弃解密的程度。
五、数字签名可以证明数据的发送者是谁
接下来介绍一种公开密钥加密技术的实际应用 —— 数字签名。在商界有盖章和签字的习惯。印章和签名都可以证明一个事实,那就是某个人承认了文件的内容是完整有效的。而在通过网络传输的文件中,数字签名可以发挥出与印章和签名同样的证明效果。通常可以按照下面的步骤生成数据签名。步骤中所提及的“信息摘要”(Message Digest)可以理解为就是一个数值,通过对构成明文的所有字符的编码进行某种运算就能得出该数值。
【文本数据的发送者】
(1)选取一段明文 例:NIKKEI
(2)计算出明文内容的信息摘要 例:(78+73+75+75+69+73)÷100 的余数 = 43
(3)用私钥对计算出的信息摘要进行加密 例:43 → 66(字母 B 的编码)
(4)把步骤(3)得出的值附加到明文后面再发送给接收者 例:NIKKEIB
【文本数据的接收者】
(1)用发送者的公钥对信息摘要进行解密 例 :B = 6 6 → 4 3
(2)计算出明文部分的信息摘要 例:(78+73+75+75+69+73)÷100 的余数 = 43
(3)比较在步骤(1)和(2)中求得的值,二者相同则证明接收的 信息有效
例:因为两边都是 43,所以信息有效
请诸位注意,这里是使用私钥进行加密、使用公钥进行解密,这与之前的用法刚好相反(如下图所示)。而且这里所使用的是信息发送者(图中的 A 小姐)的密钥对儿,而之前所使用的则是信息接收者(B 先生)的密钥对儿。
本例中信息摘要的算法是把明文中所有字母的编码加起来,然后取总和的最后两位。而在实际中计算数字签名时,使用的是通过更加复杂的公式计算得出的、被称作 MD5(Message Digest5)的信息摘要。由于 MD5 经过了精心的设计,所以使得两段明文即使只有略微的差异,计算后也能得出不同的信息摘要。
也许诸位会认为把文件发送者的名字,比如“张三”这个字符串用私钥加密,然后让对方用公钥解密也能代替印章或签字。但是如果这样做就不算是数字签名了,因为印章或签字有两层约束。其一是 发送者承认文件的内容是完整有效的;其二是文件确实是由发送者本人发送的。发送者用构成文件的所有字符的编码生成了信息摘要,就证明发送者从头到尾检查了文件并承认其内容完整有效。如果接收者重新算出的信息摘要和经过发送者加密的信息摘要匹配,就证明文件在传输过程中没有被篡改,并且的确是发送者本人发送的。正因为数据是用发送者的私钥加密的,接收者才能用发送者的公钥进行解密。
总结
其实,绝对无法破解的加密技术也是存在的。首先密钥的位数要与文件数据中的字符个数相同,其次每次发送文件时都需要先更换密钥,最后为了防止密钥被盗,发送者还要亲手把密钥交给接收者。诸位明白为什么说这样做就绝对无法破解了吗?原因在于这样做等同于发送完全随机并且没有任何意义的数据。可是这种加密技术是不切实际的。合理的密钥应该满足如下条件:长短适中、可以反复使用、可以通过某种通信手段交给接收者,并且通信双方以外的其他人难以用它来解密。
本文摘自《计算机是怎样跑起来的》第10章