smartcard: add filesystem and emulation base

master
Shiz 4 years ago
parent 8f7b372d72
commit d0bc7fc18f
  1. 18
      Makefile
  2. 2
      ext/emu8051
  3. 4
      src/build.mk
  4. 13
      src/smartcard/build.mk
  5. 91
      src/smartcard/emu.c
  6. 24
      src/smartcard/emu.h
  7. 12
      src/smartcard/error.h
  8. 219
      src/smartcard/fs.c
  9. 81
      src/smartcard/fs.h
  10. 140
      src/smartcard/smartcard.c
  11. 14
      src/smartcard/smartcard.h
  12. 17
      src/util.c
  13. 32
      src/util.h

@ -1,19 +1,23 @@
CFLAGS = -std=c99
SRCS =
OBJS =
BIN = nonsenselock
ROOT = $(dir $(abspath $(firstword $(MAKEFILE_LIST))))
include $(ROOT)/src/build.mk
.PHONY: all
all: $(BIN)
.PHONY: clean
clean:
rm -f $(OBJS) $(BIN)
OBJS = $(addprefix obj/,$(SRCS:.c=.o))
include $(ROOT)/src/build.mk
$(BIN): $(OBJS)
OBJS += $(addprefix obj/,$(SRCS:.c=.o))
$(BIN): $(OBJS) $(EXT_OBJS)
obj/%.o: src/%.c
@mkdir -p $(dir $@)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $^ -o $@
.PHONY: clean
clean:
rm -f $(OBJS) $(BIN)

@ -1 +1 @@
Subproject commit b93d1da3a93b83175308e390526b476b1557977a
Subproject commit 130e9ea9852820e375f1175b678b80d6a5467b05

@ -1,4 +1,6 @@
SRCS += dongle.c
SRCS += \
util.c \
dongle.c
include $(ROOT)/src/transport/build.mk
include $(ROOT)/src/smartcard/build.mk

@ -0,0 +1,13 @@
SRCS += \
smartcard/emu.c \
smartcard/fs.o \
smartcard/smartcard.o
OBJS += \
ext/emu8051/libem8051.a
ext/emu8051/libem8051.a:
cd $(dir $@) && make CPPFLAGS=-DEM8051_MINIMAL=1 $(notdir $@)
CPPFLAGS += -I ext/emu8051

@ -0,0 +1,91 @@
#include <stdlib.h>
#include <string.h>
#include "emu.h"
int nsl_smartcard_emu_init(struct nsl_smartcard_emu *emu, size_t code_size, size_t ext_data_size)
{
memset(&emu->cpu, 0, sizeof(emu->cpu));
emu->cpu.mCodeMem = malloc(code_size);
if (!emu->cpu.mCodeMem)
goto err;
emu->cpu.mCodeMemSize = code_size;
emu->cpu.mExtData = malloc(ext_data_size);
if (!emu->cpu.mExtData)
goto err;
emu->cpu.mExtDataSize = ext_data_size;
emu->cpu.mLowerData = malloc(128);
if (!emu->cpu.mLowerData)
goto err;
emu->cpu.mUpperData = malloc(128);
if (!emu->cpu.mUpperData)
goto err;
emu->cpu.mSFR = malloc(128);
if (!emu->cpu.mSFR)
goto err;
em8051_reset(&emu->cpu, 0);
return 0;
err:
if (emu->cpu.mCodeMem)
free(emu->cpu.mCodeMem);
if (emu->cpu.mExtData)
free(emu->cpu.mExtData);
if (emu->cpu.mLowerData)
free(emu->cpu.mLowerData);
if (emu->cpu.mUpperData)
free(emu->cpu.mUpperData);
return 1;
}
void nsl_smartcard_emu_reset(struct nsl_smartcard_emu *emu, int wipe)
{
em8051_reset(&emu->cpu, wipe);
}
uint8_t nsl_smartcard_emu_read(struct nsl_smartcard_emu *emu, enum nsl_smartcard_emu_bank bank, uint16_t addr)
{
switch (bank) {
case NSL_SMARTCARD_EMU_BANK_CODE:
return emu->cpu.mCodeMem[addr];
case NSL_SMARTCARD_EMU_BANK_DATA:
if (addr < 128) {
return emu->cpu.mLowerData[addr];
} else {
return emu->cpu.mUpperData[addr - 128];
}
case NSL_SMARTCARD_EMU_BANK_EXT_DATA:
return emu->cpu.mExtData[addr];
}
}
void nsl_smartcard_emu_write(struct nsl_smartcard_emu *emu, enum nsl_smartcard_emu_bank bank, uint16_t addr, uint8_t value)
{
switch (bank) {
case NSL_SMARTCARD_EMU_BANK_CODE:
emu->cpu.mCodeMem[addr] = value;
case NSL_SMARTCARD_EMU_BANK_DATA:
if (addr < 128) {
emu->cpu.mLowerData[addr] = value;
} else {
emu->cpu.mUpperData[addr - 128] = value;
}
case NSL_SMARTCARD_EMU_BANK_EXT_DATA:
emu->cpu.mExtData[addr] = value;
}
}
void nsl_smartcard_emu_read_range(struct nsl_smartcard_emu *emu, enum nsl_smartcard_emu_bank bank, uint16_t addr, uint8_t *buf, size_t len)
{
for (size_t i = 0; i < len; i++) {
buf[i] = nsl_smartcard_emu_read(emu, bank, addr + i);
}
}
void nsl_smartcard_emu_write_range(struct nsl_smartcard_emu *emu, enum nsl_smartcard_emu_bank bank, uint16_t addr, uint8_t *buf, size_t len)
{
for (size_t i = 0; i < len; i++) {
nsl_smartcard_emu_write(emu, bank, addr + i, buf[i]);
}
}

