我们需要第前端传输内容进行加密然后传递到后端,我们该如何做呢?
偶然间看到网络上有一个加密解密代码,然后我开始进入郁闷的道路,这些代码有时好有时又行了,
问题在哪里呢? 我研究了很久,终于修复了错误,并讲加密解密代码分享给大家。
首先上代码,以下代码同网络上类似的代码有区别,请特别注意。
JS 相关
"use strict"
import md5 from 'js-md5'
import { encode, decode } from 'js-base64';
export default {
//加密
encode(txt, key){
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/-=";
var nh = 1;//Math.floor(Math.random() * 64) ;//获取一个字符
var ch = chars[nh];//字典中字符
var mdKey = md5(key + ch);//创建了一个随机的key
mdKey = mdKey.substr(nh % 8, nh % 8 + 7);
txt = encode(txt);//base64
txt = txt.replace('=','');//替换多余的等号等号是为了凑字数没有实际意义
var tmp = '',j = 0, k = 0;
for (var i = 0; i < txt.length; i++) {
k = k == mdKey.length ? 0 : k;//获取mdKey中的索引
//57(随机位置)+ (base64字符在字典中的位置) + (字典中字符码)
j = (nh + chars.indexOf(txt[i]) + mdKey[k++].charCodeAt(0)) % 64;//余数
tmp += chars[j];
}
return encodeURIComponent(ch + tmp);//
},
//解密
decode(txt, key){
txt = decodeURIComponent(txt);
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/-=";
var ch = txt[0];
var nh = chars.indexOf(ch);
var mdKey = md5(key + ch);
mdKey = mdKey.substr(nh % 8, nh % 8 + 7);
txt = txt.substr(1);
var tmp = '', j = 0, k = 0;
for (var i = 0; i < txt.length; i++) {
k = k == mdKey.length ? 0 : k;
j = chars.indexOf(txt[i]) - nh - mdKey[k++].charCodeAt(0);
while (j < 0) {
j += 64;
}
tmp += chars[j];
}
return decode(tmp);
}
};
PHP相关代码
<?php //php加密解密:同时满足前端加密解密要求 class Encryption{ //解密函数 public static function decode($txt, $key = '******') { $txt = urldecode($txt); $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/-="; $ch = $txt[0]; $nh = strpos($chars,$ch); $mdKey = md5($key.$ch); $mdKey = substr($mdKey,$nh%8, $nh%8+7); $txt = substr($txt,1); $tmp = ''; $i=0;$j=0; $k = 0; for ($i=0; $i<strlen($txt); $i++) { $k = $k == strlen($mdKey) ? 0 : $k; $j = strpos($chars,$txt[$i])-$nh - ord($mdKey[$k++]); while ($j<0) $j+=64; $tmp .= $chars[$j]; } return base64_decode($tmp); } //加密函数 public static function encrypt($txt, $key = '******') { $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/-="; $nh = rand(0,64); $ch = $chars[$nh]; $mdKey = md5($key.$ch); $mdKey = substr($mdKey,$nh%8, $nh%8+7); $txt = base64_encode($txt); #如果没有4个字节的整数倍末尾用等号补上 $txt = str_replace('=','',$txt);//替换没有用的等号否则解密会出错的 $tmp='';$i=0;$j=0;$k = 0; for ($i=0; $i<strlen($txt); $i++) { $k = $k == strlen($mdKey) ? 0 : $k; $j = ($nh+strpos($chars,$txt[$i])+ord($mdKey[$k++]))%64; $tmp .= $chars[$j]; } return urlencode($ch.$tmp); } }
以上内容大部分来自网络,但是我调试了很久,基本上看是类似但是都无法成功加密和解密。
其中问题在于 base64 函数和 encodeURIComponent 相关函数带来的困扰。
网络上的代码错误的原因:
1、没有考虑base64 在加密后的对4字节通过“=” 号补齐的规定,但是部分内容加密后无法解密。
2、没有考虑到网络传输中转码的要求,而在前端(JS) 采用了 encodeURI 和 decodeURI,导致后端(PHP) 断无法解密
为此以上代码已经做了修正:
js 端修正
txt = encode(txt);//base64
txt = txt.replace('=','');//替换多余的等号等号是为了凑字数没有实际意义
PHP端修正
$txt = str_replace('=','',$txt);//替换没有用的等号否则解密会出错的
对应前端加密应用场景,例如密码加密,保证传输过程是加密状态;
当然以上前端代码如何直接使用肯定是有问题的,建议看我的rollup打包开箱就用文章,直接将该内容打包成js类库文件;这样就相对好些
感谢本加密解密的最初作者。
感谢阅读本文的作者。
如果需要技术交流留言联系。