如何使用KMS对文件进行完整性保护
应用场景
当有大量文件(例如:镜像、电子保单或者重要文件等)需要在传输或者存储时确保安全性,用户可以使用KMS对文件摘要进行签名,再次使用时可以重新计算摘要进行验签。确保文件在传输或者存储过程中没有被篡改。
解决方案
用户需要在KMS中创建一个用户主密钥。
用户计算文件的摘要,调用KMS的“sign”接口对摘要进行签名。用户得到摘要的签名结果。将摘要签名结果和密钥ID与文件一同传输或者存储。签名流程如图 签名流程所示。
用户需要使用文件时,先进行完整性校验,确保文件未被篡改。
用户重新计算文件的摘要,连同签名值调用KMS的“verify”接口对摘要进行验签。用户得到验签结果。如果能正常验签,则表明文件未被篡改。验签流程如图 验签流程所示。
操作步骤
- 获取AK/SK:
- 获取region相关信息:
- 使用KMS对文件进行签名并验签。
public class FileStreamSignVerifyExample { /** * 基础认证信息: * - ACCESS_KEY: 华为云账号Access Key * - SECRET_ACCESS_KEY: 华为云账号Secret Access Key, 敏感信息,建议密文存储 * - IAM_ENDPOINT: 华为云IAM服务访问终端地址,详情见终端节点 * - KMS_REGION_ID: 华为云KMS支持的地域,详情见KMS地域KMS支持地域 * - KMS_ENDPOINT: 华为云KMS服务访问终端地址,详情见终端地址终端地址 */ 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>"; public static void main(String[] args) { // 用户主密钥ID,需要选择密钥及用途包含SIGN_VERIFY的密钥 final String keyId = args[0]; signAndVerifyFile(keyId); } /** * 使用KMS对文件进行签名和验签 * * @param keyId 用户主密钥ID */ static void signAndVerifyFile(String keyId) { // 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)).withCredential(auth).build(); // 3.准备待签名的文件 // inFile 待签名的文件 final File inFile = new File("FirstSignFile.iso"); final String fileSha256Sum = getFileSha256Sum(inFile); // 4.计算摘要,需要根据密钥类型,选择合适的签名算法 final SignRequest signRequest = new SignRequest().withBody( new SignRequestBody().withKeyId(keyId).withSigningAlgorithm(SignRequestBody.SigningAlgorithmEnum.RSASSA_PSS_SHA_256) .withMessageType(SignRequestBody.MessageTypeEnum.DIGEST).withMessage(fileSha256Sum)); final SignResponse signResponse = kmsClient.sign(signRequest); // 5.验证摘要 final ValidateSignatureRequest validateSignatureRequest = new ValidateSignatureRequest().withBody( new VerifyRequestBody().withKeyId(keyId).withMessage(fileSha256Sum).withSignature(signResponse.getSignature()) .withSigningAlgorithm(VerifyRequestBody.SigningAlgorithmEnum.RSASSA_PSS_SHA_256) .withMessageType(VerifyRequestBody.MessageTypeEnum.DIGEST)); final ValidateSignatureResponse validateSignatureResponse = kmsClient.validateSignature(validateSignatureRequest); // 6.比对摘要结果 assert validateSignatureResponse.getSignatureValid().equalsIgnoreCase("true"); } /** * 计算文件SHA256摘要 * * @param file 文件 * @return SHA256摘要, Base64格式 */ static String getFileSha256Sum(File file) { int length; MessageDigest sha256; byte[] buffer = new byte[1024]; try { sha256 = MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e.getMessage()); } try (FileInputStream inputStream = new FileInputStream(file)) { while ((length = inputStream.read(buffer)) != -1) { sha256.update(buffer, 0, length); } return Base64.getEncoder().encodeToString(sha256.digest()); } catch (IOException e) { throw new RuntimeException(e.getMessage()); } } }