java网络学习之 jca 常用引擎类简单介绍(13)

jca 常用服务详细介绍

0 所有的引擎类实例化都是通过静态方法实例化,有三个实例化方法如下:

 

Security类

Security类管理已安装的provider和安全性属性。 它只包含静态方法,永远不会实例化。 用于添加或删除提供者以及设置安全属性的方法只能由受信任的程序执行。

getAlgorithms(service )方法可以查看服务可以使用的算法。

管理Providers

下表总结了Security类中的方法,您可以使用它来查询安装了哪些提供程序,以及在运行时安装或删除提供程序。

查询Provider

方法描述
static Provider[] getProviders()返回一个包含所有已安装提供程序的数组(技术上,每个包提供程序的提供程序子类)。 数组中提供者的顺序是他们的偏好顺序。
static Provider getProvider(String providerName)返回提供程序名providerName。 如果找不到Provider,它将返回null。

增加Provider

方法描述
static int addProvider(Provider provider)将提供程序添加到已安装提供程序列表的末尾。 它将返回提供者添加的偏好位置,如果提供者因为已经安装而未被添加,则返回-1。
static int insertProviderAt (Provider provider, int position)在指定的位置添加一个新的提供程序。 如果给定的供应商安装在要求的位置,则以前在该位置的供应商和位置大于位置的所有供应商向上移动一个位置(靠近清单的末尾)。 此方法返回提供程序添加的优先级位置,如果提供程序因为已经安装而未添加,则返回-1。

删除Provider

方法描述
static void removeProvider(String name)删除具有指定名称的提供程序。 如果没有安装提供程序,它将静默地返回。 当指定的提供者被移除时,位于比指定提供者所在位置更大的位置的所有提供者被向下移动一个位置(朝向已安装提供者列表的头部)。

注意:如果要更改提供者的偏好位置,则必须先将其删除,然后将其重新插入到新的偏好位置。

安全属性

Security类维护一个系统范围的安全属性的列表。 这些属性与系统属性类似,但与安全性相关。 这些属性可以静态或动态设置。 我们已经看到了一个静态安全属性的例子(即,通过“security.provider.i”安全属性静态注册一个提供者)。 如果要动态设置属性,可信程序可以使用以下方法:

static String getProperty(String key) 
static void setProperty(String key, String datum)

注意:安全提供程序的列表是在VM启动过程中建立的,因此必须使用上述方法来更改提供程序列表。

提醒一下,配置文件位于以下位置:

  • Solaris, Linux, or Mac OS X: JAVA_HOME/lib/security/java.security
  • Windows: JAVA_HOME\lib\security\java.security

SecureRandom类

SecureRandom类是提供随机数生成器(RNG)功能的引擎类。 它不同于java.lang.Random类,因为它产生密码强的随机数。 如果生成器中的随机性不足,则会使保护机制变得更加容易。 在密码学中使用随机数字,例如生成加密密钥,算法参数等等。

所有Java SE实现都必须指出它们在java.security.Security类的securerandom.strongAlgorithms属性中提供的最强(最随机)的SecureRandom实现。 当需要特别强的随机值时,可以使用此实现。 
伪随机数

创建SecureRandom对象

有几种方法可以获得SecureRandom的实例:

  • 所有Java SE实现都使用无参数构造函数提供默认的SecureRandom:new SecureRandom()。
  • 要获得SecureRandom的特定实现,请使用getInstance()静态工厂方法之一。

设置或者重设种子

SecureRandom实现尝试完全随机化发生器本身的内部状态,除非调用者通过调用其中一个setSeed方法来调用getInstance方法:

synchronized public void setSeed(byte[] seed)
public void setSeed(long seed)

一旦SecureRandom对象被设置了种子,它将产生与原始种子一样随机的比特。

在任何时候,SecureRandom对象都可以使用setSeed方法之一重新设置种子。 此时会对原来的种子进行补充,而不是取代现有的种子; 因此,保证重复的调用永远不会降低随机性。

使用SecureRandom对象

要获得随机字节,调用者只需传递任意长度的数组,然后用随机字节填充:

synchronized public void nextBytes(byte[] bytes)

生成种子字节

如果需要,可以调用generateSeed方法来生成给定数量的种子字节(例如,为其他随机数生成器生成种子):

byte[] generateSeed(int numBytes)

 

MessageDigest

MessageDigest类是一个引擎类,用于提供密码安全的消息摘要(如SHA-256或SHA-512)的功能。 加密安全的消息摘要采用任意大小的输入(一个字节数组),并生成一个固定大小的输出,称为摘要或散列。例如,SHA-256算法产生一个32字节的摘要,而SHA-512的是64字节

摘要有两个属性:

  • 找到两个哈希值相同的消息在计算上应该是不可行的。
  • 摘要不应该透露任何关于用于生成它的输入。

1 :常用方法列表如下

2 方法含义和使用

创建MessageDigest对象

MessageDigest messageDigest=MessageDigest.getInstance("SHA-512")

更新Message Digest对象

计算某些数据的摘要的下一步是将数据提供给初始化的消息摘要对象。 它可以一次或一块地提供。 可以通过调用其中一种更新方法将消息提供给消息摘要:

void update(byte input)
void update(byte[] input)
void update(byte[] input, int offset, int len)

计算摘要

在通过调用更新数据块之后,使用对其中一个摘要方法的调用来计算摘要:

byte[] digest()
byte[] digest(byte[] input)
int digest(byte[] buf, int offset, int len)

第一种方法返回计算的摘要。

第二种方法在调用digest()之前用输入字节数组进行最终更新(输入)然后digest()返回摘要字节数组。

第三种方法将计算的摘要存储在提供的缓冲区buf中,从偏移量开始。 len是分配给摘要的buf中的字节数,该方法返回实际存储在buf中的字节数。 如果缓冲区中没有足够的空间,该方法将抛出异常。

