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?