密码学


Java 与系统安全,第一部分:密码术基础


第一章 关于本教程


  ■本教程是关于什么方面的?
  恐怕没有什么软件工程主题的重要性比应用程序安全性更紧迫了。无论是来自内部或外部的攻击都会带来巨大损失,某些攻击会使软件公司对造成的损失承担赔偿责任。随着计算机(尤其是因特网)技术的发展,安全性攻击正在变得越来越成熟和频繁。利用各种最新技术和工具是应用程序安全性的一个关键;另一个关键是由经过考验的技术(如数据加密、认证和授权)构筑的牢固的基础。
  Java 平台的基本语言和库扩展都提供了用于编写安全应用程序的极佳基础。本教程讨论了密码术基础知识与如何用Java 编程语言实现密码术,并提供了样本代码来说明这些概念。
  在这个两部分教程的第一部分中,我们讨论库扩展(现在是JDK 1.4 库的一部分)中的内容,这些库扩展被称为Java 密码术扩展(Java Cryptography Extension(JCE))和Java 安全套接字扩展(Java Secure Sockets Extension (JSSE))。此外,本教程还介绍了CertPath API,这是JDK 1.4 中新增加的特性。在本教程第二部分(请参阅参考资料)中,我们将把讨论范围扩大到由Java 平台中Java 认证和授权服务(Java Authentication and Authorization Service (JAAS))管理的访问控制。


  ■我应该学习本教程吗?
  这是一篇中级教程;它假设您知道如何阅读和编写基本的Java 程序,包括应用程序和applet。
  如果您已经是Java 程序员并且对密码术(关于诸如私钥和公钥加密、RSA、SSL、证书之类的主题)以及支持它们的Java 库(JCE、JSSE)感到好奇,那么本教程就是为您准备的。本教程不要求您已经具有任何密码术、JCE 或JSSE 等方面的知识背景。
  本教程介绍了基本密码构件概念。每个概念都附有Java 实现考虑事项、代码示例和示例执行的结果。


  ■工具、代码样本和安装需求
  您将需要以下几项以完成本教程中的编程练习:
  JDK 1.4,标准版
  本教程源代码和类,以便您能够随着我们的进度理解示例
  用于RSA 示例的Bouncy Castle Crypto 库
  支持Java 1.4 插件的浏览器
  您可以使用JDK 1.3.x,但必须自行安装JCE 和JSSE。


  ■关于代码示例的说明
  代码示例直接将已加密的数据显示到屏幕上。大多数情况下,这会产生奇形怪状的控制字符,其中的一些偶尔可能会引起屏幕格式化问题。这不是良好的编程实践(将它们转换成可显示的ASCII 字符或十进制表示会更好),但我们这样做是为了保持代码示例及其输出的简洁。
  在示例执行章节的大多数情况下,我们修改了实际字符串以便与本教程中的字符集需求兼容。还有,我们在大多数示例中查询和显示了用于给定算法的实际安全性提供程序库。这样做是为了让用户更好地了解哪个功能是调用哪个库实现的。为什么这样做呢?因为,在大多数安装中都安装了许多这样的提供程序。


  ■关于作者
  Brad Rubin 是Brad Rubin & Associates Inc. 的负责人,该公司是一家专门从事无线网络和Java 应用程序安全性和教育的计算机安全性咨询公司。Brad 在IBM(位于明尼苏达州的Rochester)工作了14 年,他从AS/400 的第一个发行版就开始从事其所有方面的硬件和软件开发。他是促使IBM 转而支持Java 平台的关键人物,并且是IBM 最大的Java 应用程序—称为SanFrancisco(现在是WebSphere 的一部分)的商业应用程序框架产品—的首席架构设计师。他还是Imation Corp. 数据存储部门的首席技术官,以及该公司研发组织的领导。
  Brad 拥有计算机和电子工程学位,以及威斯康星大学麦迪逊分校计算机科学博士头衔。他目前在明尼苏达大学教授电子和计算机工程高级设计课程,并将于2002 年秋季开设和教授该大学的计算机安全性课程。可通过BradRubin@BradRubin.com 与Brad 联系。