sha.update(i1);
sha.update(i2);
sha.update(i3);
byte[] hash = sha.digest();

等同于

sha.update(i1);
sha.update(i2);
byte[] hash = sha.digest(i3);

 

 

 

Signature类

Signature类是一个引擎类,旨在提供加密数字签名算法(如DSA或RSAwithMD5)的功能。 密码安全签名算法采用任意大小的输入和私钥,并生成一个相对较短(通常是固定大小)的字节串,称为签名,具有以下属性:

  • 只有私钥/公钥对的所有者才能创建签名。 任何拥有公钥的人都可以在计算上不可能恢复私钥
  • 鉴于与用于生成签名的私钥相对应的公钥,应该有可能验证输入的真实性和完整性。
  • 签名和公钥没有透露有关私钥的任何信息。

它也可以用来验证所谓的签名是否实际上是与其相关的数据的真实签名。

签名

一个签名对象被初始化为用一个私钥进行签名,并被赋予待签名的数据。 结果签名字节通常与签名数据保持一致。 当需要验证时,另一个签名对象被创建和初始化以进行验证并给出相应的公钥。 数据和签名字节被馈送到签名对象,并且如果数据和签名匹配,则签名对象报告成功。

尽管签名看起来与消息摘要相似,但它们在提供的保护类型上却有着非常不同的目的。 事实上,诸如“SHA256withRSA”的算法使用消息摘要“SHA256”将大数据集初始“压缩”为更易于管理的形式,然后用“RSA”算法对得到的32字节消息摘要进行签名。

可用方法列表:

3 方法含义和使用

Signature对象状态

签名对象是模态对象。 这意味着一个Signature对象总是处于一个给定的状态,它只能执行一种操作。 状态被表示为在其各自的类中定义的最终整数常量。

签名对象可能具有的三种状态是:

  • UNINITIALIZED
  • SIGN
  • VERIFY

第一次创建时,Signature对象处于UNINITIALIZED状态。 Signature类定义了两个初始化方法initSign和initVerify,它们分别将状态更改为SIGN和VERIFY。

创建Signature对象

签名或验证签名的第一步是创建一个签名实例。 签名对象是通过使用Signature getInstance()静态工厂方法之一获得的。

初始化Signature对象

Signature对象在使用之前必须被初始化。 初始化方法取决于对象是要用于签名还是验证。

如果要用于签名,则必须首先使用要生成签名的实体的私钥来初始化该对象。 这个初始化通过调用方法完成:

final void initSign(PrivateKey privateKey)

此方法将Signature对象置于SIGN状态。

如果相反,Signature对象将用于验证,则必须首先使用将要验证签名的实体的公钥来初始化。 这个初始化是通过调用以下任一方法来完成的:

    final void initVerify(PublicKey publicKey)

    final void initVerify(Certificate certificate)

此方法将Signature对象置于VERIFY状态。

签名

如果签名对象已经被初始化为签名(如果它处于SIGN状态),则待签名的数据可以被提供给该对象。 这是通过对其中一个更新方法进行一个或多个调用完成的:

final void update(byte b)
final void update(byte[] data)
final void update(byte[] data, int off, int len)

应该调用update方法,直到所有要签名的数据都被提供给签名对象。

要生成签名,只需调用其中一个签名方法:

final byte[] sign()
final int sign(byte[] outbuf, int offset, int len)

第一个方法以字节数组的形式返回签名结果。 第二个将签名结果存储在提供的缓冲区outbuf中,从offset开始。 len是分配给签名的outbuf中的字节数。 该方法返回实际存储的字节数。

对sign方法的调用会将签名对象重置为之前通过调用initSign进行初始化以进行签名的状态。 也就是说,如果需要,该对象将被重置并可用于生成具有相同私钥的另一个签名,通过新的调用来更新和签名。或者,可以对指定不同私钥的initSign或initVerify(初始化Signature对象以验证签名)进行新的调用。

验证

如果签名对象已被初始化以进行验证(如果它处于VERIFY状态),则它可以验证所谓的签名实际上是与其相关联的数据的真实签名。 为了开始这个过程,要被验证的数据(而不是签名本身)被提供给对象。 通过调用其中一种更新方法将数据传递给对象:

final void update(byte b)
final void update(byte[] data)
final void update(byte[] data, int off, int len)

应该调用更新方法,直到所有要验证的数据都被提供给Signature对象。 现在可以通过调用其中一种验证方法来验证签名:

final boolean verify(byte[] signature)

final boolean verify(byte[] signature, int offset, int length)

参数必须是包含签名的字节数组。 这个字节数组将保存以前调用返回的签名字节。

verify方法返回一个布尔值,指示编码签名是否是提供给更新方法的数据的真实签名。

对verify方法的调用通过调用initVerify将初始化后的签名对象重置为其状态。 也就是说,该对象被重置并可用于验证在initVerify调用中指定了公钥的身份的另一个签名。

或者,可以对initVerify进行一次新的调用,指定一个不同的公钥(初始化Signature对象以验证来自不同实体的签名)或initSign(初始化Signature对象以生成签名)。

 

 

 SealedObject类

这个类使程序员能够用密码算法创建对象并保护其机密性。

给定任何实现了java.io.Serializable接口的对象,可以使用密码算法创建一个封装原始对象的SealedObject,以序列化格式(即“深层复制”)封装原始对象,并封装(加密)其序列化内容 如AES,以保护其机密性。 加密的内容稍后可以被解密(使用正确的解密密钥的相应算法)并且解序列化,产生原始对象。

下面的代码段说明了一个典型的用法:为了密封一个对象,您需要从要被密封的对象和一个完全初始化的Cipher对象中创建一个SealedObject,它将加密序列化的对象内容。 在这个例子中,字符串“这是一个秘密”是使用AES算法密封的。 请注意,密封操作中可能使用的任何算法参数都存储在SealedObject内部:

    // create Cipher object
    // NOTE: sKey is assumed to refer to an already-generated
    // secret AES key.
    Cipher c = Cipher.getInstance("AES");
    c.init(Cipher.ENCRYPT_MODE, sKey);

    // do the sealing
    SealedObject so = new SealedObject("This is a secret", c);

