すべてのプロダクト
Search
ドキュメントセンター

Key Management Service:非対称キーにキーマテリアルをインポートする

最終更新日:Nov 09, 2025

外部キーマテリアルオリジンで非対称キーを作成する場合、Key Management Service (KMS) はキーマテリアルを生成しません。代わりに、独自のキーマテリアルをインポートする必要があります。このトピックでは、非対称キーにキーマテリアルをインポートする方法について説明します。

重要

お使いのソフトウェアキー管理インスタンスまたはハードウェアキー管理インスタンスがキーマテリアルのインポートをサポートしていない場合、またはキーマテリアルのインポート時にエラーが発生した場合は、Alibaba Cloud テクニカルサポートに連絡してインスタンスをアップグレードしてください。

概要

キーは KMS の基本的なリソースです。キーは、キー ID、キーステータスなどの基本メタデータ、およびキーマテリアルで構成されます。キーを作成するときに、KMS にキーマテリアルを生成させるか、外部ソースのキーマテリアルを使用するかを選択できます。外部ソースを選択した場合は、外部キーマテリアルをキーにインポートする必要があります。この機能は、Bring Your Own Key (BYOK) とも呼ばれます。

次の表に、キーマテリアルのインポートをサポートする KMS キー管理タイプを示します。キー管理タイプの詳細については、「キー管理タイプとキー仕様」をご参照ください。

  • Check mark: 対応するキーマテリアルのインポートがサポートされていることを示します。

  • Cross mark: 対応するキーマテリアルのインポートがサポートされていないことを示します。

キー管理タイプ

対称キーマテリアルのインポート

非対称キーマテリアルのインポート

デフォルトキー

  • カスタマーマスターキー: √

  • サービスキー: ×

  • カスタマーマスターキー: ×

  • サービスキー: ×

ソフトウェア保護キー

ハードウェア保護キー

×

使用上の注意

  • キーにキーマテリアルを初めてインポートすると、キーはそのキーマテリアルに永続的に関連付けられます。異なるキーマテリアルをキーにインポートすることはできません。

  • 必要に応じて、同じキーマテリアルを KMS キーに再インポートできます。異なるキーマテリアルを KMS キーにインポートすることはできません。

  • キーのマテリアルが有効期限切れまたは削除された場合、同じキーマテリアルを再インポートしてキーを再び利用可能にすることができます。キーマテリアルをインポートした後は、エクスポートできません。キーマテリアルは安全な場所に保管してください。

前提条件

KMS インスタンスを購入し、有効化していること。詳細については、「KMS インスタンスの購入と有効化」をご参照ください。

KMS コンソールでのキーマテリアルのインポート

ステップ 1: 非対称キーの作成

キーマテリアルをインポートする前に、外部キーマテリアルオリジンを持つ非対称キーを作成する必要があります。

ソフトウェア保護キー

  1. KMS コンソールにログインします。上部のナビゲーションバーで、リージョンを選択します。左側のナビゲーションウィンドウで、リソース > キー管理 を選択します。

  2. キー タブで、インスタンス管理 ドロップダウンリストからソフトウェア管理の KMS インスタンスを選択し、キーを作成 をクリックします。

  3. キーを作成 パネルで、設定項目を設定し、[OK] をクリックします。

    設定項目

    説明

    キータイプ

    キーのタイプ。非対称キーを選択します。

    キー仕様

    キー使用

    キーの目的。有効な値:

    • 暗号化/復号: データの暗号化と復号。

    • 署名/検証: デジタル署名の生成と検証。

    キーのエイリアス

    キーのエイリアス。エイリアスには、文字、数字、アンダースコア (_)、ハイフン (-)、スラッシュ (/) を含めることができます。

    タグ

    キーに追加するタグ。タグを使用してキーを分類および管理します。各タグは、タグキーとタグ値で構成されるキーと値のペアです。

    説明
    • タグキーまたはタグ値は、最大 128 文字で、文字、数字、スラッシュ (/)、バックスラッシュ (\)、アンダースコア (_)、ハイフン (-)、ピリオド (.)、プラス記号 (+)、等号 (=)、コロン (:)、アットマーク (@)、およびスペースを含めることができます。

    • タグキーは aliyun または acs: で始めることはできません。

    • 各キーに最大 20 個のキーと値のペアを設定できます。

    Description

    キーの説明。

    Advanced Settings

    • ポリシー設定: 詳細については、「キーポリシーの概要」をご参照ください。

    • キーマテリアルソース: 外部 (キーマテリアルのインポート) を選択します。

      説明

      [外部キーマテリアルを使用することの意味を理解しています] を読んで選択します。

