diff --git a/src/CryptoAgent/CryptoAgent.csproj b/src/CryptoAgent/CryptoAgent.csproj
index 7720812..b18271c 100644
--- a/src/CryptoAgent/CryptoAgent.csproj
+++ b/src/CryptoAgent/CryptoAgent.csproj
@@ -12,6 +12,7 @@
+
diff --git a/src/CryptoAgent/CryptoAgentSettings.cs b/src/CryptoAgent/CryptoAgentSettings.cs
index 1383255..4a27a84 100644
--- a/src/CryptoAgent/CryptoAgentSettings.cs
+++ b/src/CryptoAgent/CryptoAgentSettings.cs
@@ -36,7 +36,12 @@
public string AzureKeyvaultAdTenantId { get; set; }
public string AzureKeyvaultAdAppId { get; set; }
public string AzureKeyvaultAdSecret { get; set; }
- // GCP...
+ // Google Cloud KMS
+ public string GoogleCloudProjectId { get; set; }
+ public string GoogleCloudLocationId { get; set; }
+ public string GoogleCloudKeyringId { get; set; }
+ public string GoogleCloudKeyId { get; set; }
+ public string GoogleCloudKeyVersionId { get; set; }
// AWS...
// Hashicorp Vault...
// Other HSMs...
diff --git a/src/CryptoAgent/Services/GoogleCloudKmsRsaKeyService.cs b/src/CryptoAgent/Services/GoogleCloudKmsRsaKeyService.cs
new file mode 100644
index 0000000..e5b47b9
--- /dev/null
+++ b/src/CryptoAgent/Services/GoogleCloudKmsRsaKeyService.cs
@@ -0,0 +1,77 @@
+using Google.Cloud.Kms.V1;
+using Google.Protobuf;
+using System;
+using System.Security.Cryptography;
+using System.Threading.Tasks;
+
+namespace Bit.CryptoAgent.Services
+{
+ public class GoogleCloudKmsRsaKeyService : IRsaKeyService
+ {
+ private readonly KeyManagementServiceClient _keyManagementServiceClient;
+ private readonly CryptoKeyName _cryptoKeyName;
+ private readonly CryptoKeyVersionName _cryptoKeyVersionName;
+
+ public GoogleCloudKmsRsaKeyService(
+ CryptoAgentSettings settings)
+ {
+ _keyManagementServiceClient = KeyManagementServiceClient.Create();
+ _cryptoKeyName = new CryptoKeyName(settings.RsaKey.GoogleCloudProjectId,
+ settings.RsaKey.GoogleCloudLocationId, settings.RsaKey.GoogleCloudKeyringId,
+ settings.RsaKey.GoogleCloudKeyId);
+ _cryptoKeyVersionName = new CryptoKeyVersionName(settings.RsaKey.GoogleCloudProjectId,
+ settings.RsaKey.GoogleCloudLocationId, settings.RsaKey.GoogleCloudKeyringId,
+ settings.RsaKey.GoogleCloudKeyId, settings.RsaKey.GoogleCloudKeyVersionId);
+ }
+
+ public async Task EncryptAsync(byte[] data)
+ {
+ var result = await _keyManagementServiceClient.EncryptAsync(_cryptoKeyName, ByteString.CopyFrom(data));
+ return result.Ciphertext.ToByteArray();
+
+ }
+
+ public async Task DecryptAsync(byte[] data)
+ {
+ var result = await _keyManagementServiceClient.DecryptAsync(_cryptoKeyName, ByteString.CopyFrom(data));
+ return result.Plaintext.ToByteArray();
+ }
+
+ public async Task SignAsync(byte[] data)
+ {
+ using var sha256 = SHA256.Create();
+ var hash = sha256.ComputeHash(data);
+ var digest = new Digest
+ {
+ Sha256 = ByteString.CopyFrom(hash)
+ };
+ var result = await _keyManagementServiceClient.AsymmetricSignAsync(_cryptoKeyVersionName, digest);
+ return result.Signature.ToByteArray();
+ }
+
+ public async Task VerifyAsync(byte[] data, byte[] signature)
+ {
+ using var sha256 = SHA256.Create();
+ var hash = sha256.ComputeHash(data);
+ var rsa = await GetRsaPublicKeyAsync();
+ var verified = rsa.VerifyHash(hash, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
+ return verified;
+ }
+
+ public async Task GetPublicKeyAsync()
+ {
+ var rsa = await GetRsaPublicKeyAsync();
+ return rsa.ExportRSAPublicKey();
+ }
+
+ public async Task GetRsaPublicKeyAsync()
+ {
+ var publicKey = await _keyManagementServiceClient.GetPublicKeyAsync(_cryptoKeyVersionName);
+ var blocks = publicKey.Pem.Split("-", StringSplitOptions.RemoveEmptyEntries);
+ var pem = Convert.FromBase64String(blocks[1]);
+ var rsa = RSA.Create();
+ rsa.ImportSubjectPublicKeyInfo(pem, out _);
+ return rsa;
+ }
+ }
+}