новости
статьи
.программирование

интеграция шифрования в Календарь Google при помощи расширений Firefox

Сегодня веб-приложения предоставляют множество возможностей для обмена файлами, совместного доступа и работы. Хотя некоторые из этих приложений поддерживают шифрование пользовательской информации, таких программ – меньшинство. В этой статье обсуждаются средства и программный код, необходимые для поддержки базового шифрования в одном из наиболее популярных онлайновых органайзеров. В статье рассказано, как благодаря удивительной гибкости расширений Firefox и Gnu Privacy Guard можно хранить события Календаря Google зашифрованными, отображая их в виде простого текста только обладателям соответствующих ключей шифрования.

Мы воспользуемся великолепным расширением Элиаса Торреса (Elias Torres) "Google Calendar Quick Add", рассмотрим выбор, изменение и вставку различных компонентов для реализации шифрования событий, без использования безопасного канала данных TLS. На рисунке 1 показан пример того, как будет выглядеть приложение для оператора сервера (слева) и для Интернет-пользователя (справа) после выполнения всех инструкций в данной статье.



Рис. 1. Зашифрованный Календарь Google.

оборудование

Любое оборудование, поддерживающее веб-технологии, появившиеся после 2002 года, будет способно работать с кодом, приведенным в данной статье. Алгоритмы шифрования активно используют процессор, поэтому, если на каждой странице вам необходимо дешифровать несколько десятков или сотен событий календаря, для комфортной работы вам понадобится быстрый процессор.

программное обеспечение

Требуется браузер Firefox 1.5 или выше, а также программа GnuPG - Gnu Privacy Guard. Также пригодятся инструменты разработки расширений Firefox.

Хотя эта статья создавалась с использованием ОС Ubuntu 7.10, все основные идеи легко переносятся на множество других операционных систем. Перед началом работы убедитесь в том, что ваша ОС поддерживает Perl, GnuPG и Firefox.

общий подход

В этой статье подразумевается, что вы знакомы с основами разработки расширений Firefox. Не требуется никаких специальных компиляторов или сред разработки, однако вы должны быть знакомы с процессом созданием программного обеспечения, чтобы иметь возможность диагностировать неполадки и решать проблемы с настройкой при установке программ.

Для работы рекомендуется создать новый профиль Firefox. Все функции шифрования данного расширения будет обеспечивать GnuPG. Это избавляет от неэффективного использования JavaScript, одновременно обеспечивая надежное кроссплатформенное управление ключами. Вам понадобится полная установка GnuPG с возможностью выбора удобных для вас ключей шифрования. Также понадобится программа gpg-agent (обычно входит в пакет GnuPG) для обслуживания временного хранилища и удаления истекших паролей.

Имея в наличии рабочую среду разработки создания расширений и GnuPG для выполнения шифрования, мы модифицируем интерфейс, взяв за основу существующее расширение. Расширение Google Quick Add Элиаса Торреса представляет собой хорошую отправную точку для реализации поддержки шифрования. На этапе шифрования вводимый текст сохраняется на диске и шифруется при помощи внешней программы, после чего зашифрованный файл считывается и загружается на серверы Google. При дешифровании каждое событие записывается на диск, расшифровывается и выводится пользователю в виде дешифрованного текста. Альтернативой могло бы быть написание новых протоколов для Firefox. Хотя такой подход может обеспечить более надежный канал данных, для этого вида расширений более простым является организация взаимодействия программ в форме вывода, обработки и чтения. Прежде чем переходить к коду, приведенному в данной статье, убедитесь в том, что вы располагаете работоспособными программами Firefox, GnuPG и gpg-agent.


кроссплатформенная совместимость

При работе над статьей использовался дистрибутив Linux Ubuntu 7.10. Если вы точно следуете данной статье, вам потребуется современный дистрибутив Linux. В то же время для всех программ, рассматриваемых в статье (Firefox, GnuPG и Perl), есть версии для ОС Microsoft Windows. С незначительными изменениями, касающимися путей к файлам и внешним программам, код, приведенный здесь, должен работать и в других
системах.

доработка расширения Google Calendar Quick

Расширение Google Calendar Quick Add позволяет добавлять события в ваш календарь с любой страницы, используя API-интерфейс SOAP. Для записи в календарь шифрованных событий мы перехватываем передаваемую информацию и шифруем ее. Можно было бы просто вводить в Календарь Google шифрованные записи в формате ASCII, но предлагаемый подход позволяет автоматизировать этот процесс.

