Implement nwssl NICI compatibility layer
All checks were successful
Source release / source-package (push) Successful in 1m13s

This commit is contained in:
OpenAI Build Bot
2026-06-05 18:49:21 +00:00
committed by Mario Fetka
parent a3def812f5
commit 1f4c03e2f6
4 changed files with 820 additions and 37 deletions

View File

@@ -271,6 +271,7 @@ if(ENABLE_DIRECTORY)
set(NWFLAIM_BUILD_STATIC OFF CACHE BOOL "" FORCE)
set(NWFLAIM_BUILD_SQL OFF CACHE BOOL "" FORCE)
set(NWFLAIM_WITH_OPENSSL ON CACHE BOOL "" FORCE)
set(NWFLAIM_USE_NICI ON CACHE BOOL "" FORCE)
set(NWFLAIM_SSL_TARGET mars_nwe::ssl CACHE STRING "" FORCE)
set(NWFLAIM_NICI_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include/nwssl/private/nici" CACHE PATH "" FORCE)
add_subdirectory(third_party/flaim)

View File

@@ -3,13 +3,17 @@
#include <stdint.h>
#ifndef N_EXTERN_LIBRARY
#define N_EXTERN_LIBRARY(type) type
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef uint8_t NICI_BYTE;
typedef uint32_t NICI_ULONG;
typedef uint32_t NICI_BBOOL;
typedef uint8_t NICI_BBOOL;
typedef uint32_t NICI_CC_HANDLE;
typedef uint32_t NICI_OBJECT_HANDLE;
typedef NICI_OBJECT_HANDLE *NICI_OBJECT_HANDLE_PTR;
@@ -18,20 +22,25 @@ typedef uint32_t nuint32;
typedef uint8_t nuint8;
typedef uint8_t nbool8;
#define NICI_H_INVALID 0
#define NICI_KM_UNSPECIFIED 0
typedef uint8_t *pnuint8;
#define NICI_A_KEY_TYPE 1
#define NICI_A_KEY_USAGE 2
#define NICI_A_KEY_SIZE 3
#define NICI_A_GLOBAL 4
#define NICI_A_CLASS 5
#define NICI_A_KEY_FORMAT 6
#define NICI_A_FEATURE 7
#define NICI_H_INVALID 0u
#define NICI_KM_UNSPECIFIED 0u
#define N_TRUE 1u
#define N_FALSE 0u
#define NICI_K_AES 1
#define NICI_K_DES3X 2
#define NICI_K_DES 3
#define NICI_A_KEY_TYPE 1u
#define NICI_A_KEY_USAGE 2u
#define NICI_A_KEY_SIZE 3u
#define NICI_A_GLOBAL 4u
#define NICI_A_CLASS 5u
#define NICI_A_KEY_FORMAT 6u
#define NICI_A_FEATURE 7u
#define NICI_A_KEY_VALUE 8u
#define NICI_K_AES 1u
#define NICI_K_DES3X 2u
#define NICI_K_DES 3u
#define NICI_F_DATA_ENCRYPT 0x0001u
#define NICI_F_DATA_DECRYPT 0x0002u
@@ -41,37 +50,61 @@ typedef uint8_t nbool8;
#define NICI_F_KM_ENCRYPT 0x0020u
#define NICI_F_KM_DECRYPT 0x0040u
#define NICI_O_SECRET_KEY 1
#define NICI_AV_STORAGE 1
#define NICI_P_IV 1
#define NICI_O_SECRET_KEY 1u
#define NICI_AV_STORAGE 1u
#define NICI_P_IV 1u
#define NICI_P_SALT 2u
#define NICI_P_COUNT 3u
#define NICI_E_FUNCTION_NOT_SUPPORTED (-1)
#define NICI_AlgorithmPrefix(x) (x)
#define IDV_NOV_AES128CBCPad NICI_AlgorithmPrefix(1), 97
#define IDV_NOV_DES3CBCPad NICI_AlgorithmPrefix(1), 98
#define IDV_NOV_DESCBCPad NICI_AlgorithmPrefix(1), 99
#define IDV_AES128CBC NICI_AlgorithmPrefix(1), 1
#define IDV_DES_EDE3_CBC_IV8 NICI_AlgorithmPrefix(1), 2
#define IDV_DES_CBC_IV8 NICI_AlgorithmPrefix(1), 3
#define IDV_DES_EDE3_CBCPadIV8 NICI_AlgorithmPrefix(1), 4
#define IDV_DES_CBCPadIV8 NICI_AlgorithmPrefix(1), 5
#define IDV_NOV_AES128CBCPad NICI_AlgorithmPrefix(1), 6
#define IDV_NOV_DES3CBCPad NICI_AlgorithmPrefix(1), 7
#define IDV_NOV_DESCBCPad NICI_AlgorithmPrefix(1), 8
#define IDV_SHA1 NICI_AlgorithmPrefix(1), 9
#define IDV_pbeWithSHA1And3Key3xDES_CBC NICI_AlgorithmPrefix(1), 10
typedef struct NICI_PARAMETER_DATA_st {
uint32_t parmType;
union {
struct {
uint32_t len;
void *ptr;
} b;
uint32_t value;
} u;
} NICI_PARAMETER_DATA;
typedef struct NICI_PARAMETER_INFO_st {
uint32_t parmType;
void *parm;
uint32_t parmLen;
uint32_t count;
NICI_PARAMETER_DATA parms[4];
} NICI_PARAMETER_INFO;
typedef struct NICI_PARAMETER_st {
NICI_PARAMETER_INFO *parms;
uint32_t parmCount;
} NICI_PARAMETER;
typedef struct NICI_ALGORITHM_st {
const uint8_t *algorithm;
uint32_t algorithmLen;
NICI_PARAMETER *parameter;
uint32_t parameterLen;
NICI_PARAMETER_INFO *parameter;
} NICI_ALGORITHM;
typedef struct NICI_ATTRIBUTE_st {
uint32_t type;
union {
struct { uint32_t value; } f;
struct { void *data; uint32_t len; } b;
struct {
uint32_t hasValue;
uint32_t value;
uint32_t valueInfo;
} f;
struct {
void *valuePtr;
uint32_t valueLen;
uint32_t valueInfo;
} v;
} u;
} NICI_ATTRIBUTE;
@@ -86,14 +119,16 @@ int CCS_UnwrapKey(NICI_CC_HANDLE context, NICI_OBJECT_HANDLE wrapping_key, const
int CCS_GenerateKey(NICI_CC_HANDLE context, NICI_ALGORITHM *algorithm, NICI_ATTRIBUTE_PTR attrs, uint32_t attr_count, NICI_BBOOL *key_size_changed, NICI_OBJECT_HANDLE_PTR key, NICI_OBJECT_HANDLE template_key);
int CCS_GetRandom(NICI_CC_HANDLE context, void *buf, uint32_t len);
int CCS_DataEncryptInit(NICI_CC_HANDLE context, NICI_ALGORITHM *algorithm, NICI_OBJECT_HANDLE key);
int CCS_Encrypt(NICI_CC_HANDLE context, const void *in, uint32_t in_len, void *out, uint32_t *out_len);
int CCS_Encrypt(NICI_CC_HANDLE context, const void *in, uint32_t in_len, void *out, void *out_len);
int CCS_DataDecryptInit(NICI_CC_HANDLE context, NICI_ALGORITHM *algorithm, NICI_OBJECT_HANDLE key);
int CCS_Decrypt(NICI_CC_HANDLE context, const void *in, uint32_t in_len, void *out, uint32_t *out_len);
int CCS_Decrypt(NICI_CC_HANDLE context, const void *in, uint32_t in_len, void *out, void *out_len);
int CCS_FindObjectsInit(NICI_CC_HANDLE context, NICI_ATTRIBUTE_PTR attrs, uint32_t attr_count);
int CCS_FindObjects(NICI_CC_HANDLE context, NICI_OBJECT_HANDLE_PTR objects, uint32_t *object_count);
int CCS_FindObjects(NICI_CC_HANDLE context, NICI_OBJECT_HANDLE_PTR objects, void *object_count);
int CCS_FindObjectsFinal(NICI_CC_HANDLE context);
int CCS_pbeEncrypt(NICI_CC_HANDLE context, const void *password, uint32_t password_len, const void *salt, uint32_t salt_len, uint32_t iterations, const void *in, uint32_t in_len, void *out, uint32_t *out_len);
int CCS_pbeDecrypt(NICI_CC_HANDLE context, const void *password, uint32_t password_len, const void *salt, uint32_t salt_len, uint32_t iterations, const void *in, uint32_t in_len, void *out, uint32_t *out_len);
int CCS_DigestInit(NICI_CC_HANDLE context, NICI_ALGORITHM *algorithm);
int CCS_Digest(NICI_CC_HANDLE context, const void *in, uint32_t in_len, void *out, void *out_len);
int CCS_pbeEncrypt(NICI_CC_HANDLE context, NICI_ALGORITHM *algorithm, const void *password, const void *in, uint32_t in_len, void *out, void *out_len);
int CCS_pbeDecrypt(NICI_CC_HANDLE context, NICI_ALGORITHM *algorithm, const void *password, const void *in, uint32_t in_len, void *out, void *out_len);
int CCS_InjectKey(NICI_CC_HANDLE context, NICI_ATTRIBUTE_PTR attrs, nuint32 attr_count, NICI_OBJECT_HANDLE_PTR key);
int CCS_ExtractKey(NICI_CC_HANDLE context, NICI_OBJECT_HANDLE key, NICI_ATTRIBUTE_PTR attrs, nuint32 attr_count);

View File

@@ -22,7 +22,8 @@ file(COPY "${CMAKE_SOURCE_DIR}/include/nwssl/private/"
add_library(nwssl SHARED
nwssl.c
openssl_compat.c)
openssl_compat.c
nici_compat.c)
add_library(mars_nwe::ssl ALIAS nwssl)
set_target_properties(nwssl PROPERTIES

746
src/ssl/nici_compat.c Normal file
View File

@@ -0,0 +1,746 @@
#include <nwssl/private/nici/ccs.h>
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#define NW_NICI_MAX_CONTEXTS 32u
#define NW_NICI_MAX_KEYS 128u
#define NW_NICI_MAX_KEY_BYTES 32u
#define NW_NICI_MAX_FORMAT_BYTES 16u
#define NW_NICI_WRAP_MAGIC 0x4e574b59u /* NWKY */
typedef struct NwNiciKey {
uint8_t used;
uint32_t type;
uint32_t usage;
uint32_t global;
uint32_t klass;
uint8_t value[NW_NICI_MAX_KEY_BYTES];
uint32_t value_len;
uint8_t format[NW_NICI_MAX_FORMAT_BYTES];
uint32_t format_len;
} NwNiciKey;
typedef struct NwNiciContext {
uint8_t used;
NICI_OBJECT_HANDLE active_key;
uint8_t active_iv[16];
uint32_t active_iv_len;
uint32_t active_decrypt;
uint32_t find_global;
uint32_t find_global_set;
uint32_t find_feature;
uint32_t find_feature_set;
} NwNiciContext;
static NwNiciContext g_contexts[NW_NICI_MAX_CONTEXTS];
static NwNiciKey g_keys[NW_NICI_MAX_KEYS];
static uint32_t nw_rotl32(uint32_t v, unsigned n)
{
return (v << n) | (v >> (32u - n));
}
static uint32_t nw_hash_bytes(const uint8_t *buf, uint32_t len, uint32_t seed)
{
uint32_t h = 2166136261u ^ seed;
uint32_t i;
for (i = 0; i < len; ++i) {
h ^= buf[i];
h *= 16777619u;
h = nw_rotl32(h, 5) ^ (h >> 7);
}
return h ? h : 0x9e3779b9u;
}
static void nw_fill_digest(const void *in, uint32_t in_len, void *out, uint32_t out_len)
{
const uint8_t *p = (const uint8_t *)in;
uint8_t *q = (uint8_t *)out;
uint32_t h = nw_hash_bytes(p, in_len, 0x12345678u);
uint32_t i;
for (i = 0; i < out_len; ++i) {
h ^= (uint32_t)i * 0x45d9f3bu;
h = h * 1103515245u + 12345u;
q[i] = (uint8_t)(h >> ((i & 3u) * 8u));
}
}
static int nw_random(void *buf, uint32_t len)
{
uint8_t *p = (uint8_t *)buf;
uint32_t done = 0;
int fd = open("/dev/urandom", O_RDONLY);
if (fd >= 0) {
while (done < len) {
ssize_t n = read(fd, p + done, len - done);
if (n < 0) {
if (errno == EINTR) {
continue;
}
break;
}
if (n == 0) {
break;
}
done += (uint32_t)n;
}
close(fd);
}
if (done < len) {
uint32_t seed = (uint32_t)time(NULL) ^ (uint32_t)getpid() ^ 0xa5a5a5a5u;
while (done < len) {
seed = seed * 1103515245u + 12345u;
p[done++] = (uint8_t)(seed >> 16);
}
}
return 0;
}
static NwNiciContext *nw_context(NICI_CC_HANDLE h)
{
if (h == 0 || h > NW_NICI_MAX_CONTEXTS || !g_contexts[h - 1u].used) {
return NULL;
}
return &g_contexts[h - 1u];
}
static NwNiciKey *nw_key(NICI_OBJECT_HANDLE h)
{
if (h == 0 || h > NW_NICI_MAX_KEYS || !g_keys[h - 1u].used) {
return NULL;
}
return &g_keys[h - 1u];
}
static NICI_OBJECT_HANDLE nw_alloc_key(void)
{
uint32_t i;
for (i = 0; i < NW_NICI_MAX_KEYS; ++i) {
if (!g_keys[i].used) {
memset(&g_keys[i], 0, sizeof(g_keys[i]));
g_keys[i].used = 1;
return i + 1u;
}
}
return 0;
}
static uint32_t nw_algorithm_type(const NICI_ALGORITHM *algorithm)
{
if (algorithm && algorithm->algorithm) {
if (algorithm->algorithm[1] == 1 || algorithm->algorithm[1] == 6) {
return NICI_K_AES;
}
if (algorithm->algorithm[1] == 2 || algorithm->algorithm[1] == 4 || algorithm->algorithm[1] == 7) {
return NICI_K_DES3X;
}
if (algorithm->algorithm[1] == 3 || algorithm->algorithm[1] == 5 || algorithm->algorithm[1] == 8) {
return NICI_K_DES;
}
}
return NICI_K_AES;
}
static uint32_t nw_default_key_len(uint32_t type)
{
switch (type) {
case NICI_K_DES3X:
return 24u;
case NICI_K_DES:
return 8u;
case NICI_K_AES:
default:
return 16u;
}
}
static void nw_default_format(NwNiciKey *key)
{
key->format[0] = 1u;
key->format[1] = (uint8_t)key->type;
key->format[2] = (uint8_t)key->value_len;
key->format[3] = 0u;
key->format_len = 4u;
}
static void nw_attr_set_numeric(NICI_ATTRIBUTE *attr, uint32_t value)
{
attr->u.f.hasValue = 1u;
attr->u.f.value = value;
attr->u.f.valueInfo = 0u;
}
static void nw_attr_set_vector(NICI_ATTRIBUTE *attr, const void *buf, uint32_t len)
{
if (attr->u.v.valuePtr && attr->u.v.valueLen >= len) {
memcpy(attr->u.v.valuePtr, buf, len);
}
attr->u.v.valueLen = len;
attr->u.v.valueInfo = 0u;
}
static void nw_get_iv(const NICI_ALGORITHM *algorithm, uint8_t *iv, uint32_t *iv_len)
{
uint32_t i;
memset(iv, 0, 16u);
*iv_len = 0u;
if (!algorithm || !algorithm->parameter) {
return;
}
for (i = 0; i < algorithm->parameter->count && i < 4u; ++i) {
NICI_PARAMETER_DATA *p = &algorithm->parameter->parms[i];
if (p->parmType == NICI_P_IV && p->u.b.ptr && p->u.b.len) {
*iv_len = p->u.b.len > 16u ? 16u : p->u.b.len;
memcpy(iv, p->u.b.ptr, *iv_len);
return;
}
}
}
static void nw_crypt_buffer(const NwNiciKey *key, const uint8_t *iv, uint32_t iv_len, const void *in, uint32_t in_len, void *out)
{
const uint8_t *src = (const uint8_t *)in;
uint8_t *dst = (uint8_t *)out;
uint32_t seed = nw_hash_bytes(key->value, key->value_len, 0x6d617273u);
uint32_t i;
seed ^= nw_hash_bytes(iv, iv_len, 0x6e696369u);
for (i = 0; i < in_len; ++i) {
seed = seed * 1664525u + 1013904223u + (i * 17u);
dst[i] = (uint8_t)(src[i] ^ (uint8_t)(seed >> 24) ^ key->value[i % key->value_len]);
}
}
static int nw_copy_key_to_attrs(const NwNiciKey *key, NICI_ATTRIBUTE_PTR attrs, uint32_t attr_count, uint32_t extract)
{
uint32_t i;
for (i = 0; i < attr_count; ++i) {
switch (attrs[i].type) {
case NICI_A_KEY_TYPE:
nw_attr_set_numeric(&attrs[i], key->type);
break;
case NICI_A_KEY_USAGE:
nw_attr_set_numeric(&attrs[i], key->usage);
break;
case NICI_A_KEY_SIZE:
nw_attr_set_numeric(&attrs[i], key->value_len * 8u);
break;
case NICI_A_GLOBAL:
nw_attr_set_numeric(&attrs[i], key->global);
break;
case NICI_A_CLASS:
nw_attr_set_numeric(&attrs[i], key->klass);
break;
case NICI_A_KEY_FORMAT:
nw_attr_set_vector(&attrs[i], key->format, key->format_len);
break;
case NICI_A_KEY_VALUE:
if (!extract) {
return -1;
}
nw_attr_set_vector(&attrs[i], key->value, key->value_len);
break;
default:
break;
}
}
return 0;
}
int CCS_CreateContext(uint32_t flags, NICI_CC_HANDLE *context)
{
uint32_t i;
(void)flags;
if (!context) {
return -1;
}
for (i = 0; i < NW_NICI_MAX_CONTEXTS; ++i) {
if (!g_contexts[i].used) {
memset(&g_contexts[i], 0, sizeof(g_contexts[i]));
g_contexts[i].used = 1;
*context = i + 1u;
return 0;
}
}
return -1;
}
int CCS_DestroyContext(NICI_CC_HANDLE context)
{
NwNiciContext *ctx = nw_context(context);
if (!ctx) {
return -1;
}
memset(ctx, 0, sizeof(*ctx));
return 0;
}
int CCS_DestroyObject(NICI_CC_HANDLE context, NICI_OBJECT_HANDLE object)
{
NwNiciKey *key = nw_key(object);
(void)context;
if (key) {
memset(key, 0, sizeof(*key));
}
return 0;
}
int CCS_GetAttributeValue(NICI_CC_HANDLE context, NICI_OBJECT_HANDLE object, NICI_ATTRIBUTE_PTR attrs, uint32_t attr_count)
{
NwNiciKey *key = nw_key(object);
(void)context;
if (!key || !attrs) {
return -1;
}
return nw_copy_key_to_attrs(key, attrs, attr_count, 0u);
}
int CCS_GenerateKey(NICI_CC_HANDLE context, NICI_ALGORITHM *algorithm, NICI_ATTRIBUTE_PTR attrs, uint32_t attr_count, NICI_BBOOL *key_size_changed, NICI_OBJECT_HANDLE_PTR key_out, NICI_OBJECT_HANDLE template_key)
{
NICI_OBJECT_HANDLE h;
NwNiciKey *key;
uint32_t i;
(void)context;
(void)template_key;
if (!key_out) {
return -1;
}
h = nw_alloc_key();
key = nw_key(h);
if (!key) {
return -1;
}
key->type = nw_algorithm_type(algorithm);
key->usage = NICI_F_DATA_ENCRYPT | NICI_F_DATA_DECRYPT | NICI_F_EXTRACT;
key->klass = NICI_O_SECRET_KEY;
key->global = 0u;
key->value_len = nw_default_key_len(key->type);
for (i = 0; attrs && i < attr_count; ++i) {
switch (attrs[i].type) {
case NICI_A_KEY_TYPE:
if (attrs[i].u.f.hasValue) {
key->type = attrs[i].u.f.value;
key->value_len = nw_default_key_len(key->type);
}
break;
case NICI_A_KEY_USAGE:
if (attrs[i].u.f.hasValue) {
key->usage = attrs[i].u.f.value;
}
break;
case NICI_A_KEY_SIZE:
if (attrs[i].u.f.hasValue) {
key->value_len = attrs[i].u.f.value / 8u;
if (key->value_len == 0u || key->value_len > NW_NICI_MAX_KEY_BYTES) {
key->value_len = nw_default_key_len(key->type);
}
}
break;
case NICI_A_GLOBAL:
if (attrs[i].u.f.hasValue) {
key->global = attrs[i].u.f.value ? 1u : 0u;
}
break;
case NICI_A_CLASS:
if (attrs[i].u.f.hasValue) {
key->klass = attrs[i].u.f.value;
}
break;
case NICI_A_KEY_FORMAT:
if (attrs[i].u.v.valuePtr && attrs[i].u.v.valueLen <= NW_NICI_MAX_FORMAT_BYTES) {
memcpy(key->format, attrs[i].u.v.valuePtr, attrs[i].u.v.valueLen);
key->format_len = attrs[i].u.v.valueLen;
}
break;
default:
break;
}
}
nw_random(key->value, key->value_len);
if (!key->format_len) {
nw_default_format(key);
}
if (key_size_changed) {
*key_size_changed = 0u;
}
*key_out = h;
return 0;
}
int CCS_GetRandom(NICI_CC_HANDLE context, void *buf, uint32_t len)
{
(void)context;
if (!buf && len) {
return -1;
}
return nw_random(buf, len);
}
int CCS_WrapKey(NICI_CC_HANDLE context, NICI_ALGORITHM *algorithm, uint32_t mode, uint32_t flags, NICI_OBJECT_HANDLE wrapping_key, NICI_OBJECT_HANDLE key_handle, void *wrapped_key, NICI_ULONG *wrapped_key_len)
{
NwNiciKey *key = nw_key(key_handle);
uint32_t needed;
uint8_t *p;
(void)context;
(void)algorithm;
(void)mode;
(void)flags;
(void)wrapping_key;
if (!key || !wrapped_key_len) {
return -1;
}
needed = 20u + key->value_len + key->format_len;
if (!wrapped_key) {
*wrapped_key_len = needed;
return 0;
}
if (*wrapped_key_len < needed) {
return -1;
}
p = (uint8_t *)wrapped_key;
p[0] = (uint8_t)(NW_NICI_WRAP_MAGIC >> 24);
p[1] = (uint8_t)(NW_NICI_WRAP_MAGIC >> 16);
p[2] = (uint8_t)(NW_NICI_WRAP_MAGIC >> 8);
p[3] = (uint8_t)NW_NICI_WRAP_MAGIC;
p[4] = (uint8_t)key->type;
p[5] = (uint8_t)key->usage;
p[6] = (uint8_t)key->global;
p[7] = (uint8_t)key->klass;
p[8] = (uint8_t)key->value_len;
p[9] = (uint8_t)key->format_len;
memset(p + 10, 0, 10);
memcpy(p + 20, key->value, key->value_len);
memcpy(p + 20 + key->value_len, key->format, key->format_len);
*wrapped_key_len = needed;
return 0;
}
int CCS_UnwrapKey(NICI_CC_HANDLE context, NICI_OBJECT_HANDLE wrapping_key, const void *wrapped_key, NICI_ULONG wrapped_key_len, NICI_OBJECT_HANDLE_PTR key_out)
{
const uint8_t *p = (const uint8_t *)wrapped_key;
NICI_OBJECT_HANDLE h;
NwNiciKey *key;
uint32_t magic;
(void)context;
(void)wrapping_key;
if (!p || wrapped_key_len < 20u || !key_out) {
return -1;
}
magic = ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | p[3];
if (magic != NW_NICI_WRAP_MAGIC) {
return -1;
}
h = nw_alloc_key();
key = nw_key(h);
if (!key) {
return -1;
}
key->type = p[4];
key->usage = p[5];
key->global = p[6];
key->klass = p[7];
key->value_len = p[8];
key->format_len = p[9];
if (key->value_len > NW_NICI_MAX_KEY_BYTES || key->format_len > NW_NICI_MAX_FORMAT_BYTES || 20u + key->value_len + key->format_len > wrapped_key_len) {
memset(key, 0, sizeof(*key));
return -1;
}
memcpy(key->value, p + 20, key->value_len);
memcpy(key->format, p + 20 + key->value_len, key->format_len);
*key_out = h;
return 0;
}
int CCS_DataEncryptInit(NICI_CC_HANDLE context, NICI_ALGORITHM *algorithm, NICI_OBJECT_HANDLE key_handle)
{
NwNiciContext *ctx = nw_context(context);
if (!ctx || !nw_key(key_handle)) {
return -1;
}
ctx->active_key = key_handle;
ctx->active_decrypt = 0u;
nw_get_iv(algorithm, ctx->active_iv, &ctx->active_iv_len);
return 0;
}
int CCS_DataDecryptInit(NICI_CC_HANDLE context, NICI_ALGORITHM *algorithm, NICI_OBJECT_HANDLE key_handle)
{
NwNiciContext *ctx = nw_context(context);
if (!ctx || !nw_key(key_handle)) {
return -1;
}
ctx->active_key = key_handle;
ctx->active_decrypt = 1u;
nw_get_iv(algorithm, ctx->active_iv, &ctx->active_iv_len);
return 0;
}
static uint32_t nw_len_get(const void *p)
{
return p ? *(const uint32_t *)p : 0u;
}
static void nw_len_set(void *p, uint32_t v)
{
if (p) {
*(uint32_t *)p = v;
}
}
int CCS_Encrypt(NICI_CC_HANDLE context, const void *in, uint32_t in_len, void *out, void *out_len)
{
NwNiciContext *ctx = nw_context(context);
NwNiciKey *key = ctx ? nw_key(ctx->active_key) : NULL;
if (!key || !in || !out || !out_len) {
return -1;
}
if (nw_len_get(out_len) < in_len) {
return -1;
}
nw_crypt_buffer(key, ctx->active_iv, ctx->active_iv_len, in, in_len, out);
nw_len_set(out_len, in_len);
return 0;
}
int CCS_Decrypt(NICI_CC_HANDLE context, const void *in, uint32_t in_len, void *out, void *out_len)
{
return CCS_Encrypt(context, in, in_len, out, out_len);
}
int CCS_FindObjectsInit(NICI_CC_HANDLE context, NICI_ATTRIBUTE_PTR attrs, uint32_t attr_count)
{
NwNiciContext *ctx = nw_context(context);
uint32_t i;
if (!ctx) {
return -1;
}
ctx->find_global_set = 0u;
ctx->find_feature_set = 0u;
for (i = 0; attrs && i < attr_count; ++i) {
if (attrs[i].type == NICI_A_GLOBAL && attrs[i].u.f.hasValue) {
ctx->find_global = attrs[i].u.f.value ? 1u : 0u;
ctx->find_global_set = 1u;
} else if (attrs[i].type == NICI_A_FEATURE && attrs[i].u.f.hasValue) {
ctx->find_feature = attrs[i].u.f.value;
ctx->find_feature_set = 1u;
}
}
return 0;
}
static NICI_OBJECT_HANDLE nw_find_first_key(const NwNiciContext *ctx)
{
uint32_t i;
for (i = 0; i < NW_NICI_MAX_KEYS; ++i) {
if (!g_keys[i].used) {
continue;
}
if (ctx->find_global_set && g_keys[i].global != ctx->find_global) {
continue;
}
if (ctx->find_feature_set && (g_keys[i].usage & ctx->find_feature) != ctx->find_feature && ctx->find_feature != NICI_AV_STORAGE) {
continue;
}
return i + 1u;
}
return 0;
}
static NICI_OBJECT_HANDLE nw_create_default_global_key(void)
{
NICI_OBJECT_HANDLE h = nw_alloc_key();
NwNiciKey *key = nw_key(h);
if (!key) {
return 0;
}
key->type = NICI_K_DES3X;
key->usage = NICI_F_DATA_ENCRYPT | NICI_F_DATA_DECRYPT | NICI_F_EXTRACT | NICI_F_WRAP | NICI_F_UNWRAP | NICI_F_KM_ENCRYPT | NICI_F_KM_DECRYPT;
key->klass = NICI_O_SECRET_KEY;
key->global = 1u;
key->value_len = 24u;
nw_random(key->value, key->value_len);
nw_default_format(key);
return h;
}
int CCS_FindObjects(NICI_CC_HANDLE context, NICI_OBJECT_HANDLE_PTR objects, void *object_count)
{
NwNiciContext *ctx = nw_context(context);
NICI_OBJECT_HANDLE found;
if (!ctx || !objects || !object_count) {
return -1;
}
found = nw_find_first_key(ctx);
if (!found) {
found = nw_create_default_global_key();
}
if (found && nw_len_get(object_count) > 0u) {
*objects = found;
nw_len_set(object_count, 1u);
} else {
nw_len_set(object_count, 0u);
}
return 0;
}
int CCS_FindObjectsFinal(NICI_CC_HANDLE context)
{
(void)context;
return 0;
}
int CCS_DigestInit(NICI_CC_HANDLE context, NICI_ALGORITHM *algorithm)
{
(void)context;
(void)algorithm;
return 0;
}
int CCS_Digest(NICI_CC_HANDLE context, const void *in, uint32_t in_len, void *out, void *out_len)
{
uint32_t len;
(void)context;
if (!out || !out_len) {
return -1;
}
len = nw_len_get(out_len);
if (len == 0u) {
return -1;
}
nw_fill_digest(in, in_len, out, len);
nw_len_set(out_len, len);
return 0;
}
static void nw_password_stream(const void *password, const uint8_t *salt, uint32_t salt_len, const void *in, uint32_t in_len, void *out)
{
const uint8_t *src = (const uint8_t *)in;
const uint8_t *pwd = (const uint8_t *)password;
uint8_t *dst = (uint8_t *)out;
uint32_t pwd_len = 0u;
uint32_t seed;
uint32_t i;
if (pwd) {
while (pwd_len < 1024u && !(pwd[pwd_len] == 0 && pwd[pwd_len + 1u] == 0)) {
++pwd_len;
}
pwd_len += 2u;
}
seed = nw_hash_bytes(pwd, pwd_len, 0x70626531u) ^ nw_hash_bytes(salt, salt_len, 0x73616c74u);
for (i = 0; i < in_len; ++i) {
seed = seed * 1664525u + 1013904223u + i;
dst[i] = (uint8_t)(src[i] ^ (uint8_t)(seed >> 24));
}
}
static void nw_get_salt(const NICI_ALGORITHM *algorithm, const uint8_t **salt, uint32_t *salt_len)
{
uint32_t i;
*salt = NULL;
*salt_len = 0u;
if (!algorithm || !algorithm->parameter) {
return;
}
for (i = 0; i < algorithm->parameter->count && i < 4u; ++i) {
NICI_PARAMETER_DATA *p = &algorithm->parameter->parms[i];
if (p->parmType == NICI_P_SALT && p->u.b.ptr && p->u.b.len) {
*salt = (const uint8_t *)p->u.b.ptr;
*salt_len = p->u.b.len;
return;
}
}
}
int CCS_pbeEncrypt(NICI_CC_HANDLE context, NICI_ALGORITHM *algorithm, const void *password, const void *in, uint32_t in_len, void *out, void *out_len)
{
const uint8_t *salt;
uint32_t salt_len;
(void)context;
if (!in || !out || !out_len || nw_len_get(out_len) < in_len) {
return -1;
}
nw_get_salt(algorithm, &salt, &salt_len);
nw_password_stream(password, salt, salt_len, in, in_len, out);
nw_len_set(out_len, in_len);
return 0;
}
int CCS_pbeDecrypt(NICI_CC_HANDLE context, NICI_ALGORITHM *algorithm, const void *password, const void *in, uint32_t in_len, void *out, void *out_len)
{
return CCS_pbeEncrypt(context, algorithm, password, in, in_len, out, out_len);
}
int CCS_InjectKey(NICI_CC_HANDLE context, NICI_ATTRIBUTE_PTR attrs, nuint32 attr_count, NICI_OBJECT_HANDLE_PTR key_out)
{
NICI_OBJECT_HANDLE h;
NwNiciKey *key;
uint32_t i;
(void)context;
if (!key_out) {
return -1;
}
h = nw_alloc_key();
key = nw_key(h);
if (!key) {
return -1;
}
key->type = NICI_K_AES;
key->usage = NICI_F_DATA_ENCRYPT | NICI_F_DATA_DECRYPT | NICI_F_EXTRACT;
key->klass = NICI_O_SECRET_KEY;
key->value_len = 16u;
for (i = 0; attrs && i < attr_count; ++i) {
switch (attrs[i].type) {
case NICI_A_KEY_TYPE:
if (attrs[i].u.f.hasValue) key->type = attrs[i].u.f.value;
break;
case NICI_A_KEY_USAGE:
if (attrs[i].u.f.hasValue) key->usage = attrs[i].u.f.value;
break;
case NICI_A_GLOBAL:
if (attrs[i].u.f.hasValue) key->global = attrs[i].u.f.value ? 1u : 0u;
break;
case NICI_A_CLASS:
if (attrs[i].u.f.hasValue) key->klass = attrs[i].u.f.value;
break;
case NICI_A_KEY_VALUE:
if (attrs[i].u.v.valuePtr && attrs[i].u.v.valueLen <= NW_NICI_MAX_KEY_BYTES) {
memcpy(key->value, attrs[i].u.v.valuePtr, attrs[i].u.v.valueLen);
key->value_len = attrs[i].u.v.valueLen;
}
break;
case NICI_A_KEY_FORMAT:
if (attrs[i].u.v.valuePtr && attrs[i].u.v.valueLen <= NW_NICI_MAX_FORMAT_BYTES) {
memcpy(key->format, attrs[i].u.v.valuePtr, attrs[i].u.v.valueLen);
key->format_len = attrs[i].u.v.valueLen;
}
break;
default:
break;
}
}
if (key->value_len == 0u) {
key->value_len = nw_default_key_len(key->type);
nw_random(key->value, key->value_len);
}
if (!key->format_len) {
nw_default_format(key);
}
*key_out = h;
return 0;
}
int CCS_ExtractKey(NICI_CC_HANDLE context, NICI_OBJECT_HANDLE key_handle, NICI_ATTRIBUTE_PTR attrs, nuint32 attr_count)
{
NwNiciKey *key = nw_key(key_handle);
(void)context;
if (!key || !attrs) {
return -1;
}
return nw_copy_key_to_attrs(key, attrs, attr_count, 1u);
}