密封的原始对象可以通过两种不同的方法恢复:

  • by using a Cipher object that has been initialized with the exact same algorithm, key, padding scheme, etc., that were used to seal the object:
    c.init(Cipher.DECRYPT_MODE, sKey);
    try {
        String s = (String)so.getObject(c);
    } catch (Exception e) {
        // do something
    };
    这种方法的优点是开封密封对象的一方不需要知道解密密钥。 例如,在一方用所需的解密密钥初始化密码对象之后,它可以将密码对象交给另一方,然后开封密封的对象。
  • 通过使用适当的解密密钥(由于AES是对称加密算法,我们使用相同的密钥来进行密封和解封):
    try {
        String s = (String)so.getObject(sKey);
    } catch (Exception e) {
        // do something
    };
    在这种方法中,getObject方法为相应的解密算法创建一个密码对象,并使用给定的解密密钥和存储在密封对象中的算法参数(如果有的话)对其初始化。 这种方法的优点是开封对象的一方不需要跟踪用于密封对象的参数(例如,IV)。

 

Mac类

与消息摘要类似,消息认证码(MAC)提供了一种方法来检查通过或存储在不可靠介质中的信息的完整性,但在计算中包括秘密密钥。 只有具有正确密钥的人才能够验证收到的消息。 典型地,在共享密钥的双方之间使用消息认证码以验证在这些方之间传输的信息。

Mac

基于密码散列函数的MAC机制被称为HMAC。 HMAC可以与任何密码散列函数(例如SHA-256)结合秘密共享密钥一起使用。

常用方法列表

创建Mac对象

Mac对象是通过使用Mac getInstance()静态工厂方法之一获得的。

初始化Mac对象

一个Mac对象总是用一个(秘密)密钥初始化的,并且可以根据底层的MAC算法用一组参数初始化。

您可以使用实现javax.crypto.SecretKey接口的任何(秘密)密钥对象来初始化您的Mac对象。 这可以是javax.crypto.KeyGenerator.generateKey()返回的对象,也可以是javax.crypto.KeyAgreement.generateSecret()返回的密钥协议协议的结果,也可以是javax.crypto的实例。spec.SecretKeySpec。

使用一些MAC算法,与用于初始化Mac对象的密钥对象关联的密钥算法无关紧要(SunJCE提供者的HMAC-MD5和HMAC-SHA1实现就是这种情况)。 然而,对于MAC算法来说,密钥算法确实很重要,如果使用具有不适当密钥算法的密钥对象,则会引发InvalidKeyException。

计算MAC

MAC可以一步(单部分操作)或多步(多部分操作)来计算。 如果事先不知道数据将要运行多长时间,或者数据太长而无法一次存储在内存中,则多部分操作非常有用。

要一步计算某些数据的MAC,请调用以下doFinal方法:

    public byte[] doFinal(byte[] input);

要多步骤计算某些数据的MAC,请调用以下update方法之一:

    public void update(byte input);

    public void update(byte[] input);

    public void update(byte[] input, int inputOffset, int inputLen);

多部分操作必须由上面的doFinal方法终止(如果仍有一些输入数据留给最后一步),或者通过以下doFinal方法之一(如果最后一步没有剩余输入数据):

    public byte[] doFinal();

    public void doFinal(byte[] output, int outOffset);

 

Key接口

到目前为止,我们已经将JCA的高层次使用集中在了Key以及如何生成/表示的细节上。 现在是把注意力转向Key的时候了。

java.security.Key接口是所有不透明密钥的顶层接口。 它定义了所有不透明密钥对象共享的功能。

秘钥是 基于某个规范(psck12或者x.509)组织数据格式,然后使用编码格式(der,pem)编码后的字符串。 

一个不透明的密钥表示就是你不能直接访问构成密钥的密钥材料。 换句话说:“不透明”使您能够有限地访问密钥 - 只有Key接口定义的三个方法(参见下面):getAlgorithm,getFormat和getEncoded。

这与透明表示形式相反,在透明表示形式中,可以通过相应规范类中定义的某个get方法单独访问每个关键材料值。

所有不透明的密钥有三个特征:

算法

该密钥的关键算法 关键算法通常是加密或非对称操作算法(如AES,DSA或RSA),它们将与这些算法和相关算法(如SHA256withRSA)一起工作。使用此方法可获得密钥算法的名称:

String getAlgorithm()

编码表单

在Java虚拟机之外需要密钥的标准表示形式时使用的密钥的外部编码形式,就像将密钥传输给其他方时一样。 密钥按照标准格式(如X.509或PKCS8)进行编码,并使用以下方法返回:

byte[] getEncoded()

格式

编码密钥格式的名称。 它是由该方法返回的:

String getFormat()

密钥一般通过密钥生成器(如KeyGeneratorKeyPairGenerator),证书,密钥规范(使用KeyFactory)或访问用于管理密钥的密钥库数据库的KeyStore实现获得。 可以使用KeyFactory以算法相关的方式解析编码密钥。

也可以使用CertificateFactory解析证书。

以下是在java.security.interfaces和javax.crypto.interfaces包中扩展Key接口的接口列表:

 

PublicKey和PrivateKey接口

PublicKey和PrivateKey接口(它们都扩展了Key接口)是无方法的接口,用于类型安全和类型标识。

KeyPair类

KeyPair类是密钥对(公钥和私钥)的简单持有者。 它有两个公共方法,一个用于返回私钥,另一个用于返回公钥:

PrivateKey getPrivate()
PublicKey getPublic()

密钥规范接口和秘钥

