

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 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 | 永久金鑰，會跨叢集中的所有 HSM 進行複寫並包含在備份中。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 映射](https://devdocs.io/openjdk~8/java/util/map)的物件，您可以使用它來設定金鑰物件的屬性值。`CloudHsmKeyAttributesMap` 函數的方法類似於用於 Java 映射處理的方法。

若要設定屬性的自訂值，您有兩個選項：
+ 使用下表中列出的方法
+ 使用本文稍後示範的產生器模式

屬性映射物件支援以下列方法設定屬性：


****  

| 作業 | 傳回值 | `CloudHSMKeyAttributesMap` 方法 | 
| --- | --- | --- | 
| 獲取現有金鑰的金鑰屬性的值 | 物件 (包含值) 或 null |  **get**(keyAttribute)  | 
| 填入一個金鑰屬性的值  | 與金鑰屬性相關聯的先前值，如果金鑰屬性沒有映射，則為 null |  **put**(keyAttribute, value)  | 
| 填入多個金鑰屬性的值 | N/A |  **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) 封存和 GitHub 上的[範例](https://github.com/aws-samples/aws-cloudhsm-jce-examples/blob/master/src/main/java/com/amazonaws/cloudhsm/examples/CustomKeyAttributesRunner.java)。若要瀏覽 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) | 
| 秘密 | 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);
```