среда, октября 31, 2007

Extreme Programming Essentials

Недавно обнаружил в загашниках интересный документ "Регламент разработчика XP". В 2004 году мы решили начать разработку очередного проекта по методологии XP. А поскольку большинство наших программистов знали об XP только то, что кодировать надо вдвоем, я написал небольшой документ, в котором на пяти страницах постарался изложить всю суть этой методологии, а также краткий свод требований для повседневной работы. Сегодня я перечитал этот док, и понял что ничего не могу в него ни добавить ни убрать. Значит он выдержал проверку временем. Итак, здесь выжимка из всего того, что должен знать каждый программист об XP.



Extreme Programming Essentials


Что такое XP


Экстремальное программирование (eXtreme Programming) – это методика разработки программного обеспечения, которая представляет собой набор принципов и практик, направленных на быстрое создание программного продукта, в максимальной степени удовлетворяющего потребности заказчика. Прилагательное «экстремальное» обозначает, что данная методика предполагает максимально интенсивное использование всех входящих в нее практик.

Основные ценности XP:

  • Общение (communication). Причина большей части проблем разработки программного обеспечения это недостаток общения между членами команды разработчиков, между разработчиками и заказчиками. Постоянные коммуникации обеспечивают большую согласованность процесса разработки.

  • Простота (simplicity). Всегда старайтесь решить задачу самым простым способом из всех возможных. Сделай самую простую вещь, которая способна работать (Do simplest thing that could possibly work).

  • Обратная связь. Чем раньше вы сможете получать отзывы от пользователей, тем лучше вы сможете удовлетворить требования заказчика.

  • Храбрость (courage). Вы должны обладать храбростью для того, чтобы двигаться с максимальной скоростью и совершать правильные поступки (например, отказаться от написанного кода, обнаружив в нем серьезную ошибку и начать все заново).


Основные практики XP. Ниже перечислены 12 практик XP, которые должны использоваться комплексно и с максимальной интенсивностью. Поскольку каждая из этих практик опирается на другие и дополняет их.

  1. Процесс планирования. Планирование производится непрерывно в ходе всего процесса разработки с целью определения текущих задач приоритетов и сроков разработки.

  2. Тестирование. Любая разрабатываемая функциональность сопровождается тестами позволяющими определить, что код делает именно то, что от него требуется.

  3. Парное программирование. Любой код разрабатывается двумя программистами.

  4. Простой дизайн. Любая функциональность реализуется максимально простым образом. Дизайн системы постоянно перерабатывается с целью ее (системы, не дизайна) улучшения.

  5. Рефакторинг. Улучшение кода путем его переработки. Один и тот же код не должен встречаться в нескольких местах системы (once and only once).

  6. Коллективное владение кодом. Каждый из разработчиков отвечает за работоспособность всей системы.

  7. Постоянная интеграция. Новый код постоянно интегрируется в систему, и система постоянно поддерживается в работоспособном состоянии.

  8. Заказчик на месте разработки. Разработчик всегда может проконсультироваться с заказчиком по поводу функциональных требований. Заказчик всегда может увидеть, как исполняются его пожелания.

  9. Частые выпуски версий. Новые версии системы передаются заказчику как можно чаще, для того чтобы тот мог оценить в правильном ли направлении движется разработка.

  10. 40 часовая рабочая неделя. Разработчики не должны работать сверхурочно, так как от этого снижается производительность и качество работы.

  11. Стандарты кодирования. Разработчики придерживаются общих стандартов кодирования для облегчения понимания кода.

  12. Метафора системы. Простая аналогия, доступно и понятно описывающая предназначение и внутреннее устройство системы.



Взаимодействие заказчика и разработчика.

Методология XP определяет две роли в процессе разработки: заказчик и разработчик.

Методология XP построена на принципах взаимодействия и тесной обратной связи между этими ролями. Предполагается, что заказчик активно участвует в процессе разработки с самого начала.

Обязанности и привилегии роли заказчика:
  • Заказчик определяет функциональные требования к системе через «пожелания заказчика»

  • Заказчик определяет приоритеты в реализации тех или иных требований.

  • Заказчик определяет дату выпуска системы.

  • Заказчик совместно с разработчиком определяет общий план разработки системы, а также план каждой итерации (для этого определяется перечень пожеланий, реализуемых в ходе итерации)

  • Заказчик принимает результаты разработки отдельно по каждому из пожеланий.

  • Заказчик может добавлять новые пожелания или снимать старые в ходе всего цикла разработки системы, вплоть до сдачи системы в эксплуатацию.