@ -0,0 +1,24 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <emu8051.h>
struct nsl_smartcard_emu
{
struct em8051 cpu;
};
enum nsl_smartcard_emu_bank
{
NSL_SMARTCARD_EMU_BANK_CODE,
NSL_SMARTCARD_EMU_BANK_DATA,
NSL_SMARTCARD_EMU_BANK_EXT_DATA,
};
int nsl_smartcard_emu_init(struct nsl_smartcard_emu *, size_t code_size, size_t ext_data_size);
void nsl_smartcard_emu_reset(struct nsl_smartcard_emu *, int wipe);
uint8_t nsl_smartcard_emu_read(struct nsl_smartcard_emu *, enum nsl_smartcard_emu_bank bank, uint16_t addr);
void nsl_smartcard_emu_write(struct nsl_smartcard_emu *, enum nsl_smartcard_emu_bank bank, uint16_t addr, uint8_t value);
void nsl_smartcard_emu_read_range(struct nsl_smartcard_emu *, enum nsl_smartcard_emu_bank bank, uint16_t addr, uint8_t *buf, size_t len);
void nsl_smartcard_emu_write_range(struct nsl_smartcard_emu *, enum nsl_smartcard_emu_bank bank, uint16_t addr, uint8_t *buf, size_t len);

@ -0,0 +1,12 @@
enum nsl_smartcard_error
{
NSL_SMARTCARD_ERROR_NONE = 0,
NSL_SMARTCARD_ERROR_WRONG_TYPE,
NSL_SMARTCARD_ERROR_WRONG_ID,
NSL_SMARTCARD_ERROR_WRONG_VALUE,
NSL_SMARTCARD_ERROR_NOT_FOUND,
NSL_SMARTCARD_ERROR_IN_USE,
NSL_SMARTCARD_ERROR_UNAUTHORIZED,
NSL_SMARTCARD_ERROR_ALREADY_EXISTS,
NSL_SMARTCARD_ERROR_NO_MEMORY,
};

