也许没有比应用程序安全更重要的软件工程主题。 攻击是昂贵的,无论是来自内部还是外部,而且某些攻击可能会使软件公司承担赔偿责任。 随着计算机(尤其是Internet)技术的发展,安全攻击变得越来越复杂和频繁。 掌握最新技术和工具是应用程序安全的关键之一。 另一个是成熟的技术的坚实基础,例如数据加密,身份验证和授权。
Java平台(包括基本语言和库扩展)为编写安全的应用程序奠定了良好的基础。 本教程介绍了密码学的基础知识以及如何用Java编程语言实现密码学,并提供了示例代码来说明这些概念。
在分两部分的教程的第一部分中,我们介绍了库扩展(现在是JDK 1.4基础的一部分)中的资料,这些扩展称为Java密码术扩展(JCE)和Java安全套接字扩展(JSSE)。 另外,本教程介绍了CertPath API,它是JDK 1.4的新增功能。 在第2部分(请参阅参考资料 )中,我们将扩大讨论范围以涵盖访问控制,访问控制由Java身份验证和授权服务(JAAS)在Java平台中进行管理。
这是一个中级教程。 它假定您知道如何读写基本的Java程序,包括应用程序和applet。
如果您已经是Java程序员,并且对加密技术(诸如私钥和公钥加密,RSA,SSL,证书等主题)以及支持它们的Java库(JCE,JSSE)感到好奇,那么本教程适合您。 它不假定密码学,JCE或JSSE具有任何以前的背景。
本教程介绍了基本的密码构建块概念。 每个概念后都有Java实现注意事项,代码示例以及示例执行的结果。
您需要以下各项来完成本教程中的编程练习:
JDK 1.4,标准版 本教程的源代码和类JavaSecurity1-source.jar ,以便您可以按照示例进行操作 RSA示例的Bouncy Castle Crypto库 支持Java 1.4插件的浏览器您可以使用JDK 1.3.x,但必须自己安装JCE和JSSE。
这些代码示例将加密的数据直接转储到屏幕上。 在大多数情况下,这将导致外观怪异的控制字符,其中某些字符有时可能会导致屏幕格式问题。 这不是一个好的编程习惯(最好将它们转换为可显示的ASCII字符或十进制表示形式),但是此处已这样做是为了保持代码示例及其输出简短。
在大多数情况下,在示例执行部分中,实际字符串已被修改为与本教程的字符集要求兼容。 同样,在大多数示例中,我们查找并显示用于给定算法的实际安全提供程序库。 这样做是为了使用户更好地了解针对哪些函数调用了哪些库。 为什么? 因为在大多数安装中,安装了许多这些提供程序。
Java编程语言和环境具有许多有助于安全编程的功能:
没有指针 ,这意味着Java程序无法寻址地址空间中的任意内存位置。 字节码验证程序 ,在对.class文件进行编译后运行,并在执行之前检查安全性问题。 例如,将拒绝访问超出数组大小的数组元素的尝试。 由于缓冲区溢出攻击是造成大多数系统漏洞的原因,因此这是一项重要的安全功能。 对applet和应用程序的资源访问进行细粒度控制 。 例如,可以限制applet读取或写入磁盘空间,或者可以授权applet仅从特定目录读取。 该授权可以基于谁对代码进行签名 (请参阅代码签名的概念 )和代码源的http地址。 这些设置显示在java.policy文件中。 用于所有主要密码构造块和SSL(本教程的主题)以及身份验证和授权(在本系列的第二篇教程中讨论) 的大量库函数 。 此外,许多第三方库可用于其他算法。简而言之,可以使用多种编程样式和技术来帮助确保更安全的应用程序。 考虑以下两个一般示例:
存储/删除密码。 如果密码存储在Java String对象中,则密码将保留在内存中,直到被垃圾回收或过程结束为止。 如果是垃圾回收,它将一直存在于可用内存堆中,直到重新使用内存空间为止。 密码String在内存中保留的时间越长,它越容易受到监听。 更糟的是,如果实际内存不足,则操作系统可能将此密码String分页到磁盘的交换空间,因此容易受到磁盘块监听的攻击。 为了尽量减少(但不能消除)这些风险,您应该将密码存储在char数组中,并在使用后将其归零。 ( String是不可变的,因此您不能将它们归零。) 智能序列化。 当对象被序列化以存储或传输时,默认情况下,流中会存在任何私有字段。 因此,敏感数据容易受到监听。 您可以使用transient关键字标记属性,以便在流中将其跳过。在整个教程中,当我们需要这些技术时,我们将更详细地讨论它们。
在JDK 1.4之前,必须将许多安全功能作为扩展添加到基本Java代码发行版中。 美国严格的出口限制要求这种功能分离。
现在,新的宽松法规为更紧密地集成安全功能和基本语言打开了大门。 以下软件包(在1.4版本之前用作扩展)现已集成到JDK 1.4中:
JCE (Java密码学扩展) JSSE (Java安全套接字扩展) JAAS (Java身份验证和授权服务)JDK 1.4还引入了两个新功能:
JGSS (Java通用安全服务) CertPath API (Java认证路径API)JCE,JSSE和CertPath API是本教程的主题。 在本系列的下一个教程中,我们将重点介绍JAAS。 这两个教程都没有涵盖JGSS(它提供了一个通用框架来在应用程序之间安全地交换消息)。
我们可以使用第三方库(也称为provider)来增强当前Java语言中已经丰富的功能集。 提供程序添加其他安全算法。
作为图书馆的一个例子,我们将与充气城堡提供商合作(参见相关主题 )。 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。 用于在客户端和服务器之间建立安全通信通道的协议。 传输层安全性(TLS)替代了安全套接字层(SSL)。在讨论每个主题时,我们将提供示例和示例代码。
在本节中,我们将学习消息摘要,这些摘要将消息中的数据带入并生成一个位块,用于表示消息的“指纹”。 我们还将介绍与消息摘要有关的JDK 1.4支持的算法,类和方法,为消息摘要和消息身份验证功能提供代码示例和示例执行代码。
消息摘要是一种确保消息完整性的功能。 消息摘要将一条消息作为输入,并生成通常代表几百位长的位块,以表示消息的指纹。 消息中的微小变化(例如,闯入者或窃听者)使指纹产生了明显的变化。
消息摘要功能是单向功能。 从消息中生成指纹是一件简单的事情,但是要生成与给定指纹匹配的消息则相当困难。
消息摘要可以弱也可以强。 校验和(即消息所有字节的XOR)是弱消息摘要功能的示例。 修改一个字节以生成任何所需的校验和指纹很容易。 最强大的功能使用哈希。 消息中的1位更改会导致指纹发生巨大变化(理想情况下,指纹位的50%会发生变化)。
JDK 1.4支持以下消息摘要算法:
MD2和MD5 ,它们是128位算法 SHA-1 ,这是一种160位算法 SHA-256, SHA-383和SHA-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对象。请注意,密钥生成需要很长时间,因为代码使用线程行为的时序生成了高质量的伪随机数。 一旦生成第一个数字,其他数字将花费更少的时间。
另外,请注意,与消息摘要不同,消息身份验证代码使用加密提供程序。 (有关提供商的更多信息,请参见第三方库丰富了安全性 。)
在本节中,我们将研究私钥加密的用法,并重点关注密码块,填充,流密码和密码模式等概念。 我们将快速详细介绍密码算法,类和方法,并通过代码示例和示例执行来说明此概念。
消息摘要可以确保消息的完整性,但是不能用于确保消息的机密性。 为此,我们需要使用私钥加密来交换私信。
考虑这种情况:Alice和Bob都有一个只有他们知道的共享密钥,并且他们同意使用通用的加密算法或密码。 换句话说,他们将密钥保密。 当爱丽丝(Alice)要发送消息给鲍勃(Bob)时,她会加密原始消息(称为纯文本)以创建密文 ,然后将密文发送给鲍勃(Bob)。 鲍勃从爱丽丝那里收到密文,并用他的私钥解密密文以重新创建原始的明文消息。 如果窃听者Eve正在收听通信,则她仅听到密文,因此可以保留消息的机密性。
您可以加密单个位或大块位,称为块。 这些称为密码块的块通常为64位。 如果消息不是64位的倍数,则必须填充短块(有关填充的更多信息,请参见填充是什么? )。 在硬件实现中单位加密更常见。 单位密码称为流密码 。
私钥加密的强度由加密算法和密钥的长度确定。 如果算法是合理的,则攻击它的唯一方法是尝试每种可能的密钥的蛮力方法,平均将进行(1/2)* 2 * n次尝试,其中n是位数在关键。
当美国出口法规具有限制性时,仅允许输出40位密钥。 该密钥长度相当弱。 美国官方标准DES算法使用了56位密钥,随着处理器速度的加快,它变得越来越弱。 通常,当今首选使用128位密钥。 有了它们,如果每秒可以尝试一百万个密钥,那么平均要花费宇宙年龄的很多倍才能找到密钥!
正如我们在上一节中提到的,如果使用块密码并且消息长度不是块长度的倍数,则必须用字节填充最后一个块,以产生完整的块大小。 有许多填充块的方法,例如使用全零或全零。 在本教程中,我们将对私有密钥加密使用PKCS5填充,对于公共密钥加密使用PKCS1。
对于PKCS5,在短块中填充一个重复字节,该重复字节的值表示剩余的字节数。 在本教程中,我们将不再进一步讨论填充算法,但是为您提供参考,JDK 1.4支持以下填充技术:
没有填充 PKCS5 OAEP SSL3该BouncyCastle的库(见安全富含第三方库和相关信息 )支持其它填充技术。
给定的密码可以用于多种模式 。 模式允许您指定加密的工作方式。
例如,您可以允许一个块的加密取决于上一个块的加密,或者可以使一个块的加密独立于任何其他块。
选择的模式取决于您的需求,并且必须考虑折衷(安全性,并行处理能力以及对明文和密文错误的容忍度)。 模式的选择超出了本教程的范围(请参阅参考资料,以进行进一步的阅读),但是再次提醒您,Java平台支持以下模式:
ECB (电子密码书) CBC (密码块链接) CFB (密码反馈模式) OFB (输出反馈模式) PCBC (传播密码块链接)JDK 1.4支持以下私钥算法:
DES。 DES(数据加密标准)是IBM在1970年代发明的,并被美国政府采纳为标准。 它是一个56位的分组密码。 三重DES。 该算法用于处理56位密钥日益严重的弱点,同时利用DES技术,通过两次使用两个密钥的DES算法运行纯文本,有效密钥强度为112位。 TripleDES有时也称为DESede(用于加密,解密和加密,这是三个阶段)。 AES。 AES(高级加密标准)取代了DES作为美国标准。 它是由Joan Daemen和Vincent Rijmen发明的,也被称为Rinjdael算法。 它是128位的块密码,密钥长度为128、192或256位。 RC2, RC4和RC5。 这些是来自领先的加密安全公司RSA Security的算法。 河豚。 该算法由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) :计算密文。在本节中,我们将研究公共密钥加密技术,该功能解决了在各方之间无需事先安排密钥就加密消息的问题。 我们将简短地介绍支持公钥功能的算法,类和方法,并提供代码示例和执行以说明该概念。
私钥加密有一个主要缺点:私钥如何首先到达Alice和Bob? 如果Alice生成了它,则必须将其发送给Bob,但这是敏感信息,因此应进行加密。 但是,尚未交换密钥来执行加密。
1970年代发明的公钥密码术解决了在无需事先就密钥达成协议的情况下在两方之间加密消息的问题。
在公共密钥加密中,Alice和Bob不仅具有不同的密钥,而且每个都有两个密钥。 一个密钥是私有的,不能与任何人共享。 另一个密钥是公共密钥,可以与任何人共享。
当爱丽丝(Alice)要向鲍勃(Bob)发送安全消息时,她使用鲍勃(Bob)的公钥对消息进行加密,然后将结果发送给鲍勃(Bob)。 鲍勃使用他的私钥来解密消息。 当Bob想要向Alice发送安全消息时,他使用Alice的公钥对消息进行加密,然后将结果发送给Alice。 爱丽丝使用她的私钥来解密消息。 夏娃可以窃听公共密钥和加密的消息,但是她不能解密消息,因为她没有两个私有密钥。
公钥和私钥是成对生成的,并且比等效强度的私钥加密密钥需要更长的长度。 RSA算法的典型密钥长度为1,024位。 从另一对派生密钥对中的一个成员是不可行的。
公钥加密很慢(比私钥加密慢100到1000倍),因此在实践中通常使用混合技术。 公共密钥加密用于将私钥(称为会话密钥 )分发给另一方,然后使用该私密会话密钥的私钥加密用于大部分消息加密。
公钥加密中使用以下两种算法:
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) :解密密文。在本节中,我们将检查数字签名,这是确定交换消息的各方的标识的第一级。 我们将说明通过代码示例识别消息源的困难和简便方法。 我们还将列出JDK 1.4支持的数字签名算法,并研究其中涉及的类和方法。
您是否注意到什么是公共密钥密码学中描述的公共密钥消息交换中的缺陷? ? 鲍勃(Bob)如何证明该消息确实来自爱丽丝? 夏娃本可以用她的公钥代替爱丽丝的,然后鲍勃将与夏娃交换信息,以为自己是爱丽丝。 这就是所谓的中间人攻击 。
我们可以使用数字签名来解决此问题-一种位模式,它证明消息来自给定的参与者。
实现数字签名的一种方法是使用什么是公共密钥密码学中描述的公共密钥过程的相反过程。 。 发件人使用私钥对消息签名,而不是使用公钥加密和私钥解密,而收件人则使用发件人的公钥来解密消息。 因为只有发件人才知道私钥,所以收件人可以确定邮件确实来自发件人。
实际上,消息摘要( 什么是消息摘要? )不是整个消息,而是由私钥签名的位流。 因此,如果爱丽丝想向鲍勃发送签名消息,则她会生成消息的消息摘要,并使用她的私钥对其进行签名。 她将消息(明文)和签名的消息摘要发送给Bob。 Bob使用Alice的公钥解密已签名的消息摘要,并根据明文消息计算消息摘要,并检查两个摘要是否匹配。 如果他们这样做,鲍勃可以确定消息是来自爱丽丝的。
请注意,数字签名不提供消息的加密,因此,如果您还需要保密,则必须将加密技术与签名结合使用。
您可以将RSA算法用于数字签名和加密。 可以将称为DSA(数字签名算法)的美国标准用于数字签名,但不能用于加密。
JDK 1.4支持以下数字签名算法:
MD2 / RSA MD5 / RSA SHA1 / DSA SHA1 / RSA在本节中,我们将研究两个示例。 第一种是硬方法(请参阅数字签名代码示例:硬方法 ),它使用已经讨论过的原语来进行消息摘要和公共密钥加密来实现数字签名。 第二种简便方法(请参见数字签名代码示例:easy method )使用Java语言对签名的直接支持。
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" ); } } }在本节中,我们将讨论数字证书,这是确定消息始发者身份的第二级。 我们将研究证书颁发机构及其扮演的角色。 我们将研究密钥和证书存储库以及管理工具(keytool和keystore),并讨论CertPath API,这是一组旨在构建和验证证书路径的功能。
您可能已经注意到, 什么是数字签名?中描述的数字签名方案存在问题。 。 它证明消息是由给定的一方发送的,但是我们如何确定发件人确实是她说的那个人。 如果有人声称自己是爱丽丝并签署了一条消息,但实际上是阿曼达,该怎么办? 我们可以使用数字证书来提高我们的安全性, 数字证书将身份和公钥打包在一起,并由称为证书颁发机构或CA的第三方进行数字签名。
证书颁发机构是一个组织,它在真实世界的物理意义上验证一方的身份,并使用CA私钥对该方的公钥和身份进行签名。 邮件收件人可以获取发件人的数字证书,并使用CA的公钥对其进行验证(或解密)。 这证明证书是有效的,并允许收件人提取发件人的公共密钥以验证其签名或向他发送加密的消息。 浏览器和JDK本身带有来自多个CA的内置证书及其公共密钥。
JDK 1.4支持X.509数字证书标准。
Java平台使用密钥库作为密钥和证书的存储库。 从物理上讲,密钥库是一个文件(可以选择将其加密),其默认名称为.keystore。 密钥和证书可以具有称为别名的名称,并且每个别名都可以由唯一的密码保护。 密钥库本身也受密码保护。 您可以选择使每个别名密码与主密钥库密码匹配。
Java平台使用密钥工具操纵密钥库。 该工具提供了许多选项。 下面的示例( keytool示例 )显示了生成公共密钥对和相应证书并通过查询密钥库查看结果的基础。
可以使用keytool将密钥导出到X.509格式的文件中,该文件可以由证书颁发机构签名,然后重新导入到密钥库中。
还有一个特殊的密钥库,用于保存证书颁发机构(或任何其他受信任的)证书,依次包含用于验证其他证书的有效性的公共密钥。 此密钥库称为信任库。 Java语言在名为cacerts的文件中带有默认信任库。 如果搜索此文件名,则将至少找到这些文件中的两个。 您可以使用以下命令显示内容:
keytool -list -keystore cacerts Use a password of "changeit"在此示例中,使用默认密钥库.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认证路径API是JDK 1.4的新增功能。 它是用于构建和验证认证路径或链的一组功能。 这在SSL / TLS(请参阅什么是安全套接字层/传输层安全性? )和JAR文件签名验证之类的协议中隐式完成,但是现在可以在具有此支持的应用程序中显式完成。
如什么是数字证书中所述? ,CA可以使用其私钥对证书进行签名,如果接收者持有的CA证书具有进行签名验证所需的公钥,则它可以验证签名证书的有效性。
在这种情况下,证书链的长度为两个-信任锚(CA证书)和签名证书。 自签名证书的长度为一-信任的锚点是已签名证书本身。
链的长度可以是任意的,因此在三链中,信任证书的CA锚可以签署中间证书; 该证书的所有者可以使用其私钥来签署另一个证书。 CertPath API可用于遍历证书链以验证有效性,以及构建这些信任链。
证书具有到期日期,但是可以在到期之前受到损害,因此必须检查证书吊销列表 (CRL)以真正确保签名证书的完整性。 这些列表可在CA网站上找到,也可以使用CertPath API进行编程操作。
特定的API和代码示例不在本教程的讨论范围之内,但是Sun除了API文档外还提供了几个代码示例。
在本节中,我们将回顾代码签名的概念,重点是管理JAR文件认证的工具Jarsigner。
JAR文件与ZIP文件在Java平台上等效,允许将多个Java类文件打包为一个扩展名为.jar的文件。 然后可以对该JAR文件进行数字签名,以证明其中的类文件代码的起源和完整性。 JAR文件的接收者可以基于发送者的签名来决定是否信任该代码,并且可以确信在接收之前内容没有被篡改。 JDK附带了提供此功能的jarsigner工具。
In deployment, access to machine resources can be based on the signer's identity by putting access control statements in the policy file.
The jarsigner tool takes a JAR file and a private key and corresponding certificate as input, then generates a signed version of the JAR file as output. It calculates the message digests for each class in the JAR file and then signs these digests to ensure the integrity of the file and to identify the file owner.
In an applet environment, an HTML page references the class file contained in a signed JAR file. When this JAR file is received by the browser, the signature is checked against any installed certificates or against a certificate authority public signature to verify validity. If no existing certificates are found, the user is prompted with a screen giving the certificate details and asking if the user wants to trust the code.
In this example, we first create a JAR file from a .class file and then sign it by specifying the alias for the certificate in the keystore that is used for the signing. We then run a verification check on the signed JAR file.
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.Here is the HTML for this program:
<HTML> <HEAD> <TITLE> Hello World Program </TITLE> </HEAD> <BODY> <APPLET CODE="HelloWorld.class" ARCHIVE="HelloWorld.jar" WIDTH=150 HEIGHT=25> </APPLET> </BODY> </HTML>When this example is executed with a browser that uses the Java plug-in as the Java virtual machine, a dialog box pops up asking if the user wants to install and run the signed applet distributed by "Joe User", and says that the publisher authenticity is verified by "Company, Inc.", but that the security was issued by a company that is not trusted. The security certificate has not expired and is still valid. It cautions that "Joe User" asserts that this content is safe and should only be installed or viewed if you trust "Joe User" to make that assertion. The user is given the following options:
Grant this session 拒绝 Grant always View certificateIn this section, we'll examine the building blocks of the Secure Sockets Layer (and its replacement, Transport Layer Security), the protocol used to authenticate the server to the client. We'll offer a few code examples as illustrations.
Secure Sockets Layer (SSL) and its replacement, Transport Layer Security (TLS), is a protocol for establishing a secure communications channel between a client and a server. It is also used to authenticate the server to the client and, less commonly, used to authenticate the client to the server. It is usually seen in a browser application, where the lock at the bottom of the browser window indicates SSL/TLS is in effect.
TLS 1.0 is the same as SSL 3.1.
SSL/TLS uses a hybrid of three of the cryptographic building blocks already discussed in this tutorial, but all of this is transparent to the user. Here is a simplified version of the protocol:
When a request is made to a site using SSL/TLS (usually with an https:// URL), a certificate is sent from the server to the client. The client verifies the identify of the server from this certificate using the installed public CA certificates, then checks that the IP name (machine name) matches the machine that the client is connected to. The client generates some random info that can be used to generate a private key for the conversation, known as a session key, and encrypts it with the server's public key and sends it to the server. The server decrypts the message with its private key and uses the random info to derive the same private session key as the client. The RSA public key algorithm is usually used for this phase. The client and server then communicate using the private session key and a private key algorithm, usually RC4. A message-authentication code , using yet another key, is used to ensure the integrity of the message.In this example, we write an HTTPS daemon process using an SSL server socket that returns an HTML stream when a browser connects to it. This example also shows how to generate a machine certificate in a special keystore to support the SSL deployment.
In Java programming, the only thing that needs to be done is to use an SSL Server Socket Factory instead of a Socket Factory, using lines like the following:
SSLServerSocketFacctory sslf = (SSLServerSocketFactor)SSLServerSocketFactory.getDefault(); ServerSocket serverSocket = sslf.createServerSocket(PORT);The complete code example is listed below:
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(); } } } }In this example, we create an HTTPS server daemon that waits for a client browser connection and returns "Hello, World!". The browser connects to this daemon via https://localhost:8080 .
We first create a machine certificate. The name must match the machine name of the computer where the daemon runs; in this case, localhost . In addition, we cannot use the same .keystore we have used in the past. We must create a separate keystore just for the machine certificate. In this case, it has the name 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]Then, we start the server daemon process specifying the special keystore and its password:
D:\IBM>java -Djavax.net.ssl.keyStore=sslKeyStore -Djavax.net.ssl.keyStorePassword=password HTTPSServerExampleAfter waiting a few seconds, fire up a browser and point it to https://localhost:8080 and you should be prompted on whether or not to trust the certificate. Selecting "yes" should display "Hello World!", and clicking on the lock in Internet Explorer will give the certificate details.
This tutorial introduced the major cryptographic building blocks that can be used to provide a vast array of application security solutions. You've become familiar with such Java security topics as:
Built-in features that facilitate secure programming (no pointers, a bytecode verifier, fine-grained control over resource access for both applets and applications, a large number of library functions for all the major cryptographic building blocks, and SSL). Secure programming techniques (proper storage and deletion of passwords and intelligent serialization). Features newly integrated in JDK 1.4 (JCE, JSSE, JAAS, JGSS, and CertPath API). Enriching, third-party security offerings .And the following concepts:
Message digests Message authentication codes Private key cryptography Public key cryptography 数字签名 Digital certificates Certification authorities and paths Code signing SSL/TLSYou should be well poised to explore Java security in more detail (see the Related topics section) and to take the next tutorial, Java security, Part 2: Authentication and authorization .
翻译自: https://www.ibm.com/developerworks/java/tutorials/j-sec1/j-sec1.html