这篇文章描述了如何使用Java密码体系结构 (JCA),该体系结构使您可以在应用程序中使用密码服务。
Java密码体系结构服务
JCA提供了许多加密服务,例如消息摘要和签名 。
这些服务可以通过特定于服务的API来访问,例如MessageDigest
和Signature
。
密码服务抽象了不同的算法。 例如,对于摘要,可以使用MD5或SHA1 。 您可以将算法指定为加密服务类的getInstance()
方法的参数:
MessageDigest digest = MessageDigest.getInstance("MD5");
您可以在“ JCA 标准算法名称文档”中找到算法参数的值。
一些算法具有参数。 例如,生成私钥/公钥对的算法将把密钥大小作为参数。 您可以使用initialize()
方法指定参数:
KeyPairGenerator generator = KeyPairGenerator.getInstance("DSA");
generator.initialize(1024);
如果不调用initialize()
方法,则将使用某些默认值,该默认值可能是您想要的,也可能不是。
不幸的是,用于初始化的API在服务之间并非100%一致。
例如, Cipher
类将init()
与指示加密或解密的参数一起使用,而Signature
类将initSign()
用于签名, initVerify()
用于验证。
Java密码体系结构提供程序
JCA通过提供程序系统使您的代码独立于特定密码算法的实现。
提供商根据可配置的首选项顺序进行排名(请参见下文)。 最佳优先级是1,次佳是2,依此类推。优先级顺序允许JCA选择实现给定算法的最佳可用提供程序。
另外,您可以在getInstance()
的第二个参数中指定特定的提供程序:
Signature signature = Signature.getInstance("SHA1withDSA", "SUN");
默认情况下,JRE附带了来自Oracle的一堆提供程序 。 但是,由于历史上的出口限制,这些并不是最安全的实现。 要获得更好的算法和更大的密钥大小,请安装Java密码学扩展无限强度管辖权策略文件 。
更新 :请注意,以上声明对Oracle JRE是正确的。 OpenJDK没有相同的限制 。
使您可以对密码学进行配置
您应始终确保应用程序使用的加密服务是可配置的。
如果这样做,则可以在不发布补丁的情况下更改密码算法和/或实现。
当对(一种实现)算法有新的攻击时,这特别有价值。
JCA使配置加密的使用变得容易。
getInstance()
方法同时接受算法的名称和实现该算法的提供程序的名称。 您应该从某种配置文件中读取算法参数的值和所有值。
还要确保将代码DRY保留在一个地方并实例化加密服务。
检查所请求的算法和/或提供程序是否实际可用。
当给定的算法或提供程序不可用时, getInstance()
方法将引发NoSuchAlgorithmException
,因此您应该捕获该异常。 然后最安全的选择是失败,并请他人确保系统配置正确。 如果在配置错误的情况下仍然继续,则可能会导致系统安全性低于要求。
请注意, Oracle建议不要指定提供程序 。 它们提供的原因是,并非所有提供程序都可以在所有平台上使用,并且指定提供程序可能意味着您错过了优化。
您应该权衡这些不利因素和易受攻击的风险。
在您的应用程序中部署具有已知特征的特定提供程序可能会消除Oracle提到的缺点。
添加加密服务提供商
提供程序系统是可扩展的,因此您可以添加提供程序。
例如,您可以使用开源Bouncy Castle或商业RSA BSAFE提供程序。
为了添加提供程序,必须确保其jar对应用程序可用。 为此,您可以将其放在类路径中。
另外,您可以通过将其放置在$JAVA_HOME/lib/ext
目录中来使其成为已安装的扩展 ,其中$JAVA_HOME
是JDK / JRE发行版的位置。
两种方法之间的主要区别在于,默认情况下, 已授予安装的扩展所有权限 ,而classpath上的代码则未被授予 。 当您的代码(的一部分)在沙盒中运行时,这非常重要。
某些服务(例如Cipher
)要求对提供者jar进行签名 。
下一步是在JCA提供者系统中注册提供者。 最简单的方法是使用Security.addProvider()
:
Security.addProvider(new BouncyCastleProvider());
您还可以使用Security.insertProviderAt()
方法设置提供者的优先顺序:
Security.insertProviderAt (new JsafeJCE(), 1);
这种方法的一个缺点是,它将代码耦合到提供程序,因为您必须导入提供程序类。 在像OSGi这样的模块化系统中,这可能不是重要的问题。
需要注意的另一件事是代码需要SecurityPermission
以编程方式添加提供程序。
通过将注册项添加到java.security
属性文件(可在$JAVA_HOME/jre/lib/security/java.security
找到),还可以通过静态注册将提供程序配置为您环境的一部分:
security.provider.1=com.rsa.jsafe.provider.JsafeJCE
security.provider.2=sun.security.provider.Sun
该文件中的属性名称以security.provider.
开头security.provider.
并以提供者的偏好结束。 该属性值是实现Provider
的类的完全限定名称。
实施您自己的加密服务提供商
不要这样做 。 您会弄错它,并且容易受到攻击。
使用加密服务提供者
提供程序的文档应告诉您将哪个提供程序名称用作getInstance()
的第二个参数。 例如,Bouncy Castle使用BC
,而RSA BSAFE使用JsafeJCE
。
大多数提供程序都有自定义API以及符合JCA的API。 请勿使用自定义API,因为那样将无法配置所使用的算法和提供程序。
并非所有算法和实现都是相同的
重要的是要注意,不同的算法和实现具有不同的特性,这些特性或多或少会使它们适合您的情况。
例如,某些组织仅允许使用经过FIPS 140-2认证或在NSA Suite B加密算法列表中的算法和实现。
始终确保您了解客户的加密需求和要求。
在OSGi环境中使用JCA
getInstance()
方法是使用服务提供商接口 (SPI)的工厂方法 。 这在OSGi世界中是有问题的,因为OSGi违反了SPI框架关于存在单个类路径的假设。
另一个潜在的问题是,JCA需要对一些jar进行签名。 如果这些罐子不是有效的OSGi捆绑包,则不能通过bnd来运行它们,因为这样会使签名无效。
幸运的是,您可以用一块石头杀死两只鸟。 将提供程序jar放在主程序(即启动OSGi框架的程序)的类路径中。
然后使用org.osgi.framework.system.packages.extra
系统属性从OSGi系统捆绑包导出提供程序包。 这将使系统捆绑包导出该软件包。
现在,您可以简单地在包中的提供程序Import-Package
上使用Import-Package
。
还有其他的选择 ,因为如果你不能使用上述方案解决这些问题。
参考: Secure Software Development博客上的JCG合作伙伴 Remon Sinnema提供了在Java应用程序中使用加密的信息 。
翻译自: https://www.javacodegeeks.com/2012/12/test-using-cryptography-in-java-applications.html