

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# AWS CloudHSM 客户端 SDK 3 支持的 Java 密钥属性
<a name="java-lib-attributes"></a>

本主题介绍如何使用 Java 库版本 3.1 的专有扩展来设置 AWS CloudHSM 客户端 SDK 3 的关键属性。使用此扩展可在以下操作期间设置受支持的密钥属性及其值：
+ 密钥生成
+ 密钥导入
+ 密钥解开包装

**注意**  
用于设置自定义密钥属性的扩展是一项可选功能。如果您已有适用于 Java 库版本 3.0 的代码，则无需修改该代码。您创建的密钥仍将包含与以前相同的属性。

**Topics**
+ [了解属性](#java-understanding-attributes)
+ [支持的 属性](#java-attributes)
+ [设置密钥的属性](#java-setting-attributes)
+ [组合起来](#java-attributes-summary)

## 了解属性
<a name="java-understanding-attributes"></a>

可以使用密钥属性指定允许对密钥对象（包括公有密钥或私有密钥）执行哪些操作。可以在创建密钥对象的过程中定义密钥属性和值。

但是，Java Cryptography Extension (JCE) 不指定如何设置密钥属性值，因此，默认情况下允许执行大多数操作。相比之下，PKCS \$111 标准定义了一组具有更受限的默认值的综合属性。从 Java 库版本 3.1 开始，CloudHSM 提供了专有扩展，使您能够为常用属性设置更受限的值。

## 支持的 属性
<a name="java-attributes"></a>

可以为下表中列出的属性设置值。作为最佳实践，仅为应受限的属性设置值。如果您未指定值，CloudHSM 将使用下表中指定的默认值。默认值列中的空单元格表示未向该属性分配特定的默认值。


****  

| 属性 | 默认值 | 注意 | 
| --- | --- | --- | 
|  | 对称密钥 | 密钥对中的公有密钥 | 密钥对中的私有密钥 |  | 
| CKA\$1TOKEN | FALSE | FALSE | FALSE | 永久密钥，可在集群 HSMs 中的所有密钥中复制并包含在备份中。CKA\$1TOKEN = FALSE 表示一个会话密钥，该密钥仅加载到一个 HSM 上，并且系统会在与 HSM 的连接断开时自动将其擦除。 | 
| CKA\$1LABEL |   |  |  | 用户定义的字符串。您可以通过它轻松识别 HSM 上的密钥。 | 
| CKA\$1EXTRACTABLE | TRUE |  | TRUE | True 表示可从 HSM 中导出此密钥。 | 
| CKA\$1ENCRYPT | TRUE | TRUE |  | True 表示可使用密钥对任何缓冲区进行加密。 | 
| CKA\$1DECRYPT | TRUE |  | TRUE | True 表示可使用密钥对任何缓冲区进行解密。对于其 CKA\$1WRAP 设置为 true 的密钥，通常将此项设置为 FALSE。 | 
| CKA\$1WRAP | TRUE | TRUE |  | True 表示可使用密钥包装另一个密钥。对于私有密钥，通常将此项设置为 FALSE。 | 
| CKA\$1UNWRAP | TRUE |  | TRUE | True 表示可使用密钥解开包装（导入）另一个密钥。 | 
| CKA\$1SIGN | TRUE |  | TRUE | True 表示可使用密钥对消息摘要进行签名。对于已存档的公有密钥和私有密钥，此项通常设置为 FALSE。 | 
| CKA\$1VERIFY | TRUE | TRUE |  | True 表示可使用密钥验证签名。对于私有密钥，此项通常设置为 FALSE。 | 
| CKA\$1PRIVATE | TRUE | TRUE | TRUE | True 表示用户在通过身份验证之前将无法访问密钥。为了清楚起见，用户在通过身份验证之前将无法访问 CloudHSM 上的任何密钥，即使此属性设置为 FALSE 也是如此。 | 

**注意**  
您将获得对 PKCS \$111 库中属性的更广泛支持。有关更多信息，请参阅[支持的 PKCS \$111 属性](pkcs11-attributes.md)。

## 设置密钥的属性
<a name="java-setting-attributes"></a>

`CloudHsmKeyAttributesMap` 是一个类似于 [Java Map](https://devdocs.io/openjdk~8/java/util/map) 的对象，可以使用它设置密钥对象的属性值。`CloudHsmKeyAttributesMap` 函数的方法与用于 Java 映射操作的方法类似。

可以通过下面两种方式为属性设置自定义值：
+ 使用下表中列出的方法
+ 使用本文档后面演示的生成器模式

属性映射对象支持通过以下方法来设置属性：


****  

| 操作 | 返回值 | `CloudHSMKeyAttributesMap` 方法 | 
| --- | --- | --- | 
| 获取现有密钥的密钥属性值 | 对象（包含值）或 null |  **get**(keyAttribute)  | 
| 填充一个密钥属性的值  | 与密钥属性关联的上一个值，或 null（如果没有密钥属性的映射） |  **put**(keyAttribute, value)  | 
| 填充多个密钥属性的值 | 不适用 |  **putall** () keyAttributesMap  | 
| 从属性映射中删除密钥/值对 |  与密钥属性关联的上一个值，或 *null*（如果没有密钥属性的映射）  |  **remove**(keyAttribute)  | 

**注意**  
未明确指定的任何属性都将设置为 [支持的 属性](#java-attributes) 中前面的表中列出的默认值。

### 生成器模式示例
<a name="java-setting-attributes-builder-example"></a>

开发人员通常会发现，可以通过生成器模式更轻松地使用类。例如：

```
import com.amazonaws.cloudhsm.CloudHsmKeyAttributes;
import com.amazonaws.cloudhsm.CloudHsmKeyAttributesMap;
import com.amazonaws.cloudhsm.CloudHsmKeyPairAttributesMap;

CloudHsmKeyAttributesMap keyAttributesSessionDecryptionKey = 
   new CloudHsmKeyAttributesMap.Builder()
      .put(CloudHsmKeyAttributes.CKA_LABEL, "ExtractableSessionKeyEncryptDecrypt")
      .put(CloudHsmKeyAttributes.CKA_WRAP, false)
      .put(CloudHsmKeyAttributes.CKA_UNWRAP, false)
      .put(CloudHsmKeyAttributes.CKA_SIGN, false)
      .put(CloudHsmKeyAttributes.CKA_VERIFY, false)
      .build();

CloudHsmKeyAttributesMap keyAttributesTokenWrappingKey = 
   new CloudHsmKeyAttributesMap.Builder()
      .put(CloudHsmKeyAttributes.CKA_LABEL, "TokenWrappingKey")
      .put(CloudHsmKeyAttributes.CKA_TOKEN, true)
      .put(CloudHsmKeyAttributes.CKA_ENCRYPT, false)
      .put(CloudHsmKeyAttributes.CKA_DECRYPT, false)
      .put(CloudHsmKeyAttributes.CKA_SIGN, false)
      .put(CloudHsmKeyAttributes.CKA_VERIFY, false)
      .build();
```

开发人员还可以利用预定义的属性集来轻松地实施密钥模板中的最佳实践。例如：

```
//best practice template for wrapping keys

CloudHsmKeyAttributesMap commonKeyAttrs = new CloudHsmKeyAttributesMap.Builder()
    .put(CloudHsmKeyAttributes.CKA_EXTRACTABLE, false)
    .put(CloudHsmKeyAttributes.CKA_DECRYPT, false)
    .build();

// initialize a new instance of CloudHsmKeyAttributesMap by copying commonKeyAttrs
// but with an appropriate label

CloudHsmKeyAttributesMap firstKeyAttrs = new CloudHsmKeyAttributesMap(commonKeyAttrs);
firstKeyAttrs.put(CloudHsmKeyAttributes.CKA_LABEL, "key label");

// alternatively, putAll() will overwrite existing values to enforce conformance

CloudHsmKeyAttributesMap secondKeyAttrs = new CloudHsmKeyAttributesMap();
secondKeyAttrs.put(CloudHsmKeyAttributes.CKA_DECRYPT, true);
secondKeyAttrs.put(CloudHsmKeyAttributes.CKA_ENCRYPT, true);
secondKeyAttrs.put(CloudHsmKeyAttributes.CKA_LABEL, “safe wrapping key”);
secondKeyAttrs.putAll(commonKeyAttrs); // will overwrite CKA_DECRYPT to be FALSE
```

### 设置密钥对的属性
<a name="java-setting-attributes-key-pair"></a>

使用 Java 类 `CloudHsmKeyPairAttributesMap` 处理密钥对的密钥属性。`CloudHsmKeyPairAttributesMap` 封装了两个 `CloudHsmKeyAttributesMap` 对象；一个用于公有密钥，另一个用于私有密钥。

要分别为公有密钥和私有密钥设置单个属性，您可以对该密钥的相应 `CloudHsmKeyAttributes` 映射对象使用 `put()` 方法。使用 `getPublic()` 方法可检索公有密钥的属性映射，使用 `getPrivate()` 可检索私有密钥的属性映射。使用 `putAll()` 填充公有密钥和私有密钥对的多个密钥属性的值，并将密钥对属性映射作为其参数。

### 生成器模式示例
<a name="java-setting-attributes-key-pair-builder-example"></a>

开发人员通常会发现，可以通过生成器模式更轻松地设置密钥属性。例如：

```
import com.amazonaws.cloudhsm.CloudHsmKeyAttributes;
import com.amazonaws.cloudhsm.CloudHsmKeyAttributesMap;
import com.amazonaws.cloudhsm.CloudHsmKeyPairAttributesMap;

//specify attributes up-front 
CloudHsmKeyAttributesMap keyAttributes = 
    new CloudHsmKeyAttributesMap.Builder()
        .put(CloudHsmKeyAttributes.CKA_SIGN, false)
        .put(CloudHsmKeyAttributes.CKA_LABEL, "PublicCertSerial12345")
        .build();

CloudHsmKeyPairAttributesMap keyPairAttributes =
    new CloudHsmKeyPairAttributesMap.Builder()
        .withPublic(keyAttributes)
        .withPrivate(
            new CloudHsmKeyAttributesMap.Builder() //or specify them inline 
                .put(CloudHsmKeyAttributes.CKA_LABEL, "PrivateCertSerial12345")
                .put (CloudHSMKeyAttributes.CKA_WRAP, FALSE)
                .build()
        )
        .build();
```

**注意**  
有关此专有扩展的更多信息，请参阅 [Javadoc](https://s3.amazonaws.com/cloudhsmv2-software/CloudHsmClient/Docs/CloudHsm_CustomKeyAttributes_Javadoc.zip) 存档和上的[示例](https://github.com/aws-samples/aws-cloudhsm-jce-examples/blob/master/src/main/java/com/amazonaws/cloudhsm/examples/CustomKeyAttributesRunner.java)。 GitHub要浏览 Javadoc，请下载并展开档案。

## 组合起来
<a name="java-attributes-summary"></a>

要使用密钥操作指定密钥属性，请执行以下步骤：

1. 实例化对称密钥的 `CloudHsmKeyAttributesMap` 或密钥对的 `CloudHsmKeyPairAttributesMap`。

1. 使用所需的密钥属性和值来定义步骤 1 中的属性对象。

1. 实例化与特定密钥类型对应的 `Cavium*ParameterSpec` 类，并将此配置的属性对象传入其构造函数。

1. 将此 `Cavium*ParameterSpec` 对象传递给相应的加密类或方法。

下表包含支持自定义密钥属性的 `Cavium*ParameterSpec` 类和方法以供您参考。


****  

| 密钥类型 | 参数规范类 | 示例构造函数 | 
| --- | --- | --- | 
| 基本类 | CaviumKeyGenAlgorithmParameterSpec | CaviumKeyGenAlgorithmParameterSpec(CloudHsmKeyAttributesMap keyAttributesMap) | 
| DES | CaviumDESKeyGenParameterSpec | CaviumDESKeyGenParameterSpec(int keySize, byte[] iv, CloudHsmKeyAttributesMap keyAttributesMap) | 
| RSA | CaviumRSAKeyGenParameterSpec | CaviumRSAKeyGenParameterSpec(int keysize, BigInteger publicExponent, CloudHsmKeyPairAttributesMap keyPairAttributesMap) | 
| Secret | CaviumGenericSecretKeyGenParameterSpec | CaviumGenericSecretKeyGenParameterSpec(int size, CloudHsmKeyAttributesMap keyAttributesMap) | 
| AES | CaviumAESKeyGenParameterSpec | CaviumAESKeyGenParameterSpec(int keySize, byte[] iv, CloudHsmKeyAttributesMap keyAttributesMap) | 
| EC | CaviumECGenParameterSpec | CaviumECGenParameterSpec(String stdName, CloudHsmKeyPairAttributesMap keyPairAttributesMap) | 

### 示例代码：生成和包装密钥
<a name="example-generate-wrap-key"></a>

这些简短的代码示例演示了两项不同的操作的步骤：密钥生成和密钥包装：

```
// Set up the desired key attributes

KeyGenerator keyGen = KeyGenerator.getInstance("AES", "Cavium");
CaviumAESKeyGenParameterSpec keyAttributes = new CaviumAESKeyGenParameterSpec(
    256,
    new CloudHsmKeyAttributesMap.Builder()
        .put(CloudHsmKeyAttributes.CKA_LABEL, "MyPersistentAESKey")
        .put(CloudHsmKeyAttributes.CKA_EXTRACTABLE, true)
        .put(CloudHsmKeyAttributes.CKA_TOKEN, true)
        .build()
);

// Assume we already have a handle to the myWrappingKey
// Assume we already have the wrappedBytes to unwrap

// Unwrap a key using Custom Key Attributes

CaviumUnwrapParameterSpec unwrapSpec = new CaviumUnwrapParameterSpec(myInitializationVector, keyAttributes);

Cipher unwrapCipher = Cipher.getInstance("AESWrap", "Cavium");
unwrapCipher.init(Cipher.UNWRAP_MODE, myWrappingKey, unwrapSpec);
Key unwrappedKey = unwrapCipher.unwrap(wrappedBytes, "AES", Cipher.SECRET_KEY);
```