2016-11-14 14 views
2

При использовании адаптивных блоков APDU для Desfire для связи с картой, какие части команды и ответа должны использоваться для вычисления CMAC?Mifare Desfire Wrapped Mode: как рассчитать CMAC?

После успешной аутентификации, у меня есть следующий ключ сеанса:

Session Key: 7CCEBF73356F21C9191E87472F9D0EA2 

Затем, когда я отправить команду GetKeyVersion, карта возвращает следующий КЦР который я пытаюсь проверить:

<< 90 64 00 00 01 00 00 
>> 00 3376289145DA8C27 9100 

Я реализовал алгоритм CMAC в соответствии с «Специальной публикацией NIST 800-38B» и убедился, что это правильно. Но я не знаю, какие части APDU команды и ответа должны использоваться для вычисления CMAC.

Я использую TDES, поэтому MAC составляет 8 байт.

+0

Привет, Мохаммад, смогли ли вы это разрешить? Я столкнулся с той же проблемой ... – macbutch

+0

Нет, я еще не смог решить эту проблему. –

+0

Я думаю, что понял (см. Мой ответ). Большая проблема, с которой я столкнулся, заключается в том, что я неправильно вычислял сеансовый ключ. – macbutch

ответ

1

Я смотрел ту же самую проблему за последние несколько дней, и я думаю, что могу хотя бы дать вам несколько указателей. Получение всего «всего-навсего» заняло некоторое время, и документация от NXP (при условии, что у вас есть доступ) в некоторых случаях трудно интерпретировать.

Итак, как вы, вероятно, знаете, вам нужно рассчитать CMAC (и обновить ваш init vec) при передаче, а также получить. Вы должны сохранять CMAC каждый раз, когда вы вычисляете его как init vec для следующей криптографической операции (будь то CMAC или шифрование и т. Д.).

При вычислении CMAC для вашего примера данные для подачи в ваш алгоритм CMAC - это байт INS (0x64) и данные команды (0x00). Конечно, это будет дополнено и т. Д., Как указано CMAC. Обратите внимание, однако, что вы делаете не вычисляют CMAC по всей упаковке APDU (то есть 90 64 00 00 01 00 00) используется только байт INS и полезная нагрузка данных.

При получении вам необходимо взять данные (0x00) и второй байт статуса (также 0x00) и вычислить CMAC над этим. Это не важно в этом примере, но порядок здесь важен. Вы используете тело ответа (исключая CMAC), затем SW2.

Обратите внимание, что отправляется только половина CMAC - CMAC должен давать 16 байт, а карта отправляет первые 8 байтов.

Были несколько других вещей, которые держали меня в том числе:

  • Я вычислял ключ сеанса неправильно - это стоит дважды проверить это, если что-то не выходит, как и следовало ожидать
  • Я интерпретировал документацию, чтобы сказать, что вся структура APDU используется для вычисления CMAC (трудно читать их любым другим способом tbh)

Я все еще работаю над правильным вычислением ответа из команды Write Data. Команда выполнена успешно, но я не могу проверить CMAC. Я знаю, что Write Data не дополняется дополнением CMAC, а только нулями - еще не уверен, что еще я пропустил.

Наконец, вот реальный пример из общения с картой из моих журналов:

  1. аутентификация завершена (AES) и ключа сеанса определяется как F92E48F9A6C34722A90EA29CFA0C3D12; INIT VEC является нулями

  2. Я собираюсь отправить Get Key команду Version (как в вашем примере), так что я вычислить КЦР над 6400 и получить 1200551CA7E2F49514A1324B7E3428F1 (который теперь моя инициализация VEC для следующего расчета)

  3. Отправьте 90640000010000 на номер и получите 00C929939C467434A8 (статус 9100).

  4. Вычислить КЦР над 00 00 и получить C929939C467434A8A29AB2C40B977B83 (и обновление инициализации VEC для следующего расчета)

  5. Первая половина нашей КЦР от шага # 4 матча 8 байт, полученный с карты на этапе # 3

+0

Я использую TDES, поэтому MAC уже 8 байтов. В настоящее время моя проблема в том, что мой MAC и карта иногда совпадают, а иногда и не совпадают! –

+0

