Mémoires — лучший способ вести дневник на Маке

Так как Google Reader закрывается, а большинство читателей этого блога пользуется именно им для чтения Sellme.ru, хотел напомнить, что можно подписаться на получение новых заметок по электронной почте:

Введите свой email:

(если форма не работает, кликните по этой ссылке).

Я нынче в блог пишу не часто, но не хотелось бы с вами потеряться. Тем более, скоро будет несколько интересных анонсов.

Написал на Go BLAKE-512 (в дополнение к BLAKE-256) и Skein (Threefish тоже). Обе хэш-функции не выиграли SHA-3, выиграл Keccak. Плохо, Keccak в софте медленный.

SipHash! Я рассказывал про SipHash? Это криптографическая функция (MAC): даете ей 128-битный ключ и текст любой длины, она считает 64-битный хэш. Очень быстро работает (> 1 гигабайта в секунду на компе 2009 года), но самое главное, быстро считает хэш очень коротких текстов (8 байт, например). Ее придумали Jean-Philippe Aumasson и Dan Bernstein для того, чтобы победить HashDoS. Ruby на нее недавно перешел и Rust тоже. Если будете писать хэш-таблицу, обязательно используйте SipHash — она почти так же быстра, как MurMurHash или CityHash, но в отличие от них, безопасна (повторяю — криптографическая функция). Люди-то думали, что достаточно впихнуть любое рэндомное число куда-нибудь в функцию, и тогда коллизии невозможно угадать; а Жан-Филиппе с Бернштейном показали, что это не так: коллизии, например, для MurMur можно сделать такие, что они вообще не будут зависеть от seed будь он хоть трижды рэндомным. Так вот, я, конечно же, написал пакет для Go.

А еще я перевел на Go Бернштейновскую криптобиблиотеку NaCl, а потом оказалось, что Adam Langley работал над тем же. Мы объединили мои версии на Go, его ассемблерные версии, он написал новый интерфейс (лучше), и теперь все это дело живет в официальном репозитории go.crypto (документация тут). Если вам надо что-то зашифровать в своей программе, обязательно используйте NaCl. Она в несколько раз быстрее какой бы то ни было нехардварной комбинации MAC с AES, а самое главное, интерфейс — проще некуда.

В go.crypto, кстати, теперь еще живет scrypt, которую я написал в апреле. Scrypt придумал Colin Percival. Если вам нужен хэш пароля, или надо пароль преобразовать в ключ для шифрования, используете scrypt и будете счастливы. А не как LinkedIn, у которого утекли пароли, или Bitrix24, который хвастается тем, что хэширует пароли “двойным MD5”. Интересно, как они пришли к тому, что двойной MD5 лучше, чем, например, пятерной? Хе-хе.

Richard Hipp придумал для прототипа SQLite4 хорошую кодировку для беззнаковых целых чисел. Опять же, я написал пакетик для Go. Смысл кодировки в том, что маленькие числа кодируются в маленькое количество байт, а большие числа — в большее количество байт, но не равномерно, как, например, у гугловского varint используемого в компрессоре Snappy, а оптимизированно под маленькие числа. Если Snappy кодирует число 200 в два байта, то эта кодировка — в один. Кроме того, по первому байту можно определить сколько еще байт в числе, а у Snappy для этого нужно читать байты до финального.

WebP. Помните еще такой формат картинок? Google придумал, Opera использует в “Turbo”. Так вот они теперь поддерживают альфа-канал в lossy картинках и добавили lossless, который сжимает лучше PNG. Я обновил свой QuickLook плагин (это который показывает картинки, если нажать пробел в Finder) — теперь он поддерживает все нововведения.

Еще я написал кучу строк кода для всяких секретных проектов, но пока рассказать о них не могу, потому что секретные проекты часто не релизятся.

Вроде все.

PS. За моим кодом можно следить на CodingRobots.org и GitHub.

