1 个不稳定版本

0.1.0 2023年11月22日

#1191 in 密码学

Apache-2.0

3MB
60K SLoC

C 30K SLoC // 0.1% comments C++ 26K SLoC // 0.1% comments Rust 3K SLoC // 0.1% comments Forge Config 301 SLoC // 0.9% comments Shell 22 SLoC // 0.3% comments

SecApi Rust绑定

此仓库包含SecAPI的Rust绑定。此仓库中有两个不同的crate

  1. secapi-sys:使用原始的C绑定作为FFI(Foreign Function Interface)。必须与用户链接的SecAPI版本二进制兼容。由于Rust不能读取头文件(就像C和C++可以共享相同的头文件一样),我们需要让Rust知道当我们将它链接到C/C++编译的库时,它可以期望什么数据类型和函数接口。使用#[repr(C)]宏确保所有数据类型都与它们的C/C++对应类型具有相同的内存布局。此crate中不应实现任何附加功能。
  2. secapi:提供一个反腐败层。调用secapi-sys但公开一个使用惯用数据结构的Rust API。这是必要的,以确保此库的调用者使用Rust而不是某些Rust/C/C++混合语言编写程序。由于FFI调用必须与它们的C/C++对应类型匹配,因此将有大量包装代码来将Rust数据结构转换为C指针或其他原始数据结构。此外,所有FFI调用都是unsafe,必须用unsafe { }块包装。由于借用检查器不能解析指针,我们必须手动调用Box::into_raw()来为FFI提供原始指针,然后调用Box::from_raw()将指针带回到Rust的借用检查器之下。

构建

推荐的构建方式是使用包含的Dockerfiledocker-compose.yml文件的Docker。使用Docker可以确保在每台系统上构建行为都是可重复的,无论主机系统如何。

首先,我们需要创建一个容器,我们将在这里放置我们的工作区域。我们希望这个容器是持久的,即使我们的容器停止或被移除,也不会被销毁。要创建持久容器,请运行以下命令:

$ docker volume create rust_work_area

接下来,我们需要构建我们的Docker镜像。这个Docker镜像将被用作Rust开发的构建和运行环境。要使用Dockerfile构建镜像,请执行以下命令。

$ cd docker
$ docker compose build

现在镜像已经构建,我们需要启动一个容器。容器只是镜像的一个实例,就像进程是程序的一个实例一样。一旦容器启动,我们就可以启动一个shell,允许我们与容器交互。

$ docker compose up
$ docker exec -it rust /bin/bash

一旦我们进入容器,现在需要再次克隆此仓库(我知道这就像《盗梦空间》)。仓库克隆完成后,进入新创建的仓库,你应该能够构建。第一次构建可能需要更长的时间,因为我们将会构建SecAPI的参考实现。请耐心等待。

(Docker Container) $ git clone https://github.com/rdkcentral/secapi-rust.git
(Docker Container) $ cd secapi-rust
(Docker Container) $ git submodule init
(Docker Container) $ git submodule update
(Docker Container) $ cargo build

完成后,你现在可以进行快速的功能测试。你必须设置ROOT_KEYSTORE环境变量,以便参考实现知道使用什么作为根密钥库。

(Docker Container) $ ROOT_KEYSTORE=~/secapi-rust/root_keystore.p12 cargo test

过程

构建整个过程的步骤相当复杂。这里有一个高级概述,以便在出现错误或你只是感兴趣时,你可以理解构建过程:

  1. tasecureapi被构建。这个tasecureapi项目作为子模块存在于这个仓库中。由于secapi-sys的版本和输出的libsaclient.so必须是二进制兼容的,我们确保任何更改在更新Rust绑定之前都不会被推送到这个库。一旦库构建完成,我们就将其复制到Rust的OUT_DIR中。
  2. secapi-sys被构建,并链接到libc.solibsaclient.so
  3. secapi被构建,并链接到secapi-sys

特性

这个库有几个不同的功能标志,它们将影响库的构建方式。以下列出:

  1. system-sa-client(默认禁用):默认情况下将构建参考SecAPI并链接到其共享库输出。如果启用此标志,则构建过程将在系统库文件夹(/lib/usr/lib等)中查找libsaclient.so,并将其链接到该库。

依赖项

