密钥管理服务支持离线加解密数据吗?
正常来说,密钥管理服务提供小数据加解密的公开API“encrypt-data”和“decrypt-data”。该接口的运算基于密钥管理服务,密钥管理服务对密文进行一定的包装。因此是不支持离线加解密数据的。
但是针对非对称密钥场景,密钥管理服务遵从通用规范,不会对密文进行重新包装。因此是支持公钥离线加密,私钥在线解密的。
本文提供如下示例:
使用RSA_3072主密钥,密钥用途为ENCRYPT_DECRYPT。使用公钥离线加密"hello world!",调用decrypt-data使用私钥进行解密,加解密使用的算法为"RSA/ECB/OAEPWithSHA-256AndMGF1Padding":
public class RsaEncryptDataExample { /** * 基础认证信息: * - ACCESS_KEY: 华为云账号Access Key,获取方式请参见获取AK/SK。 * - SECRET_ACCESS_KEY: 华为云账号Secret Access Key, 敏感信息,建议密文存储,获取方式请参见获取AK/SK。 * - IAM_ENDPOINT: 华为云IAM服务访问终端地址,获取方式请参见IAM终端节点。 * - KMS_REGION_ID: 华为云KMS支持的地域,,获取方式请参见地区和终端节点。 * - KMS_ENDPOINT: 华为云KMS服务访问终端地址,获取方式请参见终端节点。 * - 认证用的ak和sk直接写到代码中有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全。 * - 本示例以ak和sk保存在环境变量中来实现身份验证为例,运行本示例前请先在本地环境中设置环境变量HUAWEICLOUD_SDK_AK和HUAWEICLOUD_SDK_SK。 */ private static final String ACCESS_KEY = System.getenv("HUAWEICLOUD_SDK_AK"); private static final String SECRET_ACCESS_KEY = System.getenv("HUAWEICLOUD_SDK_SK"); private static final String IAM_ENDPOINT = "https://<IamEndpoint>"; private static final String KMS_REGION_ID = "<RegionId>"; private static final String KMS_ENDPOINT = "https://<KmsEndpoint>"; private static final String RSA_PUBLIC_KEY_BEGIN = "-----BEGIN PUBLIC KEY-----\n"; private static final String RSA_PUBLIC_KEY_END = "-----END PUBLIC KEY-----"; private static final String RSAES_OAEP_SHA_256 = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"; private static final String SHA_256 = "SHA-256"; private static final String MGF1 = "MGF1"; private static final String HELLO_WORLD = "hello world!"; public static void main(String[] args) throws Exception { final String keyId = args[0]; publicKeyEncrypt(keyId); } private static void publicKeyEncrypt(String keyId) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { // 1.准备访问华为云的认证信息 final BasicCredentials auth = new BasicCredentials() .withIamEndpoint(IAM_ENDPOINT).withAk(ACCESS_KEY).withSk(SECRET_ACCESS_KEY); // 2.初始化SDK,传入认证信息及KMS访问终端地址 final KmsClient kmsClient = KmsClient.newBuilder() .withRegion(new Region(KMS_REGION_ID, KMS_ENDPOINT)).withHttpConfig(new HttpConfig() .withIgnoreSSLVerification(true)).withCredential(auth).build(); // 3.获取公钥信息,返回的是PKCS8格式 final ShowPublicKeyRequest showPublicKeyRequest = new ShowPublicKeyRequest() .withBody(new OperateKeyRequestBody().withKeyId(keyId)); final ShowPublicKeyResponse showPublicKeyResponse = kmsClient.showPublicKey(showPublicKeyRequest); // 4.获取公钥字符串 final String publicKeyStr = showPublicKeyResponse.getPublicKey().replace(RSA_PUBLIC_KEY_BEGIN, "") .replaceAll("\n", "").replace(RSA_PUBLIC_KEY_END, ""); // 5.获取公钥二进制 final X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyStr)); final KeyFactory keyFactory = KeyFactory.getInstance("RSA", new BouncyCastleProvider()); final PublicKey publicKey = keyFactory.generatePublic(keySpec); // 6.公钥离线加密字符串"hello world!" final Cipher cipher = Cipher.getInstance(RSAES_OAEP_SHA_256); final OAEPParameterSpec oaepParameterSpec = new OAEPParameterSpec(SHA_256, MGF1, new MGF1ParameterSpec(SHA_256), PSource.PSpecified.DEFAULT); cipher.init(Cipher.ENCRYPT_MODE, publicKey, oaepParameterSpec); final byte[] cipherData = cipher.doFinal(HELLO_WORLD.getBytes(StandardCharsets.UTF_8)); // 7.私钥在线解密 final DecryptDataRequest decryptDataRequest = new DecryptDataRequest() .withBody(new DecryptDataRequestBody().withKeyId(keyId) .withEncryptionAlgorithm(DecryptDataRequestBody.EncryptionAlgorithmEnum.RSAES_OAEP_SHA_256) .withCipherText(Base64.getEncoder().encodeToString(cipherData))); final DecryptDataResponse decryptDataResponse = kmsClient.decryptData(decryptDataRequest); assert HELLO_WORLD.equals(decryptDataResponse.getPlainText()); } }