Fossil хранит все данные — коммиты, тикеты, странички вики, аттачменты, и т.д. — в виде артефактов, к которым он адресуется по SHA1 хэшу содержимого.

Например, вот так выглядит описание коммита (манифест) 30fbf3723ed00679c60006217c5d996b20cb5aa6:

C Add\stest.txt.
D 2012-08-12T11:40:52.146
F test.txt e2db724da21fa19b21835946bcf8359a598ef67c
P 337fd550fc7257170d25a6b22622c20d137d1b56
R 6e7be55bd50eabe58814c006fd8a25a6
U dchest
Z aa72952b1d3914bc6502058f0e66239a

Этот манифест говорит, что пользователем dchest был сделан коммит 8 августа 2012 года с комментарием “Add test.txt”, и что теперь в проекте 1 файл, test.txt.

Сами файлы хранятся аналогично: как видно из манифеста, файл test.txt адресуется по хэшу содержимого, e2db724da21fa19b21835946bcf8359a598ef67c.

This is test.

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

Fossil deconstructed repository

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

Как Fossil отличает простое содержимое файлов от манифестов? А никак — любой текст, который можно пропарсить как манифест, будет манифестом. В этом ничего страшного нет, потому что случайно сделать содержимое файла, который будет парсится как правильный манифест, сложно. А если неслучайно?

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

Вот как можно было делать коммиты в любой репозиторий Fossil без прав на коммиты, только с правами на аттачменты:

  1. Склонировать репозиторий.
  2. Понаделать нужных коммитов (например, встроить куда-нибудь бэкдор).
  3. Запустить fossil deconstruct и найти коммиты и новые файлы для этих коммитов.
  4. Создать тикет и прикрепить к нему, один по одному, содержимое файлов из пункта 3.
  5. Готово — теперь репозиторий содержит ваши коммиты!

Что еще хуже, в оригинальном репозитории в timeline новые коммиты не покажутся пока администратор репозитория не запустит fossil rebuild или не синхронизируется с другой копией репозитория, а те, кто склонирует оригинальный репозиторий получат и наши злые коммиты.

Я сообщил об этой уязвимости автору. Он закрыл уязвимость 4 апреля: теперь любой аттачмент, который парсится как манифест, просто сжимается gzip’ом, то есть, если вы приаттачили malicious_commit.txt, он окажется в репозитории сжатым в malicious_commit.txt.gz. Вот только новая версия Fossil (1.23) вышла 8 августа, и в release notes про уязвимость ни слова, поэтому если у ваших проектов была всем открыта возможность добавлять аттачменты, сделайте fossil rebuild и проверьте историю коммитов, убедившись, что в репозитории нет лишних (или отсутствующих) коммитов. Ну и, естественно, если вы еще сидите на старых версиях Fossil, срочно обновитесь или хотя бы запретите аттачменты.