如果进行默认构建(默认情况下禁用system-sa-client特性),则Cargo将构建默认参考库tasecureapi,并将其动态链接到本项目输出。然后,你需要以下依赖项来构建tasecureapi

  • tasecureapi

    1. cmake:需要构建库
    2. gtestgmock:需要构建单元测试(但不会链接到输出的共享库saclient.so
    3. libyajl:需要构建并链接
    4. openssl:需要构建并链接

许可证

本项目采用Apache-2.0许可证 - 请参阅LICENSE文件了解详细信息

示例

生成随机字节并将其用作对称密钥

use secapi::{DigestAlgorithm, ErrorStatus, Rights};
use secapi::key::{Key, KeyFormat};
use secapi::crypto::random_bytes;

// The size of a 128 bit key in bytes
const SYM_128_KEY_SIZE: usize = (128 / 8);

// The rust counterpart of the following:
// std::vector<uint8_t> random_bytes(SYM_128_KEY_SIZE);
// if (RAND_bytes(random_bytes.data(), static_cast<int>(random_bytes.size())) != 1) {
//    ERROR("RAND_bytes failed");
//    std::exit(-1);
// }
let mut random_bytes = random_bytes(SYM_128_KEY_SIZE)?;

// The Rust counterpart of the following:
// sa_rights rights;
// sa_rights_set_allow_all(&rights);
let rights = Rights::allow_all();

// The Rust counterpart of the following:
// auto key = create_uninitialized_sa_key();
// sa_import_parameters_symmetric params = {rights};
// sa_status const status = sa_key_import(
//    key.get(),
//    SA_KEY_FORMAT_SYMMETRIC_BYTES,
//    random_bytes.data(),
//    random_bytes.size(),
//    &params
// );
//
// if (status != SA_STATUS_OK) {
//    ERROR("sa_key_import failed");
//    std::exit(-1);
// }
let key = Key::import(KeyFormat::SymmetricBytes { rights }, &mut clone_key)?;

// The Rust counterpart of the following:
// size_t out_length = 0;
// sa_status status = sa_key_digest(nullptr, &out_length, *key, SA_DIGEST_ALGORITHM_SHA1);
// if (status != SA_STATUS_OK) {
//    ERROR("sa_key_digest failed");
//    std::exit(-1);
// }
//
// auto digest = std::vector<uint8_t>(out_length);
// status = sa_key_digest(digest.data(), &out_length, *key, SA_DIGEST_ALGORITHM_SHA1);
// if (status != SA_STATUS_OK) {
//    ERROR("sa_key_digest failed");
//    std::exit(-1);
// }
let sha1_digest = key.digest(DigestAlgorithm::SHA1)?;

导入RSA密钥

use secapi::{ErrorStatus, Rights};
use secapi::key::{Key, KeyFormat};

// The Rust counterpart of the following:
// sa_rights rights;
// sa_rights_set_allow_all(&rights);
let rights = Rights::allow_all();

// The Rust counterpart of the following:
// auto key = create_uninitialized_sa_key();
// sa_import_parameters_rsa_private_key_info params = {rights};
// sa_status const status = sa_key_import(
//    key.get(),
//    SA_KEY_FORMAT_RSA_PRIVATE_KEY_INFO,
//    clear_key.data(),
//    clear_key.size(),
//    &params
// );
//
// if (status != SA_STATUS_OK) {
//    ERROR("sa_key_import failed");
//    std::exit(-1);
// }
let mut clone_key = RSA_1024;
let key = Key::import(KeyFormat::RsaPrivateKeyInfo { rights }, &mut clone_key)?;

// The Rust counterpart of the following:
// sa_header header;
// sa_status const status = sa_key_header(&header, *key);
// if (status != SA_STATUS_OK) {
//    ERROR("sa_key_header failed");
//    std::exit(-1);
// }
// ASSERT_EQ(header.type, 2);
// ASSERT_EQ(header.size, 128);
let header = key.header()?;
assert_eq!(header.key_type, KeyType::Rsa);
assert_eq!(header.size, 128);

当前实现状态

sa.h

函数 已实现 单元测试 Rust 对应版本
sa_get_version 版本
sa_get_name 名称
sa_get_device_id 设备ID
sa_get_ta_uuid TA UUID

sa_crypto.h

函数 已实现 单元测试 Rust 对应版本
sa_crypto_random crypto::fill_random_bytes, crypto::random_bytes
sa_crypto_cipher_init N/A
sa_crypto_cipher_update_iv N/A
sa_crypto_cipher_process N/A
sa_crypto_cipher_process_last N/A
sa_crypto_cipher_release N/A
sa_crypto_mac_init crypto::MacContext::初始化
sa_crypto_mac_process crypto::MacContext::处理字节
sa_crypto_mac_process_key crypto::MacContext::处理密钥
sa_crypto_mac_compute crypto::MacContext::计算
sa_crypto_mac_release 自动作为 crypto::MacContext::Drop 的一部分处理
sa_crypto_sign 密钥::密钥::签名

sa_key.h

函数 已实现 单元测试 Rust 对应版本
sa_key_generate 密钥::密钥::生成
sa_key_export 密钥::密钥::导出
sa_key_import 密钥::密钥::导入
sa_key_unwrap 密钥::密钥::解包
sa_key_get_public 密钥::密钥::公开组件
sa_key_derive 密钥::密钥::派生
sa_key_exchange N/A
sa_key_release 自动作为 key::Key::Drop 的一部分处理
sa_key_header 密钥::密钥::头部
sa_key_digest 密钥::密钥::摘要

sa_svp.h

函数 已实现 已测试 Rust 对应版本
sa_svp_supported svp::svp_supported
sa_svp_memory_alloc svp::SvpMemory::分配
sa_svp_buffer_alloc svp::SvpBuffer::分配
sa_svp_buffer_create svp::SvpBuffer::具有底层内存
sa_svp_memory_free 自动作为 svp::SvpMemory::Drop 的一部分处理
sa_svp_buffer_free 自动作为 svp::SvpBuffer::Drop 的一部分处理
sa_svp_buffer_release 自动作为 svp::SvpBuffer::Drop 的一部分处理
sa_svp_buffer_write svp::SvpBuffer::写入
sa_svp_buffer_copy svp::SvpBuffer::复制
sa_svp_key_check N/A
sa_svp_buffer_check svp::SvpBuffer::检查

依赖项