ハードウェア保護キー

  1. KMS コンソールにログインします。上部のナビゲーションバーで、リージョンを選択します。左側のナビゲーションウィンドウで、リソース > キー管理 を選択します。

  2. キー タブで、インスタンス管理 にハードウェアキー管理インスタンスを選択し、キーを作成 をクリックします。

  3. キーを作成 パネルで、パラメーターを設定し、[OK] をクリックします。

    設定項目

    説明

    キータイプ

    非対称キーを選択します。

    キー仕様

    キー使用

    キーの目的。有効な値:

    • 暗号化/復号: データを暗号化および復号します。

    • 署名/検証: デジタル署名を生成および検証します。

    キーのエイリアス

    キーのエイリアス。エイリアスには、文字、数字、アンダースコア (_)、ハイフン (-)、スラッシュ (/) を含めることができます。

    タグ

    キーに追加するタグ。タグを使用してキーを分類および管理できます。各タグは、タグキーとタグ値で構成されるキーと値のペアです。

    説明
    • タグキーまたはタグ値は、最大 128 文字で、文字、数字、スラッシュ (/)、バックスラッシュ (\)、アンダースコア (_)、ハイフン (-)、ピリオド (.)、プラス記号 (+)、等号 (=)、コロン (:)、アットマーク (@)、およびスペースを含めることができます。

    • タグキーは aliyun または acs: で始めることはできません。

    • 各キーに最大 20 個のキーと値のペアを設定できます。

    Description

    キーの説明。

    Advanced Settings

    • ポリシー設定: 詳細については、「キーポリシーの概要」をご参照ください。

    • キーマテリアルソース: 外部 (キーマテリアルのインポート) を選択します。

      説明

      [外部キーマテリアルを使用することの意味を理解しています] を読んで選択します。

ステップ 2: ラッピング公開鍵とインポートトークンのダウンロード

キーマテリアルをインポートするためのパラメーターには、ラッピング公開鍵とインポートトークンが含まれます。ラッピング公開鍵は、インポートプロセス中にキーマテリアルを保護するために暗号化します。インポートトークンは、キーマテリアルをインポートするために必要です。

  1. ターゲットキーを見つけ、操作 列の 詳細 をクリックします。キー詳細ページの キーマテリアル セクションで、インポートのパラメーターを取得 をクリックします。

  2. キー暗号化マテリアル ダイアログボックスで、パブリックキータイプ暗号化アルゴリズム を選択し、次へ をクリックします。

    キー管理タイプ

    キー仕様

    ラッピング公開鍵タイプ

    暗号化アルゴリズム

    ソフトウェア保護キー

    • RSA_2048

    • RSA_3072

    • EC_P256

    • EC_P256K

    RSA_2048

    RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD

    ハードウェア保護キー

    • RSA_2048

    • RSA_3072

    • RSA_4096

    • EC_P256

    • EC_P256K

    RSA_2048

    RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD

  3. ラッピング公開鍵とインポートトークンをダウンロードし、安全な場所に保管します。

    • パブリックキー形式:

      • DER形式: ダウンロードされたファイルのデフォルト名は publickey_******.bin です。

      • PEM形式: ダウンロードされたファイルのデフォルト名は publickey_******.pem です。

    • トークンのインポート: ダウンロードされたファイルのデフォルト名は token_******.txt です。

      重要
      • インポートトークンは 24 時間有効で、有効期間内に複数回使用できます。トークンの有効期限が切れた後は、新しいインポートトークンと公開鍵を取得する必要があります。

      • ラッピング公開鍵とインポートトークンは一緒に使用する必要があります。異なるダウンロードからのインポートトークンでラッピング公開鍵を使用することはできません。