Совсем случайный. Компьютер такого не сможет! Этот метод так же можно использовать вместо занятий физкультурой.

  1. Открываем текстовый редактор (или бумажный блокнот).

  2. Берем монетку.

  3. Бросаем монетку и запоминаем результат.

  4. Бросаем монетку еще раз. Если результат такой же как в прошлый раз (орел-орел или решка-решка), оба результата игнорируются (можно записать прочерк "-", чтобы потом посмотреть сколько всего бросков было). Если результат другой (решка-орел или орел-решка), записываем первый результат (1 - решка, 0 - орел) и забываем второй.

  5. Повторяем с шага 3 до получения нужного количества битов. Для 16-символьного пароля нам понадобится 96 битов, то есть 96 ноликов или единиц. В результате у нас получится что-то вроде этого: --1-0----0-111--0-0--1110--011-00--1--00-1-1-1-1---00000011-1-------011... и т.д.

  6. Убираем прочерки и группируем получившиеся единички и нолики в столбик по шесть штук:

    100111
    001110
    011001
    001111
    000000
    111011
    ...
    
  7. Смотрим в эту табличку, ищем комбинацию из цифр и записываем соответствующую ей буковку.

    000000  A      100000  g
    000001  B      100001  h
    000010  C      100010  i
    000011  D      100011  j
    000100  E      100100  k
    000101  F      100101  l
    000110  G      100110  m
    000111  H      100111  n
    001000  I      101000  o
    001001  J      101001  p
    001010  K      101010  q
    001011  L      101011  r
    001100  M      101100  s
    001101  N      101101  t
    001110  O      101110  u
    001111  P      101111  v
    010000  Q      110000  w
    010001  R      110001  x
    010010  S      110010  y
    010011  T      110011  z
    010100  U      110100  0
    010101  V      110101  1
    010110  W      110110  2
    010111  X      110111  3
    011000  Y      111000  4
    011001  Z      111001  5
    011010  a      111010  6
    011011  b      111011  7
    011100  c      111100  8
    011101  d      111101  9
    011110  e      111110  +
    011111  f      111111  /
    

Таким образом у нас получится:

100111 n
001110 O
011001 Z
001111 P
000000 A
111011 7
...

Случайно сгенерированный пароль: nOZPA7...

* * *

Такие пароли не очень подходят для систем, где регистр букв не важен (например, n и N -- одно и то же). Для них можно взять табличку ascii85 вместо base64, которую я тут привел (или придумать свою), и сделать пароль длиннее.

Почему нужно кидать монетку по два раза и игнорировать одинаковый результат? Чтобы превратить "biased coin" в "fair coin".

Бросайте монетки на здоровье!

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

Программирование:

*) Как сказали на HN, “I sometimes wonder whether Russ Cox is actually human or is in fact a collective pen name for a group of very talented hackers”. См. количество коммитов в Go, например.

Исторического интереса ссылки:

Go — хороший язык программирования. Сегодня вышла его первая стабильная версия.

Если вы еще не пробовали на нем что-нибудь написать, сейчас самое время. Можете начать с тура по Go.

Гофер и Усяка
Усяка и Гофер (by Alexandra Zakharova, Creative Commons BY-NC-SA 3.0)

Тем, кто будет программировать на нем для веба, возможно, пригодятся мои пакеты:

  • captcha - визуальная и аудио капча. Очень весело было писать этот пакет, особенно код для генерации звука. На трех языках говорит: на английском, русском и китайском. На картинке показывает цифры.
  • authcookie - создание и верификация подписанных куки. Для случаев, когда надо держать пользователей залогиненными.
  • passwordreset - имплементация функции “сбросить забытый пароль”. Генерирует токены, которые надо отослать пользователю, забывшему пароль, чтобы он мог его сбросить.
  • passwordhash - секьюрное “хеширование” паролей на основе PBKDF2.
  • uniuri - правильная генерация рэндомных строк текста, которые подходят для URL. Например, “apHCJBl7L1OmC57n”.
  • blake256 - имплементация хэш-функции BLAKE-256. BLAKE — кандидат в SHA-3, и я надеюсь, он победит. Но пока не победил, лучше не использовать для серьезных вещей.
  • stemmer - cтеммер английских слов на основе алгоритма Porter2. Нормализует слова так, чтобы их можно было найти вне зависимости от окончаний и прочих преобразований. Например, и “delicious”, и “deliciously”, пропущенные через него, дают “delici”.

Я писал в апреле 2010:

Пока для программ на Mac (платформа, на которую я так радостно перешел с Windows) никаких ограничений нет. Но это только пока. С Mac OS X 10.5 приложения можно подписывать сертификатом (как в Windows). Конечно, это служит многим полезным security целям, но появляется еще одна возможность -- выборочный запрет исполнения программ. Что если через несколько лет Mac OS X вообще не будет исполнять неподписанные приложения, как iPhone OS?

