Using Key by Azure Key Vault to Encrypt and Decrypt text - c#

I'm trying use a key from Azure Key Vault to Encrypt and Decrypt the cookies of a web API.
To encryption proccess I'm using the RSA, in that class:
public class SimpleRSA
{
private RSA _rsa;
public SimpleRSA(RSA rsa)
{
_rsa = rsa;
}
public string EncryptAsync(string value)
{
var byteData = Encoding.Unicode.GetBytes(value);
var encryptedText = _rsa.Encrypt(byteData, RSAEncryptionPadding.OaepSHA1);
var encodedText = Convert.ToBase64String(encryptedText);
return encodedText;
}
public string DecryptAsync(string encryptedText)
{
var encryptedBytes = Convert.FromBase64String(encryptedText);
var decryptionResult = _rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.OaepSHA1);
var decryptedText = Encoding.Unicode.GetString(decryptionResult);
return decryptedText;
}
}
And I'm getting my RSA from the Key, using that code:
public RSA GetRSA(string appId, string appSecret)
{
AuthenticationCallback callback = async (authority, resource, scope) =>
{
var authContext = new AuthenticationContext(authority);
var credential = new ClientCredential(appId, appSecret);
var authResult = await authContext.AcquireTokenAsync(resource, credential);
return authResult.AccessToken;
};
var client = new KeyVaultClient(callback);
var result = client.GetKeyAsync(_vaultBaseUrl, _keyId).Result;
var key = result.Key;
return key.ToRSA();
}
I got the RSA from my Azure Key Vault and I managed encrypt my string. The problem is when I'm trying Decrypt the value. In that process I got that error:
System.Security.Cryptography.CryptographicException: 'Error decoding OAEP padding.'
I think that can be happening because I'm without the private keys in RSA, but I've tried use this method to get the RSA with private key::
key.ToRSA(true);
But a got that error:
So, I don't know how I can complete this process. Are there other way to do that? Or what's wrong?

If you want to use Azure Key Vault to Encrypt and Decrypt text, you can use SDK Azure.Security.KeyVault.Keys to implement it.
For example
Install SDK
Install-Package Azure.Security.KeyVault.Keys -Version 4.0.3
Install-Package Azure.Identity -Version 1.1.1
Code
ClientSecretCredential clientSecretCredential = new ClientSecretCredential(tenantId, // your tenant id
clientId, // your AD application appId
clientSecret // your AD application app secret
);
//get key
var KeyVaultName = "<your kay vault name>";
KeyClient keyClient = new KeyClient(new Uri($"https://{KeyVaultName}.vault.azure.net/"), clientSecretCredential);;
var keyName="<your key name>"
var key = await keyClient.GetKeyAsync(keyName);
// create CryptographyClient
CryptographyClient cryptoClient = new CryptographyClient(key.Value.Id, clientSecretCredential);
var str ="test"
Console.WriteLine("The String used to be encrypted is : " +str );
Console.WriteLine("-------------encrypt---------------");
var byteData = Encoding.Unicode.GetBytes(str);
var encryptResult = await cryptoClient.EncryptAsync(EncryptionAlgorithm.RsaOaep, byteData);
var encodedText = Convert.ToBase64String(encryptResult.Ciphertext);
Console.WriteLine(encodedText);
Console.WriteLine("-------------dencrypt---------------");
var encryptedBytes = Convert.FromBase64String(encodedText);
var dencryptResult = await cryptoClient.DecryptAsync(EncryptionAlgorithm.RsaOaep, encryptedBytes);
var decryptedText = Encoding.Unicode.GetString(dencryptResult.Plaintext);
Console.WriteLine(decryptedText);

Key Vault can store three item types: Keys, Secrets and Certificates. Keys are always asymmetric - RSA or Elliptic Curve, and the private keys don't leave KV. What you need is to use a symmetric key, but you need to store that as a Secret, not a key.
So store a 256-bit random secret in KV, call it MyCoolCryptoKey, pull that symmetric key into your C# code and use that as a key for AES.

Related

How do I send the data to API with encrypted data and signature with private key generated by RSA

I am C# developer and I have the below code works well in C# application. I am trying to use the same functionality in the VueJS and Node Js application. I have done with serialization and conversion to fromBase64String, but I am stuck here with generating signature to send it to API. please suggest.
byte[] privateKey = Convert.FromBase64String(File.ReadAllText(appConfig.PrivateKey));
using (CngKey signingKey = CngKey.Import(privateKey, CngKeyBlobFormat.Pkcs8PrivateBlob))
using (RSACng rsaCng = new RSACng(signingKey))
{
request.Data.Signature = Convert.ToBase64String(rsaCng.SignData(Encoding.UTF8.GetBytes(request.Data.Content), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1));
}
var response = (Response)SendRequest(request, 1);
return response;
I have tried the below in Vue and node Js code
var utf8 = (encodeURIComponent(serializedProductInfo));
var dataInfo = [];
for (var i = 0; i < utf8.length; i++) {
dataInfo.push(utf8.charCodeAt(i));
}
let base64Contenet = window.btoa((encodeURIComponent(dataInfo)));
//let base64Contenet = Buffer.toString((encodeURIComponent(dataInfo)));
console.log(base64Contenet);
var privateKey = [];
privateKey = Buffer.from("My PrivateKey", "base64");
var crypto = require('crypto');
var sha1 = crypto.createHash('sha1');
sha1.key = privateKey;
sha1.update(dataInfo);
var hash = sha1.digest();
var signature = crypto.privateEncrypt({ key: privateKey, padding: crypto.constants.RSA_PKCS1_PADDING }, hash);
console.log(signature);
I am getting the below error
vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in v-on handler: "TypeError: Cannot read properties of null (reading '2')"

