文档

导入非对称密钥材料

更新时间:
重要

本文中含有需要您注意的重要提示信息,忽略该信息可能对您的业务造成影响,请务必仔细阅读。

当创建密钥材料来源为外部的非对称密钥时,KMS不会生成密钥材料,您需要导入自己的密钥材料。本文介绍如何为非对称密钥导入密钥材料。

背景信息

密钥是KMS的基本资源,由密钥ID、基本元数据(如密钥状态等)以及密钥材料组成。创建密钥时,您可以选择由KMS生成密钥材料,也可以选择外部来源的密钥材料。如果选择了外部来源的密钥材料,您需要将外部密钥材料导入到密钥中。

不同KMS密钥管理类型对导入密钥材料的支持情况,请参见下表。关于密钥管理类型的更多信息,请参见密钥管理类型和密钥规格

  • 对:表示支持导入相应的密钥材料。

  • 错:表示不支持导入相应的密钥材料。

密钥管理类型

导入对称密钥材料

导入非对称密钥材料

默认密钥

  • 主密钥:对

  • 服务密钥:错

  • 主密钥:错

  • 服务密钥:错

软件密钥

错

错

硬件密钥

对

对

使用限制

为密钥首次导入密钥材料后,密钥即和该密钥材料绑定,不再支持导入其他密钥材料。

重要

如果密钥的密钥材料过期,您可以为该密钥再次导入相同的密钥材料,使得该密钥再次可用,因此请妥善保管密钥材料。

前提条件

已购买和启用KMS硬件密钥管理实例。具体操作,请参见购买和启用KMS实例

通过控制台导入密钥材料

步骤一:创建非对称密钥

导入密钥材料前,请创建密钥材料来源为外部的非对称密钥。

  1. 登录密钥管理服务控制台,在顶部菜单栏选择地域后,在左侧导航栏单击资源 > 密钥管理

  2. 用户主密钥页签,实例ID选择硬件密钥管理实例,单击创建密钥

  3. 创建密钥面板,完成配置项设置,然后单击确定

    配置项

    说明

    密钥类型

    选择非对称密钥。

    密钥规格

    密钥的规格。

      • 对称密钥规格:Aliyun_AES_256、Aliyun_AES_192、Aliyun_AES_128、Aliyun_SM4

      • 非对称密钥规格:RSA_2048、RSA_3072、RSA_4096、EC_P256、EC_P256K、EC_SM2

    密钥用途

    密钥的用途。取值:

    • Encrypt/Decrypt:数据加密和解密。

    • Sign/Verify:产生和验证数字签名。

    密钥别名

    密钥的别名标识符。支持英文字母、数字、下划线(_)、短划线(-)和正斜线(/)。

    标签

    密钥的标签,方便您对密钥进行分类管理。每个标签由一个键值对(Key:Value)组成,包含标签键(Key)、标签值(Value)。

    说明
    • 标签建和标签值的格式:最多支持128个字符,可以包含英文大小写字母、数字、正斜线(/)、反斜线(\)、下划线(_)、短划线(-)、半角句号(.)、加号(+)、等于号(=)、半角冒号(:)、字符at(@)。

    • 标签键不能以aliyun或acs:开头。

    • 每个密钥最多可以设置20个标签键值对。

    描述信息

    密钥的说明信息。

    高级选项

    • 密钥材料来源:选择外部

      说明

      请仔细阅读并选中我了解使用外部密钥材料的方法和意义

    • 附加密钥用途:根据业务需要配置。

步骤二:下载公钥和导入令牌