Потом были расширения для Сафари.

Сегодня Грубер анонсировал следующую версию Mac OS X:

Users have three choices which type of apps can run on Mountain Lion:

  1. Only those from the App Store
  2. Only those from the App Store or which are signed by a developer ID
  3. Any app, whether signed or unsigned

The default for this setting is, I say, exactly right: the one in the middle, disallowing only unsigned apps.

(выделение мое)

Следующие шаги Apple угадать не сложно.

Постоянные читатели помнят про мои отношения с Fossil. Fossil -- это распределенная система контроля версий со встроенным багтрекером, вики, и просмотрщиком документации; по сути, Git + GitHub в одном исполняемом файле размером примерно в полтора мегабайта, только лучше, потому что тикеты и вики, как и код, распределенные, а не сидящие на одном сервере, а веб-интерфейс доступен даже в офлайне. Fossil написал Ричард Хипп, автор SQLite.

Я часто пользуюсь почти всеми известными DVCS (например, Git для моих пакетов Go потому что goinstall его поддерживает, Mercurial для нескольких проектов и работы над Go), и мои персональные проекты постоянно мигрируют с одной DVCS на другую, но только Fossil мне как родной. Им реально просто и удобно пользоваться, и я на 100% уверен, что информация, лежащая в репозитории не повреждена (привет, Mercurial!).

Конечно, и у Fossil были и есть недостатки. Но на то он и опенсорсный проект (с BSD лицензией, кстати, а не GPL, как почти все остальные), чтобы мы могли их устранять ;-). Пару лет назад, например, я добавил поддержку SSL/TLS.

Я как-то жаловался здесь, что Fossil не поддерживает симлинки. Они важны для некоторых моих мак-проектов -- я храню в репозитории скомпилированные фреймворки (зачем -- отдельный вопрос), а фреймворк в Mac OS X -- это директория, в которой есть несколько ссылок. Пожаловался, и забыл. А потом, когда в начале этого года вернулся к Fossil после путешествий по другим DVCS, все-таки начал работать над поддержкой симлинков. Сделал перерыв на весну и лето, и недавно закончил -- бранч смёрджили в транк (привет русскому языку) и сегодня вышла версия 1.20, в которой симлинки есть (включаются опцией "allow-symlinks").

Вторым пунктом моей жалобы была производительность коммитов и добавления файлов. С тех пор в Fossil заменили код SHA-1 на более скоростной, я улучшил время добавления кучи файлов на ~30% простым патчем. Тем не менее, производительность все равно хуже, чем у идеала -- Git -- но, большое НО, это из-за специальных параноидальных проверок (которые можно отключить, но лучше не надо). Они описаны в этом документе, но я кратко расскажу тут. Во-первых, Fossil кроме высчитывания SHA-1 отдельных файлов еще считает MD5 всех файлов в коммите, а так же самого манифеста коммита (списка файлов с SHA-1 хэшами и разными свойствами, типа тэгов и бранчей). Во-вторых, после дельта-кодирования артефактов, перед тем, как сделать COMMIT транзакции в репозиторий (да, коммиты в Fossil атомарные), Fossil пробует обратно восстановить артефакты и посчитать их контрольную сумму; если получилось, коммит удался. Естественно, все эти действия, хоть и очень быстры, приводят к тому, что производительность коммита -- чуть медленней, чем у Git или Mercurial, которые не делают таких проверок. (Чтобы вы не пугались, я говорю о разнице в полсекунды, а не десятки секунд.) Но именно из-за этих проверок, я могу быть уверен, что история проекта -- именно такая, какая есть, нигде ничего не испорчено.

Еще из хороших фич в версии 1.20: side-by-side diffs (пример) и всякие улучшения security. Полный changelog тут.

В общем, качайте Fossil 1.20. Никаких сложных установок -- всего один исполняемый файл. На сервер тоже устанавливать проще, чем другие VCS, поддерживается даже обычный shared hosting с CGI.

