В реализации AES Брайана Гладмана, как aes_encrypt_key128 отображается на aes_xi? - PullRequest
0 голосов
/ 16 февраля 2020

Я могу следовать пути кода до определенного момента. Кратко:

  1. Программа принимает шестнадцатеричную строку ASCII и преобразует ее в двоичную. https://github.com/BrianGladman/aes/blob/master/aesxam.c#L366 -L382
  2. Если arg[3] является «E», оно определяет структуру aes_encrypt_ctx и передает ключ, вычисленное значение key_len и aes_encrypt_ctx Stuct to aes_encrypt_key. https://github.com/BrianGladman/aes/blob/master/aesxam.c#L409 -L412
  3. aes_encrypt_key определено в aeskey.c. В зависимости от key_len вызывается функция aes_encrypt_key<NNN>. Они ключ и структура передаются в функцию. https://github.com/BrianGladman/aes/blob/master/aeskey.c#L545 -L547

Но где есть функция aes_encrypt_key128?

Эта строка появляется быть моим черникой :

#  define aes_xi(x) aes_ ## x

Так что, надеюсь, я на что-то. Это отображение aes_encrypt_key128 на aes_xi(encrypt_key128), верно?

AES_RETURN aes_xi(encrypt_key128)(const unsigned char *key, aes_encrypt_ctx cx[1])
{   uint32_t    ss[4];

    cx->ks[0] = ss[0] = word_in(key, 0);
    cx->ks[1] = ss[1] = word_in(key, 1);
    cx->ks[2] = ss[2] = word_in(key, 2);
    cx->ks[3] = ss[3] = word_in(key, 3);

#ifdef ENC_KS_UNROLL
    ke4(cx->ks, 0);  ke4(cx->ks, 1);
    ke4(cx->ks, 2);  ke4(cx->ks, 3);
    ke4(cx->ks, 4);  ke4(cx->ks, 5);
    ke4(cx->ks, 6);  ke4(cx->ks, 7);
    ke4(cx->ks, 8);
#else
    {   uint32_t i;
        for(i = 0; i < 9; ++i)
            ke4(cx->ks, i);
    }
#endif
    ke4(cx->ks, 9);
    cx->inf.l = 0;
    cx->inf.b[0] = 10 * AES_BLOCK_SIZE;

#ifdef USE_VIA_ACE_IF_PRESENT
    if(VIA_ACE_AVAILABLE)
        cx->inf.b[1] = 0xff;
#endif
    MARK_AS_ENCRYPTION_CTX(cx);
    return EXIT_SUCCESS;
}

Я вижу, что здесь происходит замена какого-то шаблона. Думаю, в этот момент мне стало интересно, не могли бы вы указать мне документы, которые объясняют эту особенность #define?

Ответы [ 2 ]

1 голос
/ 17 февраля 2020

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

  1. Стандарт C. На этом сайте вы можете загрузить WG14 N1570, который очень похож на стандарт C11 (это предварительный черновик, но в основном он такой же, как и стандарт, за исключением того, что вам не нужно за него платить. ) Существует версия HTML этого документа в http://port70.net/~nsz/c/c11/n1570.html, которая удобна для построения ссылок. Имея это в виду, я могу указать вам фактическое стандартное определение ## в §6.10.3.3 стандарта.

  2. Стандарт C может быть немного грубо, если вы еще не являетесь экспертом в C. Это делает очень мало уступок для учащихся. Более читаемым документом является руководство Gnu G CC C препроцессора (CPP) , хотя оно не всегда различает guish между стандартными функциями и G CC расширения. Тем не менее, он довольно читабелен и содержит много полезной информации. Оператор ## описан в Глава 3.5

  3. cppreference.com более известен как справочный сайт C ++, но он также содержит документация о C. Его язык почти такой же телеграфный c, как и стандарты C ++ / C, и он не всегда точен на 100% (хотя и очень хорош), но имеет ряд преимуществ. С одной стороны, он объединяет документацию для разных стандартных версий, поэтому он действительно полезен для определения, когда функция вошла в язык (и, следовательно, какая версия компилятора вам понадобится для использования этой функции). Кроме того, он хорошо сшит, поэтому очень легко ориентироваться. Вот что он говорит о препроцессоре ; документацию о ## вы найдете здесь .

0 голосов
/ 16 февраля 2020

Я давно этим занимался, но мне стало ясно, что в макросах предварительной обработки файла aeskey.c происходит сопоставление с образцом. Единственное, что мне удалось найти c, это это .

Pattern Matching

Оператор ## используется для объединения двух токены в один токен. Это обеспечивает очень мощный способ сопоставления с образцом. Скажем, мы хотим написать макрос IIF, мы могли бы написать его так:

#define IIF(cond) IIF_ ## cond
#define IIF_0(t, f) f
#define IIF_1(t, f) t

Однако в этом подходе есть одна проблема. Тонкий побочный эффект оператора ## заключается в том, что он запрещает расширение. Вот пример:

#define A() 1
//This correctly expands to true
IIF(1)(true, false)
// This will however expand to
IIF_A()(true, false)
// This is because A() doesn't expand to 1,
// because its inhibited by the ## operator
IIF(A())(true, false) 

Чтобы обойти это, используйте другое косвенное обращение. Поскольку это обычно делается, мы можем написать макрос под названием CAT, который будет объединяться без блокировки.

#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__

Итак, теперь мы можем написать макрос IIF (его сейчас называют IIF, позже мы покажет, как определить более обобщенный способ определения макроса IF):

#define IIF(c) PRIMITIVE_CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t

#define A() 1
//This correctly expands to true
IIF(1)(true, false)
// And this will also now correctly expand to true
IIF(A())(true, false) 

При сопоставлении с образцом мы можем определить другие операции, такие как COMPL, который принимает дополнение:

#define COMPL(b) PRIMITIVE_CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0

или BITAND:

#define BITAND(x) PRIMITIVE_CAT(BITAND_, x)
#define BITAND_0(y) 0
#define BITAND_1(y) y

Мы можем определить операторы увеличения и уменьшения как макросы:

#define INC(x) PRIMITIVE_CAT(INC_, x)
#define INC_0 1
#define INC_1 2
#define INC_2 3
#define INC_3 4
#define INC_4 5
#define INC_5 6
#define INC_6 7
#define INC_7 8
#define INC_8 9
#define INC_9 9

#define DEC(x) PRIMITIVE_CAT(DEC_, x)
#define DEC_0 0
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define DEC_6 5
#define DEC_7 6
#define DEC_8 7
#define DEC_9 8
...