Недосвідчений вилучення пароля [закрито]


33

У дусі конкурсу Underhanded C я розпочинаю конкурс Underhanded Code. Мета цього конкурсу полягає в тому, щоб прямо реалізувати якийсь код, при цьому тонко приховавши в ньому нечестивий помилку.

Конкурс

Ви таємний російський крот, який працює в ІТ-відділі американського шпигунського агентства. Ваш американський бос щойно попросив вас застосувати алгоритм збору паролів, який слід використовувати для шифрування секретних повідомлень.

Ваш начальник хоче, щоб ви реалізували таку функцію:

f: String -> byte[16]

який перетворює пароль на 16-байтну кількість, придатну для використання в якості ключа AES. Ваш начальник хоче захищену функцію, що в цьому контексті означає, що різні рядки паролів повинні створювати різні результати з величезною ймовірністю. Наприклад, повернення хеду md5 введення було б простою реалізацією f.

Звичайно, ваш справжній начальник у російському шпигунському агентстві хотів би, щоб ви підривали цей процес. Ваше завдання полягає в тому, щоб реалізувати fтак, щоб росіяни могли розшифрувати всі секретні повідомлення, зашифровані за допомогою повернених ключів f.

Для цього потрібно здійснити fтак, щоб він повертав лише невелику підмножину з 2 ^ 128 можливих виходів. Зокрема, ви fповинні повернути щонайменше 2 ^ 16 різних результатів, щоб росіяни могли легко здійснити грубу силу пошуку правильного ключа для кожного зашифрованого повідомлення, яке вони хочуть розшифрувати.

Майте на увазі, що шпигунство несе смертну кару. Щоб не попастися, ваша функція fповинна генерувати принаймні 2 ^ 8 різних результатів, так що короткий огляд кількох результатів fнавряд чи виявить дублікат. І найголовніше, що код, який ви вводите для обмеження кола, fповинен виглядати ненавмисно, а не навмисно. Якщо вас коли-небудь забирають у залу суду, має бути певне розумне сумнів у тому, чи ви ввели помилку навмисно чи випадково.

Судження

Я та двоє інших, яких я набираю, будуть судити про записи (надішліть мені електронне повідомлення, якщо ви хочете судити). Я пропоную 200 виграшних репутацій за виграшну заявку. Заявки потрібно завантажити до 1 травня.

Судячи з урахуванням наступних критеріїв:

  • Чи fдотримується специфікацію, тобто створює між 2 ^ 8 і 2 ^ 16 можливих виходів. Не відчувайте, що це жорсткі межі, але ми вирахуємо бали, якщо ви занадто далеко за межами діапазону.
  • Чи правдоподібно помилка є наслідком ненавмисної помилки?
  • Чи результати fвиглядають випадковими?
  • Чим коротше ваша реалізація f, тим краще.
  • Чим чіткіше ваша реалізація f, тим краще.

Примітки

Ви можете використовувати будь-яку мову для реалізації свого коду. Ви намагаєтесь приховати помилку на очах, тому не заперечений код не пропонується.

Можливо, ви захочете поглянути на деяких попередніх переможців конкурсу Underhanded C, щоб отримати уявлення про те, що добре подає заяву.

Рядки введення будуть друкуватися ascii (від 32 до 126, включно). Ви можете припустити розумну максимальну довжину, якщо хочете.


1
чи є обмеження на вхідний рядок? як, що складається лише з алфавіту?
Ali1S232

@Gajet: ви повинні працювати з усіма друкованими символами ascii (від 32 до 126, включно).
Кіт Рендалл

Чи є вихідний діапазон для всіх 16-байтових рядків або лише для друку?
виставка

@boothby: усі можливі 16-байтові значення (2 ^ 128 можливості)
Кіт Рандалл

1
Я голосую за те, щоб закрити це питання як позатематичне, тому що недостатньо важкі виклики вже не є актуальними на цьому веб-сайті. meta.codegolf.stackexchange.com/a/8326/20469
кіт

Відповіді:


15

С

2 ^ 16 можливих виходів (або в 2 ^ 8 разів більше використаних символів).
Використовується реалізація MD5 для Linux, що є, AFAIK, чудовим. Але це дає той самий хеш, наприклад, для "40" та "42".
EDIT: Перейменовано bcopyна memcpy(змінено параметри, звичайно).
EDIT: Перетворюється з програми на функцію, щоб краще відповідати вимогам.

#include <string.h>
#include <openssl/md5.h>

void f(const unsigned char *input, unsigned char output[16]) {

    /* Put the input in a 32-byte buffer, padded with zeros. */
    unsigned char workbuf[32] = {0};
    strncpy(workbuf, input, sizeof(workbuf));

    unsigned char res[MD5_DIGEST_LENGTH];
    MD5(workbuf, sizeof(workbuf), res);

    /* NOTE: MD5 has known weaknesses, so using it isn't 100% secure.
     * To compensate, prefix the input buffer with its own MD5, and hash again. */
    memcpy(workbuf+1, workbuf, sizeof(workbuf)-1);
    workbuf[0] = res[0];
    MD5(workbuf, sizeof(workbuf), res);

    /* Copy the result to the output buffer */
    memcpy(output, res, 16);
}

