文档首页/ 数据加密服务 DEW/ 常见问题/ 密钥管理类/ 如何使用非对称密钥对公钥对签名结果进行验签?
更新时间:2023-12-12 GMT+08:00
分享

如何使用非对称密钥对公钥对签名结果进行验签?

在公私钥对的使用场景中,通常使用私钥进行签名,使用公钥进行验签。公钥可以分发给需要使用的业务主体,业务主体对关键数据进行验签。密钥管理服务提供获取公钥的接口get-publickey。

本示例使用RSA_3072主密钥,密钥用途为SIGN_VERIFY。通过调用密钥管理服务sign接口。请求体如下:

{
 "key_id": "key_id_value",
 "message": "MTIzNA==",
 "signing_algorithm": "RSASSA_PSS_SHA_256",
 "message_type": "RAW"
}

获取的结果如下:

{
 "key_id": "key_id_value",
 "signature": "xxx"
}

通过get-publickey获取公钥后,对signature进行验签。

public class RawDataVerifyExample {

    /**
     * 基础认证信息:
     * - ACCESS_KEY: 华为云账号Access Key
     * - SECRET_ACCESS_KEY: 华为云账号Secret Access Key, 敏感信息,建议密文存储
     * - IAM_ENDPOINT: 华为云IAM服务访问终端地址,详情见https://developer.huaweicloud.com/endpoint?IAM
     * - KMS_REGION_ID: 华为云KMS支持的地域,详情见https://developer.huaweicloud.com/endpoint?DEW
     * - KMS_ENDPOINT: 华为云KMS服务访问终端地址,详情见https://developer.huaweicloud.com/endpoint?DEW
     */
    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 int SALT_LENGTH = 32;
    private static final int TRAILER_FIELD = 1;
    public static final String RSA_PUBLIC_KEY_BEGIN = "-----BEGIN PUBLIC KEY-----\n";
    public static final String RSA_PUBLIC_KEY_END = "-----END PUBLIC KEY-----";

    // 示例签名数据,BASE64编码格式,原文信息1234
    private static final String RWA_DATA = "MTIzNA==";

    // 通过密钥管理服务sign接口获取的签名值
    private static final String SIGN = "xxx";
    public static void main(String[] args) throws Exception {

        final String keyId = args[0];

        publicKeyVerify(keyId);
    }
   public static void publicKeyVerify(String keyId) throws Exception {

        // 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.获取公钥信息,返回的是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.进行验签
        final Signature signature = getSignature();
        signature.initVerify(publicKey);
        signature.update(commonHash(Base64.getDecoder().decode(RWA_DATA)));

        // 7.验签结果
        assert signature.verify(Base64.getDecoder().decode(SIGN));

    }
    private static Signature getSignature() throws Exception {
        Signature signature= Signature.getInstance("NONEwithRSASSA-PSS", new BouncyCastleProvider());
        MGF1ParameterSpec mgfParam = new MGF1ParameterSpec("SHA256");
        PSSParameterSpec pssParam = new PSSParameterSpec("SHA256", "MGF1", mgfParam, SALT_LENGTH, TRAILER_FIELD);
        signature.setParameter(pssParam);
        return signature;
    }
    private static byte[] commonHash(byte[] data) {
        byte[] digest;
        try {
            MessageDigest md = MessageDigest.getInstance("SHA256", BouncyCastleProvider.PROVIDER_NAME);
            md.update(data);
            digest = md.digest();
        } catch (Exception e) {
            throw new RuntimeException("Digest failed.");
        }
        return digest;
    }
}

相关文档