Имея столь широкие полномочия, заказчик несет полую ответственность за результаты проекта (включая обоснованность и коммерческую востребованность реализованного функционала).

Обязанности разработчика:
  • Разработчик совместно с заказчиком определяет план разработки системы и планы каждой итерации.

  • Разработчик определяет дизайн системы, максимально соответствующий требованиям заказчика.

  • Разработчик информирует заказчика о возможных технических проблемах, или о возможных последствиях в ходе реализации тех или иных пожеланий заказчика.

  • Разработчик оценивает затраты ресурсов на реализацию того или иного из пожеланий заказчика.

  • Разработчик реализует пожелания заказчика в функционале системы.

  • Разработчик информирует заказчика о ходе выполнения проекта, о возникающих проблемах и (или) отклонениях от графика.



До начала разработки заказчик совместно с разработчиком выполняет сбор требований, планирование и разработку общего дизайна (фаза анализа или нулевая итерация).

Разработка ведется короткими итерациями (2-3 недели). Для каждой итерации составляется план, состоящий из набора пожеланий заказчика. Заказчик определяет, какие из пожеланий следует реализовать в первую очередь. Разработчик оценивает затраты ресурсов на реализацию пожеланий и исходя из этого верстает план итерации. По окончании итерации заказчик принимает функционал по каждому из пожеланий.

В ходе реализации пожеланий разработчики решают все возникающие вопросы с представителем заказчика.

Процесс планирования разработки

Разработка ведется в соответствии с функциональными требованиями, формируемыми заказчиком (заказчиками). Основным элементом, в виде которого оформляются функциональные требования, является «пожелание заказчика».

Перед началом разработки выполняется так называемая фаза анализа или нулевая итерация, в ходе которой заказчик и разработчик формируют общее видение системы и первичный перечень пожеланий заказчика. Из полученного перечня пожеланий формируется предварительная функциональная спецификация. Разработчик выполняет предварительную оценку затрат ресурсов по каждому из пожеланий заказчика, а заказчик выставляет приоритеты для каждого пожелания. Данная информация используется при планировании итераций. В первые итерации попадают те пожелания, которые имеют наивысший приоритет.

Пожелания заказчика должны быть такими, чтобы их можно было реализовать за 2 – 4 дня разработки. Более крупные пожелания должны быть разбиты на несколько более мелких (конкретизированы).

Методология XP исходит из того, что не возможно сформулировать все функциональные требования перед началом разработки. Поэтому пожелания могут вноситься и удаляться в процессе разработки. Выполнять эти действия может только заказчик (либо с согласия заказчика – разработчик). Все практики XP нацелены на то, чтобы облегчить внесение таких изменений в ходе разработки.

При добавлении новых функциональных требований происходит перепланирование. Разработчик оценивает затраты ресурсов на реализацию новых пожеланий, а заказчик должен либо удалить другие свои пожелания на такую же сумму ресурсов, либо пересмотреть срок сдачи продукта (версии, итерации).

Планирование итерации

Разработка ведется итерациями. Продолжительность 2-3 недели. В начале каждой итерации выполняется планирование.

Планирование итерации. Планирование итерации состоит в том, что разработчик совместно с заказчиком выбирает из общего перечня пожеланий те, которые будут реализованы в ходе итерации. Далее разработчик уточняет у заказчика суть каждого пожелания, и разбивает его на отдельные задачи. Задачи отражают то как, будет реализовано пожелание, и представляют собой описания отдельных частей программы (бизнес объект, визуальная форма, сервис и т.д.). Для задач оцениваются необходимые затраты ресурсов, и на основе этих оценок уточняются затраты ресурсов по пожеланиям заказчика. Задачи должны формулироваться таким образом, чтобы реализация каждой из них занимала не более двух дней. Совокупная оценка затрат ресурсов по всем пожеланиям заказчика, включенным в итерацию не должна превышать совокупных наличных ресурсов итерации (число разработчиков умноженное на число рабочих дней итерации). Если затраты ресурсов по пожеланиям превосходят фонд ресурсов команды на итерацию, следует перенести лишние пожелания заказчика на следующую итерацию, либо разбить некоторые пожелания на более конкретные (мелкие) и часть из них перенести в следующую итерацию.