@ -0,0 +1,219 @@
#include <string.h>
#include <stdlib.h>
#include "fs.h"
#include "error.h"
#include "../util.h"
#define NSL_SMARTCARD_USER_PIN_DEFAULT "12345678"
#define NSL_SMARTCARD_DEV_PIN_DEFAULT "123456781234567812345678"
#define NSL_SMARTCARD_PIN_LEN_REPORT_CUTOFF 16
static inline void init_common(struct nsl_smartcard_file *file, uint16_t id, enum nsl_smartcard_file_type type)
{
file->parent = NULL;
file->next = NULL;
file->id = id;
file->type = type;
}
static inline int is_authorized(struct nsl_smartcard_file *file, enum nsl_smartcard_auth_level level)
{
if (!nsl_smartcard_is_dir(file)) {
return 0;
}
return file->contents.dir.auth >= level;
}
int nsl_smartcard_file_init(struct nsl_smartcard_file *file, uint16_t id, enum nsl_smartcard_file_type type)
{
init_common(file, id, type);
if (!nsl_smartcard_is_file(file)) {
return NSL_SMARTCARD_ERROR_WRONG_TYPE;
}
file->contents.file.data = NULL;
file->contents.file.len = 0;
return 0;
}
int nsl_smartcard_file_read(struct nsl_smartcard_file *file, const uint8_t **data, size_t *len, enum nsl_smartcard_file_type type)
{
if (!nsl_smartcard_is_file(file) || file->type != type) {
return NSL_SMARTCARD_ERROR_WRONG_TYPE;
}
switch (file->type) {
case NSL_SMARTCARD_FILE_EXECUTABLE:
if (!is_authorized(file, NSL_SMARTCARD_AUTH_DEV)) {
return NSL_SMARTCARD_ERROR_UNAUTHORIZED;
}
break;
case NSL_SMARTCARD_FILE_DATA:
case NSL_SMARTCARD_FILE_KEY:
if (!is_authorized(file, NSL_SMARTCARD_AUTH_INTERNAL)) {
return NSL_SMARTCARD_ERROR_UNAUTHORIZED;
}
break;
default:
return NSL_SMARTCARD_ERROR_UNAUTHORIZED;
}
*data = file->contents.file.data;
*len = file->contents.file.len;
return 0;
}
int nsl_smartcard_dir_init(struct nsl_smartcard_file *file, uint16_t id)
{
init_common(file, id, NSL_SMARTCARD_FILE_DIR);
file->contents.dir.children = NULL;
file->contents.dir.auth = NSL_SMARTCARD_AUTH_NONE;
file->contents.dir.auth_attempts = 0;
memcpy(file->contents.dir.user_pin, NSL_SMARTCARD_USER_PIN_DEFAULT, sizeof(file->contents.dir.user_pin));
memcpy(file->contents.dir.dev_pin, NSL_SMARTCARD_DEV_PIN_DEFAULT, sizeof(file->contents.dir.user_pin));
return 0;
}
int nsl_smartcard_dir_authorize(struct nsl_smartcard_file *file, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level)
{
if (!nsl_smartcard_is_dir(file)) {
return NSL_SMARTCARD_ERROR_WRONG_TYPE;
}
const uint8_t *match_pin;
size_t match_len;
switch (level) {
case NSL_SMARTCARD_AUTH_NONE:
match_pin = NULL;
match_len = 0;
break;
case NSL_SMARTCARD_AUTH_USER:
match_pin = file->contents.dir.user_pin;
match_len = sizeof(file->contents.dir.user_pin);
break;
case NSL_SMARTCARD_AUTH_DEV:
match_pin = file->contents.dir.dev_pin;
match_len = sizeof(file->contents.dir.dev_pin);
break;
default:
return NSL_SMARTCARD_ERROR_WRONG_VALUE;
}
if (len != match_len) {
return NSL_SMARTCARD_ERROR_WRONG_VALUE;
}
if (nsl_util_memcmp(match_pin, pin, match_len)) {
if (match_len > NSL_SMARTCARD_PIN_LEN_REPORT_CUTOFF && !nsl_util_memcmp(match_pin, pin, NSL_SMARTCARD_PIN_LEN_REPORT_CUTOFF)) {
file->contents.dir.auth_attempts++;
}
return NSL_SMARTCARD_ERROR_UNAUTHORIZED;
}
if (match_len > NSL_SMARTCARD_PIN_LEN_REPORT_CUTOFF) {
file->contents.dir.auth_attempts = 0;
}
file->contents.dir.auth = level;
return 0;
}
int nsl_smartcard_dir_change_pin(struct nsl_smartcard_file *file, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level)
{
if (!nsl_smartcard_is_dir(file)) {
return NSL_SMARTCARD_ERROR_WRONG_TYPE;
}
if (!is_authorized(file, level)) {
return NSL_SMARTCARD_ERROR_UNAUTHORIZED;
}
uint8_t *target_pin;
size_t target_len;
switch (level) {
case NSL_SMARTCARD_AUTH_USER:
target_pin = file->contents.dir.user_pin;
target_len = sizeof(file->contents.dir.user_pin);
break;
case NSL_SMARTCARD_AUTH_DEV:
target_pin = file->contents.dir.dev_pin;
target_len = sizeof(file->contents.dir.dev_pin);
break;
default:
return NSL_SMARTCARD_ERROR_WRONG_VALUE;
}
if (target_len != len) {
return NSL_SMARTCARD_ERROR_WRONG_VALUE;
}
memcpy(target_pin, pin, target_len);
return 0;
}
int nsl_smartcard_dir_add(struct nsl_smartcard_file *file, struct nsl_smartcard_file *child)
{
if (!nsl_smartcard_is_dir(file)) {
return NSL_SMARTCARD_ERROR_WRONG_TYPE;
}
if (file->id == NSL_SMARTCARD_ROOT_DIR_ID) {
return NSL_SMARTCARD_ERROR_WRONG_ID;
}
if (!is_authorized(file, NSL_SMARTCARD_AUTH_DEV)) {
return NSL_SMARTCARD_ERROR_UNAUTHORIZED;
}
if (child->parent || child->next) {
return NSL_SMARTCARD_ERROR_IN_USE;
}
if (file->id == child->id || (file->parent && file->parent->id == child->id)) {
return NSL_SMARTCARD_ERROR_WRONG_ID;
}
if (nsl_smartcard_dir_find(file, child->id, NULL)) {
return NSL_SMARTCARD_ERROR_WRONG_ID;
}
child->parent = file;
child->next = file->contents.dir.children;
file->contents.dir.children = child;
return 0;
}
int nsl_smartcard_dir_find(struct nsl_smartcard_file *file, uint16_t id, struct nsl_smartcard_file **child)
{
if (!nsl_smartcard_is_dir(file)) {
return NSL_SMARTCARD_ERROR_WRONG_TYPE;
}
for (struct nsl_smartcard_file *f = file->contents.dir.children; f; f = f->next) {
if (f->id == id) {
if (child) {
*child = f;
}
return 0;
}
}
return NSL_SMARTCARD_ERROR_NOT_FOUND;
}
int nsl_smartcard_dir_clear(struct nsl_smartcard_file *file)
{
if (!nsl_smartcard_is_dir(file)) {
return NSL_SMARTCARD_ERROR_WRONG_TYPE;
}
if (!is_authorized(file, NSL_SMARTCARD_AUTH_DEV)) {
return NSL_SMARTCARD_ERROR_UNAUTHORIZED;
}
struct nsl_smartcard_file *prev = NULL, *f = file->contents.dir.children;
while (f) {
if (nsl_smartcard_is_dir(f)) {
nsl_smartcard_dir_clear(f);
prev = f;
f = f->next;
} else {
struct nsl_smartcard_file *next = f->next;
free(f);
prev->next = f;
f = next;
}
}
return 0;
}