密钥对象和密钥规范(KeySpecs)是密钥数据的两种不同表示。 密码使用密钥对象来初始化他们的加密算法,但密钥可能需要转换成更便携的格式进行传输或存储。

密钥的透明表示意味着您可以通过相应规范类中定义的某个get方法单独访问每个关键字值。 例如,DSAPrivateKeySpec定义了getX,getP,getQ和getG方法来访问私钥x以及用于计算密钥的DSA算法参数:素数p,次数q和基数g。 如果密钥存储在硬件设备上,其规格可能包含有助于识别设备密钥的信息。

这种表示形式与密钥接口中定义的不透明表示形式相反,在这种表示形式中,您无法直接访问密钥材料字段。 换句话说,“不透明”的表示形式使得您可以有限地访问键 - 只有Key接口定义的三种方法:getAlgorithm,getFormat和getEncoded。

 

KeySpec接口

这个接口不包含方法或常量。 其唯一目的是为所有规范进行分组和提供类型安全。 所有密钥规范都必须实现这个接口。

KeySpec子类

就像Key接口一样,KeySpec接口也是类似的。

EncodedKeySpec类

这个抽象类(实现KeySpec接口)表示编码格式的公钥或私钥。 它的getEncoded方法返回编码密钥:

abstract byte[] getEncoded();

它的getFormat方法返回编码格式的名称:

abstract String getFormat();

PKCS8EncodedKeySpec类

该类是EncodedKeySpec的一个子类,它表示根据PKCS8标准中指定的格式对私钥进行DER编码。 它的getEncoded方法返回按照PKCS8标准编码的密钥字节。 它的getFormat方法返回字符串“PKCS#8”。

X509EncodedKeySpec类

这个类是EncodedKeySpec的一个子类,它表示公钥的DER编码,根据X.509标准中规定的格式。 它的getEncoded方法返回按照X.509标准编码的密钥字节。 它的getFormat方法返回字符串“X.509”。

 

生成器和工厂类

Java的新手和特别是和JCA API相关的有时并没有把握区分Generator和Factory之间的区别。

生成器 
生成器用于生成全新的对象。 发生器可以以算法相关或算法独立的方式进行初始化。 例如,要创建Diffie-Hellman(DH)密钥对,应用程序可以指定必要的P和G值,或者可以简单地使用适当的密钥长度对生成器进行初始化,生成器将选择适当的P和G值。 在这两种情况下,发生器将根据参数生成全新的密钥。

另一方面,工厂用于将数据从一个现有的对象类型转换为另一个。 例如,一个应用程序可能具有DH私钥的组件,并且可以将它们打包为KeySpec,但是需要将它们转换为KeyAgreement对象可以使用的PrivateKey对象,反之亦然。 或者他们可能拥有证书的字节数组,但需要使用CertificateFactory将其转换为X509Certificate对象。 应用程序使用工厂对象来进行转换。

 

KeyFactory类

KeyFactory类是一个引擎类,设计用于在不透明的加密密钥和密钥规范(底层密钥材料的透明表示)之间执行转换。

KeyFactory

密钥工厂是双向的。 它们允许您从给定的密钥规范(密钥材料)构建不透明的密钥对象,或者以合适的格式检索密钥对象的基础密钥材料。

同一个密钥可以存在多个兼容的密钥规范。 例如,DSA公钥可以由其组件y,p,q和g(参见java.security.spec.DSAPublicKeySpec)指定,也可以根据X.509标准使用其DER编码来指定

一个密钥工厂可以用来在兼容的密钥规范之间进行转换。 可以通过兼容密钥规范之间的转换来实现密钥解析,例如,当从X509EncodedKeySpec转换为DSAPublicKeySpec时,基本上将编码密钥解析为其组件。

创建KeyFactory

KeyFactory对象是通过使用KeyFactory的getInstance()静态工厂方法之一获得的。

在密钥规范和密钥对象之间进行转换

如果您有公钥的密钥规范,则可以使用generatePublic方法从规范中获取不透明的PublicKey对象:

PublicKey generatePublic(KeySpec keySpec)

同样,如果您拥有私钥的密钥规范,则可以使用generatePrivate方法从规范中获取不透明的PrivateKey对象:

PrivateKey generatePrivate(KeySpec keySpec)

在密钥对象和密钥规范之间进行转换

如果您有Key对象,则可以通过调用getKeySpec方法来获取相应的密钥规范对象:

KeySpec getKeySpec(Key key, Class keySpec)

keySpec标识应该返回密钥材料的规范类。 例如,它可以是DSAPublicKeySpec.class,用于指示应该在DSAPublicKeySpec类的实例中返回密钥材料。

 

SecretKeyFactory类

这个类代表一个秘密密钥的工厂。 与KeyFactory不同的是,javax.crypto.SecretKeyFactory对象仅在秘密(对称)键上运行,而java.security.KeyFactory对象则处理密钥对的公钥和私钥组件。

密钥

密钥工厂用于将密钥(java.security.Key类型的不透明密钥)转换为密钥规范(以合适的格式对基础密钥材料进行透明表示),反之亦然。

java.security.Key类型的对象(其中java.security.PublicKey,java.security.PrivateKey和javax.crypto.SecretKey是子类)是不透明的密钥对象,因为您无法知道它们是如何实现的。 底层的实现依赖于提供者,可能是基于软件或硬件的。 密钥工厂允许供应商提供他们自己的加密密钥的实现。

例如,如果您具有Diffie Hellman公钥的密钥规范(由公有值y,主模数p和基数g组成),并将相同的规范从不同的提供程序提供给Diffie-Hellman密钥工厂,则 结果PublicKey对象将很可能有不同的底层实现。

提供者应记录其密钥工厂支持的密钥规范。 例如,SunJCE提供者提供的DES密钥的SecretKeyFactory支持DESKeySpec作为DES密钥的透明表示,DES-EDE密钥的SecretKeyFactory支持DESedeKeySpec作为DES-EDE密钥的透明表示,而PBE的SecretKeyFactory支持PBEKeySpec作为 底层密码的透明表示。

