自定义加解密算法原理解析

  网上的自定义加解密算法都是基于异或运算来实现的,我们先来了解一下什么是异或运算。
 
  异或运算是双目运算(和加减乘除一样),即运算符左右两边要各有一个操作数,其计算机运算符号为“^”。
 
  异或运算会把两个操作数都转为二进制才开始按位计算,其运算法则可以用一句话概括:相同则结果为0,否则为1。
 
<?php
var_dump(0 ^ 0); // int(0)  0和0相同,结果为0
var_dump(0 ^ 1); // int(1)  0和1不同,结果为1
var_dump(1 ^ 0); // int(1)  1和0不同,结果为1
var_dump(1 ^ 1); // int(0)  1和1相同,结果为0
var_dump(5 ^ 3); // int(6)
 
  根据运算法则,上面代码的0和1之间的异或运算很容易理解,主要是“5 ^ 3”不好理解,但只要把两个数转都为二进制,就很清楚了。
 
  5和3转为二进制分别为0101和0011,把两个二进制数上下排列并且将每一位对齐,然后每一位的上下两个数字成对进行异或运算:
 
  0  1  0  1(二进制的5)
  0  0  1  1(二进制的3)
  -------------------------
  0  1  1  0(二进制的6)
 
  所以5 ^ 3的异或运算结果为二进制数0110,也就是十进制的6。
 
  异或运算强调一个“异”字,也就是两数不同结果才为1,与之相反的是同或运算,这里就不再说明。
 
  说了这么多,这跟加密有什么关系呢?异或运算有一个非常重要的性质:自反性,这个性质可以说是使用异或运算实现加密的根本。
 
  异或运算自反性:给定一个数a,将其与b进行两次异或运算,得到的结果为a本身。
 
  下面的代码就直观地展示了异或运算的自反性:
 
<?php
var_dump('msg' ^ 'key' ^ 'key'); // string(3) "msg"
 
  如果把msg当做信息明文,把key当做密钥,那么“msg ^ key”就是加密过程,而其结果就是加密后的密文,把密文和key再进行一次异或运算就是解密过程,这就是利用异或运算的自反性实现加解密的原理。
 
  重要提醒:异或运算加密安全性很弱,如非必要应尽量使用openssl_encrypt()、openssl_public_encrypt()、password_hash()等内置函数来加密,尤其是保存用户登录密码、网络传输数据、生成数字签名等场景更应该使用这些安全性更强的内置加密函数来实现。
 
  下面是异或运算加解密的实现代码:

<?php
/**
 * 基于异或运算自反性的加解密函数
 *
 * @param string $data 要加密或解密的数据
 * @param string $action 操作,可选值:encrypt=加密|decrypt=解密
 * @return string 加密或解密结果
 */
function xor_crypt($data, $action = 'encrypt')
{
    $key = 'www.manong.life'; // 加解密所必须的密钥

    /**
     * 加解密核心函数(异或运算)
     * 备注:这个匿名函数是代码的核心部分。
     *
     * @param string $data 要加密或解密的数据
     * @param string $key 密钥
     * @return string 加密或解密结果
     */
    $xor = static function ($data, $key) {
        $datalen = strlen($data); // 数据长度,单位:字节(byte)
        $keylen = strlen($key); // 密钥长度,单位:字节(byte)

        $result = ''; // 保存加解密数据每个字节的异或运算结果

        // 逐个字节遍历要加密或解密的数据,每个字节都进行一次异或运算
        for ($i = 0; $i < $datalen; $i++) {
            $byte = $key[$i % $keylen]; // 从密钥取一个字节作为异或运算的操作数
            $result .= $data[$i] ^ $byte;
        }

        return $result;
    };

    //========== 加密操作·开始 ==========//
    if ($action === 'encrypt') {
        $encrypt = $xor($data, $key);
        $encrypt = base64_encode($encrypt); // 密文是一堆乱码,需要用base64_encode()进行编码处理方便传输和保存
        return $encrypt;
    }
    //========== 加密操作·结束 ==========//

    //========== 解密操作·开始 ==========//
    $decrypt = base64_decode($data); // 加密操作最后用base64_encode()编码了密文,这里需要先解码
    $decrypt = $xor($decrypt, $key);
    return $decrypt;
    //========== 解密操作·结束 ==========//
}

$encrypt = xor_crypt('PHP是世界上最好的语言', 'encrypt');
$decrypt = xor_crypt($encrypt, 'decrypt');

echo "加密结果:{$encrypt}<br>" . PHP_EOL; // 加密结果:Jz8nyPXOitf4gLvgjd7vkev3y8jcifXqj4HBgc7l
echo "解密结果:{$decrypt}<br>" . PHP_EOL; // 解密结果:PHP是世界上最好的语言

Copyright © 2024 码农人生. All Rights Reserved