0

I wrote (what I thought to be) identical encryption functions in PHP and C#. However, encrypting the same string is not producing identical results. I'm no expert in either C# nor PHP so I was hoping someone might be able to spot the difference that for some reason I am not catching here.

PHP function:

function encrypt($string, $key) { 
$result = NULL; 
for($i=0; $i<strlen($string); $i++) { 
$char = substr($string, $i, 1); 
$keychar = substr($key, ($i % strlen($key))-1, 1); 
$char = chr(ord($char)+ord($keychar)); 
$result.=$char; 
}

//return $result;
return $result;
}

C# function:

        public static string encrypt_php_data(string stringToEncrypt, string key)
        {
            var result = string.Empty;

            for (int i = 0; i < stringToEncrypt.Length; i++)
            {
                string keychar = phpSubStr_replacement(key, (i % key.Length) - 1);
                result += (char)(Convert.ToChar(stringToEncrypt.Substring(i, 1)) + Convert.ToChar(keychar));
            }

            return result;
        }

private static string phpSubStr_replacement(string stringToGrab, int startIndex)
        {

            if (startIndex < 0)
            {
                // Take from end of string
                return stringToGrab.Substring(stringToGrab.Length + startIndex, 1);
            }

            else
            {
                // Take from beginning of string
                return stringToGrab.Substring(startIndex, 1);
            }
        }

Here are the results of encrypting identical strings:

String encrypted: 09/16/2011 15:27:45

password used: somekey

C# Result: ©¬©¤  «ª©¡ 

PHP Result: ©¬žž›š—©¤ – Ÿ«ª©¡š

Note:

Not all outputs vary from each other. I cannot understand why some are different, while others produce the same outcome, makes no sense.

I look forward to your responses,

Evan

8
  • are these on the same system? The PHP version looks like the C# version but with extra characters. Commented Sep 16, 2011 at 19:53
  • 3
    Have you looked at the encoding of the strings? Commented Sep 16, 2011 at 19:55
  • Could you explain a bit further? I have not ... Commented Sep 16, 2011 at 20:01
  • @Chris Yes these are on the same system. Commented Sep 16, 2011 at 20:02
  • What do you want to use this encryption for? It has a number of weaknesses. It's basically a stream cypher, and thus has the associated problems. In particular it's broken if you ever reuse a key or if your input exceeds the key length. Commented Sep 16, 2011 at 20:11

4 Answers 4

2

First, you really should be using a cryptographically-strong encryption function because schemes like this one where individual bytes are summed with key bytes can be easily broken. That being said, the main reason why the two codes differ in output is that PHP is performing the addition operations on 8-bit ASCII-encoded bytes whereas C# is performing the addition operations on 16-bit UTF-16 code units (See: .NET internal Encoding).

The "fix" on the C# side is to convert the string-to-be-encrypted and the key to their ASCII encodings before performing the addition operations:

using System;
using System.Collections.Generic;
using System.Text;

namespace Test
{
    public class SO7449615
    {
        public static string encrypt_php_data(string stringToEncrypt, string key) {
            ASCIIEncoding asciiEncoding = new ASCIIEncoding();
            byte[] stringToEncryptBytes = asciiEncoding.GetBytes(stringToEncrypt);
            byte[] keyBytes = asciiEncoding.GetBytes(key);

            byte[] retBytes = new byte[stringToEncryptBytes.Length];
            for (int i = 0; i < stringToEncryptBytes.Length; ++i) {
                byte keyByte = keyBytes[(i + keyBytes.Length - 1) % keyBytes.Length];
                retBytes[i] = (byte)(stringToEncryptBytes[i] + keyByte);
                //Console.Write(' ');
                //Console.Write(retBytes[i]);
            }
            //Console.WriteLine();
            return asciiEncoding.GetString(retBytes);
        }

        public static void Main(string[] args)
        {
            string stringToEncrypt = "test";
            string key = "somekey";
            Console.WriteLine(encrypt_php_data(stringToEncrypt, key));
        }
    }
}

It is equivalent to your original PHP code as well as the following version:

<?php
function encrypt($string, $key) {
    $string_len = strlen($string);
    $key_len = strlen($key);
    $ret = "";

    for ($i = 0; $i < $string_len; ++$i) {
        $key_char = $key[($i + $key_len - 1) % $key_len];
        $b = ord($string[$i]) + ord($key_char);
        $ret .= chr($b);
        //echo " $b";
    }
    //echo "\n";
    return $ret;
}

echo encrypt("test", "somekey") . "\n";

But again, I do not recommend that these functions be used to encrypt data. This encrypt() function employs a weak encryption scheme that is easily broken. Also, it does not allow non-ASCII strings to be encrypted or used as keys.

You mentioned that you are running PHP on a web host that does not allow extensions. Have you specifically checked for the presence of the mcrypt extension? Perhaps your web host has it pre-installed.

Sign up to request clarification or add additional context in comments.

5 Comments

Yes I have done a check for this extension, it does not exist. I may just upgrade to a new host.
@Evan: Out of curiosity, which web hosting company are you using?
@Evan: If encrypting strings is a critical aspect of your app, then it might be a good idea to switch hosting companies. If not, you can simply use a pure PHP implementation of the RSA algorithm (e.g. stevish.com/rsa-encryption-in-pure-php).
I was using free hosting for the time being (Zymos), but I will be changing hosts after this debacle.
RC4 is a lot more secure than what you are using and is extremely easy to program. It is obsolescent for really secure work, but fine for mid-level security.
0

Write output in hexadecimal, there are a lot of characters which is unseen

1 Comment

I understand that characters are missing. Regardless, though, the outputs are not identical.
0

Your "encryption" function is subject to overflow. When you add two ASCII values like you do with ord($char) + ord($keychar) in the PHP version, you can easily end up with a value that is no longer a valid ASCII character. PHP and C# may handle this differently, and that's what you're seeing. It works fine for some characters like the numerals, but gets messed up for characters like the '\' and ':'.

You should really use an established encryption or encoding function here, but if you really need to roll your own, you may need to redesign it as this one is broken.

3 Comments

Unfortunately, my hosting does not support any PHP modules - making it necessary for me to produce my own. Might you have any tips for me?
Here, overflow is not an issue because PHP's chr() function mods the argument by 256: codepad.org/adOqAg5e
I see, so in C# where an overflow exception would be thrown, PHP self-fixes it?
0

I suspect C# adds the key modulo 2^16 (It's using 16 bit chars) and php modulo 2^8 using 8 bit chars.

Also your C# code is very bloated. I'd try something like the following:

public static string encrypt_php_data(string stringToEncrypt, string key)
{
    var result = string.Empty;
    for (int i = 0; i < stringToEncrypt.Length; i++)
    {
        char keychar = key[(i+key.Length- 1) % key.Length];
        result += (char)((stringToEncrypt[i] + keychar));
    }
    return result;
}

2 Comments

How would I go about fixing this then? Is there some way I could specify which to use?
What encoding do you want? And what do you want to happen if you get a character as input that can't be represented in the reduced charset? Unicode has been introduced for a reason.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.