По окончании итерации заказчик совместно с разработчиком принимает реализованные в данной итерации пожелания. Если для пожелания существуют функциональные тесты, то приемка осуществляется на основании этих тестов. Если функциональных тестов нет, приемка осуществляется на основании описания пожелания заказчика. Отметку о том, что данное пожелание реализовано, ставит заказчик.

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

Разработка функционала.

Разработка прикладного функционала ведется в разрезе пожеланий заказчика. Для реализации каждого пожелания заказчика, как правило, выделяются два разработчика (если позволяет размер команды). Пара разработчиков, по своему желанию, может вести свою работу в режиме парного программирования (оба разработчика в паре последовательно работают над задачами), либо распределить задачи между собой и выполнять их параллельно.

Все вопросы, касающиеся толкования (понимания) пожелания заказчика разработчиками, или реализации изложенных в нем требований должны решаться совместно с представителем заказчика. Разработчики не должны делать никаких предположений по поводу функциональных требований, если они им не ясны или допускают двоякое толкование.

Разработчик должен стремиться реализовать пожелание заказчика максимально простым способом (Do simplest thing that could possibly work). Не следует делать никаких предположений относительно будущей модернизации кода, если это прямо не вытекает из имеющихся в наличии пожеланий заказчика. Разработчик должен руководствоваться правилом «Это нам не понадобится» YAGNI (You Aren't Gonna Need It), относительно любой функциональности, не описанной в текущих пожеланиях заказчика.

Весь разрабатываемый функционал должен сопровождаться модульными тестами. Нельзя добавить в проект функционал без модульных тестов. Исключение составляет тривиальный код (методы аксессоры, обертки, и т.п.), а также код, сгенерированный мастерами и генераторами кода (напр., DataSet).

В ходе разработки необходимо проводить постоянный рефакторинг кода, с целью повышения его надежности и простоты. Разработчик должен придерживаться правила трех О: “Once and Only Once”, что значит, избегать дублирования кода.

Каждый разработчик отвечает за работоспособность всей системы. Перед внесением своих изменений следует убедиться (прогнав весь набор модульных тестов) в том, что вносимые изменения не нарушат работоспособность системы. Если такое случается, разработчик должен добиться правильного срабатывания всех тестов. Либо отменить свои изменения.

Разработчик должен как можно чаще интегрировать свой код в систему (соблюдая при этом требования предыдущего пункта). Следует избегать ситуации, когда файлы с исходным кодом остаются на check-out в VSS более чем на один день. Это существенно затрудняет последующую интеграцию кода.

Для разработчика определяется следующий регламент действий по реализации каждого пожелания заказчика:
  • Для удобства, в случае, когда Solution продукта велик, разработчик создает локальный solution, в который он включает проекты, необходимые ему в разработке.

  • Перед началом реализации пожелания следует взять из VSS последнюю версию исходных кодов системы.

  • Для каждой задачи параллельно разрабатывается модульный тест и исходный код (предпочтительно разрабатывать сначала тесты, а затем код). Необходимо добиться срабатывания модульного теста.

  • Модульный тест включается в состав общего плана тестирования, и проверяется срабатывание всех модульных тестов системы в тестовом solution продукта. Если какие либо из тестов перестали срабатывать, разработчик должен выяснить причину, и внести необходимые изменения в код системы, не зависимо от того, кто разрабатывал этот код. В случае затруднения разработчик может призвать на помощь автора кода. В любом случае разработчик должен уведомить членов команды о внесенных изменениях.

  • Добившись срабатывания всех модульных тестов, разработчик может приступать к внесению нового кода в VSS (интеграции). Процедура интеграции следующая. Сохранив изменения в VSS (check-in), разработчик должен на специально выделенной для целей интеграции машине взять последнюю версию исходных кодов системы, собрать тестовый и основной solution системы и выполнить полный набор модульных тестов. Если какие либо из тестов не выполняются, следует либо выявить и устранить ошибки (не зависимо от того, к какой части кода системы они расположены) и добиться срабатывания тестов, либо откатить в VSS свои изменения. При необходимости разработчик должен проделать дополнительные действия (развертывание конфигурации импорт – экспорт прикладных данных и т.п.) необходимые для того, чтобы на интеграционной машине была развернута работоспособная, последняя версия разрабатываемого продукта.

  • В случае если система оказывается в неработоспособном состоянии, ответственность за это лежит на том, чьи изменения привели к ошибке (а не на том, в чьем коде обнаружена ошибка).



В рамках команды проекта проводятся ежедневные короткие совещания (stand-up meeting), на которых разработчики рассказывают друг другу о проделанной за прошлый день работе, имеющихся проблемах и планах на текущий день. Вопросы по реализации конкретных пожеланий заказчика и решении возникающих проблем обсуждаются в частном порядке с участием заинтересованных лиц вне рамок данного совещания.

четверг, октября 25, 2007

Блогу год

Как-то незаметно проскочила "знаменательная дата" :)
Есть повод поговорить о статистике. Итак, пятерка самых популярных постов.
1. "Золотой век русского программиста", что в общем-то не удивительно.
2. "Собеседование, вопросы на засыпку" - к великому моему сожалению. Этот же пост лидер по поисковым запросам. У меня есть много чего интересного рассказать и про собеседования и про вопросы по C#, но мне не очень хочется разрабатывать эту "золотую жилу".
3. "Xml serialization" - с этой штукой нам пришлось плотно поработать еще на проекте "Бизнес монитор" в "Галактике" в 2004 году. В статье я лишь собрал все до кучи и адаптировал под FW 2.0
4. "Web сервис и протокол HTTPS (SSL)" - один из первых постов, а на самом деле это немного переработанная инструкция по адаптации web сервисов к работе по HTTPS, которую я написал для наших программистов устав, объяснять все "на пальцах". Пост содержит некоторые неточности, до которых никак не дойдут руки.
5. "Обзор архитектуры Windows Communication Foundation..." - это перевод статьи из MSDN и первый пост в блоге. Было много свободного времени, болел, и я просто попытался совместить полезное с полезным :) - изучение WCF и практику в английском. За практику в английском получил, к стати, довольно язвительный комментарий.

