i.MX7 CAAM  сопроцессор криптографии

Хоть документация на CAAM и закрыта под NDA (Nикому не DAвать), это вовсе не значит, что вы гадёныши не дай бог контрольную сумму посчитаете! Если бы вас хотели лишить этой функциональности, то просто не ставили бы CAAM
в камушек. А так, модуль есть. Деньги за него заплачены. Так какие тогда проблемы?

На самом деле, всё не так плохо. Секьюришные референсы на камни не настолько жёстко закрыты, как может показаться.
Их можно достать. А если вы захотите копнуть глубже, то вот совет: в линейке NXP есть сетевые контроллеры серии QorIQ.
Их отличие от i.MX только в том, что они Big Endian. А в остальном, это такой же ARM. И главное, модуль шифрования
у них практически 1:1 как во всей линейке i.MX. А секьюришные референсы открыты для свободного скачивания!
Всё то же самое, только расположение битов зеркальное! Берите и пользуйтесь!

Код ниже раскрывает высокоуровневый алгоритм работы с модулем криптографии CAAM.

Доступ к функциональности CAAM происходит через дескрипторы, небольшие командные файлы, состоящие
из набора 32-битных слов. Дескриптор описывает алгоритм, адрес размещения данных и их размер.

Сердцем модуля CAAM является контроллер DECO, принимающий дескриптор и выполняющий его. Всё, что нужно сделать, это положить дескриптор во входящий буфер DECO, запустить его на выполнение и дождаться завершения.
После того, как задача будет выполнена, вы можете забрать данные по адресу, который был указан в дескрипторе.

Дескрипторы ещё называют Job. И их можно объединять в Job Ring. Но эта функциональность не рассматривается.

CAAM - это мир среднего размера. Видно, что над ним трудился целый отдел, или цех,
который честно отбивал свою зарплату. Напихано под завязку.

Поэтому я не стал лезти во все эти дебри и вытащил на поверхность только самое необходимое - посчитать контрольные суммы, зашифровать-расшифровать данные. Получить RNG. Много ли для счастья нужно?

В реальности же, на основе знаний, заложенных в модуль CAAM, можно создавать научные труды по криптографии.

Для начала работы с модулем, его нужно затактировать и установить один бит в одном регистре.
Процедура инициализации описана в файле caam_init.asm. Очень просто.

	@ Затактировать CAAM
	MOV32 R0, CCM_BASE + CCGR36 @ CAAM clock gate
	SER R1 
	STR R1, [R0]

	MOV32 R0, CAAM_BASE

	@ Активировать ручное управление регистрами CAAM
	MOV R1, 1 << RQD
	STR R1, [R0, DECORR]

	@ Дождаться завершения активации
	1:
	LDR R1, [R0, DECORR]
	TST R1, 1 << DEN0
	BEQ 1b
	

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

Что бы выполнить дескриптор, передайте его адрес подпрограмме через R1:

	MOV32 R1, Адрес_дескриптора
	CALL Выполнить_дескриптор_DECO
	
После завершения работы DECO, можно проверить наличие ошибок.
Загляните в регистры D0OPSTA_MS и D0DDR и вы узнаете много нового.

	MOV32 R0, CAAM_CCB_BASE
	LDR R1, [R0, D0OPSTA_MS] @ Статус завершения операции
	LDR R2, [R0, D0DDR] @ Отладочная информация

	printf "D0OPSTA_MS: 0x%R1H\nD0DDR: 0x%R2H\n"
	
Регистр D0OPSTA_MS должен быть == 0. D0DDR обычно завершается значением 0x06000008.
Если значения регистров другие, значит в дескрипторе есть ошибки.

Примеры основных дескрипторов находятся в стартовом комплекте.


Что ещё можно сделать

Поразобравшись с дескрипторами, можно упростить и усложнить себе жизнь задачу одновременно.
Данные инкапсулируются в тело дескриптора, что бы сократить транзакции в ОЗУ.
Команда JUMP умеет тестировать биты и перескакивать на другие строки.
Можно объединять несколько дескрипторов в один.
Инкапсулировать счётчики и математические функции.

А когда всё надоест и заняться будет нечем, покопайтесь в мануале и освойте функциональность Job Ring.
В общем, обшифроваться и обсчитаться можно, до помутнения в мозгу!


Скоростные характеристики CAAM

@ Подсчёт контрольных сумм
MD5 = 128 МБ/сек
SHA1 = 79 МБ/сек
SHA256 = 95 МБ/сек

@ Шифрование
AES = 49 МБ/сек
3DES = 103 МБ/сек

@ Генерация True RNG
~~460.000 штук в секунду, независимо от размера.
Размер одного TRNG может быть от 8 до 64 байт.

@ Генерация одной аналоговой 512-битной энтропии
~~0.06 секунд, с настройками по умолчанию
Используется аналоговый генератор шума.
		


К сожалению, CAAM не поддерживает алгоритмы CRC.

Поэтому я написал небольшую программку, которой в большинстве случаев должно хватить.
А если переделать её на работу с таблицами, то скорость возрастёт.

Эта небольшая программа вычисляет любую известную CRC из описанных в википопии.
Максимальная разрядность вычислений 32 бита. 40 и 64 бит не поддерживаются.

	@ Заполните только эти 6 строк
	@ На основе данных в таблице из википедии
	@ Смотрите поля Width / Poly / Init / RefIn / RefOut / XorOut
	@ Возьмём пример для алгоритма CRC-8/MAXIM
	CRC_разрядность = 8 @ Width
	CRC_полином = 0x31 << (32 - CRC_разрядность) @ Poly
	CRC_начальный = 0 << (32 - CRC_разрядность) @ Init
	CRC_RefIn = 1 @ 1 = обратный порядок битов в байте (мл ... ст) (RefIn)
	CRC_RefOut = 1 @ 1 = обратный порядок битов перед финальным XOR (RefOut)
	XOR_на_выходе = 0 << (32 - CRC_разрядность) @ XorOut

	@ =====
	@ Хрум

	MOV32 R6, CRC_полином
	MOV32 R3, CRC_начальный
	MOV32 R4, crc_text @ Адрес начала текста
	MOV32 R10, crc_text_length @ Длина текста в !битах!

	1: @ Цикл по 32-битным словам
	LDR R0, [R4], 4 @ Взяли одно слово

	.if CRC_RefIn == 0
	REV R0, R0 @ Исправить обратный порядок байтов
	.else
	RBIT R0, R0 @ Обратный порядок битов
	.endif

	EOR R3, R3, R0 @ Присобачили в результат

		@ Обработать побитово
		MOV R9, 32 @ 32 бита в одном слове
		2:
		LSLS R3, 1 @ Выдвинуть в флаг переноса
		EORCS R3, R3, R6 @ Инвертировать полиномом, если C=1
		DEC R10 @ Счётчик битов в сообщении
		BEQ 3f @ Выйти если биты закончились
		DEC R9 @ Счётчик этого цикла
		BNE 2b @ Обработать следующий бит

	JMP 1b @ Обработать следующее слово

	3:

	.if CRC_RefOut == 1
	RBIT R3, R3 @ Инвертировать порядок битов перед финальным xor
	LSL R3, 32 - CRC_разрядность
	.endif

	@ XorOut
	MOV32 R1, XOR_на_выходе
	EOR R3, R3, R1

	LSR R3, 32 - CRC_разрядность @ Поставить результат на место

	@ Хрум
	@ =====


	@ Посмотрим что получилось
	printf "CRC-8/MAXIM: 0x%R3H\n" @ Должно быть 0x000000A1



	@ Тестовая строка из википедии
	.text 2
	.align 2, 0 @ С выравниванием быстрее
	crc_text: .ascii "123456789" @ Текст из википедии
	crc_text_length = (. - crc_text) * 8 @ Длина текста в битах
	.align 2, 0 @ Добить последнее слово нулями
	.text 0