1. Ruby / Говнокод #21971

    −96

    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, 13 Января 2017

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

    • #SEO #Криптография #СамыйЛучшийЯзыкИзЯпонии
      Ответить
    • Я бы вообще принимал не строку, а какой-нить 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

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

      P.S я не рубист
      Ответить
    • team lead senior developer, как всегда
      Ответить
      • Ну хоть не ниндзя-евангелист, как любят сейчас писать хипстеры.
        Ответить
        • боже, неужели и тебя пересекло с великой вебстудией uprock?
          Ответить
    • https://github.com/chicks/aes/issues/5
      Ответить
      • The keys being generated are only HALF as long as they need to be.
        Ответить
      • 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
        Криптостойкий генератор случайных чисел. Блядь, как это развидеть... Лавры пхпшников переходят автору либы.
        Ответить
    • Ну на реддите правильно ответили "если вам пришлось набирать в коде A-E-S, значит вы делаете что-то очень не то" https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2009/july/if-youre-typing-the-letters-a-e-s-into-your-code-youre-doing-it-wrong/
      Ответить
      • > But we just asked that to see how he thinks. We’re never going to let him implement crypto code anyways.
        Жиза. На собеседовании компьютерсайнс и паттерны проектирования, а на работе костыли и бойлерплейт на пхп.
        Ответить
      • Mike vomits onto the floor.
        Ответить
    • Ставить какие-то криптобиблиотеки "от Васяна" это очень хуевая идея. Думаете что рубихипстеры, попивая смузи у себя в старбаксах за макбуками, будут задумываться над всякой там хуйней, вроде акустического криптоанализа https://www.opennet.ru/opennews/art.shtml?num=38689 ?
      Вот еще про side-channel атаки https://www.youtube.com/watch?v=fJCSYL9jc7Y
      Ответить
      • Ты так сказал, как будто это что-то плохое. Этот твой криптоанализ никому не нужен. В бизнесе главное прибыль, а не абсолютная безопасность или нулевой технический долг.
        Ответить
        • > В бизнесе главное прибыль
          +1. Кого ебут эти side channel'ы, когда даже шифр цезаря с одним ключём на всех железках приносит профит:

          http://cybergibbons.com/security-2/csl-dualcom-cs2300-signalling-unit-vulnerabilities/
          Ответить
        • Вообще бизнесу даже код нахуй не нужен. Из чего следует, что мы все тут страдаем хуйнёй. Расходимся.
          Ответить
          • Все верно. Хочу только отметить, что программировать - это прикольно, а пилить костыли против тайминг атак и прочего говна - не прикольно.
            Ответить
            • пфф.. нельзя исключать тот факт, что могут быть люди, которым всё-таки прикольно пилить эти самые костыли.
              Ответить
              • Ну и пускай пилят, а не пиздят, что это что-то абсолютно важное и что если ты не задумался об акустическом криптоанале, то ты лох и рабихипстер.
                Ответить
                • > если ты не задумался об акустическом криптоанале, то ты лох и рабихипстер.
                  Будешь это рассказывать своим клиентам, когда кулхацкеры похакают твой сайт (если он у тебя конечно есть) с ценной инфой из-за кривой самопальной криптографии
                  Ответить
                  • мне кажется сайт хипстера скорее похакают потому что он пароли плейн текстом хранит и SQL инъекшен имеет, а не потому что он уязвим для акустического криптоанализа
                    Ответить
      • > side-channel
        Или padding oracle.
        Ответить
      • >>акустического криптоанализа
        очень актуально когда твой сайт хостица на дижитал океане
        Ответить
        • > когда твой сайт хостица
          Угу, там актуальней side channel через обращение к кешу :)
          Ответить
          • проще дать суппортеру денег, имхо, чтобы он тебе пароль рута сбросил
            Ответить

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