When you create an asymmetric key with an external key material source, KMS does not generate key material. You must import your own key material. This topic describes how to import key material for an asymmetric key.
If your software key management instance or hardware key management instance does not support key material import, or the import fails, contact Alibaba Cloud technical support to upgrade your instance.
Features
In regulated industries, compliance audits often require you to prove exclusive custody of cryptographic key material. When you create an asymmetric key with an external key material source, Key Management Service (KMS) does not generate key material — you supply and import your own. This is known as Bring Your Own Key (BYOK).
Key management type | Import asymmetric key material |
Default key |
|
Software-protected key | |
Hardware-protected key |
Usage notes
After the first import of key material, the key is bound to that key material and no longer supports importing other key material.
You can import the same key material multiple times to a KMS key as needed, but you cannot import different key material to one KMS key.
If the key material of a key expires or is deleted, you can import the same key material again to make the key available again. Key material cannot be exported after import. Store the key material properly.
Scope
A KMS instance is purchased and enabled. For more information, see Purchase and enable a KMS instance.
Import key material in the KMS console
Step 1: Create an asymmetric key with an external key material source
Before importing key material, create an asymmetric key with an external key material source.
Software-protected key
Log on to the Key Management Service console. In the top navigation bar, select a region. In the left-side navigation pane, choose .
On the Customer Master Keys tab, select a software key management instance from the Instance ID drop-down list, and click Create Key.
In the Create Key panel, complete the parameter settings, and click OK.
Parameter
Description
Key Type
Select Asymmetric Key.
Key Specifications
Asymmetric key specifications: RSA_2048, RSA_3072, RSA_4096, EC_P256, and EC_P256K.
Key Usage
The usage of the key. Valid values:
Encrypt/Decrypt: encrypts and decrypts data.
Sign/Verify: generates and verifies digital signatures.
Key Alias
The alias of the key. Letters, digits, underscores (_), hyphens (-), and forward slashes (/) are supported.
Tags
The tags of the key, which allow you to classify keys. Each tag consists of a key-value pair.
NoteFormat of a tag key and a tag value: A tag key or a tag value can be up to 128 characters in length and can contain letters, digits, forward slashes (/), backslashes (\), underscores (_), hyphens (-), periods (.), plus signs (+), equal signs (=), colons (:), at signs (@), and spaces.
A tag key cannot start with
aliyunoracs:.Each key supports up to 20 tag key-value pairs.
Description
The description of the key.
Advanced Settings
Policy Settings: For more information, see Key policy overview.
Key Material Origin: Select External (Import Key Material).
NoteRead carefully and select I understand the methods and implications of using external key material.
Hardware-protected key
Log on to the Key Management Service console. In the top navigation bar, select a region. In the left-side navigation pane, choose .
On the Customer Master Keys tab, select a hardware key management instance from the Instance ID drop-down list, and click Create Key.
In the Create Key panel, complete the parameter settings, and click OK.
Parameter
Description
Key Type
Select Asymmetric Key.
Key Specifications
Asymmetric key specifications: RSA_2048, RSA_3072, RSA_4096, EC_P256, and EC_P256K
Key Usage
The usage of the key. Valid values:
Encrypt/Decrypt: encrypts and decrypts data.
Sign/Verify: generates and verifies digital signatures.
Key Alias
The alias of the key. Letters, digits, underscores (_), hyphens (-), and forward slashes (/) are supported.
Tags
The tags of the key, which allow you to classify keys. Each tag consists of a key-value pair.
NoteFormat of a tag key and a tag value: A tag key or a tag value can be up to 128 characters in length and can contain letters, digits, forward slashes (/), backslashes (\), underscores (_), hyphens (-), periods (.), plus signs (+), equal signs (=), colons (:), at signs (@), and spaces.
A tag key cannot start with
aliyunoracs:.Each key supports up to 20 tag key-value pairs.
Description
The description of the key.
Advanced Settings
Policy Settings: For more information, see Key policy overview.
Key Material Origin: Select External (Import Key Material).
NoteRead carefully and select I understand the methods and implications of using external key material.
Step 2: Download a wrapping public key and an import token
The parameters for importing key material include a wrapping public key and an import token. The wrapping public key is used to encrypt the key material and protect it during the import process. The import token is used to authorize the import.
Find the target key, click Actions in the Details column. On the key details page, in the Key Material section, click Obtain Parameters for Import.
In the Obtain Parameters to Import Key Material dialog box, select the Public Key Type and Encryption Algorithm, and click Next.
Key management type
Key specifications
Wrapping public key type
Encryption algorithm
Software-protected key
RSA_2048
RSA_3072
EC_P256
EC_P256K
RSA_2048
RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD
Hardware-protected key
RSA_2048
RSA_3072
RSA_4096
EC_P256
EC_P256K
RSA_2048
RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD
RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD: For the detailed encryption process, see Example: Use OpenSSL to generate key material for the RSA_2048 algorithm.
Download the wrapping public key and the import token, and store them securely.
Public Key Format:
DER Format: The downloaded file is named
WrappingPublicKey**.binby default.PEM Format: The downloaded file is named
WrappingPublicKey**.pemby default.
Import Token: The downloaded file is named
ImportToken***.txtby default.ImportantAn import token is valid for 24 hours and can be reused within this period. After it expires, you must obtain a new import token and public key.
The wrapping public key and the import token must be used as a pair. You cannot use a wrapping public key from one download with an import token from another.
Step 3: Encrypt the key material using the wrapping public key
Generate and encrypt the key material in your system environment. The following keys are used in the process. See the table below for details.
Key | Purpose | Provider | Notes |
Target Asymmetric Key (TAK) | The target asymmetric key to be imported. | Your system environment or tool (such as an offline key management infrastructure KMI, or an offline hardware security module HSM). |
|
Import Wrapping Key (IWK) | The encryption key used to import the TAK. | Alibaba Cloud KMS. |
|
Ephemeral Symmetric Key (ESK) | A transient symmetric key used to directly encrypt TAKpriv. | Your system or tool in the source environment. Destroy it immediately after exporting the TAK. | N/A |
Create a target asymmetric key private key (TAKpriv). The key specification must be consistent with the one you selected when creating the asymmetric key. If you already have a target asymmetric key private key (TAKpriv), skip this step.
NoteThe TAKpriv format must follow: RSA private keys are encoded per RFC 3447, ECC private keys per RFC 5915, then wrapped in PKCS#8 format per RFC 5208.
Create an ephemeral symmetric key (ESK).
Use the import wrapping key public key (IWKpub) to encrypt the ephemeral symmetric key (ESK) to obtain the ephemeral symmetric key ciphertext (Cipher(ESK)).
Use the ephemeral symmetric key (ESK) to encrypt the target asymmetric key private key (TAKpriv) to obtain the private key ciphertext (Cipher(TAKpriv)).
Assemble the result data in the Cipher(ESK)||Cipher(TAKpriv) format to obtain the encrypted key material.
Step 4: Import key material
On the key details page, click Import Key Material. In the Import Wrapped Key Material dialog box, complete the configurations and click OK.
Parameter | Description |
Wrapped Key Material | Upload the key material file generated in Step 3: Encrypt the key material using the wrapping public key. |
Import Token | Upload the token file downloaded in Step 2: Download a wrapping public key and an import token. |
Key Material Expired On | You can select Never Expire or specify a custom expiration time. Important If you set an expiration time for the key material, KMS deletes the expired key material after that time, and you can no longer use it. To restore it, you can import the same key material again. |
After the key material is successfully imported, the key status changes from Pending Import to Enabling.
Import key material using Alibaba Cloud SDK
You can use Alibaba Cloud SDK to create RSA and ECC keys in KMS and import key material. The following Java code example demonstrates the process.
An AccessKey pair for an Alibaba Cloud account has permissions for all API operations. We recommend that you use a RAM user to call API operations or perform routine O&M. To prevent security risks, do not hardcode your AccessKey ID and AccessKey Secret in your project code. Hardcoding credentials can lead to leaks that compromise all resources in your account.
This topic provides an example of how to configure the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables for identity authentication.
For more information about how to configure access credentials, see Manage access credentials.
The method for configuring environment variables varies based on the operating system. For more information, see Configure environment variables on Linux, macOS, and Windows.
Install the SDK
Add the Maven dependency to your project to automatically download the Java installation package from the Maven repository. Use Alibaba Cloud SDK V2.0.
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>kms20160120</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>tea</artifactId>
<version>1.3.2</version>
</dependency>package com.aliyun;
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.aliyun.kms20160120.models.*;
import com.aliyun.kms20160120.Client;
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 {
private final static String dedicatedKmsInstanceId = "<yourKmsInstanceId>";
// The public endpoint of KMS.
private final static String endpoint = "kms.<regionId>.aliyuncs.com";
private final Client 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) throws Exception {
// Initialize the KMS SDK.
Client client = BringYourOwnAsymmetricKeySample.createClient();
BringYourOwnAsymmetricKeySample sample = new BringYourOwnAsymmetricKeySample(client);
// Create and import an external key of the EC_SM2 type.
sample.doByok("EC_SM2", "EC_SM2", sample.SM2PKE_SM4_ECB, "SM4");
// Create and import an external key of the EC_P256 type.
sample.doByok("EC_P256", "RSA_2048", sample.RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD, "AES_256");
// Create and import an external key of the RSA type.
sample.doByok("RSA_2048", "RSA_2048", sample.RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD, "AES_256");
}
/**
* <b>description</b> :
* <p>Initialize the client using credentials.</p>
*
* @return Client
* @throws Exception
*/
public static Client createClient() throws Exception {
// We recommend that you use the more secure credential-based initialization without hardcoding AccessKey pairs. For more information, see: https://www.alibabacloud.com/help/document_detail/378657.html.
com.aliyun.credentials.Client credential = new com.aliyun.credentials.Client();
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
.setCredential(credential);
// For the endpoint, see https://api.aliyun.com/product/Kms.
config.endpoint = endpoint;
return new Client(config);
}
public BringYourOwnAsymmetricKeySample(Client kmsClient) {
this.kmsClient = kmsClient;
}
public void doByok(String targetKeySpec, String wrappingKeySpec, String wrappingAlgorithm, String ephemeralKeySpec) {
try {
// Create an external ECC key.
CreateKeyResponseBody.CreateKeyResponseBodyKeyMetadata keyMetadata = this.createExternalKeyInDkms(dedicatedKmsInstanceId, targetKeySpec, "SIGN/VERIFY");
String keyId = keyMetadata.getKeyId();
// Obtain the parameters for importing key material.
GetParametersForImportResponse parametersForImportResponse = this.getParametersForImport(keyId, wrappingKeySpec,
wrappingAlgorithm);
String importToken = parametersForImportResponse.body.getImportToken();
String publicKeyBase64 = parametersForImportResponse.body.getPublicKey();
// Generate the ephemeral symmetric key.
byte[] ephemeralSymmetricKeyPlaintext = this.generateEphemeralSymmetricKey(ephemeralKeySpec);
// Generate the target asymmetric key.
byte[] targetAsymmetricKeyPlaintext = this.generateTargetAsymmetricKey(targetKeySpec);
// Use the import wrapping key public key to encrypt the ephemeral symmetric key.
byte[] ephemeralSymmetricKeyCipher = this.encryptEphemeralSymmetricKey(publicKeyBase64,
wrappingAlgorithm, ephemeralSymmetricKeyPlaintext);
// Use the ephemeral symmetric key to encrypt the target asymmetric key.
byte[] targetAsymmetricKeyCipher = this.encryptTargetAsymmetricKey(ephemeralSymmetricKeyPlaintext, targetAsymmetricKeyPlaintext,
wrappingAlgorithm);
// Generate the key material.
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);
// Import the key material to KMS.
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.setKeyId(keyId);
request.setWrappingKeySpec(keySpec);
request.setWrappingAlgorithm(algorithm);
return this.kmsClient.getParametersForImport(request);
}
private CreateKeyResponseBody.CreateKeyResponseBodyKeyMetadata createExternalKeyInDkms(String dedicatedKmsInstance, String keySpec, String keyUsage) throws Exception {
CreateKeyRequest request = new CreateKeyRequest();
// Create an external key.
request.setOrigin("EXTERNAL");
request.setDKMSInstanceId(dedicatedKmsInstance);
request.setKeySpec(keySpec);
request.setKeyUsage(keyUsage);
return kmsClient.createKey(request).body.keyMetadata;
}
private byte[] generateEphemeralSymmetricKey(String ephemeralSymmetricKeySpec) throws Exception {
// If the ephemeral symmetric key is AES_256, the length is 32 bytes.
int ephemeralSymmetricKeyLength = 32;
if ("SM4".equals(ephemeralSymmetricKeySpec)) {
ephemeralSymmetricKeyLength = 16;
}
byte[] key = new byte[ephemeralSymmetricKeyLength];
new Random().nextBytes(key);
return key;
}
private byte[] generateTargetAsymmetricKey(String keySpec) throws Exception {
PrivateKey privateKey = null;
// Generate an SM2 key and obtain the D value of the private key.
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;
}
// Generate an RSA or ECC private key.
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")) {
// Generate an EC_P256K private key.
privateKey = generateEccKeyPair("secp256k1").getPrivate();
} else {
// Generate an EC_P256 private key.
privateKey = generateEccKeyPair("secp256r1").getPrivate();
}
}
if (privateKey != null) {
// Return the private key in PKCS#8 format.
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 void importKeyMaterial(
String keyId,
String material,
String token,
Long expire
) throws Exception {
ImportKeyMaterialRequest req = newImportKeyMaterialRequest(
keyId, material, token, expire);
this.kmsClient.importKeyMaterial(req);
}
private ImportKeyMaterialRequest newImportKeyMaterialRequest(
String keyId,
String material,
String token,
Long expire
) {
ImportKeyMaterialRequest request = new ImportKeyMaterialRequest();
request.setEncryptedKeyMaterial(material);
request.setImportToken(token);
request.setKeyId(keyId);
request.setKeyMaterialExpireUnix(expire);
return request;
}
}
FAQ
Is key material deletion supported?
Yes, it is supported.
ImportantAfter the imported key material expires or is deleted, the key becomes unavailable. You must import the same key material again to restore the key.
Delete key material directly
Console: On the key details page, in the Key Material section, click Delete Key Material.
API: Call the DeleteKeyMaterial operation to delete the key material. This operation does not delete your key.
Automatic deletion by KMS after expiration
Set an expiration time when importing key material. After that time, KMS deletes the expired key material.
How do I reimport the same key material?
After the key material expires or is deleted, you can import the same key material again so the key can continue to be used.
Delete the expired key material.
On the key details page, click the Key Material tab, and click Delete Key Material.
Download the wrapping public key and import token again. For more information, see Step 2: Download a wrapping public key and an import token.
NoteThe key wrapping process does not affect the content of the key material. You can use a different wrapping public key and wrapping algorithm to import the same key material.
Encrypt the key material using the wrapping public key. For more information, see Step 3: Encrypt the key material using the wrapping public key.
NoteThe key material must be the same as the previously expired one.
Use the import token to import the encrypted key material. For more information, see Step 4: Import key material.
How do I determine whether the key material is imported externally or generated by KMS?
Method 1: Check in the KMS console.
On the Keys page, click the Customer Master Keys tab, select a Instance ID, find the target key, click Actions in the Details column, and check the Key Material Origin on the details page.
Method 2: Check by calling the DescribeKey operation.
If the value of
OriginisEXTERNAL, the key material is imported externally. If the value ofOriginisAliyun_KMS, the key material is generated by KMS.
How do I rotate a key that uses external key material?
For a software-protected symmetric key with imported external key material, only immediate manual rotation is supported. Automatic periodic rotation is not supported. For more information, see Bring Your Own Keys (BYOKs) with imported key material..
For a software-protected asymmetric key with imported external key material, rotation is not supported.
For a hardware-protected key (symmetric or asymmetric) with imported external key material, rotation is not supported.