Как стать автором
Обновить

Подключение белорусской криптографии в Swift

Уровень сложностиПростой
Время на прочтение4 мин
Количество просмотров1.6K
bee2 + swift = bee2swift
bee2 + swift = bee2swift

Часто при разработке на языке 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(&params, "1.2.112.0.2.0.34.101.45.3.1")
print(params.l)

Для вывода обычного целого числа мы воспользовались функцией print. Для вывода больших чисел мы должны их представить в шестнадцатеричной форме и вывести через строковый буфер:

hexFrom(buf, &params.q, 32)
print(String(cString:sbuf))

Далее мы загружаем в переменную тестовое значение личного ключа и для проверки выводим соответствующее ему значение открытого ключа:

hexTo(privkey, "1F66B5B84B7339674533F0329C74F21834281FED0732429E0C79235FC273E269")
err = bignPubkeyCalc(pubkey, &params, 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, &params, der, count, hash, privkey, nil, 0)
hexFrom(buf, sig, 16*3)
print(String(cString:sbuf))

Для проверки подписи нужно использовать аналогичный набор параметров, но вместо личного ключа используется открытый. В результате выведется 0, если подпись корректная, или код ошибки.

err = bignVerify(&params, der, count, hash, sig, pubkey)
print(err)

В конце остается только освободить использованную пямять:

buf.deallocate()
privkey.deallocate()
pubkey.deallocate()
hash.deallocate()
der.deallocate()
sig.deallocate()

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

Теги:
Хабы:
+4
Комментарии3

Публикации

Работа

iOS разработчик
12 вакансий

Ближайшие события