If you set the Origin parameter to EXTERNAL, KMS does not create key material. In this case, you must import external key material to the customer master key (CMK). This topic describes how to import external key material.
Prerequisites
An Alibaba Cloud account is created. To create an Alibaba Cloud account, visit the account registration page.
Background information
CMKs are basic resources of KMS. A CMK is composed of a key ID, basic metadata (such as key state), and key material that is used to encrypt and decrypt data. When you call the CreateKey operation to create a CMK, if you use the default value Aliyun_KMS of the Origin parameter, KMS generates key material. If you set the Origin parameter to EXTERNAL, KMS does not generate key material. In this case, you must import external key material to the CMK.
- If the value of Origin in KeyMetadata is Aliyun_KMS, the key material is generated by KMS. In this case, the CMK is considered a common key.
- If the value of Origin is EXTERNAL, the key material is imported from an external source. In this case, the CMK is considered an external key.
- Make sure that the source of randomness from which the key material is generated meets security requirements.
- Make sure that the key material is reliable.
- KMS ensures the high availability of imported key material. However, it cannot ensure that the imported key material has the same reliability as the key material generated by KMS.
- You can call the DeleteKeyMaterial operation to delete the imported key material. You can also set an expiration time to automatically delete the key material after it expires. The CMK is not deleted. To delete key material generated by KMS, you can only call the ScheduleKeyDeletion operation to specify a waiting period of 7 to 30 days for deleting the CMK. The key material is deleted along with the relevant CMK after the waiting period ends.
- After you delete the imported key material, you can re-import the same key material to make the relevant CMK available again. Therefore, we recommend that you save a copy of the key material.
- Key material is unique for each CMK. When you import key material into a CMK, the CMK is associated with that key material. Even after the key material expires or is deleted, you cannot import different key material into that CMK. If you need to rotate a CMK that uses external key material, you must create a CMK and then import new key material.
- CMKs are independent. You cannot use a CMK to decrypt data that is encrypted by using another CMK, even if the two CMKs use the same key material.
- The key material to be imported must be a 256-bit symmetric key.
Import key material in the KMS console
Import key material by using Alibaba Cloud CLI
Sample code
- JAVA SDK
//Use the latest KMS SDK for Java. //KmsClient.java import com.aliyuncs.kms.model.v20160120.*; import com.aliyuncs.profile.DefaultProfile; //KMS API encapsulation public class KmsClient { DefaultAcsClient client; public KmsClient( String region_id, String ak, String secret) { DefaultProfile profile = DefaultProfile.getProfile(region_id, ak, secret); this.client = new DefaultAcsClient(profile); } public CreateKeyResponse createKey() throws Exception { CreateKeyRequest request = new CreateKeyRequest(); request.setOrigin("EXTERNAL"); //Create an external key. return this.client.getAcsResponse(request); } //... Omitted. The remaining operations are the same as those in the API method. } //example.java import com.aliyuncs.kms.model.v20160120.*; import KmsClient import java.security.KeyFactory; import java.security.PublicKey; import java.security.spec.MGF1ParameterSpec; import javax.crypto.Cipher; import javax.crypto.spec.OAEPParameterSpec; import javax.crypto.spec.PSource.PSpecified; import java.security.spec.X509EncodedKeySpec; import java.util.Random; import javax.xml.bind.DatatypeConverter; public class CreateAndImportExample { public static void main(String[] args) { String regionId = "cn-hangzhou"; String accessKeyId = "*** Provide your AccessKeyId ***"; String accessKeySecret = "*** Provide your AccessKeySecret ***"; KmsClient kmsclient = new KmsClient(regionId,accessKeyId,accessKeySecret); //Create an external key. try { CreateKeyResponse keyResponse = kmsclient.createKey(); String keyId = keyResponse.KeyMetadata.getKeyId(); //Generate a 32-byte random number. byte[] keyMaterial = new byte[32]; new Random().nextBytes(keyMaterial); //Obtain the parameters that are used to import key material. GetParametersForImportResponse paramResponse = kmsclient.getParametersForImport(keyId,"RSAES_OAEP_SHA_256"); String importToekn = paramResponse.getImportToken(); String encryptPublicKey = paramResponse.getPublicKey(); //Base64 decode the public key. byte[] publicKeyDer = DatatypeConverter.parseBase64Binary(encryptPublicKey); //Use RSA to parse the public key. KeyFactory keyFact = KeyFactory.getInstance("RSA"); X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKeyDer); PublicKey publicKey = keyFact.generatePublic(spec); //Encrypt the key material. Cipher oaepFromAlgo = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); String hashFunc = "SHA-256"; OAEPParameterSpec oaepParams = new OAEPParameterSpec(hashFunc, "MGF1", new MGF1ParameterSpec(hashFunc), PSpecified.DEFAULT); oaepFromAlgo.init(Cipher.ENCRYPT_MODE, publicKey, oaepParams); byte[] cipherDer = oaepFromAlgo.doFinal(keyMaterial); //Base64 encode the encrypted key material. String encryptedKeyMaterial = DatatypeConverter.printBase64Binary(cipherDer); //Import the key material. Long expireTimestamp = 1546272000L; //UNIX timestamp, precise to the second. The value 0 indicates that the key material does not expire. kmsClient.importKeyMaterial(keyId,encryptedKeyMaterial, expireTimestamp); } catch(Exception e) { //... Omitted. } } }
- Go SDK
package main import ( "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/base64" "fmt" "log" random "math/rand" "time" "github.com/aliyun/alibaba-cloud-sdk-go/services/kms" ) //Encapsulate the CreateKey operation. func kmsCreateKey(client *kms.Client) (string, error) { request := kms.CreateCreateKeyRequest() request.Scheme = "https" request.Origin = "EXTERNAL" //Create an external key. response, err := client.CreateKey(request) if err ! = nil { return "", fmt.Errorf("CreateKey error:%v", err) } return response.KeyMetadata.KeyId, nil } //Encapsulate the GetParametersForImport operation. func kmsGetParametersForImport(client *kms.Client, keyId, wrappingKeySpec, wrappingAlgorithm string) (string, string, error) { request := kms.CreateGetParametersForImportRequest() request.Scheme = "https" request.KeyId = keyId request.WrappingKeySpec = wrappingKeySpec request.WrappingAlgorithm = wrappingAlgorithm response, err := client.GetParametersForImport(request) if err ! = nil { return "", "", fmt.Errorf("GetParametersForImport error:%v", err) } return response.PublicKey, response.ImportToken, nil } //Encapsulate the ImportKeyMaterial operation. func kmsImportKeyMaterial(client *kms.Client, keyId, importToken, encryptedKeyMaterial string) error { request := kms.CreateImportKeyMaterialRequest() request.Scheme = "https" request.KeyId = keyId request.ImportToken = importToken request.EncryptedKeyMaterial = encryptedKeyMaterial _, err := client.ImportKeyMaterial(request) if err ! = nil { return fmt.Errorf("ImportKeyMaterial error:%v", err) } return nil } func randBytes(n int) []byte { var r = random.New(random.NewSource(time.Now().UnixNano())) bytes := make([]byte, n) for i := range bytes { bytes[i] = byte(r.Intn(256)) } return bytes } func main() { accessKeyId := "*** Provide your AccessKeyId ***" accessKeySecret := "*** Provide your AccessKeySecret ***" regionId := "cn-hangzhou" client, err := kms.NewClientWithAccessKey(regionId, accessKeyId, accessKeySecret) if err ! = nil { log.Fatalf("NewClientWithAccessKey error:%+v\n", err) } //Create an external key. keyId, err := kmsCreateKey(client) if err ! = nil { log.Fatalf("kmsCreateKey error:%+v\n", err) } //The following sample code is executed to generate a 32-byte random number. In actual scenarios, you need to generate a key in your own key management system. In addition, you must use the public key in the parameters that are used to import key material to encrypt the key material. keyMaterial := randBytes(32) //Obtain the parameters that are used to import key material. encryptPublicKey, importToken, err := kmsGetParametersForImport(client, keyId, "RSA_2048", "RSAES_OAEP_SHA_256") if err ! = nil { log.Fatalf("kmsGetParametersForImport error:%v\n", err) } //Base64 decode the public key. publicKeyDer, err := base64.StdEncoding.DecodeString(encryptPublicKey) if err ! = nil { log.Fatalf("base64.StdEncoding.DecodeString error:%v\n", err) } //Use RSA to parse the public key. publicKey, err := x509.ParsePKIXPublicKey(publicKeyDer) if err ! = nil { log.Fatalf("x509.ParsePKIXPublicKey error:%v\n", err) } //Encrypt the key material. cipherDer, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey.(*rsa.PublicKey), keyMaterial, nil) if err ! = nil { log.Fatalf("rsa.EncryptOAEP error:%v\n", err) } //Base64 encode the encrypted key material. encryptedKeyMaterial := base64.StdEncoding.EncodeToString(cipherDer) //Import the key material. err = kmsImportKeyMaterial(client, keyId, importToken, encryptedKeyMaterial) if err ! = nil { log.Fatalf("ImportKeyMaterial error:%v", err) } }