1 个不稳定版本
0.1.0 | 2023年11月22日 |
---|
#1191 in 密码学
3MB
60K SLoC
SecApi Rust绑定
此仓库包含SecAPI的Rust绑定。此仓库中有两个不同的crate
secapi-sys
:使用原始的C绑定作为FFI(Foreign Function Interface)。必须与用户链接的SecAPI版本二进制兼容。由于Rust不能读取头文件(就像C和C++可以共享相同的头文件一样),我们需要让Rust知道当我们将它链接到C/C++编译的库时,它可以期望什么数据类型和函数接口。使用#[repr(C)]
宏确保所有数据类型都与它们的C/C++对应类型具有相同的内存布局。此crate中不应实现任何附加功能。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的借用检查器之下。
构建
推荐的构建方式是使用包含的Dockerfile
和docker-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
过程
构建整个过程的步骤相当复杂。这里有一个高级概述,以便在出现错误或你只是感兴趣时,你可以理解构建过程:
tasecureapi
被构建。这个tasecureapi
项目作为子模块存在于这个仓库中。由于secapi-sys
的版本和输出的libsaclient.so
必须是二进制兼容的,我们确保任何更改在更新Rust绑定之前都不会被推送到这个库。一旦库构建完成,我们就将其复制到Rust的OUT_DIR
中。secapi-sys
被构建,并链接到libc.so
和libsaclient.so
。secapi
被构建,并链接到secapi-sys
。
特性
这个库有几个不同的功能标志,它们将影响库的构建方式。以下列出:
system-sa-client
(默认禁用):默认情况下将构建参考SecAPI并链接到其共享库输出。如果启用此标志,则构建过程将在系统库文件夹(/lib
、/usr/lib
等)中查找libsaclient.so
,并将其链接到该库。
依赖项
如果进行默认构建(默认情况下禁用system-sa-client
特性),则Cargo将构建默认参考库tasecureapi
,并将其动态链接到本项目输出。然后,你需要以下依赖项来构建tasecureapi
:
-
tasecureapi
cmake
:需要构建库gtest
和gmock
:需要构建单元测试(但不会链接到输出的共享库saclient.so
)libyajl
:需要构建并链接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(),
// ¶ms
// );
//
// 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(),
// ¶ms
// );
//
// 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::检查 |