С годовщиной.
Спасибо Вам всем!

четверг, октября 18, 2007

Восход и закат CORBA

Весьма поучительная статья "Восход и закат CORBA".
Для тех кто, не застал эти времена поясню. CORBA - Common Object Request Broker Architecture - архитектура и набор спецификаций для распределенного взаимодействия приложений, продвигаемая консорциумом OMG.
Поддержка CORBA появилась в Delphi 3 (если не ошибаюсь), и при настойчивых попытках разобраться в этой технологии меня всегда поражала запредельная ее сложность. Тогда я думал, что просто недостаточно квалифицирован для такой продвинутой технологии, как CORBA.
В качестве своего ответа OMG, Microsift создала DCOM. А Sun для Java - свою знаменитую EJB. И CORBA тихо загнулась. Еще до того как появились SOAP и web сервисы. Загнулась из-за своей сложности, многословности, из-за бюрократизма в OMG.
Со многими проектами происходит такое. В некоторых мне самому довелось поучаствовать (Ranet - привет :). Но провал такого масштаба, когда угроблены миллиарды, когда участвовали компании с мировыми именами, когда, наконец, сам провал занял более десятка лет... Почитайте, очень поучительно.

F# будет включен в состав .Net

Как сообщает Joe Daffy в своем блоге, семейство языков .Net пополнилось: "Welcoming F# to the family".
Вице президент Microsoft Developer Division S. Somasegar анонсировал новый функциональный язык, созданный в недрах Microsoft Research.
Soma[segar] говорит:
"One of the important themes in programming languages over recent years has been a move to embrace ideas from functional programming."


И мы видим это на примере C#. Последние изменения в C# пришли именно из области функционального программирования (анонимные делегаты, лямбда выражения, LINQ). Joe Daffy говорит о том что F# упростит построение параллельных программ.
Похоже MS всерьез повернулась лицом к функциональному программированию:
"This is one of the best things that has happened at Microsoft ever since we created Microsoft Research over 15 years ago." (Somasegar)


И основная причина тому - необходимость адекватного ответа в области средств разработки на вызов со стороны производителей железа в виде многоядерных процессоров.
F# это полностью CLR совместимый язык, и его поддержка будет включена в Visual Studio. В принципе можно уже пробовать

А пока несколько code snippets на F#:


let task1 = async { return 10+10 }
let task2 = async { return 20+20 }
Async.Run (Async.Parallel [ task1; task2 ])

.....

