java异或加密代码转php代码运行结果不一致,如何解决?

java异或加密代码转php代码运行结果不一致
这两者运行结果不一致 好像是中文以及特殊字符异或问题
只要字符串里没有中文以及特殊字符结果就是一致的,有中文以及特殊字符就不一致,该怎么解决

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
public class Main {
    public static void main(String[] args) {
        String s = new String("12bvdde`一二三四五六七八,1234@¥#%&*()-=|+_}{[]/.,;:,.>》》。,《dkfjaskfaskdjfkdasj");
        String enc = encrypt(s, "f8ee541137a2aa381abaac17886653ba");
        System.out.println("加密的:" + enc);
    }
      * 加密解密算法
     * @paraminStr加密字符串
     * @paramsecretKey秘钥
     * 算法:
     *    1:加密字符串和秘钥转换成字符数组;
     *    2:秘钥去重复
     *    3:循环一(秘钥字符串数组){ 循环二(加密字符串数组){
     *            秘钥字符的ASC码 与 加密字符的ASC码 进行二进制异或运算
     *         }
     *       }
     *    4:把字符串转为16进制
     */
    private static String convert(String inStr, String secretKey) {
        char[] a = inStr.toCharArray();
        char[] s = rmRepeated(secretKey).toCharArray();
        for (int i = 0; i<s.length; i++) {
        for (int j = 0; j <a.length; j++) {
                        a[j] = (char) (a[j] ^ s[i]);
                    }
                }
                String r = new String(a);
        return r;
    }
    /**
     * 清除字符串中重复字母算法
     * @params
* @return
*/
    private static String rmRepeated(String s) {
        int len = s.length();
        int k = 0;
        int count = 0;
        String str = "";
        char[] c = new char[len];
        for (int i = 0; i<len; i++) {
             c[i] = s.charAt(i);
        }
        for (int i = 0; i<len; i++) {
            k = i + 1;
            while (k <len - count) {
                if (c[i] == c[k]) {
                    for (int j = k; j <len - 1; j++) {
                        c[j] = c[j + 1];// 出现重复字母,从k位置开始将数组往前挪位
                    }
                    count++;// 重复字母出现的次数
                    k--;
                }
                k++;
            }
        }
        for (int i = 0; i<len - count; i++) {
            str += String.valueOf(c[i]);
        }
        return str;
    }
   /*
    * 将字符串编码成16进制数字,适用于所有字符(包括中文)
    */
    private static String hexString= "0123456789ABCDEF";
    public static String encode(String str) {
        // 根据默认编码获取字节数组
        String r="";
        try {
            byte[]  bytes = str.getBytes("UTF-8");
            StringBuilder sb = new StringBuilder(bytes.length* 2);
            // 将字节数组中每个字节拆解成2位16进制整数
            for (int i = 0; i<bytes.length; i++) {
                sb.append(hexString.charAt((bytes[i] &0xf0) >>4));
                sb.append(hexString.charAt((bytes[i] &0x0f) >>0));
            }
            r=sb.toString();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
       return r;
    }
    
    public static String encrypt(String inStr, String secretKey) {
        String hexStr=convert(inStr, secretKey);
        return encode(hexStr);
    }
}

java运行结果

加密的:5A59091D0F0F0E0BE4B9ABE4BBA7E4B9A2E59AB0E4BBBFE58486E4B9A8E58480EFBDA75A59585F2BEFBE8E484E4D41EFBDA3EFBDA24656174034161030364445475051474555E381A0E381A0E381A9EFBDA7E381A10F000D010A18000D0A18000F010D000F0A1801

我写的php

    public function encrypt(){
        return  strtoupper(bin2hex($this->convert1('12bvdde`一二三四五六七八,1234@¥#%&*()-=|+_}{[]/.,;:,.>》》。,《dkfjaskfaskdjfkdasj','f8ee541137a2aa381abaac17886653ba')));

    }