Кстати, почти все опенсорсные проекты на http://www.codingrobots.org теперь хостятся именно Fossil-ом (каждый сайт проекта и есть репозиторий). Мак-юзерам пригодится QLFossil для удобного просмотра репозиториев в Finder.

Допустим, вы живете в каменном веке и изобрели шифр с 8-битным ключом, то есть, всего имеется 28 = 256 комбинаций. Назвали вы его SAES (Stone Age Encryption Standard). Шифр работал отлично, но прогресс не стоит на месте: у людей отросло больше пальцев на руках, они научились быстрее считать, и ваш 8-битный шифр стал не таким надежным, как раньше, потому что подобрать комбинацию из 256 вариантов стало просто. Вы решаете, что нужно сделать 16-битный шифр (216 = 65536 вариантов ключа). SAES себя хорошо зарекомендовал во всех остальных качествах, кроме размера ключа. Почему бы не взять его за основу и просто увеличить размер ключа с 8-ми до 16-ти бит?

Как это сделать? -- думаете вы. Что если взять и зашифровать текст сначала одним 8-битным ключом, например, "A", а потом полученный зашифрованный текст зашифровать еще одним (возможно, другим) 8-битным ключом, например "B"?

  1. ШИФРОВАТЬ("Dear Bob", "A") = "Ynfxr4hf"
  2. ШИФРОВАТЬ("Ynfxr4hf", "B") = "1m6Bp0nh"

Или вот так можно изобразить: EncryptK2(EncryptK1(текст)).

В итоге получится, что шифр у нас один и тот же, но две операции шифрования с 8-битным ключом расширяют размер ключа до 16-ти бит. Да? Назовем его 2SAES.

Как только вы подумали об этом, начался ураган, гром и молния, яркая вспышка и перед вами появились Диффи с Хеллманом, которые изобрели машину времени и путешествуют по всяким векам, предостерегая народ в прошлом от ошибок в криптографии и спрашивая у народа в будущем, как обстоят дела с дискретными логарифмами.

Хеллман и Диффи с машиной времени

"Чувак," -- говорят они, -- "мы в 1977 году занимались такой же фигней как ты и придумали атаку "встреча посередине" (meet-in-the-middle). Для нахождения ключей для твоего шифра понадобится не 216 операций, а 29 операций плюс 28 памяти. Нужно сначала зашифровать известный текст всеми возможными 8-битными ключами и сохранить результат, а потом пробовать расшифровывать шифротекст, опять же, 8-битными ключами. Если текст, который мы расшифровали совпадет с одним из тех, что мы зашифровали и сохранили ранее, то мы получим все два ключа."

И начали выдалбливать на большом камне код на Си, чтобы продемонстрировать атаку. (Стоит отметить, что код вы прекрасно понимали, потому что Си был изобретен как раз где-то в каменном веке.)

#include <err.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <openssl/blowfish.h>
#include <openssl/lhash.h>

Это инклюды, которые нам понадобятся. Давай сделаем пару функций для шифрования:

/* Encryption and decryption */

void
cipher(int what, uint8_t *dst, uint8_t *src, uint8_t key)
{
    BF_KEY bk;

    BF_set_key(&bk, 1, &key);
    BF_ecb_encrypt(src, dst, &bk, what);
}

Для примера будем использовать Blowfish с 8-битным ключом, потому что твой SAES в libcrypto еще не добавили. Аргумент what может быть BF_ENCRYPT для шифрования и BF_DECRYPT для расшифровки. Эта функция может шифровать текст длинной только 1 байт.

Теперь выдолбим аналог 2SAES. Для демонстрации атак нам нужно только шифрование:

void
double_encrypt(uint8_t *dst, uint8_t *src, uint8_t key[2])
{
    cipher(BF_ENCRYPT, dst, src, key[0]);
    cipher(BF_ENCRYPT, dst, dst, key[1]);
}

