无法找到我的c#加密函数和PHP加密函数之间的区别


Can't locate the difference between my C# encryption function, and my PHP encryption function

我用PHP和c#写了(我认为是)相同的加密函数。但是,加密相同的字符串不会产生相同的结果。我既不是c#也不是PHP的专家,所以我希望有人能够发现由于某种原因我在这里没有捕捉到的差异。

PHP功能:

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#功能:

        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);
            }
        }

下面是对相同字符串加密的结果:

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

使用的密码:somekey

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

注意:

并非所有输出都彼此不同。我不明白为什么有些不同,而另一些却产生相同的结果,这没有意义。

我期待你的回复,

艾凡

首先,您确实应该使用密码学强的加密函数,因为像这种将单个字节与密钥字节相加的方案很容易被破解。也就是说,这两种代码输出不同的主要原因是PHP对8位ascii编码的字节执行加法运算,而c#对16位UTF-16编码单元执行加法运算(参见:. net内部编码)。

c#方面的"修复"是在执行加法操作之前将要加密的字符串和密钥转换为它们的ASCII编码:
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));
        }
    }
}

它相当于您的原始PHP代码以及以下版本:

<?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";

但是,我还是不建议使用这些函数来加密数据。这个encrypt()函数采用了一个很容易被破解的弱加密方案。此外,它不允许非ascii字符串被加密或用作密钥。

你提到你正在一个不允许扩展的web主机上运行PHP。您是否特别检查了加密扩展的存在?

用十六进制写输出,有很多字符是看不见的

您的"加密"功能可能会溢出。当您像在PHP版本中使用ord($char) + ord($keychar)那样添加两个ASCII值时,您很容易得到一个不再是有效ASCII字符的值。PHP和c#可能会以不同的方式处理这个问题,这就是您所看到的。对于像数字这样的字符,它工作得很好,但对于像'''和':'这样的字符,它会变得混乱。

您确实应该在这里使用已建立的加密或编码函数,但如果您确实需要使用自己的加密或编码函数,则可能需要重新设计它,因为这个函数已经损坏。

我怀疑c#添加了键模2^16(它使用16位字符)和php模2^8使用8位字符。

而且你的c#代码非常臃肿。我将尝试如下操作:

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;
}