Яuбy / Говнокод #21971 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
require 'aes'

message = "Super secret message"
key = "password"

encrypted = AES.encrypt(message, key)    # RZhMg/RzyTXK4QKOJDhGJg==$BYAvRONIsfKjX+uYiZ8TCsW7C2Ug9fH7cfRG9mbvx9o=
decrypted = AES.decrypt(encrypted, key)  # Super secret message

https://blog.elpassion.com/simple-and-terrifying-encryption-story-c1f1d6707c07#.lryae7h7b

Simple and Terrifying Encryption Story
I wanted to build an app where users can encrypt and decrypt messages.
...
I found an important bug and felt like it’s the right thing to do to share it.


Господи, как страшно жыть. Один мудак пишет шифрование, не зная разницы между ключём и паролем, второй толком не валидирует пользовательский инпут в либе для шифрования. Действительно, TERRIFYING STORY, BRO.

Запостил: roman-kashitsyn roman-kashitsyn, (Updated )

Комментарии (100) RSS

  • Я бы вообще принимал не строку, а какой-нить ByteArray. И он у меня умел бы создаваться fromHexString, хотя я не знаю философию руби. Может быть там так не принято.

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

      А вообще, пример поучителен и полезен. Бесед о потенциальных дырах никогда не бывает много.
      Ответить
  • Ничего не понял, но статический питух рулит.
    Ответить
    • да, будь тут стат тупизация -- такого бы не произошло скорее всего
      Ответить
      • Почему? Статичность типизации перестала играть роль ровно в тот момент, когда автор впервые запустил свой код.
        Ответить
        • Это если бы автор проверял типы)

          Просто в ЯП со стат типизацией никто не стал бы принимать ключ как String с hex-encoded.
          Ответить
          • Мне кажется, в сишочке в 90% случаев используют (char|void)* и int.
            Ответить
            • в сишечке -- да. Но сишечка на то и сишечка чтобы страд читать мануал, а не пихать строковой литерал туда где ожидается char *.

              А вот в жабе и .NET стопудово не так.

              Кстати, во многих криптолибах есть фреймворк для криптографии, и там вообще отдельно работать с AES не нужно.

              Ты говоришь примерно: ШифруйМеня(данные, ключ, провайдер=AES)
              И пофиг там AES или 3DES
              Ответить
              • С новым годом. Скажи, просвети идиота, чем разнится ** char и char * ??
                Ответить
                • char** это указатель на указатель на чар. Например чтобы сделать некое подобие двумертного массива байт, либо массива строк

                  char * это указатель на чар. Например чтобы сделать строку или одномерный массив байт.
                  Ответить
                  • Ясно. Ты говоришь о PPСhar и PChar.
                    @Указатель на указатель
                    Так его ж два раза придётся разыменовывать?
                    Первым разыменованием получаем адрес второго указателя, а вторым разыменованием создаём ссылку на память. Так?
                    Ответить
                  • Ещё char ** используют для возврата char* из функции. Примерно как var в паскале.
                    int test(char** out) {
                        *out = ...;
                    }
                    
                    char* p  = NULL;
                    int res = test(&p);
                    Ответить
                        • Выделить память самому, рассказать функции об адресе в памяти и предельном размере буфера, в ответ она вернет сколько памяти на самом деле пригодилось (или не хватило). Так все винапи работает, например.

                          Просто хороший тон (и единственно правильно в некоторых случаях) память освобождать там же, где и выделял.
                          Ответить
                          • > Выделить память самому
                            > Так все винапи работает
                            Попросить функцию оценить, сколько ей надо памяти, выделить память, позвать функцию ещё раз, обломаться, потому что условия изменились, реаллокнуть память. Плавали, знаем. Тьфублядь.
                            Ответить
                            • Как ты внешней либе подсунешь свой "аллокатор". Если она в дллке вообще будет, а дллку аля кернел какой нить в 100 щячел сношают, что будет спустя 1 месяц аптайма. "Дефрагментацияъ кучиъ". На всё есть причины
                              Ответить
                              • > подсунешь свой "аллокатор"
                                Некоторые либы позволяют. Но редко, да.

                                Твой способ, кстати, ещё рулит когда структура заранее известного и не плавающего размера - можно вообще кучу не лапать.

                                > На всё есть причины
                                +1. Оба способа имеют свои недостатки, достоинства и право на жизнь.
                                Ответить
                          • > память освобождать там же, где и выделял
                            Да, но описанный мной приём этому правилу не противоречит. И позволяет вернуть что-то посложнее и поинкапсулированнее, чем просто буфер (какую-нибудь древовидную структуру, к примеру).
                            int load_foo(foo** out);
                            void free_foo(foo* p);
                            Ответить
                          • > Так все винапи работает, например.

                            Мне кажется, приводить винапи как образец хорошего дизайна интерфейсов -- не самая удачная стратегия.
                            Ответить
                          • А если время жизни объекта мне не ведомо, а его знает только библиотечная функция?

                            Когда я его удалять буду?
                            Ответить
                            • > а его знает только библиотечная функция
                              То как ты вообще сможешь им пользоваться? Он же в любой момент может сдохнуть.

                              В таком случае тебе какие-нибудь AddRef и Release дадут.
                              Ответить
                              • >>В таком случае тебе какие-нибудь AddRef и Release дадут

                                Вот ты сам и ответил -- как)

                                попользовался -- сказал Release.

                                А он остался жив, пока его в соседнем треде через полтора часа не релизнут, и тогда он окончательно даст дуба.

                                Ref Counting, короче.
                                Ответить
  • > не зная разницы между ключём и паролем
    А какая разница?
    Ответить
    • Ключ можно использовать в алгоритме напрямую, а пароль -- нет. Потому что ключ достаточно криптостоек, а пароль нет.

      Отсюда вытекают их особенности:
      * Ключ обычно имеет фиксированную длину, жестко прописанную в алгоритме, и обычно она слишком большая чтобы человек вводил ее с клавиатуры. А пароль таких ограничений не имеет и напротив: должен быть доступен для ввода с клавиатуры.
      * Ключ может состоять из любых байт, а пароль это человекочитаемый текст, и в большинстве раскладок он не будет использовать, скажем, байт 0x1.
      * Пароль имеет смысл брудфорсить, а ключ нет.

      зы: полагаю что пароль можно превратить в некоторое подобие ключа, если сложить его со случайным числом и взять от этого хеш.
      Ответить
      • Как все это относится к задаче автора поста - шифровать сообщения по паролю?
        Ответить
        • Я не знаю что такое "шифровать сообщения по паролю".
          Возможно есть такая библиотека. Но AES не имеет понятия "пароль", и потому ожидает ключ.
          Ответить
          • > Я не знаю что такое "шифровать сообщения по паролю".
            Придираст!

            > полагаю что пароль можно превратить в некоторое подобие ключа, если сложить его со случайным числом и взять от этого хеш.
            Кстати, что обычно используют для выжимки пароля в ключ?
            Ответить
            • Обычно всё таки ключ генерируют на основе случайных чисел: датчиков проца, стучания пользователя по клавиатуре, мак адресов пролетающих на ethernet кадров итд.

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

              В ключ у AES, например, 192 байта. Это значит что десяти байт явно мало.
              Ответить
            • > для выжимки пароля в ключ
              PBKDF2, bcrypt, scrypt и т.п. Пыхомакаки - одну итерацию первого попавшегося хеша.
              Ответить
              • З.Ы. И пока ты не побежал писать код - полученный ключ не стоит юзать для шифрования данных. Им можно шифровать только ключи, сгенерённые криптостойким ГПСЧ.
                Ответить
                • Хотя... PKCS #5 утверждает, что можно и сразу данные. Но только 1 раз для каждого значения соли.
                  Ответить
                • Почему? Расшифровать данные, зашированные таким ключом, проще, чем подобрать пароль?
                  Ответить
                  • Большой риск залететь на переиспользование пары ключ-IV. Long-term симметричными ключами вообще не советуют данные шифровать, даже если они не из пароля сделаны.

                    З.Ы. Если как в PKCS #5 каждый раз делать новую соль - всё норм, ключ уже не long-term.
                    Ответить
                    • > Большой риск залететь на переиспользование пары ключ-IV.
                      Если у разных юзеров пароли совпадут? Или о чем речь?
                      Ответить
                      • > Или о чем речь?
                        Если ты юзаешь PBKDF(salt, password) напрямую как ключ (не меняя соль на каждое сообщение), то ты, по сути, юзаешь один ключ для всех данных. Такая схема очень чувствительна к выбору IV, особенно если шифр потоковый (аля AES в режиме CTR). Повторился IV - одинаковая пара (ключ, IV) - кровь-кишки (можно узнать инфу о плейнтексте не зная ключа).

                        Ещё есть ограничения на объём и количество сообщений, которые допустимо шифровать одним ключом. Ты не сможешь этот объём контролировать при такой схеме.

                        Поэтому проще сгенерить/породить новый ключ и не лезть на поле с граблями (хоть и теоретическими).
                        Ответить
                          • З.Ы. Я могу и заблуждаться, криптография она такая. Почитай какие-нибудь авторитетные источники и проверь.
                            Ответить
                • А что делать? Шифровать случайным ключом и прикладывать его в зашифрованном виде?
                  ENCRYPT(password, data) = concat(AES(PBKDF2(password), random_key), AES(random_key, data))
                  Ответить
                  • Ну да, схема примерно такая. Вроде ещё можно ключ породить как KDF(случайная_хуйня + PBKDF2(password)).

                    З.Ы. Надо ещё аутентификацию добавить, чтобы знать, что никто не помял сообщение по дороге. Ибо шифрование не спасает от изменения данных.
                    Ответить
                    • > аутентификацию добавить, чтобы знать, что никто не помял сообщение по дороге
                      Добавить к данным перед шифрованием их дайджест?
                      Ответить
                      • > Добавить к данным перед шифрованием их дайджест?
                        Нет. Это плохой, дырявый способ.

                        Много холиваров на эту тему было... Погугли на тему hash-than-encrypt, encrypt-than-mac и т.п.
                        Ответить
    • Автор поста не прочитал документацию к библиотеке и передал в функцию хуйню вместо ключа.
      Ответить
      • А автор библиотеки не выдал ошибку, а молча поюзал эту хуйню. Оба хороши.
        Ответить
  • @Один мудак пишет шифрование, не зная разницы между ключём и паролем,

    :-/
    Ответить
    • Стертор, а у вас в дельфях симметричное шифрование как реализовано?
      Ответить
      • Средствами VCL - никак, только сесть и самому написать.
        Ещё можно прибегнуть к Indy, там наверняка есть.
        Ответить
        • А у вас же там доступ к Win32Api нормальный, значит можно Crypto API
          Ответить
          • @Стертор, а у вас в дельфях симметричное шифрование как реализовано?
            @А у вас же там доступ к Win32Api нормальный, значит можно Crypto API

            Далеко пойдёшь.
            Ответить
            • А в чем проблема? Начиная с семерки там даже набор алгоритмов актуальный изкоробки.
              Ответить
              • Проблема в том, что Палочка с крючком сперва задаёт вопрос, потом сама же даёт исчерпывающий ответ. Вам это не кажется странным? Думаю, тут без инопланетного заговора не обошлось. Мы явно имеем дело с засланным марсианским шпионом.
                Ответить
  • Если заглянуть в ту либу, то(или хотя бы прочитать ту статью до конца), станет ясно, что весь хоррор этой истории заключается в том, что автор гема ожидает на вход encrypt/decrypt 32-символьный ключ, но не в виде массива байт, а в виде строки.

    P.S я не рубист
    Ответить
    • Truncating non-hex characters to zero seems like a valid design decision, albeit something the user should be made aware of.

      Ну да, чтобы всякие пробелы и т.п. убрать. Но посчитать то символы после этого можно было? 🙂
      Ответить
      • Эм, а зачем убирать пробелы? Если в ключе есть какие-то иные символы, кроме hex-символов, это же ошибка?
        Ответить
        • Ключ - это биты. Хекс - просто одна из форм записи этих битов, удобная для транспортировки. Можно и пробелами разбавить для красоты и удобства, просто получится другое представление того же ключа. Вай нот? Тем более рядом он тот же ключ в бейс64 таскает.

          З.Ы. Т.е. пробелы не в самом ключе, пробелы в одном из его текстовых представлений.
          Ответить
    • Там ещё и расшифровка из base64 поломана, походу. При шифровании IV и шифротекст склеены через $, а при расшифровке их разделить забыли.
      Ответить
    • # Generates a random seed value
      def _random_seed(size=32)
          if defined? OpenSSL::Random
              return OpenSSL::Random.random_bytes(size)
          else
              chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
              (1..size).collect{|a| chars[rand(chars.size)] }.join        
          end
      end
      Криптостойкий генератор случайных чисел. Блядь, как это развидеть... Лавры пхпшников переходят автору либы.
      Ответить
    • > But we just asked that to see how he thinks. We’re never going to let him implement crypto code anyways.
      Жиза. На собеседовании компьютерсайнс и паттерны проектирования, а на работе костыли и бойлерплейт на пхп.
      Ответить
  • Ставить какие-то криптобиблиотеки "от Васяна" это очень хуевая идея. Думаете что рубихипстеры, попивая смузи у себя в старбаксах за макбуками, будут задумываться над всякой там хуйней, вроде акустического криптоанализа https://www.opennet.ru/opennews/art.shtml?num=38689 ?
    Вот еще про side-channel атаки https://www.youtube.com/watch?v=fJCSYL9jc7Y
    Ответить
    • Ты так сказал, как будто это что-то плохое. Этот твой криптоанализ никому не нужен. В бизнесе главное прибыль, а не абсолютная безопасность или нулевой технический долг.
      Ответить
      • Вообще бизнесу даже код нахуй не нужен. Из чего следует, что мы все тут страдаем хуйнёй. Расходимся.
        Ответить
        • Все верно. Хочу только отметить, что программировать - это прикольно, а пилить костыли против тайминг атак и прочего говна - не прикольно.
          Ответить
          • пфф.. нельзя исключать тот факт, что могут быть люди, которым всё-таки прикольно пилить эти самые костыли.
            Ответить
            • Ну и пускай пилят, а не пиздят, что это что-то абсолютно важное и что если ты не задумался об акустическом криптоанале, то ты лох и рабихипстер.
              Ответить
              • > если ты не задумался об акустическом криптоанале, то ты лох и рабихипстер.
                Будешь это рассказывать своим клиентам, когда кулхацкеры похакают твой сайт (если он у тебя конечно есть) с ценной инфой из-за кривой самопальной криптографии
                Ответить
                • мне кажется сайт хипстера скорее похакают потому что он пароли плейн текстом хранит и SQL инъекшен имеет, а не потому что он уязвим для акустического криптоанализа
                  Ответить
    • >>акустического криптоанализа
      очень актуально когда твой сайт хостица на дижитал океане
      Ответить
      • > когда твой сайт хостица
        Угу, там актуальней side channel через обращение к кешу 🙂
        Ответить
        • проще дать суппортеру денег, имхо, чтобы он тебе пароль рута сбросил
          Ответить

Добавить комментарий

Помни, guest, за тобой могут следить!

    А не использовать ли нам bbcode?


    8