let AsyncHttp(url:string) =
async {// Create the web request object
let req = WebRequest.Create(url)

// Get the response, asynchronously
let! rsp = req.GetResponseAsync()

// Grab the response stream and a reader. Clean up when we're done
use stream = rsp.GetResponseStream()
use reader = new System.IO.StreamReader(stream)

// synchronous read-to-end
return reader.ReadToEnd() }

...

Async.Run
(Async.Parallel [ AsyncHttp "http://www.live.com";
AsyncHttp "http://www.google.com";
AsyncHttp "http://maps.live.com";
AsyncHttp "http://maps.google.com"; ])



Выглядит интересно.

понедельник, октября 15, 2007

Жили были...

Недавно наткнулся на очень интересный блог, название которого собственно так и расшифровывается - "Жили были". Автор, просто не реальный человек. С далекого тихоокеанского побережья Британской Колумбии он неспешно рассказывает об истории становления и распада советской компьютерной (и не только) индустрии в преломлении своего личного опыта. Начало его истории здесь. Каждый пост сопровождается зарисовкой из жизни далекого далека, о том, например, как хорошо бывает вздремнуть часок с утра на бережке Тихого океана под кустом цветущего шиповника перед началом трудного рабочего дня. А для того, чтобы читатель не решил, что все это бред воспаленного воображения, каждый пост сопровождается фото/видео материалами :)
В общем, все очень живо, интересно и увлекательно. Вот, например, 90-ый год:
Немецкая частная инжиниринговая компания принимала нас душевно. Годдарт Питерс, баварский барон, мультимиллионер, инженер, гонщик и хозяин компании устроил состязание между РИПАКом (под моим управлением) и IDEAS (его сотрудники). Я победил с огромным отрывом, решив тестовые задачи за два часа на РИПАКе, установленном на их VAXе. Его ребята представили результаты только на следующий день. Более того, решалка в IDEAS оказалась несовершенной - элемент для моделирования стенок балок был несвободен от ложного сдвига. Немцы ошиблись на 30%, что я легко доказал. Эффект моей победы был очень силен.

Я вот только одного не пойму. IDEAS использовал для расчетов BMW, а РИПАК-ом, вроде бы пользовались на ВАЗе. Так почему же конечный результат у нас такой убогий?
Впрочем, это вопрос уже не к автору блога.

среда, октября 10, 2007

Релакс



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

Стартапы среди нас.

Когда в посте "Золотой век русского программиста" я сокрушался по поводу слишком малого количества системного и прочего "мозгоёмкого" софта, производимого в России, я вовсе не думал о таких предвыборных извращениях как Российская ОС для российских школ. Я думал, к примеру, о технических комитетах W3C и OASIS в которых будут работать представители наших компаний наряду с парнями из BEA, IONA, Sun и других. А такие компании, как известно, вырастают из стартапов.

А стартапы есть таки, и причем, прямо среди нас. Вот вчера, обнаружил один буквально в пяти минутах ходьбы от своей квартиры :) Ну, вернее обнаружил я его в Интернете, представляю: Pawlin Technologies молодая фирма из Дубны. Занимаются искусственным интеллектом (AI) и нейросетевыми технологиями, а вернее различными практическими применениями этих технологий (обработка изображений, распознание образов и т.д.). Ребята, выходцы из МФТИ и Физикона, теперь пытаются продвигать чертовски интересные вещи. Надеюсь, все у них получится.

Кстати, у них открыты вакансии программистов и (внимание!) научных сотрудников. Предлагают они и удаленную работу.

вторник, октября 09, 2007

Смените фамилию

Представьте себе, вы приходите устраиваться на работу в компанию, успешно проходите все интервью, но в отделе кадров вам говорят: "К сожалению мы не можем вас принять. У нас уже есть сотрудник с такой фамилией именем и отчеством, и наша корпоративная система не позволяет добавить еще одного с такими же инициалами. Вы можете прийти позже, если смените фамилию." Звучит как анекдот, не правда ли?
Есть у нас корпоративная система, тесно интегрированная в Microsoft Project Server 2003. Так вот, в БД Microsoft Project Server 2003 в таблице, хранящей сотрудников Enterprise Resource Pool (т.е. всех сотрудников компании) есть unique constraint на поле ФИО. Не знаю, в каких облаках витали разработчики, когда проектировали Project Server, но у нас в компании около дюжины полных однофамильцев. Теперь сервис, который автоматически добавляет новых сотрудников в Project Server Enterprise Resource Pool проявляет чудеса изворотливости, а человек видит себя в MS Project как-то так: "Иванов Иван Иванович (4864)".
Ну, действительно, не отказывать же кандидату из-за того, что у него фамилия не уникальная :)