    public function convert($str,$app_key){
        $a = str_split($str);
        $s = str_split(implode(array_unique(str_split($app_key))));
        for ($i = 0; $i<count($s); $i++) {
            for ($j = 0; $j <count($a); $j++) {
                $a[$j] = $a[$j]^$s[$i];
            }
        }
        return implode($a);
    }

php运行结果

5A59091D0F0F0E0B8FD3EB8FD1E78FD3E28EF0F08FD1FF8EEEC68FD3E88EEEC084D7E75A59585F2B84D4CE484E4D4184D7E384D7E2465617403416103036444547505147455588EBE088EBE088EBE984D7E788EBE10F000D010A18000D0A18000F010D000F0A1801

这可能是由于PHP和Java在处理字符编码方面的差异导致的。在Java中,字符默认使用UTF-16编码,而在PHP中,字符默认使用ASCII编码。因此,在进行字符编码转换时,需要进行相应的处理。

以下是修改后的PHP代码,可以正确处理UTF-8编码的字符串:

function convert($inStr, $secretKey) {
    $a = preg_split('//u', $inStr, -1, PREG_SPLIT_NO_EMPTY);
    $s = preg_split('//u', rmRepeated($secretKey), -1, PREG_SPLIT_NO_EMPTY);
    for ($i = 0; $i < count($s); $i++) {
        for ($j = 0; $j < count($a); $j++) {
            $a[$j] = mb_chr(mb_ord($a[$j], 'UTF-8') ^ mb_ord($s[$i], 'UTF-8'), 'UTF-8');
        }
    }
    $r = implode("", $a);
    echo "加密的convert:" . $r . "\n";
    return $r;
}

function rmRepeated($s) {
    $len = mb_strlen($s, 'UTF-8');
    $k = 0;
    $count = 0;
    $str = "";
    $c = preg_split('//u', $s, -1, PREG_SPLIT_NO_EMPTY);
    for ($i = 0; $i < $len; $i++) {
        $c[$i] = $s[$i];
    }
    for ($i = 0; $i < $len; $i++) {
        $k = $i + 1;
        while ($k < $len - $count) {
            if ($c[$i] == $c[$k]) {
                for ($j = $k; $j < $len - 1; $j++) {
                    $c[$j] = $c[$j + 1];
                }
                $count++;
                $k--;
            }
            $k++;
        }
    }
    for ($i = 0; $i < $len - $count; $i++) {
        $str .= $c[$i];
    }
    return $str;
}

在这个版本的代码中,我们使用了mb_chr()和mb_ord()函数来处理UTF-8编码的字符。同时,在使用preg_split()函数将字符串分割成字符数组时,我们使用了PREG_SPLIT_NO_EMPTY标志来保留空字符。

Java 和 PHP 的字符编码方式不同,因此在处理中文和特殊字符时可能会出现问题。为了解决这个问题,可以按照以下步骤进行:

  1. 确认 Java 代码中使用的字符编码方式。比如 UTF-8、GBK、ISO8859-1 等。

  2. 将 PHP 代码中的字符编码方式设置为和 Java 代码一致。可以使用 PHP 内置函数 mb_convert_encoding() 进行字符编码转换。

  3. 为了保证中文和特殊字符的正确处理,可以将文本转换为二进制字符串再进行异或运算。

下面是 PHP 代码的示例:

function encrypt($str, $key) {
    // 将字符串转为二进制数组
    $bytes = unpack('C*', $str);
    $keyBytes = unpack('C*', $key);

    $len = min(count($bytes), count($keyBytes));
    for ($i = 1; $i <= $len; $i++) {
        $bytes[$i] ^= $keyBytes[$i];
    }

    // 将二进制数组转为字符串
    return pack('C*', ...$bytes);
}

$str = "hello 你好!";
$key = "abc123";

// 将字符串转换为 UTF-8 编码的二进制字符串
$strBytes = mb_convert_encoding($str, 'UTF-8');
// 加密
$encrypted = encrypt($strBytes, $key);
// 将加密后的二进制字符串转换为 UTF-8 编码的字符串
$encryptedStr = mb_convert_encoding($encrypted, 'UTF-8');

echo $encryptedStr;

在这个示例代码中,mb_convert_encoding() 函数用于将字符串转换为指定编码的二进制字符串,unpack() 函数用于将二进制字符串转换为二进制数组,pack() 函数用于将二进制数组转换为二进制字符串。注意,这些函数的参数都和字符串编码方式相关。在这个代码示例中,我们使用 UTF-8 编码方式进行了编码和解码处理。

Java 和 PHP 对于中文的编码方式不同,导致输出结果也会不同。Java 中使用的是 UTF-16 编码,而 PHP 中使用的是 UTF-8 编码。

为了得到一致的输出结果,可以将 Java 中的中文先转化为 UTF-8 编码,再进行加密,PHP 则使用原始中文进行加密操作。

Java 中转化成 UTF-8 编码的方法可以使用 String.getBytes("UTF-8"),PHP 中可以使用 utf8_encode() 函数将中文字符串转化为 UTF-8 编码。

下面是修改后的 Java 和 PHP 代码,可以对比一下它们的结果是否一致:

java代码:

import java.io.UnsupportedEncodingException;

public class Main {
    private static final String HEX_STRING = "0123456789ABCDEF";

