How to verify signature authenticity that was signed using google KMS (Asymmetric sign, Elliptic Curve P-256 key SHA256 Digest) in C#

Viewed 172

I have some string data which I signed with google key defined by Algorithm: Elliptic Curve P-256 key, SHA256 Digest. I wrote a program that should verify that the data and the signature (that was returned from KMS after the signing) and the public key are valid.

The problem is that I always get false.

For convenience, here is the code that signs the data using google KMS. I use Google.Cloud.Kms.V1, KeyManagementServiceClient and call method AsymmetricSign that returns the signature:

 public byte[] SignAsymmetric(string keyId, string message)
        {
            //Create the client.
            KeyManagementServiceClient client;
            GoogleCredential credential = CredentialManager.GetCredential();

            if (credential != null)
            {
                client = new KeyManagementServiceClientBuilder { ChannelCredentials = credential.ToChannelCredentials() }.Build();
            }
            else
            {
                client = new KeyManagementServiceClientBuilder().Build();
            }

            //get key enabled version
            CryptoKeyName name = new CryptoKeyName(_projectId, _locationId, _keyRingId, keyId);
            string cryptoKeyVersionId = client.ListCryptoKeyVersions(name).Where(s => s.State == CryptoKeyVersionState.Enabled).First().CryptoKeyVersionName.CryptoKeyVersionId;

            // Build the key version name.
            CryptoKeyVersionName keyVersionName = new CryptoKeyVersionName(_projectId, _locationId, _keyRingId, keyId, cryptoKeyVersionId);

            // Convert the message into bytes. Cryptographic plaintexts and
            // ciphertexts are always byte arrays.
            byte[] plaintext = Encoding.ASCII.GetBytes(message);

            // Calculate the digest.
            SHA256 sha256 = SHA256.Create();
            byte[] hash = sha256.ComputeHash(plaintext);

            // Build the digest.
            //
            // Note: Key algorithms will require a varying hash function. For
            // example, EC_SIGN_P384_SHA384 requires SHA-384.
            Digest digest = new Digest
            {
                Sha256 = ByteString.CopyFrom(hash),
            };

            // Call the API.
            AsymmetricSignResponse result = client.AsymmetricSign(keyVersionName, digest);

            // Get the signature.
            byte[] signature = result.Signature.ToByteArray();

            // Return the result.
            return signature;
        }

Now here is the code which verify the authenticity of the signature and always returns false:

 public bool VerifyAsymmetricSignature(string keyId ,string message, byte[] signature = null)
        {
            // Create the client.
            KeyManagementServiceClient client;
            GoogleCredential credential = CredentialManager.GetCredential();

            if (credential != null)
            {
                client = new KeyManagementServiceClientBuilder { ChannelCredentials = credential.ToChannelCredentials() }.Build();
            }
            else
            {
                client = new KeyManagementServiceClientBuilder().Build();
            }

            //get key enabled version
            CryptoKeyName name = new CryptoKeyName(_projectId, _locationId, _keyRingId, keyId);
            string cryptoKeyVersionId = client.ListCryptoKeyVersions(name).Where(s => s.State == CryptoKeyVersionState.Enabled).First().CryptoKeyVersionName.CryptoKeyVersionId;

            // Build the key version name.
            CryptoKeyVersionName keyVersionName = new CryptoKeyVersionName(_projectId, _locationId, _keyRingId, keyId, cryptoKeyVersionId);

            // Get the public key.
            //KeyManagementServiceClient client = KeyManagementServiceClient.Create();
            PublicKey publicKey = client.GetPublicKey(keyVersionName);

            // Split the key into blocks and base64-decode the PEM parts.
            string[] blocks = publicKey.Pem.Split("-", StringSplitOptions.RemoveEmptyEntries);
            byte[] pem = Convert.FromBase64String(blocks[1]);

            ECDsa eCDsa = ECDsa.Create();
            eCDsa.ImportSubjectPublicKeyInfo(pem, out _);

            // Convert the message into bytes. Cryptographic plaintexts and
            // ciphertexts are always byte arrays.
            //byte[] plaintext = Encoding.ASCII.GetBytes(message);

            SHA256 sha256 = SHA256.Create();
            byte[] digest = sha256.ComputeHash(Encoding.UTF8.GetBytes(message));
            // Verify the signature.
            bool verified = eCDsa.VerifyData(digest, signature, HashAlgorithmName.SHA256);

            // Return the result.
            return verified;
        }

I'm using:

.Net Core 5 System.Security.Cryptography.ECDsa

What am I doing wrong?

1 Answers
Related