WinRT RSA encryption from public key exponent/modulus - c#

I'm trying to port this method from .NET 4.5 desktop app to a WinRT app:
static byte[] DotNetRsaEncrypt(string modulus, string exponent, byte[] data)
{
var modulusBytes = Convert.FromBase64String(modulus);
var exponentBytes = Convert.FromBase64String(exponent);
var rsaParameters = new RSAParameters { Modulus = modulusBytes, Exponent = exponentBytes };
var rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);
var encrypted = rsa.Encrypt(data, true);
return encrypted;
}
After reading this RSA Encryption in metro style Application
I tried the following:
static byte[] WinRtRsaEncrypt(string modulus, string exponent, byte[] data)
{
var modulusBytes = Convert.FromBase64String(modulus);
var exponentBytes = Convert.FromBase64String(exponent);
var keyBlob = modulusBytes.Concat(exponentBytes).ToArray().AsBuffer();
var rsa = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaOaepSha1);
var key = rsa.ImportPublicKey(keyBlob, CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey);
var encrypted = CryptographicEngine.Encrypt(key, data.AsBuffer(), null);
return encrypted;
}
But it does not work.
In order to get the same functionality as my desktop app...
What AsymmetricAlgorithmNames should I pass to OpenAlgorithm()?
What CryptographicPublicKeyBlobType should I pass to ImportPublicKey()?

Following up on user1968335's hint, this worked for me.
First, in a C# application, use the following code to obtain a CspBlob from your modulus/exponent:
var exponent = Encoding.Default.GetBytes(exponentStr);
var modulus = Encoding.Default.GetBytes(modulusStr);
var rsaParameters = new RSAParameters { Modulus = modulus, Exponent = exponent };
var rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);
var cspBlobString = Convert.ToBase64String(rsa.ExportCspBlob(false));
Then, in a WinRT application you can use that CspBlob to sign a piece of data like this:
private static string SignString(string data)
{
string cspBlobString = //cspBlob
var keyBlob = CryptographicBuffer.DecodeFromBase64String(cspBlobString);
AsymmetricKeyAlgorithmProvider rsa = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
CryptographicKey key = rsa.ImportPublicKey(keyBlob, CryptographicPublicKeyBlobType.Capi1PublicKey);
IBuffer plainBuffer = CryptographicBuffer.ConvertStringToBinary(data, BinaryStringEncoding.Utf8);
IBuffer encryptedBuffer = CryptographicEngine.Encrypt(key, plainBuffer, null);
byte[] encryptedBytes;
CryptographicBuffer.CopyToByteArray(encryptedBuffer, out encryptedBytes);
return Convert.ToBase64String(encryptedBytes);
}
If it matters, this is how I generated my asymmetric keys: http://43n141e.blogspot.co.uk/2008/08/rsa-encryption-openssl-to-ruby-to-c-and_27.html

According to CryptoWinRT sample, OpenAlgorithm(...) method takes these values.
RSA_PKCS1
RSA_OAEP_SHA1
RSA_OAEP_SHA256
RSA_OAEP_SHA384
See also : RSA cryptography between a WinRT and a .Net app

Related

Converting from a Public Microsoft.IdentityModel.Tokens.JsonWebKey.JsonWebKey to RSAParameters (Public Key)

