JCA - 核心类和接口 - Provider类
Provider类
术语“加密服务提供者(CSP)”(在本文档中与“Provider”可互换使用)是指提供JDK安全API加密功能子集的具体实现的一个或一组包。Provider类是这种包或一组包的接口。它有用来访问Provider名称,版本号和其他信息
的方法。请注意,除了注册加密服务的实现外,Provider类还可以用于注册其他被定义为JDK安全API或其扩展之一的其他安全服务的实现。
为了提供密码服务的实现,一个实体(例如开发组)编写实现代码并创建Provider类的子类。Provider子类的构造函数设置各种属性的值; JDK安全API使用这些值来查找Provider实现的服务。换句话说,子类指定实现服务的类的名称
。
有几种类型的服务可以通过提供者包实现; 更多信息,请参阅Engine Classes and Algorithms。
不同的实现可能具有不同的特性。有些可能是基于软件的,有些可能是基于硬件的。有些可能是平台无关的,有些可能是平台特定的。一些供应商的源代码可能可用于审查和评估,而有些则可能不可用。JCA让最终用户和开发者决定他们的需求。
在本节中,我们解释最终用户如何安装符合他们需求的加密实现,以及开发人员如何请求适合他们的实现。
注意:有关实现Provider的更多信息,请参阅指南How To Implement a Provider for the Java Cryptography Architecture
如何请求和提供Provider实现
对于API中的每个引擎类,通过调用引擎类的getInstance方法来请求和实例化实现实例,指定想要实现的所需算法的名称以及可选的Provider(或Provider类)的名称。
static EngineClassName getInstance(String algorithm) throws NoSuchAlgorithmException
static EngineClassName getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException
static EngineClassName getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException
其中EngineClassName是所需的引擎类型(MessageDigest/Cipher/etc)。 例如:
MessageDigest md = MessageDigest.getInstance("SHA-256");
KeyAgreement ka = KeyAgreement.getInstance("DH", "SunJCE");
分别返回“SHA-256”MessageDigest和“DH”KeyAgreement对象的实例。
附录A包含已经标准化的用于Java环境的名称列表。有些Provider可能会选择也包含指向相同算法的别名。 例如,“SHA256”算法可能被称为“SHA-256”。 应用程序应该使用标准名称而不是别名,因为不是所有的提供者都可以用同样的方法来命名算法名称。
注意:算法名称不区分大小写
。例如,以下所有调用都是等同的:
MessageDigest.getInstance("SHA256")
MessageDigest.getInstance("sha256")
MessageDigest.getInstance("sHa256")
如果没有指定提供程序,getInstance将搜索已注册的提供程序,以获得与指定算法关联的请求的加密服务的实现。在任何给定的Java虚拟机(JVM)中,提供程序都是以给定的优先顺序安装的,如果没有请求特定的提供程序,搜索提供程序列表的顺序就会被搜索到。例如,假设在JVM,PROVIDER_1和PROVIDER_2中安装了两个提供程序。假设:
- PROVIDER_1实现SHA-256和DESede
- PROVIDER_1拥有优先顺序1(最高优先级)
- PROVIDER_2使用DSA,SHA-256,RC5和RSA实现SHA256
- PROVIDER_2具有优先顺序2
现在让我们看看三种情况:
- 如果我们正在寻找一个SHA-256实现,那么这两个提供者都提供这样的实现。 由于PROVIDER_1具有最高优先级并且首先被搜索,所以PROVIDER_1实现被返回。
- 如果我们正在寻找SHA256withDSA签名算法,则首先搜索PROVIDER_1。 没有找到实现,因此搜索了PROVIDER_2。 由于实现被发现,它被返回。
- 假设我们正在寻找一个SHA256withRSA签名算法。 由于没有安装的提供者实现它,抛出了NoSuchAlgorithmException。
包含Provider参数的getInstance方法适用于想要指定Provider需要算法的开发人员。例如,联邦机构将希望使用已获得联邦认证的提供商实现方案。假设来自PROVIDER_1的SHA256withDSA实施尚未获得此认证,而PROVIDER_2的DSA实现已获得此认证。
然后联邦机构计划将会有以下调用,并指定PROVIDER_2,因为它具有经过认证的实施:
Signature dsa = Signature.getInstance("SHA256withDSA", "PROVIDER_2");
在这种情况下,如果PROVIDER_2未安装,即使另一个已安装的提供程序实现了所请求的算法,也会引发NoSuchProviderException。
程序还可以选择获取所有已安装提供程序的列表(使用Security类中的getProviders方法),并从列表中选择一个。
注:通用应用程序不应该请求来自特定提供商的加密服务
。否则,应用程序绑定到特定的Provider可能没有其他可用的java实现。他们也可能无法利用可用的优化Provider(例如,通过PKCS11的硬件加速器或Microsoft的MSCAPI等本机操作系统实现),这些Provider的优先顺序高于特定的请求提供程序。
安装Provider
为了使用Provider,必须首先安装加密Provider,然后静态或动态注册。Sun发行版提供了多种Sun Provider(SUN,SunJCE,SunJSSE,SunRsaSign等),已经安装并注册。 以下各节介绍如何安装和注册其他提供程序。
安装Provider类
有两种可能的方法来安装Provider类:
- 在正常的Java classpath
在你的classpath路径的任何位置放置一个包含Provider类的zip或JAR文件。一些算法类型(Cipher)要求Provider是一个签过名的Jar包。
- 作为安装的/绑定的扩展
如果将Provider置于标准扩展目录中,则该Provider将被视为已安装的扩展程序。 在JDK中,这将位于:
- Solaris, Linux, or Mac OS X: <JAVA_HOME>/lib/ext
- Windows:<JAVA_HOME>\lib\ext
这里的是指安装运行时软件的目录,它是Java运行时环境(JRE)的顶层目录或Java JDK软件中的jre目录。例如,如果在Solaris上将JDK 6安装在名为/home/user1/JDK1.6.0的目录中或在Microsoft Windows上的名为C:\Java\JDK1.6.0的目录中,则需要将JAR文件安装到 以下目录: - Solaris, Linux, or Mac OS X: /home/user1/JDK1.6.0/jre/lib/ext
- Windows: C:\JDK1.6.0\jre\lib\ext
同样,如果在Solaris上将JRE 6安装在名为/home/user1/jre1.6.0的目录中或在Microsoft Windows上的名为C:\jre1.6.0的目录中,则需要将JAR文件安装在以下目录中: - Solaris, Linux, or Mac OS X: /home/user1/jre1.6.0/lib/ext
- Windows: C:\jre1.6.0\lib\ext
如何部署扩展的更多信息,请查看How is an extension deployed?
注册Provider
下一步是将Provider添加到Provider注册列表中。Provider可以在Java程序启动之前通过安全策略配置文件静态地注册,或者在运行时调用方法动态地注册。为了防止将恶意Provider的安装添加到运行时环境中,试图动态注册提供程序的应用程序必须拥有适当的运行时权限。
静态注册
配置文件在如下路径:
Solaris, Linux, or Mac OS X: /lib/security/java.security
- Windows: \lib\security\java.security
每个注册后地Provider,文件中由下面格式地一句话:
security.provider.n=masterClassName
这样声明一个Provider,并且指定了它的优先顺序n。优先顺序是向Provider搜索请求算法的顺序(当没有请求特定的Provider时)。顺序从1开始:1是最优先的,然后是2,依此类推。
masterClassName必须指定Provider的主类的完全限定名称。Provider的文档将指定它的主类。这个类总是Provider类的一个子类。子类构造函数设置Java加密API所需的各种属性的值,以查找Provider实现的算法或其他工具。
JDK标配自动安装和配置的提供程序,跟“SUN”和“SunJCE”一样。“SUN” Provider的主类是sun.security.provider包中的SUN类,相应的java.security文件条目如下:
security.provider.5=sun.security.provider.Sun
要使用另一个JCA Provider,为Provider添加一条条目,指定优先顺序(如果需要,对其他Provider的条目进行相应的调整)。
假设CompanyX的Provider的主类是com.companyx.provider.ProviderX,并且你想把这个Provider配置成第八个优先级。 为此,您可以将以下行添加到java.security文件中:
security.provider.8=com.companx.provider.ProviderX
动态注册
要动态注册Provider,应用程序需要调用Security类中的addProvider或insertProviderAt方法。 这种方式的注册在VM实例中不是永久性的,只能通过具有适当权限的“可信任”程序完成。 参见Security。
设置Provider权限
每当使用加密Provider(即提供Cipher,KeyAgreement,KeyGenerator,Mac或SecretKeyFactory的实现的Provider),并且Provider不是已安装的扩展时,如果安装了安全管理器,可能需要为使用JCA的applet或应用程序授予权限 。每当一个applet运行的时候,通常都会安装一安全管理器,并且可以通过应用程序本身的代码或通过命令行参数为应用程序安装安全管理器。 由于默认系统策略配置文件授予安装的扩展的所有权限(即安装在扩展目录中),因此不需要授予安装的扩展的权限。
您将要使用的每个Provider的文档应该包括所需的权限以及如何授予这些权限的信息。 例如,如果Provider不是已安装的扩展程序并安装了安全管理器,则可能需要以下权限:
- java.lang.RuntimePermission “getProtectionDomain” 获取类保护域。Provider可能需要在进行自我完整性检查的过程中获得自己的保护域
- java.security.SecurityPermission “putProviderProperty.{name}” 去设置Provider属性,其中{name}由实际Provider名称替换
例如,下面给出了一个样例语句,该语句授予名称为“MyJCE”且代码位于myjce_provider.jar中的提供程序的权限。这样的陈述可以出现在政策文件中。在这个例子中,假设myjce_provider.jar文件位于/ localWork目录中。
grant codeBase "file:/localWork/myjce_provider.jar" {
permission java.lang.RuntimePermission "getProtectionDomain";
permission java.security.SecurityPermission "putProviderProperty.MyJCE";
};
Provider类方法
每个Provider类实例都有一个名称(当前区分大小写的),一个版本号以及Provider和其服务的字符串描述。 您可以通过调用以下方法来查询Provider实例以获取此信息:
public String getName()
public double getVersion()
public String getInfo()