导入密钥材料的参数包含公钥和导入令牌,公钥用于加密密钥材料,导入令牌用于导入密钥材料。

  1. 定位到目标密钥,单击操作列的详情,在密钥详情页面的密钥材料区域,单击获取导入参数

  2. 获取导入密钥材料的参数对话框,选择公钥类型加密算法后,单击下一步

    • 密钥规格为RSA_2048RSA_3072RSA_4096EC_P256EC_P256K时:公钥类型为RSA_2048,加密算法RSAES_OAEP_SHA_256_AES_256_ECB_PKCS7_PAD。

    • 密钥规格为EC_SM2时,公钥类型取值为EC_SM2加密算法SM2PKE_SM4_ECB

  3. 下载公钥以及导入令牌,并妥善保存。

    • 公钥格式

      • der格式:下载后文件名默认为publickey_key-******.bin。

      • pem格式:下载后文件名默认为publickey_key-******.pem。

    • 导入令牌:下载后文件名默认为token_key-******.txt。

      说明

      导入令牌的有效期为24小时,在有效期内可以重复使用,失效以后需要获取新的导入令牌和公钥。

步骤三:加密密钥材料

请在您的系统环境中生成并加密密钥材料,过程中会使用到以下密钥,具体说明请参见下表。

密钥

用途

提供者

标记说明

目标非对称密钥TAK(Target Asymmetric Key)

待导入的目标非对称密钥。

您的系统环境或者工具(如线下的密钥管理设施KMI,或者线下的硬件安全模块HSM)。

  • TAKpub:公钥部分

  • TAKpriv:私钥部分

加密密钥IWK(Import Wrapping Key)

用于导入TAK的加密密钥。

阿里云KMS。

  • IWKpub:公钥部分

    说明

    即您在密钥管理服务控制台下载的公钥。

  • IWKpriv:私钥部分

瞬时密钥ESK(Ephemeral Symmetric Key)

一个瞬时存在的对称密钥,用于直接加密TAKpriv。

源环境的系统或者工具,在完成对TAK的导出操作后请立即销毁。

不涉及

  1. 创建一个目标非对称密钥私钥(TAKpriv),密钥规格与您创建非对称密钥时选择的密钥规格一致。如果您已有目标非对称密钥私钥(TAKpriv),请跳过本步骤。

    说明

    TAKpriv格式需要遵循:RSA私钥根据RFC3447进行编码,ECC私钥根据RFC5915进行编码,然后根据RFC5208包装为PKCS#8格式。

  2. 创建一个瞬时密钥(ESK)。

  3. 使用加密密钥公钥(IWKpub)来加密瞬时密钥(ESK),得到瞬时密钥密文(Cipher(ESK))。

  4. 使用瞬时密钥(ESK)加密目标非对称密钥私钥(TAKpriv),得到目标非对称密钥的私钥密文(Cipher(TAKpriv))。

  5. 按照Cipher(ESK)||Cipher(TAKpriv)格式组装结果数据,得到加密后的密钥材料。

示例一:使用GMSSL生成SM2算法的密钥材料。

  1. 创建一个SM2算法的目标非对称密钥私钥(TAKpriv),并获取私钥的椭圆曲线的参数D。

    #生成SM2私钥。
    gmssl ecparam -name sm2p256v1 -genkey -outform DER -out TakSm2Priv.bin
    #查看私钥的D值。
    gmssl asn1parse -inform DER -in TakSm2Priv.bin
    
    #将D值写入文件。
    echo 'CB55E5ECC20BF7E9249ADEDE990EF141D14252E024734EB058A6B9F103F12A04' | xxd -r -p > TakSm2D.bin
  2. 创建一个SM4算法的瞬时密钥(ESK)。

    gmssl rand -out EskSm4.bin 16
  3. 使用加密密钥公钥(IWKpub),采用SM2算法加密瞬时密钥(ESK),得到瞬时密钥密文(Cipher(ESK))。

    gmssl sm2utl -encrypt -in EskSm4.bin -pubin -inkey PublicKey.pem -out CipherEsk.bin
    说明

    请将PublicKey.pem替换为您在密钥管理服务控制台下载的公钥文件的名称。

  4. 使用瞬时密钥(ESK)加密目标非对称密钥私钥(TAKpriv)的椭圆曲线参数D ,生成目标非对称密钥的私钥密文(Cipher(TAKpriv))。其中加密模式为ECB,填充模式为NoPadding。

    xxd -l 16  -c 16 -ps EskSm4.bin | xargs -I {} openssl enc -sms4-ecb -e  -K {} -in 
    TakSm2D.bin -nosalt -nopad -out CipherTakPriv.bin
  5. 按照Cipher(ESK) || Cipher(TAKpriv)格式组装结果数据,得到加密后的密钥材料。

    cat CipherEsk.bin CipherTakPriv.bin > EncryptedKeyMaterial.bin