То есть, берем 16-битный (2-байтный) ключ, шифруем текст первыми восемью битами, а результат шифруем вторыми восемью битами.

Приступим к атакам. Это нам пригодится:

/* Attacks */

const char report[]   = "Key: \"%c%c\"\tOperations: %d\n";
const char notfound[] = "No keys founds in %d operations\n";

Итак, брутфорс, простой перебор ключей:

/*
 * Bruteforce attack 
 */

void
bruteforce(uint8_t *plaintext, uint8_t *ciphertext)
{
    uint8_t buf1[8], buf2[8];
    int i, j, op = 0;

    for (i = 0; i < 256; i++) {
        cipher(BF_DECRYPT, buf1, ciphertext, i);
        for (j = 0; j < 256; j++) {
            ++op;
            cipher(BF_DECRYPT, buf2, buf1, j);
            if (memcmp(buf2, plaintext, 8) == 0) {
                printf(report, j, i, op);
                return;
            }
        }
    }
    printf(notfound, op);
}

Нам известны текст и шифротекст (например, мы знаем, что Алиса всегда начинает свои письма с фразы "Hello Bob"). Тупо подбираем первый и второй ключи, расшифровывая текст комбинациями и сравнивая его с оригинальным текстом. Если текст совпал, значит мы нашли ключи. Нам понадобится в худшем случае 65536 вариантов, чтобы найти правильные ключи.

А смотри как делается наша meet-in-the-middle атака. Нам нужно где-то хранить шифротексты -- известный текст, зашифрованный всеми возможными 8-битными ключами. Типа:

  • Ynfxr4hf => A
  • dfRYO1Hi => B
  • ...

и так со всеми 256 ключами.

Давай-ка возьмем OpenSSL-евскую хэш-таблицу, в которую запихаем 28 шифротекстов с соответствующими ключами.

/* 
 * Meet-in-the-middle attack 
 */

/* Hash table of encrypted texts mapped to all possible keys */
typedef struct {
    uint8_t enc[8]; /* encrypted text, hash table key */
    uint8_t key;    /* 8-bit encryption key */
} EK;

/* EK_hash works reliably only if long is 64 bits */
unsigned long EK_hash(const EK *v) { return *(unsigned long *)v->enc; }
static IMPLEMENT_LHASH_HASH_FN(EK_hash, const EK*);

int EK_cmp(const EK *v1, const EK *v2) { return memcmp(v1->enc, v2->enc, 8); }
static IMPLEMENT_LHASH_COMP_FN(EK_cmp, const EK*);

Ключом хэш-таблицы будет шифротекст, а значением -- 8-битный ключ шифрования, чтобы мы могли примерно так спрашивать нашу таблицу: "таблица-таблица, повернись ко мне передом, а к лесу задом, и скажи мне: если у меня есть шифротекст "бла-бла", то каким ключом это было зашифровано?"

Но для начала таблицу надо заполнить, для чего выдолбим такую функцию:

void
encrypt_all_keys(LHASH *h, EK items[], uint8_t *plaintext)
{
    int i;

    for (i = 0; i < 256; i++) {
        items[i].key = i;
        cipher(BF_ENCRYPT, items[i].enc, plaintext, i);
        lh_insert(h, &items[i]);
    }
}

Эта функция будет шифровать заданный текст всеми ключами от 0 до 255 поочередно, поворачивать таблицу к нам передом, а к лесу задом, и запихивать в нее получившиеся шифротексты и соответствующие им ключи.

Приступим непосредственно к атаке:

