使用非对称密钥
更新时间:2023-03-07
相比对称加密,非对称密钥通常用于在信任程度不对等的系统之间,实现数字签名验签或者加密传递敏感信息的目的。
创建非对称密钥
- 点击 创建密钥 按钮,选择 密钥类型,选择 密钥材质,填写 密钥描述,即可完成对称用户主密钥( Customer Master Key,以下简称 CMK )的创建。
算法类型
目前 KMS 支持的非对称加密算法类型如下:
算法 长度 规格 保护级别 RSA 1024 RSA_1024 HSM RSA 2048 RSA_2048 HSM RSA 4096 RSA_4096 HSM SM2 256 SM2_256 HSM 密钥材质
创建 CMK 所必须的内容,支持 KMS生成 以及 外部导入 两种方式。
- KMS生成 :自动为用户创建密钥材料,并使用密钥材质生成 CMK。
- 外部导入 :创建一个待导入的 CMK,需要用户将自己的密钥材质导入到 CMK 后方可正常使用。只有 RSA_1024 / RSA_2048 / RSA_4096 / SM2_256 这四种规格支持自主密钥材质的导入。
导入非对称密钥材质
- 先创建一个密钥材质类型为外部导入的对称密钥,点击 获取密钥参数 。
- 点击 确认,生成 加密公钥 和 令牌 。令牌有效期为24小时。
- 获取 加密公钥 和 令牌 后,使用正确的加密密钥材料加密您的信封密钥,形成信封密钥密文。并将公钥材料和通过信封密钥加密的私钥材料以及获取的令牌正确填入,点击确认即可导入。
- 导入成功后,CMK 的状态会从 待导入 变更为 已启用 。
导入非对称密钥(RSA_1024)过程示例
通过控制台导入
- 在控制台创建一个待导入的 RSA_1024 密钥。
- 点击获取密钥参数,获取密钥参数文件。如果是第一次创建,加密公钥和令牌为空,直接确认,获取导入密钥参数文档。
- 准备一个对称密钥,用来处理要导入的非对称密钥。
说明:
- 对称密钥为 AES 128bit ECB加密模式,用于加密您非对称密钥私钥的各二进制分量。
- 处理待导入密钥
- 使用步骤3准备的对称密钥来对待导入的 RSA_1024 密钥的私钥各分量进行加密,并转化为 base64 加密的字符串。公钥直接 base64 加密处理。
名称 | 处理方法 |
---|---|
公钥 | 进行base64加密 |
密钥材料-D密文 | 使用对称密钥(AES 128 ECB)对D分量二进制进行加密,然后进行 base64 加密 |
密钥材料-P密文 | 使用对称密钥(AES 128 ECB)对P分量二进制进行加密,然后进行 base64 加密 |
密钥材料-Q密文 | 使用对称密钥(AES 128 ECB)对Q分量二进制进行加密,然后进行 base64 加密 |
密钥材料-Dp密文 | 使用对称密钥(AES 128 ECB)对Dp分量二进制进行加密,然后进行 base64 加密 |
密钥材料-Dq密文 | 使用对称密钥(AES 128 ECB)对Dq分量二进制进行加密,然后进行 base64 加密 |
密钥材料-Qinv密文 | 使用对称密钥(AES 128 ECB)对Qinv分量二进制进行加密,然后进行 base64 加密 |
- 使用下载的密钥参数中的公钥对步骤3准备的对称密钥进行加密,得到信封密钥密文。
echo "11223344556677881122334455667788"|xxd -ps -r > KeyMaterial.bin
cat public_key_xxxxxxx.txt |xxd -ps -r > PublicKey.bin
openssl rsautl -encrypt -in KeyMaterial.bin -pkcs -inkey PublicKey.bin -keyform DER -pubin -out EncryptedKeyMaterial.bin
openssl enc -e -base64 -A -in EncryptedKeyMaterial.bin -out EncryptedKeyMaterial_base64.txt
- 点击确认,完成导入。
通过 JAVA SDK 导入
- 代码示例
import com.baidubce.BceClientException;
import com.baidubce.BceServiceException;
import com.baidubce.Protocol;
import com.baidubce.auth.DefaultBceCredentials;
import com.baidubce.services.kms.KmsClient;
import com.baidubce.services.kms.KmsClientConfiguration;
import com.baidubce.services.kms.model.*;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Random;
public class testImportRSA1024 {
public static void main(String[] args){
String ACCESS_KEY_ID = "<AK>";
String SECRET_ACCESS_KEY = "<SK>";
String ENDPOINT = "https://bkm.bj.baidubce.com"; // kms域名
// 初始化一个KmsClient
KmsClientConfiguration config = new KmsClientConfiguration();
config.setCredentials(new DefaultBceCredentials(ACCESS_KEY_ID, SECRET_ACCESS_KEY));
config.setEndpoint(ENDPOINT);
config.setProtocol(Protocol.HTTPS); // 设置https协议
KmsClient client = new KmsClient(config);
try {
//产生一个16字节随机数作为信封密钥
byte[] keyMaterial = new byte[16];
new Random().nextBytes(keyMaterial);
//创建一个RSA_1024待导入密钥
CreateKeyRequest createReq = new CreateKeyRequest();
createReq.setKeySpec("RSA_1024");
createReq.setKeyUsage("ENCRYPT_DECRYPT");
createReq.setOrigin("EXTERNAL");
createReq.setProtectedBy("HSM");
CreateKeyResponse createRes = client.createKey(createReq);
String keyId = createRes.getKeyMetadata().getKeyId();
GetParametersForImportResponse getParametersRes = client
.getParametersForImport(new GetParametersForImportRequest(keyId,"BASE64"));
String pubKey = getParametersRes.getPublicKey();
String token = getParametersRes.getImportToken();
byte[] publicKeyDer = DatatypeConverter.parseBase64Binary(pubKey);
//解析成RSA的公钥
KeyFactory keyFact = KeyFactory.getInstance("RSA");
X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKeyDer);
PublicKey publicKey = keyFact.generatePublic(spec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] cipherDer = cipher.doFinal(keyMaterial);
//加密后的信封密钥,需要进行base64编码
String encryptedKeyMaterial = DatatypeConverter.printBase64Binary(cipherDer);
cipher = Cipher.getInstance("AES/ECB/NoPadding");
Key key = new SecretKeySpec(keyMaterial, "AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
//待导入的RSA密钥各分量(16进制表示)
String publickDerHex = "30818902818100b985d0d957e8c17c3d2ed1a0e6d522dbf3a5812429aacaf1a0cc5171"
+"12d9927d58166bc06ce14481a443d0545751065f4220f2a3d03c553ebb4fd5f7849a2a574d0f92a3518a6ccc96f41092deca64dcf"
+"8101edaefdf8597bcb30f74a93f82c203ac3d571a7073101c3b2fc7bd27060ef90245d5fe54356524a72ae13bac91470203010001";
String D = "43b683b3d05233cc94c831daf8657283b53a03189fdca695ea8aa86f0ce23c8563514ba2c01ab856590e274ba15301706342834d2"
+"703de593724bc83caf239e1643663fcb5490d623fa8fb325aefb5a6a954625af99ebc05c72c58f613bc0e822d77ee061223bc66d95a0d977a17a60eae8d4520f"
+"c8f335b2648f40400540c01";
String P = "dc7dd1239889ca4f702f46563611b4495c643538b5136f064b834e865902513804f90c46903001bf23"
+"5a1cc847a347609d7dbcb0b6a064a8d7180fe931b3bae1";
String Q = "d766585371b4bf7a717ab2ffa20565d95009a02e00a4d07bd4fec73da1b9a8bd3cec173aa9a78b0f53a"
+"019d4bd19eb229411c46995f4b71c439554b5618f3927";
String DP = "653e8ca2e8af14aba75abdd4665d78c85ad954aae652b71f4fdb4a5a5c52b9129d0df2ba10094b3406"
+"3aa18ec17e530f2522105ba07043e85764202237054d61";
String DQ = "9f8425a9362ddb17bc6e579d44c9a69176da8a0b4762c71acdb418ad25d5ae86e6551926d279475c845"
+"bae8583bd6c0ae188fee20ab17de1aa932e765cd78a45";
String Qinv = "25f1e8ea900548e3b9664e5c3719a2ba34155fdafb4b2f70cebcffddc6bcdd4815515694b916b2234"
+"314bd6be97edee735afef8e535461b608f6e4427a052381";
String publicDerBase64 = DatatypeConverter.printBase64Binary(DatatypeConverter.parseHexBinary(publickDerHex));
System.out.println("publicDerBase64:"+publicDerBase64);
String DBase64 = DatatypeConverter.printBase64Binary(cipher.doFinal(DatatypeConverter.parseHexBinary(D)));
System.out.println("DBase64:"+DBase64);
String PBase64 = DatatypeConverter.printBase64Binary(cipher.doFinal(DatatypeConverter.parseHexBinary(P)));
System.out.println("DBase64:"+DBase64);
String QBase64 = DatatypeConverter.printBase64Binary(cipher.doFinal(DatatypeConverter.parseHexBinary(Q)));
System.out.println("DBase64:"+QBase64);
String DPBase64 = DatatypeConverter.printBase64Binary(cipher.doFinal(DatatypeConverter.parseHexBinary(DP)));
System.out.println("DBase64:"+DPBase64);
String DQBase64 = DatatypeConverter.printBase64Binary(cipher.doFinal(DatatypeConverter.parseHexBinary(DQ)));
System.out.println("DBase64:"+DQBase64);
String QinvBase64 = DatatypeConverter.printBase64Binary(cipher.doFinal(DatatypeConverter.parseHexBinary(Qinv)));
System.out.println("DBase64:"+QinvBase64);
//初始化RSA导入密钥请求
ImportAsymmetricKeyRequest importReq = new ImportAsymmetricKeyRequest();
importReq.setKeyId(keyId);
importReq.setImportToken(token);
importReq.setAsymmetricKeySpec("RSA_1024");
importReq.setEncryptedKeyEncryptionKey(encryptedKeyMaterial);
importReq.setAsymmetricKeyUsage("ENCRYPT_DECRYPT");
EncryptedRsaKey rsaKey = new EncryptedRsaKey();
rsaKey.setPublicKeyDer(publicDerBase64);
rsaKey.setEncryptedD(DBase64);
rsaKey.setEncryptedP(PBase64);
rsaKey.setEncryptedQ(QBase64);
rsaKey.setEncryptedDp(DPBase64);
rsaKey.setEncryptedDq(DQBase64);
rsaKey.setEncryptedQinv(QinvBase64);
importReq.setEncryptedRsaKey(rsaKey);
//导入RSA密钥
KmsResponse res = client.importAsymmetricKey(importReq);
}catch (BceServiceException e) {
System.out.println(e.getMessage());
} catch (BceClientException e) {
System.out.println(e.getMessage());
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
导入非对称密钥(SM2_256)过程示例
通过控制台导入
- 在控制台创建一个待导入的 RSA_1024 密钥。
- 点击获取密钥参数,获取密钥参数文件。如果是第一次创建,加密公钥和令牌为空,直接确认,获取导入密钥参数文档。
- 准备一个对称密钥,用来处理要导入的非对称密钥。
说明:
- 对称密钥为 AES 128bit ECB加密模式,用于加密您非对称密钥私钥的各二进制分量。
- 处理待导入密钥
- 使用步骤3准备的对称密钥来对待导入的 SM2_256 密钥的私钥进行加密,并转化为 base64 加密的字符串。公钥直接 base64 加密处理。
名称 | 处理方法 |
---|---|
公钥 | 进行base64加密 |
私钥 | 使用对称密钥(AES 128bit ECB加密模式)进行加密,然后进行base64加密 |
- 使用下载的密钥参数中的公钥对步骤3准备的对称密钥进行加密,得到信封密钥密文。
echo "11223344556677881122334455667788"|xxd -ps -r > KeyMaterial.bin
cat public_key_xxxxxxx.txt |xxd -ps -r > PublicKey.bin
openssl rsautl -encrypt -in KeyMaterial.bin -pkcs -inkey PublicKey.bin -keyform DER -pubin -out EncryptedKeyMaterial.bin
openssl enc -e -base64 -A -in EncryptedKeyMaterial.bin -out EncryptedKeyMaterial_base64.txt
- 点击确认,完成导入。
通过 JAVA SDK 导入
- 代码示例
import com.baidubce.BceClientException;
import com.baidubce.BceServiceException;
import com.baidubce.Protocol;
import com.baidubce.auth.DefaultBceCredentials;
import com.baidubce.services.kms.KmsClient;
import com.baidubce.services.kms.KmsClientConfiguration;
import com.baidubce.services.kms.model.*;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Random;
public class testImportSM2256 {
public static void main(String[] args){
String ACCESS_KEY_ID = "<AK>";
String SECRET_ACCESS_KEY = "<SK>";
String ENDPOINT = "https://bkm.hb-fsg.baidubce.com"; // 用户自己指定的域名
// 初始化一个KmsClient
KmsClientConfiguration config = new KmsClientConfiguration();
config.setCredentials(new DefaultBceCredentials(ACCESS_KEY_ID, SECRET_ACCESS_KEY));
config.setEndpoint(ENDPOINT);
config.setProtocol(Protocol.HTTPS); // 设置https协议
KmsClient client = new KmsClient(config);
try {
//产生一个16字节随机数作为信封密钥
byte[] keyMaterial = new byte[16];
new Random().nextBytes(keyMaterial);
//创建一个SM2_256待导入密钥
CreateKeyRequest createReq = new CreateKeyRequest();
createReq.setKeySpec("SM2_256");
createReq.setKeyUsage("ENCRYPT_DECRYPT");
createReq.setOrigin("EXTERNAL");
createReq.setProtectedBy("HSM");
CreateKeyResponse createRes = client.createKey(createReq);
String keyId = createRes.getKeyMetadata().getKeyId();
GetParametersForImportResponse getParametersRes = client
.getParametersForImport(new GetParametersForImportRequest(keyId,"BASE64"));
String pubKey = getParametersRes.getPublicKey();
String token = getParametersRes.getImportToken();
byte[] publicKeyDer = DatatypeConverter.parseBase64Binary(pubKey);
//解析成RSA的公钥
KeyFactory keyFact = KeyFactory.getInstance("RSA");
X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKeyDer);
PublicKey publicKey = keyFact.generatePublic(spec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] cipherDer = cipher.doFinal(keyMaterial);
//加密后的信封密钥,需要进行base64编码
String encryptedKeyMaterial = DatatypeConverter.printBase64Binary(cipherDer);
cipher = Cipher.getInstance("AES/ECB/NoPadding");
Key key = new SecretKeySpec(keyMaterial, "AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
String publickDerHex = "3059301306072a8648ce3d020106082a811ccf5501822d0342000449451af193e9bd4d7d4329504a9f"
+"3a3bd9981318b8177535b02d02b361b579cda9d5eb0feb9980ed41cd159ef7036f5cacd7e018bacb5ec854d3f575fdcc6182";
String privatekeyHex = "c227a82bf3ae6819d9f1d8179e9bbb5f2ce7f49acb1a64b0f6d1698b5ac0a160";
String publicDerBase64 = DatatypeConverter.printBase64Binary(DatatypeConverter.parseHexBinary(publickDerHex));
System.out.println("publicDerBase64:"+publicDerBase64);
String privatekeyBase64 = DatatypeConverter.printBase64Binary(cipher
.doFinal(DatatypeConverter.parseHexBinary(privatekeyHex)));
System.out.println("DBase64:"+privatekeyBase64);
//初始化SM2导入密钥请求
ImportAsymmetricKeyRequest importReq = new ImportAsymmetricKeyRequest();
importReq.setKeyId(keyId);
importReq.setImportToken(token);
importReq.setAsymmetricKeySpec("SM2_256");
importReq.setEncryptedKeyEncryptionKey(encryptedKeyMaterial);
importReq.setAsymmetricKeyUsage("ENCRYPT_DECRYPT");
EncryptedSm2Key sm2Key = new EncryptedSm2Key();
sm2Key.setEncryptedPrivateKey(privatekeyBase64);
sm2Key.setPublicKeyDer(publicDerBase64);
importReq.setEncryptedSm2Key(sm2Key);
//导入SM2密钥
KmsResponse res = client.importAsymmetricKey(importReq);
}catch (BceServiceException e) {
System.out.println(e.getMessage());
} catch (BceClientException e) {
System.out.println(e.getMessage());
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}