以下是如何使用SecretKeyFactory将密钥数据转换为可用于后续密码操作的SecretKey对象的示例:

    // Note the following bytes are not realistic secret key data
    // bytes but are simply supplied as an illustration of using data
    // bytes (key material) you already have to build a DESedeKeySpec.

    byte[] desEdeKeyData = getKeyData();
    DESedeKeySpec desEdeKeySpec = new DESedeKeySpec(desEdeKeyData);
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
    SecretKey secretKey = keyFactory.generateSecret(desEdeKeySpec);

在这种情况下,SecretKey的底层实现基于KeyFactory的提供者。

使用相同的密钥材料创建功能上等价的SecretKey对象的另一种独立于提供者的方法是使用实现javax.crypto.SecretKey接口的javax.crypto.spec.SecretKeySpec类:

    byte[] aesKeyData = getKeyData();
    SecretKeySpec secretKey = new SecretKeySpec(aesKeyData, "AES");

创建SecretKeyFactory对象

SecretKeyFactory对象是通过使用SecretKeyFactory getInstance()静态工厂方法之一获得的。

在密钥对象和密钥规范之间转换

如果您拥有密钥的密钥规范,则可以使用generateSecret方法从规范中获取不透明的SecretKey对象:

SecretKey generateSecret(KeySpec keySpec)

keySpec标识应该返回密钥材料的规范类。 例如,它可以是DESKeySpec.class,以指示密钥材料应该在DESKeySpec类的实例中返回。

在密钥对象和密钥规范之间转换

如果您有密钥对象,则可以通过调用getKeySpec方法来获取相应的密钥规范对象:

KeySpec getKeySpec(Key key, Class keySpec)

keySpec标识应该返回密钥材料的规范类。 例如,它可以是DESKeySpec.class,以指示密钥材料应该在DESKeySpec类的实例中返回。

KeyPairGenerator类

KeyPairGenerator类是用于生成公钥和私钥对的引擎类。

密钥对生成器

有两种方法来生成密钥对:以独立于算法的方式,以特定于算法的方式。 两者之间的唯一区别是对象的初始化。

创建KeyPairGenerator

所有密钥对生成都以KeyPairGenerator开始。 KeyPairGenerator对象是通过使用KeyPairGenerator getInstance()静态工厂方法之一获得的。

初始化KeyPairGenerator

用于特定算法的密钥对生成器创建可用于该算法的公钥/私钥对。 它还将算法特定的参数与每个生成的密钥相关联。

密钥对生成器在生成密钥之前需要进行初始化。 在大多数情况下,独立于算法的初始化就足够了。 但在其他情况下,可以使用算法特定的初始化。

算法独立初始化

所有的密钥对生成器都共享一个密钥的概念和一个随机的来源。 对于不同的算法,密钥大小的解释是不同的。 例如,在DSA算法的情况下,密钥大小对应于模数的长度。 (有关特定算法的密钥大小的信息,请参阅标准名称文档。)

初始化方法需要两个普遍共享的参数类型:

void initialize(int keysize, SecureRandom random)

另一个初始化方法只需要一个keysize参数; 它使用系统提供的随机来源:

void initialize(int keysize)

由于在您调用上述与算法无关的初始化方法时没有指定其他参数,因此提供程序应该如何处理与每个密钥关联的算法特定参数(如果有)。

如果算法是“DSA”算法,并且模数大小(密钥大小)是512,768或1024,那么SUN提供程序使用一组预先计算的p,q和g参数值。 如果模数大小不是以上值之一,则SUN提供程序会创建一组新的参数。 其他提供者可能具有预先计算的参数集,不仅仅是上面提到的三个模量大小。 还有一些可能根本没有预先计算的参数列表,而是总是创建新的参数集。

特定于算法的初始化

对于已经存在一组算法特定参数的情况(例如DSA中的“社区参数”),有两个具有AlgorithmParameterSpec参数的初始化方法。 一个也有一个SecureRandom参数,而随机性的来源是系统为另一个提供的:

void initialize(AlgorithmParameterSpec params, SecureRandom random)

void initialize(AlgorithmParameterSpec params)

 

生成密钥对

无论初始化(和算法)如何,生成密钥对的过程总是相同的。 您始终从KeyPairGenerator调用以下方法:

KeyPair generateKeyPair()

多次调用generateKeyPair将产生不同的密钥对。

KeyGenerator类

密钥生成器用于为对称算法生成密钥。

密钥生成器

创建KeyGenerator

KeyGenerator对象是通过使用KeyGenerator getInstance()静态工厂方法之一获得的。

初始化KeyGenerator对象

用于特定对称密钥算法的密钥生成器创建可用于该算法的对称密钥。 它还将算法特定的参数(如果有的话)与生成的密钥相关联。

有两种方法来生成密钥:以独立于算法的方式,以特定于算法的方式。 两者之间唯一的区别是对象的初始化:

  • 算法独立初始化 
    所有的密钥生成器都共享一个密钥的概念和一个随机的来源。 有一个init方法使用这两个普遍共享类型的参数。 还有一个只需要一个密钥大小的参数,并使用系统提供的随机源,以及只是一个随机源:
    public void init(SecureRandom random);

    public void init(int keysize);

    public void init(int keysize, SecureRandom random);
  • 特定于算法的初始化 
    对于已经存在一组特定于算法的参数的情况,有两个具有AlgorithmParameterSpec参数的init方法。 一个也有一个SecureRandom参数,而随机性的来源是系统为另一个提供的:
    public void init(AlgorithmParameterSpec params);

    public void init(AlgorithmParameterSpec params, SecureRandom random);

如果客户端没有明确初始化KeyGenerator(通过调用init方法),则每个提供者都必须提供(并记录)一个默认的初始化。