понедельник, октября 08, 2007

Бардак в сайтостроении.

Я всегда считал web разработку занятием легковесным и неблагодарным. Вся эта смесь серверных, клиентских скриптов, SQL, разметки, стилей. А обеспечение совместимости браузеров чего стоит.
Используемые языки и инструменты также не способствуют облагораживанию дизайна web приложений. Несмотря на усилия Sun и Microsoft придать этому бедламу некое благообразие в продвигаемых ими платформах, мало чего изменилось к лучшему. Вот, оказывается не один я придерживаюсь такого мнения. IBM DeweloperWorks публикует статью Питера Сибаха "Недовольный пользователь: Что же случилось с Web-проектированием?"
В отличие от меня, автор не только противно брюзжит по этому поводу, но и предлагает пути решения проблемы.

пятница, октября 05, 2007

Где хранить ключи?

Когда нам надо защитить данные системы в БД, в файле, при пересылке, мы просто берем и шифруем их каким ни будь симметричным алгоритмом. Данные зашифрованы, и тут перед нами встает проблема, куда теперь девать ключ, которым зашифрованы данные. Ведь их потом надо расшифровать, причем этим же ключом. С такой проблемой сталкиваются многие разработчики и каждый решает ее по своему с разной степени кривизны и навороченности. Сталкивался с ней и я, причем несколько раз за последнее время. И решал, с разной степенью навороченности и кривизны :) Опытом своих экзерциций я и хочу поделиться.

Начнем с очевидных вещей. Первое, ключ следует хранить отдельно от защищаемых данных. Если шифруемые данные хранятся в БД, то ключ там хранить не стоит.

Второе, ключ должен быть защищен. Открытый ключ, доступный каждому, сводит на ноль все усилия по защите данных.

Третий момент менее очевидный и касается он только многопользовательских систем. В таких системах необходимо обеспечить доступ авторизованных пользователей к ключам. Стратегий может быть две: либо каждый пользователь шифрует свои личные данные персональным ключом, либо все пользователи шифруют общие (shared) данные одним ключом. Выбор стратегии зависит от функциональных требований, а сама стратегия накладывает ограничения на способ хранения ключей.

Итак, задача номер один - защитить (зашифровать) ключ, задача номер два – придумать, где его хранить.

Для шифрования ключа можно, например, использовать ассиметричный алгоритм (RSA), но опять же - где хранить ключи ассиметричного алгоритма? Замкнутый круг. В .Net 1.1 для этой цели я пытался использовать CSPParameters но результат получался не удовлетворительный (конкретно, не удавалось использовать CspProviderFlags.UseMachineKeyStore для пользователей с ограниченными правами). Хорошо если пользователи вводят пароль при входе в систему, тогда этот пароль можно использовать для защиты персонального ключа. А если ключ должен быть общий? Или пользователи используют windows integrated аутентификацию и не вводят никаких паролей? К счастью этой же проблемой озаботились парни из Рэдмонда и написали для этих целей Data Protection API (DPAPI). В .Net 1.1 надо было делать managed обертку для DPAPI. В .Net 2.0 появился специальный класс System.Security.Cryptography.ProtectedData. Его методы Protect и Unprotect замечательно подходят для таких задач, как шифрование симметричного ключа:


byte[] salt = new byte[] { 143, 22, 104, 10, 12, 83 };
byte[] cryptedKey = ProtectedData.Protect(key, salt, DataProtectionScope.CurrentUser);
byte[] cryptedIV = ProtectedData.Protect(IV, salt, DataProtectionScope.CurrentUser);



Здесь key и IV это и есть наш симметричный ключ (и вектор инициализации), в salt - это хвост, который добавляется для повышения криптостойкости полученного результата. DataProtectionScope определяет область действия защиты. Если данные зашифрованы в DataProtectionScope.CurrentUser расшифровать их можно будет только для того же пользователя. Если область действия LocalMachine – то любой пользователь на этой машине.