/* Some operating systems don't have memcpy(), so include a simple implementation */
void *
memcpy(void *_dest, const void *_src, size_t n)
{
    const unsigned char *src = _src;
    unsigned char *dest = _dest;
    while (n--) *dest++ = *src++;
    return _dest;
}

це вада з MD5?
Ali1S232

@Gajet, Ні, я використовував MD5 Linux Linux, що цілком нормально (AFAIK).
угорен

чому вони не генерують більше можливих результатів?
Ali1S232

1
@Gajet: Поміркуйте, що відбувається на bcopyкроці ... це приємний біг помилок , оскільки фактична bcopyфункція BSD тут нормально працюватиме.
хан

@han, насправді я зараз бачу, що моя bcopyбаггі. Я зміню його на memcpy, і тоді така сама реалізація набуде чинності.
угорен

13

С

Це може бути не найяскравішим конкурсом, але я думаю, що наступне - це така хеш-функція, яку міг би зробити будь-який кодер занадто розумним для власного блага, з невиразним уявленням про те, які операції ви бачите в хеш-функціях:

#include <stdio.h>
#include <string.h>
#include <stdint.h>

void hash(const char* s, uint8_t* r, size_t n)
{
     uint32_t h = 123456789UL;
     for (size_t i = 0; i < n; i++) {
          for (const char* p = s; *p; p++) {
               h = h * 33 + *p;
          }
          *r++ = (h >> 3) & 0xff;
          h = h ^ 987654321UL;
     }
}

int main()
{
     size_t n = 1024;
     char s[n];
     size_t m = 16;
     uint8_t b[m];
     while (fgets(s, n, stdin)) {
          hash(s, b, m);
          for (size_t i = 0; i < m; ++i)
               printf("%02x", b[i]);
          printf("\n");
     }
}

Насправді хеш-функція може повертати не більше L * 2048 різних результатів, де L - кількість різних довжин вхідних рядків. На практиці я перевірив код на 1,85 мільйона унікальних рядків введення з сторінок вручну та html-документів на своєму ноутбуці, і отримав лише 85428 різних унікальних хешей.


0

Scala:

// smaller values for more easy tests:
val len = 16
// make a 16 bytes fingerprint
def to16Bytes (l: BigInt, pos: Int=len) : List[Byte] = 
  if (pos == 1) List (l.toByte) else (l % 256L).toByte :: to16Bytes (l / 256L, pos-1)
/** if number isn't prime, take next */
def nextProbPrime (l: BigInt) : BigInt = 
  if (l.isProbablePrime (9)) l else nextProbPrime (l + 1)
/** Take every input, shift and add, but take primes */
def codify (s: String): BigInt = 
  (BigInt (17) /: s) ((a, b) => nextProbPrime (a * BigInt (257) + b))
/** very, very short Strings - less than 14 bytes - have to be filled, to obscure them a bit: */
def f (s: String) : Array [Byte] = {
  val filled = (if (s.size < 14) s + "secret" + s else s)
  to16Bytes (codify (filled + filled.reverse)).toArray.map (l => nextProbPrime (l).toByte) 
}

Тестуйте, якщо результат не схожий на аналогічне введення:

val samples = List ("a", "aa", "b", "", "longer example", "This is a foolish, fishy test") 

samples.map (f) 

 List[Array[Byte]] = List(
Array (-41, -113, -79, 127, 29, 127, 31, 67, -19, 83, -73, -31, -101, -113, 97, -113), 
Array (-19, 7, -43, 89, -97, -113, 47, -53, -113, -127, -31, -113, -67, -23, 127, 127), 
Array (-41, -113, -79, 127, 29, 127, 31, 67, -19, 83, -73, -31, -101, -113, 97, -113), 
Array (37, -19, -7, 67, -83, 89, 59, -11, -23, -47, 97, 83, 19, 2, 2, 2), 
Array (79, 101, -47, -103, 47, -13, 29, -37, -83, -3, -37, 59, 127, 97, -43, -43), 
Array (37, 53, -43, -73, -67, 5, 11, -89, -37, -103, 107, 97, 37, -71, 59, 67))

Помилка полягає у використанні просто кодування для кодування. Замість

scala> math.pow (256, 16)
res5: Double = 3.4028236692093846E38

цінностей, на яких ми закінчуємо

scala> math.pow (54, 16)
res6: Double = 5.227573613485917E27

оскільки тут є 54 прайми нижче 256.


2
5.22e27 >> 2^16. Немає жодного способу насильницької сили з великими можливостями.
Кіт Рендалл

ви забули назву мови
ajax333221

@ ajax333221: Scala. Я додав його до верху.
користувачеві невідомо

@KeithRandall: Я "випадково" міг використовувати лише позитивні байти, що зменшило б можливості math.pow (27, 16), але це все ще приблизно 8e22.
користувач невідомий
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.