Essentially, I'm looking to convert a Public Microsoft.IdentityModel.Tokens.JsonWebKey.JsonWebKey to RSAParameters to then use in an RSA Instance. After this, i'm creating an Azure KeyVault JsonWebKey so I can import this key into my vault. I currently tried this, however have not gotten it to work. Any recommendations/shortcuts?
var jwk = new JsonWebKey(someStr); // IdentityModel.Tokens...
var rsaParams = new RSAParameters
{
Modulus = WebEncoders.Base64UrlDecode(jwk.N),
Exponent = WebEncoders.Base64UrlDecode(jwk.E)
};
var rsa = RSA.Create(rsaParams);
var key = new JsonWebKey(rsa); // Azure.Security.KeyVault.Keys
....
var kvKey = keyClient.ImportKey(keyName, key); // keyClient = KeyClient class
The error I am receiving from this request is:
RSA key is not valid - cannot instantiate crypto service
Try adding other rsa parameters and then importing into an RSACryptoServiceProvider. Then you can recover the SecurityKey.
The code below is an example of how to recover a SecurityKey from a previous RSASecurityKey stored in a JsonWebKey
using RSACryptoServiceProvider provider = new RSACryptoServiceProvider(2048);
JsonWebKey key = JsonConvert.DeserializeObject<JsonWebKey>(jsonwebkeystringcontent);
RSAParameters rsaParameters = new()
{
Modulus = WebEncoders.Base64UrlDecode(key.N),
Exponent = WebEncoders.Base64UrlDecode(key.E),
D = WebEncoders.Base64UrlDecode(key.D),
DP = WebEncoders.Base64UrlDecode(key.DP),
DQ = WebEncoders.Base64UrlDecode(key.DQ),
P = WebEncoders.Base64UrlDecode(key.P),
Q = WebEncoders.Base64UrlDecode(key.Q),
InverseQ = WebEncoders.Base64UrlDecode(key.QI)
};
provider.ImportParameters(rsaParameters);
SecurityKey Key = new RsaSecurityKey(provider.ExportParameters(true));

Decrypt RSA encrypted value generated from .net in Android