Для начала при помощи команды mkdir ~/calendarEncrypt создадим каталог для хранения программного кода и каталогов расширения. Перейдем в этот каталог и загрузим расширение Quick Google Calendar Quick Add в формате xpi.

Распакуйте расширение при помощи команды unzip quickgooglecal.xpi. Перейдите в созданный каталог chrome и выполните команду unzip
quickgooglecal.jar. У вас должно получиться следующее дерево каталогов:

calendarEncrypt/chrome.manifest
calendarEncrypt/readme.txt
calendarEncrypt/chrome
calendarEncrypt/chrome/content
calendarEncrypt/chrome/content/hello.xul
calendarEncrypt/chrome/content/overlay.xul
calendarEncrypt/chrome/content/overlay.js
calendarEncrypt/chrome/skin
calendarEncrypt/chrome/skin/overlay.css
calendarEncrypt/chrome/quickgooglecal.jar
calendarEncrypt/chrome/locale
calendarEncrypt/chrome/locale/en-US
calendarEncrypt/chrome/locale/en-US/hello.dtd
calendarEncrypt/chrome/locale/en-US/overlay.dtd
calendarEncrypt/install.rdf
calendarEncrypt/quickgooglecal.xpi


Перейдите в каталог ~/calendarEncrypt и отредактируйте файл install.rdf. Измените значения идентификатора и автора:
Измените идентификатор:

<em:id>{E31AE5B1-3E5B-4927-9B48-76C0A701F105}</em:id>

на:

<em:id>calendarEncrypt@devWorks_IBM.com</em:id>

Также измените имя автора:

<em:creator>Elias Torres</em:creator>

на:

<em:creator>Elias Torres с изменениями devWorks</em:creator>

Отредактируйте файл chrome.manifest, чтобы изменить пакет расширения на основе jar на более удобную для разработчика структуру каталогов. Редактирование файла chrome.manifest для изменения формата из jar в структуру каталогов:

Исходный chrome.manifest:

content quickgooglecal jar:chrome/quickgooglecal.jar!/content/
overlay chrome://browser/content/browser.xul chrome://quickgooglecal/content/overlay.xul

locale quickgooglecal en-US jar:chrome/quickgooglecal.jar!/locale/en-US/

skin quickgooglecal classic/1.0 jar:chrome/quickgooglecal.jar!/skin/
style chrome://global/content/customizeToolbar.xul
chrome://quickgooglecal/skin/overlay.css


Измененный chrome.manifest:

content quickgooglecal chrome/content/

overlay chrome://browser/content/browser.xul chrome://quickgooglecal/content/overlay.xul

locale quickgooglecal en-US chrome/locale/en-US/

skin quickgooglecal classic/1.0 chrome/skin/
style chrome://global/content/customizeToolbar.xul
chrome://quickgooglecal/skin/overlay.css


Теперь добавим ссылку на каталог расширения в ваш тестовый профиль Firefox. Например, если ваш профиль расположен в
~/.mozilla/firefox/b2w2sglj.development, создайте ссылку на ~/.mozilla/firefox/b2w2sglj.development/extensions/ под названием
calendarEncrypt@devWorks_IBM.com. Добавьте путь к каталогу с Google Quick Add в файл calendarEncrypt@devWorks_IBM.com; в нашем случае это /home/username/calendarEncrypt.

Войдите в Календарь Google и нажмите ctrl+, чтобы активировать расширение Google Calendar Quick Add. Убедитесь в том, что события добавляются как положено, введя событие Test unencrypted event tomorrow 15:30. Убедитесь, что событие было добавлено правильно.

Теперь мы можем вносить изменения в расширение Google Calendar Quick Add для поддержки шифрования и дешифрования событий.

отправка шифрованных событий

Для автоматизации добавления шифрованных событий в календарь в этой статье используется перехват и шифрование данных расширения Quick Add. Изменение готового расширения для поддержки перехвата показано ниже начиная с листинга 4. Отредактируйте файл chrome/content/hello.xul и удалите строку 69 var quickAddText = number_html(document.getElementById("quickText").value);. Вставьте в строку 69 следующий код.

var words = document.getElementById("quickText").value.split(' ');
var dayVal = words[words.length-2];
var timeVal = words[words.length-1];
var elementData = "";