@ -0,0 +1,81 @@
#include <stdint.h>
#include <stddef.h>
#define NSL_SMARTCARD_USER_PIN_LEN 8
#define NSL_SMARTCARD_DEV_PIN_LEN 24
#define NSL_SMARTCARD_ROOT_DIR_ID 0x3F00
enum nsl_smartcard_auth_level
{
NSL_SMARTCARD_AUTH_NONE,
NSL_SMARTCARD_AUTH_USER,
NSL_SMARTCARD_AUTH_DEV,
NSL_SMARTCARD_AUTH_INTERNAL,
};
enum nsl_smartcard_file_type
{
NSL_SMARTCARD_FILE_EXECUTABLE,
NSL_SMARTCARD_FILE_DATA,
NSL_SMARTCARD_FILE_KEY,
NSL_SMARTCARD_FILE_DIR,
NSL_SMARTCARD_FILE_MODULE,
};
struct nsl_smartcard_file_contents
{
uint8_t *data;
size_t len;
};
struct nsl_smartcard_dir_contents
{
struct nsl_smartcard_file *children;
uint8_t user_pin[NSL_SMARTCARD_USER_PIN_LEN];
uint8_t dev_pin[NSL_SMARTCARD_DEV_PIN_LEN];
enum nsl_smartcard_auth_level auth;
uint8_t auth_attempts;
};
struct nsl_smartcard_file
{
struct nsl_smartcard_file *parent;
struct nsl_smartcard_file *next;
enum nsl_smartcard_file_type type;
uint16_t id;
union {
struct nsl_smartcard_file_contents file;
struct nsl_smartcard_dir_contents dir;
} contents;
};
static inline int nsl_smartcard_is_dir(struct nsl_smartcard_file *file)
{
return file->type == NSL_SMARTCARD_FILE_DIR;
}
static inline int nsl_smartcard_is_file(struct nsl_smartcard_file *file)
{
switch (file->type) {
case NSL_SMARTCARD_FILE_DATA:
case NSL_SMARTCARD_FILE_EXECUTABLE:
case NSL_SMARTCARD_FILE_KEY:
return 1;
default:
return 0;
}
}
int nsl_smartcard_file_init(struct nsl_smartcard_file *, uint16_t id, enum nsl_smartcard_file_type type);
int nsl_smartcard_file_read(struct nsl_smartcard_file *, const uint8_t **data, size_t *len, enum nsl_smartcard_file_type type);
int nsl_smartcard_dir_init(struct nsl_smartcard_file *, uint16_t id);
int nsl_smartcard_dir_authorize(struct nsl_smartcard_file *, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level);
int nsl_smartcard_dir_change_pin(struct nsl_smartcard_file *, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level);
int nsl_smartcard_dir_add(struct nsl_smartcard_file *, struct nsl_smartcard_file *child);
int nsl_smartcard_dir_find(struct nsl_smartcard_file *, uint16_t id, struct nsl_smartcard_file **child);
int nsl_smartcard_dir_clear(struct nsl_smartcard_file *);

