Featured image of post [Authcode]Python3,PHP字符串加解密

[Authcode]Python3,PHP字符串加解密

**2019年5月12日凌晨1点37分** 前两天看到一句话,大概意思是永远不要想一个人去设计某种的加密方式;emmm... 我觉得对我这种正在学习过程中的人来讲,的确是个不错的建议;所以下面的代码或者思路大家用来学习就行,“切勿当真”。 ![77491d6994ee231eb84de0f1034d48ec.jpg](/usr/uploads/images/qzone_work/2019/05/2160124163.jpg)

可能是自己无聊,也可能闲得慌,改写了一个比较简单的字符串加解密类,支持中英文特殊字符串加解密,支持设置有效性。

先简单介绍一下Authcode这个函数,Authcode这个函数很多人都使用,这函数来自Discuz程序,用于加密解密字符串,可以设置钥匙(key)和过期时间,在很多时候都用得着。

emmm… 大佬下面就不用看了吧… 菜鸡[脸红]

有道云的源码里面,又被其作者重整成一个类,可直接调用;以前自己菜,只知道这个函数特别牛X,相同内容每次加密密文都不同,也不知道其原理是什么;这次查了一些资料也引入了自己的一些想法。

Authcode如果用于字符串简单加密是一个不错的选择,想着要是python3 里面有类似函数就很棒,然而查了一下并没有类似作品,索性自己再造一次轮子。

再当python3 写完加密部分之后测试发现,即便相同字符串用相同密匙加密,用php解密函数竟然无法解密???,之后发现原因是两种语言的编码存在问题。

加解密过程中两种语言均会用到chr()和ord()函数,ASCII转换前126位正常,但超过126之后,py chr()是按照返回字符的unicode十进制值,然而PHP就开始返回乱码,原因是对中文和特殊字符会自动截断;思考之后决定PHP计算也直接unicode,unicode包括所有的字符(中文);所以有了上一篇博文,PHP unicode 单字符转换。

加解密原理:

其实吧,特别简单的一个计算方法,“异或”计算,如若不懂,这里不做介绍;针对于此种加密,个人的看法是,增加破解难度的最直接的办法就是提高密匙的复杂度,重改密匙簿的计算方法

说再多也是废话,直接上效果演示。


PHP加解密效果: PHP.png

Python3加解密效果: py3.png

两者混用: 1.png 2.png 混用:相同密匙的情况下,利用py3对字符串进行加密,再用PHP进行解密,很完美,当然反过来利用php加密Py解密效果也相同。

最后留下源码:

PHP

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<?php

class Mcrypt {
	public static $default_key = 'a!takA:dlmcldEv,e';
	
	/*
	 * 字符加解密,一次一密,可定时解密有效
	 * 
	 */
	public static function encode($string, $key = '', $expiry = 0) {
		$ckeyLength = 16;
		$key = md5($key ? $key : self::$default_key); 
		$key = md5(substr($key, 0, 16).$key.md5(substr($key, 16, 16))); 
		$keya = md5(substr($key, 0, 16)); 
		$keyb = md5(substr($key, 16, 16)); 
		$keyc = substr(md5(microtime()), -$ckeyLength);
		$cryptkey = $keya . md5($keya . $keyc);
		$keyLength = mb_strlen($cryptkey);
		$string = sprintf('%010d', $expiry ? $expiry + intval(time()) : 0) . substr(md5($string . $keyb), 0, 16) . $string;
		$stringLength = mb_strlen($string);
		
		
		$rndkey = array();
		for ($i = 0; $i <= 255; $i++) {
			$rndkey[$i] = self::char_unicode($cryptkey[$i % $keyLength], False);
		}
		
		
		$box = range(0, 255);
		for ($j = $i = 0; $i < 256; $i++) {
			$j = ($j + $box[$i] + $rndkey[$i]) % 256;
			$tmp = $box[$i];
			$box[$i] = $box[$j];
			$box[$j] = $tmp;
		}
		
		
		$result = '';
		for ($a = $j = $i = 0; $i < $stringLength; $i++) {
			$a = ($a + 1) % 256;
			$j = ($j + $box[$a]) % 256;
			$tmp = $box[$a];
			$box[$a] = $box[$j];
			$box[$j] = $tmp;
			$result .= self::char_unicode(self::char_unicode(mb_substr($string, $i, 1, 'UTF-8'), False) ^ ($box[($box[$a] + $box[$j]) % 256]));
		}

		$result = $keyc . str_replace('=', '', base64_encode($result));
		$result = str_replace(array(
			'+',
			'/',
			'='
		), array(
			'-',
			'_',
			'.'
		), $result);
		return $result;
	}
	