ステップ 3: ラッピング公開鍵を使用してキーマテリアルを暗号化する

システム環境でキーマテリアルを生成し、暗号化します。次の表に、このプロセスで使用されるキーを示します。

キー

目的

プロバイダー

説明

ターゲット非対称キー (TAK)

インポートするターゲット非対称キー。

オンプレミスのキー管理インフラストラクチャ (KMI) やハードウェアセキュリティモジュール (HSM) などのシステム環境またはツール。

  • TAKpub: 公開鍵

  • TAKpriv: 秘密鍵

インポートラッピングキー (IWK)

TAK のインポートに使用される暗号鍵。

Alibaba Cloud KMS。

  • IWKpub: IWK の公開鍵

    説明

    IWKpub は、Key Management Service コンソールからダウンロードするラッピング公開鍵です。

  • IWKpriv: IWK の秘密鍵

エフェメラル対称キー (ESK)

TAKpriv を直接暗号化するエフェメラル対称キー。

TAK をエクスポートした後、ソース環境のシステムまたはツールを直ちに破棄します。

N/A

  1. ターゲット非対称秘密鍵 (TAKpriv) を作成します。キー仕様は、非対称キーを作成したときに選択したものと同じでなければなりません。すでに TAKpriv がある場合は、このステップをスキップしてください。

    説明

    TAKpriv 形式は、次の標準に準拠する必要があります: RSA 秘密鍵は RFC 3447 に基づいてエンコードされます。ECC 秘密鍵は RFC 5915 に基づいてエンコードされます。その後、キーは RFC 5208 に基づいて PKCS#8 形式にラップされます。

  2. ESK を作成します。

  3. インポートラッピング公開鍵 (IWKpub) を使用して ESK を暗号化します。これにより、ESK の暗号文 (Cipher(ESK)) が生成されます。

  4. ESK を使用して TAKpriv を暗号化します。これにより、ターゲット非対称秘密鍵の暗号文 (Cipher(TAKpriv)) が生成されます。

  5. 結果を Cipher(ESK)||Cipher(TAKpriv) 形式で組み立てて、暗号化されたキーマテリアルを取得します。

例: OpenSSL を使用して RSA_2048 アルゴリズム用のキーマテリアルを生成する

  1. RSA_2048 アルゴリズム用のターゲット非対称秘密鍵を作成し、秘密鍵を PKCS#8 形式に変換します。

    openssl genrsa -out TakPrivPkcs1.pem 2048
    openssl pkcs8 -topk8 -inform PEM -in TakPrivPkcs1.pem -outform der -nocrypt -out TakPrivPkcs8.bin
  2. AES_256 アルゴリズム用のエフェメラルキー (ESK) を作成します。

    openssl rand -out EskAes256.bin 32
  3. インポートラッピング公開鍵 (IWKpub) を使用して ESK を暗号化します。これにより、ESK の暗号文 (Cipher(ESK)) が生成されます。暗号化は RSAES-OAEP 標準に基づいて実行され、ハッシュアルゴリズムとして MGF1 と SHA256 が使用されます。

    openssl pkeyutl -encrypt -pubin -inkey PublicKey.pem  -in EskAes256.bin  -pkeyopt \
    rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256 -out \
    CipherEsk.bin
    説明

    PublicKey.pem を KMS コンソールからダウンロードした公開鍵ファイルの名前に置き換えます。

  4. ESK を使用して TAKpriv を暗号化します。これにより、ターゲット非対称秘密鍵の暗号文 (Cipher(TAKpriv)) が生成されます。暗号化モードは ECB、パディングモードは PKCS#7 Padding です。

    xxd -l 32  -c 32 -ps EskAes256.bin | xargs -I {} openssl enc  -aes-256-ecb -e  -K {} -in \ 
    TakPrivPkcs8.bin -nosalt -out CipherTakPriv.bin
  5. 結果を Cipher(ESK) || Cipher(TAKpriv) 形式で組み立ててから、Base64 エンコーディングを実行します。

    cat CipherEsk.bin CipherTakPriv.bin > EncryptedKeyMaterial.bin
    openssl enc -e -base64 -A -in EncryptedKeyMaterial.bin -out EncryptedKeyMaterial_base64.txt
    説明

    EncryptedKeyMaterial_base64.txt ファイルは、KMS にインポートするキーマテリアルファイルです。