for( var n=0; n < words.length-2; n++ ){
elementData = elementData + " " + words[n];
}


Код, приведенный выше, предполагает, что дата и время всегда являются двумя последними словами в тексте заголовка события. Чтобы убедиться в корректном добавлении в календарь, все последующие заголовки событий должны иметь формат «текст сообщения дата время», где дата - это «пятница/понедельник/завтра» и т.п., а время - «05:30/10:30» и т.п.

После того, как мы отделили текст описания события от даты и времени, нужно записать текст события на диск и зашифровать его. Добавьте в строку 77 код, приведенный ниже:

// Записываем текст события на диск
var fileOut = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
fileOut.initWithPath("/tmp/calendarEvent");
var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
foStream.init(fileOut, 0x02 | 0x08 | 0x20, 0666, 0);
foStream.write(elementData, elementData.length);
foStream.close();

// Запускаем внешнюю программу шифрования
var fileExe = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
fileExe.initWithPath("/tmp/CalendarCrypt.pl");
var process = Components.classes["@mozilla.org/process/util;1"]
.createInstance(Components.interfaces.nsIProcess);
process.init(fileExe);
var args = ["encrypt"];
process.run(true, args, args.length);


Первая часть кода указывает использовать файл "/tmp/calendarEvent" для записи перехваченного текста событий на диск. Этот файл содержит данные в виде простого текста, но он будет удален и затерт после завершения шифрования. Первая часть кода указывает использовать файл для рекомендуемого компонента nsIProcess. За шифрование, дешифрование и безопасное удаление отвечает программа на языке Perl /tmp/CalendarCrypt.pl , которая будет описана ниже. Когда шифрование данных будет завершено, код, приведенный ниже в листинге 6, считывает зашифрованный текст события обратно. Добавьте следующий код в строку 98 файла chrome/content/hello.xul.

// Считываем обратно зашифрованный текст
var fileIn = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
fileIn.initWithPath("/tmp/calendarEvent.asc");
var istream = Components.classes["@mozilla.org/network/file-input-stream;1"]
.createInstance(Components.interfaces.nsIFileInputStream);
istream.init(fileIn, 0x01, 0444, 0);
istream.QueryInterface(Components.interfaces.nsILineInputStream);

var data = "";
var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]
.createInstance(Components.interfaces.nsIFileInputStream);
var sstream = Components.classes["@mozilla.org/scriptableinputstream;1"]
.createInstance(Components.\
interfaces.nsIScriptableInputStream);
// перед строками, разделенными \ для форматирования, не вставляйте разрыв строк

fstream.init(fileIn, -1, 0, 0);
sstream.init(fstream);

var str = sstream.read(4096);
while (str.length > 0) {
data += str;
str = sstream.read(4096);
}

sstream.close();
fstream.close();

quickAddText = data + " " + dayVal + " " + timeVal;


Код в предыдущем листинге выполняет запись текста события в файл и запуск процесса шифрования. Код в этом листинге выполняет чтение зашифрованного ASCII-текста из файла, добавление информации о дате и времени и возобновление работы расширения quick-add.
Теперь каждое событие, добавляемое при помощи Google Calendar Quick Add, будет перехватываться, шифроваться и размещаться на серверах Google в зашифрованном виде.

изменение файла overlay.js для чтения зашифрованных сообщений

После того как мы разобрались с кодом в chrome/content/hello.xul, отвечающим за шифрование, добавьте код для дешифрования событий в chrome/content/overlay.js. Вставьте эти строки в конец файла.

window.addEventListener("load", function() { calendarDecryptExtension.init(); }, false);