Хорошо, если вы делаете TDES, это не CMAC, как в вашем вопросе. Я не смотрел на это, но если карта отправляет MAC, я верю, что он отправит только первые 4 байта. По поводу этого иногда ошибочно ... да, я тоже это вижу. Это немного запутанно (и, похоже, не задокументировано). Одним из примеров является то, что даже после аутентификации, если вы отправляете команду GetVersion, вам не нужно обновлять CMAC на стороне отправки или получения. Я нашел некоторую странность и с WriteData (я не могу получить CMAC сразу после WriteData, хотя и не выкопал глубоко). – macbutch

+0

При использовании TDES MAC-адрес равен 8 байтам. –

0

Sry для моего английского языка, - его страшный :), но это не мой родной язык. Я русский.

Проверьте сначала MSB (7 бит) массива [0], а затем сдвиньте это налево. А затем XOR, если бит MSB 7 был равен 1; Или сохраните первый бит MSB бит [0] и после того, как shiffting поместите этот бит в конец массива [15] в конец (бит LSB).

Просто доказательство его здесь: https://www.nxp.com/docs/en/application-note/AN10922.pdf

Попробуйте так:

Нули < - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

SessionKey < - 00 01 02 03 E3 27 64 0C 0C 0D 0E 0F 5C 5D B9 D5

Данные < - 6F 80 00 00 00 00 00 00 00 0 0 0 00 00 00 00 00

Сначала вы должны зашифровать 16 байтов (нулей) с помощью SesionKey;

enc_aes_128_ecb(Zeros); 

И получить зашифрованные данные.

< EncryptedData - 3D 08 А2 49 D9 71 58 75 73 EA 18 F2 FA 6A 27 переменного тока

Проверить бит 7 [MSB - младший бит] из EncryptedData [0] == 1? переключить i в true;

bool i = false; 
    if (EncryptedData[0] & 0x80){ 
    i = true; 
    } 

Затем сделайте Shiffting всех EncryptedData 1 бит < <.

ShiftLeft(EncryptedData,16); 

И теперь, когда я == TRUE - XOR последний байт [15] с 0x87

if (i){ 
    ShiftedEncryptedData[15] ^= 0x87; 
    } 

7А 11 44 ​​93 В2 В1 Е2 Д4 Е.А. Е6 31 Е5 F4 D4 4F 58

Сохраните его как KEY_1.

Попробуйте бит 7 [MSB - LSB] ShiftedEncryptedData [0] == 1?

i = false; 
    if (ShiftedEncryptedData[0] & 0x80){ 
    i = true; 
    } 

Затем сделайте Shiffting всех ShiftedEncryptedData 1 бит < <.

ShiftLeft(ShiftedEncryptedData,16); 

И теперь, когда я == TRUE - XOR последний байт [15] с 0x87

if (i){ 
    ShiftedEncryptedData[15] ^= 0x87; 
} 

F4 22 89 27 65 63 С5 А9 Д5 CC 63 КБ Е9 A8 9E B0

Сохраните его как KEY_2.

Теперь мы принимаем наши данные (6F 80 00)

Как Майкл Сэя - команда коврик с 0x80 0x00 ...

XOR Данные с KEY_2 - если команда была заполнена, или KEY_1, если нет. Если у нас больше 16 байт (например, 32), вы должны XOR только последние 16 байт.

Затем зашифровать:

enc_aes_128_ecb(Data); 

Теперь у вас есть КЦР.

CD-С0 52 62 6D F6 60 CA 9В C1-09 FF EF 64 1A E3


Нули < - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

< SessionKey - 00 01 02 03 27 64 Е3 0C 0C 0D 0E 0F 5C 5D В9 Д5

Key_1 < - 7A 11 44 ​​93 В2 Е2 В1 Д4 Е.А. Е6 31 Е5 F4 D4 4F 58

Key_2 < - F4 22 89 27 65 С5 63 А9 Д5 CC 63 КБ Е9 A8 9E В0

данных < - 6F 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00

КЦР < - CD-С0 52 62 6D F6 60 CA 9В C1-09 FF EF 64 1A E3

C/C++ функция:

void ShiftLeft(byte *data, byte dataLen){ 
    for (int n = 0; n < dataLen - 1; n++) { 
    data[n] = ((data[n] << 1) | ((data[n+1] >> 7)&0x01)); 
    } 
    data[dataLen - 1] <<= 1; 
} 

Имейте хороший день :)

 Смежные вопросы

  • Нет связанных вопросов^_^