ステップ 4: キーマテリアルのインポート

キー詳細ページで、キーマテリアルのインポート をクリックします。開いた ラップされたキーマテリアルのインポート ダイアログボックスで、パラメーターを設定し、[OK] をクリックします。

設定項目

説明

包まれたキーマテリアル

ステップ 3: ラッピング公開鍵を使用してキーマテリアルを暗号化するで生成されたキーマテリアルファイルをアップロードします。

トークンのインポート

ステップ 2: ラッピング公開鍵とインポートトークンのダウンロードでダウンロードしたインポートトークンファイルをアップロードします。

有効期限が切れたキーマテリアル

有効期限はありません を選択するか、有効期限を指定できます。

重要

キーマテリアルの有効期限を指定すると、KMS は有効期限に達したときにキーマテリアルを削除し、そのキーマテリアルは使用できなくなります。キーマテリアルを再利用したい場合は、同じキーマテリアルをキーに再インポートできます。

キーマテリアルをインポートすると、キーステータスが インポート待ち から 有効化 に変わります。

SDK を使用したキーマテリアルのインポート

Alibaba Cloud SDK を使用して、KMS で RSA および ECC アルゴリズムキーを作成し、キーマテリアルをインポートできます。以下は Java のサンプルコードです:

説明

Alibaba Cloud アカウントの AccessKey ペアは、すべての API 操作に対する権限を持っています。AccessKey ペアを使用して操作を実行することは、リスクの高い操作です。さらに、RAM ユーザーを使用して API 操作を呼び出すか、日常の O&M を実行します。AccessKey ID と AccessKey Secret をプロジェクトコードに保存しないことをお勧めします。保存すると、AccessKey ペアが漏洩し、アカウントに属するすべてのリソースのセキュリティが危険にさらされる可能性があります。

この例では、ID 認証を実装するために、AccessKey ペアが ALIBABA_CLOUD_ACCESS_KEY_ID および ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数に保存されています。

import java.security.InvalidAlgorithmParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.ECPrivateKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource.PSpecified;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

