0

I have a program that encrypts passwords using a c# rsa public key which outputs a byte array.

In order for me to transport it easily and maintain data I am converting the bytes directly to a Hex string. Now this is where I am having issue. I send the post data to my script and am now unsure what to convert it to and how to decrypt it.

I am attempting to use http://phpseclib.sourceforge.net/ which I was pointed to by this post RSA decryption using private key The documentation on this is very vague and I don't know what data/type decrypt() should take.

<?php
include('Crypt/RSA.php');
if (isset($_POST['Password'])) 
    {

        $Password = $_POST['Password'];
        $crypttext = pack("H*",$Password);
        echo $cryptext;
        $rsa = new Crypt_RSA();
        $rsa->loadKey('key.priv'); 

        $decryptedText =$rsa->decrypt($cryptext);

        echo "Pass = >" . $decryptedText;
    }
?>

Note that this gives no errors but $decryptedText is empty.

EDIT: Adding more info.

This is my c# encrypt method.

public static string Encrypt(string data, string keyLocation, string keyName)
    {

        Console.WriteLine("-------------------------BEGIN Encrypt--------------------");
        // Variables
        CspParameters cspParams = null;
        RSACryptoServiceProvider rsaProvider = null;
        string publicKeyText = "";
        string result = "";
        byte[] plainBytes = null;
        byte[] encryptedBytes = null;

        try
        {
            // Select target CSP
            cspParams = new CspParameters();
            cspParams.ProviderType = 1; // PROV_RSA_FULL 

            rsaProvider = new RSACryptoServiceProvider(2048, cspParams);

            // Read public key from Server
            WebClient client = new WebClient();
            Stream stream = client.OpenRead(keyLocation + "/" + keyName);
            StreamReader reader = new StreamReader(stream);
            publicKeyText = reader.ReadToEnd();
            //
            //Console.WriteLine("Key Text : {0}",publicKeyText);

            // Import public key
            rsaProvider.FromXmlString(publicKeyText);


            // Encrypt plain text
            plainBytes = Convert.FromBase64String(data);
            Console.WriteLine("inputlength : {0}",plainBytes.Length);
            encryptedBytes = rsaProvider.Encrypt(plainBytes, false);




            result = ByteArrayToString(encryptedBytes);
            Console.WriteLine("Encrypted Hex string : {0}", result);


        }
        catch (Exception ex)
        {
            // Any errors? Show them
            Console.WriteLine("Exception encrypting file! More info:");
            Console.WriteLine(ex.Message);
        }

        rsaProvider.Dispose();
        Console.WriteLine("-------------------------END Encrypt--------------------");
        return result;
    } // Encrypt


public static byte[] StringToByteArray(String hex)
    {
        int NumberChars = hex.Length / 2;
        byte[] bytes = new byte[NumberChars];
        using (var sr = new StringReader(hex))
        {
            for (int i = 0; i < NumberChars; i++)
                bytes[i] =
                  Convert.ToByte(new string(new char[2] { (char)sr.Read(), (char)sr.Read() }), 16);
        }
        return bytes;
    }
    public static string ByteArrayToString(byte[] ba)
    {
        StringBuilder hex = new StringBuilder(ba.Length * 2);
        foreach (byte b in ba)
            hex.AppendFormat("{0:x2}", b);
        return hex.ToString();
    }

I modified the php to this

<?php
include('Crypt/RSA.php');
if (isset($_POST['Password'])) 
    {

        $Password = $_POST['Password'];
        $crypttext = pack("H*",$Password);
        echo $cryptext;
        $rsa = new Crypt_RSA();
        $rsa->loadKey(file_get_contents('key.priv')); // Added file_get_contents() which fixed the key loading
        $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1); // Added this which is essential thank you guys/gals
        $decryptedText =$rsa->decrypt($cryptext);

        echo "Pass = >" . $decryptedText; // gives unsual data. This needs to be converted from binary data to base64string I think
        echo "Pass = >" . base64_encode($decryptedText); // gives no data.
        echo "Pass = >" . base64_decode($decryptedText); // gives no data.
    }
?>

I searched around and tried several things to convert back to text and I have tried base64_encode() and base64_decode() but I get nothing and otherwise I get gobbledey gook.

Community
  • 1
  • 1
  • 1
    What encryption algorithm/scheme is your C# library using? I'd think you'd have to set the encryption/decryption mode in php and then try it. From phpseclib site `$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);` – czobrisky Aug 09 '14 at 20:50
  • I think it's RSA_Full and the little bit I gathered from inspecting the php library is that that is the default for Crypt_RSA->decrypt() $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1); tried that – That Homeless Guy Aug 09 '14 at 20:56
  • 1
    Please show us your C# code. It may be that this is due to the wrong character encoding. – Maarten Bodewes Aug 09 '14 at 23:03
  • Updated The Question with c# – That Homeless Guy Aug 10 '14 at 10:14
  • 1
    Eh, yes, but I still don't know the input: `plainBytes = Convert.FromBase64String(data);`. Maybe you should convert your PHP result to base 64 as well. Depending on the content (control characters etc.) it may not print well. – Maarten Bodewes Aug 10 '14 at 10:58
  • In addition to what owlstead suggested, did you try `$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);`? And what's the format of the key? Does `$rsa->loadKey()` return `true` or `false`? – neubert Aug 10 '14 at 14:16
  • After some inspection I found that the `$rsa->loadKey()` returns `false` – That Homeless Guy Aug 10 '14 at 21:46
  • OK, voting to close the question. Please ask a different question if you cannot get `loadKey` to work (after searching for SO questions and answers, obviously). – Maarten Bodewes Aug 10 '14 at 22:49
  • Thank you I am much closer to a result I am just a bit stuck on the base64 conversion. I updated the post. – That Homeless Guy Aug 10 '14 at 23:25
  • Is it necessary to do the frombase64string in the C# code, why not try it without? – czobrisky Aug 11 '14 at 00:00
  • frombase64string() returns an array of bytes which is essential for the encrypton in c# – That Homeless Guy Aug 11 '14 at 21:42
  • @That Homeless Guy - I'd say follow owlstead's advice and post a new question about the key. And if you can generate a key with the same format as the one you're currently using that reproduces the problem then post that so we can see what the key you're trying to use looks like. – neubert Aug 12 '14 at 14:44
  • I have one thing to test before I close this question. My webserver is currently down so I'll test when it's back up. – That Homeless Guy Aug 13 '14 at 16:34
  • 1
    If `data` is an arbitrary string, this approach is very, very broken. Yes, `FromBase64String` converts a string to a byte array - but it assumes that the input is valid base64! If you're trying to convert an *arbitrary* string to a byte array, you should use an encoding, e.g. `Encoding.UTF8.GetBytes(data)`. (Then later, you'll need to *decode* the binary data you get when you've decrypted it, to get a string result.) – Jon Skeet Aug 21 '14 at 22:26
  • Since you're using PKCS1v1.5 padding instead of OAEP, you're vulnerable to http://crypto.stackexchange.com/q/12688/24405 – Scott Arciszewski Mar 06 '16 at 18:34

1 Answers1

0

The final solution was to use imap_binary($decryptedText) to convert back.

Edit :

It has since been brought to my attention that a better way of doing this would be to replace 2 things

C#

plainBytes = Convert.FromBase64String(data);

Changed to

plainBytes = Encoding.UTF8.GetBytes(data);

and PHP

imap_binary($decryptedText)

Changed to

utf8_decode($decryptedText)