var calendarDecryptExtension = {
init: function() {
var appcontent = document.getElementById("appcontent"); // браузер
if(appcontent)
appcontent.addEventListener("DOMContentLoaded", this.onPageLoad, true);
var messagepane = document.getElementById("messagepane"); // почта
if(messagepane)
messagepane.addEventListener("load", function () \
{ calendarDecryptExtension.onPageLoad(); }, false);
// перед строками, разделенными \ для форматирования, не вставляйте разрыв строк
},


Каждый раз при загрузке страницы с событием выполняется вызов функции calendarDecryptExtension при помощи addEventListener. За функцией calendarDecryptionExtension следуют различные определения и перехваты, которые обеспечивают запуск кода при каждой загрузке страницы и передачу в функцию соответствующих данных. Добавьте код, приведенный ниже, вслед за строками из предыдущего листинга, для продолжения дешифрования документа.

onPageLoad: function(aEvent) {
dump("pre elemenet \n");

var elementData = "NODATA";
var allSpans = content.document.getElementsByTagName("span");

for (var n = 0; n < allSpans.length; n++){
if( allSpans[n].innerHTML.indexOf("BEGIN PGP") > -1 ){

// выходной файл для шифрования текста события
elementData = allSpans[n].innerHTML;
var fileOut = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
fileOut.initWithPath("/tmp/calendarEvent.temp");
var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance(Components. \
interfaces.nsIFileOutputStream);
// перед строками, разделенными \ для форматирования, не вставляйте разрыв строк
foStream.init(fileOut, 0x02 | 0x08 | 0x20, 0666, 0);
foStream.write(elementData, elementData.length);
foStream.close();


Все записи календаря заключены в HTML-элементы span. После задания временных переменных производится обработка всех элементов span в цикле for, и если их текст зашифрован, их содержимое выгружается. Ниже показан вызов программы CalendarCrypt.pl с параметром "decrypt" для дешифрования текста события.

// создаем исполняемый файл nsILocalFile
var fileExe = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
fileExe.initWithPath("/tmp/CalendarCrypt.pl");
var process = Components.classes["@mozilla.org/process/util;1"]
.createInstance(Components.interfaces.nsIProcess);
process.init(fileExe);
var args = ["decrypt"];
process.run(true, args, args.length);


Зашифрованный текст записывается на диск и запускается процесс дешифрования, который создает файл с расшифрованным текстом. Добавьте этот код для обратного считывания данных и изменения выводимой информации:

// входной файл для дешифрования текста события
var data = "";
var fileIn = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
fileIn.initWithPath("/tmp/calendarEvent.decrypted");
var istream = Components.classes["@mozilla.org/network/file-input-stream;1"]
.createInstance(Components.interfaces.nsIFileInputStream);
istream.init(fileIn, 0x01, 0444, 0);
istream.QueryInterface(Components.interfaces.nsILineInputStream);
var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]
.createInstance(Components.interfaces.nsIFileInputStream);
var sstream = Components.classes["@mozilla.org/scriptableinputstream;1"]
.createInstance(Components. \
interfaces.nsIScriptableInputStream);
// перед строками, разделенными \ для форматирования, не вставляйте разрыв строк
fstream.init(fileIn, -1, 0, 0);
sstream.init(fstream);

var str = sstream.read(4096);
while (str.length > 0) {
data += str;
str = sstream.read(4096);
}

sstream.close();
fstream.close();

allSpans[n].innerHTML = data;


Чтение из файла производится аналогично процессу шифрования. Обратите внимание на последнюю строку, которая подставляет в текущий элемент span расшифрованный текст вместо "BEGIN PGP..." исходного текста. Для завершения процесса дешифрования добавьте следующее.

// очищаем данные с диска
args = ["shred"];
process.run(true, args, args.length);

}//если содержимое span зашифровано

}//для каждого элемента span

}//при загрузке страницы
}//calendarDecryptExtension


Изменение параметра на "shred" и повторный запуск компонента nsiProcess гарантируют надежное удаление дешифрованного текста из временного хранилища на локальном диске. В следующем разделе рассматривается программа CalendarCrypt.pl, вызов которой был показан выше.

программа CalendarCrypt.pl

Завершает данный обзор программа CalendarCrypt.pl , показанная в следующем листинге. Обратите внимание на то, что приведенная реализация содержит несколько допущений относительно типичных ситуаций шифрования/дешифрования для обычного пользователя GnuPG. В случае необходимости поддерживается замена вызова внешней программы и настроек другими параметрами, включающимися при помощи GnuPG::Encrypt. Например, если вам необходимо использовать несколько ключей или ваша конфигурация несовместима с gpg-agent, модуль Perl GnuPG::Encrypt содержит множество параметров, позволяющих встроить программу в вашу рабочую среду. Начните с создания в каталоге /tmp скрипта Perl calendarEncrypt.pl с содержанием, приведенным ниже:

#!/usr/bin/perl -w
# calendarEncrypt.pl - шифрование/дешифрование/удаление файлов
use strict;

die "specify a mode " unless @ARGV == 1;
my $mode = $ARGV[0];