	/**
	 * 字符加解密,一次一密,可定时解密有效
	 * 
	 */
	public static function decode($string, $key = '') {
		$string = str_replace(array(
			'-',
			'_',
			'.'
		), array(
			'+',
			'/',
			'='
		), $string);
		$ckeyLength = 16;
		$key = md5($key ? $key : self::$default_key); 
		$key = md5(substr($key, 0, 16).$key.md5(substr($key, 16, 16))); 
		$keya = md5(substr($key, 0, 16)); 
		$keyb = md5(substr($key, 16, 16)); 
		$keyc = substr($string, 0, $ckeyLength);
		$cryptkey = $keya . md5($keya . $keyc);
		$keyLength = strlen($cryptkey);
		$string = base64_decode(substr($string, $ckeyLength));
		$stringLength = mb_strlen($string);
		
		
		$rndkey = array();
		for ($i = 0; $i <= 255; $i++) {
			$rndkey[$i] = self::char_unicode($cryptkey[$i % $keyLength], False);
		}
		$box = range(0, 255);
		
		for ($j = $i = 0; $i < 256; $i++) {
			$j = ($j + $box[$i] + $rndkey[$i]) % 256;
			$tmp = $box[$i];
			$box[$i] = $box[$j];
			$box[$j] = $tmp;
		}
		
		$result = '';
		for ($a = $j = $i = 0; $i < $stringLength; $i++) {
			$a = ($a + 1) % 256;
			$j = ($j + $box[$a]) % 256;
			$tmp = $box[$a];
			$box[$a] = $box[$j];
			$box[$j] = $tmp;
			$result .= self::char_unicode(self::char_unicode(mb_substr($string, $i, 1, 'UTF-8'), False) ^ ($box[($box[$a] + $box[$j]) % 256]));
		}
		if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
			return substr($result, 26);
		} else {
			return '';
		}
	}
	
	public static function char_unicode($str, $DECODE = True) {
		$result = '';
		if ($DECODE === False) {
			$unicodestr = intval(base_convert(bin2hex(iconv('utf-8', 'UCS-4', $str)), 16, 10));
			$result = $unicodestr;
		} else {
			$temp = intval($str);
			$result = iconv('UCS-2BE', 'utf-8', ($temp < 256) ? chr(0) . chr($temp) : chr($temp / 256) . chr($temp % 256));
		}
		return $result;
	}
}

Python3

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File  : Mcrypt.class.py
# @Author: MoMing
# @Date  : 2019/4/15
# @Desc  : 字符串加解密


