外部キーマテリアル起源で非対称キーを作成すると、Key Management Service (KMS) はそのキーに対してキーマテリアルを生成しません。代わりに、ご自身で秘密鍵のキーマテリアルを用意し、それをキーにインポートする必要があります。この手法は一般的に「Bring Your Own Key (BYOK)」と呼ばれます。
ハードウェアキー管理タイプまたはソフトウェアキー管理タイプの KMS インスタンスでキーマテリアルのインポートが許可されていない場合、またはインポート時にエラーが発生した場合は、テクニカルサポートまでお問い合わせください。
サポートされるキー管理タイプ
すべてのキー管理タイプが非対称キーマテリアルのインポートをサポートしているわけではありません。以下の表にサポート状況を示します。
| キー管理タイプ | 対称キーマテリアルのインポート | 非対称キーマテリアルのインポート |
|---|---|---|
| デフォルトキー – カスタマーマスターキー | サポート対象 | 非サポート |
| デフォルトキー – サービスキー | 非サポート | 非サポート |
| ソフトウェア保護キー | サポート対象 | サポート対象 |
| ハードウェア保護キー | サポート対象 | 非サポート |
キー管理タイプの詳細については、「キー管理タイプおよびキー仕様」をご参照ください。
注意事項
初回インポートは恒久的です。 キーへのキーマテリアルの初回インポート後、そのキーは当該キーマテリアルと恒久的に関連付けられます。その後、同一のキーに異なるキーマテリアルをインポートすることはできません。
再インポートは可能です。 同一のキーマテリアルを複数回キーにインポートできます。キーマテリアルが有効期限切れになったり削除されたりした場合、同じキーマテリアルを再インポートしてキーを再利用してください。
キーマテリアルはエクスポートできません。 インポート後、キーマテリアルは KMS から取得できません。インポート前に、安全な場所に保管してください。
前提条件
開始する前に、以下の条件を満たしていることを確認してください。
購入済みかつ有効化済みの KMS インスタンス。詳細については、「KMS インスタンスの購入と有効化」をご参照ください。
KMS コンソールでのキーマテリアルのインポート
コンソールベースのインポート手順は、以下の 4 ステップで構成されます。
外部キーマテリアル起源の非対称キーを作成します。
ラッピング公開鍵およびインポートトークンをダウンロードします。
ラッピング公開鍵を使用して秘密鍵を暗号化します。
暗号化されたキーマテリアルおよびインポートトークンをアップロードします。
ステップ 1:非対称キーの作成
外部キーマテリアル起源を使用する非対称キーを作成します。手順は、ご利用の KMS インスタンスタイプによって若干異なります。
ソフトウェア保護キー
KMS コンソールにログインします。上部ナビゲーションバーでリージョンを選択し、左側ナビゲーションウィンドウで リソース > キー を選択します。
カスタマーマスターキー タブで、インスタンス ID のドロップダウンリストからソフトウェアキー管理インスタンスを選択し、キーの作成 をクリックします。
キーの作成 パネルで、以下のパラメーターを設定し、OK をクリックします。
パラメーター 説明 キーの種類 非対称キー を選択します。 キー仕様 RSA_2048、RSA_3072、EC_P256、または EC_P256K のいずれかを指定します。 キー使用目的 ENCRYPT/DECRYPT:データの暗号化または復号。SIGN/VERIFY:データの署名またはデジタル署名の検証。 キーのエイリアス キーの別名です。使用可能な文字:英字、数字、アンダースコア ( _)、ハイフン (-)、およびスラッシュ (/)。タグキー、タグ値 キーの分類および管理に使用するタグです。タグキーおよびタグ値は最大 128 文字(英字、数字、 /、\、_、-、.、+、=、:、@、空白)まで使用可能です。タグキーはaliyunまたはacs:で始めてはいけません。1 つのキーにつき最大 20 個のタグキーと値のペアを設定できます。説明 キーの任意の説明文です。 ポリシー設定(詳細設定 内) 概要「」をご参照ください。 キーマテリアルの起源(詳細設定 内) 外部(キーマテリアルのインポート) を選択します。「外部キーマテリアルを使用することによる影響について理解しました」という確認事項を読み、チェックを入れてください。
ハードウェア保護キー
KMS コンソールにログインします。上部ナビゲーションバーでリージョンを選択し、左側ナビゲーションウィンドウで リソース > キー を選択します。
カスタマーマスターキー タブで、インスタンス ID のドロップダウンリストからハードウェアキー管理インスタンスを選択し、キーの作成 をクリックします。
キーの作成 パネルで、以下のパラメーターを設定し、OK をクリックします。
パラメーター 説明 キーの種類 非対称キー を選択します。 キー仕様 RSA_2048、RSA_3072、RSA_4096、EC_P256、または EC_P256K のいずれかを指定します。 キーの使用目的 ENCRYPT/DECRYPT:データの暗号化または復号。SIGN/VERIFY:データの署名またはデジタル署名の検証。 キーのエイリアス キーの別名です。使用可能な文字:英字、数字、アンダースコア ( _)、ハイフン (-)、およびスラッシュ (/)。タグキー、タグ値 キーの分類および管理に使用するタグです。タグキーおよびタグ値は最大 128 文字(英字、数字、 /、\、_、-、.、+、=、:、@、空白)まで使用可能です。タグキーはaliyunまたはacs:で始めてはいけません。1 つのキーにつき最大 20 個のタグキーと値のペアを設定できます。説明 キーの任意の説明文です。 ポリシー設定(詳細設定 内) 概要「」をご参照ください。 キーマテリアルの起源(詳細設定 内) 外部(キーマテリアルのインポート) を選択します。「外部キーマテリアルを使用することによる影響について理解しました」という確認事項を読み、チェックを入れてください。
ステップ 2:ラッピング公開鍵およびインポートトークンのダウンロード
キーマテリアルをインポートするには、KMS から次の 2 つのファイルを取得する必要があります。
ラッピング公開鍵 — アップロード前にキーマテリアルを暗号化するために使用します。
インポートトークン — インポート操作を承認します。
作成したキーを見つけ、詳細 をクリックします(操作 列内)。キーマテリアル タブで、インポート用パラメーターの取得 をクリックします。
キーマテリアルのインポート用パラメーターの取得 ダイアログボックスで、公開鍵の種類 および 暗号化アルゴリズム を選択し、次へ をクリックします。以下の表を参考に、キーに適したラッピング公開鍵の種類および暗号化アルゴリズムを選択してください。
キーマテリアルの種類 キー仕様 ラッピング公開鍵の種類 暗号化アルゴリズム RSA 秘密鍵(ソフトウェア保護) RSA_2048、RSA_3072 RSA_2048 RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD ECC 秘密鍵(ソフトウェア保護) EC_P256、EC_P256K RSA_2048 RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD RSA 秘密鍵(ハードウェア保護) RSA_2048、RSA_3072、RSA_4096 RSA_2048 RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD ECC 秘密鍵(ハードウェア保護) EC_P256、EC_P256K RSA_2048 RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD 両方のファイルをダウンロードし、安全な場所に保存してください。
DER 形式の公開鍵:ファイル名は
publickey_******.binの形式です。PEM 形式の公開鍵:ファイル名は
publickey_******.pemの形式です。インポートトークン:ファイル名は
token_******.txtの形式です。
インポートトークンは 24 時間有効であり、その期間内であれば再利用可能です。24 時間経過後は、新しいインポートトークンおよび新しいラッピング公開鍵をダウンロードしてください。
必ず同一のダウンロードから取得したラッピング公開鍵およびインポートトークンを使用してください。異なるダウンロードから取得したファイルを混在させないでください。
ステップ 3:秘密鍵の暗号化
アップロード前に秘密鍵を暗号化する必要があります。この暗号化では、3 つの鍵を用いた二重ラッピング方式が採用されます。
| 鍵 | 略称 | 種類 | 提供元 | 説明 |
|---|---|---|---|---|
| 対象非対称キー | TAK | RSA または ECC キーペア | お客様のシステム、KMI、または HSM | 使用するキーペアです。TAKpub は公開鍵、TAKpriv はインポートする秘密鍵です。 |
| インポートラッピング鍵 | IWK | RSA キーペア | KMS | インポートを保護するために使用されるキーペアです。IWKpub はダウンロードしたラッピング公開鍵です。 |
| 一時的対称鍵 | ESK | AES-256(または SM4) | お客様のシステム | TAKpriv を暗号化するための一時的な対称鍵です。使用後は直ちに破棄してください。 |
TAKpriv のフォーマット要件:
秘密鍵をその種類に応じてエンコードします(RSA:RFC 3447、ECC:RFC 5915)、その後 PKCS #8 形式(RFC 5208)に変換します。最終出力は DER エンコーディングである必要があります。
暗号化手順:
PKCS #8 DER 形式で TAKpriv を準備します。すでにこの形式の秘密鍵をお持ちの場合は、このステップをスキップできます。
AES-256 ESK(32 バイトのランダム値)を生成します。
RSAES-OAEP(ハッシュおよび MGF1 に SHA-256 を使用)を用いて IWKpub で ESK を暗号化します。結果は
Cipher(ESK)です。AES-256 ECB モードおよび PKCS #7 パディングを用いて ESK で TAKpriv を暗号化します。結果は
Cipher(TAKpriv)です。2 つの暗号文を
Cipher(ESK) || Cipher(TAKpriv)の順序で連結し、Base64 エンコーディングします。これがアップロードする暗号化キーマテリアルです。
例:OpenSSL を使用した RSA_2048 秘密鍵の暗号化
# ステップ 1:TAK 用の RSA_2048 秘密鍵を生成し、PKCS #8 DER 形式に変換
openssl genrsa -out TakPrivPkcs1.pem 2048
openssl pkcs8 -topk8 -inform PEM -in TakPrivPkcs1.pem -outform der -nocrypt -out TakPrivPkcs8.bin
# ステップ 2:AES-256 ESK(32 バイト)を生成
openssl rand -out EskAes256.bin 32
# ステップ 3:RSAES-OAEP(SHA-256)を用いて IWK 公開鍵で ESK を暗号化
# PublicKey.pem は、KMS コンソールからダウンロードしたラッピング公開鍵ファイルに置き換えてください。
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
# ステップ 4:AES-256 ECB + PKCS #7 パディングを用いて ESK で TAKpriv を暗号化
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:連結および Base64 エンコーディング
cat CipherEsk.bin CipherTakPriv.bin > EncryptedKeyMaterial.bin
openssl enc -e -base64 -A -in EncryptedKeyMaterial.bin -out EncryptedKeyMaterial_base64.txtEncryptedKeyMaterial_base64.txt ファイルには、次のステップでアップロードする暗号化キーマテリアルが含まれています。
ステップ 4:キーマテリアルのインポート
キーの詳細ページで、キーマテリアルのインポート をクリックします。
ラップされたキーマテリアルのインポート ダイアログボックスで、以下のパラメーターを設定し、OK をクリックします。
パラメーター 説明 ラップされたキーマテリアル ステップ 3 で生成した暗号化キーマテリアルファイルをアップロードします。 インポートトークン ステップ 2 でダウンロードしたインポートトークンファイルをアップロードします。 キー材料の有効期限切れ日 有効期限なし を選択するか、有効期限を指定します。有効期限を設定した場合、有効期限が過ぎると KMS がキーマテリアルを削除し、キーは同一のキーマテリアルを再インポートするまで利用不可になります。
インポート後、キーのステータスは インポート待ち から 有効化中 に変わります。
Alibaba Cloud SDK を使用したキーマテリアルのインポート
以下の Java の例では、KMS で外部非対称キーを作成し、Alibaba Cloud SDK を使用してキーマテリアルをインポートする方法を示します。RSA または ECC
認証情報は環境変数から読み込まれます。AccessKey ID および AccessKey Secret は、プロジェクト内にハードコードせず、ALIBABA_CLOUD_ACCESS_KEY_ID および ALIBABA_CLOUD_ACCESS_KEY_SECRET という環境変数に格納してください。
認証情報の構成については、「アクセス認証情報の管理」をご参照ください。
環境変数の設定については、「Linux、macOS、Windows で環境変数を設定する」をご参照ください。
すべての例では、最終的なキーマテリアルペイロードを構築する前に、一時的対称鍵を暗号化するために RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD または SM2PKE_SM4_ECB アルゴリズムを使用します。
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) {
// Alibaba Cloud 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 Client の構築:
* 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);
// 暗号化キーマテリアルの構築:Cipher(ESK) || Cipher(TAKpriv)
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();
//need retry
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;
}
}以下のプレースホルダーを置き換えてください。
| プレースホルダー | 説明 |
|---|---|
* Provide your DedicatedKmsInstanceId * | 専用 KMS インスタンスの ID |
cn-hangzhou | KMS インスタンスが展開されているリージョン |
よくある質問
キーマテリアルを削除できますか?
はい。キーマテリアルが削除または有効期限切れになると、同一のキーマテリアルを再インポートするまでキーは利用不可になります。
直接キーマテリアルを削除するには、以下の手順を実行します。
KMS コンソール:キーの詳細ページで、キーマテリアル タブをクリックし、キーマテリアルの削除 をクリックします。
KMS API:DeleteKeyMaterial 操作を呼び出します。これにより、キーマテリアルのみが削除され、キー自体は削除されません。
自動削除を設定するには、インポート時に有効期限を指定します。KMS は有効期限に達するとキーマテリアルを削除します。
同一のキーマテリアルを再インポートするにはどうすればよいですか?
キーマテリアルが有効期限切れまたは削除された場合、同一のキーマテリアルを再インポートしてキーを復元できます。
キーの詳細ページで、キーマテリアル タブをクリックし、キーマテリアルの削除 をクリックして、有効期限切れのキーマテリアルをクリアします。
新しいラッピング公開鍵およびインポートトークンをダウンロードします(ステップ 2 を参照)。ラッピング手順はキーマテリアルの内容に影響しないため、異なるラッピング公開鍵およびアルゴリズムを使用できます。
新しいラッピング公開鍵を使用してキーマテリアルを暗号化します(ステップ 3 を参照)。キーマテリアル自体は元のものと同一である必要があります。
新しいインポートトークンとともに暗号化キーマテリアルをアップロードします(ステップ 4 を参照)。
キーのキーマテリアルの起源を確認するにはどうすればよいですか?
KMS コンソール:カスタマーマスターキー タブで、該当のキーを見つけ、詳細 をクリックします(操作 列内)。詳細ページの キーマテリアルの起源 フィールドを確認します。
KMS API:DescribeKey を呼び出します。
OriginフィールドがEXTERNALの場合、キーマテリアルはインポートされています。また、Aliyun_KMSの場合、KMS がキーマテリアルを生成しています。
インポートされたキーマテリアルでキーのローテーションは機能しますか?
キーのローテーションのサポート状況は、キーの種類によって異なります。
インポートされたキーマテリアルを持つソフトウェア保護対称キー:即時手動ローテーションのみがサポートされます。自動定期ローテーションはサポートされていません。詳細については、「Bring-Your-Own-Key (BYOK) キーのローテーション」をご参照ください。
インポートされたキーマテリアルを持つソフトウェア保護非対称キー:ローテーションはサポートされていません。
インポートされたキーマテリアルを持つハードウェア保護キー(対称および非対称):ローテーションはサポートされていません。