第二章 Java安全性编程概念


  ■Java 平台是如何使安全编程更方便的
  Java 编程语言和环境有许多特性使安全编程更方便:
  ·无指针,这意味着Java 程序不能对地址空间中的任意内存位置寻址。
  ·字节码验证器,在编译成.class 文件之后运行,在执行之前检查安全性问题。例如,访问超出数组大小的数组元素的尝试将被拒绝。因为缓冲区溢出攻击是造成大多数系统漏洞的主要原因,所以这是一种重要的安全性特性。
  ·对资源访问的细颗粒度控制,用于applet 和应用程序。例如,可以限制applet 对磁盘空间的读或写,或者可以授权它仅从特定目录读数据。可以根据对代码签名的人(请参阅代码签名的概念)以及代码来源处的http 地址来进行授权。这些设置都出现在java.policy 文件中。
  ·大量库函数,这些函数用于主要密码构件和SSL(本教程的主题)以及认证和授权(在本系列的第二篇教程中讨论)。此外,有众多的第三方库可用于额外的算法。


  ■什么是安全编程技术?
  简单地说,有多种编程风格和技术可以帮助确保应用程序更安全。考虑下列两个一般示例:
  ·存储/删除密码。如果密码是存储在Java String 对象中的,则直到对它进行垃圾收集或进程终止之前,密码会一直驻留在内存中。即使进行了垃圾收集,它仍会存在于空闲内存堆中,直到重用该内存空间为止。密码String 在内存中驻留得越久,遭到窃听的危险性就越大。
  更糟的是,如果实际内存减少,则操作系统会将这个密码String 换页调度到磁盘的交换空间,因此容易遭受磁盘块窃听攻击。
  为了将这种泄密的可能性降至最低(但不是消除),您应该将密码存储在char 数组中,并在使用后对其置零。(String 是不可变的,所以无法对其置零。)
  ·智能序列化。当为存储器或传输任何私有字段而序列化对象时,缺省情况下,这些对象都呈现在流中。因此,敏感数据很容易被窃听。可以使用transient 关键字来标记属性,这样在流中将忽略该属性。
  当在本教程中需要用到这些技术以及其它技术时,我们将更详细地讨论它们。


  ■JDK 1.4 中集成了安全性
  在JDK 1.4 之前,许多安全性功能必须作为扩展添加到基本Java 代码分发版中。严格的美国出口限制要求这种功能的分离。
  现在,新的宽松法规使安全性特性和基本语言更紧密的集成成为可能。下列软件包(在1.4 发行版之前作为扩展使用)现在集成到了JDK 1.4 中:
  ·JCEJava 密码术扩展)
  ·JSSEJava 安全套接字扩展)
  ·JAASJava 认证和授权服务)
  JDK 1.4 还引入了两种新功能:
  ·JGSSJava 通用安全性服务(Java General Security Service))
  ·CertPath APIJava 证书路径API (Java Certification Path API))
  ·JCE、JSSE 和CertPath API 是本教程讨论的主题。在本系列的下一篇教程中,我们将重点介绍JAAS。这两篇教程都不讨论JGSS(它提供一般框架以在两个应用程序之间安全地交换消息)。


  ■第三方库充实了安全性
  我们可以用第三方库(也称为提供程序)来增强当前Java 语言中已经很丰富的功能集。提供程序添加了额外的安全性算法。
  作为库示例,我们将使用Bouncy Castle 提供程序(请参阅参考资料)。Bouncy Castle 库提供了其它密码算法,包括本教程什么是公钥密码术?和什么是数字签名?中讨论的流行的RSA 算法。
  尽管您的目录名和java.security 文件可能有一点不同,但仍可用以下模板安装Bouncy Castle 提供程序。要安装这个库,请下载bcprov-jdk14-112.jar 文件并将它放到j2sdk1.4.0\jre\lib\ext 和Program Files\Java\J2re1.4.0\lib\ext 目录中。在两个java.security 文件(他们位于上述相同的目录下,但位于“security”子目录而不是“ext”)中,将下面的行:
  security.provider.6=org.bouncycastle.jce.provider.BouncyCastleProvider
  添加至这些行的末尾:
  security.provider.1=sun.security.provider.Sun
  security.provider.2=com.sun.net.ssl.internal.ssl.Provider
  security.provider.3=com.sun.rsajca.Provider
  security.provider.4=com.sun.crypto.provider.SunJCE
  security.provider.5=sun.security.jgss.SunProvider
  security.provider.6=org.bouncycastle.jce.provider.BouncyCastleProvider


  ■展望
  在本章中,我们已经介绍了Java 语言提供的有助于确保编程保持安全的特性(无论是完全集成的还是基于扩展的)。我们提供了一些安全编程技术的通用示例以帮助您熟悉这个概念。我们介绍了过去是作为扩展的但现在集成到版本1.4 发行版中的安全性技术;我们也注意到两种新的安全性技术。我们还说明了了第三方库通过提供新技术能够增强安全性程序。
  在本教程余下的部分,我们将让您熟悉这些旨在提供安全的消息传递的概念(因为它们应用于Java 编程):
  ·消息摘要。这是一种与消息认证码结合使用以确保消息完整性的技术。
  ·私钥加密。被设计用来确保消息机密性的技术。
  ·公钥加密。允许通信双方不必事先协商秘钥即可共享秘密消息的技术。
  ·数字签名。证明另一方的消息确定来自正确通信方的位模式。
  ·数字证书。通过让第三方认证机构认证消息,向数字签名添加另一级别安全性的技术。
  ·代码签名。由可信的实体将签名嵌入被传递的代码中的概念。
  ·SSL/TLS。在客户机和服务器之间建立安全通信通道的协议。传输层安全性(Transport Layer Security (TLS))是安全套接字层(Secure Sockets Layer (SSL))的替代品。
  当我们讨论上述每个主题时,都将提供示例和样本代码。


第三章 确保消息的完整性


  ■概述
  我们将在本章中了解消息摘要,它获取消息中的数据并生成一个被设计用来表示该消息“指纹”的位块。我们还将讨论JDK 1.4 支持的与消息摘要相关的算法、类和方法,并为消息摘要和消息认证特性提供代码示例和样本的执行代码。


  ■什么是消息摘要?
  消息摘要是一种确保消息完整性的功能。消息摘要获取消息作为输入并生成位块(通常是几百位长),该位块表示消息的指纹。消息中很小的更改(比如说,由闯入者和窃听者造成的更改)将引起指纹发生显著更改。
  消息摘要函数是单向函数。从消息生成指纹是很简单的事情,但生成与给定指纹匹配的消息却很难。
  消息摘要可强可弱。校验和(消息的所有字节异或运算的结果)是弱消息摘要函数的一个示例。很容易修改一个字节以生成任何期望的校验和指纹。大多数强函数使用散列法。消息中1 位更改将引起指纹中巨大的更改(理想的比例是更改指纹中50% 的位)。
  
  ■算法、类和方法
  JDK 1.4 支持下列消息摘要算法:
  ·MD2MD5,它们都是128 位算法
  ·SHA-1 是160 位算法
  ·SHA-256SHA-383SHA-512 提供更长的指纹,大小分别是256 位、383 位和512 位
  MD5 和SHA-1 是最常用的算法。
  MessageDigest 类操作消息摘要。消息摘要代码示例中使用下列方法:
  ·MessageDigest.getInstance("MD5"):创建消息摘要。
  ·.update(plaintext):用明文字符串计算消息摘要。
  ·.digest():读取消息摘要。
  如果密钥被用作消息摘要生成过程的一部分,则将该算法称为消息认证码。JDK 1.4 支持HMAC/SHA-1 和HMAC/MD5 消息认证码算法。
  Mac 类使用由KeyGenerator 类产生的密钥操作消息认证码。消息认证码示例中使用了下列方法:
  ·KeyGenerator.getInstance("HmacMD5") 和.generateKey():生成密钥。
  ·Mac.getInstance("HmacMD5"):创建MAC 对象。
  ·.init(MD5key):初始化MAC 对象。
  ·.update(plaintext) 和.doFinal():用明文字符串计算MAC 对象。


  ■消息摘要代码示例
  import java.security.*;
  import javax.crypto.*;
  //
  // Generate a Message Digest
  public class MessageDigestExample {
   public static void main (String[] args) throws Exception {
    //
    // check args and get plaintext
    if (args.length !=1) {
     System.err.println("Usage: java MessageDigestExample text");
     System.exit(1);
    }
    byte[] plainText = args[0].getBytes("UTF8");
    //
    // get a message digest object using the MD5 algorithm
    MessageDigest messageDigest = MessageDigest.getInstance("MD5");
    //
    // print out the provider used
    System.out.println( "\n" + messageDigest.getProvider().getInfo() );
    //
    // calculate the digest and print it out
    messageDigest.update( plainText);
    System.out.println( "\nDigest: " );
    System.out.println( new String( messageDigest.digest(), "UTF8") );
   }
  }


  ■消息摘要样本执行的结果
  D:\IBM>java MessageDigestExample "This is a test!"


  SUN (DSA key/parameter generation; DSA signing; SHA-1, MD5 digests
  ; SecureRandom; X.509 certificates; JKS keystore; PKIX CertPathValidator
  ; PKIX CertPathBuilder; LDAP, Collection CertStores)


  Digest:
  D93,.x2%$kd8xdp3di5*
  
  ■消息认证码示例
  import java.security.*;
  import javax.crypto.*;
  //
  // Generate a Message Authentication Code
  public class MessageAuthenticationCodeExample {
   public static void main (String[] args) throws Exception {
    //
    // check args and get plaintext
    if (args.length !=1) {
     System.err.println
      ("Usage: java MessageAuthenticationCodeExample text");
     System.exit(1);
    }
    byte[] plainText = args[0].getBytes("UTF8");
    //
    // get a key for the HmacMD5 algorithm
    System.out.println( "\nStart generating key" );
    KeyGenerator keyGen = KeyGenerator.getInstance("HmacMD5");
    SecretKey MD5key = keyGen.generateKey();
    System.out.println( "Finish generating key" );
    //
    // get a MAC object and update it with the plaintext
    Mac mac = Mac.getInstance("HmacMD5");
    mac.init(MD5key);
    mac.update(plainText);
    //
    // print out the provider used and the MAC
    System.out.println( "\n" + mac.getProvider().getInfo() );
    System.out.println( "\nMAC: " );
    System.out.println( new String( mac.doFinal(), "UTF8") );
   }
  }
  
  ■消息认证样本执行
  
  D:\IBM>java MessageAuthenticationCodeExample "This is a test!"


  Start generating key
  Finish generating key


  SunJCE Provider (implements DES, Triple DES, Blowfish, PBE, Diffie-Hellman,
  HMAC-MD5, HMAC-SHA1)


  MAC:
  Dkdj47x4#.@kd#n8a-x>


  注:因为代码用线程行为定时来生成优质的伪随机数,所以密钥生成很费时。一旦生成了第一个数,其它数的生成就快得多了。
  还请注意,与消息摘要不同的是,消息认证码使用密码提供程序。(有关提供程序的更多信息,请参阅第三方库充实了安全性。)