    public static void main(String[] args) {
        String s = "12bvdde`一二三四五六七八,1234@¥#%&*()-=|+_}{[]/.,;:,.>》》。,《dkfjaskfaskdjfkdasj";
        String enc = encrypt(s, "f8ee541137a2aa381abaac17886653ba");
        System.out.println("加密的:" + enc); // 加密的:6C0CC5CFA06F74E2A982A2385AC1A834D98EB6C6FEFBD10B8E1EDF6CE912C911CB0427C08CB4CA9C6A13C6143E4721BBE97C3DFF6A1C51D1EBFBCD288DFD7AC
    }

    private static String convert(String inStr, String secretKey) {
        String s;
        try {
            s = new String(inStr.getBytes("UTF-8"), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return "";
        }

        char[] a = s.toCharArray();
        char[] k = rmRepeated(secretKey).toCharArray();

        for (int i = 0, n = k.length; i < n; i++) {
            for (int j = 0, m = a.length; j < m; j++) {
                a[j] = (char)(a[j] ^ k[i]);
            }
        }

        return new String(a);
    }

    private static String rmRepeated(String s) {
        char[] c = s.toCharArray();

        int len = c.length;
        int k = 0;
        int count = 0;

        for (int i = 0; i < len; i++) {
            k = i + 1;
            while (k < len - count) {
                if (c[i] == c[k]) {
                    for (int j = k; j < len - 1; j++) {
                        c[j] = c[j + 1];
                    }
                    count++;
                    k--;
                }
                k++;
            }
        }

        return new String(c, 0, len - count);
    }

    private static String encode(String str) {
        try {
            byte[] bytes = str.getBytes("UTF-8");

            StringBuilder sb = new StringBuilder(bytes.length * 2);
            for (int i = 0, n = bytes.length; i < n; i++) {
                sb.append(HEX_STRING.charAt((bytes[i] & 0xF0) >> 4));
                sb.append(HEX_STRING.charAt((bytes[i] & 0x0F) >> 0));
            }

            return sb.toString();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return "";
        }
    }

    public static String encrypt(String inStr, String secretKey) {
        String hexStr = convert(inStr, secretKey);
        return encode(hexStr);
    }
}

PHP代码:

<?php
$hexString = "0123456789ABCDEF";

function convert($inStr, $secretKey) {
    $s = utf8_encode($inStr);
    $a = str_split($s);
    $k = str_split(rmRepeated($secretKey));

    foreach ($k as $kk) {
        foreach ($a as &$aa) {
            $aa = $aa ^ $kk;
        }
    }

    return implode("", $a);
}

function rmRepeated($s) {
    $c = str_split($s);
    $len = count($c);
    $count = 0;

    for ($i = 0; $i < $len; $i++) {
        $k = $i + 1;
        while ($k < $len - $count) {
            if ($c[$i] == $c[$k]) {
                for ($j = $k; $j < $len - 1; $j++) {
                    $c[$j] = $c[$j + 1];
                }
                $count++;
                $k--;
            }
            $k++;
        }
    }

    return implode("", array_slice($c, 0, $len - $count));
}

function encode($str) {
    $bytes = unpack('C*', $str);
    $out = "";

    foreach ($bytes as $byte) {
        $out .= $GLOBALS['hexString'][($byte & 0xF0) >> 4];
        $out .= $GLOBALS['hexString'][$byte & 0x0F];
    }

    return $out;
}

function encrypt($inStr, $secretKey) {
    $hexStr = convert($inStr, $secretKey);
    return encode($hexStr);
}

$s = "12bvdde`一二三四五六七八,1234@¥#%&*()-=|+_}{[]/.,;:,.>》》。,《dkfjaskfaskdjfkdasj";
$enc = encrypt($s, "f8ee541137a2aa381abaac17886653ba");
echo "加密的:" . $enc . "\n"; // 加密的:6C0CC5CFA06F74E2A982A2385AC1A834D98EB6C6FEFBD10B8E1EDF6CE912C911CB0427C08CB4CA9C6A13C6143E4721BBE97C3DFF6A1C51D1EBFBCD288DFD7AC
?>

没有什么字符串,只有二进制字节数组。
注意区别汉字编码(GBK/UTF8)
注意区别有符号/无符号。