@ -0,0 +1,140 @@
#include <stdlib.h>
#include <string.h>
#include "smartcard.h"
#include "error.h"
#include "../util.h"
#define NSL_SMARTCARD_DIR_SEP "\\"
static int parse_file_name(const char *name, uint16_t *id)
{
uint8_t pname[2];
if (nsl_util_fromhex(name, pname, sizeof(pname))) {
return 0;
}
*id = (pname[0] << 8) | pname[1];
return 1;
}
int nsl_smartcard_init(struct nsl_smartcard *smartcard)
{
smartcard->rootdir = smartcard->curdir = NULL;
nsl_smartcard_emu_init(&smartcard->emu, 0xFFFF, 0xFFFF);
return nsl_smartcard_reset(smartcard);
}
int nsl_smartcard_reset(struct nsl_smartcard *smartcard)
{
smartcard->curdir = smartcard->rootdir;
nsl_smartcard_emu_reset(&smartcard->emu, 1);
return 0;
}
int nsl_smartcard_authorize(struct nsl_smartcard *smartcard, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level)
{
if (!smartcard->curdir) {
return NSL_SMARTCARD_ERROR_NOT_FOUND;
}
return nsl_smartcard_dir_authorize(smartcard->curdir, pin, len, level);
}
int nsl_smartcard_change_pin(struct nsl_smartcard *smartcard, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level)
{
if (!smartcard->curdir) {
return NSL_SMARTCARD_ERROR_NOT_FOUND;
}
return nsl_smartcard_dir_authorize(smartcard->curdir, pin, len, level);
}
int nsl_smartcard_mkdir(struct nsl_smartcard *smartcard, const char *name)
{
uint16_t id;
if (!parse_file_name(name, &id)) {
return NSL_SMARTCARD_ERROR_WRONG_VALUE;
}
if (!smartcard->curdir) {
return NSL_SMARTCARD_ERROR_NOT_FOUND;
}
struct nsl_smartcard_file *parent = smartcard->curdir;
if (nsl_smartcard_dir_find(parent, id, NULL)) {
return NSL_SMARTCARD_ERROR_ALREADY_EXISTS;
}
struct nsl_smartcard_file *dir = malloc(sizeof(*dir));
if (!dir) {
return NSL_SMARTCARD_ERROR_NO_MEMORY;
}
int err = nsl_smartcard_dir_init(dir, id);
if (err) {
goto err;
}
err = nsl_smartcard_dir_add(parent, dir);
if (err) {
goto err;
}
return 0;
err:
free(dir);
return err;
}
int nsl_smartcard_chdir(struct nsl_smartcard *smartcard, char *name)
{
struct nsl_smartcard_file *dir;
if (!strcmp(name, NSL_SMARTCARD_DIR_SEP)) {
dir = smartcard->rootdir;
name += sizeof(NSL_SMARTCARD_DIR_SEP) - 1;
} else {
dir = smartcard->curdir;
}
if (!dir) {
return NSL_SMARTCARD_ERROR_NOT_FOUND;
}
do {
char *seg = strsep(&name, NSL_SMARTCARD_DIR_SEP);
uint16_t id;
if (!parse_file_name(seg, &id)) {
return NSL_SMARTCARD_ERROR_WRONG_VALUE;
}
if (nsl_smartcard_dir_find(dir, id, &dir)) {
return NSL_SMARTCARD_ERROR_NOT_FOUND;
}
if (!nsl_smartcard_is_dir(dir)) {
return NSL_SMARTCARD_ERROR_WRONG_TYPE;
}
} while (name);
smartcard->curdir = dir;
return 0;
}
int nsl_smartcard_exec(struct nsl_smartcard *smartcard, const char *name, const uint8_t *inbuf, size_t inlen, uint8_t *outbuf, size_t outlen)
{
uint16_t id;
if (!parse_file_name(name, &id)) {
return NSL_SMARTCARD_ERROR_WRONG_VALUE;
}
if (!smartcard->curdir) {
return NSL_SMARTCARD_ERROR_NOT_FOUND;
}
struct nsl_smartcard_file *file;
if (nsl_smartcard_dir_find(smartcard->curdir, id, &file)) {
return NSL_SMARTCARD_ERROR_NOT_FOUND;
}
const uint8_t *data;
size_t len;
int err = nsl_smartcard_file_read(file, &data, &len, NSL_SMARTCARD_FILE_EXECUTABLE);
if (err) {
return err;
}
/* TODO: setup VM and run. */
return 0;
}

