Javascript-форум (https://javascript.ru/forum/)
-   Оффтопик (https://javascript.ru/forum/offtopic/)
-   -   Представление текста как массив байтов (https://javascript.ru/forum/offtopic/12888-predstavlenie-teksta-kak-massiv-bajjtov.html)

poorking 07.11.2010 14:47

Представление текста как массив байтов
 
Здравствуйте, уважаемые программисты.
Сейчас я взялся за реализацию алгоритма шифрования AES на javascript. Для тех кто не в курсе, супер-кратко опишу. AES - блочный симметричный шифр, единовременно шифрующий блоки информации по 128 бит ключом 128/192/256 бит. В самом шифре производятся различные операции с байтами, то бишь перестановка, нелинейная замена и т.п. Но это уже не суть.

На страничке есть 3 textarea, в одну я ввожу текст, 2 другие - readonly, когда нажимаю кнопку "Зашифровать", берется значение первого поля, шифруется, выводится вся эта абра-кадабра во второе поле. Когда нажимаем "Расшифровать", берется значение второго поля, расшифровывается и выводится в третье поле.

Но проблема моя заключается в следующем. Так как алгоритм оперирует с байтами, то входной текст надо представить как последовательность байтов, и это было бы не проблемой если бы все символы юникода весили одинаковое количество байт, но дело в том, что латиница, например имеет чаркоды до 1 байта, а кириллица уже по 2 байта, есть символы, которые весят и то более. Например имеем строку: "3ЖF". Если представлю этот текст в виде последовательности юникодных десятичных чаркодов то получится [51, 1046, 70]. В двоичном виде: [110011,10000010110,1000110] . Мы видим что символ "Ж" занимает 2 байта. "Ж"= 1046 = [4,26] .

Кстати, вот игрушка, сделал чтобы не мучить калькулятор. А в стандартной таблице символов в юникодных шрифтах можно найти 3-4 байтные символы.

<html>
<head><title></title></head>
<body>
<span>Enter the symbol (string): </span><input type='text' id="char" maxlength="1" size="1"/> <b id="info"></b>
<p id='chcode'></p>
<p id='dec'></p>
<p id='bin'></p>
<p id='tostr2'></p>
</body>

<script lang='javascript'>

document.getElementById("char").onkeyup=function(){

	var dbtz=[], bbtz=[];
		chCode = this.value.charCodeAt(0),
		q=Math.ceil(Math.log(chCode)/Math.log(255)),
		temp=chCode;

	for(var i=0; i<q;i++){
		
		var p = Math.floor(temp/Math.pow(255,q-i-1));
		
		temp = temp-p*Math.pow(255,q-i-1);
		
		dbtz[i] =p;
		bbtz[i] =p.toString(2);
	} 
	info.innerHTML = "= "+q+" bytes.";
	chcode.innerHTML ="Char code: " + chCode;
	dec.innerHTML = "In decimal: ["+dbtz+"].";
	bin.innerHTML = "In binary: ["+bbtz+"]."
	tostr2.innerHTML = "('"+this.value+"').charCodeAt(0).toString(2) = "+chCode.toString(2);
}


</script>
</html>

И как поступать в таком случае? Если я представлю эту строку в виде последовательности байтов [51,4,26,70], то раскодировать эту последовательность обратно в "3ЖF" будет, надеюсь я ошибаюсь, невозможно, из-за того что мы не знаем сколько брать байтов для раскодирования одного символа.

Как сначала делал я. Принял допущение, что больше 2х байт символов не будет. На самом деле, символы больше 2х байт очень редкие. Затем чаркод каждого символа переводил в двоичный вид с помощью .toString(2), и добивал вначале каждой строки недостающие нули до16 бит. Таким образом, в итоге у меня получалась строка, в которой я твердо знал, что каждый ее отрезок длиной в 16 - это двоичный чаркод одного символа. Но этот вариант меня не устроил, потому что мне кажется что это как-то не по-уму. Зачем хранить двоичный код в виде строки, тем более в данном контексте это не выгодно, так как сам алгоритм шифрования будет работать в разы медленнее, потому что "байтами" в 128-битном блоке будут строки по 8 символов "0" или "1", которые в свою очередь и так весят по 1-му байту. Вот собственно и суть проблемы. Как представить текст в виде массива байтов, чтобы потом его можно было раскодировать. Простите за много букв, просто накипело и не удержался, решил выплакаться. Пишу сюда, потому что вопрос не по Яваскрипту, а общего плана. Подскажите, пожалуйста, как это делать правильно.

Gvozd 07.11.2010 15:01

http://ru.wikipedia.org/wiki/Юни...BD.D0.B8.D1.8F

SV0L0CH 07.11.2010 15:04

Тут нормально будет использовать String.prototype.charCodeAt и рассматривать результат как 4 байта. Вся побитовая арифметика завязана именно на 4 байта. Непосредственная работа с utf-8 тут не оправдана как и использование для реализации 16-байтовой арифметики через операции над отдельными байтами(когда можно использовать сразу 4 байта).

poorking 07.11.2010 15:23

Gvozd,
Цитата:

...поскольку в Юникоде нет символов с кодом больше 10FFFF, и вводить их в будущем не планируется)....
Скажите мне придется каждый символ представлять как последовательность 3х байт тогда? даже если символ на 1 байт, в начале добавлять вначале "пустые" байты равные 0? Например символ "1" будет равен [0,0,49].

SV0L0CH,
На вики написано что в Юникоде нет символов с кодом больше 1114111=3байта, все равно брать по 4 байта лучше?

tenshi 07.11.2010 15:45

encodeURIComponent('текст').split('%').map(fu nction( val ){return Number( '0x'+val ) })

tenshi 07.11.2010 15:47

пиздец, илья, ты опустился в моих глазах совсем ниже плинтуса =_=

poorking 07.11.2010 16:22

tenshi,
encodeURIComponent() ведь кодирует все символы кроме латиницы. А у меня текст может быть абсолютно из любого набора символов.

Буду делать как предложил SV0L0CH, наверно. Не нравится мне что 128/192/256 ключи тогда будут 4/6/8 символов всего.. как то это не так..

poorking 07.11.2010 16:58

function str2bytes(str){
	var arr=[], bytesPerSymbol=4;
		
	for (var i=0;i<str.length;i++){			
			var chCode = str.charCodeAt(i);			
			var temp=chCode;
	
		for(var j=0; j<bytesPerSymbol;j++){			
				var oneByte = Math.floor(temp/Math.pow(255,bytesPerSymbol-j-1));
				
				arr.push(oneByte);
				
				temp = temp-oneByte*Math.pow(255,bytesPerSymbol-j-1);			
		} 
	
	}
	return arr;
}

function bytes2str(arr){
	var bytesPerSymbol=4, str="";
	
	for (var i=0; i<arr.length; i+=bytesPerSymbol){
		var chCode=0;
		for (var j=0;j<bytesPerSymbol;j++){	
			chCode+=arr.slice(i,i+bytesPerSymbol)[j]*Math.pow(255,bytesPerSymbol-j-1);
		
		}
		str+=String.fromCharCode(chCode);
	}
	return str;
}

document.write(str2bytes("Привет!"));

document.write("<br />"+ bytes2str(str2bytes("Привет!")));


Что-то типа того. Такой массив я раскодировать смогу, потому что знаю, что каждые bytesPerSymbol его элементов = 1 символ

SV0L0CH 07.11.2010 18:13

Цитата:

Сообщение от poorking
Юникоде нет символов с кодом больше 1114111=3байта, все равно брать по 4 байта лучше?

Это на много лучше, один байт можно перед шифрованием заменять рандомным значением, а после расшифровки подставлять обратно 0, но это уже дело вкуса. Место можно экономить, а можно и не экономить.

poorking 07.11.2010 19:07

SV0L0CH,
Ну я согласен что шифрование будет сильнее:) но я ничего заменять не буду, в самом AES и так достаточно замен и перестановок. Спасибо:thanks:


Часовой пояс GMT +3, время: 01:25.