本文部分整理编译自:深入java虚拟机第二版
注:关于数字证书部分,主要是我的一些推理。本人并没找到关于数字证书更详细的资料。
一、基本模型
   对于一个给定程序,如果我们能找到其作者,那么程序的作者就不敢编写夹带一些恶意的代码在里面。因为如果他编写夹带了恶意代码在里面,用户因此而造成任何损失的话,用户可以找到他,并可以起诉他。程序的作者必须对自己的程序负责。   通过使用数字签名和数字证书就可以达到这个目的。
    首先,要成立一些颁发和管理数字证书的公司或机构。如果有一个程序员或公司想开发一个程序,我们暂且称它们为 开发者A
开发者A需要向一个 数字证书公司或机构提交一些信息来请求 该公司或机构对 开发者A 的程序进行担保。我暂且称 数字证书公司或机构为 数字证书机构B 开发者A 应该提供了足够的信息给 数字证书机构B ,以便 数字证书机构B 找到他。 数字证书机构B 给开发者颁发一个 公钥/私钥对, 中数字证书机构B 用它自己的 私钥( 暂称为 机构私钥B 颁发的 公钥 进行加密 对于私钥,我暂且称之为 私钥BA 对于公,我暂且称之为 公钥BA 对于该加密后的 公钥BA (暂称为 公钥BA1 和其他的一些关于 数字证书机构B 的信息放在一个叫做数字证书的东西中 我暂且称之为 数字证书BA
    开发者A 在他的程序(暂称为程序/JAR包C开发完成后,首先用对它的程序本身(class文件及资源)进行散列计算,得到散列值(暂称之为散列值D),用 私钥BA 对散列值进行加密。对于加密后的散列值我暂且称之为 散列值D1 。接着把 散列值D1 数字证书BA 都加到 程序/ JAR包C 中。这时候数字签名就完成了。 开发者A 就可以发布它的 程序/ JAR包C
    当有个用户(暂称之为 用户E )得到了 程序/ JAR包C, 并试图运行它。
第一步:这时JVM解压 程序/ JAR包C, 发现里面有 数字证书BA 然后根据中的 数字证书BA 信息,在用户的系统中查找 数字证书机构B 钥(暂称为 机构钥B ),如果找到直接进入第三步,否则进入第二步
第二步 JVM 就从 数字证书机构B 中提取的 机构钥B 地址,告诉用户 程序/ JAR包C 需要 机构钥B 并询问用户是在其地址否下载它。如果用户不信任该地址而不同意,试图运行 程序/ JAR包C 失败 。如果用户同意下载,但是下载失败的话, 试图运行 程序/ JAR包C 失败。如果下载成功就进入一步。
第三步 JVM 机构钥B 数字证书BA 中的 公钥BA1 进行解密计算得到 公钥BA, 然后用 公钥BA 散列值D1 进行解密计算得到 散列值D
程序/ JAR包C 本身内容(class文件及资源)进行散列计算,比较结果是否和 散列值D 一样。如果一样就说明 程序/ JAR包C 的确是 开发者A 编写的, 数字证书机构B 为他进行了担保,并且在 程序/ JAR包C 传输的途中并没有被窜改,验证成功,进入下一步。否则验证失败,就不能 运行 程序/ JAR包C .如果验证成功,JVM就告诉用户 程序/ JAR包C 来自于 开发者A数字证书机构B 开发者A 的此程序进行了担保,并 继续询问用户是否信任该程序。如果用户选择了不信任,那么 试图运行 程序/ JAR包C 失败。否则就开始运行 程序/ JAR包C
    如果在 程序/ JAR包C 运行的过程, 用户E 发现它有一些恶意的行为;那么 用户E 可以通过 机构钥B 找到 数字证书机构B ,然后 数字证书机构B 通过 程序/ JAR包C 中的 数字证书BA 找到 公钥BA1 ,然后 数字证书机构B 可以通过 公钥BA1 来找到 开发者A 开发者A 请求 数字证书机构B 开发者A 的程序进行担保的时候, 开发者A 已经提供了足够的信息给 数字证书机构B ,以便 数字证书机构B 找到它 当找到 开发者A 后, 用户E 数字证书机构B 就可以向法院起诉 开发者A 了。如果严重的话,警察也会介入。 开发者A 必须对它的 程序/ JAR包C 负责。
   因为程序的开发者必须对它的程序负责,所以他 就不敢放一些恶意的代码在其程序中。
    数字签名和数字证书可以使用户确认,由某些团体担保的一些class文件是值得信任的,并且这些class文件在到达用户虚拟机的途中没有被改变。这样,如果用户在一定程度上信任这个为代码作担保的团体,也就可以在一定程度上简化沙箱对这段代码实施的限制。可以对由不同团体签名的代码建立不同的安全限制。理论上对于一个进行团体担保的程序,我们可以通过数字证书找到该程序的作者。
二、基本数字签名
     要对一段代码作担保或者签名,必须首先牛成一个 公钥/私钥对 程序员应该保管那把私钥,而把公钥公开 。一旦拥有了一个公钥/私钥对,就必须将要签名的 class 文件 和其他文件放到一个 JAR  文件中,然后使用一个工具(例如 JDK 中的 jarSigner )对整个 JAR  文件签名。这个签名工具将首先对 JAR 文件的 内容进行单向散列计算,以产生一个散列 。然后这个工具将 使用私钥对这个散列进行签名,并将经过签名后的散列加到JAR文件的末尾 。这个签名后的散列代表了你对这个JAR 文件内容的数字签名。当你发布这个包含签名散列的JAR 文件时,那些持有你的公钥的人将对 JAR文件 验证两件事:第一, JAR 文件 确实是你签名的;第二,你签名后这个 JAR 文件 没有做过任何改动。
      数字签名过程的 第一步 是一个单向的 散列计算 它输入大量的数据,但产生少量的数据,称为散列 。在这个JAR文件的例子中,这个计算的大量输人就是组成这个JAR 文件内容的字节流。这个单向散列计算之所以被称为“ 单向 ”,是因为在只给出散列(即那个少量的数据)的情况下,这个散列值不能包含足够的输人的信息,因此不能从散列重新生成原输人。
      散列 也被称为消息文摘,它相当于一种输入“指纹”.虽然不同的输人可能产生相同的散列,但通常认为,在实际情况下,一个散列足以唯一标识产生它的输人。就像用指纹代表入一样,一个散列也被用于识别用单向散列算法产生这个散列的输人。在认证过程中,散列被用于验证某个输入是否和产生这个原始散列的输入相同、换句话说,这个输人在到达日的地的途中有没有被改动。
      数字签名过程的 第二步 是用私锁对散列值进行加密 。但是散列本身可能被窜改。因此必须在发送散列前,用私钥对它进行加密。只 加密散列 而不是对整个 JAR  进行加密,这是因为用私钥进行加密是一个相当费时的过程,而且只对散列加密就足够了。一般来说,从 JAR 文件 中计算、产生一个单项散列,并对这个散列用私钥进行加密,要比对整个JAR 文件用私钥进行加密来得快。只有当一个黑客拥有你的私钥时,他才能同时替换输入和其加密后的散列,因此要小心保存你的私钥,这样,相对于输人和散列组合, 破解输人和加密散列组合 就更困难了,因为黑客不可能拥有你的私钥。
      任何用你的私钥加密的东西都可以用你的公钥解密 公钥/私钥 对具有这种特点, 在仅给出公钥的情况下时,想要产生私钥是非常困难的 。如果黑客不能得到你的私钥,对他来说最好的选择就是试图将原输人替换为另一个输人,这个输人必须和原输人产生相同的散列值。例如,如果一个黑客想要在你的JAR 文件中将一个class文件替换成另一个执行恶意动作的 class 文件 .被修改的JAR 文件(包含了那个恶意的 class  文件)产生一个和原散列一样的散列的几率是非常低的。但是这个黑客可以往 JAR 文件 中添加随机的数据,直到能产生和原来一样的散列值。如果黑客可以产生既能达到其邪恶目的,又能其散列值和原散列值一样的输入的话,它就不需要你的私锁。然而对干黑客来说,这样的方法会花去大量的时间,因此几乎是不可行的。
    因为单向散列算法是 从大量数据(输人)中产生少量数据(消息摘要或者散列) ,所以不同的输人可能产生相同的散列:单向散列算法倾向于充分随机地分布产生相同散列的输人,从而使产生相同散列值的概率上要依赖于散列的大小。例如,如果使用了一个长8 位的散列值,散列算法最多产生256个不同的散列值。如果 散列的位数越多,产生相同散列值的几率就越低 。在实际情况中,普遍采用的是 64 位或128 位的散列 ,通常认为这个长度已经足够了,这时想从不同的输人中产生一个相同的散列的计算是不可行的。因此防止黑客用恶意输人替换你的善意输入,并且产生相同散列值的主要障碍在于他必须花费大鳌的时间和资源才能找到这个恶意的输入。
      数字签名过程的 第三步 就是将这个加密后的散列值加到其JAR文件中 在用私钥对散列值进行加密后, 就需要将这个加密后的散列值加到其JAR文件中 ,在JAR文件中,除了输入源( class文件和数据文件),还包含 你的已经加密后的散列值,还包含了你最初产生这个散列的文件。 其中加密的散列代表了你对JAR文件中的class类文件和数据文件的数字签名。 图3-3显示 了对一个JAR 文件进行数字签名的过程。

 
 验证一个已签名的JAR文件很简单。 首先 接收者用公钥对签名散列进行解密,得到原始散列值。 然后 从JAR文件的输入源计算得到的散列值相等。 最后 比较计算的散列值是否和原始散列值相等。如果相等,就说明公锁的所有者的确对该JAR文件进行了签名并担保,该JAR文件在此之后也没别人窜改。这个JAR文件中包含的代码就可以被放在一个不严格的沙箱,这个沙箱信任你的签名。 图3-4  显示了验证JAR文件的数字签名的过程。

三、数字证书
   对于大多数开发者,用户并不认识他。如果程序运行当中有什么恶意行为,用户很难在茫茫人海中去找其开发者,并让它负责。用户根本无法信任不认识或不是很熟的开发者的程序。这时就需要一些担保机构。
   开发者让 担保机构 对其程序进行担保, 担保机构 向开发颁发担保机构给开发者颁发一个公钥/私钥对,其中 担保机构 用它自己的私钥对要颁发的公钥进行加密,把加密后的公钥和其他一些信息放在一个叫做数字证书的东西中。开发者用 担保机构 颁发的私 钥对程序进行签名,然后把 担保机构 颁发的 数字证书 一同放在程序中。
    用户在得到程序时,通过程序中的 数字证书 确定其 担保机构 ,并取得担保机构的公 钥来解密 数字证书中的开发者的 ,然后用 开发者的 钥进行数字签名验证。如果验证通过,就说明该 担保机构 对这个程序进行担保。用户虽然不认识程序的开发者,但是如果其程序 有什么恶意行为,用户可以找到 担保机构 担保机构 能找到其担保的开发者,并追究其责任,甚至可以和用户一起起诉开发者。当然 担保机构 本身至少还是有一定信誉度的。
    这样的话,用户可以相信该 担保机构 担保的程序了。 程序的开发者必须对它的程序负责,所以他也 不敢放一些恶意的代码在其程序中。
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