import com.aliyuncs.AcsRequest;
import com.aliyuncs.AcsResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.FormatType;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.kms.model.v20160120.CreateKeyRequest;
import com.aliyuncs.kms.model.v20160120.CreateKeyResponse;
import com.aliyuncs.kms.model.v20160120.GetParametersForImportRequest;
import com.aliyuncs.kms.model.v20160120.GetParametersForImportResponse;
import com.aliyuncs.kms.model.v20160120.ImportKeyMaterialRequest;
import com.aliyuncs.kms.model.v20160120.ImportKeyMaterialResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import org.apache.commons.lang3.tuple.Pair;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class BringYourOwnAsymmetricKeySample {
    static String regionId = "cn-hangzhou";
    static String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
    static String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
    static String dedicatedKmsInstanceId = "*** Provide your DedicatedKmsInstanceId ***";
    DefaultAcsClient kmsClient;
    private final String SM2PKE_SM4_ECB = "SM2PKE_SM4_ECB";
    private final String RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD = "RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD";
    private static Provider BC = new BouncyCastleProvider();
    private static X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1");
    private static ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
    static {
        java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    }

    public static void main(String[] args) {
        // KMS SDK を初期化します。
        DefaultAcsClient client = getClientForPublicEndpoint(regionId, accessKeyId, accessKeySecret);
        BringYourOwnAsymmetricKeySample sample = new BringYourOwnAsymmetricKeySample(client);

        // 外部 EC_SM2 キーを作成してインポートします。
        sample.doByok("EC_SM2", "EC_SM2", sample.SM2PKE_SM4_ECB, "SM4");
        // 外部 EC_P256 キーを作成してインポートします。
        sample.doByok("EC_P256", "RSA_2048", sample.RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD, "AES_256");
        // 外部 RSA キーを作成してインポートします。
        sample.doByok("RSA_2048", "RSA_2048", sample.RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD, "AES_256");
    }


    public static DefaultAcsClient getClientForPublicEndpoint(String regionId, String accessKeyId, String accessKeySecret) {
        /**
         * Aliyun クライアントを構築します:
         * RegionId、AccessKeyId、AccessKeySecret を設定します
         */
        IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
        DefaultAcsClient client = new DefaultAcsClient(profile);
        return client;
    }

    public BringYourOwnAsymmetricKeySample(DefaultAcsClient kmsClient) {
        this.kmsClient = kmsClient;
    }

    public void doByok(String targetKeySpec, String wrappingKeySpec, String wrappingAlgorithm, String ephemeralKeySpec) {
        try {
            // 外部 ECC キーを作成します。
            CreateKeyResponse.KeyMetadata keyMetadata = this.createExternalKeyInDkms(dedicatedKmsInstanceId, targetKeySpec, "SIGN/VERIFY");
            String keyId = keyMetadata.getKeyId();
            // キーマテリアルのインポートに使用されるパラメーターを取得します。
            GetParametersForImportResponse parametersForImportResponse = this.getParametersForImport(keyId, wrappingKeySpec,
                wrappingAlgorithm);
            String importToken = parametersForImportResponse.getImportToken();
            String publicKeyBase64 = parametersForImportResponse.getPublicKey();
            // ESK を作成します。
            byte[] ephemeralSymmetricKeyPlaintext = this.generateEphemeralSymmetricKey(ephemeralKeySpec);
            // TAK を作成します。
            byte[] targetAsymmetricKeyPlaintext = this.generateTargetAsymmetricKey(targetKeySpec);
            // IWK の公開鍵を使用して ESK を暗号化します。
            byte[] ephemeralSymmetricKeyCipher = this.encryptEphemeralSymmetricKey(publicKeyBase64,
                wrappingAlgorithm, ephemeralSymmetricKeyPlaintext);
            // ESK を使用して TAK を暗号化します。
            byte[] targetAsymmetricKeyCipher = this.encryptTargetAsymmetricKey(ephemeralSymmetricKeyPlaintext, targetAsymmetricKeyPlaintext,
                wrappingAlgorithm);
            // キーマテリアルを生成します。
            byte[] encryptedKeyMaterial = new byte[ephemeralSymmetricKeyCipher.length + targetAsymmetricKeyCipher.length];
            System.arraycopy(ephemeralSymmetricKeyCipher, 0, encryptedKeyMaterial, 0, ephemeralSymmetricKeyCipher.length);
            System.arraycopy(targetAsymmetricKeyCipher, 0, encryptedKeyMaterial, ephemeralSymmetricKeyCipher.length, targetAsymmetricKeyCipher.length);
            String encryptedKeyMaterialBase64 =  DatatypeConverter.printBase64Binary(encryptedKeyMaterial);
            // キーマテリアルをインポートします。
            this.importKeyMaterial(keyId, encryptedKeyMaterialBase64, importToken, 0L);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private GetParametersForImportResponse getParametersForImport(String keyId, String keySpec, String algorithm) throws Exception {
        GetParametersForImportRequest request = new GetParametersForImportRequest();
        request.setAcceptFormat(FormatType.JSON);
        request.setMethod(MethodType.POST);
        request.setProtocol(ProtocolType.HTTPS);
        request.setKeyId(keyId);
        request.setWrappingKeySpec(keySpec);
        request.setWrappingAlgorithm(algorithm);
        GetParametersForImportResponse resp;
        try {
            resp = this.getAcsResponseWithRetry(request);
        } catch (Exception e) {
            throw e;
        }
        return resp;
    }

    private CreateKeyResponse.KeyMetadata createExternalKeyInDkms(String dedicatedKmsInstance, String keySpec, String keyUsage) throws Exception {
        CreateKeyRequest request = new CreateKeyRequest();
        // 外部キーを作成します。
        request.setOrigin("EXTERNAL"); 
        request.setKeyStoreId(dedicatedKmsInstance);
        request.setKeySpec(keySpec);
        request.setKeyUsage(keyUsage);

        request.setProtocol(ProtocolType.HTTPS);
        request.setAcceptFormat(FormatType.JSON);
        request.setMethod(MethodType.POST);
        CreateKeyResponse.KeyMetadata ret = null;
        String requestId = null;
        try {
            CreateKeyResponse response = getAcsResponseWithRetry(request);
            ret = response.getKeyMetadata();
            requestId = response.getRequestId();
        } catch (Exception e) {
            throw e;
        }
        return Pair.of(ret, requestId).getKey();
    }

    private <T extends AcsResponse> T getAcsResponseWithRetry(AcsRequest<T> request) throws ServerException,
        ClientException {
        String expStr = "Retry Max Times";
        for (int i = 0; i < 3; i++) {
            try {
                T resp = this.kmsClient.getAcsResponse(request);
                if (resp == null) {
                    throw new ClientException("Get a null response");
                }
                return resp;
            } catch (ServerException e) {
                throw e;
            } catch (ClientException e) {
                expStr = e.toString();
              //リトライが必要です
                if (expStr.contains("SDK.ServerUnreachable")) {
                    continue;
                }
                throw e;
            }
        }
        throw new ClientException(expStr);
    }

    private byte[] generateEphemeralSymmetricKey(String ephemeralSymmetricKeySpec) throws Exception {
       // ESK が AES_256 タイプの場合、長さを 32 ビットに設定します。
       int ephemeralSymmetricKeyLength = 32; 
        if ("SM4".equals(ephemeralSymmetricKeySpec)) {
            ephemeralSymmetricKeyLength = 16;
        }
        byte[] key = new byte[32];
        new Random().nextBytes(key);

        return key;
    }

    private byte[] generateTargetAsymmetricKey(String keySpec) throws Exception {
        PrivateKey privateKey = null;
        // SM2 キーを作成し、秘密鍵の D パラメーターの値を取得します。
        if ("EC_SM2".equals(keySpec)) {
            ECPrivateKey ecPrivateKey = (ECPrivateKey)generateSm2KeyPair().getPrivate();
            byte[] dT = ecPrivateKey.getS().toByteArray();
            byte[] d = new  byte[32];
            if (dT.length == 33) {
                System.arraycopy(dT, 1, d, 0, 32);
            }
            return dT.length == 32 ? dT : d;
        }

        // RSA または ECC 秘密鍵を生成します。
        if (keySpec.contains("RSA")) {
            String[] keySpecAttrs = keySpec.split("_");
            int bits = Integer.parseInt(keySpecAttrs[keySpecAttrs.length - 1]);
            privateKey = generateRsaKeyPair(bits).getPrivate();
        } else if  (keySpec.contains("EC")) {
            if (keySpec.contains("P256K")) {
                // EC_P256K 秘密鍵を生成します。
                privateKey  = generateEccKeyPair("secp256k1").getPrivate();
            } else {
                // EC_P256 秘密鍵を生成します。
                privateKey=   generateEccKeyPair("secp256r1").getPrivate();
            }
        }
        if (privateKey != null) {
            // PKCS #8 形式で秘密鍵を返します。
            return  privateKey.getEncoded();
        }
        return null;
    }

    private  KeyPair generateEccKeyPair(String keySpec)
        throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
        ECGenParameterSpec ecSpec = new ECGenParameterSpec(keySpec);
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
        keyPairGenerator.initialize(ecSpec, new SecureRandom());
        return keyPairGenerator.generateKeyPair();
    }
    private  KeyPair generateRsaKeyPair(int length) throws Exception {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(length);
        return keyGen.genKeyPair();
    }

    private KeyPair generateSm2KeyPair() throws Exception {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", "BC");
        keyGen.initialize(new ECGenParameterSpec("sm2p256v1"), new SecureRandom());
        return keyGen.genKeyPair();
    }


    private byte[] encryptEphemeralSymmetricKey (String publicKeyBase64, String wrappingAlgorithm, byte[] ephemeralSymmetricKeyPlaintext) throws Exception {
        PublicKey publickey = null;
        byte[] enchbk = null;
        if ("RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD".equals(wrappingAlgorithm)) {
            publickey = parseDerPublicKey("RSA", publicKeyBase64);
            Cipher oaepFromAlgo = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
            OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), PSpecified.DEFAULT);
            oaepFromAlgo.init(Cipher.ENCRYPT_MODE, publickey, oaepParams);
            enchbk = oaepFromAlgo.doFinal(ephemeralSymmetricKeyPlaintext);
        } else if ("SM2PKE_SM4_ECB".equals(wrappingAlgorithm)) {
            publickey = parseDerPublicKey("EC", publicKeyBase64, BC);
            BCECPublicKey localECPublicKey = (BCECPublicKey) publickey;
            ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(localECPublicKey.getQ(), ecDomainParameters);
            SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
            sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters));
            enchbk = sm2Engine.processBlock(ephemeralSymmetricKeyPlaintext, 0, ephemeralSymmetricKeyPlaintext.length);

        } else {
            throw new Exception("Invalid wrappingAlgorithm");
        }
        return enchbk;
    }

    private PublicKey parseDerPublicKey(String keyType, String pemKey) throws Exception {
        byte[] derKey = DatatypeConverter.parseBase64Binary(pemKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(derKey);
        return KeyFactory.getInstance(keyType).generatePublic(keySpec);
    }
    private PublicKey parseDerPublicKey(String keyType, String pemKey, Provider provider) throws Exception {
        byte[] derKey = DatatypeConverter.parseBase64Binary(pemKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(derKey);
        return KeyFactory.getInstance(keyType, provider).generatePublic(keySpec);
    }

    private byte[] encryptTargetAsymmetricKey (byte[] secretKey, byte[] targetAsymmetricKeyPlaintext, String wrappingAlgorithm)
        throws Exception {
        if ("RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD".equals(wrappingAlgorithm)) {
            SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
            return cipher.doFinal(targetAsymmetricKeyPlaintext);
        } else if ("SM2PKE_SM4_ECB".equals(wrappingAlgorithm)) {
            SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, "SM4");
            Cipher cipher = Cipher.getInstance("SM4/ECB/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
            return cipher.doFinal(targetAsymmetricKeyPlaintext);
        }

        throw new Exception("Invalid WrappingAlgorithm");
    }

    private boolean importKeyMaterial(
        String keyId,
        String material,
        String token,
        Long expire
    ) throws Exception {
        ImportKeyMaterialRequest req = newImportKeyMaterialRequest(
            keyId, material, token, expire);
        try {
            ImportKeyMaterialResponse resp = this.getAcsResponseWithRetry(req);
        } catch (Exception e) {
            throw e;
        }
        return true;
    }

    private ImportKeyMaterialRequest newImportKeyMaterialRequest(
        String keyId,
        String material,
        String token,
        Long expire
    ) {
        ImportKeyMaterialRequest request = new ImportKeyMaterialRequest();
        request.setAcceptFormat(FormatType.JSON);
        request.setMethod(MethodType.POST);
        request.setProtocol(ProtocolType.HTTPS);
        request.setEncryptedKeyMaterial(material);
        request.setImportToken(token);
        request.setKeyId(keyId);
        request.setKeyMaterialExpireUnix(expire);
        return request;
    }
}
            

よくある質問

キーマテリアルは削除できますか?

はい、できます。

重要

インポートされたキーマテリアルの有効期限が切れるか削除されると、そのキーマテリアルを使用するキーは利用できなくなります。キーを再度使用するには、同じキーマテリアルを再インポートする必要があります。

  • キーマテリアルを直接削除する

    • コンソールで、キー詳細ページの キーマテリアル エリアで、キーマテリアルを削除 をクリックします。

    • API 操作: DeleteKeyMaterial 操作を呼び出してキーマテリアルを削除します。この操作はキーを削除しません。

  • KMS に有効期限切れ後にキーマテリアルを削除させる

    キーマテリアルをインポートするときに、有効期限を設定できます。KMS は指定された時間の後にキーマテリアルを削除します。

同じキーマテリアルを再インポートするにはどうすればよいですか?

キーマテリアルの有効期限が切れたり削除されたりした後、同じキーマテリアルを再インポートしてキーの使用を継続できます。

  1. 有効期限が切れたキーマテリアルを削除します。

    キー詳細ページで、キーマテリアル タブをクリックします。次に、キーマテリアルを削除 をクリックします。

  2. ラッピング公開鍵とインポートトークンを再ダウンロードします。詳細については、「ステップ 2: ラッピング公開鍵とインポートトークンのダウンロード」をご参照ください。

    説明

    キーラッピングプロセスはキーマテリアルの内容に影響しません。異なるラッピング公開鍵と異なるラッピングアルゴリズムを使用して、同じキーマテリアルをインポートできます。

  3. ラッピング公開鍵を使用してキーマテリアルを暗号化します。詳細については、「ステップ 3: ラッピング公開鍵を使用してキーマテリアルを暗号化する」をご参照ください。

    説明

    キーマテリアルは、有効期限が切れたキーマテリアルと同じでなければなりません。

  4. インポートトークンを使用して暗号化されたキーマテリアルをインポートします。詳細については、「ステップ 4: キーマテリアルのインポート」をご参照ください。

キーマテリアルがインポートされたものか、KMS によって生成されたものかを判断するにはどうすればよいですか?

  • 方法 1: KMS コンソールを確認する。

    キー管理 ページで、キー タブをクリックし、インスタンス管理 を選択し、ターゲットキーを見つけて、操作 列の 詳細 をクリックします。詳細ページで、キーマテリアルソース を表示できます。

  • 方法 2: DescribeKey 操作を呼び出す。

    Origin の値が EXTERNAL の場合、キーマテリアルはインポートされます。Origin の値が Aliyun_KMS の場合、キーマテリアルは KMS によって生成されます。

外部キーマテリアルを使用するキーをローテーションするにはどうすればよいですか?

  • インポートされたキーマテリアルを使用するソフトウェア保護された対称キーの場合、即時の手動ローテーションのみがサポートされ、自動定期ローテーションはサポートされません。詳細については、「Bring-Your-Own-Key (BYOK) キーのローテーション」をご参照ください。

  • インポートされたキーマテリアルを使用するソフトウェア保護された非対称キーのローテーションはサポートされていません。

  • インポートされたキーマテリアルを使用するハードウェア保護されたキー (対称および非対称の両方) のローテーションはサポートされていません。

関連ドキュメント