第四章 保持消息的机密性


  ■概述
  在本节中,我们将研究私钥加密的使用并主要讨论诸如密码块、填充、序列密码和密码方式之类的概念。我们将迅速地讨论密码算法、类和方法的细节并用代码示例和样本执行来说明这个概念。


  ■什么是私钥密码术?
  消息摘要可以确保消息的完整性,但不能用来确保消息的机密性。要确保机密性,我们需要使用私钥密码术来交换私有消息。
  Alice 和Bob 各有一个只有他们两人知道的共享密钥,并且约定使用一种公用密码算法或密码。也就是说,他们保持密钥的私有性。当Alice 想给Bob 发送消息时,她加密原始消息(称为明文)以创建密文,然后将密文发送给Bob。Bob 接收了来自Alice 的密文并用自己的私钥对它解密,以重新创建原始明文消息。如果窃听者Eve 侦听该通信,她仅得到密文,因此消息的机密性得以保持。
  您可以加密单一位或位块(称为块)。块(称为密码块)通常是64 位大小。如果消息大小不是64 位的整数倍,那么必须填充短块(关于填充的更多信息请参阅什么是填充?)。单一位加密在硬件实现中更常见。单一位的密码被称为序列密码
  私钥加密的强度取决于密码算法和密钥的长度。如果算法比较好,那么攻击它的唯一方法就是使用尝试每个可能密钥的蛮力攻击,它平均要尝试(1/2)*2*n 次,其中n 是密钥的位数。
  在美国出口法规很严时,只允许出口40 位密钥。这种密钥长度相当弱。美国官方标准(DES 算法)使用56 位密钥,但随着处理器速度的增加,它变得越来越弱。现在,通常首选128 位密钥。如果每秒可以尝试一百万个密钥,那么,使用128 位密钥,找到密钥所需的平均时间是宇宙年龄的许多倍!


  ■什么是填充?
  如前所述,如果使用分组密码而消息长度不是块长度的整数倍,那么,必须用字节填充最后一个块以凑成完整的块大小。有许多方法填充块,譬如全用零或一。在本教程中,我们将对私钥加密使用PKCS5 填充,而对公钥加密使用PKCS1。
  使用PKCS5 时,由一个其值表示剩余字节数的重复字节来填充短块。我们不会在本教程中更深入地讨论填充算法,但您需要了解的信息是,JDK 1.4 支持下列填充技术:
  无填充
  ·PKCS5
  ·OAEP
  ·SSL3
  BouncyCastle 库(请参阅第三方库充实了安全性和参考资料)支持其它填充技术。


  ■方式:确定加密是如何工作的
  可以以各种方式使用给定密码。方式允许您确定加密是如何工作的。
  例如,您可以允许一个块的加密依赖于前一个块的加密,也可以使块的加密独立于任何其它块的加密。
  根据您的需求选择方式,并且您必须考虑各方面的权衡(安全性、并行处理能力以及明文和密文的容错等)。方式的选择超出了本教程的讨论范围(请参阅参考资料以进行更深入的阅读),但再次指出,您要了解的信息是,Java 平台支持下列方法:
  ·ECB(电子密码本(Electronic Code Book))
  ·CBC(密码块链接(Cipher Block Chaining))
  ·CFB(密码反馈方式(Cipher Feedback Mode))
  ·OFB(输出反馈方式(Output Feedback Mode))
  ·PCBC(填充密码块链接(Propagating Cipher Block Chaining))


  ■算法、类和方法
  JDK 1.4 支持下列私钥算法:
  ·DES。DES(数据加密标准)是由IBM 于上世纪70 年代发明的,美国政府将其采纳为标准。它是一种56 位分组密码。
  ·TripleDES。该算法被用来解决使用DES 技术的56 位时密钥日益减弱的强度,其方法是:使用两个密钥对明文运行DES 算法三次,从而得到112 位有效密钥强度。TripleDES 有时称为DESede(表示加密、解密和加密这三个阶段)。
  ·AES。AES(高级加密标准)取代DES 成为美国标准。它是由Joan Daemen 和Vincent Rijmen 发明的,也被称为Rinjdael 算法。它是128 位分组密码,密钥长度为128 位、192 位或256 位。
  ·RC2RC4、和RC5。这些算法来自领先的加密安全性公司RSA Security。
  ·Blowfish。这种算法是由Bruce Schneier 开发的,它是一种具有从32 位到448 位(都是8 的整数倍)可变密钥长度的分组密码,被设计用于在软件中有效实现微处理器。
  ·PBE。PBE(基于密码的加密)可以与多种消息摘要和私钥算法结合使用。
  Cipher 类使用由KeyGenerator 类产生的密钥操作私钥算法。私钥密码术代码示例中使用了下列方法:
  ·KeyGenerator.getInstance("DES")、.init(56) 和.generateKey():生成密钥。
  ·Cipher.getInstance("DES/ECB/PKCS5Padding"):创建Cipher 对象(确定算法、方式和填充)。
  ·.init(Cipher.ENCRYPT_MODE, key):初始化Cipher 对象。
  ·.doFinal(plainText):用明文字符串计算密文。
  ·.init(Cipher.DECRYPT_MODE, key):解密密文。
  ·.doFinal(cipherText):计算密文。


  ■私钥密码术代码示例
  import java.security.*;
  import javax.crypto.*;
  //
  // encrypt and decrypt using the DES private key algorithm
  public class PrivateExample {
   public static void main (String[] args) throws Exception {
    //
    // check args and get plaintext
    if (args.length !=1) {
     System.err.println("Usage: java PrivateExample text");
     System.exit(1);
    }
    byte[] plainText = args[0].getBytes("UTF8");
    //
    // get a DES private key
    System.out.println( "\nStart generating DES key" );
    KeyGenerator keyGen = KeyGenerator.getInstance("DES");
    keyGen.init(56);
    Key key = keyGen.generateKey();
    System.out.println( "Finish generating DES key" );
    //
    // get a DES cipher object and print the provider
    Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
    System.out.println( "\n" + cipher.getProvider().getInfo() );
    //
    // encrypt using the key and the plaintext
    System.out.println( "\nStart encryption" );
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] cipherText = cipher.doFinal(plainText);
    System.out.println( "Finish encryption: " );
    System.out.println( new String(cipherText, "UTF8") );
    //
    // decrypt the ciphertext using the same key
    System.out.println( "\nStart decryption" );
    cipher.init(Cipher.DECRYPT_MODE, key);
    byte[] newPlainText = cipher.doFinal(cipherText);
    System.out.println( "Finish decryption: " );
    System.out.println( new String(newPlainText, "UTF8") );
   }
  }


  ■私钥密码术样本执行
  D:\IBM>java PrivateExample "This is a test!"


  Start generating DES key
  Finish generating DES key


  SunJCE Provider (implements DES, Triple DES, Blowfish, PBE, Diffie-Hellman,
  HMAC-MD5, HMAC-SHA1)


  Start encryption
  Finish encryption:
  Kdkj4338*3n1#kxkgtixo4


  Start decryption
  Finish decryption:
  This is a test!