示例二:使用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),得到瞬时密钥密文(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替换为您在密钥管理服务控制台下载的公钥文件的名称。

  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的密钥材料文件。

步骤四:导入密钥材料

在密钥详情页面,单击导入密钥材料,在导入打包后的密钥材料对话框,完成各项配置后,单击确定

配置项

说明

打包后的密钥材料

上传步骤三:加密密钥材料中生成的密钥材料文件。

导入令牌

上传步骤二:下载公钥和导入令牌中下载的令牌文件。

导入密钥材料成功后,密钥状态从待导入更新为启用中

通过SDK导入密钥材料

您也可以通过KMS Java SDK在KMS中创建RSA、ECC和SM2算法的密钥,并导入密钥材料。Java代码示例如下。

说明

阿里云账号AccessKey拥有所有API的访问权限,建议您使用RAM用户进行API访问或日常运维。强烈建议不要把AccessKey ID和AccessKey Secret保存到工程代码里,否则可能导致AccessKey泄露,威胁您账号下所有资源的安全。

本示例以将AccessKey配置在环境变量ALIBABA_CLOUD_ACCESS_KEY_ID和ALIBABA_CLOUD_ACCESS_KEY_SECRET的方式来实现身份验证为例。更多认证信息配置方式,请参见Credentials 设置

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) {
        /**
         * Construct an Aliyun Client:
         * Set RegionId, AccessKeyId and 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();
            //生成瞬时对称密钥。
            byte[] ephemeralSymmetricKeyPlaintext = this.generateEphemeralSymmetricKey(ephemeralKeySpec);
            //生成目标非对称密钥。
            byte[] targetAsymmetricKeyPlaintext = this.generateTargetAsymmetricKey(targetKeySpec);
            //使用加密公钥加密瞬时对称密钥。
            byte[] ephemeralSymmetricKeyCipher = this.encryptEphemeralSymmetricKey(publicKeyBase64,
                wrappingAlgorithm, ephemeralSymmetricKeyPlaintext);
            //使用瞬时对称密钥加密目标非对称密钥。
            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);
            //导入密钥材料到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.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 {
       //瞬时对称密钥是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;
    }
}
            

常见问题

是否支持删除密钥材料?

由于密钥材料导入到密码机集群中,因此不支持删除密钥材料,仅当您计划删除密钥时,随密钥一同删除。

警告

密钥删除后将无法恢复,使用该密钥加密的内容及产生的数据密钥也将无法解密。因此建议您先禁用密钥,确认不再使用后再计划删除密钥。关于如何禁用密钥,请参见禁用密钥

计划删除密钥的操作,请参见计划删除密钥ScheduleKeyDeletion

如何判断密钥材料是由外部导入还是由KMS生成?

  • 方式一:在密钥管理服务控制台查看。

    密钥管理页面,单击用户主密钥页签,选择实例ID后定位到目标密钥,单击操作列的详情,在详情页面查看密钥材料来源

  • 方式二:通过调用DescribeKey接口查看。

    如果Origin值为EXTERNAL,说明密钥材料由外部导入。如果Origin值为Aliyun_KMS,说明密钥材料由KMS生成。

如何轮转使用外部密钥材料的密钥?

对外部导入密钥材料的密钥,KMS不提供定期自动轮转功能。如果您需要轮转,只能创建一个新的密钥然后导入新的密钥材料。

相关文档

  • 本页导读 (1)
文档反馈