Мар
13
2008
Асинхронное шифрование в javascript
Автор: Азарёнок Иван
А началось все с этой темы. Поначалу, действительно была не очень ясна необходимость такой системы. Но поразмыслив немного (да ещё и интересно было реализовать это именно на js) я решил, что такая схема всё-же имеет смысл. В частности, предлагаемое здесь решение, при всей своей простоте, позволит надежно защитить канал передачи конфиденциальных данных (того же пароля) от большинства видов сниффинга.
Ниже представлен простейший код обмена зашифрованными данными между сервером и js-клиентом. Вкратце, алгорим действий таков:
Предлагаемые скрипты реализуют алгоритм шифрования RSA c 32х-битным ключом. Серверный и клиентский скрипт практически идентичны, за исключением того, что генерация ключей осуществляется только серверной частью (при желании ее тоже можно портировать в js, но необходимости в этом я не увидел). Алгоритм использует пре- и пост-обработку шифруемой/дешифруемой информации в base64. Это сделано для исключения проблем с кириллицей, но приводит к увеличению объема закодированной информации примерно в полтора раза. Кроме того клиентская часть использует таблицы преобразования кодов символов (ASCII-коды с 128 по 255) всё для той же кириллицы. Дело в том, что в javascript используется чистый Unicode, который в php к сожалению, пока не поддерживается. Перейдём, собственно к разбору кода:
<?php
class RSA {
private $primes, $maxprimes;
function __construct() {
$this->primes = array(
4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591,
4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673,
4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787,
4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889,
4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969,
4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051,
5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153,
5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261,
5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381,
5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443,
5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527,
5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647,
5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717,
5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821,
5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881,
5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, 6029,
6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113,
6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211,
6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299,
6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367,
6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481,
6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581,
6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691,
6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791,
6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871,
6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971,
6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057,
7069, 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187,
7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283,
7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411,
7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507,
7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577,
7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673,
7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757,
7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877,
7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, 7951, 7963,
7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089,
8093, 8101, 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191,
8209, 8219, 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287,
8291, 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387,
8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, 8513,
8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609,
8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681, 8689, 8693,
8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747, 8753, 8761, 8779,
8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863,
8867, 8887, 8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971,
8999, 9001, 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067,
9091, 9103, 9109, 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181,
9187, 9199, 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281,
9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377,
9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461,
9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533
);
$this->maxprimes = count($this->primes) - 1;
}
function generate_keys() {
while(empty($e) || empty($d)) {
$p = $this->primes[mt_rand(0, $this->maxprimes)];
while(empty($q) || ($p==$q)) $q = $this->primes[mt_rand(0, $this->maxprimes)];
$n = $p*$q;
$pi = ($p - 1) * ($q - 1);
$e = $this->coprime($pi);
$d = $this->extend($e, $pi);
$keys = array($n, $e, $d);
}
return $keys;
}
function encrypt($m, $e, $n) {
$m = base64_encode($m); $asci = array();
for($i=0; $i<strlen($m); $i+=3) {
$tmpasci = '1';
for($h=0; $h<3; $h++) {
if($i+$h < strlen($m)) {
$tmpstr = ord (substr ($m, $i+$h, 1)) - 30;
if(strlen($tmpstr) < 2) $tmpstr = "0$tmpstr";
} else break;
$tmpasci .=$tmpstr;
}
array_push($asci, $tmpasci.'1');
}
for($k=0; $k<count($asci); $k++) {
$resultmod = $this->powmod($asci[$k], $e, $n);
$coded .= str_pad(dechex($resultmod), 7, '0', STR_PAD_LEFT);
}
$coded = trim($coded);
return $this->hexstr($coded);
}
function decrypt($c, $d, $n) {
$c = $this->strhex($c);
$decryptarray = explode('!', chunk_split($c, 7, '!'));
for($u=0; $u<count($decryptarray); $u++)
if($decryptarray[$u]=="") array_splice($decryptarray, $u, 1);
for($u=0; $u<count($decryptarray); $u++) {
$resultmod = $this->powmod(hexdec($decryptarray[$u]), $d, $n);
$deencrypt.= substr($resultmod, 1, strlen($resultmod) - 2);
}
for($u=0; $u<strlen($deencrypt); $u+=2)
$resultd .= chr(substr($deencrypt, $u, 2) + 30);
return base64_decode($resultd);
}
private function mod($g, $l) {
return $g - ($l * floor ($g/$l));
}
private function extend($Ee, $Epi) {
$u1 = 1; $u2 = 0; $u3 = $Epi; $v1 = 0; $v2 = 1; $v3 = $Ee;
while($v3 != 0) {
$qq = floor($u3 / $v3);
$t1 = $u1 - $qq * $v1; $t2 = $u2 - $qq * $v2; $t3 = $u3 - $qq * $v3;
$u1 = $v1; $u2 = $v2; $u3 = $v3; $v1 = $t1; $v2 = $t2; $v3 = $t3; $z = 1;
}
$uu = $u1; $vv = $u2;
if($vv < 0) $inverse = $vv + $Epi;
else $inverse = $vv;
return $inverse;
}
private function gcd($e, $pi) {
$y = $e; $x = $pi;
while($y != 0) {
$w = $this->mod($x, $y);
$x = $y; $y = $w;
}
return $x;
}
private function coprime($pi) {
$great = 0; $cc = mt_rand(0, $this->maxprimes); $startcc = $cc;
while($cc >= 0) {
$se = $this->primes[$cc];
$great = $this->gcd($se, $pi);
$cc--; if($great==1) break;
}
if($great==0) {
$cc = $startcc + 1;
while ($cc <= $this->maxprimes) {
$se = $this->primes[$cc]; $great = $this->gcd($se, $pi); $cc++;
if ($great == 1) break;
}
}
return $se;
}
private function powmod($base, $exp, $modulus) {
$accum = 1; $i = 0; $basepow2 = $base;
while(($exp >> $i) > 0) {
if ((($exp >> $i) & 1) == 1) $accum = $this->mod(($accum * $basepow2), $modulus);
$basepow2 = $this->mod(($basepow2 * $basepow2), $modulus); $i++;
}
return $accum;
}
private function hexstr($str) {
$result = '';
for($i=0; $i<strlen($str); $i+=2) {
$byte = hexdec($str{$i}.$str{$i+1});
$result .= chr($byte);
}
return $result;
}
private function strhex($str) {
$result = '';
for($i=0; $i<strlen($str); $i++) {
$byte = ord($str{$i});
$result .= str_pad(dechex($byte), 2, '0', STR_PAD_LEFT);
}
return $result;
}
}?>
Пояснения:
- Массив $primes содержит последовательность простых чисел, необходимых для генерации ключей. При желании её можно дополнить (только в большую строну).
- Методы generate_keys, encrypt и decrypt — единственные методы объекта, которые непосредственно требуются для работы. Использование их будет подробно рассмотрено ниже.
- Метод mod необходим для вычисления остатка от деления независимо от платформы, на которой запускается скрипт.
- Метод extend предназначен для получения подходящего закрытого ключа на основе открытого показателя e и результата функции Эйлера для выбраных простых чисел.
- Метод gcd используется для вычисления НОД.
- Метод coprime вычисляет открытый показатель e, взаимно простой фунции Эйлера.
- Методы hexstr и strhex используются только для промежуточной обработки данных в удобный формат (соответственно, в строку, либо 16-ричное число).
- Ну и наконец, метод powmod выполняет операцию возведения в степень по модулю сдвигом регистра (используется собственно при обработке блоков сообщения).
<?php
$rsa = new RSA;
list($public, $e, $private) = $rsa->generate_keys();
?>
Вот мы и получили ключи для зашифровки/расшифровки сообщений. Думаю, из названий переменных понятно, что где лежит ($e — это открытый показатель, часть публичного ключа).
Теперь попробуем что-нибудь зашифровать:
<?php
$encoded = $rsa->encrypt('Здесь был Вася', $e, $public);
// в переменной $encoded теперь лежит строка вроде "#K1МHzв_ў(®P+д8љ&Ѕ •6"
?>
и расшифровать обратно:
<?php
echo $rsa->decrypt($encoded, $private, $public);
// Выведет "Здесь был Вася"
?>
Ура! Оно работает!
Но мы немного отклонились от темы. Посмотрим, как это будет выглядеть в javascript, например при шифровании пароля, отправляемого на сервер.
Для начала посмотрим объекты, реализующие нужный функционал:
var RSA = {
encrypt: function(m, e, n) {
m = BASE64.encode(m); var asci = [], coded = ''
for(var i = 0; i < m.length; i+=3) {
var tmpasci = '1'
for(var h = 0; h < 3; h++) {
if(i+h < m.length) {
tmpstr = this.ord(m.charAt(i+h)) - 30
if(tmpstr.length < 2) tmpstr = '0' + tmpstr
} else break
tmpasci += tmpstr
}
asci.push(tmpasci+'1')
}
for(var k = 0; k < asci.length; k++) {
var resultmod = this.powmod(asci[k], e, n)
var chunk = resultmod.toString(16)
while(chunk.length<7) chunk = '0'+chunk;
coded += chunk
}
coded = coded.replace(new RegExp('^ +| +$', 'g'), '')
return this.hexstr(coded)
},
decrypt: function(c, d, n) {
c = this.strhex(c)
var decryptarray = [], deencrypt = '', resultd = ''
for(var i=0; i<c.length; i+=7) decryptarray.push(c.substr(i, 7))
for(var u = 0; u < decryptarray.length; u++)
if(decryptarray[u]=='') decryptarray.splice(u, 1)
for(var u = 0; u < decryptarray.length; u++) {
var resultmod = this.powmod(parseInt(decryptarray[u], 16), d, n) + ''
deencrypt += resultmod.substr(1, resultmod.length - 2)
}
for(var u = 0; u < deencrypt.length; u+=2)
resultd += this.chr(parseInt(deencrypt.substr(u, 2), 10) + 30)
return BASE64.decode(resultd)
},
ord: function(chr) {
return ASCII.ord(chr)
},
chr: function(num) {
return ASCII.chr(num)
},
mod: function(g, l) {
return g - (l * Math.floor(g / l))
},
powmod: function(base, exp, modulus) {
var accum = 1, i = 0, basepow2 = base
while((exp >> i) > 0) {
if (((exp >> i) & 1) == 1) accum = this.mod((accum * basepow2), modulus)
basepow2 = this.mod((basepow2 * basepow2), modulus); i++
}
return accum
},
hexstr: function(str) {
var result = ''
for(var i=0,len=str.length; i<len; i+=2) {
var bte = parseInt(''+str.charAt(i)+str.charAt(i+1), 16).toString(10);
result += ASCII.chr(bte)
}
return result
},
strhex: function(str) {
var result = ''
for(var i=0,len=str.length; i<len; i++) {
var bte = ASCII.ord(str.charAt(i)).toString(16)
result += bte.length==2 ? bte : '0'+bte
}
return result
}
}
var ASCII = {
translations: {
js2php: {1026:128, 1027:129, 8218:130, 1107:131, 8222:132,
8230:133, 8224:134, 8225:135, 8364:136, 8240:137,
1033:138, 8249:139, 1034:140, 1036:141, 1035:142,
1039:143, 1106:144, 8216:145, 8217:146, 8220:147,
8221:148, 8226:149, 8211:150, 8212:151, 65533:152,
8482:153, 1113:154, 8250:155, 1114:156, 1116:157,
1115:158, 1119:159, 1038:161, 1118:162, 1032:163,
1168:165, 1025:168, 1028:170, 1031:175, 1030:178,
1110:179, 1169:180, 1105:184, 8470:185, 1108:186,
1112:188, 1029:189, 1109:190, 1111:191, 1040:192,
1041:193, 1042:194, 1043:195, 1044:196, 1045:197,
1046:198, 1047:199, 1048:200, 1049:201, 1050:202,
1051:203, 1052:204, 1053:205, 1054:206, 1055:207,
1056:208, 1057:209, 1058:210, 1059:211, 1060:212,
1061:213, 1062:214, 1063:215, 1064:216, 1065:217,
1066:218, 1067:219, 1068:220, 1069:221, 1070:222,
1071:223, 1072:224, 1073:225, 1074:226, 1075:227,
1076:228, 1077:229, 1078:230, 1079:231, 1080:232,
1081:233, 1082:234, 1083:235, 1084:236, 1085:237,
1086:238, 1087:239, 1088:240, 1089:241, 1090:242,
1091:243, 1092:244, 1093:245, 1094:246, 1095:247,
1096:248, 1097:249, 1098:250, 1099:251, 1100:252,
1101:253, 1102:254, 1103:255},
php2js: {128:1026, 129:1027, 130:8218, 131:1107, 132:8222,
133:8230, 134:8224, 135:8225, 136:8364, 137:8240,
138:1033, 139:8249, 140:1034, 141:1036, 142:1035,
143:1039, 144:1106, 145:8216, 146:8217, 147:8220,
148:8221, 149:8226, 150:8211, 151:8212, 152:65533,
153:8482, 154:1113, 155:8250, 156:1114, 157:1116,
158:1115, 159:1119, 161:1038, 162:1118, 163:1032,
165:1168, 168:1025, 170:1028, 175:1031, 178:1030,
179:1110, 180:1169, 184:1105, 185:8470, 186:1108,
188:1112, 189:1029, 190:1109, 191:1111, 192:1040,
193:1041, 194:1042, 195:1043, 196:1044, 197:1045,
198:1046, 199:1047, 200:1048, 201:1049, 202:1050,
203:1051, 204:1052, 205:1053, 206:1054, 207:1055,
208:1056, 209:1057, 210:1058, 211:1059, 212:1060,
213:1061, 214:1062, 215:1063, 216:1064, 217:1065,
218:1066, 219:1067, 220:1068, 221:1069, 222:1070,
223:1071, 224:1072, 225:1073, 226:1074, 227:1075,
228:1076, 229:1077, 230:1078, 231:1079, 232:1080,
233:1081, 234:1082, 235:1083, 236:1084, 237:1085,
238:1086, 239:1087, 240:1088, 241:1089, 242:1090,
243:1091, 244:1092, 245:1093, 246:1094, 247:1095,
248:1096, 249:1097, 250:1098, 251:1099, 252:1100,
253:1101, 254:1102, 255:1103}
},
ord: function(chr, dir) {
dir = dir || 'js2php'
if(!this.translations[dir]) return null
chr = chr.charCodeAt(0)
return (chr in this.translations[dir]) ? this.translations[dir][chr] : chr
},
chr: function(ord, dir) {
dir = dir || 'php2js'
if(!this.translations[dir]) return null
ord = (ord in this.translations[dir]) ? this.translations[dir][ord] : ord
return String.fromCharCode(ord)
}
}
var BASE64 = {
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
encode: function(input) {
var output = '', chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0
while(i < input.length) {
chr1 = ASCII.ord(input.charAt(i++))
chr2 = ASCII.ord(input.charAt(i++))
chr3 = ASCII.ord(input.charAt(i++))
enc1 = chr1 >> 2
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4)
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6)
enc4 = chr3 & 63
if(isNaN(chr2)) enc3 = enc4 = 64
else if(isNaN(chr3)) enc4 = 64
output = output +
this.alphabet.charAt(enc1) + this.alphabet.charAt(enc2) +
this.alphabet.charAt(enc3) + this.alphabet.charAt(enc4)
}
return output
},
decode: function(input) {
var output = '', chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0
input = input.replace(new RegExp('[^A-Za-z0-9+/=]', 'g'), '')
while(i < input.length) {
enc1 = this.alphabet.indexOf(input.charAt(i++))
enc2 = this.alphabet.indexOf(input.charAt(i++))
enc3 = this.alphabet.indexOf(input.charAt(i++))
enc4 = this.alphabet.indexOf(input.charAt(i++))
chr1 = (enc1 << 2) | (enc2 >> 4)
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2)
chr3 = ((enc3 & 3) << 6) | enc4
output = output + ASCII.chr(chr1)
if (enc3 != 64) output = output + ASCII.chr(chr2)
if (enc4 != 64) output = output + ASCII.chr(chr3)
}
return output
}
}
Очевидно, что реализация кодирования/декодирования (как и служебные функции) практически идентичны классу в php. Присутствуют лишь незначительные изменения, связанные со специфическими функциями.
Объект ASCII представляет собой ту самую таблицу преобразований с методами ord и chr, аналогичными по результату соответствующим функциям php.
Объект BASE64 является реализацией уже упомянутого алгоритма применительно к данному скрипту. Я НЕ рекоммендую использовать другие реализации из-за плохой поддержки ими кириллицы.
А теперь попробуем объединить всё это во что-то более осмысленное - Клиент запрашивает страницу, которая требует авторизации.
- Сервер отправляет клиенту форму ввода логина и пароля, и сгенерированный открытый ключ. Закрытый ключ при этом сохраняется где-нибудь в сессии.
- Клиент шифрует введённый пользователем пароль открытым ключом и отправляет форму на сервер.
- Сервер дешифрует пароль при помощи закрытого ключа и проверяет подлинность пользователя какими-то своими средствами.
<?php
session_start();
require_once('rsa.php');
$url = "http://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
$rsa = new RSA();
if(isset($_POST['user'])) {
$_SESSION['logged_user'] = $_POST['user'];
$_SESSION['pass_cipher'] = $_POST['pass'];
$_SESSION['real_pass'] = $rsa->decrypt($_POST['pass'],
$_SESSION['keys']['private'],
$_SESSION['keys']['public']);
header("Location: $url");
exit;
}
if(isset($_GET['quit'])) {
$_SESSION['logged_user'] = '';
$_SESSION['keys'] = array();
$url = substr($url, 0, -5);
header("Location: $url");
exit;
}
if(empty($_SESSION['logged_user'])) {
list($public, $e, $private) = $rsa->generate_keys();
$_SESSION['keys'] = array(
'public' => $public,
'private' => $private,
'e' => $e,
);
}
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head profile="http://gmpg.org/xfn/11">
<meta http-equiv="Content-Type" content="application/xhtml+xml;charset=windows-1251" />
<title>RSA example</title>
<script type="text/javascript" src="rsa.js"></script>
</head>
<body>
<script type="text/javascript">
//<![CDATA[
function encode_pass(e, pub) {
var dp = document.getElementById('dummy_password');
var rp = document.getElementById('real_password');
rp.value = RSA.encrypt(dp.value, e, pub);
alert('Password encoded: '+rp.value);
/* Не забываем очищать поле с введённым паролем,
а иначе все наши старания напрасны */
dp.value = '';
}
//]]>
</script>
<? if(empty($_SESSION['logged_user'])) { ?>
<form action="" method="post" onsubmit="encode_pass(<?=$e?>, <?=$public?>)">
Имя: <input type="text" name="user" value="" /><br />
Пароль: <input type="password" name="dummy" id="dummy_password" value="" /><br />
<input type="hidden" name="pass" id="real_password" value="" />
<input type="submit" value="Войти" />
</form>
<? } else { ?>
Вы вошли как: <?=$_SESSION['logged_user']?> [<a href="<?=$url?>?quit">выход</a>]<br />
Зашифрованный пароль: <?=$_SESSION['pass_cipher']?><br />
Введённый пароль: <?=$_SESSION['real_pass']?><br />
Открытый ключ: <?=$_SESSION['keys']['e']?> / <?=$_SESSION['keys']['public']?><br />
Закрытый ключ: <?=$_SESSION['keys']['private']?>
<? } ?>
</body>
</html>
Метки: javascript, php, rsa
Grin пишет:
Интересно) Пиши исчо!
Single пишет:
СПАСИБО!!! С меня прямая ссылка на Ваш блог!
Dmc пишет:
Спасибо!
А намного ли сложнее реализовать RSA с 2048-битным ключём? 32 бита на сегодняшний день - смешно(
Азарёнок Иван пишет:
Dmc: реализация с 2048-битным ключом будет отличаться лишь массивом $primes
длина генерируемого ключа будет лежать в интервале между произведением меньших значений этого массива и, соответственно, больших (т.е. длина результата в двоичном виде). Чтобы продолжить последовательность этих чисел можно воспользоваться вот этим (там есть формула).
Но не забывайте, что чем длиннее ключ, тем больше ресурсов требуется для работы алгоритма, а JavaScript всё-таки довольно медленный язык, поэтому желательно экспериментально найти оптимальную длину ключа, при которой браузеры не будут очень сильно тормозить (я бы сам поэкспериментировал, да пока времени нет).
Dmc пишет:
Я нашёл на буржуйских ресурсах неплохие реализации алгоритма blowfish на js и php (без mcrypt), синхронизировал их, только увы base64 приходится применять и на входе и на выходе для корректного распознавания кириллицы, это увеличивает трафик в 3.21 раза, но я за его объём пока не очень волнуюсь.
Использую подобную криптографию в качестве замены SSL, шифрую все более-менее важные входящие и исходящие данные.
Кстати, предложенная Вами реализация base64 некорректно работает с юникодом, вот тут лежит 100%но рабочая версия:
http://www.webtoolkit.info/javascript-base64.html
(просьба удалить предыдущее сообщение, случайно сабмит прошёл)
Азарёнок Иван пишет:
Dmc: спасибо, проверим.
mrsheff пишет:
Что то сорцы с блога некорректно работают, а пример(blog.mesos.ru/examples/rsa_js_example.php) выложенный в блог работает нормально, нельзя ли скрипты выложить в архиве?
Азарёнок Иван пишет:
mrsheff, пожалуйста: архив. А с кодом как-нибудь разберусь, это видимо wordpress что-то порезал.