В
4eed9f47294d277e84f8ba1451b1b4ced04a09de упоминал, что начал делать
аналог CMS EnvelopedData контейнера. Всё уже настолько устаканилось, что
бОльшую часть всего перешифровал в cm/encrypted контейнеры.
Изначально у меня вовсю использовались слова типа "pki" и сертификаты.
Выпилил любое упоминание PKI, решив назвать все эти криптографические
форматы "cm"-ом -- cryptographic messages. И коротко и не пересекается с
чем-то другим распространённым. Сертификаты заменил просто на публичные
ключи. У которых, как и в случае с PGP, могут быть подписи, не без этого.
ChaPoly шифрование распараллелил, аналогично как делал в реализации на
основе деревьев Меркла (
f77b37849893c17724125acc62916d01521e363d). Всё
равно до сих пор не понимаю где затык, но утилизировать все ядра не
выходит -- 2.5+GiB/sec потолок, хотя он достигается на 3-4 потоках
шифрования уже, половина ядер остаются у меня не использованными.
Чтобы рандомизировать шифрование, на всякий пожарный, решил nonce для
ChaPoly делать не просто счётчиком, но подмешивать в него неизвестное
злоумышленнику значение, как это делается в TLS 1.3.
Причесал работу с HKDF-ом, ибо где-то его Extract шаг не нужен, где-то
нужен. В целом зоопарк стал более упрощённым. ChaPoly для DEM-а не
отличается теперь от ChaPoly применяемом в KEM-ах (для key wrapping).
Доработал утилиты cmkeytool, cmenctool, cmsigtool, cmhshtool для более
удобной интерактивной работы с человеком. Собственно, их и применяю уже
для своих нужд, радуясь огромной скорости работы без бутылочного
горлышка в виде одного ядра.
Обнаружил, что вообще нет ни BLAKE3 реализаций на Си, ни BLAKE2
распараллеленных. Ни ChaPoly распараллеленного не смог найти (возможно
оно только в составе более сложного софта). Такое впечатление, что
распараллеливание толком никому не нужно и все удовлетворяются
скоростями на одном ядре. Но ChaPoly у меня даже до GiB/sec не
дотягивает. Аппаратно ускоренный AES-OCB в GnuPG вроде тоже что-то около
GiB/sec был, как и BLAKE2b. Это конечно относительно не мало, но всё же
SSD диски во много раз быстрее, как и суммарная производительность всех
ядер процессора. Понимаю что parallel код сложнее устроен, но он же
стоит того. А вот нифига свободных и открытых реализаций не видно, кроме
как на Rust попадаются.
Добавил возможность шифровать приватные ключи тем же самым cm/encrypted
контейнером но с применением KEM-а на основе парольной фразы. И
прозрачно использовать такие ключи при дешифровании. Типа весь основной
функционал age повторил удобный.
А ещё в KEKS появился новый тип данных: MAGIC. 16-байтная строчка
начинающаяся с "KEKS". "K" является тэгом, не используемый прежде
codepoint. 12 байт произвольных данных можно засунуть в неё.
Предполагается, что MAGIC будет просто добавляться в начало файла, чтобы
хоть как-то намекать на используемый в нём тип данных. Ведь ни в ASN.1,
ни в JSON невозможно это легко и просто понять. В ASN.1 любят делать
контейнеры типа {"type": "SignedData", "data": ...}, но с этим не очень
удобно работать если хочется делать аналог json.Unmarshal -- оно всё
загрузит в память. А MAGIC можно потоково декодировать просто как один
единственный KEKS-атом, а дальше продолжить чтение из io.Reader.
И для удобства использования и в cm/signed и в cm/encrypted применяется
BLOB вне основной структуры. В случае с cm/signed:
MAGIC(cm/signed) || cm-signed-prehash || BLOB(detached-data) || cm-signed
и подписывается:
[detached-data] || /load || sig-tbs
всё это позволяет не делать потоковое декодирование данных, а частями
засовывать в io.Reader/hash.Hash и подобные. KEKS позволяет потоково
работать, как и сама Go реализация, но это не так удобно и просто как
сделать .Unmarshal. В случае с cm/encrypted:
MAGIC(cm/encrypted) || cm-encrypted || BLOB(encrypted-data)
Для себя применяю (
d0120e47839413c5e3a04c9c6e31bab5f3996de9) Classic
McEliece в качестве KEM-а (не считая Balloon-BLAKE2b для шифрования по
парольной фразе).
А ещё обнаружил, что в http://libpqcrypto.org/command.html софте от DJB
вовсю используются не только stdout файловые дескрипторы. В моём
cmenctool я один из таких дополнительных "файлов" использовал для вывода
bind значения (сейчас его не стало). А в libpqcrypto они вообще
используются вовсю для передачи и приватных и публичных ключей. Чем
дальше, тем больше у меня появляется схожих идей и ещё больше одобрения
того как делается DJB софт.