创建密钥

以下方法生成一个密钥:

    public SecretKey generateKey();

 

 

KeyAgreement类

密钥协议是两方或多方可以建立相同密码密钥而不必交换任何秘密信息的协议。

密钥交换

各方用自己的私钥初始化密钥协商对象,然后输入参与通信的各方的公钥。 在大多数情况下,只有两方,但Diffie-Hellman等算法允许多方(3个或更多)参与。 当所有的公钥都被输入时,每个KeyAgreement对象都会生成(同意)相同的密钥。

KeyAgreement类提供了密钥协议协议的功能。 建立共享密钥所涉及的密钥由密钥生成器(KeyPairGenerator或KeyGenerator)之一,KeyFactory或者密钥协商协议的中间阶段的结果创建。

创建KeyAgreement对象

参与密钥协议的每一方都必须创建一个KeyAgreement对象。 KeyAgreement对象是通过使用KeyAgreement getInstance()静态工厂方法之一获得的。

初始化KeyAgreement

您使用您的私人信息初始化KeyAgreement对象。 在Diffie-Hellman的情况下,你用你的Diffie-Hellman私钥初始化它。 额外的初始化信息可能包含一个随机源和/或一组算法参数。 请注意,如果所请求的密钥协商算法需要指定算法参数,并且只有一个密钥,但没有提供参数来初始化KeyAgreement对象,则密钥必须包含所需的算法参数。 (例如,Diffie-Hellman算法使用质数模p和基生成器g作为其参数。)

要初始化一个KeyAgreement对象,调用它的一个init方法:

    public void init(Key key);

    public void init(Key key, SecureRandom random);

    public void init(Key key, AlgorithmParameterSpec params);

    public void init(Key key, AlgorithmParameterSpec params, SecureRandom random);

执行密钥协商阶段

每个密钥协议协议都由许多阶段组成,这些阶段需要由密钥协议中涉及的每一方执行。

要执行密钥协议中的下一个阶段,请调用doPhase方法:

    public Key doPhase(Key key, boolean lastPhase);

key参数包含该阶段要处理的密钥字节。 在大多数情况下,这是密钥协议中涉及的其中一方的公钥,或者是上一阶段产生的中间密钥。 doPhase可能会返回一个中间密钥,您可能必须将其发送给此密钥协议的其他方,以便他们可以在后续阶段处理它。

lastPhase参数指定要执行的阶段是否是密钥协议中的最后一个阶段:值为FALSE表示这不是密钥协议的最后阶段(有更多阶段需要遵循),并且值 TRUE表示这是密钥协议的最后阶段,密钥协商完成,即generateSecret可以被调用。

双方Diffie-Hellman的例子中,你可以调用doPhase一次,lastPhase设置为TRUE。 在三方之间的Diffie-Hellman示例中,您可以调用doPhase两次:第一次将lastPhase设置为FALSE,第二次将lastPhase设置为TRUE。

生成共享密钥

在每一方执行了所有需要的密钥协商阶段之后,它可以通过调用一个generateSecret方法来计算共享密钥:

    public byte[] generateSecret();

    public int generateSecret(byte[] sharedSecret, int offset);

    public SecretKey generateSecret(String algorithm);

 

密钥管理

称为“密钥库”的数据库可用于管理密钥和证书的存储库。 (证书是来自一个实体的数字签名声明,表示某个其他实体的公钥具有特定的价值。)

Keystore位置

用户密钥库默认存储在用户主目录中名为.keystore的文件中,由“user.home”系统属性确定。 在Solaris系统上,“user.home”默认为用户的主目录。 在Win32系统上,给定用户名uName,“user.home”默认为:

  • C:\Winnt\Profiles\uName on multi-user Windows NT systems
  • C:\Windows\Profiles\uName on multi-user Windows 95/98/2000 systems
  • C:\Windows on single-user Windows 95/98/2000 systems

当然,密钥库文件可以根据需要进行定位。 在某些环境中,可能存在多个密钥库。 例如,在JSSE(SSL / TLS)中,一个密钥库可能包含用户的私钥,而另一个可能包含用于建立信任关系的证书。

除了用户的密钥仓库以外,JDK还维护一个系统范围的密钥仓库,用于存储来自各种证书颁发机构(CA)的可信证书。 这些CA证书可以用来帮助做出信任决定。 例如,在SSL / TLS中,当SunJSSE提供者被呈现来自远程对等体的证书时,缺省的信任管理者将查询:

  • Solaris, Linux, or Mac OS X: /lib/ext/cacerts
  • Windows: \lib\ext\cacerts

文件来确定连接是否被信任。 应用程序可以设置和使用自己的密钥库,甚至可以使用上述的用户密钥库,而不是使用系统范围的cacerts密钥库。

Keystore实现

KeyStore类提供了定义良好的接口来访问和修改密钥库中的信息。 有可能存在多个不同的具体实现,其中每个实现都是针对特定类型的密钥库的实现。

应用程序可以使用KeyStore类中的getInstance工厂方法,从不同的提供者中选择不同类型的密钥库实现。 密钥库类型定义密钥库信息的存储和数据格式,以及用于保护密钥库中的私钥和密钥库本身的完整性的算法。 不同类型的密钥库实现不兼容。

推荐的keystore实现是“pkcs12”。 这是基于RSA PKCS12个人信息交换语法标准的跨平台密钥库。 此标准主要用于存储或传输用户的私钥,证书和其他秘密。 任意属性可以与PKCS12密钥库中的单个条目相关联。

注:密钥库类型标识不区分大小写。 例如,“jks”将被视为与“JKS”相同。

 

KeyStore类

KeyStore类是一个引擎类,提供良好定义的接口来访问和修改密钥库中的信息。

keyStore

这个类表示内存中的密钥和证书集合。 KeyStore管理两种类型的条目:

Key Entry