How create a jwt signature using a private key and a rsasha256 algorithm (.net)?

I am trying to sign a JWT with a private key and the rsasha256 algorithm. Everytime a try to create the tokenHandler, it goes into the Catch part.
The exception that I get is:
System.Exception: 'Erro ao obter ID do processo: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'System.String', SecurityKey: 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey'
is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms'
var privateKey = File.ReadAllText(#"C:\Cencosud\Git\APIs\Api_Unico\Unico.Infra.Data\API.Services\Implementations\.key.pem");
privateKey = privateKey.Replace("-----BEGIN PRIVATE KEY-----", string.Empty).Replace("-----END PRIVATE KEY-----", string.Empty);
privateKey = privateKey.Replace(Environment.NewLine, string.Empty);
var privateKeyBytes = Encoding.UTF8.GetBytes(privateKey);
var tokenHandler = new JwtSecurityTokenHandler();
var key = privateKeyBytes;
var token = tokenHandler.CreateToken(new SecurityTokenDescriptor
{
Issuer = "service_account_name#tenant_id.iam.acesso.io",
Audience = "https://identityhomolog.acesso.io",
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.RsaSha256)
});
var jwt = tokenHandler.WriteToken(token);
A couple problems here:
The code is converting the private key as if it's a UTF8 string using Encoding.UTF8.GetBytes. Use Convert.FromBase64String instead.
The code is attempting to initialize SigningCredentials as a symmetric key but a private RSA key isn't symmetrical and needs to be created differently.
See my changes below:
var privateKey = File.ReadAllText(#"C:\Cencosud\Git\APIs\Api_Unico\Unico.Infra.Data\API.Services\Implementations\.key.pem");
privateKey = privateKey.Replace("-----BEGIN PRIVATE KEY-----", string.Empty).Replace("-----END PRIVATE KEY-----", string.Empty);
privateKey = privateKey.Replace(Environment.NewLine, string.Empty);
// CHANGE CONVERSION TYPE
var privateKeyBytes = Convert.FromBase64String(privateKey);
// INITIALIZE RSA
using var rsa = RSA.Create();
// Since the private key starts with "BEGIN PRIVATE KEY" it's PKCS8 encoded
rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _);
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(new SecurityTokenDescriptor
{
Issuer = "service_account_name#tenant_id.iam.acesso.io",
Audience = "https://identityhomolog.acesso.io",
// CREATE SIGNING CREDENTIALS WITH THE RSA INITIALIZED ABOVE
SigningCredentials = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256)
});
var jwt = tokenHandler.WriteToken(token);

403 Forbidden Access, while decrypting using Azure key vault

I am trying to encrypt and decrypt a string locally (client-side encryption). I am encrypting successfully, whereas while trying to decrypt. I am getting Error 403.
I am attaching my code and the permission screenshot here. Any help will be appreciated.
var vaultUri = new Uri(keyVaultUrl);
var client = new KeyClient(vaultUri, credential: new DefaultAzureCredential());
var cryptoClient = new CryptographyClient(key1.Id, new DefaultAzureCredential());
EncryptResult encryptResult = cryptoClient.Encrypt(EncryptionAlgorithm.RsaOaep256, Encoding.UTF8.GetBytes(VarToEncrypt));
Console.WriteLine("Encrypted string is: " + Convert.ToBase64String(encryptResult.Ciphertext));
var secretClient = new SecretClient(vaultUri, new DefaultAzureCredential());
secretClient.SetSecret(new KeyVaultSecret("Temp", Convert.ToBase64String(encryptResult.Ciphertext)));
Console.WriteLine("Do you want to decrypt? (Y/N)");
if (Console.ReadLine().ToUpper() == "Y")
{
var encryptedSecret = secretClient.GetSecret("Temp");
DecryptResult decryptResult = cryptoClient.Decrypt(EncryptionAlgorithm.RsaOaep256, encryptResult.Ciphertext);
Console.WriteLine("Decrypted string is: " + Encoding.UTF8.GetString(decryptResult.Plaintext));
}
403 means your service principal does not have an access policy configured to decrypt.

Verifying a JWT using the public key with C#