class Mcrypt:
    default_key = 'a!takA:dlmcldEv,e'

    @staticmethod
    def encode(string='', key='', expiry=0):
        """
        :param string: 待加密字符串
        :param key: 加密密匙
        :param expiry: 有效期,0->永久
        :return:
        """
        import time
        from base64 import b64encode
        ckeylength = 16
        if key == '':
            key = Mcrypt.default_key
        key = Mcrypt.__md5(key)
        key = Mcrypt.__md5(key[0:16] + key + Mcrypt.__md5(key[16:]))
        keya = Mcrypt.__md5(key[0:16])
        keyb = Mcrypt.__md5(key[16:])
        keyc = Mcrypt.__md5(str(int(time.time()) * 10000))[-ckeylength:]
        cryptkey = keya + Mcrypt.__md5(keya + keyc)
        keylength = len(cryptkey)
        if expiry != 0:
            string = str(expiry + int(time.time())) + Mcrypt.__md5(string + keyb)[0:16] + string
        else:
            string = '0000000000' + Mcrypt.__md5(string + keyb)[0:16] + string
        stringlength = len(string)

        rndkey = dict()
        for i in range(256):
            rndkey[i] = ord(cryptkey[i % keylength])

        box = dict()
        for i in range(256):
            box[i] = i

        j = int(0)
        for i in range(256):
            j = (j + box[i] + rndkey[i]) % 256
            tmp = box[i]
            box[i] = box[j]
            box[j] = tmp

        result = ''
        a = j = int(0)

        for i in range(stringlength):
            a = (a + 1) % 256
            j = (j + box[a]) % 256
            tmp = box[a]
            box[a] = box[j]
            box[j] = tmp
            result += chr(ord(string[i]) ^ (box[(box[a] + box[j]) % 256]))

        base64 = str(b64encode(result.encode('utf-8')), 'utf-8')
        result = keyc + base64.replace('=', '')
        old = ['+', '/', '=']
        new = ['-', '_', '.']
        return Mcrypt.__str_replace(result, old, new)

    @staticmethod
    def decode(string='', key=''):
        """
        :param string: 加密字符串
        :param key: 加密密匙
        :return: 解密失败返回空字符
        """
        import time
        from base64 import b64decode
        ckeylength = 16
        new = ['+', '/', '=']
        old = ['-', '_', '.']
        string = Mcrypt.__str_replace(string, old, new)
        if key == '':
            key = Mcrypt.default_key
        key = Mcrypt.__md5(key)
        key = Mcrypt.__md5(key[0:16] + key + Mcrypt.__md5(key[16:]))
        keya = Mcrypt.__md5(key[0:16])
        keyb = Mcrypt.__md5(key[16:])
        keyc = string[:ckeylength]
        string = string[16:]
        missing_padding = 4 - len(string) % 4
        if missing_padding:
            string += '=' * missing_padding
        string = str(b64decode(string), 'utf-8')
        cryptkey = keya + Mcrypt.__md5(keya + keyc)
        keylength = len(cryptkey)
        stringlength = len(string)

        rndkey = dict()
        for i in range(256):
            rndkey[i] = ord(cryptkey[i % keylength])

        box = dict()
        for i in range(256):
            box[i] = i

        j = int(0)
        for i in range(256):
            j = (j + box[i] + rndkey[i]) % 256
            tmp = box[i]
            box[i] = box[j]
            box[j] = tmp

        result = ''
        a = j = int(0)
        for i in range(stringlength):
            a = (a + 1) % 256
            j = (j + box[a]) % 256
            tmp = box[a]
            box[a] = box[j]
            box[j] = tmp
            result += chr(ord(string[i]) ^ (box[(box[a] + box[j]) % 256]))
        try:
            if (int(result[:10]) == 0 or int(result[:10]) - int(time.time()) > 0) \
                    and result[10:10 + ckeylength] == Mcrypt.__md5(result[10 + ckeylength:] + keyb)[0:16]:
                return result[10 + ckeylength:]
            else:
                return ''
        except ValueError:
            return ''

    @staticmethod
    def __md5(string=str()):
        """
        :param string: hash 字符串
        :return: md5
        """
        import hashlib
        m = hashlib.md5()
        m.update(string.encode('utf-8'))
        return m.hexdigest()

    @staticmethod
    def __str_replace(string, old=[], new=[]):
        """
        old 和 new 长度必须相同,新旧必须对应
        :param old: 将被替换的子字符列表。
        :param new: 新字符串,用于替换old子字符列表
        :param string: 被替换成字符串
        :return: 新字符串
        """
        for i in range(len(old)):
            string = string.replace(old[i], new[i])
        return string

使用方法:

PHP

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?php
header('Content-type:application/json;;charset=UTF-8');
require_once __dir__ . DIRECTORY_SEPARATOR . 'Mcrypt.class.php';

$str = '123456789[密文]';

$enstr = Mcrypt::encode($str);
$destr = Mcrypt::decode($enstr);

echo '原文:'.$str.PHP_EOL;
echo '加密:'.$enstr.PHP_EOL;
echo '解密:'.$destr.PHP_EOL;

Python3

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File  : main.py
# @Author: MoMing
# @Date  : 2019/4/14
# @Desc  : Mcrypt Main


from Mcrypt import Mcrypt

string = 'ABC1234567[密文]'

enstr = Mcrypt.encode(string)
destr = Mcrypt.decode(enstr)

print('原文:', string)
print('加密:', enstr)
print('解密:', destr)
使用 Hugo 构建
主题 StackJimmy 设计