use std::error::Error;
use libc::{c_char, c_void, size_t};
pub type SaHandle = u64;
pub const INVALID_HANDLE: SaHandle = u64::MAX;
pub const NUM_MAGIC: usize = 4;
pub type SaKey = SaHandle;
pub type SaSvpBuffer = SaHandle;
pub type SaCryptoCipherContext = SaHandle;
pub type SaCryptoMacContext = SaHandle;
#[derive(Debug)]
#[repr(C)]
pub struct SaVersion {
pub specification_major: u64,
pub specification_minor: u64,
pub specification_revision: u64,
pub implementation_revision: u64,
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum SaCipherAlgorithm {
AES_ECB = 0,
AES_ECB_PKCS7,
AES_CBC,
AES_CBC_PKCS7,
AES_CTR,
AES_GCM,
RSA_PKCS1V15,
RSA_OAEP,
EC_ELGAMAL,
CHACHA20,
CHACHA20_POLY1305,
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum SaCipherMode {
DECRYPT = 0,
ENCRYPT,
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum SaSignatureAlgorithm {
RSA_PKCS1V15 = 0,
RSA_PSS,
ECDSA,
EDDSA,
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum SaMacAlgorithm {
CMAC = 0,
HMAC,
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum SaDigestAlgorithm {
SHA1 = 0,
SHA256,
SHA384,
SHA512,
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum SaKdfAlgorithm {
ROOT_KEY_LADDER = 0,
HKDF,
CONCAT,
ANSI_X963,
CMAC,
NETFLIX,
COMMON_ROOT_KEY_LADDER,
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum SaKeyExchangeAlgorithm {
DH = 0,
ECDH,
NETFLIX_AUTHENTICATED_DH,
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum SaKeyFormat {
SYMMETRIC_BYTES = 0,
EC_PRIVATE_BYTES,
RSA_PRIVATE_KEY_INFO,
EXPORTED,
SOC,
TYPEJ,
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum SaKeyType {
SYMMETRIC = 0,
EC = 1,
RSA = 2,
DH = 3,
}
impl TryFrom<u8> for SaKeyType {
type Error = Box<dyn Error>;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::SYMMETRIC),
1 => Ok(Self::EC),
2 => Ok(Self::RSA),
3 => Ok(Self::DH),
_ => Err("Value is not recognized".into()),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum SaEllipticCurve {
NIST_P256 = 0,
NIST_P384 = 1,
NIST_P521 = 2,
ED25519 = 3,
X25519 = 4,
ED448 = 5,
X448 = 6,
NIST_P192 = 7,
NIST_P224 = 8,
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum SaBufferType {
TYPE_CLEAR = 0,
TYPE_SVP,
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum SaStatus {
OK = 0,
NO_AVAILABLE_RESOURCE_SLOT,
INVALID_KEY_FORMAT,
INVALID_KEY_TYPE,
NULL_PARAMETER,
INVALID_PARAMETER,
OPERATION_NOT_ALLOWED,
INVALID_SVP_BUFFER,
OPERATION_NOT_SUPPORTED,
SELF_TEST,
VERIFICATION_FAILED,
INTERNAL_ERROR,
HW_ERROR,
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum SaUsageFlags {
KEY_EXCHANGE = 0,
DERIVE = 1,
UNWRAP = 2,
ENCRYPT = 3,
DECRYPT = 4,
SIGN = 5,
ALLOWED_ANALOG_UNPROTECTED = 6,
ALLOWED_ANALOG_CGMSA = 7,
ALLOWED_DIGITAL_UNPROTECTED = 8,
ALLOWED_DIGITAL_HDCP14 = 9,
ALLOWED_DIGITAL_HDCP22 = 10,
ALLOWED_DIGITAL_DTCP = 11,
SVP_OPTIONAL = 12,
CACHEABLE = 13,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct SaUuid {
pub id: [u8; 16],
}
pub const MAX_NUM_ALLOWED_TA_IDS: usize = 32;
#[derive(Debug)]
#[repr(C)]
pub struct SaRights {
pub id: [u8; 64],
pub usage_flags: u64,
pub child_usage_flags: u64,
pub not_before: u64,
pub not_on_or_after: u64,
pub allowed_tas: [SaUuid; MAX_NUM_ALLOWED_TA_IDS],
}
pub const DH_MAX_MOD_SIZE: usize = 512;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct DhParameters {
pub p: [u8; DH_MAX_MOD_SIZE],
pub p_length: size_t,
pub g: [u8; DH_MAX_MOD_SIZE],
pub g_length: size_t,
}
#[repr(C)]
pub union SaTypeParameters {
pub curve: SaEllipticCurve,
pub dh_parameters: DhParameters,
}
#[repr(C)]
pub struct SaHeader {
pub magic: [c_char; NUM_MAGIC],
pub rights: SaRights,
pub type_: u8,
pub type_parameters: SaTypeParameters,
pub size: u16,
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct Clear {
pub buffer: *mut c_void,
pub length: size_t,
pub offset: size_t,
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct Svp {
pub buffer: SaSvpBuffer,
pub offset: size_t,
}
#[repr(C)]
pub union SaBufferContext {
pub clear: Clear,
pub svp: Svp,
}
#[repr(C)]
pub struct SaBuffer {
pub buffer_type: SaBufferType,
pub context: SaBufferContext,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaImportParametersSymmetric {
pub rights: *const SaRights,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaImportParametersEcPrivateBytes {
pub rights: *const SaRights,
pub curve: SaEllipticCurve,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaImportParametersRsaPrivateKeyInfo {
pub rights: *const SaRights,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaImportParamtersTypeJ {
pub kcipher: SaKey,
pub khmac: SaKey,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaImportParametersSoc {
pub length: [u8; 2],
pub version: u8,
pub default_rights: SaRights,
pub object_id: u64,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaGenerateParametersSymmetric {
pub key_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaGenerateParametersRsa {
pub modulus_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaGenerateParametersEc {
pub curve: SaEllipticCurve,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaGenerateParametersDh {
pub p: *const c_void,
pub p_length: size_t,
pub g: *const c_void,
pub g_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaCipherParametersAesCbc {
pub iv: *const c_void,
pub iv_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaCipherParametersAesCtr {
pub ctr: *const c_void,
pub ctr_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaCipherParametersAesGcm {
pub iv: *const c_void,
pub iv_length: size_t,
pub aad: *const c_void,
pub aad_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaCipherParametersChaCha20 {
pub counter: *const c_void,
pub counter_length: size_t,
pub nonce: *const c_void,
pub nonce_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaCipherParametersChaCha20Poly1305 {
pub nonce: *const c_void,
pub nonce_length: size_t,
pub aad: *const c_void,
pub aad_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaCipherParametersRsaOaep {
pub digest_algorithm: SaDigestAlgorithm,
pub mgf1_digest_algorithm: SaDigestAlgorithm,
pub label: *mut c_void,
pub label_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaMacParametersHmac {
pub digest_algorithm: SaDigestAlgorithm,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaCipherEndParametersAesGcm {
pub tag: *mut c_void,
pub tag_length: size_t,
}
pub type SaCipherEndParametersChaCha20Poly1305 = SaCipherEndParametersAesGcm;
#[derive(Debug)]
#[repr(C)]
pub struct SaUnwrapTypeParametersEc {
pub curve: SaEllipticCurve,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaUnwrapParametersAesCbc {
pub iv: *const c_void,
pub iv_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaUnwrapParametersAesCtr {
pub ctr: *const c_void,
pub ctr_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaUnwrapParametersAesGcm {
pub iv: *const c_void,
pub iv_length: size_t,
pub aad: *const c_void,
pub aad_length: size_t,
pub tag: *const c_void,
pub tag_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaUnwrapParametersChaCha20 {
pub counter: *const c_void,
pub counter_length: size_t,
pub nonce: *const c_void,
pub nonce_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaUnwrapParametersChaCha20Poly1305 {
pub nonce: *const c_void,
pub nonce_length: size_t,
pub aad: *const c_void,
pub aad_length: size_t,
pub tag: *const c_void,
pub tag_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaUnwrapParametersRsaOaep {
pub digest_algorithm: SaDigestAlgorithm,
pub mgf1_digest_algorithm: SaDigestAlgorithm,
pub label: *mut c_void,
pub label_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaUnwrapParametersEcElgamal {
pub offset: size_t,
pub key_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaSignParametersRsaPss {
pub digest_algorithm: SaDigestAlgorithm,
pub mgf1_digest_algorithm: SaDigestAlgorithm,
pub precomputed_digest: bool,
pub salt_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaSignParametersRsaPkcs1v15 {
pub digest_algorithm: SaDigestAlgorithm,
pub precomputed_digest: bool,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaSignParametersEcdsa {
pub digest_algorithm: SaDigestAlgorithm,
pub precomputed_digest: bool,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaKdfParametersRootKeyLadder {
pub c1: *const c_void,
pub c1_length: size_t,
pub c2: *const c_void,
pub c2_length: size_t,
pub c3: *const c_void,
pub c3_length: size_t,
pub c4: *const c_void,
pub c4_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaKdfParametersHkdf {
pub key_length: size_t,
pub digest_algorithm: SaDigestAlgorithm,
pub parent: SaKey,
pub salt: *const c_void,
pub salt_length: size_t,
pub info: *const c_void,
pub info_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaKdfParametersConcat {
pub key_length: size_t,
pub digest_algorithm: SaDigestAlgorithm,
pub parent: SaKey,
pub info: *const c_void,
pub info_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaKdfParametersAnsiX963 {
pub key_length: size_t,
pub digest_algorithm: SaDigestAlgorithm,
pub parent: SaKey,
pub info: *const c_void,
pub info_length: size_t,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaKdfParametersCmac {
pub key_length: size_t,
pub parent: SaKey,
pub other_data: *const c_void,
pub other_data_length: size_t,
pub counter: u8,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaKdfParametersNetflix {
pub kenc: SaKey,
pub hmac: SaKey,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaKeyExchangeParametersNetflixAuthenticatedDh {
in_kw: SaKey,
out_ke: *mut SaKey,
rights_ke: *mut SaRights,
out_kh: *mut SaKey,
rights_kh: *mut SaRights,
}
#[derive(Debug)]
#[repr(C)]
pub struct SaSvpOffset {
pub out_offset: size_t,
pub in_offset: size_t,
pub length: size_t,
}
#[link(name = "saclient")]
extern "C" {
pub fn sa_get_version(version: *mut SaVersion) -> SaStatus;
pub fn sa_get_name(name: *mut c_char, name_length: *mut size_t) -> SaStatus;
pub fn sa_get_device_id(id: *mut u64) -> SaStatus;
pub fn sa_get_ta_uuid(uuid: *mut SaUuid) -> SaStatus;
pub fn sa_crypto_random(out: *mut c_void, length: size_t) -> SaStatus;
pub fn sa_crypto_cipher_init(
context: *mut SaCryptoCipherContext,
cipher_algorithm: SaCipherAlgorithm,
sa_cipher_mode: SaCipherMode,
sa_key: SaKey,
parameters: *mut c_void,
) -> SaStatus;
pub fn sa_crypto_cipher_update_iv(
context: SaCryptoCipherContext,
iv: *const c_void,
iv_length: size_t,
) -> SaStatus;
pub fn sa_crypto_cipher_process(
out: *mut SaBuffer,
context: SaCryptoCipherContext,
in_: *mut SaBuffer,
bytes_to_process: *mut size_t,
) -> SaStatus;
pub fn sa_crypto_cipher_process_last(
out: *mut SaBuffer,
context: SaCryptoCipherContext,
in_: *mut SaBuffer,
bytes_to_process: *mut size_t,
parameters: *mut c_void,
) -> SaStatus;
pub fn sa_crypto_cipher_release(context: SaCryptoCipherContext) -> SaStatus;
pub fn sa_crypto_mac_init(
context: *mut SaCryptoMacContext,
mac_algorithm: SaMacAlgorithm,
key: SaKey,
parameters: *mut c_void,
) -> SaStatus;
pub fn sa_crypto_mac_process(
context: SaCryptoMacContext,
in_: *const c_void,
in_length: size_t,
) -> SaStatus;
pub fn sa_crypto_mac_process_key(context: SaCryptoMacContext, key: SaKey) -> SaStatus;
pub fn sa_crypto_mac_compute(
out: *mut c_void,
out_length: *mut size_t,
context: SaCryptoMacContext,
) -> SaStatus;
pub fn sa_crypto_mac_release(context: SaCryptoMacContext) -> SaStatus;
pub fn sa_crypto_sign(
out: *mut c_void,
out_length: *mut size_t,
signature_algorithm: SaSignatureAlgorithm,
key: SaKey,
in_: *const c_void,
in_length: size_t,
parameters: *const c_void,
) -> SaStatus;
pub fn sa_key_generate(
key: *mut SaKey,
rights: *const SaRights,
key_type: SaKeyType,
parameters: *mut c_void,
) -> SaStatus;
pub fn sa_key_export(
out: *mut c_void,
out_length: *mut size_t,
mixin: *const c_void,
mixin_length: size_t,
key: SaKey,
) -> SaStatus;
pub fn sa_key_import(
key: *mut SaKey,
key_format: SaKeyFormat,
in_: *const c_void,
in_length: size_t,
parameters: *mut c_void,
) -> SaStatus;
pub fn sa_key_unwrap(
key: *mut SaKey,
rights: *const SaRights,
key_type: SaKeyType,
type_parameters: *mut c_void,
cipher_algorithm: SaCipherAlgorithm,
algorithm_parameters: *mut c_void,
wrapping_key: SaKey,
in_: *const c_void,
in_length: size_t,
) -> SaStatus;
pub fn sa_key_get_public(out: *mut c_void, out_length: *mut size_t, key: SaKey) -> SaStatus;
pub fn sa_key_derive(
key: *mut SaKey,
rights: *const SaRights,
kdf_algorithm: SaKdfAlgorithm,
parameters: *mut c_void,
) -> SaStatus;
pub fn sa_key_exchange(
key: *mut SaKey,
rights: *const SaRights,
key_exchange_algorithm: SaKeyExchangeAlgorithm,
private_key: SaKey,
other_public: *const c_void,
other_public_length: size_t,
parameters: *mut c_void,
) -> SaStatus;
pub fn sa_key_release(key: SaKey) -> SaStatus;
pub fn sa_key_header(header: *mut SaHeader, key: SaKey) -> SaStatus;
pub fn sa_key_digest(
out: *mut c_void,
out_length: *mut size_t,
key: SaKey,
digest_algorithm: SaDigestAlgorithm,
) -> SaStatus;
pub fn sa_svp_supported() -> SaStatus;
pub fn sa_svp_memory_alloc(svp_memory: *mut *mut c_void, size: size_t) -> SaStatus;
pub fn sa_svp_buffer_alloc(svp_buffer: *mut SaSvpBuffer, size: size_t) -> SaStatus;
pub fn sa_svp_buffer_create(
svp_buffer: *mut SaSvpBuffer,
svp_memory: *mut c_void,
size: size_t,
) -> SaStatus;
pub fn sa_svp_memory_free(svp_memory: *mut c_void) -> SaStatus;
pub fn sa_svp_buffer_free(svp_buffer: SaSvpBuffer) -> SaStatus;
pub fn sa_svp_buffer_release(
svp_memory: *mut *mut c_void,
size: *mut size_t,
svp_buffer: SaSvpBuffer,
) -> SaStatus;
pub fn sa_svp_buffer_write(
out: SaSvpBuffer,
in_: *const c_void,
in_length: size_t,
offsets: *mut SaSvpOffset,
offsets_length: size_t,
) -> SaStatus;
pub fn sa_svp_buffer_copy(
out: SaSvpBuffer,
in_: SaSvpBuffer,
offsets: *mut SaSvpOffset,
offsets_length: size_t,
) -> SaStatus;
pub fn sa_svp_key_check(
key: SaKey,
in_: *mut SaBuffer,
bytes_to_process: size_t,
expected: *const c_void,
expected_length: size_t,
) -> SaStatus;
pub fn sa_svp_buffer_check(
svp_buffer: SaSvpBuffer,
offset: size_t,
length: size_t,
digest_algorithm: SaDigestAlgorithm,
hash: *const c_void,
hash_length: size_t,
) -> SaStatus;
}