В общем понадобилось хранить зашифрованный пароль в базе данных (firebase). При этом бэкэнд работает с firebase и может принимать запросы от фронтэнда, фронтэнд работает с firebase и может отправлять запросы на бэкэнд. Для редактирования базы данных связка фронтэнда с бэкэндом не нужна, как не нужна и для работы с бэкэндом из консоли сервера.
Проще говоря нужна была возможность:
1)шифровать и расшифровывать строку в javascript
2)шифровать и расшифровывать строку в php
3)шифровать в javascript, расшифровывать в php
4)шифровать в php, расшифровывать в javascript
Все это должно быть действительное шифрование с ключевой строкой, а не просто кодирование. На то чтобы это организовать убил по меньшей мере несколько часов ковыряния google в поисках ответов. Ответы пришлось собирать по кусочкам и все равно написать собственные функции.
Со стороны javascript библиотека ssl представлена CryptoJS.
Со стороны php библиотекой php-mcrypt.
Путем проб и ошибок написал функцию для шифрования/дешифрования в javascrypt
1 |
MyCryptoAES(mkey, salt, message, command); |
mkey — ключ для шифрования/дешифрования
salt — вертор шифрования/дешифрования
message — строка для шифрования/дешифрования
command — encrypt для шифрования/decrypt для дешифрования
Для работы функции нужно подключить AES(в данном случае) из пакета CryptoJS:
Скачать его можно по ссылке выше или ТУТ.
Также для работы функции необходима функция вычисления md5(спасибо жителям форумов за нее, гуглится по ключу «аналог md5() javascript»):
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 |
var md5=new function(){ var l='length', h=[ '0123456789abcdef',0x0F,0x80,0xFFFF, 0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476 ], x=[ [0,1,[7,12,17,22]], [1,5,[5, 9,14,20]], [5,3,[4,11,16,23]], [0,7,[6,10,15,21]] ], A=function(x,y,z){ return(((x>>16)+(y>>16)+((z=(x&h[3])+(y&h[3]))>>16))<<16)|(z&h[3]) }, B=function(s){ var n=((s[l]+8)>>6)+1,b=new Array(1+n*16).join('0').split(''); for(var i=0;i<s[l];i++)b[i>>2]|=s.charCodeAt(i)<<((i%4)*8); return(b[i>>2]|=h[2]<<((i%4)*8),b[n*16-2]=s[l]*8,b) }, R=function(n,c){return(n<<c)|(n>>>(32-c))}, C=function(q,a,b,x,s,t){return A(R(A(A(a,q),A(x,t)),s),b)}, F=function(a,b,c,d,x,s,t){return C((b&c)|((~b)&d),a,b,x,s,t)}, G=function(a,b,c,d,x,s,t){return C((b&d)|(c&(~d)),a,b,x,s,t)}, H=function(a,b,c,d,x,s,t){return C(b^c^d,a,b,x,s,t)}, I=function(a,b,c,d,x,s,t){return C(c^(b|(~d)),a,b,x,s,t)}, _=[F,G,H,I], S=(function(){ with(Math)for(var i=0,a=[],x=pow(2,32);i<64;a[i]=floor(abs(sin(++i))*x)); return a })(), X=function (n){ for(var j=0,s='';j<4;j++) s+=h[0].charAt((n>>(j*8+4))&h[1])+h[0].charAt((n>>(j*8))&h[1]); return s }; return function(s){ var $=B(''+s),a=[0,1,2,3],b=[0,3,2,1],v=[h[4],h[5],h[6],h[7]]; for(var i,j,k,N=0,J=0,o=[].concat(v);N<$[l];N+=16,o=[].concat(v),J=0){ for(i=0;i<4;i++) for(j=0;j<4;j++) for(k=0;k<4;k++,a.unshift(a.pop())) v[b[k]]=_[i]( v[a[0]], v[a[1]], v[a[2]], v[a[3]], $[N+(((j*4+k)*x[i][1]+x[i][0])%16)], x[i][2][k], S[J++] ); for(i=0;i<4;i++) v[i]=A(v[i],o[i]); };return X(v[0])+X(v[1])+X(v[2])+X(v[3]); }}; |
Код функции шифрования/дешифрования приведен ниже:
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 |
function MyCryptoAES(mkey, salt, message, command){ try{ var key = CryptoJS.enc.Hex.parse(md5(mkey)); var iv = CryptoJS.enc.Hex.parse(md5(salt)); if(command == 'encrypt'){ var encrypted = CryptoJS.AES.encrypt( message,key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 } ); return (encrypted.toString()); } else if(command == 'decrypt'){ var decrypted = CryptoJS.AES.decrypt( message,key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 } ); return (decrypted.toString(CryptoJS.enc.Utf8)); } else {return;} } catch(e) {return e;} } |
Со стороны php, как уже писал выше должен быть установлен и подключен php-mcrypt. Сама функция шифрования/дешифрования максимально приближена к той, что в javascript(аргументы функции аналогичны и расписаны выше):
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 |
function MyCryptoAES($mkey, $salt, $message, $command){ try { if($command == 'encrypt') { $key = pack("H*", md5($mkey)); $iv = pack("H*", md5($salt)); $shown = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $message, MCRYPT_MODE_CBC, $iv); return base64_encode($shown); } elseif($command == 'decrypt'){ $key = pack("H*", md5($mkey)); $iv = pack("H*", md5($salt)); $encrypted = base64_decode($message); $shown = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv); $dec_s = strlen($shown); $padding = ord($shown[$dec_s-1]); $shown = substr($shown, 0, -$padding); return trim($shown); } else { return; } } catch(Exception $e) { return $e; } } |
Из особенностей то, что в php нужно кодировать результат в base64 и декодировать сообщение из base64, а также при декодировании удалять мусор от PKCS7.