chomp(my $userName = `whoami`);

if( $mode eq "encrypt" )
{
my $res = `gpg --yes --armor --encrypt -r $userName /tmp/calendarEvent`;
$res = `shred /tmp/calendarEvent; rm /tmp/calendarEvent`;


После проверки параметров и задания имени пользователя по умолчанию выполняется шифрование файла /tmp/calendarEvent . Очистка и удаление исходного файла с незашифрованным текстом гарантирует, что на диске не останется конфиденциальных данных. Ниже показан режим дешифрования.

}elsif( $mode eq "decrypt" )
{

open(INFILE,"/tmp/calendarEvent.temp") or die "no in file";
open(OUTFILE,"> /tmp/calendarEvent.encrypted" ) or die "no file out";

while(my $line =<INFILE>)
{
my $begin = substr( $line, 0, 23 );
print OUTFILE "-----$begin\n";

my $version = substr( $line, 23, 34 );
print OUTFILE "$version\n";

print OUTFILE "\n";

my $body = substr( $line, 57 );
$body = substr($body, 0, length($body)-26);

my @parts = split " ", $body;
for my $piece( @parts )
{
print OUTFILE "$piece\n";
}

print OUTFILE "-----END PGP MESSAGE-----\n";
}#while each line

close(OUTFILE);
close(INFILE);

my $cmd = qq{ gpg --yes --decrypt /tmp/calendarEvent.encrypted };
$cmd .= qq{ > /tmp/calendarEvent.decrypted };
my $res = `$cmd`;


В процессе загрузки, обработки или отображения событий календаря могут быть утеряны некоторые элементы исходного форматирования. В частности, удаляются префикс "-----" в сообщении "BEGIN PGP", а также переносы строки, удаляются. Функции обработки строк восстанавливают потерянное форматирование перед вызовом команды дешифрования. Наконец, следующий код выполняет безопасное удаление расшифрованного текстового файла, сохраненного на диске.

}elsif( $mode eq "shred" )
{
my $res = `shred /tmp/calendarEvent.decrypted`;
$res = `rm /tmp/calendarEvent.decrypted`;
}

# EOF


После сохранения файла /tmp/CalendarCrypt.pl убедитесь, что файл является исполняемым, выполнив команду chmod a+x /tmp/CalendarCrypt.pl.

примеры использования

Теперь каждое событие, добавляемое при помощи Google Calendar Quick Add, будет перехватываться, шифроваться и загружаться на серверы Google в зашифрованном виде. Перезагрузите все события из каталога chrome при помощи расширения Extension Developer's Extension или перезапустите Firefox. Используйте сочетание клавиш Ctrl+; и добавьте событие с текстом «Визит к врачу завтра 16:30». Откройте Календарь Google в «обычном» режиме; вы должны увидеть событие, подобное показанному слева на рисунке 1.

Чтобы просмотреть событие в расшифрованном виде, откройте ссылку http://www.google.com/calendar/htmlembed?src=<yourCalendarName>%40gmail.com где <yourCalendarName> это имя вашей учетной записи, например "developer.works" или "bob_smith". При загрузке страницы вы должны увидеть всплывающее окно gpg-agent с запросом вашего пароля. Введите пароль для пользователя, указанного в параметре "uname" команды из раздела 1 программы CalendarCrypt.pl, и ваши события будут расшифрованы и отображены в вашем календаре.

заключение, дополнительные примеры

При помощи инструментов и кода, описанных в этой статье, вы можете хранить весь текст Календаря Google в зашифрованном виде. Благодаря модификации расширения Firefox Google Calendar Quick Add от Элиаса Торреса каждое добавляемое или просматриваемое событие будет прозрачно шифроваться или дешифроваться. В результате вы получаете возможность лучше контролировать свои личные данные, пользуясь при этом лучшими возможностями приложений Web 2.0.

Можно добавить дополнительный уровень шифрования для изменения сохраняемого времени событий, чтобы снизить эффективность анализа трафика. Создайте собственную программу, использующую интерфейсы SOAP API Google Calendar, для обработки, шифрования и хранения всех прошлых и будущих событий календаря. Попробуйте создать расширение для прозрачного шифрования стандартного интерфейса Календаря Google, используя все возможности Ajax.



Натан Харрингтон, программист, IBM. Впервые опубликовано на IBM developerWorks
обсудить статью
© сетевые решения
.
.