void
meetinthemiddle(uint8_t *plaintext, uint8_t *ciphertext)
{
    EK items[256], lookup, *found;
    LHASH *h;
    int i;

    if ((h = lh_new(LHASH_HASH_FN(EK_hash),
                    LHASH_COMP_FN(EK_cmp))) == NULL) {
        warn("hash table");
        return;
    }
    encrypt_all_keys(h, items, plaintext);

    for (i = 0; i < 256; i++) {
        cipher(BF_DECRYPT, lookup.enc, ciphertext, i);
        if ((found = lh_retrieve(h, &lookup)) != NULL) {
            printf(report, found->key, i, i+256);
            goto done;
        }
    }
    printf(notfound, i+256);
done:
    lh_free(h);
}

В этой функции мы создаем таблицу и заполняем ее, как описано выше на камне. После чего начинаем полу-брутфорсить: расшифровывать шифротекст всеми ключами от 0 до 255 и спрашивать таблицу, есть ли в ней соответствующий шифротекст с ключом. Если есть -- та-да-м! -- встретились посередине и нашли оба ключа.

(В отчете к i добавляется 256, потому что мы хотим посчитать количество операций, а при заполнении хэш-таблицы мы как раз сделали 256 операций.)

Чтобы проверить, как все это работает, давай выдолбим макрос, который будет измерять, сколько времени затрачивают атаки:

#define MEASURE(x) do {                                          \
    printf("%s\n", #x);                                          \
    clock_t t = clock(); (x);                                    \
    printf("%.3f sec\n\n", (clock()-t)/(double)CLOCKS_PER_SEC);  \
} while (0)

и main, в которой сначала запустим брутфорс, а потом meet-in-the-middle:

int
main()
{
    uint8_t plaintext[8] = "Dear Bob";
    uint8_t key[2] = "Go";
    uint8_t ciphertext[8];

    double_encrypt(ciphertext, plaintext, key);

    MEASURE( bruteforce(plaintext, ciphertext)      );
    MEASURE( meetinthemiddle(plaintext, ciphertext) );

    return 0;
}

Программа шифрует текст "Dear Bob" 16-битным ключом "Go" и запускает атаки, выводя найденный ключ.

Попробуем? Назовем камень, на котором мы выдалбливали код "meet.c", откомпилируем,

$ cc -lcrypto -o meet meet.c

и запустим:

$ ./meet

bruteforce(plaintext, ciphertext)
Key: "Go"       Operations: 28488
1.361 sec

meetinthemiddle(plaintext, ciphertext)
Key: "Go"       Operations: 367
0.018 sec

Йай! Брутфорс занял 1.4 секунды и 28488 операций, а наша крутая атака всего 0.018 секунды и 367 операций (и примерно 256*(8+8) = 4096 байт памяти)!

На этом Диффи с Хеллманом завели Делореан и улетели в будущее узнавать, как там поживают квантовые компьютеры, а в наше время археологи раскопали камень с выбитым кодом и выложили его на гитхаб:

Заодно перевели на современный язык:

Для алгоритмов шифрования с нормальным размером ключа такая атака, конечно, не очень практична. Например, чтобы сломать двойной Blowfish, как выше, но, скажем, с двумя 64-битными ключами, нужно 265 операций и 2 эксабайта памяти. Где столько найти-то? (Да и вообще, что за экса такая?) Но знать о такой штуке полезно. Например, 3DES, который делает EncryptK3(DecryptK2(EncryptK1(текст))), хоть и позволяет шифровать с тройным ключом (56*3 = 168 бит), но из-за meet-in-the-middle секьюрность у него 168-56 = 112 бит.

C'est la vie.

Коллаж сделан из фоток с википедии: 1 2 3.

Уважаемая ФСБ,

Microsoft сначала обещала передать вам алгоритмы шифрования, используемые в Skype, а потом опровергла это. Как же так?

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

Вот они:


С уважением,
Агент 000

P.S. Все, теперь можно расшифровывать все разговоры! Да? ДА???? ДАААА????

Май 2013

Пн Вт Ср Чт Пт Сб Вс
    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    

Архив по месяцам

Проектики

Mac diary

Mac journal software

Language Burger Games