I am building a React app backed by Azure functions written in C#. I've implemented JWT authentication via Userfront which is working fine on the front end but I'm struggling to verify the token using the public key in the functions.
I've tried numerous approaches, JWT-DotNet being the most recent but to no avail.
Can anyone please provide a working code example?
Here is what I have currently (which errors when creating the new RS256Algorithm with "Cannot find the requested object."):
var headers = req.Headers;
if (!headers.TryGetValue("Authorization", out var tokenHeader))
return new StatusCodeResult(StatusCodes.Status403Forbidden);
var token = tokenHeader[0].Replace("Bearer ", "");
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(Environment.GetEnvironmentVariable("Userfront_PublicKey"));
var urlEncoder = new JwtBase64UrlEncoder();
var publicKey = urlEncoder.Encode(plainTextBytes);
try
{
IJsonSerializer serializer = new JsonNetSerializer();
var provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
IJwtAlgorithm algorithm = new RS256Algorithm(new X509Certificate2(plainTextBytes));
IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder,algorithm);
var json = decoder.Decode(token[0], publicKey, verify: true);
}
catch (TokenExpiredException)
...
catch (SignatureVerificationException)
...
Assuming that the environment variable "Userfront_PublicKey" contains a PEM-encoded RSA public key, i.e.:
-----BEGIN RSA PUBLIC KEY-----
(your base64-encoded RSA public key)
-----END RSA PUBLIC KEY-----
then I would try the following (not tested, sorry):
var headers = req.Headers;
if (!headers.TryGetValue("Authorization", out var tokenHeader))
return new StatusCodeResult(StatusCodes.Status403Forbidden);
var token = tokenHeader[0].Replace("Bearer ", "");
var publicKeyPem = Environment.GetEnvironmentVariable("Userfront_PublicKey");
var publicKey = RSA.Create();
publicKey.ImportFromPem(publicKeyPem);
try
{
var json = JwtBuilder.Create()
.WithAlgorithm(new RS256Algorithm(publicKey))
.MustVerifySignature()
.Decode(token);
}
catch (TokenExpiredException)
...
catch (SignatureVerificationException)
...

Create a valid JWT Token for DocuSign API

Ι try to create a valid jwt token
From settings i create an RSA keypairs and i get the private key without the "-----BEGIN RSA PRIVATE KEY----------END RSA PRIVATE KEY-----
"
var rsaPrivateKey = #"MIIEogIBAAKCAQEAoGujdXbYVy68a4CSWz963SpYxVs20/..............HQ/jW8pFom6gJreCDkca5axYo/gXp3W3rQHFTkooTNbOk2MyFMZUqRD3aCG1wuUW3w8TgGX4slrLDV0pP4=";
var jwt = Sign(rsaPrivateKey);
I follow the instructions here https://developers.docusign.com/docs/admin-api/admin101/application-auth/ and after a lot of hours i create this method
public string Sign(string privateKey)
{
List<string> segments = new List<string>();
var header = new { alg = "RS256", typ = "JWT" };
//For production environments, use account.docusign.com
var payload = new
{
iss = "4f489d61-dc8b------a828-3992e670dcbc",
iat = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds,
aud = "account-d.docusign.com",
scope = "signature impersonation"
};
byte[] headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header, Formatting.None));
byte[] payloadBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload, Formatting.None));
segments.Add(Base64UrlEncode(headerBytes));
segments.Add(Base64UrlEncode(payloadBytes));
string stringToSign = string.Join(".", segments.ToArray());
byte[] bytesToSign = Encoding.UTF8.GetBytes(stringToSign);
byte[] keyBytes = Convert.FromBase64String(privateKey);
var privKeyObj = Asn1Object.FromByteArray(keyBytes);
var privStruct = RsaPrivateKeyStructure.GetInstance((Asn1Sequence)privKeyObj);
ISigner sig = SignerUtilities.GetSigner("SHA256withRSA");
sig.Init(true, new RsaKeyParameters(true, privStruct.Modulus, privStruct.PrivateExponent));
sig.BlockUpdate(bytesToSign, 0, bytesToSign.Length);
byte[] signature = sig.GenerateSignature();
segments.Add(Base64UrlEncode(signature));
return string.Join(".", segments.ToArray());
}
private static string Base64UrlEncode(byte[] input)
{
var output = Convert.ToBase64String(input);
output = output.Split('=')[0]; // Remove any trailing '='s
output = output.Replace('+', '-'); // 62nd char of encoding
output = output.Replace('/', '_'); // 63rd char of encoding
return output;
}
When i check the JWT validation in this tool https://jwt.io/#debugger-io, i get invalid signature error.
How can i fix the token ?? I cant proceed with Step 2 Obtain the access token...
I'm sorry you having problems with JWT. I would recommend you use the DocuSign C# SDK instead of trying to write your own code.
Then you can find the example of how to use JWT here - https://github.com/docusign/code-examples-csharp.
The specific code relevant to JWT is here - https://github.com/docusign/code-examples-csharp/blob/38c2eb46948a3cbf55edcce758f88d775f80cae9/launcher-csharp/Common/RequestItemService.cs under the UpdateUserFromJWT() method.
Common problems with JWT:
Not obtaining consent.
Using public token instead of private.
Using malform token. Token must be exactly, including new-lines, as provided.
Not using correct UserId (GUID) in the request.
Not requesting "impersonation" scope in consent (#1 above).

Categories

Resources