Etherman
Etherman

Reputation: 1867

X509EncodedKeySpec/RSA encryption from java to c#

How do we translate the following java into C# for .Net Framework 4.8?

private static String getBearerToken(String publicKeyBase64, String apiKey)
{
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    Cipher cipher = Cipher.getInstance("RSA");
    byte[] encodedPublicKey = Base64.decodeBase64(publicKeyBase64);
    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedPublicKey);
    PublicKey pk = keyFactory.generatePublic(publicKeySpec);

    cipher.init(Cipher.ENCRYPT_MODE, pk);

    byte[] encryptedApiKey = Base64.encodeBase64(cipher.doFinal(apiKey.getBytes("UTF-8")));

    return new String(encryptedApiKey, "UTF-8");
}

I have tried fiddling with the following (with BouncyCastle package):

public static string GetBearerToken(string publicKeyBase64, string apiKey)
{
    var key = Convert.FromBase64String(publicKeyBase64);
    var info = SubjectPublicKeyInfo.GetInstance(key);
    var pk = PublicKeyFactory.CreateKey(info);
    var x = ???(pk);

    using (var rsa = new RSACryptoServiceProvider(???))
    {
        var parameters = new RSAParameters()
        {
            Modulus = x.???,
            Exponent = x.???
        };

        rsa.ImportParameters(parameters);

        var data = Encoding.UTF8.GetBytes(apiKey);
        var encryptedBytes = rsa.Encrypt(data, true);

        return Convert.ToBase64String(encryptedBytes);
    }
}

I also tried this, which runs but does not produce the expected result in the test case:

public static string GetBearerToken(string publicKeyBase64, string apiKey)
{
    var keyBytes = Convert.FromBase64String(publicKeyBase64);
    var info = SubjectPublicKeyInfo.GetInstance(keyBytes);
    var keyParameter = PublicKeyFactory.CreateKey(info);

    var encryptEngine = new RsaEngine();

    encryptEngine.Init(true, keyParameter);

    var dataToEncrypt = Encoding.UTF8.GetBytes(apiKey);
    var encryptedBytes = encryptEngine.ProcessBlock(dataToEncrypt, 0, dataToEncrypt.Length);

    return Convert.ToBase64String(encryptedBytes);
}

And here is the unit test I'm trying to get passing:

[TestMethod]
public void Utils_GetBearerToken()
{
    var publicKey = "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAszE+xAKVB9HRarr6/uHYYAX/RdD6KGVIGlHv98QKDIH26ldYJQ7zOuo9qEscO0M1psSPe/67AWYLEXh13fbtcSKGP6WFjT9OY6uV5ykw9508x1sW8UQ4ZhTRNrlNsKizE/glkBfcF2lwDXJGQennwgickWz7VN+AP/1c4DnMDfcl8iVIDlsbudFoXQh5aLCYl+XOMt/vls5a479PLMkPcZPOgMTCYTCE6ReX3KD2aGQ62uiu2T4mK+7Z6yvKvhPRF2fTKI+zOFWly//IYlyB+sde42cIU/588msUmgr3G9FYyN2vKPVy/MhIZpiFyVc3vuAAJ/mzue5p/G329wzgcz0ztyluMNAGUL9A4ZiFcKOebT6y6IgIMBeEkTwyhsxRHMFXlQRgTAufaO5hiR/usBMkoazJ6XrGJB8UadjH2m2+kdJIieI4FbjzCiDWKmuM58rllNWdBZK0XVHNsxmBy7yhYw3aAIhFS0fNEuSmKTfFpJFMBzIQYbdTgI28rZPAxVEDdRaypUqBMCq4OstCxgGvR3Dy1eJDjlkuiWK9Y9RGKF8HOI5a4ruHyLheddZxsUihziPF9jKTknsTZtF99eKTIjhV7qfTzxXq+8GGoCEABIyu26LZuL8X12bFqtwLAcjfjoB7HlRHtPszv6PJ0482ofWmeH0BE8om7VrSGxsCAwEAAQ==";
    var apiKey = "aaaab09uz9f3asdcjyk7els777ihmwv8";
    var expectedToken = "rfNjFso4uJbzhwl8E9vizqmHEuD7XDmPqfsRx1L62UoTmURGGLAGgJSl9lCPbgy03Q7NwozFYD4r9BFQY5QpvErHximBDU8HE25urVahm0HnB8VyCIobs684XGSN4GjdequePDrG6xUAxxpvmhqZRlGt1tUjUBeBg6kYqp4EnKHsiaBtvd0THGLZbefpT6UaShASQWYNiEPwEon5wtUMaDwnyQEazDu1H2ieN3r8cCVM3hsak59J/1MP07FQjdFbxdCLfA0DuxgpeKpvLs7WrA767WJSB1QZy7hcP1igSGRfd7Zrp6E7gIukdpC0DApqPKa4XsNTo2AMpG4AwiET2WeKvHn539gbwREXf79kZlYdFDCgTc0Zs7OfDx5ZXMCBKHOS/H3tVFJqXTfEfIF5LOzrFU5pPE0HeNBV0Q2vm8qRwQX0RijnvMOGpdcmXb0qoph4oy8Mj+vjRfFRboMAafttDozBhRmWEmeBB3EjYASm1fToQp5ey6ltCiEt8rjL5PlexxB0u3u2LVJQcDzMVNiiq10t1xyw8qtc6BMOyrKVlIANWglRYOKr9saVBVvDFUcCfsghMjUTDeAwHom4A3cSDWmVlNF9Vs/WqCoUzjQCV0BFPDzeAUbQqt7h7OgFno/+D9n5j1eMro0aXbbHNx71u8YmgPJhdixzFhxM1Pw=";

    var token = Utils.GetBearerToken(publicKey, apiKey);

    Assert.AreEqual(expectedToken, token, "GetBearerToken");
}