第五章 用公钥保密消息


  ■概述
  在本章中,我们将研究公钥密码术,该特性解决在事先没有约定密钥的通信双方之间加密消息的问题。我们将简单地浏览一下支持公钥功能的算法、类和方法,并提供代码样本和执行来说明该概念。


  ■什么是公钥密码术?
  私钥密码术受到一个主要缺点的困扰:一开始怎样将私钥交给Alice 和Bob 呢?如果Alice 生成了私钥,则必须将它发送给Bob,但私钥是敏感信息,所以应该加密。但是,还没有交换密钥来执行加密。
  公钥密码术是上世纪70 年代发明的,它解决在没有事先约定密钥的通信双方之间加密消息的问题。
  在公钥密码术中,Alice 和Bob 不仅有不同的密钥,而且每人有两个密钥。一个是私有的,不应与任何人共享。另一个是公共的,可以与任何人共享。
  当Alice 想给Bob 发送安全消息时,她用Bob 的公钥加密消息并将结果发送给Bob。Bob 使用他的私钥解密消息。当Bob 想给Alice 发送安全消息时,他用Alice 的公钥加密消息并将结果发送给Alice。Alice 使用她的私钥解密消息。Eve 可以窃听公钥和已加密的消息,但她不能解密消息,因为她没有任何一个私钥。
  公钥和私钥是成对生成的,并需要比同等强度的私钥加密密钥更长。RSA 算法的典型密钥长度是1,024 位。从该密钥对的一个成员派生出另一个是不可行的。
  公钥加密比较慢(比私钥加密慢100 到1,000 倍),因此实际上通常使用混合技术。公钥加密被用于向对方分发称为会话密钥的私钥,使用该私有会话密钥的私钥加密被用于进行大量的消息加密。


  ■算法、类和方法
  公钥加密中使用下列两种算法:
  ·RSA。这个算法是最流行的公钥密码,但JDK 1.4 中不支持它。您必须使用类似于BouncyCastle 的第三方库来获得这种支持。
  ·Diffie-Hellman。技术上将这种算法称为密钥协定算法。它不能用于加密,但可以用来允许双方通过在公用通道上共享信息来派生出秘钥。然后这个密钥可以用于私钥加密。
  Cipher 类使用由KeyPairGenerator 类产生的密钥来操作公钥算法。公钥密码术代码示例示例中使用了下列方法:
  ·KeyPairGenerator.getInstance("RSA")、.initialize(1024) 和.generateKeyPair():生成密钥对。
  ·Cipher.getInstance("RSA/ECB/PKCS1Padding") 创建Cipher 对象(确定算法、方式和填充)。
  ·.init(Cipher.ENCRYPT_MODE, key.getPublic()):初始化Cipher 对象。
  ·.doFinal(plainText):用明文字符串计算密文。
  ·.init(Cipher.DECRYPT_MODE, key.getPrivate()) 和.doFinal(cipherText):解密密文。


  ■公钥密码术代码示例
  import java.security.*;
  import javax.crypto.*;
  //
  // Public Key cryptography using the RSA algorithm.
  public class PublicExample {
   public static void main (String[] args) throws Exception {
    //
    // check args and get plaintext
    if (args.length !=1) {
     System.err.println("Usage: java PublicExample text");
     System.exit(1);
    }
    byte[] plainText = args[0].getBytes("UTF8");
    //
    // generate an RSA key
    System.out.println( "\nStart generating RSA key" );
    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
    keyGen.initialize(1024);
    KeyPair key = keyGen.generateKeyPair();
    System.out.println( "Finish generating RSA key" );
    //
    // get an RSA cipher object and print the provider
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    System.out.println( "\n" + cipher.getProvider().getInfo() );
    //
    // encrypt the plaintext using the public key
    System.out.println( "\nStart encryption" );
    cipher.init(Cipher.ENCRYPT_MODE, key.getPublic());
    byte[] cipherText = cipher.doFinal(plainText);
    System.out.println( "Finish encryption: " );
    System.out.println( new String(cipherText, "UTF8") );
    //
    // decrypt the ciphertext using the private key
    System.out.println( "\nStart decryption" );
    cipher.init(Cipher.DECRYPT_MODE, key.getPrivate());
    byte[] newPlainText = cipher.doFinal(cipherText);
    System.out.println( "Finish decryption: " );
    System.out.println( new String(newPlainText, "UTF8") );
   }
  }


  公钥密码术样本执行第5 页(共5 页)
  
  D:\IBM>java PublicExample "This is a test!"


  Start generating RSA key
  Finish generating RSA key


  BouncyCastle Security Provider v1.12


  Start encryption
  Finish encryption:
  Ajsd843*342l,AD;LKJL;1!*AD(XLKASD498asdjlkkKSFJHDuhpja;d(kawe#kjalfcas,
  .asd+,1LKSDJf;khaouiwheyahdsl87458q9734hjfc*nuywe


  Start decryption
  Finish decryption:
  This is a test!


第六章 无纸签名


  ■概述
  在本章中,我们将研究数字签名,它是确定交换消息的通信方身份的第一个级别。我们将通过代码样本说明标识消息源的两种方法(一种比较难,另一种比较容易)。我们还将列出JDK 1.4 支持的数字签名算法,并研究所涉及的类和方法。


  ■什么是数字签名?
  您注意到什么是公钥密码术?中描述的公钥消息交换的缺陷了吗?Bob 怎么能够证实该消息确实是来自于Alice 呢?Eve 可以用她的公钥替代Alice 的公钥,然后Bob 就会与Eve 交换消息,并以为她就是Alice。这被称为中间人(Man-in-the-Middle)攻击
  我们可以通过使用数字签名解决该问题—数字签名是证实消息来自特定通信方的位模式。
  实现数字签名的方法之一是逆用什么是公钥密码术?中描述的公钥过程。不是用公钥加密和用私钥解密,而是由发送方用私钥来对消息签名,然后接收方用发送方的公钥来解密消息。因为只有发送方才知道私钥,所以接收方可以确保消息确实是来自接收方。
  实际上,消息摘要(什么是消息摘要?)(但并非整个消息)是用私钥签名的位流。因此,如果Alice 想发送一条签名的消息给Bob,她就生成该消息的消息摘要,然后用私钥对它签名。她将消息(以明文形式)和签名的消息摘要发送给Bob。Bob 用Alice 的公钥解密签名的消息摘要,然后计算明文消息的消息摘要并检查两个摘要是否匹配。如果它们匹配,则Bob 可以确认消息来自于Alice。
  注:数字签名不提供消息加密,所以如果您还需要机密性,则必须将加密技术与签名结合使用。
  您可以将RSA 算法用于数字签名和加密。名为DSA(数字签名算法(Digital Signature Algorithm))的美国标准可以用于数字签名,但不可以用于加密。


  ■算法
  JDK 1.4 支持下列数字签名算法:
  ·MD2/RSA
  ·MD5/RSA
  ·SHA1/DSA
  ·SHA1/RSA
  我们将在本章中研究两个示例。首先研究困难的方法(请参阅数字签名代码示例:困难的方法),它使用我们已经讨论过的用于消息摘要和公钥密码术的原语来实现数字签名。然后研究简单的方法(请参阅数字签名代码示例:简单的方法),它使用Java 语言对签名的直接支持。


  ■数字签名代码示例:困难的方法
  import java.security.*;
  import javax.crypto.*;
  //
  // This program demonstrates the digital signature technique at the
  // primative level by generating a message digest of the plaintext
  // and signing it with an RSA private key, to create the signature.
  // To verify the signature, the message digest is again generated from
  // the plaintext and compared with the decryption of the signature
  // using the public key. If they match, the signature is verified.
  public class DigitalSignature1Example {
   public static void main (String[] args) throws Exception {
   //
   // check args and get plaintext
   if (args.length !=1) {
   System.err.println("Usage: java DigitalSignature1Example text");
   System.exit(1);
   }
   byte[] plainText = args[0].getBytes("UTF8");
   //
   // get an MD5 message digest object and compute the plaintext digest
   MessageDigest messageDigest = MessageDigest.getInstance("MD5");
   System.out.println( "\n" + messageDigest.getProvider().getInfo() );
   messageDigest.update( plainText );
   byte[] md = messageDigest.digest();
   System.out.println( "\nDigest: " );
   System.out.println( new String( md, "UTF8") );
   //
   // generate an RSA keypair
   System.out.println( "\nStart generating RSA key" );
   KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
   keyGen.initialize(1024);
   KeyPair key = keyGen.generateKeyPair();
   System.out.println( "Finish generating RSA key" );
   //
   // get an RSA cipher and list the provider
   Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
   System.out.println( "\n" + cipher.getProvider().getInfo() );
   //
   // encrypt the message digest with the RSA private key
   // to create the signature
   System.out.println( "\nStart encryption" );
   cipher.init(Cipher.ENCRYPT_MODE, key.getPrivate());
   byte[] cipherText = cipher.doFinal(md);
   System.out.println( "Finish encryption: " );
   System.out.println( new String(cipherText, "UTF8") );
   //
   // to verify, start by decrypting the signature with the
   // RSA private key
   System.out.println( "\nStart decryption" );
   cipher.init(Cipher.DECRYPT_MODE, key.getPublic());
   byte[] newMD = cipher.doFinal(cipherText);
   System.out.println( "Finish decryption: " );
   System.out.println( new String(newMD, "UTF8") );
   //
   // then, recreate the message digest from the plaintext
   // to simulate what a recipient must do
   System.out.println( "\nStart signature verification" );
   messageDigest.reset();
   messageDigest.update(plainText);
   byte[] oldMD = messageDigest.digest();
   //
   // verify that the two message digests match
   int len = newMD.length;
   if (len > oldMD.length) {
   System.out.println( "Signature failed, length error");
   System.exit(1);
   }
   for (int i = 0; i < len; ++i)
   if (oldMD[i] != newMD[i]) {
   System.out.println( "Signature failed, element error" );
   System.exit(1);
   }
   System.out.println( "Signature verified" );
   }
  }
  
  ■样本执行


  D:\IBM>java DigitalSignature1Example "This is a test!"


  SUN (DSA key/parameter generation; DSA signing; SHA-1, MD5 digests
  ; SecureRandom; X.509 certificates; JKS keystore; PKIX CertPathValidator
  ; PKIX CertPathBuilder; LDAP, Collection CertStores)


  Digest:
  D647dbdek12*e,ad.?e


  Start generating RSA key
  Finish generating RSA key


  BouncyCastle Security Provider v1.12


  Start encryption
  Finish encryption:
  Akjsdfp-9q8237nrcas-9de8fn239-4rb[*[OPOsjkdfJDL:JF;lkjs;ldj


  Start decryption
  Finish decryption:
  iNdf6D213$dcd(ndz!0)


  Start signature verification
  Signature verified


  ■数字签名代码示例:简单的方法
  Signature 类使用由KeyPairGenerator 类产生的密钥来操作数字签名。下面的示例中使用了下列方法:
  ·KeyPairGenerator.getInstance("RSA")、.initialize(1024) 和.generateKeyPair():生成密钥。
  ·Cipher.getInstance("MD5WithRSA"):创建Signature 对象。
  ·.initSign(key.getPrivate()):初始化Signature 对象。
  ·.update(plainText) 和.sign():用明文字符串计算签名。
  ·.initVerify(key.getPublic()) 和.verify(signature):验证签名。
  
  import java.security.*;
  import javax.crypto.*;
  //
  // This example uses the digital signature features to generate and
  // verify a signature much more easily than the previous example
  public class DigitalSignature2Example {
   public static void main (String[] args) throws Exception {
   //
   // check args and get plaintext
   if (args.length !=1) {
   System.err.println("Usage: java DigitalSignature1Example text");
   System.exit(1);
   }
   byte[] plainText = args[0].getBytes("UTF8");
   //
   // generate an RSA keypair
   System.out.println( "\nStart generating RSA key" );
   KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
   keyGen.initialize(1024);
   KeyPair key = keyGen.generateKeyPair();
   System.out.println( "Finish generating RSA key" );
   //
   // get a signature object using the MD5 and RSA combo
   // and sign the plaintext with the private key,
   // listing the provider along the way
   Signature sig = Signature.getInstance("MD5WithRSA");
   sig.initSign(key.getPrivate());
   sig.update(plainText);
   byte[] signature = sig.sign();
   System.out.println( sig.getProvider().getInfo() );
   System.out.println( "\nSignature:" );
   System.out.println( new String(signature, "UTF8") );
   //
   // verify the signature with the public key
   System.out.println( "\nStart signature verification" );
   sig.initVerify(key.getPublic());
   sig.update(plainText);
   try {
   if (sig.verify(signature)) {
   System.out.println( "Signature verified" );
   } else System.out.println( "Signature failed" );
   } catch (SignatureException se) {
   System.out.println( "Signature failed" );
   }
   }
  }
  
  ■样本执行
  Start generating RSA key
  Finish generating RSA key
  Sun JSSE provider(implements RSA Signatures, PKCS12, SunX509 key/trust
  factories, SSLv3, TLSv1)
  Signature:
  Ldkjahasdlkjfq[?owc42093nhasdk1a;sn;a#a;lksjd;fl@#kjas;ldjf78qwe09r7
  Start signature verification
  Signature verified


第七章 证实您的身份


  ■概述
  在本章中,我们将讨论数字证书,这是确定消息发送方身份的第二个级别。我们将研究认证中心以及它们所起的作用。我们还将研究密钥、证书资源库和管理工具(keytool 和密钥库(keystore)),并讨论CertPath API —一组被设计用于构建和验证证书路径的函数。


  ■什么是数字证书?
  正如您可能注意到的,什么是数字签名?中描述的数字签名方式有一个问题。它证实消息是由特定的发送方发送的,但我们怎么才能知道发送方确实是她所说的那个人呢?如果某人实际上是Amanda,却自称Alice,并对一条消息进行了签名,那会怎么样呢?我们可以通过使用数字证书来改进安全性,它将一个身份标识连同公钥一起进行封装,并由称为认证中心或CA 的第三方进行数字签名。
  从实际意义上来说,认证中心是验证某个实体的身份并用CA 私钥对该实体的公钥和身份进行签名的组织。消息接收方可以获取发送方的数字证书并用CA 的公钥验证(或解密)该证书。这可以证实证书是否有效,并允许接收方抽取发送方的公钥来验证其签名或向他发送加密的消息。浏览器和JDK 本身都带有内置的来自几个CA 的证书及其公钥。
  JDK 1.4 支持X.509 数字证书标准。


  ■理解keytool 和密钥库
  Java 平台将密钥库用作密钥和证书的资源库。从物理上讲,密钥库是缺省名称为.keystore 的文件(有一个选项使它成为加密文件)。密钥和证书可以拥有名称(称为别名),每个别名都由唯一的密码保护。密钥库本身也受密码保护;您可以选择让每个别名密码与主密钥库密码匹配。
  Java 平台使用keytool 来操作密钥库。这个工具提供了许多选项;下列示例演示了(keytool 示例)生成公钥对和相应的证书、以及通过查询密钥库查看结果的基本方法。
  可以用keytool 将密钥以X.509 格式导出到文件中,由认证中心对该文件签名,然后将其重新导入到密钥库中。
  还有一个用来保存认证中心(或其它可信的)证书的特殊密钥库,它又包含了用于验证其它证书有效性的公钥。这个密钥库称为truststoreJava 语言在名为cacerts 的文件中提供了缺省的truststore。如果您搜索这个文件名,就会发现至少两个这样的文件。您可以使用下列命令显示其内容:
  keytool -list -keystore cacerts
  Use a password of "changeit"
  
  ■keytool 示例
  在本示例中,使用缺省密钥库.keystore,我们用RSA 算法生成别名为JoeUserKey 的自签名的证书,然后查看所创建的证书。我们将在代码签名的概念中使用这个证书来对一个JAR 文件进行签名。
  
  D:\IBM>keytool -genkey -v -alias JoeUserKey -keyalg RSA
  Enter keystore password: password
  What is your first and last name?
   [Unknown]: Joe User
  What is the name of your organizational unit?
   [Unknown]: Security
  What is the name of your organization?
   [Unknown]: Company, Inc.
  What is the name of your City or Locality?
   [Unknown]: User City
  What is the name of your State or Province?
   [Unknown]: MN
  What is the two-letter country code for this unit?
   [Unknown]: US
  Is CN=Joe User, OU=Security, O="Company, Inc.", L=User City, ST=MN, C=US
  correct?
   [no]: y
  Generating 1,024 bit RSA key pair and self-signed certificate (MD5WithRSA)
   for: CN=Joe User, OU=Security, O="Company, Inc.", L=User City,
   ST=MN, C=US
  Enter key password for <JoeUserKey>
   (RETURN if same as keystore password):
  [Saving .keystore]
  D:\IBM>keytool -list -v -alias JoeUserKey
  Enter keystore password: password
  Alias name: JoeUserKey
  Creation date: Apr 15, 2002
  Entry type: keyEntry
  Certificate chain length: 1
  Certificate[1]:
  Owner: CN=Joe User, OU=Security, O="Company, Inc.", L=User City, ST=MN,
  C=US
  Issuer: CN=Joe User, OU=Security, O="Company, Inc.", L=User City, ST=MN,
  C=US
  Serial number: 3cbae448
  Valid from: Mon Apr 15 09:31:36 CDT 2002 until: Sun Jul 14 09:31:36
  CDT 2002
  Certificate fingerprints:
   MD5: 35:F7:F7:A8:AC:54:82:CE:68:BF:6D:42:E8:22:21:39
   SHA1: 34:09:D4:89:F7:4A:0B:8C:88:EF:B3:8A:59:F3:B9:65:AE:CE:7E:C9


  ■CertPath API
  证书路径API 是JDK 1.4 的新特性。它们是一组用于构建和验证证书路径或证书链的函数。这是在诸如SSL/TLS 的协议(请参阅什么是安全套接字层/传输层安全性?)和JAR 文件签名验证中是隐式地完成的,但有了这个支持后,就可以在应用程序中显式地完成了。
  正如什么是数字证书?中所提到的,CA 可以用自己的私钥对证书签名,因此,如果接收方持有的CA 证书具有签名验证所需要的公钥,则它可以验证已签名证书的有效性。
  在本例中,证书链由两个环节组成—信任锚(CA 证书)环节和已签名证书环节。自我签名的证书仅有一个环节的长度—信任锚环节就是已签名证书本身。
  证书链可以有任意环节的长度,所以在三节的链中,信任锚证书CA 环节可以对中间证书签名;中间证书的所有者可以用自己的私钥对另一个证书签名。CertPath API 可以用来遍历证书链以验证有效性,也可以用来构造这些信任链。
  证书虽然有期限,但有可能在过期之前泄露,因此必须检查证书撤销列表(Certificate Revocation Lists (CRL))以切实保证已签名证书的完整性。可以在CA 网站查看这些列表,也可以使用CertPath API 以编程方式进行操作。
  特定API 和代码示例不在本教程讨论范围之中,但除了API 文档之外,Sun 还提供了一些代码示例。


第八章 信任代码


  ■概述
  在本章中,我们将研究代码签名的概念,主要讨论管理JAR 文件证书的工具Jarsigner。


  ■代码签名的概念
  JAR 文件在Java 平台上相当于ZIP 文件,允许将多个Java 类文件打包到一个具有.jar 扩展名的文件中。然后,可以对这个JAR 文件进行数字签名,以证实其中的类文件代码的来源和完整性。该JAR 文件的接收方可以根据发送方的签名决定是否信任该代码,并可以确信该内容在接收之前没有被篡改过。JDK 提供了带有这种功能的jarsigner 工具。
  在部署中,可以通过在策略文件中放置访问控制语句根据签名者的身份分配对机器资源的访问权。


  ■jarsigner 工具
  jarsigner 工具将一个JAR 文件、一个私钥和相应的证书作为输入,然后生成JAR 文件的签名版本作为输出。它为JAR 文件中的每个类计算消息摘要,然后对这些摘要进行签名以确保文件的完整性并标识文件的拥有者。
  在applet 环境中,HTML 页面引用已签名JAR 文件中包含的类文件。当浏览器接收这个JAR 文件时,会对照任何安装的证书或认证中心的公用签名检查该JAR 文件的签名以验证其有效性。如果未找到现有的证书,则会向用户显示一个提示屏幕,给出证书详细信息并询问用户是否打算信任该代码。


  ■代码签名示例
  在本示例中,我们首先从.class 文件创建JAR 文件,然后通过在用于签名的密钥库中指定证书的别名来对JAR 文件签名。然后,我们对已签名的JAR 文件运行验证检查。
  D:\IBM>jar cvf HelloWorld.jar HelloWorld.class
  added manifest
  adding: HelloWorld.class(in = 372) (out= 269)(deflated 27%)
  D:\IBM>jarsigner HelloWorld.jar JoeUserKey
  Enter Passphrase for keystore: password
  D:\IBM>jarsigner -verify -verbose -certs HelloWorld.jar
   137 Mon Apr 15 12:38:38 CDT 2002 META-INF/MANIFEST.MF
   190 Mon Apr 15 12:38:38 CDT 2002 META-INF/JOEUSERK.SF
   938 Mon Apr 15 12:38:38 CDT 2002 META-INF/JOEUSERK.RSA
   0 Mon Apr 15 12:38:00 CDT 2002 META-INF/
  smk 372 Mon Apr 15 12:33:02 CDT 2002 HelloWorld.class
   X.509, CN=Joe User, OU=Security, O="Company, Inc.", L=User City,
   ST=MN, C=US (joeuserkey)
   s = signature was verified
   m = entry is listed in manifest
   k = at least one certificate was found in keystore
   i = at least one certificate was found in identity scope
  jar verified.


  ■代码签名示例执行
  下面是用于该程序的HTML:
  <HTML>
  <HEAD>
  <TITLE> Hello World Program </TITLE>
  </HEAD>
  <BODY>
  <APPLET CODE="HelloWorld.class" ARCHIVE="HelloWorld.jar"
   WIDTH=150 HEIGHT=25>
  </APPLET>
  </BODY>
  </HTML>
  当在将Java 插件用作Java 虚拟机的浏览器中执行这个示例时,会弹出一个对话框询问用户是否希望安装和运行由“Joe User”分发的已签名的applet,并告知用户发布者的可靠性是由“Company,Inc.”验证的,但安全性结论是由一家未获信任的公司发出的。该安全性证书还未过期并仍然有效。它警告:“Joe User”断言该内容是安全的,仅当您相信“Joe User”所作的断言时才应该安装或查看其内容。向用户提供了下列选项:
  ·准许这个会话
  ·拒绝
  ·始终准许
  ·查看证书


第九章 SSL/TLS:保护C/S通信


  ■概述
  在本章中,我们将研究安全套接字层(Secure Sockets Layer)(及其替代品,传输层安全性(Transport Layer Security))的构件,该协议用于为客户机认证服务器。我们提供一些代码示例作为说明。


  ■什么是安全套接字层/传输层安全性?
  安全套接字层(SSL)和取代它的传输层安全性(TLS)是用于在客户机和服务器之间构建安全的通信通道的协议。它也用来为客户机认证服务器,以及(不太常用的)为服务器认证客户机。该协议在浏览器应用程序中比较常见,浏览器窗口底部的锁表明SSL/TLS 有效。
  TLS 1.0 和SSL 3.1 一样。
  SSL/TLS 使用本教程中已经讨论过的三种密码术构件的混合体,但这一切都是对用户透明的。以下是该协议的简化版本:
  当使用SSL/TLS(通常使用https:// URL)向站点进行请求时,从服务器向客户机发送一个证书。客户机使用已安装的公共CA 证书通过这个证书验证服务器的身份,然后检查IP 名称(机器名)与客户机连接的机器是否匹配。
  客户机生成一些可以用来生成对话的私钥(称为会话密钥)的随机信息,然后用服务器的公钥对它加密并将它发送到服务器。服务器用自己的私钥解密消息,然后用该随机信息派生出和客户机一样的私有会话密钥。通常在这个阶段使用RSA 公钥算法。
  然后,客户机和服务器使用私有会话密钥和私钥算法(通常是RC4)进行通信。使用另一个密钥的消息认证码来确保消息的完整性。


  ■SSL/TLS 代码样本
  在本示例中,我们编写了一个使用SSL 服务器套接字的HTTPS 守护程序进程,该进程在浏览器与它连接时返回HTML 流。本示例还演示了如何在支持SSL 部署的特殊密钥库中生成机器证书。
  在Java 编程中,只需要做一件事:使用SSL 服务器套接字工厂(Server SocketFactory)代替套接字工厂(Socket Factory),代码如下:
  SSLServerSocketFacctory sslf =
   (SSLServerSocketFactor)SSLServerSocketFactory.getDefault();
  ServerSocket serverSocket = sslf.createServerSocket(PORT);
  下面列出了完整的代码示例:
  import java.io.*;
  import java.net.*;
  import javax.net.ssl.*;
  //
  // Example of an HTTPS server to illustrate SSL certificate and socket
  public class HTTPSServerExample {
   public static void main(String[] args) throws IOException {
   //
   // create an SSL socket using the factory and pick port 8080
   SSLServerSocketFactory sslsf =
   (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
   ServerSocket ss = sslsf.createServerSocket(8080);
   //
   // loop forever
   while (true) {
   try {
   //
   // block waiting for client connection
   Socket s = ss.accept();
   System.out.println( "Client connection made" );
   // get client request
   BufferedReader in = new BufferedReader(
   new InputStreamReader(s.getInputStream()));
   System.out.println(in.readLine());
   //
   // make an HTML response
   PrintWriter out = new PrintWriter( s.getOutputStream() );
   out.println("<HTML><HEAD><TITLE>HTTPS Server Example</TITLE>" +
   "</HEAD><BODY><H1>Hello World!</H1></BODY></HTML>\n");
   //
   // Close the stream and socket
   out.close();
   s.close();
   } catch (Exception e) {
   e.printStackTrace();
   }
   }
   }
  }


  ■HTTPS 服务器样本执行
  在本示例中,我们创建了一个HTTPS 服务器守护程序,该守护程序等待客户机浏览器的连接并返回“Hello, World!”。浏览器通过https://localhost:8080 连接到该守护程序。
  我们首先创建一个机器证书。名称必须与运行守护程序的计算机的机器名匹配;在本例中是localhost。此外,我们不能使用先前所用的同一.keystore。必须专门为机器证书创建一个单独的密钥库。在本例中,它的名称是sslKeyStore
  D:\IBM>keytool -genkey -v -keyalg RSA -alias MachineCert
   -keystore sslKeyStore
  Enter keystore password: password
  What is your first and last name?
   [Unknown]: localhost
  What is the name of your organizational unit?
   [Unknown]: Security
  What is the name of your organization?
   [Unknown]: Company, Inc.
  What is the name of your City or Locality?
   [Unknown]: Machine Cert City
  What is the name of your State or Province?
   [Unknown]: MN
  What is the two-letter country code for this unit?
   [Unknown]: US
  Is CN=localhost, OU=Security, O="Company, Inc.", L=Machine Cert City,
  ST=MN, C=US correct?
   [no]: y
  Generating 1,024 bit RSA key pair and self-signed certificate (MD5WithRSA)
   for: CN=localhost, OU=Security, O="Company, Inc.", L=Machine Cert City,
  ST=MN, C=US
  Enter key password for <MachineCert>
   (RETURN if same as keystore password):
  [Saving sslKeyStore]
  然后,我们指定特殊的密钥库及其密码,启动该服务器守护程序进程:
  D:\IBM>java -Djavax.net.ssl.keyStore=sslKeyStore
   -Djavax.net.ssl.keyStorePassword=password HTTPSServerExample
  在等待数秒之后,启动一个浏览器并使它指向https://localhost:8080,然后会提示您是否要信任该证书。选择“yes”应该显示“Hello World!”,接着单击Internet Explorer 上的锁会给出证书的详细信息。


第十章 结束语和参考资料


  ■结束语
  本教程介绍了可以用来提供众多应用程序安全性解决方案的主要密码术构件。您已经熟悉了此类Java 安全性主题:
  ·使安全编程更方便的内置特性(无指针、字节码验证器、对applet 和应用程序资源访问权的细颗粒度控制、用于所有主要密码术构件的大量的库函数,以及SSL)。
  ·安全编程技术(密码的正确存储和删除和智能序列化)。
  ·JDK 1.4 中新集成的特性(JCE、JSSE、JAAS、JGSS 和CertPath API)。
  ·第三方提供的丰富的安全性特性
  我们还了解了下列概念:
  ·消息摘要
  ·消息认证码
  ·私钥密码术
  ·公钥密码术
  ·数字签名
  ·数字证书
  ·认证中心和路径
  ·代码签名
  ·SSL/TLS
  您现在应该可以很轻松地研究Java 安全性的更多详细信息(请参阅参考资料一章),并学习下一篇教程Java security,Part 2:Authentication and authorization


  ■参考资料


  下载
  ·下载本教程中使用的完整源代码和类。
  ·有关本教程中使用的第三方提供程序库,请参阅BouncyCastle(http://www.bouncycastle.org)。


  文章、教程和其它在线参考资料
  ·Sun 的Java Security 网站(http://java.sun.com/security)是Java 安全性的权威资料来源。
  ·阅读Brad Rubin 在本系列中的第二篇教程“Javasecurity,Part 2:Authentication and authorization”(developerWorks,2002 年7 月,http://www-106.ibm.com/developerworks/education/r-jsec2.html)。
  ·Michael Yuan 在文章“Securing your J2ME/MIDP apps”(developerWorks,2002 年7 月,http://www-106.ibm.com/developerworks/library/j-midpds.html)中演示了如何在无线设备上使用Bouncy Castle Crypto API 对XML 文档进行数字签名和验证。
  ·Greg Travis 在其教程“Using JSSE for secure socket communication”(developerWorks,2002 年4 月,http://www-106.ibm.com/developerworks/education/r-jsse.html)中提供了对JSSE 的实践性研究。


  书籍
  ·要获取对Web 安全性和Java 技术的完整讨论,请参阅Web Security, Privacy, and Commerce,第2 版(http://www.oreilly.com/catalog/websec2/),Simson Garfinkel 和Gene Spafford 著,O'Reilly 出版,2002 年。
  ·如果您想更多地关注Java 安全性,请参阅Professional Java Security(http://www.amazon.com/exec/obidos/ASIN/1861004257/104-8739833-1347930),Jess Garms 和Daniel Somerfield 著,Wrox Press 出版,2001 年。
  ·另一本用于了解Java 安全性的重要参考资料是Java Security(http://www.amazon.com/exec/obidos/ASIN/0596001576),Scott Oaks 著,O'Reilly & Associates 出版,2001 年。
  ·从Secrets and Lies:Digital Security in a Networked World(http://www.counterpane.com/sandl.html,Bruce Schneier 著,2000 年)中找出人们为了生存和竞争需要知道哪些关于安全性的知识。
  ·Applied Cryptography,第2 版(http://www.counterpane.com/applied.html),(Bruce Schneier 著,1995)这本书自夸拥有新的算法、关于Clipper Chip 和密钥托管(key escrow)的更多信息、数十个新协议、关于PGP 的更多信息、关于密钥管理和操作方式的详细信息以及新的源代码,如果真是这样,它应该成为安全性方面书籍的赢家。


  其它参考资料
  ·IBM Java Security Research 页面(http://www.research.ibm.com/javasec/)详细描述了正在进行中的各种安全性项目。
  ·访问Tivoli 开发者园地(http://www-106.ibm.com/developerworks/tivoli/)以获取构建和维护您的电子商务安全性方面的帮助。
  ·developerWorks 安全特别专题(http://www-106.ibm.com/developerworks/security/)向开发人员提供了涵盖一般安全性主题的实用技术信息。
  ·请参与由Paul Abbott 主持的developerWorks Java安全论坛。
  ·您可以在developerWorks Java 技术专区(http://www-106.ibm.com/developerworks/java/)找到关于Java 编程的各个方面的数百篇文章。
  ·请参阅developerWorks 教程页面,以便从developerWorks 获取与Java 技术相关的免费教程的完整清单。


没有评论: