Часто при разработке на языке Swift мы сталкиваемся с отсутствием необходимых инструментов, которые давно стали привычными в других языках. В частности, чувствуется нехватка криптографических инструментов с хорошей историей и репутацией. В таком случае нам приходит на помощь возможность подключать и использовать в Swift библиотеки, написанные на языках Си и С++.
Библиотека bee2 является референсной имплементацией криптографических алгоритмов, стандартизированных в Республике Беларусь. Она написана на Си и распространяется под свободной лицензией Apache License, Version 2.0. B сообществе bcrypto разрабатывается набор инструментов криптографической инфрастуктуры, в основе которых лежит библиотека bee2. Там же возникла идея сделать доступным и удобным использование этой библиотеки на максимально возможном количестве платформ и языков программирования. Начало было положено в 2017 году с разработки библиотеки bee2j, которая позволяет не только вызывать функции bee2, но и встраивает их в криптографическую подсистему JCA (Java Cryptography Architecture) языка Java. Ниже я покажу, как подключить и использовать библиотеку bee2 в программах на языке Swift.
Поскольку одной из целей является покрытие максимального количества платформ, я не буду описывать привычную для Swift-программистов среду разработки XCode. Для создания примера вполне достаточно встроенной в язык системы управления пакетами, доступной везде, где поддерживается язык Swift (Linux, Windows и платформы Apple). Также предполагается, что библиотека bee2 установлена в систему, как описано в руководстве.
Для начала создадим пустой проект:
mkdir bee2swift cd bee2swift swift package init --type=executable
Далее в каталоге Sources проекта создадим каталог для модуля библиотеки:
cd Sources mkdir bee2
Также Swift требует отдельных каталогов для каждого модуля, если их больше одного. Поэтому нужно переместить основной файл программы в отдельный каталог:
mkdir bee2swift mv main.swift bee2swift/
Затем в каталоге bee2 создаём два файла: заголовочный файл библиотеки bee2swift.h и описание модуля module.modulemap. В заголовочный файл включаем минимальное количество заголовочных файлов, необходимых для реализации примера выработки электронной цифровой подписи (ЭЦП).
#include "bee2/core/safe.h" #include "bee2/core/mem.h" #include "bee2/core/hex.h" #include "bee2/crypto/belt.h" #include "bee2/crypto/bign.h"
В описании модуля указываем созданный заголовочный файл и ссылку на библиотеку:
module bee2 { umbrella header "bee2swift.h" link "/usr/local/lib/libbee2_static.a" }
Для подключения библиотеки в проект нужно добавить в файл Package.swift объявление библиотеки и подключение зависимости для исполняемого файла:
targets: [ .systemLibrary(name: "bee2"), .executableTarget( name: "bee2swift", dependencies: ["bee2"]), ]
Подготовка закончена, теперь можно перейти к программе на языке Swift. Для этого добавим в программу импорт модуля и вызов функции из него:
import bee2 print(beltHash_keep())
Теперь можно проверить, что библиотека собирается и программа запускается. Для этого в каталоге проекта выполняем команды:
swift build swift run
Для выработки ЭЦП необходимо выделить неуправляемую память под все данные, которые используются в функциях библиотеки:
let privkey = UnsafeMutableRawPointer.allocate(byteCount: 64, alignment: 4) let pubkey = UnsafeMutableRawPointer.allocate(byteCount: 128, alignment: 4) let hash = UnsafeMutableRawPointer.allocate(byteCount: 64, alignment: 4) let der = UnsafeMutableRawPointer.allocate(byteCount: 512, alignment: 4) let sig = UnsafeMutableRawPointer.allocate(byteCount: 64+32, alignment: 4)
Также понадобится строковый буфер для вывода информации на экран. Для него мы делаем привязку к массиву символов. Подробнее об этом я писал в посте.
let buf = UnsafeMutableRawPointer.allocate(byteCount: 128, alignment: 4) let sbuf = buf.bindMemory(to:CChar.self, capacity:128)
Для структур языка Си Свифт создаёт классы. Ниже мы создаем экземпляр класса параметров и заполняем его значениями параметров стандартизованной кривой
bign-curve128v1:
var params = bign_params() var err = bignParamsStd(¶ms, "1.2.112.0.2.0.34.101.45.3.1") print(params.l)
Для вывода обычного целого числа мы воспользовались функцией print. Для вывода больших чисел мы должны их представить в шестнадцатеричной форме и вывести через строковый буфер:
hexFrom(buf, ¶ms.q, 32) print(String(cString:sbuf))
Далее мы загружаем в переменную тестовое значение личного ключа и для проверки выводим соответствующее ему значение открытого ключа:
hexTo(privkey, "1F66B5B84B7339674533F0329C74F21834281FED0732429E0C79235FC273E269") err = bignPubkeyCalc(pubkey, ¶ms, privkey) hexFrom(buf, pubkey, 64) print(String(cString:sbuf))
Для тестирования ЭЦП используется встроенный в библиотеку набор данных, указатель на которые возвращает функция beltH. От этих данных вырабатывается хэш-значение, которое и будет подписываться.
let src = beltH() err = beltHash(hash, src, 13) hexFrom(buf, hash, 64) print(String(cString:sbuf))
Для выработки ЭЦП также необходимо передать значение идентификатора использованного алгоритма хэширования в DER-кодировке:
var count: Int = 512 bignOidToDER(der, &count, "1.2.112.0.2.0.34.101.31.81") print(count)
В предыдущей функции длина DER-кода запишется в переменную count. Для целочисленных переменных, которые передаются в функции языка Си как параметры, необходимо явно указывать тип переменной.
Теперь всё готово к выработке ЭЦП. Здесь для простоты мы используем детерминированную ЭЦП из СТБ 34.101.45:
err = bignSign2(sig, ¶ms, der, count, hash, privkey, nil, 0) hexFrom(buf, sig, 16*3) print(String(cString:sbuf))
Для проверки подписи нужно использовать аналогичный набор параметров, но вместо личного ключа используется открытый. В результате выведется 0, если подпись корректная, или код ошибки.
err = bignVerify(¶ms, der, count, hash, sig, pubkey) print(err)
В конце остается только освободить использованную пямять:
buf.deallocate() privkey.deallocate() pubkey.deallocate() hash.deallocate() der.deallocate() sig.deallocate()
Полный код проекта доступен в репозитории. Надеюсь, что этот пример не только поможет подключать библиотеки в Swift, но и расширить область применения криптографии для увеличения безопасности ваших программ и данных.
ссылка на оригинал статьи https://habr.com/ru/articles/911266/
Добавить комментарий