RSA cryptography between a WinRT and a .Net app

In this blog post, I share how I managed to enable RSA cryptography between a .Net app (actually a WCF service hosted in Azure) and WinRT app. I found few entries on the Internet talking about this issue but none of them solved my issue directly. In particular, I had to use some options I wasn’t using before the interop need with WinRT. That’s the reason behind this blog post.

Context

The following diagram showcase the need I have in my scenario:

WinRT encryption

I need to securely transfer data from a WinRT app to a .Net server app. The transport mechanism is out the scope of this article but it worth noting I’m using this approach because I cannot use HTTPS.

In order to give you a complete implementation I will be sharing in the rest of this article this way (encrypted data from WinRT to the server) and the other way around. So for each platform, you have the creation of the key pair, the encryption and the description method.

WinRT

Create key pairs

public static Tuple WinRTCreateKeyPair()
{
    AsymmetricKeyAlgorithmProvider asym = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
    CryptographicKey key = asym.CreateKeyPair(1024);
            
    IBuffer privateKeyBuffer = key.Export(CryptographicPrivateKeyBlobType.Capi1PrivateKey);
    IBuffer publicKeyBuffer = key.ExportPublicKey(CryptographicPublicKeyBlobType.Capi1PublicKey);
            
    byte[] privateKeyBytes;
    byte[] publicKeyBytes;
            
    CryptographicBuffer.CopyToByteArray(privateKeyBuffer, out privateKeyBytes);
    CryptographicBuffer.CopyToByteArray(publicKeyBuffer, out publicKeyBytes);

    string privateKey = Convert.ToBase64String(privateKeyBytes);
    string publicKey = Convert.ToBase64String(publicKeyBytes);

    return new Tuple(privateKey, publicKey);
}

Encrypt

public static byte[] WinRTEncrypt(string publicKey, string data)
{
    IBuffer keyBuffer = CryptographicBuffer.DecodeFromBase64String(publicKey);

    AsymmetricKeyAlgorithmProvider asym = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
    CryptographicKey key = asym.ImportPublicKey(keyBuffer, CryptographicPublicKeyBlobType.Capi1PublicKey);

    IBuffer plainBuffer = CryptographicBuffer.ConvertStringToBinary(data, BinaryStringEncoding.Utf8);
    IBuffer encryptedBuffer = CryptographicEngine.Encrypt(key, plainBuffer, null);

    byte[] encryptedBytes;
    CryptographicBuffer.CopyToByteArray(encryptedBuffer, out encryptedBytes);

    return encryptedBytes;
}

Decrypt

public static string WinRTDecrypt(string privateKey, byte[] data)
{
    IBuffer keyBuffer = CryptographicBuffer.DecodeFromBase64String(privateKey);

    AsymmetricKeyAlgorithmProvider asym = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
    CryptographicKey key = asym.ImportKeyPair(keyBuffer, CryptographicPrivateKeyBlobType.Capi1PrivateKey);
            
    IBuffer plainBuffer = CryptographicEngine.Decrypt(key, data.AsBuffer(), null);

    byte[] plainBytes;
    CryptographicBuffer.CopyToByteArray(plainBuffer, out plainBytes);

    return Encoding.UTF8.GetString(plainBytes, 0, plainBytes.Length);
}

.Net

Create key pairs

public static Tuple DotNetCreateKeyPair()
{
    CspParameters cspParams = new CspParameters { ProviderType = 1 /* PROV_RSA_FULL */ };

    RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(1024, cspParams);

    string publicKey = Convert.ToBase64String(rsaProvider.ExportCspBlob(false));
    string privateKey = Convert.ToBase64String(rsaProvider.ExportCspBlob(true));

    return new Tuple(privateKey, publicKey);
}

Encrypt

public static byte[] DotNetEncrypt(string publicKey, string data)
{
    CspParameters cspParams = new CspParameters { ProviderType = 1 /* PROV_RSA_FULL */ };
    RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(cspParams);

    rsaProvider.ImportCspBlob(Convert.FromBase64String(publicKey));

    byte[] plainBytes = Encoding.UTF8.GetBytes(data);
    byte[] encryptedBytes = rsaProvider.Encrypt(plainBytes, false);

    return encryptedBytes;
}

Decrypt

public static string DotNetDecrypt(string privateKey, byte[] encryptedBytes)
{
    CspParameters cspParams = new CspParameters { ProviderType = 1 /* PROV_RSA_FULL */ };
    RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(cspParams);

    rsaProvider.ImportCspBlob(Convert.FromBase64String(privateKey));

    byte[] plainBytes = rsaProvider.Decrypt(encryptedBytes, false);

    string plainText = Encoding.UTF8.GetString(plainBytes, 0, plainBytes.Length);

    return plainText;
}

Hope it helps 🙂

5 thoughts on “RSA cryptography between a WinRT and a .Net app

  1. As when i’m trying to encrypt the data i’m getting Bad Data at “asym.ImportPublicKey(keyBuffer, CryptographicPublicKeyBlobType.Capi1PublicKey);”

    please let me know if i done any mistake.

Leave a Reply

Your email address will not be published. Required fields are marked *