I have gone through many posts here but did not find the right solution. I want to decrypt a value encrypted in c# .net from Android.
I have successfully decrypted in .net platform using the following code snippet
public static void Main()
{
string _privateKey = Base64Decode("myprivatekey");
var rsa = new RSACryptoServiceProvider();
string data = "198,47,144,175,154,47,194,175,242,41,212,150,220,177,198,161,236,36,197,62,18,111,21,244,232,245,90,234,195,169,141,195,139,199,131,163,26,124,246,50,102,229,73,148,18,110,170,145,112,237,23,123,226,135,158,206,71,116,9,219,56,96,140,19,180,192,80,29,63,160,43,127,204,135,155,67,46,160,225,12,85,161,107,214,104,218,6,220,252,73,252,92,152,235,214,126,245,126,129,150,49,68,162,120,237,246,27,25,45,225,106,201,251,128,243,213,250,172,26,28,176,219,198,194,7,202,34,210";
var dataArray = data.Split(new char[] { ',' });
byte[] dataByte = new byte[dataArray.Length];
for (int i = 0; i < dataArray.Length; i++)
{
dataByte[i] = Convert.ToByte(dataArray[i]);
}
rsa.FromXmlString(_privateKey);
var decryptedByte = rsa.Decrypt(dataByte, false);
Console.WriteLine(_encoder.GetString(decryptedByte));
}
Now I want to do the same process in Android app. Please can somebody guide me through this?
I have tried the following code but its throwing javax.crypto.IllegalBlockSizeException: input must be under 128 bytes exception
String modulusString = "hm2oRCtP6usJKYpq7o1K20uUuL11j5xRrbV4FCQhn/JeXLT21laKK9901P69YUS3bLo64x8G1PkCfRtjbbZCIaa1Ci/BCQX8nF2kZVfrPyzcmeAkq4wsDthuZ+jPInknzUI3TQPAzdj6gim97E731i6WP0MHFqW6ODeQ6Dsp8pc=";
String publicExponentString = "AQAB";
byte[] modulusBytes = Base64.decode(modulusString, DEFAULT);
byte[] exponentBytes = Base64.decode(publicExponentString, DEFAULT);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger publicExponent = new BigInteger(1, exponentBytes);
RSAPrivateKeySpec rsaPubKey = new RSAPrivateKeySpec(modulus, publicExponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey pubKey = fact.generatePrivate(rsaPubKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] plainBytes = result.getBytes("UTF-16LE");
byte[] cipherData = cipher.doFinal(plainBytes);
String encryptedStringBase64 = Base64.decode(cipherData, DEFAULT).toString();

How to write RSA encrypt function in C#

I have following nodejs code to encrypt RSA:
const encryptWithRSA = (PublicKey, selData) => {
let encrypted = crypto.publicEncrypt(
{
key: -----BEGIN PUBLIC KEY-----\n${PublicKey}\n-----END PUBLIC KEY-----,
padding: crypto.constants.RSA_PKCS1_PADDING,
},
Buffer.from(selData)
);
return encrypted.toString("base64");
};
Then I tried to convert this code block to C# :
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
public static string Encrypt(string publickey, string data)
{
string key = publickey;
Asn1Object obj = Asn1Object.FromByteArray(Convert.FromBase64String(key));
DerSequence publicKeySequence = (DerSequence)obj;
DerBitString encodedPublicKey = (DerBitString)publicKeySequence[1];
DerSequence publicKey = (DerSequence)Asn1Object.FromByteArray(encodedPublicKey.GetBytes());
DerInteger modulus = (DerInteger)publicKey[0];
DerInteger exponent = (DerInteger)publicKey[1];
RsaKeyParameters keyParameters = new RsaKeyParameters(false, modulus.PositiveValue, exponent.PositiveValue);
RSAParameters parameters = DotNetUtilities.ToRSAParameters(keyParameters);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(parameters);
byte[] dataToEncrypt = Encoding.UTF8.GetBytes(data);
byte[] encryptedData = rsa.Encrypt(dataToEncrypt, RSAEncryptionPadding.Pkcs1);
return Convert.ToBase64String(encryptedData);
}
Two code return 2 different results. Anyone can show me what wrong? Thanks!

Using Azure Key Vault RSA Key to encrypt and decrypt strings

I have setup Azure Key Vault to retrieve RSA Keys for encryption. Azure send me an object of type KeyBundle. This object contains a JsonWebKey of type RSA of size 2048. Looking at my RSA Key, it has 2 methods called Encrypt(byte[] data, RSAEncryptionPadding padding) and Decrypt(byte[] data, RSAEncryptionPadding padding). Now I am trying to encrypt and decrypt a simple string like this:
public EncryptionManager(KeyBundle encryptionKey)
{
string test = "Hello World!";
var key = encryptionKey.Key.ToRSA();
var encryptedString = key.Encrypt(Encoding.UTF8.GetBytes(test), RSAEncryptionPadding.OaepSHA256);
var decryptedString = key.Decrypt(encryptedString, RSAEncryptionPadding.OaepSHA256);
}
Encryption works, but decryption throws an exception with message:
Key does not exist.
Here is the StackTrace
at System.Security.Cryptography.RSAImplementation.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle
key, ReadOnlySpan`1 input, AsymmetricPaddingMode paddingMode, Void*
paddingInfo, Boolean encrypt) at
System.Security.Cryptography.RSAImplementation.RSACng.EncryptOrDecrypt(Byte[]
data, RSAEncryptionPadding padding, Boolean encrypt) at
System.Security.Cryptography.RSAImplementation.RSACng.Decrypt(Byte[]
data, RSAEncryptionPadding padding) at
NxtUtils.Security.EncryptionManager..ctor(KeyBundle encryptionKey) in
C:\Repos\Enigma\EnigmaPrototype\SharedLibaries\NxtUtils\Security\EncryptionManager.cs:line
26
I am really not familiar with cryptographic algorithms. My question is: How can I encrypt and decrypt a simple strig using this RSA Key provided by Azure?
Thanks!
I got the same issue, what I did is here although I searched from internet and got this from the Microsoft docs
so this is my working code below
public static class KeyVaultEncryptorDecryptor
{
public static string KeyDecryptText(this string textToDecrypt , KeyVaultClient keyVaultClient, string keyidentifier)
{
var kv = keyVaultClient;
try
{
var key = kv.GetKeyAsync(keyidentifier).Result;
var publicKey = Convert.ToBase64String(key.Key.N);
using var rsa = new RSACryptoServiceProvider();
var p = new RSAParameters() {
Modulus = key.Key.N, Exponent = key.Key.E
};
rsa.ImportParameters(p);
var encryptedTextNew = Convert.FromBase64String(textToDecrypt);
var decryptedData = kv.DecryptAsync(key.KeyIdentifier.Identifier.ToString(), JsonWebKeyEncryptionAlgorithm.RSAOAEP, encryptedTextNew).GetAwaiter().GetResult();
var decryptedText = Encoding.Unicode.GetString(decryptedData.Result);
return decryptedText;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return default;
}
}
public static string KeyEncryptText(this string textToEncrypt , KeyVaultClient keyVaultClient, string keyidentifier)
{
var kv = keyVaultClient;
try
{
var key = kv.GetKeyAsync(keyidentifier).GetAwaiter().GetResult();
var publicKey = Convert.ToBase64String(key.Key.N);
using var rsa = new RSACryptoServiceProvider();
var p = new RSAParameters() {
Modulus = key.Key.N, Exponent = key.Key.E
};
rsa.ImportParameters(p);
var byteData = Encoding.Unicode.GetBytes(textToEncrypt);
var encryptedText = rsa.Encrypt(byteData, true);
string encText = Convert.ToBase64String(encryptedText);
return encText;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return default;
}
}
}
ToRSA has a default boolean parameter indicating if the private key should be available, or not.
Since you didn't explicitly say true it is implicitly false, therefore your key object is public-only. With a public RSA key you can encrypt data or verify a signature, but you cannot sign or decrypt.

UWP [Universal windows platform] RSA AsymmetricKeyAlgorithmProvider import public key

When I am trying to use Windows.Security.Cryptography.Core in UWP, I always get an error on importing the public key from AsymmetricKeyAlgorithmProvider. I tried every combination without success. I always checked the input string to be in UTF8 mode.
try {
var bytes = Encoding.UTF8.GetBytes(publicKeyString);
publicKeyString = Encoding.UTF8.GetString(bytes);
Debug.WriteLine(publicKeyString);
IBuffer keyBuffer = CryptographicBuffer.DecodeFromBase64String(publicKeyString);
byte[] bytes = Convert.FromBase64String(publicKeyString);
string hex = "2D2D2D2D2D424547494E205055424C4943204B45592D2D2D2D2D0A4D494942496A414E42676B71686B6947397730424151454641414F43415138414D49494243674B434151454172336767514744726E5645562B786A4F484F2B390A4B72595541547166756935666F364D65736E53466C6B797937482F4775327135667273724B305246383933507A584F664371414A6753534D58673330793463720A594E3742617838467979314C58744E2B5A35576B43436D644F597438704F636D7A75494D6A636E4E733063486B767859576B336658516D513255535A685063700A51595761382F4469392B344462745464587A643263346F717A4E4A4A4A4B66437A647731796E72776F4A755A4245563547747363396F48782F6D7231725434420A386F377635473553706D543368687661396762617034436C4231745677434B584F41636A2F71782F49416A505A35566E4B7A363669325534706A6F43764A79590A564E53497A3557346276726A6E622B76775848626B506D62316E6655503864526D33683767644F314D7330766B72715A4567714746416953343475686974576B0A65514944415141420A2D2D2D2D2D454E44205055424C4943204B45592D2D2D2D2D0A";
Debug.WriteLine(hex);
AsymmetricKeyAlgorithmProvider provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
CryptographicKey publicKey = provider.ImportPublicKey(CryptographicBuffer.DecodeFromHexString(hex), CryptographicPublicKeyBlobType.BCryptPublicKey);
IBuffer dataBuffer = CryptographicBuffer.CreateFromByteArray(Encoding.UTF8.GetBytes(plainText));
var encryptedData = CryptographicEngine.Encrypt(publicKey, dataBuffer, null);
return CryptographicBuffer.EncodeToBase64String(encryptedData);
}
catch (Exception e)
{
throw;
return "Error in Encryption:With RSA ";
}
I have found a solution to my problem the problem was that the public key i was trying to import was not in ASN1 form and therefore the uwp Cryptography Core couldn't do the conversion from DER to ASN1 the new code is :
byte[] bytes = Encoding.UTF8.GetBytes(publicKeyString);
IBuffer keyBuffer = CryptographicBuffer.DecodeFromBase64String(publicKeyString);
AsymmetricKeyAlgorithmProvider provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
CryptographicKey publicKey = provider.ImportPublicKey(keyBuffer,CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey);`
I meet the same problem:ASN1 bad tag value met.
I found that the ImportKeyPair(IBuffer) is the correct for my situation.
Sample Code:
var loginPBK = "";//your public key,such as "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp0wHYbg......."
var provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
var publicKey = provider.ImportPublicKey(CryptographicBuffer.DecodeFromBase64String(loginPBK));
var encryptData = CryptographicEngine.Encrypt(publicKey, CryptographicBuffer.ConvertStringToBinary(password, BinaryStringEncoding.Utf8), null);
var pwd2 = CryptographicBuffer.EncodeToBase64String(encryptData);

Categories

Resources