Upvotes: 1

Views: 916

Answers (3)

Etherman
Etherman

Reputation: 1867

I have figured out a solution from a very similar question: .NET equivalent of Java KeyFactory.getInstance "RSA"/"RSA/ECB/PKCS1Padding"

I also pasted the original java code into jdoodle (https://www.jdoodle.com/online-java-compiler-ide/) to see what it actually does - encrypts with randomization therefore the result is different every time and cannot be unit tested as originally presumed (contrary to the API documentation page, therefore always confirm the assumptions first!)

The following produces randomized results but so far seems to be accepted by the API (uses BouncyCastle package):

public static string GetBearerToken(string publicKeyBase64, string apiKey)
{
    var keyBytes = Convert.FromBase64String(publicKeyBase64);
    var keyParameter = PublicKeyFactory.CreateKey(keyBytes);
    var rsaKeyParameters = (RsaKeyParameters)keyParameter;
    var rsaParameters = new RSAParameters
    {
        Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned(),
        Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned()
    };

    using (var rsa = new RSACryptoServiceProvider())
    {
        rsa.ImportParameters(rsaParameters);

        var dataToEncrypt = Encoding.UTF8.GetBytes(apiKey);
        var encryptedBytes = rsa.Encrypt(dataToEncrypt, false);

        return Convert.ToBase64String(encryptedBytes);
    }
}

Upvotes: 1

matheus-fofonka
matheus-fofonka

Reputation: 28

I use like this

internal partial class Criptografia{ private string ChavePublica = String.Empty;

    public Criptografia()
    {
        //if (String.IsNullOrEmpty(PertoBus.Program.PublicKeyQrCode))
        //{
        StringBuilder chavePublica = new StringBuilder();
        chavePublica.AppendLine("-----BEGIN RSA PUBLIC KEY-----");
        chavePublica.AppendLine("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
        chavePublica.AppendLine("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
        chavePublica.AppendLine("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=");
        chavePublica.AppendLine("-----END RSA PUBLIC KEY-----");
        ChavePublica = chavePublica.ToString();
        //}
        //else
        //    ChavePublica = PertoBus.Program.PublicKeyQrCode;
    }

    public string RsaCriptografarComChavePublica(string pTexto)
    {
        var bytesToEncrypt = Encoding.UTF8.GetBytes(pTexto);

        var encryptEngine = new Pkcs1Encoding(new RsaEngine());

        using (var txtreader = new StringReader(ChavePublica.ToString()))
        {
            var keyParameter = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject();

            encryptEngine.Init(true, keyParameter);
        }

        var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length));
        return encrypted;
    }
}

Upvotes: 0

matheus-fofonka
matheus-fofonka

Reputation: 28

this project in github is a example of this usage https://github.com/RomuloSantanaFadami/fadamipay-autorizador-exemplo-rsa if you have a problem with a public key formating, try use StringBuilder to make her.

Upvotes: 0

Related Questions