这种类型的密钥库条目保存非常敏感的密码密钥信息,这些密钥信息以受保护的格式存储以防止未经授权的访问。 典型地,存储在这种类型的条目中的密钥是秘密密钥或伴随着认证相应的公共密钥的证书链的私钥。

给定实体使用私钥和证书链来使用数字签名进行自我认证。 例如,软件分发组织对JAR文件进行数字签名,作为发布和/或许可软件的一部分。

Trusted Certificate Entry

这种类型的条目包含属于另一方的单个公钥证书。 它被称为可信证书,因为密钥库所有者相信证书中的公钥确实属于由证书的主体(所有者)标识的身份。

这种类型的条目可以用来认证其他方。

密钥库中的每个条目都由“别名”字符串标识。 在私钥及其相关证书链的情况下,这些字符串区分实体可以对其自身进行验证的不同方式。 例如,实体可以使用不同的证书颁发机构或使用不同的公钥算法来验证自己。

密钥库是否是持久的,以及密钥库使用的机制是否持久,这里没有指定。 这个约定允许使用各种技术来保护敏感(例如私人或秘密)密钥。 智能卡或其他集成密码引擎(SafeKeyper)是一种选择,并且也可以使用诸如文件的更简单的机制(以各种格式)。

主要的KeyStore方法如下所述。

KeyStore创建

KeyStore对象是通过使用KeyStore getInstance()静态工厂方法之一获得的。

将特定的密钥库加载到内存中

在可以使用KeyStore对象之前,必须通过load方法将实际的密钥库数据加载到内存中:

final void load(InputStream stream, char[] password)

可选的password参数用于检查密钥库数据的完整性。 如果没有提供密码,则不执行完整性检查。

要创建一个空的密钥库,可以将null作为InputStream参数传递给load方法。

通过将DomainLoadStoreParameter传递给备用加载方法来加载DKS密钥库:

final void load(KeyStore.LoadStoreParameter param)

获取密钥库别名列表

所有密钥库条目都通过唯一的别名来访问。 别名方法返回密钥库中别名的枚举:

final Enumeration aliases()

确定密钥库条目类型

KeyStore类所述,密钥库中有两种不同类型的条目。 以下方法分别确定由给定别名指定的条目是密钥/证书还是受信任的证书条目:

final boolean isKeyEntry(String alias)
final boolean isCertificateEntry(String alias)

添加/设置/删除密钥库条目

setCertificateEntry方法将一个证书分配给指定的别名:

final void setCertificateEntry(String alias, Certificate cert)

如果别名不存在,则创建具有该别名的可信证书条目。 如果存在别名并标识可信证书条目,则与其关联的证书将由cert替换。

setKeyEntry方法添加(如果别名尚不存在)或设置键值条目:

final void setKeyEntry(String alias,
                       Key key,
                       char[] password,
                       Certificate[] chain)

final void setKeyEntry(String alias,
                       byte[] key,
                       Certificate[] chain)

在key作为字节数组的方法中,它是受保护格式的密钥的字节。 例如,在SUN提供程序提供的密钥库实现中,密钥字节数组需要包含一个受保护的私钥,该私钥被编码为PKCS8标准中定义的EncryptedPrivateKeyInfo。 在另一种方法中,密码是用于保护密钥的密码。

deleteEntry方法删除一个条目:

final void deleteEntry(String alias)

PKCS#12密钥库支持包含任意属性的条目。 使用java.security.PKCS12Attribute类来创建属性。 在创建新的密钥库条目时,使用接受属性的构造函数方法。 最后,使用以下方法将条目添加到密钥库:

final void setEntry(String alias, Entry entry, 
                    ProtectionParameter protParam)

从密钥库获取信息

getKey方法返回与给定别名关联的密钥。 密钥使用给定的密码恢复:

final Key getKey(String alias, char[] password)

以下方法分别返回与给定别名关联的证书或证书链:

final Certificate getCertificate(String alias)
final Certificate[] getCertificateChain(String alias)

您可以通过以下方式确定证书与给定证书匹配的第一个条目的名称(别名):

final String getCertificateAlias(Certificate cert)

PKCS#12密钥库支持包含任意属性的条目。 使用以下方法检索可能包含属性的条目:

final Entry getEntry(String alias, ProtectionParameter protParam)

然后使用KeyStore.Entry.getAttributes方法来提取这些属性,并使用KeyStore.Entry.Attribute接口的方法来检查它们。

保存KeyStore

内存中的密钥库可以通过存储方法保存:

final void store(OutputStream stream, char[] password)

密码用于计算密钥库数据的完整性校验和,并将其附加到密钥库数据。

通过将DomainLoadStoreParameter传递给替代存储方法来存储DKS密钥库:

final void store(KeyStore.LoadStoreParameter param)

Algorithm Parameters类

与Keys和Keyspec类似,算法的初始化参数由AlgorithmParameters或AlgorithmParameterSpecs表示。 根据使用情况,算法可以直接使用这些参数,或者可能需要将这些参数转换为更便携的格式以用于传输或存储。

一组参数的透明表示(通过AlgorithmParameterSpec)意味着您可以单独访问集合中的每个参数值。 您可以通过相应规范类中定义的某个get方法(例如,DSAParameterSpec定义getP,getQ和getG方法,分别访问p,q和g)来访问这些值。

相反,AlgorithmParameters类提供了一个不透明的表示形式,其中不能直接访问参数字段。 你只能得到与参数集相关的算法的名字(通过getAlgorithm)和参数集的某种编码(通过getEncoded)。

AlgorithmParameterSpec接口

AlgorithmParameterSpec是加密参数的透明规范的接口。 这个接口不包含方法或常量。 其唯一的目的是为所有参数规格进行分组(并提供类型安全性)。 所有的参数规格必须实现这个接口。

JDK javadoc中描述了java.security.spec和javax.crypto.spec包中的算法参数说明接口和类:

以下算法参数规范专门用于数字签名,作为JSR 105的一部分。

AlgorithmParameters类

AlgorithmParameters类是提供密码参数的不透明表示的引擎类。 您可以使用特定的AlgorithmParameterSpec对象初始化AlgorithmParameters类,或者通过以可识别的格式对参数进行编码。 您可以使用getParameterSpec方法检索结果规范(请参阅以下部分)。

创建AlgorithmParameters对象

AlgorithmParameters对象是通过使用AlgorithmParameters getInstance()静态工厂方法之一获得的。

初始化AlgorithmParameters

一旦AlgorithmParameters对象被实例化,它必须通过调用init初始化,使用适当的参数规范或参数编码:

void init(AlgorithmParameterSpec paramSpec)
void init(byte[] params)
void init(byte[] params, String format)

在这些init方法中,params是包含编码参数的数组,format是解码格式的名称。 在带有params参数但不带格式参数的init方法中,使用参数的主要解码格式。 如果存在参数的ASN.1规范,则主要的解码格式是ASN.1。

注意: AlgorithmParameters对象只能被初始化一次。 它们不可重用。

获取编码参数

AlgorithmParameters对象中表示的参数的字节编码可以通过调用getEncoded来获得:

byte[] getEncoded()

此方法返回主编码格式的参数。 如果存在这种类型参数的ASN.1规范,参数的主要编码格式是ASN.1。

如果您想要以指定的编码格式返回参数,请使用

byte[] getEncoded(String format)

如果格式为空,则使用参数的主要编码格式,就像其他getEncoded方法一样。

注: 在由SUN提供程序提供的默认AlgorithmParameters实现中,format参数当前被忽略。

将AlgorithmParameters对象转换为透明规范

算法参数的透明参数规范可以通过调用getParameterSpec从AlgorithmParameters对象获得:

AlgorithmParameterSpec getParameterSpec(Class paramSpec)

paramSpec标识了参数应该返回的规范类。 例如,规范类可以是DSAParameterSpec.class,以指示参数应该在DSAParameterSpec类的实例中返回。 (这个类在java.security.spec包中。)

AlgorithmParameterGenerator类

AlgorithmParameterGenerator类是一个引擎类,用于生成一组适用于特定算法的全新参数(该算法在创建AlgorithmParameterGenerator实例时指定)。 如果没有现有的一组算法参数,并且想从头开始生成,则使用此对象。

创建AlgorithmParameterGenerator对象

AlgorithmParameterGenerator对象通过使用AlgorithmParameterGenerator getInstance()静态工厂方法之一获得。

初始化AlgorithmParameterGenerator

AlgorithmParameterGenerator对象可以用两种不同的方式进行初始化:独立于算法的方式或特定于算法的方式。

独立于算法的方法使用所有参数生成器共享“大小”和随机源的概念。 对于不同的算法来说,大小的度量是所有算法参数所共有的,尽管它们的解释是不同的。 例如,在用于DSA算法的参数的情况下,“大小”对应于质量模数的大小,以位为单位。 (有关特定算法大小的信息,请参阅“标准名称”文档。)使用此方法时,算法特定的参数生成值(如果有的话)默认为某些标准值。 一个采用这两个普遍共享类型的参数的init方法:

void init(int size, SecureRandom random);

另一个init方法只接受一个大小参数,并使用系统提供的随机源:

void init(int size)

第三种方法使用特定于算法的语义初始化参数生成器对象,这些语义由AlgorithmParameterSpec对象中提供的一组算法特定的参数生成值表示:

void init(AlgorithmParameterSpec genParamSpec,
                          SecureRandom random)

void init(AlgorithmParameterSpec genParamSpec)

为了生成Diffie-Hellman系统参数,例如,参数生成值通常由质数的大小和随机指数的大小组成,二者均以位数指定。

生成Algorithm Parameters

一旦创建并初始化AlgorithmParameterGenerator对象,就可以使用generateParameters方法生成算法参数:

AlgorithmParameters generateParameters()

CertificateFactory类

CertificateFactory类是定义证书工厂功能的引擎类,用于从其编码生成证书和证书吊销列表(CRL)对象。

X.509的证书工厂必须返回作为java.security.cert.X509Certificate实例的证书和作为java.security.cert.X509CRL实例的CRL。

创建CertificateFactory对象

CertificateFactory对象是通过使用getInstance()静态工厂方法之一获得的。

生成Certificate

要生成证书对象并使用从输入流读取的数据进行初始化,请使用generateCertificate方法:

final Certificate generateCertificate(InputStream inStream)

要返回从给定输入流中读取的证书(可能为空)的集合视图,请使用generateCertificates方法:

final Collection generateCertificates(InputStream inStream)

生成CRL

要生成证书吊销列表(CRL)对象并使用从输入流中读取的数据进行初始化,请使用generateCRL方法:

final CRL generateCRL(InputStream inStream)

要返回从给定输入流读取的CRL的(可能是空的)集合视图,请使用generateCRLs方法:

final Collection generateCRLs(InputStream inStream)

生成CertPath

PKIX的证书路径生成器和验证器由Internet X.509公钥基础结构证书和CRL配置文件RFC 3280定义。

用于从Collection和LDAP目录中检索证书和CRL的证书存储实现(使用PKIX LDAP V2架构)也可以从IETF以RFC 2587形式获得。

要生成CertPath对象并使用从输入流中读取的数据对其进行初始化,请使用以下一种generateCertPath方法(带或不带指定要用于数据的编码):

final CertPath generateCertPath(InputStream inStream)

final CertPath generateCertPath(InputStream inStream,
                                String encoding)

要生成CertPath对象并使用证书列表对其进行初始化,请使用以下方法:

final CertPath generateCertPath(List certificates)

要检索此证书工厂支持的CertPath编码列表,可以调用getCertPathEncodings方法:

final Iterator getCertPathEncodings()

默认编码将首先列出。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值