Can't locate the difference between my C# encryption function, and my PHP encryption function
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($keycha开发者_运维百科r));
$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
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.
Write output in hexadecimal, there are a lot of characters which is unseen
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.
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;
}
精彩评论