@ -1,10 +1,22 @@
#pragma once
#include <stdint.h>
struct nsl_smartcard {
#include "fs.h"
#include "emu.h"
struct nsl_smartcard {
struct nsl_smartcard_file *rootdir;
struct nsl_smartcard_file *curdir;
struct nsl_smartcard_emu emu;
};
int nsl_smartcard_init(struct nsl_smartcard *smartcard);
int nsl_smartcard_reset(struct nsl_smartcard *smartcard);
int nsl_smartcard_authorize(struct nsl_smartcard *smartcard, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level);
int nsl_smartcard_change_pin(struct nsl_smartcard *smartcard, const uint8_t *pin, size_t len, enum nsl_smartcard_auth_level level);
int nsl_smartcard_mkdir(struct nsl_smartcard *smartcard, const char *dir);
int nsl_smartcard_chdir(struct nsl_smartcard *smartcard, char *name);
int nsl_smartcard_exec(struct nsl_smartcard *smarcard, const char *name, const uint8_t *inbuf, size_t inlen, uint8_t *outbuf, size_t outlen);
int nsl_smartcard_process(struct nsl_smartcard *smartcard, const uint8_t *inbuf, size_t inlen, uint8_t *outbuf, size_t outlen);

@ -0,0 +1,17 @@
#include "util.h"
/* taken from: https://github.com/chmike/cst_time_memcmp/blob/f09ad819bb381e7de290844fa1f6429423db8dc9/consttime_memcmp.c */
int nsl_util_memcmp(const uint8_t *c1, const uint8_t *c2, size_t len)
{
uint16_t d, r, m;
volatile uint16_t v;
for (r = 0; len; c1++, c2++, len--) {
v = ((uint16_t)(uint8_t)r)+255;
m = v/256-1;
d = (uint16_t)((int)*c1 - (int)*c2);
r |= (d & m);
}
return (int)((int32_t)(int16_t)((uint32_t)r + 0x8000) - 0x8000);
}

@ -0,0 +1,32 @@
#include <stdint.h>
#include <ctype.h>
int nsl_util_memcmp(const uint8_t *left, const uint8_t *right, size_t len);
static inline int nsl_util_fromhexdigit(int c)
{
c = tolower(c);
if (c >= '0' && c <= '9') {
return c - '0';
}
if (c >= 'a' && c <= 'f') {
return 10 + (c - 'a');
}
return -1;
}
static inline int nsl_util_fromhex(const char *src, unsigned char *dest, size_t len)
{
while (*src && len--) {
unsigned char a = nsl_util_fromhexdigit(*src++);
if (a < 0) {
return 0;
}
unsigned char b = nsl_util_fromhexdigit(*src++);
if (b < 0) {
return 0;
}
*dest++ = (a << 4) | b;
}
return !*src && !len;
}
Loading…
Cancel
Save