Итак, с защитой ключа все ясно. Теперь определимся с местом хранения. Первым делом, напрашивается хранение в файле. Но существует более удобный способ - System.IO.IsolatedStorage. Не следует думать что IsolatedStorage представляет из себя какое то защищенное хранилище, которое может повысить защищенность хранимых данных. Никакой дополнительной защиты IsolatedStorage не дает. Его скорее следует рассматривать, как некую виртуальную песочницу, которая позволяет, с одной стороны, абстрагироваться от файловой системы, а с другой стороны ограничить область видимости до необходимого уровня. Область видимости ограничена локальной машиной или пользователем, а внутри дополнительно приложением, AppDomain-ом или конкретной сборкой. Реально, данные IsolatedStorage сохраняются в пользовательском профайле. Таким образом, IsolatedStorage избавляет нас от необходимости настройки разрешений NTFS, а также от опасности того, что данные одного приложения будут затерты или прочитаны другим приложением.

Итак, мы шифруем наш симметричный ключ с помощью ProtectData и затем сохраняем его в IsolatedStorageFile:



private byte[] _key; // ключ
private byte[] _iv; // вектор инициализации
private string _name; // имя под которым будем хранить ключ
private DataProtectionScope _scope; // область видимости


private IsolatedStorageFile GetIsolatedStorage()
{
// в зависимости от области видимости получаем IsolatedStorageFile
if (_scope == DataProtectionScope.LocalMachine)
return IsolatedStorageFile.GetMachineStoreForDomain();
else return IsolatedStorageFile.GetUserStoreForDomain();
}

byte[] salt = new byte[] { 143, 25, 4, 30, 11, 83 };
// сохраняем ключ
void SaveInStorage()
{
// сначала шифруем
byte[] cryptedKey = ProtectedData.Protect(_key, salt, _scope);
byte[] cryptedIV = ProtectedData.Protect(_iv, salt, _scope);

// потом сохраняем
IsolatedStorageFile iStorage = GetIsolatedStorage();
using (BinaryWriter writer = new BinaryWriter(new IsolatedStorageFileStream(_name, FileMode.Create, iStorage)))
{
// записываем длину зашифрованного ключа
writer.Write(cryptedKey.Length);
// записываем длину зашифрованного IV
writer.Write(cryptedIV.Length);
// записываем зашифрованный ключ
writer.Write(cryptedKey);
// записываем зашифрованный IV
writer.Write(cryptedIV);
}
}

// поднимаем ключ
void LoadFromStorage()
{
byte[] encryptedKey;
byte[] encryptedIV;
// читаем ключ из IsolatedStorageFile
IsolatedStorageFile iStorage = GetIsolatedStorage();
using (BinaryReader reader = new BinaryReader(new IsolatedStorageFileStream(_name, FileMode.Open, iStorage)))
{
// сначала читаем длину ключа
int keyLength = reader.ReadInt32();
// потом читаем длину IV
int ivLength = reader.ReadInt32();

encryptedKey = new byte[keyLength];
encryptedIV = new byte[ivLength];
// затем читаем ключ и IV
reader.Read(encryptedKey, 0, encryptedKey.Length);
reader.Read(encryptedIV, 0, encryptedIV.Length);

// расшифровываем ключ и IV
_key = ProtectedData.Unprotect(encryptedKey, salt, DataProtectionScope.LocalMachine);
_iv = ProtectedData.Unprotect(encryptedIV, salt, DataProtectionScope.LocalMachine);
}
}



Здесь приведен фрагмент кода класса SymmetricKeyContainer, который инкапсулирует в себе логику защиты и хранения симметричного ключа. Этот класс входит в небольшую библиотеку CryptoUtils, которую я разместил в Google Code Project Hosting, в основном с целью опробовать этот новый инструмент Google. И надо сказать, я остался им вполне доволен. Полностью исходный код класса можно взять в репозитории проекта (svn) здесь: http://cryptoutils.googlecode.com/svn/

четверг, октября 04, 2007

Sputnik



Вот таким логотипом сегодня Google отмечает 50-летие запуска первого спутника.
Мелочь а приятно.

Microsoft открывает исходники .Net

Как сообщает в своем блоге Scott Guthrie его команда сейчас ведет работы по подготовке к публикации исходников .Net Framework 3.5. Исходные коды и отладочные символы будут включены в релиз Visual Studio 2008, а также будут доступны "via a standalone install".
Исходники публикуются под лицензией Microsoft Reference License (MS-RL).
Чтож, здорово.
Это конечно не совсем Open Source, в том смысле, как это обычно принято понимать. MS-RL оставляет все права за Microsoft. Но все же публикация исходников значительно облегчит жизнь .Net разработчиков.