Version 1.08 with public source code release.

This commit is contained in:
icex2
2020-10-03 20:56:55 +02:00
parent 656148121d
commit 762bf140c0
555 changed files with 55502 additions and 3 deletions
+518
View File
@@ -0,0 +1,518 @@
#include <stdlib.h>
#include <string.h>
#include "util/log.h"
#include "util/mem.h"
#include "util/str.h"
#include "asn1.h"
static uint32_t sec_hasp_asn1_decode_int(const uint8_t* buffer, size_t* offset, uint32_t blen);
static uint8_t* sec_hasp_asn1_decode_data(const uint8_t* buffer, size_t* offset, uint32_t blen);
static char* sec_hasp_asn1_decode_str(const uint8_t* buffer, size_t* offset, uint32_t blen);
static uint32_t sec_hasp_asn1_decode_length(const uint8_t* buffer, size_t* offset);
static uint16_t sec_hasp_asn1_decode_tag(const uint8_t* buffer, size_t* offset);
static void sec_hasp_asn1_encode_int(uint32_t val, uint8_t* buffer, size_t* offset);
static void sec_hasp_asn1_encode_data(const uint8_t* data, size_t len, uint8_t* buffer, size_t* offset);
static void sec_hasp_asn1_encode_str(const char* str, uint8_t* buffer, size_t* offset);
static void sec_hasp_asn1_encode_length(uint32_t len, uint8_t* buffer, size_t* offset);
static void sec_hasp_asn1_encode_tag(uint16_t tag, uint8_t* buffer, size_t* offset);
struct sec_hasp_asn1_store* sec_hasp_asn1_object_store_alloc(uint16_t oid, uint32_t size)
{
struct sec_hasp_asn1_store* tmp = malloc(sizeof(struct sec_hasp_asn1_store));
tmp->objects = malloc(sizeof(struct sec_hasp_asn1_object) * size);
tmp->capacity = size;
tmp->oid = oid;
tmp->pos = 0;
memset(tmp->objects, 0, sizeof(struct sec_hasp_asn1_object) * size);
return tmp;
}
void sec_hasp_asn1_store_free(struct sec_hasp_asn1_store* store)
{
for (size_t i = 0; i < store->pos; i++) {
if (store->objects[i].type == SEC_HASP_ASN1_VT_STR) {
free(store->objects[i].str);
} else if (store->objects[i].type == SEC_HASP_ASN1_VT_DATA) {
free(store->objects[i].data);
}
}
free(store);
}
void sec_hasp_asn1_object_add_int(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t value)
{
if (store->pos == store->capacity) {
return;
}
store->objects[store->pos].tag = tag;
store->objects[store->pos].type = SEC_HASP_ASN1_VT_INT;
/* Determine length, considers padding for encoding later as well */
// TODO not sure if this is correct, ask mario
if (value <= 0xFF) {
store->objects[store->pos].blen = 1;
} else if (value <= 0xFFFF) {
store->objects[store->pos].blen = 2;
} else if (value <= 0xFFFFFF) {
store->objects[store->pos].blen = 3;
} else if (value <= 0x7FFFFFFF) {
store->objects[store->pos].blen = 4;
} else {
store->objects[store->pos].blen = 5;
}
store->objects[store->pos].int_val = value;
store->pos++;
}
void sec_hasp_asn1_object_add_str(struct sec_hasp_asn1_store* store, uint16_t tag, const char* str)
{
if (store->pos == store->capacity) {
return;
}
store->objects[store->pos].tag = tag;
store->objects[store->pos].type = SEC_HASP_ASN1_VT_STR;
/* Store len + null terminator */
store->objects[store->pos].blen = strlen(str) + 1;
store->objects[store->pos].str = util_str_dup(str);
store->pos++;
}
void sec_hasp_asn1_object_add_time(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t time)
{
if (store->pos == store->capacity) {
return;
}
store->objects[store->pos].tag = tag;
store->objects[store->pos].type = SEC_HASP_ASN1_VT_TIME;
store->objects[store->pos].blen = 5;
store->objects[store->pos].time = time;
store->pos++;
}
void sec_hasp_asn1_object_add_data(struct sec_hasp_asn1_store* store, uint16_t tag, const uint8_t* data,
size_t len)
{
if (store->pos == store->capacity) {
return;
}
store->objects[store->pos].tag = tag;
store->objects[store->pos].type = SEC_HASP_ASN1_VT_DATA;
/* Store len + null terminator */
store->objects[store->pos].blen = len;
store->objects[store->pos].data = util_xmalloc(len);
memcpy(store->objects[store->pos].data, data, len);
store->pos++;
}
void sec_hasp_asn1_object_set_int(struct sec_hasp_asn1_store* store, uint16_t tag)
{
store->objects[store->pos].tag = tag;
store->objects[store->pos].type = SEC_HASP_ASN1_VT_INT;
store->pos++;
}
void sec_hasp_asn1_object_set_str(struct sec_hasp_asn1_store* store, uint16_t tag)
{
store->objects[store->pos].tag = tag;
store->objects[store->pos].type = SEC_HASP_ASN1_VT_STR;
store->pos++;
}
void sec_hasp_asn1_object_set_time(struct sec_hasp_asn1_store* store, uint16_t tag)
{
store->objects[store->pos].tag = tag;
store->objects[store->pos].type = SEC_HASP_ASN1_VT_TIME;
store->pos++;
}
void sec_hasp_asn1_object_set_data(struct sec_hasp_asn1_store* store, uint16_t tag)
{
store->objects[store->pos].tag = tag;
store->objects[store->pos].type = SEC_HASP_ASN1_VT_DATA;
store->pos++;
}
bool sec_hasp_asn1_object_get_int(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t* ret_value)
{
for (size_t i = 0; i < store->pos; i++) {
if (store->objects[i].tag == tag) {
if (store->objects[i].type != SEC_HASP_ASN1_VT_INT) {
log_error("Type of tag %X is not int", tag);
return false;
} else {
*ret_value = store->objects[i].int_val;
return true;
}
}
}
return false;
}
bool sec_hasp_asn1_object_get_str(struct sec_hasp_asn1_store* store, uint16_t tag, char** ret_value)
{
for (size_t i = 0; i < store->pos; i++) {
if (store->objects[i].tag == tag) {
if (store->objects[i].type != SEC_HASP_ASN1_VT_STR) {
log_error("Type of tag %X is not str", tag);
return false;
} else {
*ret_value = util_str_dup(store->objects[i].str);
return true;
}
}
}
return false;
}
bool sec_hasp_asn1_object_get_time(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t* ret_value)
{
for (size_t i = 0; i < store->pos; i++) {
if (store->objects[i].tag == tag) {
if (store->objects[i].type != SEC_HASP_ASN1_VT_TIME) {
log_error("Type of tag %X is not time", tag);
return false;
} else {
*ret_value = store->objects[i].int_val;
return true;
}
}
}
return false;
}
bool sec_hasp_asn1_object_get_data(struct sec_hasp_asn1_store* store, uint16_t tag, uint8_t** ret_data,
size_t* ret_len)
{
for (size_t i = 0; i < store->pos; i++) {
if (store->objects[i].tag == tag) {
if (store->objects[i].type != SEC_HASP_ASN1_VT_DATA) {
log_error("Type of tag %X is not str", tag);
return false;
} else {
*ret_len = store->objects[i].blen;
*ret_data = util_xmalloc(*ret_len);
memcpy(*ret_data, store->objects[i].data, *ret_len);
return true;
}
}
}
return false;
}
size_t sec_hasp_asn1_encode(struct sec_hasp_asn1_store* store, uint8_t* buffer, size_t len)
{
uint8_t buffer_tmp[32768];
size_t offset = 0;
/* we need to know the size of the payload to encode the first length field, encode all objects first */
for (size_t i = 0; i < store->pos; i++) {
sec_hasp_asn1_encode_tag(store->objects[i].tag, buffer_tmp, &offset);
sec_hasp_asn1_encode_length(store->objects[i].blen, buffer_tmp, &offset);
switch(store->objects[i].type) {
case SEC_HASP_ASN1_VT_INVALID:
log_error("Invalid object type");
break;
case SEC_HASP_ASN1_VT_TIME:
buffer_tmp[offset++] = 0x00;
sec_hasp_asn1_encode_int(store->objects[i].time, buffer_tmp, &offset);
break;
case SEC_HASP_ASN1_VT_INT:
sec_hasp_asn1_encode_int(store->objects[i].time, buffer_tmp, &offset);
break;
case SEC_HASP_ASN1_VT_STR:
sec_hasp_asn1_encode_str(store->objects[i].str, buffer_tmp, &offset);
break;
case SEC_HASP_ASN1_VT_DATA:
sec_hasp_asn1_encode_data(store->objects[i].data, store->objects[i].blen, buffer_tmp, &offset);
break;
default:
log_error("Unknown object type %d", store->objects[i].type);
break;
}
}
size_t offset_out = 0;
sec_hasp_asn1_encode_tag(store->oid, buffer, &offset_out);
sec_hasp_asn1_encode_length(offset, buffer, &offset_out);
if (offset > len) {
log_error("Target buffer too small: %d < %d", len, offset + offset_out);
} else {
memcpy(&buffer[offset_out], buffer_tmp, offset);
}
return offset + offset_out;
}
void sec_hasp_asn1_decode(struct sec_hasp_asn1_store* store, const uint8_t* buffer, size_t len)
{
size_t offset = 0;
store->oid = sec_hasp_asn1_decode_tag(buffer, &offset);
sec_hasp_asn1_decode_length(buffer, &offset);
while (offset < len) {
uint16_t tag = sec_hasp_asn1_decode_tag(buffer, &offset);
uint32_t obj_len = sec_hasp_asn1_decode_length(buffer, &offset);
if (tag <= 0x7F || tag >= 0x9F) {
log_error("Found invalid object tag: %X", tag);
return;
}
struct sec_hasp_asn1_object* obj = NULL;
/* find object that matches the tag and type */
for (size_t i = 0; i < store->pos; i++) {
if (store->objects[i].tag == tag) {
obj = &store->objects[i];
break;
}
}
if (!obj) {
log_error("No object in store that matches tag %X", tag);
return;
}
obj->blen = obj_len;
switch (obj->type) {
case SEC_HASP_ASN1_VT_INVALID:
log_error("Invalid object type specified for tag %X", obj->tag);
break;
case SEC_HASP_ASN1_VT_TIME:
case SEC_HASP_ASN1_VT_INT:
obj->int_val = sec_hasp_asn1_decode_int(buffer, &offset, obj->blen);
break;
case SEC_HASP_ASN1_VT_STR:
obj->str = sec_hasp_asn1_decode_str(buffer, &offset, obj->blen);
break;
case SEC_HASP_ASN1_VT_DATA:
obj->data = sec_hasp_asn1_decode_data(buffer, &offset, obj->blen);
break;
default:
log_error("Unknown object type for tag %X", obj->tag);
break;
}
}
}
static uint32_t sec_hasp_asn1_decode_int(const uint8_t* buffer, size_t* offset, uint32_t blen)
{
uint32_t data = 0;
switch (blen) {
case 1:
data = buffer[(*offset)++];
break;
case 2:
data |= buffer[(*offset)++] << 8;
data |= buffer[(*offset)++];
break;
case 3:
data |= buffer[(*offset)++] << 16;
data |= buffer[(*offset)++] << 8;
data |= buffer[(*offset)++];
break;
case 4:
data |= buffer[(*offset)++] << 24;
data |= buffer[(*offset)++] << 16;
data |= buffer[(*offset)++] << 8;
data |= buffer[(*offset)++];
break;
case 5:
/* skip first byte? */
(*offset)++;
data |= buffer[(*offset)++] << 24;
data |= buffer[(*offset)++] << 16;
data |= buffer[(*offset)++] << 8;
data |= buffer[(*offset)++];
break;
default:
// TODO invalid len?
break;
}
return data;
}
static uint8_t* sec_hasp_asn1_decode_data(const uint8_t* buffer, size_t* offset, uint32_t blen)
{
uint8_t* data = util_xmalloc(sizeof(uint8_t) * blen);
memcpy(data, buffer + *offset, blen);
(*offset) += blen;
return data;
}
static char* sec_hasp_asn1_decode_str(const uint8_t* buffer, size_t* offset, uint32_t blen)
{
/* len already includes null terminator */
char* str = util_xmalloc(sizeof(char) * blen);
memcpy(str, buffer + *offset, blen);
(*offset) += blen;
return str;
}
static uint32_t sec_hasp_asn1_decode_length(const uint8_t* buffer, size_t* offset)
{
uint32_t len;
len = buffer[(*offset)++];
if (len == 0x81) {
len = buffer[(*offset)++];
} else if (len == 0x82) {
/* Big endian */
len = buffer[(*offset)++] << 8;
len |= buffer[(*offset)++];
}
return len;
}
static uint16_t sec_hasp_asn1_decode_tag(const uint8_t* buffer, size_t* offset)
{
uint16_t tag;
tag = buffer[(*offset)++];
if (tag == 0x7F) {
/* Big endian */
tag = tag << 8;
tag |= buffer[(*offset)++];
}
return tag;
}
static void sec_hasp_asn1_encode_int(uint32_t val, uint8_t* buffer, size_t* offset)
{
uint8_t tmp[8];
size_t tmp_pos = 0;
if (val <= 0xFF) {
tmp[tmp_pos++] = (uint8_t) val;
} else if (val <= 0xFFFF) {
/* Big endian */
tmp[tmp_pos++] = (uint8_t) (val >> 8);
tmp[tmp_pos++] = (uint8_t) val;
} else if (val <= 0xFFFFFF) {
/* Big endian */
tmp[tmp_pos++] = (uint8_t) (val >> 16);
tmp[tmp_pos++] = (uint8_t) (val >> 8);
tmp[tmp_pos++] = (uint8_t) val;
} else if (val <= 0xFFFFFFFF) {
/* Big endian */
tmp[tmp_pos++] = (uint8_t) (val >> 24);
tmp[tmp_pos++] = (uint8_t) (val >> 16);
tmp[tmp_pos++] = (uint8_t) (val >> 8);
tmp[tmp_pos++] = (uint8_t) val;
} else if (val <= 0xFFFFFFFFFFFFFFFF) {
// TODO quad words not supported in decode?
}
/* Deal with padding */
if (tmp[0] > 0x7F) {
buffer[(*offset)++] = 0x00;
}
memcpy(buffer + *offset, tmp, tmp_pos);
(*offset) += tmp_pos;
}
static void sec_hasp_asn1_encode_data(const uint8_t* data, size_t len, uint8_t* buffer, size_t* offset)
{
memcpy(buffer + *offset, data, len);
(*offset) += len;
}
static void sec_hasp_asn1_encode_str(const char* str, uint8_t* buffer, size_t* offset)
{
size_t len = strlen(str);
memcpy(buffer + *offset, str, len);
(*offset) += len;
/* Add null terminator */
buffer[(*offset)++] = 0x00;
}
static void sec_hasp_asn1_encode_length(uint32_t len, uint8_t* buffer, size_t* offset)
{
if (len <= 0xF7) {
buffer[(*offset)++] = (uint8_t) len;
} else if (len <= 0xFF) {
buffer[(*offset)++] = 0x81;
buffer[(*offset)++] = (uint8_t) len;
} else if (len <= 0xFFFF) {
buffer[(*offset)++] = 0x82;
/* Big endian */
buffer[(*offset)++] = (uint8_t) (len >> 8);
buffer[(*offset)++] = (uint8_t) len;
} else if (len <= 0xFFFF) {
buffer[(*offset)++] = 0x82;
/* Big endian */
buffer[(*offset)++] = (uint8_t) (len >> 16);
buffer[(*offset)++] = (uint8_t) (len >> 8);
buffer[(*offset)++] = (uint8_t) len;
} else if (len <= 0xFFFFFFFF) {
buffer[(*offset)++] = 0x84;
/* Big endian */
buffer[(*offset)++] = (uint8_t) (len >> 24);
buffer[(*offset)++] = (uint8_t) (len >> 16);
buffer[(*offset)++] = (uint8_t) (len >> 8);
buffer[(*offset)++] = (uint8_t) len;
}
}
static void sec_hasp_asn1_encode_tag(uint16_t tag, uint8_t* buffer, size_t* offset)
{
if (tag > 0xFF) {
/* Big endian */
buffer[(*offset)++] = (uint8_t) (tag >> 8);
buffer[(*offset)++] = (uint8_t) (tag);
} else {
buffer[(*offset)++] = (uint8_t) (tag);
}
}
+71
View File
@@ -0,0 +1,71 @@
#ifndef SEC_HASP_ASN1_H
#define SEC_HASP_ASN1_H
#include <stdint.h>
#include <stdlib.h>
#include "util/list.h"
enum sec_hasp_asn1_value_type {
SEC_HASP_ASN1_VT_INVALID = 0,
SEC_HASP_ASN1_VT_INT = 1,
SEC_HASP_ASN1_VT_STR = 2,
SEC_HASP_ASN1_VT_TIME = 3,
SEC_HASP_ASN1_VT_DATA = 4,
};
struct sec_hasp_asn1_object {
uint16_t tag;
uint32_t blen;
enum sec_hasp_asn1_value_type type;
union {
uint32_t time;
uint32_t int_val;
uint8_t* data;
char* str;
};
};
struct sec_hasp_asn1_store {
uint16_t oid;
size_t capacity;
size_t pos;
struct sec_hasp_asn1_object* objects;
};
struct sec_hasp_asn1_store* sec_hasp_asn1_object_store_alloc(uint16_t oid, uint32_t size);
void sec_hasp_asn1_store_free(struct sec_hasp_asn1_store* store);
void sec_hasp_asn1_object_add_int(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t value);
void sec_hasp_asn1_object_add_str(struct sec_hasp_asn1_store* store, uint16_t tag, const char* str);
void sec_hasp_asn1_object_add_time(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t time);
void sec_hasp_asn1_object_add_data(struct sec_hasp_asn1_store* store, uint16_t tag, const uint8_t* data,
size_t len);
void sec_hasp_asn1_object_set_int(struct sec_hasp_asn1_store* store, uint16_t tag);
void sec_hasp_asn1_object_set_str(struct sec_hasp_asn1_store* store, uint16_t tag);
void sec_hasp_asn1_object_set_time(struct sec_hasp_asn1_store* store, uint16_t tag);
void sec_hasp_asn1_object_set_data(struct sec_hasp_asn1_store* store, uint16_t tag);
bool sec_hasp_asn1_object_get_int(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t* ret_value);
bool sec_hasp_asn1_object_get_str(struct sec_hasp_asn1_store* store, uint16_t tag, char** ret_value);
bool sec_hasp_asn1_object_get_time(struct sec_hasp_asn1_store* store, uint16_t tag, uint32_t* ret_value);
bool sec_hasp_asn1_object_get_data(struct sec_hasp_asn1_store* store, uint16_t tag, uint8_t** ret_data,
size_t* ret_len);
size_t sec_hasp_asn1_encode(struct sec_hasp_asn1_store* store, uint8_t* buffer, size_t len);
void sec_hasp_asn1_decode(struct sec_hasp_asn1_store* store, const uint8_t* buffer, size_t len);
#endif
+80
View File
@@ -0,0 +1,80 @@
#ifndef SEC_HASP_CONST_H
#define SEC_HASP_CONST_H
#define SEC_HAS_CONST_HEADER_SZ 24
#define SEC_HAS_CONST_FILEID_RW = 0xfff4
#define SEC_HAS_CONST_FILEID_RO = 0xfff5
#define SEC_HAS_CONST_SCOPE_LM "<?xml version=\"1.0\" encoding=\"UTF-8\"?><haspscope><hasp type=\"HASP-HL\"><license_manager ip=\"127.0.0.1\" /></hasp></haspscope>"
#define SEC_HAS_CONST_SCOPE_HANDLE "<haspscope><session handle=\"%d\"/></haspscope>"
#define SEC_HAS_CONST_FORMAT_GETID "<?xml version=\"1.0\" encoding=\"UTF-8\"?><haspformat><hasp><attribute name=\"id\" /></hasp></haspformat>"
#define SEC_HAS_CONST_FORMAT_GETSESSION "<haspformat root=\"hasp_info\"><si_feature /></haspformat>"
#define SEC_HAS_CONST_FORMAT_GETKEYINFO "<haspformat root=\"hasp_info\"><si_container /></haspformat>"
#define SEC_HAS_CONST_SPEC_FEATURE_ID "<haspspec><feature id=\"%d\" /></haspspec>"
enum sec_hasp_const_status {
SEC_HASP_CONST_STATUS_OK = 0,
SEC_HASP_CONST_STATUS_MEM_RANGE = 1,
SEC_HASP_CONST_STATUS_INV_FILEID = 10,
SEC_HASP_CONST_STATUS_NO_TIME = 12,
SEC_HASP_CONST_STATUS_INV_VCODE = 22,
SEC_HASP_CONST_STATUS_INV_HND = 9,
SEC_HASP_CONST_STATUS_TOO_SHORT = 8,
SEC_HASP_CONST_STATUS_DEVICE_ERR = 43,
SEC_HASP_CONST_STATUS_SCHAN_ERR = 46,
SEC_HASP_CONST_STATUS_BROKEN_SESSION = 0x7F000027
};
enum sec_hasp_const_operation_id {
/* Not Used - Admin or Get LMS Version? */
SEC_HASP_CONST_OP_ID_ADMIN = 0,
/* Not Used */
SEC_HASP_CONST_OP_ID_ECHO = 1,
SEC_HASP_CONST_OP_ID_LOGIN = 0x2711,
SEC_HASP_CONST_OP_ID_LOGOUT = 0x2712,
SEC_HASP_CONST_OP_ID_LOGINSCOPE = 0x2713,
SEC_HASP_CONST_OP_ID_GETINFO = 0x2714,
SEC_HASP_CONST_OP_ID_PARSE_SCOPE = 0x2715,
SEC_HASP_CONST_OP_ID_SETUPSCHANNEL = 0x2716,
SEC_HASP_CONST_OP_ID_ENCRYPT = 0x2724,
SEC_HASP_CONST_OP_ID_DECRYPT = 0x2725,
SEC_HASP_CONST_OP_ID_READ = 0x271A,
SEC_HASP_CONST_OP_ID_WRITE = 0x271B,
SEC_HASP_CONST_OP_ID_GETSIZE = 0x271C,
SEC_HASP_CONST_OP_ID_GETRTC = 0x271D,
SEC_HASP_CONST_OP_ID_GETAPIUID = 0x2774,
/* Not Used */
SEC_HASP_CONST_OP_ID_UPDATE = 0x2775,
/* Not Used */
SEC_HASP_CONST_OP_ID_DETACH = 0x2779,
};
enum sec_hasp_const_operational_object_id {
SEC_HASP_CONST_OID_CLIENTID_REQ = 0x7F34,
SEC_HASP_CONST_OID_CLIENTID_RESP =0x7F35,
SEC_HASP_CONST_OID_LOGIN_REQ = 0x61,
SEC_HASP_CONST_OID_LOGIN_REP = 0x62,
SEC_HASP_CONST_OID_LOGINSCOPE_REQ = 0x63,
SEC_HASP_CONST_OID_LOGINSCOPE_REP = 0x64,
SEC_HASP_CONST_OID_LOGOUT_REQ = 0x65,
SEC_HASP_CONST_OID_LOGOUT_REP = 0x66,
SEC_HASP_CONST_OID_INFO_REQ = 0x67,
SEC_HASP_CONST_OID_INFO_REP = 0x68,
SEC_HASP_CONST_OID_READ_REQ = 0x6A,
SEC_HASP_CONST_OID_READ_REP = 0x6B,
SEC_HASP_CONST_OID_WRITE_REQ = 0x6C,
SEC_HASP_CONST_OID_WRITE_REP = 0x6D,
SEC_HASP_CONST_OID_GETSIZE_REQ = 0x6E,
SEC_HASP_CONST_OID_GETSIZE_REP = 0x6F,
SEC_HASP_CONST_OID_GETRTC_REQ = 0x70,
SEC_HASP_CONST_OID_GETRTC_REP = 0x71,
SEC_HASP_CONST_OID_SCHANNEL_REQ = 0x72,
SEC_HASP_CONST_OID_SCHANNEL_REP = 0x73,
SEC_HASP_CONST_OID_CRYPT_REQ = 0x77,
SEC_HASP_CONST_OID_CRYPT_REP = 0x78,
};
#endif
+118
View File
@@ -0,0 +1,118 @@
#define LOG_MODULE "sec-hasp-handler"
#include <string.h>
#include "handler.h"
#include "util/log.h"
enum sec_hasp_handler_packet_type {
SEC_HASP_HANDLER_PT_APIUID = 0x2774,
SEC_HASP_HANDLER_PT_LOGIN = 0x2711,
SEC_HASP_HANDLER_PT_LOGOUT = 0x2712,
SEC_HASP_HANDLER_PT_GETINFO = 0x2714,
SEC_HASP_HANDLER_PT_SCHANNEL = 0x2716,
SEC_HASP_HANDLER_PT_ENCRYPT = 0x2724,
SEC_HASP_HANDLER_PT_DECRYPT = 0x2725,
SEC_HASP_HANDLER_PT_READ = 0x271A,
SEC_HASP_HANDLER_PT_WRITE = 0x271B,
};
void sec_hasp_handler_init(const uint8_t* key_data, size_t len)
{
}
struct sec_hasp_handler_transaction* sec_hasp_handler_alloc_transaction(size_t max_payload_size)
{
struct sec_hasp_handler_transaction* trans;
trans = malloc(sizeof(struct sec_hasp_handler_transaction));
trans->req_resp_max_size = sizeof(struct sec_hasp_handler_header) + max_payload_size;
trans->req = malloc(trans->req_resp_max_size);
trans->resp = malloc(trans->req_resp_max_size);
return trans;
}
void sec_hasp_handler_free_transaction(struct sec_hasp_handler_transaction* transaction)
{
free(transaction->req);
free(transaction->resp);
free(transaction);
}
void sec_hasp_handler_do_transaction(struct sec_hasp_handler_transaction* transaction)
{
log_debug("Req: packet_size %d, head_value 0x%X, transaction_num %d, session_id 0x%X, packet_type 0x%X, "
"unknown 0x%X, tail_value 0x%X", transaction->req->header.packet_size, transaction->req->header.head_value,
transaction->req->header.transaction_num, transaction->req->header.session_id,
transaction->req->header.packet_type, transaction->req->header.tail_value);
switch (transaction->req->header.packet_type) {
case SEC_HASP_HANDLER_PT_APIUID:
log_debug("SEC_HASP_HANDLER_PT_APIUID");
break;
case SEC_HASP_HANDLER_PT_LOGIN:
log_debug("SEC_HASP_HANDLER_PT_LOGIN");
break;
case SEC_HASP_HANDLER_PT_LOGOUT:
log_debug("SEC_HASP_HANDLER_PT_LOGOUT");
break;
case SEC_HASP_HANDLER_PT_GETINFO:
log_debug("SEC_HASP_HANDLER_PT_GETINFO");
break;
case SEC_HASP_HANDLER_PT_SCHANNEL:
log_debug("SEC_HASP_HANDLER_PT_SCHANNEL");
break;
case SEC_HASP_HANDLER_PT_ENCRYPT:
log_debug("SEC_HASP_HANDLER_PT_ENCRYPT");
break;
case SEC_HASP_HANDLER_PT_DECRYPT:
log_debug("SEC_HASP_HANDLER_PT_DECRYPT");
break;
case SEC_HASP_HANDLER_PT_READ:
log_debug("SEC_HASP_HANDLER_PT_READ");
break;
case SEC_HASP_HANDLER_PT_WRITE:
log_debug("SEC_HASP_HANDLER_PT_WRITE");
break;
default:
log_error("Invalid packet type: %X", transaction->req->header.packet_type);
memset(&transaction->req->header, 0, sizeof(struct sec_hasp_handler_header));
break;
}
}
//static void sec_hasp_handler_get_client_id(struct sec_hasp_handler_transaction* transaction)
//{
// transaction->resp->header.packet_size
// transaction->resp->header.head_value
// transaction->resp->header.transaction_num
// transaction->resp->header.session_id
// transaction->resp->header.packet_type
// transaction->resp->header.tail_value
//
// rp = request_packet.payload_object
//
// client_id = HaspUtils.make_fake_handle_value()
// client_id_response = HaspObject.HO_Client_ID_Response()
// client_id_response.populate(HaspConst.HASP_STATUS_OK,client_id)
//
// self.client_db[client_id] = {
// "hasp_serial":0,
// "sessions":{}
// }
//
// return client_id_response
//}
+41
View File
@@ -0,0 +1,41 @@
#ifndef SEC_HASP_HANDLER_H
#define SEC_HASP_HANDLER_H
#include <stdint.h>
#include <stdlib.h>
struct sec_hasp_handler_header {
uint32_t packet_size;
uint16_t head_value;
uint32_t transaction_num;
uint32_t session_id;
uint16_t unknown;
uint16_t packet_type;
uint32_t tail_value;
} __attribute((__packed__));
struct sec_hasp_handler_req {
struct sec_hasp_handler_header header;
uint8_t payload[];
};
struct sec_hasp_handler_resp {
struct sec_hasp_handler_header header;
uint8_t payload[];
};
struct sec_hasp_handler_transaction {
size_t req_resp_max_size;
struct sec_hasp_handler_req* req;
struct sec_hasp_handler_resp* resp;
};
void sec_hasp_handler_init(const uint8_t* key_data, size_t len);
struct sec_hasp_handler_transaction* sec_hasp_handler_alloc_transaction(size_t max_payload_size);
void sec_hasp_handler_free_transaction(struct sec_hasp_handler_transaction* transaction);
void sec_hasp_handler_do_transaction(struct sec_hasp_handler_transaction* transaction);
#endif
+4
View File
@@ -0,0 +1,4 @@
//
// Created by on 6/2/18.
//
+6
View File
@@ -0,0 +1,6 @@
#ifndef SEC_HASP_OBJECT_H
#define SEC_HASP_OBJECT_H
#endif
@@ -0,0 +1,61 @@
#include <time.h>
#include "sec/hasp/lib/asn1.h"
#include "sec/hasp/lib/const.h"
#include "util/mem.h"
#include "client-id-req.h"
struct sec_hasp_object_client_id_req* sec_hasp_object_client_id_req_alloc()
{
struct sec_hasp_object_client_id_req* obj = util_xmalloc(sizeof(struct sec_hasp_object_client_id_req));
obj->oid = SEC_HASP_CONST_OID_CLIENTID_REQ;
obj->val_80 = 0;
obj->api_version_major = 0;
obj->api_version_minor = 0;
obj->timestamp = 0;
return obj;
}
void sec_hasp_object_client_id_req_free(struct sec_hasp_object_client_id_req* obj)
{
free(obj);
}
size_t sec_hasp_object_client_id_req_encode(struct sec_hasp_object_client_id_req* obj, uint8_t* buffer,
size_t len)
{
struct sec_hasp_asn1_store* store = sec_hasp_asn1_object_store_alloc(obj->oid, 4);
/* populate right before encoding */
obj->timestamp = (uint32_t) time(NULL);
sec_hasp_asn1_object_add_int(store, 0x80, obj->val_80);
sec_hasp_asn1_object_add_int(store, 0x81, obj->api_version_major);
sec_hasp_asn1_object_add_int(store, 0x82, obj->api_version_minor);
sec_hasp_asn1_object_add_time(store, 0x84, obj->timestamp);
return sec_hasp_asn1_encode(store, buffer, len);
}
void sec_hasp_object_client_id_req_decode(uint8_t* buffer, size_t len, struct sec_hasp_object_client_id_req* obj)
{
struct sec_hasp_asn1_store* store = sec_hasp_asn1_object_store_alloc(obj->oid, 4);
sec_hasp_asn1_object_set_int(store, 0x80);
sec_hasp_asn1_object_set_int(store, 0x81);
sec_hasp_asn1_object_set_int(store, 0x82);
sec_hasp_asn1_object_set_time(store, 0x84);
sec_hasp_asn1_decode(store, buffer, len);
obj->oid = store->oid;
sec_hasp_asn1_object_get_int(store, 0x80, &obj->val_80);
sec_hasp_asn1_object_get_int(store, 0x81, &obj->api_version_major);
sec_hasp_asn1_object_get_int(store, 0x82, &obj->api_version_minor);
sec_hasp_asn1_object_get_time(store, 0x84, &obj->timestamp);
}
@@ -0,0 +1,24 @@
#ifndef SEC_HASP_OBJECT_CLIENT_ID_REQ_H
#define SEC_HASP_OBJECT_CLIENT_ID_REQ_H
#include <stdint.h>
#include <stdlib.h>
struct sec_hasp_object_client_id_req {
uint16_t oid;
uint32_t val_80;
uint32_t api_version_major;
uint32_t api_version_minor;
uint32_t timestamp;
};
struct sec_hasp_object_client_id_req* sec_hasp_object_client_id_req_alloc();
void sec_hasp_object_client_id_req_free(struct sec_hasp_object_client_id_req* obj);
size_t sec_hasp_object_client_id_req_encode(struct sec_hasp_object_client_id_req* obj, uint8_t* buffer,
size_t len);
void sec_hasp_object_client_id_req_decode(uint8_t* buffer, size_t len, struct sec_hasp_object_client_id_req* obj);
#endif
@@ -0,0 +1,48 @@
#include "sec/hasp/lib/asn1.h"
#include "sec/hasp/lib/const.h"
#include "util/mem.h"
#include "client-id-resp.h"
struct sec_hasp_object_client_id_resp* sec_hasp_object_client_id_resp_alloc()
{
struct sec_hasp_object_client_id_resp* obj = util_xmalloc(sizeof(struct sec_hasp_object_client_id_resp));
obj->oid = SEC_HASP_CONST_OID_CLIENTID_RESP;
obj->status = 0;
obj->client_id = 0;
return obj;
}
void sec_hasp_object_client_id_resp_free(struct sec_hasp_object_client_id_resp* obj)
{
free(obj);
}
size_t sec_hasp_object_client_id_resp_encode(struct sec_hasp_object_client_id_resp* obj, uint8_t* buffer,
size_t len)
{
struct sec_hasp_asn1_store* store = sec_hasp_asn1_object_store_alloc(obj->oid, 4);
sec_hasp_asn1_object_add_int(store, 0x80, obj->status);
sec_hasp_asn1_object_add_int(store, 0x81, obj->client_id);
return sec_hasp_asn1_encode(store, buffer, len);
}
void sec_hasp_object_client_id_resp_decode(uint8_t* buffer, size_t len, struct sec_hasp_object_client_id_resp* obj)
{
struct sec_hasp_asn1_store* store = sec_hasp_asn1_object_store_alloc(obj->oid, 2);
sec_hasp_asn1_object_set_int(store, 0x80);
sec_hasp_asn1_object_set_int(store, 0x81);
sec_hasp_asn1_decode(store, buffer, len);
obj->oid = store->oid;
sec_hasp_asn1_object_get_int(store, 0x80, &obj->status);
sec_hasp_asn1_object_get_int(store, 0x81, &obj->client_id);
}
@@ -0,0 +1,22 @@
#ifndef SEC_HASP_OBJECT_CLIENT_ID_RESP_H
#define SEC_HASP_OBJECT_CLIENT_ID_RESP_H
#include <stdint.h>
#include <stdlib.h>
struct sec_hasp_object_client_id_resp {
uint16_t oid;
uint32_t status;
uint32_t client_id;
};
struct sec_hasp_object_client_id_resp* sec_hasp_object_client_id_resp_alloc();
void sec_hasp_object_client_id_resp_free(struct sec_hasp_object_client_id_resp* obj);
size_t sec_hasp_object_client_id_resp_encode(struct sec_hasp_object_client_id_resp* obj, uint8_t* buffer,
size_t len);
void sec_hasp_object_client_id_resp_decode(uint8_t* buffer, size_t len, struct sec_hasp_object_client_id_resp* obj);
#endif
+139
View File
@@ -0,0 +1,139 @@
#include <time.h>
#include "sec/hasp/main.h"
#include "sec/hasp/const.h"
#include "util/mem.h"
#include "login-req.h"
struct sec_hasp_object_login_req* sec_hasp_object_login_req_init()
{
struct sec_hasp_object_login_req* obj = util_xmalloc(sizeof(struct sec_hasp_object_login_req));
obj->oid = SEC_HASP_CONST_OID_LOGIN_REQ;
obj->pid = 0;
obj->tid = 0;
obj->hasp_uid = 0;
obj->vendor_id = 0;
obj->feature_id = 0;
obj->username = NULL;
obj->machine_name = NULL;
obj->login_type = NULL;
obj->api_version_major = 0;
obj->api_version_minor = 0;
obj->timestamp = 0;
obj->val_8b = 0;
obj->val_8c = 0;
obj->val_8d = 0;
obj->val_8e = 0;
obj->volume_serial = 0;
obj->val_90 = 0;
obj->hasp_handle = 0;
return obj;
}
void sec_hasp_object_login_req_free(struct sec_hasp_object_login_req* obj)
{
if (obj->username) {
free(obj->username);
}
if (obj->machine_name) {
free(obj->machine_name);
}
if (obj->login_type) {
free(obj->login_type);
}
}
size_t sec_hasp_object_login_req_encode(struct sec_hasp_object_login_req* obj, uint8_t* buffer,
size_t len)
{
struct sec_hasp_asn1_store* store = sec_hasp_asn1_object_store_alloc(obj->oid, 18);
/* populate right before encoding */
obj->timestamp = (uint32_t) time(NULL);
sec_hasp_asn1_object_add_int(store, 0x80, obj->pid);
sec_hasp_asn1_object_add_int(store, 0x81, obj->tid);
sec_hasp_asn1_object_add_int(store, 0x82, obj->hasp_uid);
sec_hasp_asn1_object_add_int(store, 0x83, obj->vendor_id);
sec_hasp_asn1_object_add_int(store, 0x84, obj->feature_id);
sec_hasp_asn1_object_add_str(store, 0x85, obj->username);
sec_hasp_asn1_object_add_str(store, 0x86, obj->machine_name);
sec_hasp_asn1_object_add_str(store, 0x87, obj->login_type);
sec_hasp_asn1_object_add_int(store, 0x88, obj->api_version_major);
sec_hasp_asn1_object_add_int(store, 0x89, obj->api_version_minor);
sec_hasp_asn1_object_add_time(store, 0x8A, obj->timestamp);
sec_hasp_asn1_object_add_int(store, 0x8B, obj->val_8b);
sec_hasp_asn1_object_add_int(store, 0x8C, obj->val_8c);
sec_hasp_asn1_object_add_int(store, 0x8D, obj->val_8d);
sec_hasp_asn1_object_add_int(store, 0x8E, obj->val_8e);
sec_hasp_asn1_object_add_int(store, 0x8F, obj->volume_serial);
sec_hasp_asn1_object_add_int(store, 0x90, obj->val_90);
sec_hasp_asn1_object_add_int(store, 0x91, obj->hasp_handle);
return sec_hasp_asn1_encode(store, buffer, len);
}
void sec_hasp_object_login_req_decode(uint8_t* buffer, size_t len, struct sec_hasp_object_login_req* obj)
{
struct sec_hasp_asn1_store* store = sec_hasp_asn1_object_store_alloc(obj->oid, 18);
sec_hasp_asn1_object_set_int(store, 0x80);
sec_hasp_asn1_object_set_int(store, 0x81);
sec_hasp_asn1_object_set_int(store, 0x82);
sec_hasp_asn1_object_set_int(store, 0x83);
sec_hasp_asn1_object_set_int(store, 0x84);
sec_hasp_asn1_object_set_str(store, 0x85);
sec_hasp_asn1_object_set_str(store, 0x86);
sec_hasp_asn1_object_set_str(store, 0x87);
sec_hasp_asn1_object_set_int(store, 0x88);
sec_hasp_asn1_object_set_int(store, 0x89);
sec_hasp_asn1_object_set_time(store, 0x8A);
sec_hasp_asn1_object_set_int(store, 0x8B);
sec_hasp_asn1_object_set_int(store, 0x8C);
sec_hasp_asn1_object_set_int(store, 0x8D);
sec_hasp_asn1_object_set_int(store, 0x8E);
sec_hasp_asn1_object_set_int(store, 0x8F);
sec_hasp_asn1_object_set_int(store, 0x90);
sec_hasp_asn1_object_set_int(store, 0x91);
sec_hasp_asn1_decode(store, buffer, len);
obj->oid = store->oid;
sec_hasp_asn1_object_get_int(store, 0x80, &obj->pid);
sec_hasp_asn1_object_get_int(store, 0x81, &obj->tid);
sec_hasp_asn1_object_get_int(store, 0x82, &obj->hasp_uid);
sec_hasp_asn1_object_get_int(store, 0x83, &obj->vendor_id);
sec_hasp_asn1_object_get_int(store, 0x84, &obj->feature_id);
sec_hasp_asn1_object_get_str(store, 0x85, &obj->username);
sec_hasp_asn1_object_get_str(store, 0x86, &obj->machine_name);
sec_hasp_asn1_object_get_str(store, 0x87, &obj->login_type);
sec_hasp_asn1_object_get_int(store, 0x88, &obj->api_version_major);
sec_hasp_asn1_object_get_int(store, 0x89, &obj->api_version_minor);
sec_hasp_asn1_object_get_time(store, 0x8A, &obj->timestamp);
sec_hasp_asn1_object_get_int(store, 0x8B, &obj->val_8b);
sec_hasp_asn1_object_get_int(store, 0x8C, &obj->val_8c);
sec_hasp_asn1_object_get_int(store, 0x8D, &obj->val_8d);
sec_hasp_asn1_object_get_int(store, 0x8E, &obj->val_8e);
sec_hasp_asn1_object_get_int(store, 0x8F, &obj->volume_serial);
sec_hasp_asn1_object_get_int(store, 0x90, &obj->val_90);
sec_hasp_asn1_object_get_int(store, 0x91, &obj->hasp_handle);
}
+38
View File
@@ -0,0 +1,38 @@
#ifndef SEC_HASP_OBJECT_LOGIN_REQ_H
#define SEC_HASP_OBJECT_LOGIN_REQ_H
#include <stdint.h>
#include <stdlib.h>
struct sec_hasp_object_login_req {
uint16_t oid;
uint32_t pid;
uint32_t tid;
uint32_t hasp_uid;
uint32_t vendor_id;
uint32_t feature_id;
char* username;
char* machine_name;
char* login_type;
uint32_t api_version_major;
uint32_t api_version_minor;
uint32_t timestamp;
uint32_t val_8b;
uint32_t val_8c;
uint32_t val_8d;
uint32_t val_8e;
uint32_t volume_serial;
uint32_t val_90;
uint32_t hasp_handle;
};
struct sec_hasp_object_login_req* sec_hasp_object_login_req_init();
void sec_hasp_object_login_req_free(struct sec_hasp_object_login_req* obj);
size_t sec_hasp_object_login_req_encode(struct sec_hasp_object_login_req* obj, uint8_t* buffer,
size_t len);
void sec_hasp_object_login_req_decode(uint8_t* buffer, size_t len, struct sec_hasp_object_login_req* obj);
#endif
+162
View File
@@ -0,0 +1,162 @@
#define LOG_MODULE "sec-hasp-server"
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <unistd.h>
#include "sec/hasp/lib/handler.h"
#include "util/log.h"
#include "server.h"
#define HASP_PORT 1947
#define HASP_MAX_BUFFER 16384
static bool sec_hasp_server_run_s;
static bool sec_hasp_server_is_running_s;
void sec_hasp_server_init(const uint8_t* key_data, size_t len)
{
sec_hasp_handler_init(key_data, len);
sec_hasp_server_run_s = true;
sec_hasp_server_is_running_s = false;
}
void sec_hasp_server_run()
{
int fd = -1;
struct sockaddr_in addr;
struct sockaddr_in addr_remote;
socklen_t addr_len_remote;
int fd_remote = -1;
int retval;
struct sec_hasp_handler_transaction* transaction;
ssize_t recv_len;
log_info("Setting up socket for server");
sec_hasp_server_is_running_s = true;
transaction = sec_hasp_handler_alloc_transaction(HASP_MAX_BUFFER);
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
log_error("Opening socket failed: %s", strerror(errno));
goto return_cleanup;
}
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
/* bind to localhost which limits accepting connections to localhost, only */
addr.sin_addr.s_addr = htonl(0x7F000001);
addr.sin_port = htons(HASP_PORT);
retval = bind(fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in));
if (retval == -1) {
log_error("Binding socket failed: %s", strerror(errno));
goto return_cleanup;
}
log_info("Running server...");
while (sec_hasp_server_run_s) {
/* a single connection is fine here */
retval = listen(fd, 1);
if (retval == -1) {
log_error("Listening for incoming connections failed: %s", strerror(errno));
goto return_cleanup;
}
/* got a connection */
addr_len_remote = sizeof(addr_remote);
fd_remote = accept(fd, &addr_remote, &addr_len_remote);
if (fd_remote == -1) {
log_error("Accepting incoming connection failed: %s", strerror(errno));
goto return_cleanup;
}
log_debug("Remote %X connected", addr_remote.sin_addr.s_addr);
/* put the socket to the remote into non blocking mode */
if (fcntl(fd_remote, F_SETFL, fcntl(fd_remote, F_GETFL) | O_NONBLOCK) < 0) {
log_error("Setting socket to non blocking failed: %s", strerror(errno));
goto return_cleanup;
}
while (sec_hasp_server_run_s) {
recv_len = recv(fd_remote, transaction->req, transaction->req_resp_max_size, 0);
if (recv_len == -1) {
/* no data available, sleep to reduce cpu load and retry */
if (errno == EAGAIN || errno == EWOULDBLOCK) {
/* 10 ms */
usleep(1000 * 10);
continue;
} else if (errno == ECONNRESET) {
log_debug("Remote %X disconnected", addr_remote.sin_addr.s_addr);
close(fd_remote);
break;
} else {
log_error("Reading from connection failed: %s", strerror(errno));
goto return_cleanup;
}
}
if (recv_len == 0) {
/* remote disconnected */
log_debug("Remote %X disconnected", addr_remote.sin_addr.s_addr);
close(fd_remote);
break;
}
log_debug("Received data: %d bytes", recv_len);
sec_hasp_handler_do_transaction(transaction);
/* send reply */
recv_len = send(fd_remote, transaction->resp, transaction->resp->header.packet_size, 0);
if (recv_len == -1) {
if (errno == ECONNRESET) {
log_debug("Remote %X disconnected", addr_remote.sin_addr.s_addr);
close(fd_remote);
break;
} else {
log_error("Writing to connection failed: %s", strerror(errno));
goto return_cleanup;
}
}
}
}
return_cleanup:
if (fd_remote != -1) {
close(fd);
}
if (fd != -1) {
close(fd);
}
sec_hasp_handler_free_transaction(transaction);
sec_hasp_server_is_running_s = false;
}
bool sec_hasp_server_is_running(void)
{
return sec_hasp_server_is_running_s;
}
void sec_hasp_server_shutdown(void)
{
sec_hasp_server_run_s = false;
}
+33
View File
@@ -0,0 +1,33 @@
#ifndef SEC_HASP_SERVER_H
#define SEC_HASP_SERVER_H
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
/**
* Initialize the hasp server module. This just initializes the hasp
* dongle emulator module
*
* @param key_data Pointer to loaded key data (attributes, key table)
* @param len Length of the buffer
*/
void sec_hasp_server_init(const uint8_t* key_data, size_t len);
/**
* Run the server. This call blocks until the server is shut down.
* Recommended to run this in a separate thread.
*/
void sec_hasp_server_run(void);
/**
* Check if the server is running
*/
bool sec_hasp_server_is_running(void);
/**
* Signal a shut down to the server
*/
void sec_hasp_server_shutdown(void);
#endif
+15
View File
@@ -0,0 +1,15 @@
#include <time.h>
#include "util/rand.h"
#include "util.h"
uint32_t sec_hasp_util_make_fake_handle_value()
{
return util_rand_gen_32();
}
uint32_t sec_hasp_util_get_timestamp()
{
return (uint32_t) time(NULL);
}
+10
View File
@@ -0,0 +1,10 @@
#ifndef SEC_HASP_UTIL_H
#define SEC_HASP_UTIL_H
#include <stdint.h>
uint32_t sec_hasp_util_make_fake_handle_value();
uint32_t sec_hasp_util_get_timestamp();
#endif
+87
View File
@@ -0,0 +1,87 @@
#define LOG_MODULE "sec-hasp"
#include <string.h>
#include "sec/hasp/old/hasp.h"
#include "util/log.h"
#include "util/mem.h"
#include "util/str.h"
struct sec_hasp_key_table {
uint32_t nkeys;
struct sec_hasp_key* keys;
};
/* index 0 (type): 1 = dev, 2 = retail
index 1 (language): 3001 = english */
/* static const uint32_t sec_hasp_features[] = {2, 3001}; */
static const uint32_t sec_hasp_key_id = 0xDEADBEEF;
static struct sec_hasp_key_table sec_hasp_keys;
void sec_hasp_init(const uint8_t* key_data, size_t len)
{
sec_hasp_keys.nkeys = len / sizeof(struct sec_hasp_key);
sec_hasp_keys.keys =
util_xmalloc(sizeof(struct sec_hasp_key) * sec_hasp_keys.nkeys);
memcpy(sec_hasp_keys.keys, key_data,
sec_hasp_keys.nkeys * sizeof(struct sec_hasp_key));
log_info("Loaded %d keys", sec_hasp_keys.nkeys);
}
int sec_hasp_api_login(int feature, int vendor_code, int* handle)
{
*handle = (int) &sec_hasp_key_id;
log_debug("login, feature %d, vendor_code %d, ret handle 0x%X", feature,
vendor_code, *handle);
return 0;
}
int sec_hasp_api_logout(int handle)
{
if (handle != (int) &sec_hasp_key_id) {
log_error("Logout of unknown handle 0x%X", handle);
} else {
log_debug("Logout: 0x%X", handle);
}
return 0;
}
unsigned int sec_hasp_api_getid(void)
{
return sec_hasp_key_id;
}
int sec_hasp_api_decrypt(int handle, void* buffer, size_t length)
{
char* buf;
if (handle != (int) &sec_hasp_key_id) {
log_error("Unknown handle 0x%X sending decrypt request, ignored");
return -1;
}
for (uint32_t i = 0; i < sec_hasp_keys.nkeys; i++) {
if (!memcmp(buffer, sec_hasp_keys.keys[i].req,
sizeof(sec_hasp_keys.keys[i].req))) {
log_debug("Decrypt %u -> %u",
*((uint64_t*) sec_hasp_keys.keys[i].req),
*((uint64_t*) sec_hasp_keys.keys[i].resp));
memcpy(buffer, sec_hasp_keys.keys[i].resp,
sizeof(sec_hasp_keys.keys[i].resp));
return 0;
}
}
buf = util_str_buffer(buffer, length);
log_warn("Missing key for request %s", buf);
free(buf);
return 0;
}
+35
View File
@@ -0,0 +1,35 @@
/**
* Hasp emulator (Fiesta 2 and up)
*/
#ifndef SEC_HASP_H
#define SEC_HASP_H
#include <stdint.h>
#include <stdlib.h>
/**
* A single entry in the key table
*/
struct sec_hasp_key {
uint8_t req[64];
uint8_t resp[64];
} __attribute__((packed));
/**
* Initialize the hasp emulation module. The dongle for this
* was used on Prime and up
*
* @param key_data Pointer to loaded key data (key table)
* @param len Length of the buffer
*/
void sec_hasp_init(const uint8_t* key_data, size_t len);
int sec_hasp_api_login(int feature, int vendor_code, int* handle);
int sec_hasp_api_logout(int handle);
unsigned int sec_hasp_api_getid(void);
int sec_hasp_api_decrypt(int handle, void* buffer, size_t length);
#endif
+7
View File
@@ -0,0 +1,7 @@
#include "sec/hasp/lib/server.h"
int main(int argc, char** argv)
{
sec_hasp_server_init(NULL, 0);
sec_hasp_server_run();
}
+64
View File
@@ -0,0 +1,64 @@
#ifndef SEC_LOCKCHIP_DEFS_H
#define SEC_LOCKCHIP_DEFS_H
#include <stdint.h>
/* List of games using the old type mk3 lockchip board */
enum sec_lockchip_defs_games {
SEC_LOCK_CHIP_DEFS_GAME_3RD_SE = 0,
SEC_LOCK_CHIP_DEFS_GAME_COLLECTION = 1,
SEC_LOCK_CHIP_DEFS_GAME_PERFECT_COLLECTION = 2,
SEC_LOCK_CHIP_DEFS_GAME_EXTRA_PROTO = 3,
SEC_LOCK_CHIP_DEFS_GAME_PREMIERE = 4,
SEC_LOCK_CHIP_DEFS_GAME_PREX = 5,
SEC_LOCK_CHIP_DEFS_GAME_REBIRTH = 6,
SEC_LOCK_CHIP_DEFS_GAME_PREMIERE_2 = 7,
/* Extra Plus */
SEC_LOCK_CHIP_DEFS_GAME_PREX_2_BETA = 8,
SEC_LOCK_CHIP_DEFS_GAME_PREX_2 = 9,
SEC_LOCK_CHIP_DEFS_GAME_PREMIERE_3 = 10,
SEC_LOCK_CHIP_DEFS_GAME_PREX_3 = 11,
SEC_LOCK_CHIP_DEFS_GAME_EXTRA = 12,
/* NXA for mk3, funbox... */
SEC_LOCK_CHIP_DEFS_GAME_BOOTLEGS = 13,
SEC_LOCK_CHIP_DEFS_GAME_EXCEED = 14,
SEC_LOCK_CHIP_DEFS_GAME_COUNT = 15,
};
/** List of lockchip transforms of all pump games that used it.
*/
static const uint8_t sec_lockchip_defs_transforms
[SEC_LOCK_CHIP_DEFS_GAME_COUNT][8] = {
/* 3rd SE */
{0xF0, 0x1C, 0xFE, 0x03, 0x81, 0x40, 0x38, 0xF8},
/* Collection */
{0xF0, 0x1C, 0xFE, 0x03, 0x81, 0x40, 0x38, 0xF8},
/* Perfect Collection */
{0xF0, 0x1C, 0xFE, 0x03, 0x81, 0x40, 0x38, 0xF8},
/* Extra Proto */
{0xF8, 0x82, 0x70, 0x0C, 0xFD, 0xC1, 0x20, 0xE0},
/* Premiere */
{0xE0, 0x78, 0x7C, 0xFD, 0xF1, 0xF2, 0xC2, 0xC0},
/* Prex */
{0xE0, 0x78, 0x7C, 0xFD, 0xF1, 0xF2, 0xC2, 0xC0},
/* Rebirth */
{0xFC, 0xF9, 0x08, 0x10, 0xE2, 0xC2, 0x40, 0x80},
/* Premiere 2 */
{0xFC, 0x03, 0xE1, 0x20, 0x38, 0x78, 0x70, 0xF0},
/* Prex 2 Beta */
{0xE0, 0x38, 0x78, 0x81, 0x03, 0xFE, 0x0C, 0xF0},
/* Prex 2 */
{0xE0, 0x38, 0x78, 0x81, 0x03, 0xFE, 0x0C, 0xF0},
/* Premiere 3 */
{0x02, 0xC1, 0xF9, 0x78, 0x7C, 0x1C, 0x10, 0xF0},
/* Prex 3 */
{0xF0, 0xE1, 0xF9, 0x78, 0x7C, 0xFE, 0xC2, 0xC0},
/* Extra */
{0xF8, 0x82, 0x70, 0x0C, 0xFD, 0xC1, 0x20, 0xE0},
/* Bootlegs */
{0x02, 0xC1, 0xF9, 0x78, 0x7C, 0x1C, 0x10, 0xF0},
/* Exceed */
{0xF0, 0x78, 0xF9, 0xFD, 0x1C, 0x20, 0xC2, 0x02},
};
#endif
+87
View File
@@ -0,0 +1,87 @@
#define LOG_MODULE "sec-lockchip"
#include "sec/lockchip/lockchip.h"
static const uint8_t sec_lockchip_initial_sbox[8] = {
0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x7f
};
static const uint8_t* sec_lockchip_transform;
static uint8_t sec_lockchip_state;
static void sec_lockchip_apply_initial_sbox(void)
{
uint8_t r = 0;
for (uint8_t i = 0; i < 8; i++) {
if (sec_lockchip_state & (1 << i)) {
r ^= sec_lockchip_initial_sbox[i];
}
}
sec_lockchip_state = r;
}
static uint8_t sec_lockchip_comp_sbox_ceof(uint8_t sel, uint8_t bit)
{
uint8_t r ;
if (!sel) {
return sec_lockchip_transform[bit];
}
r = sec_lockchip_comp_sbox_ceof((sel - 1) & 7, (bit - 1) & 7);
r = (r << 1) | (((r >> 7) ^ (r >> 6)) & 1);
if (bit != 7) {
return r;
}
return r ^ sec_lockchip_comp_sbox_ceof(sel, 0);
}
static void sec_lockchip_apply_bit_sbox(uint8_t bit)
{
uint8_t r = 0;
for (uint8_t i = 0; i < 8; i++) {
if (sec_lockchip_state & (1 << i)) {
r ^= sec_lockchip_comp_sbox_ceof(bit, i);
}
}
sec_lockchip_state = r;
}
void sec_lockchip_init(const uint8_t* transform)
{
sec_lockchip_transform = transform;
sec_lockchip_state = 0;
}
void sec_lockchip_start(void)
{
sec_lockchip_state = 0xFC;
}
uint8_t sec_lockchip_step(uint8_t data)
{
uint8_t result = 0;
for (uint8_t bit = 0; bit < 8; bit++) {
if (bit == 0) {
sec_lockchip_apply_initial_sbox();
}
result ^= (((sec_lockchip_state >> bit) & 1) << bit);
if (((data >> bit) & 1) == 0) {
sec_lockchip_apply_bit_sbox(bit);
}
}
return result;
}
+31
View File
@@ -0,0 +1,31 @@
/**
* Lockchip (MK3 games) emulator
*
* Credits to TheSchaf for the emulation code and transform data
*/
#ifndef SEC_LOCKCHIP_H
#define SEC_LOCKCHIP_H
#include <stdint.h>
/**
* Initialize (or reset) the lockchip emulation module
*
* @param transform Pointer to a transform to use for the step calls
*/
void sec_lockchip_init(const uint8_t* transform);
/**
* Start lockchip emulation and set the initial state before calling step
*/
void sec_lockchip_start(void);
/**
* Execute a step on some data
*
* @param data Input data to transform
* @return Transformed output
*/
uint8_t sec_lockchip_step(uint8_t data);
#endif
+399
View File
@@ -0,0 +1,399 @@
#define LOG_MODULE "sec-microdog34"
#include <stdlib.h>
#include <string.h>
#include "util/log.h"
#include "util/mem.h"
#include "util/str.h"
#define IOCTL_REQUEST_MD_XACT 0x6B00
#define GOLD_SALT 0x646C6F47
#define MAGIC 0x484D
enum sec_microdog34_req_opcode {
SEC_MICRODOG34_OP_DOG_CHECK = 0x01,
SEC_MICRODOG34_OP_READ_DOG = 0x02,
SEC_MICRODOG34_OP_WRITE_DOG = 0x03,
SEC_MICRODOG34_OP_CONVERT = 0x04,
SEC_MICRODOG34_OP_SET_PASS = 0x07,
SEC_MICRODOG34_OP_SET_SHARE = 0x08,
SEC_MICRODOG34_OP_GET_LOCK_NO = 0x0B,
SEC_MICRODOG34_OP_LOGIN = 0x14,
SEC_MICRODOG34_OP_DOG_CASCADE = 0x15,
SEC_MICRODOG34_OP_RAINBOW_TABLE_ADD = 0x539,
SEC_MICRODOG34_OP_DOG_SERIAL = 0x53A,
SEC_MICRODOG34_OP_SET_MFG_SERIAL = 0x53B,
SEC_MICRODOG34_OP_SET_VID = 0x53C,
SEC_MICRODOG34_OP_RELOAD_RAINBOW_TABLE = 0x53D
};
struct sec_microdog34_req {
uint16_t magic;
uint16_t opcode;
uint32_t dog_serial;
uint32_t mask_key;
uint16_t dog_addr;
uint16_t dog_bytes;
uint8_t dog_data[256];
uint32_t dog_password;
uint8_t host_id;
} __attribute__((__packed__));
enum sec_microdog34_resp_code {
SEC_MICRODOG34_RESP_NO_ERR = 0,
SEC_MICRODOG34_RESP_ERR_PASS = 0x2745
};
struct sec_microdog34_resp {
uint32_t dog_serial;
uint32_t return_code;
uint8_t dog_data[200];
} __attribute__((__packed__));
struct sec_microdog34_header {
uint32_t serial;
uint32_t password;
uint8_t vendor_id[8];
uint32_t mfg_serial;
uint8_t flash_memory[200];
uint32_t num_keys;
};
struct sec_microdog34_key {
uint32_t response;
uint32_t algorithm;
uint32_t req_len;
uint8_t request[64];
};
static void sec_microdog34_dispatch(struct sec_microdog34_req* req,
struct sec_microdog34_resp* resp);
static void sec_microdog34_crypt_req(struct sec_microdog34_req* req);
static void sec_microdog34_crypt_resp(struct sec_microdog34_req* req,
struct sec_microdog34_resp* resp);
static void sec_microdog34_dump_req(struct sec_microdog34_req* req);
static void sec_microdog34_dump_resq(struct sec_microdog34_resp* resp);
static uint32_t sec_microdog34_convert_req(const uint8_t* req_data,
uint16_t req_len);
static struct sec_microdog34_header sec_microdog34_header;
static struct sec_microdog34_key* sec_microdog34_key_table;
static uint8_t sec_microdog34_share;
void sec_microdog34_init(const uint8_t* key_data, size_t len)
{
memcpy(&sec_microdog34_header, key_data,
sizeof(struct sec_microdog34_header));
if (len - sizeof(struct sec_microdog34_header) <
sec_microdog34_header.num_keys *
sizeof(struct sec_microdog34_key)) {
log_error("Loading key table failed, incomplete key table "
"(num_keys entry: %d, num_keys size: %d",
sec_microdog34_header.num_keys,
(len - sizeof(struct sec_microdog34_header)) /
sizeof(struct sec_microdog34_key));
return;
}
sec_microdog34_key_table = util_xmalloc(sec_microdog34_header.num_keys *
sizeof(struct sec_microdog34_key));
memcpy(sec_microdog34_key_table,
key_data + sizeof(struct sec_microdog34_header),
sec_microdog34_header.num_keys * sizeof(struct sec_microdog34_key));
log_info("Loaded %d keys, serial 0x%X, password 0x%X",
sec_microdog34_header.num_keys, sec_microdog34_header.serial,
sec_microdog34_header.password);
sec_microdog34_share = 0;
}
int sec_microdog34_process(int request, void* data)
{
if (request == IOCTL_REQUEST_MD_XACT) {
struct sec_microdog34_req req;
struct sec_microdog34_resp resp;
memset(&resp, 0, sizeof(struct sec_microdog34_resp));
// where to get the data? weird stuff, but that's how it's done
// it really has to be like that, otherwise we get trash from data
uint32_t req_data_offset = *(unsigned int*) data;
memcpy(&req, (void*) req_data_offset,
sizeof(struct sec_microdog34_req));
sec_microdog34_crypt_req(&req);
sec_microdog34_dispatch(&req, &resp);
sec_microdog34_crypt_resp(&req, &resp);
// again, same as req data
// it really has to be like that, otherwise we get trash from data
uint32_t resp_data_offset = *(unsigned int*) data - 272;
memcpy((void*) resp_data_offset, &resp,
sizeof(struct sec_microdog34_resp));
return 0;
}
return -1;
}
static void sec_microdog34_dispatch(struct sec_microdog34_req* req,
struct sec_microdog34_resp* resp)
{
struct sec_microdog34_key* key;
resp->dog_serial = req->dog_serial;
if (req->magic != MAGIC) {
log_error("Bad magic 0x%X for request", req->magic);
}
sec_microdog34_dump_req(req);
switch (req->opcode) {
case SEC_MICRODOG34_OP_DOG_CHECK:
log_debug("SEC_MICRODOG34_OP_DOG_CHECK");
break;
case SEC_MICRODOG34_OP_READ_DOG:
log_debug("SEC_MICRODOG34_OP_READ_DOG");
if (req->dog_password == sec_microdog34_header.password) {
memcpy(resp->dog_data,
sec_microdog34_header.flash_memory + req->dog_addr,
req->dog_bytes);
} else {
resp->return_code = SEC_MICRODOG34_RESP_ERR_PASS;
}
break;
case SEC_MICRODOG34_OP_WRITE_DOG:
log_debug("SEC_MICRODOG34_OP_WRITE_DOG");
if (req->dog_password == sec_microdog34_header.password) {
memcpy(sec_microdog34_header.flash_memory + req->dog_addr,
req->dog_data, req->dog_bytes);
} else {
resp->return_code = SEC_MICRODOG34_RESP_ERR_PASS;
}
break;
case SEC_MICRODOG34_OP_CONVERT:
log_debug("SEC_MICRODOG34_OP_CONVERT");
uint32_t resp_data = sec_microdog34_convert_req(req->dog_data,
req->dog_bytes);
memcpy(resp->dog_data, &resp_data, sizeof(uint32_t));
break;
case SEC_MICRODOG34_OP_SET_PASS:
log_debug("SEC_MICRODOG34_OP_SET_PASS: 0x%08X",
*((uint32_t*) req->dog_data));
if (req->dog_password == sec_microdog34_header.password) {
sec_microdog34_header.password = *((uint32_t*) req->dog_data);
}
else
resp->return_code = SEC_MICRODOG34_RESP_ERR_PASS;
break;
case SEC_MICRODOG34_OP_SET_SHARE:
log_debug("SEC_MICRODOG34_OP_SET_SHARE");
sec_microdog34_share = req->dog_data[0];
resp->dog_data[0] = sec_microdog34_share;
break;
case SEC_MICRODOG34_OP_GET_LOCK_NO:
log_debug("SEC_MICRODOG34_OP_GET_LOCK_NO: 0x%08X",
sec_microdog34_header.mfg_serial);
memcpy(resp->dog_data, &sec_microdog34_header.mfg_serial, 4);
break;
case SEC_MICRODOG34_OP_LOGIN:
log_debug("SEC_MICRODOG34_OP_LOGIN");
memcpy(resp->dog_data, sec_microdog34_header.vendor_id,
sizeof(sec_microdog34_header.vendor_id));
break;
case SEC_MICRODOG34_OP_DOG_CASCADE:
log_debug("SEC_MICRODOG34_OP_DOG_CASCADE");
resp->dog_data[0] = req->dog_data[0];
break;
case SEC_MICRODOG34_OP_RAINBOW_TABLE_ADD:
log_debug("SEC_MICRODOG34_OP_RAINBOW_TABLE_ADD");
/* expand table */
sec_microdog34_key_table = util_xrealloc(sec_microdog34_key_table,
(sec_microdog34_header.num_keys + 1) *
sizeof(struct sec_microdog34_key));
key = &sec_microdog34_key_table[sec_microdog34_header.num_keys];
key->response = req->dog_password;
/* algorithm(last 4 bytes of flash memory) */
key->algorithm =
*((uint32_t*) (sec_microdog34_header.flash_memory + 196));
key->req_len = req->dog_bytes;
memcpy(key->request, req->dog_data, sizeof(key->request));
sec_microdog34_header.num_keys++;
break;
case SEC_MICRODOG34_OP_DOG_SERIAL:
log_debug("SEC_MICRODOG34_OP_DOG_SERIAL: 0x%08X",
*((uint32_t*) req->dog_data));
sec_microdog34_header.serial = *((uint32_t*) req->dog_data);
break;
case SEC_MICRODOG34_OP_SET_MFG_SERIAL:
log_debug("SEC_MICRODOG34_OP_SET_MFG_SERIAL: 0x%08X ",
*((uint32_t*) req->dog_data));
sec_microdog34_header.mfg_serial = *((uint32_t*) req->dog_data);
break;
case SEC_MICRODOG34_OP_SET_VID:
log_debug("SEC_MICRODOG34_OP_SET_VID");
memcpy(sec_microdog34_header.vendor_id, req->dog_data,
sizeof(sec_microdog34_header.vendor_id));
break;
case SEC_MICRODOG34_OP_RELOAD_RAINBOW_TABLE:
log_debug("SEC_MICRODOG34_OP_RELOAD_RAINBOW_TABLE");
/* nothing to load here */
break;
default:
log_warn("Unsupported opcode: %04X", req->opcode);
break;
}
sec_microdog34_dump_resq(resp);
}
static void sec_microdog34_crypt_req(struct sec_microdog34_req* req)
{
uint32_t tmp_mask = (req->mask_key + GOLD_SALT) & 0xFFFFFFFF;
uint8_t tmb_mask[4] = {0, 0, 0, 0};
memcpy(tmb_mask, &tmp_mask, 4);
req->dog_addr ^= (tmp_mask & 0xFFFF);
req->dog_bytes ^= (tmp_mask & 0xFFFF);
req->dog_password ^= tmp_mask;
req->host_id ^= (tmp_mask & 0xFF);
for (int i = 0 ; i < sizeof(req->dog_data); i++) {
req->dog_data[i] ^= tmb_mask[i % 4];
}
}
static void sec_microdog34_crypt_resp(struct sec_microdog34_req* req,
struct sec_microdog34_resp* resp)
{
uint32_t tmp_mask = (req->mask_key + GOLD_SALT) & 0xFFFFFFFF;
uint8_t tmb_mask[4] = {0, 0, 0, 0};
memcpy(tmb_mask, &tmp_mask, 4);
for (int i = 0 ; i < sizeof(resp->dog_data); i++) {
resp->dog_data[i] ^= tmb_mask[i % 4];
}
}
static void sec_microdog34_dump_req(struct sec_microdog34_req* req)
{
char* data_tmp = util_str_buffer(req->dog_data, sizeof(req->dog_data));
log_debug(
"Dog request:\n"
"magic: 0x%X\n"
"opcode: 0x%X\n"
"dog_serial: 0x%X\n"
"mask_key: 0x%X\n"
"dog_addr: 0x%X\n"
"dog_bytes: 0x%X\n"
"dog_data: %s\n"
"dog_pass: 0x%X\n"
"host_id: 0x%X",
req->magic,
req->opcode,
req->dog_serial,
req->mask_key,
req->dog_addr,
req->dog_bytes,
data_tmp,
req->dog_password,
req->host_id);
free(data_tmp);
}
static void sec_microdog34_dump_resq(struct sec_microdog34_resp* resp)
{
char* data_tmp = util_str_buffer(resp->dog_data, sizeof(resp->dog_data));
log_debug(
"Dog response:\n"
"dog_serial: 0x%X\n"
"return_code: 0x%X\n"
"dog_data: %s\n",
resp->dog_serial,
resp->return_code,
data_tmp);
free(data_tmp);
}
static uint32_t sec_microdog34_convert_req(const uint8_t* req_data,
uint16_t req_len)
{
uint32_t cur_algo;
cur_algo = 0;
memcpy(&cur_algo, sec_microdog34_header.flash_memory + 196, 4);
for (uint32_t i = 0; i < sec_microdog34_header.num_keys; i++) {
struct sec_microdog34_key* key = &sec_microdog34_key_table[i];
if (key->algorithm == cur_algo) {
if (key->req_len == req_len) {
if (!memcmp(key->request, req_data, req_len)) {
char* tmp = util_str_buffer(req_data, req_len);
log_debug("Converting: %s ==> %X", tmp, key->response);
free(tmp);
return key->response;
}
}
}
}
char* tmp = util_str_buffer(req_data, req_len);
log_warn("Converting request %s failed, no matching response found", tmp);
free(tmp);
return 0;
}
+51
View File
@@ -0,0 +1,51 @@
/**
* Microdog 3.4 emulator
*
* Credits to batteryshark for the emulation code and key files
*/
#ifndef SEC_MICRODOG34_H
#define SEC_MICRODOG34_H
/**
* Header of a key file containing attributes of the dongle. This is followed
* by an arbitrary number of keys
*/
struct sec_microdog34_header {
uint32_t serial;
uint32_t password;
uint8_t vendor_id[8];
uint32_t mfg_serial;
uint8_t flash_memory[200];
uint32_t num_keys;
};
/**
* A single entry in the key table (comes after the header)
*/
struct sec_microdog34_key {
uint32_t response;
uint32_t algorithm;
uint32_t req_len;
uint8_t request[64];
};
/**
* Initialize the microdog (3.4) emulation module. The dongle for this
* was used on Exceed2, Zero and NX
*
* @param key_data Pointer to loaded key data (dog attributes, key table)
* @param len Length of the buffer
*/
void sec_microdog34_init(const uint8_t* key_data, size_t len);
/**
* Process an incoming request to the dongle
*
* @param request IOCTL request for the dongle
* @param data Pointer to a buffer with request data. Response is returned
* to the same buffer (request overwritten)
* @return 0 and success, -1 on failure
*/
int sec_microdog34_process(int request, void* data);
#endif
+427
View File
@@ -0,0 +1,427 @@
#define LOG_MODULE "sec-microdog40"
#include <string.h>
#include "crypt/aes.h"
#include "crypt/md5.h"
#include "sec/microdog40/microdog40.h"
#include "util/log.h"
#include "util/mem.h"
#include "util/str.h"
#define REQHEAD_SIZE 0x120
#define REQTAIL_SIZE 0x10
#define PROTOCOL_VERSION 0x11
enum sec_microdog40_req_opcode {
SEC_MICRODOG40_REQ_OPCODE_SET_SHARE = 0x08,
SEC_MICRODOG40_REQ_OPCODE_GET_LOCK_NO = 0x0B,
SEC_MICRODOG40_REQ_OPCODE_GET_ID = 0x14,
SEC_MICRODOG40_REQ_OPCODE_CONVERT = 0x40,
SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_1 = 0x65,
SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_2 = 0x67,
SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_3 = 0x66
};
struct sec_microdog40_month_key_hash_input {
uint8_t ssk_prefix[25];
uint16_t year;
uint8_t const45;
uint16_t month;
} __attribute((__packed__));
static const uint8_t sec_microdog40_shared_secret[30] = {
0x2A, 0x2F, 0xED, 0x5E, 0x49,
0x26, 0x40, 0x19, 0x40, 0x40,
0xE2, 0x51, 0xAA, 0xFA, 0xDB,
0xCB, 0x67, 0x21, 0x4C, 0xA4,
0x10, 0x7E, 0x51, 0x22, 0x25,
0x11, 0x2B, 0x3C, 0x46, 0x5E
};
static const uint16_t sec_microdog40_magic = 0x484D;
static struct sec_microdog40_header sec_microdog40_header;
static struct sec_microdog40_key* sec_microdog40_key_table;
static uint8_t sec_microdog40_share;
static void sec_microdog40_log_req(const struct sec_microdog40_req* req)
{
char* data_tmp = util_str_buffer(req->payload, sizeof(req->payload));
log_debug(
"Processing request:\n"
"magic: 0x%X\n"
"req_type: 0x%X\n"
"mask_key1: 0x%X\n"
"dog_cascade: 0x%X\n"
"mfg_serial: 0x%X\n"
"mask_key2: 0x%X\n"
"dog_addr: 0x%X\n"
"payload_size: %d\n"
"mask_key3: 0x%X\n"
"payload: %s\n"
"dog_password: 0x%X\n"
"host_id: 0x%X\n"
"mask_key4: 0x%X\n"
"timestamp.year: %d\n"
"timestamp.month: %d\n"
"timestamp.day: %d\n"
"timestamp.hour: %d\n"
"timestamp.minute: %d\n"
"timestamp.second: %d",
req->magic,
req->req_type,
req->mask_key1,
req->dog_cascade,
req->mfg_serial,
req->mask_key2,
req->dog_addr,
req->payload_size,
req->mask_key3,
data_tmp,
req->dog_password,
req->host_id,
req->mask_key4,
req->timestamp.year,
req->timestamp.month,
req->timestamp.day,
req->timestamp.hour,
req->timestamp.minute,
req->timestamp.second);
free(data_tmp);
}
static void sec_microdog40_get_month_key(uint8_t* month_key,
const struct sec_microdog40_timestamp* timestamp)
{
struct sec_microdog40_month_key_hash_input hash_in;
memcpy(hash_in.ssk_prefix, sec_microdog40_shared_secret,
sizeof(hash_in.ssk_prefix));
hash_in.year = timestamp->year;
hash_in.month = timestamp->month;
hash_in.const45 = 45;
crypt_md5_hash(month_key, (const uint8_t*) &hash_in,
sizeof(struct sec_microdog40_month_key_hash_input));
}
static void sec_microdog40_dec_req(const struct sec_microdog40_req* enc_req,
struct sec_microdog40_req* dec_req)
{
uint8_t key[16];
crypt_md5_hash(key, sec_microdog40_shared_secret,
sizeof(sec_microdog40_shared_secret));
crypt_aes_dec(key, CRYPT_AES_KEY_LENGTH_16_BYTES, ((uint8_t *) dec_req) +
REQHEAD_SIZE, ((uint8_t*) enc_req) + REQHEAD_SIZE, REQTAIL_SIZE);
sec_microdog40_get_month_key(key, &dec_req->timestamp);
crypt_aes_dec(key, CRYPT_AES_KEY_LENGTH_16_BYTES, ((uint8_t *) dec_req),
((uint8_t*) enc_req), REQHEAD_SIZE);
dec_req->magic ^= dec_req->mask_key4;
dec_req->req_type ^= dec_req->mask_key4;
dec_req->mask_key1 ^= dec_req->mask_key4;
dec_req->dog_cascade ^= dec_req->mask_key4;
dec_req->mfg_serial ^= dec_req->mask_key4;
dec_req->mask_key2 ^= dec_req->mask_key4;
dec_req->dog_addr ^= dec_req->mask_key4;
dec_req->payload_size ^= dec_req->mask_key4;
dec_req->mask_key3 ^= dec_req->mask_key4;
dec_req->dog_password ^= dec_req->mask_key4;
dec_req->host_id ^= dec_req->mask_key4;
for (int i = 0 ; i < 64 ; i++) {
((uint32_t *) dec_req->payload)[i] ^= dec_req->mask_key4;
}
dec_req->magic ^= dec_req->mask_key3;
dec_req->req_type ^= dec_req->mask_key3;
dec_req->mask_key1 ^= dec_req->mask_key3;
dec_req->dog_cascade ^= dec_req->mask_key3;
dec_req->mfg_serial ^= dec_req->mask_key3;
dec_req->mask_key2 ^= dec_req->mask_key3;
dec_req->dog_addr ^= dec_req->mask_key3;
dec_req->payload_size ^= dec_req->mask_key3;
dec_req->magic ^= dec_req->mask_key2;
dec_req->req_type ^= dec_req->mask_key2;
dec_req->mask_key1 ^= dec_req->mask_key2;
dec_req->dog_cascade ^= dec_req->mask_key2;
dec_req->mfg_serial ^= dec_req->mask_key2;
dec_req->magic ^= dec_req->mask_key1;
dec_req->req_type ^= dec_req->mask_key1;
}
/* unused */
/*
static void sec_microdog40_dec_resp(const struct sec_microdog40_resp* enc_resp,
struct sec_microdog40_resp* dec_resp,
const struct sec_microdog40_timestamp* timestamp)
{
uint8_t key[16];
sec_microdog40_get_month_key(key, timestamp);
crypt_aes_dec(key, CRYPT_AES_KEY_LENGTH_16_BYTES, (uint8_t*) dec_resp,
(uint8_t*) enc_resp, sizeof(struct sec_microdog40_resp));
for (int i = 0 ; i < 64 ; i++) {
((uint32_t *) dec_resp->payload)[i] ^= dec_resp->mask_key4;
}
dec_resp->mask_key3 ^= dec_resp->mask_key4;
dec_resp->krnl_retval ^= dec_resp->mask_key4;
dec_resp->mask_key2 ^= dec_resp->mask_key4;
dec_resp->req_type ^= dec_resp->mask_key4;
dec_resp->mask_key1 ^= dec_resp->mask_key4;
dec_resp->magic ^= dec_resp->mask_key4;
dec_resp->krnl_retval ^= dec_resp->mask_key3;
dec_resp->mask_key2 ^= dec_resp->mask_key3;
dec_resp->req_type ^= dec_resp->mask_key3;
dec_resp->mask_key1 ^= dec_resp->mask_key3;
dec_resp->magic ^= dec_resp->mask_key3;
dec_resp->req_type ^= dec_resp->mask_key2;
dec_resp->mask_key1 ^= dec_resp->mask_key2;
dec_resp->magic ^= dec_resp->mask_key2;
dec_resp->magic ^= dec_resp->mask_key1;
}
*/
/* unused */
/*
static void sec_microdog40_enc_req(const struct sec_microdog40_req* dec_req,
struct sec_microdog40_req* enc_req)
{
uint8_t key[16];
// Mask keying not necessary
sec_microdog40_get_month_key(key, &dec_req->timestamp);
crypt_aes_enc(key, CRYPT_AES_KEY_LENGTH_16_BYTES, (uint8_t*) enc_req,
(uint8_t*) dec_req, sizeof(struct sec_microdog40_req));
crypt_md5_hash(key, sec_microdog40_shared_secret,
sizeof(sec_microdog40_shared_secret));
crypt_aes_enc(key, CRYPT_AES_KEY_LENGTH_16_BYTES, ((uint8_t*) enc_req) +
REQHEAD_SIZE, ((uint8_t*) &dec_req) + REQHEAD_SIZE, REQTAIL_SIZE);
}
*/
static void sec_microdog40_encrypt_resp(
const struct sec_microdog40_resp* dec_resp,
struct sec_microdog40_resp* enc_resp,
const struct sec_microdog40_timestamp* timestamp)
{
uint8_t key[16];
sec_microdog40_get_month_key(key, timestamp);
crypt_aes_enc(key, CRYPT_AES_KEY_LENGTH_16_BYTES, (uint8_t*) enc_resp,
(uint8_t*) dec_resp, sizeof(struct sec_microdog40_resp));
}
static uint32_t sec_microdog40_convert_req(const uint8_t* req_data,
uint16_t req_len)
{
uint32_t cur_algo;
cur_algo = 0;
memcpy(&cur_algo, sec_microdog40_header.flash_memory + 196, 4);
for (uint32_t i = 0; i < sec_microdog40_header.num_keys; i++) {
struct sec_microdog40_key* key = &sec_microdog40_key_table[i];
if (key->algorithm == cur_algo) {
if (key->req_len == req_len) {
if (!memcmp(key->request, req_data, req_len)) {
char* tmp = util_str_buffer(req_data, req_len);
log_debug("Converting: %s ==> %X", tmp, key->response);
free(tmp);
return key->response;
}
}
}
}
char* tmp = util_str_buffer(req_data, req_len);
log_warn("Converting request %s failed, no matching response found", tmp);
free(tmp);
return 0;
}
static void sec_microdog40_dispatch(const struct sec_microdog40_req* req,
struct sec_microdog40_resp* resp)
{
// prepare response
resp->magic = sec_microdog40_magic;
resp->req_type = req->req_type;
if (req->magic != sec_microdog40_magic) {
log_warn("Bad magic for request: %X", req->magic);
}
sec_microdog40_log_req(req);
switch (req->req_type)
{
case SEC_MICRODOG40_REQ_OPCODE_SET_SHARE:
{
log_debug("SEC_MICRODOG40_REQ_OPCODE_SET_SHARE");
sec_microdog40_share = req->payload[0];
break;
}
case SEC_MICRODOG40_REQ_OPCODE_GET_LOCK_NO:
{
log_debug("SEC_MICRODOG40_REQ_OPCODE_GET_LOCK_NO 0x%08X",
sec_microdog40_header.mfg_serial);
memcpy(resp->payload, &sec_microdog40_header.mfg_serial, 4);
break;
}
case SEC_MICRODOG40_REQ_OPCODE_GET_ID:
{
log_debug("SEC_MICRODOG40_REQ_OPCODE_GET_ID 0x%02X 0x%02X 0x%02X "
"0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
sec_microdog40_header.vendor_id[0],
sec_microdog40_header.vendor_id[1],
sec_microdog40_header.vendor_id[2],
sec_microdog40_header.vendor_id[3],
sec_microdog40_header.vendor_id[4],
sec_microdog40_header.vendor_id[5],
sec_microdog40_header.vendor_id[6],
sec_microdog40_header.vendor_id[7]);
memcpy(resp->payload, sec_microdog40_header.vendor_id,
sizeof(sec_microdog40_header.vendor_id));
break;
}
case SEC_MICRODOG40_REQ_OPCODE_CONVERT:
{
uint32_t resp_data;
log_debug("SEC_MICRODOG40_REQ_OPCODE_CONVERT");
resp_data = sec_microdog40_convert_req(req->payload,
req->payload_size);
memcpy(resp->payload, &resp_data, sizeof(uint32_t));
break;
}
case SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_1:
{
log_debug("SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_1");
/* no-op */
break;
}
case SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_2:
{
log_debug("SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_2");
/* no-op */
break;
}
case SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_3:
{
uint8_t month_key[16];
log_debug("SEC_MICRODOG40_REQ_OPCODE_AUTH_STEP_3");
sec_microdog40_get_month_key(month_key, &req->timestamp);
crypt_aes_enc(month_key, CRYPT_AES_KEY_LENGTH_16_BYTES,
resp->payload, req->payload, 16);
break;
}
default:
{
log_warn("Unsupported Opcode: %04X", req->req_type);
resp->magic = 0; // mark to indicate error
break;
}
}
}
void sec_microdog40_init(const uint8_t* key_data, size_t len)
{
if (len < sizeof(struct sec_microdog40_header)) {
log_error("Loading key table failed, incomplete header");
return;
}
memcpy(&sec_microdog40_header, key_data,
sizeof(struct sec_microdog40_header));
if (len - sizeof(struct sec_microdog40_header) <
sec_microdog40_header.num_keys *
sizeof(struct sec_microdog40_key)) {
log_error("Loading key table failed, incomplete key table");
return;
}
sec_microdog40_key_table = util_xmalloc(sec_microdog40_header.num_keys *
sizeof(struct sec_microdog40_key));
memcpy(sec_microdog40_key_table,
key_data + sizeof(struct sec_microdog40_header),
sec_microdog40_header.num_keys * sizeof(struct sec_microdog40_key));
log_info("Loaded %d keys, serial 0x%X, password 0x%X",
sec_microdog40_header.num_keys, sec_microdog40_header.serial,
sec_microdog40_header.password);
sec_microdog40_share = 0;
}
bool sec_microdog40_do_transaction(
struct sec_microdog40_transaction* transaction)
{
struct sec_microdog40_req dec_req;
struct sec_microdog40_resp dec_resp;
if (transaction->header != PROTOCOL_VERSION) {
log_error("Wrong protocol version of transaction %X.",
transaction->header);
return false;
}
log_debug("Decrypting request...");
sec_microdog40_dec_req(&transaction->request, &dec_req);
sec_microdog40_dispatch(&dec_req, &dec_resp);
/* no error */
if (dec_resp.magic != 0) {
transaction->header = 0;
log_debug("Encrypting response...");
sec_microdog40_encrypt_resp(&dec_resp, &transaction->response,
&dec_req.timestamp);
} else {
transaction->header = 20023;
log_error("Transaction failed.");
}
log_debug("Transaction successful");
return true;
}
+111
View File
@@ -0,0 +1,111 @@
/**
* Microdog 4.0 emulator
*
* Credits to batteryshark for the emulation code and key files
*/
#ifndef SEC_MICRODOG40_H
#define SEC_MICRODOG40_H
#include <stdbool.h>
#include <stdint.h>
/**
* Header of a key file containing attributes of the dongle. This is followed
* by an arbitrary number of keys
*/
struct sec_microdog40_header {
uint32_t serial;
uint32_t password;
uint8_t vendor_id[8];
uint32_t mfg_serial;
uint8_t flash_memory[200];
uint32_t num_keys;
};
/**
* A single entry in the key table (comes after the header)
*/
struct sec_microdog40_key {
uint32_t response;
uint32_t algorithm;
uint32_t req_len;
uint8_t request[64];
};
/**
* Timestamp for a dongle request
*/
struct sec_microdog40_timestamp {
uint16_t year;
uint16_t month;
uint16_t day;
uint16_t hour;
uint16_t minute;
uint16_t second;
uint8_t padding[3];
} __attribute((__packed__));
/**
* Request to the dongle as part of a transaction
*/
struct sec_microdog40_req {
uint16_t magic;
uint8_t req_type;
uint32_t mask_key1;
uint8_t dog_cascade;
uint32_t mfg_serial;
uint32_t mask_key2;
uint16_t dog_addr;
uint16_t payload_size;
uint32_t mask_key3;
uint8_t payload[256];
uint32_t dog_password;
uint8_t host_id;
uint32_t mask_key4;
struct sec_microdog40_timestamp timestamp;
} __attribute((__packed__));
/**
* Dongle response as part of a transaction
*/
struct sec_microdog40_resp {
uint16_t magic;
uint32_t mask_key1;
uint8_t req_type;
uint32_t mask_key2;
uint32_t krnl_retval;
uint32_t mask_key3;
uint8_t payload[256];
uint32_t mask_key4;
uint8_t padding[9];
} __attribute((__packed__));
/**
* Dongle emulator transaction data
*/
struct sec_microdog40_transaction {
uint32_t header;
struct sec_microdog40_req request;
struct sec_microdog40_resp response;
} __attribute((__packed__));
/**
* Initialize the microdog (4.0) emulation module. The dongle for this
* was used on NX2, NXA, Fiesta and FiestaEX
*
* @param key_data Pointer to loaded key data (dog attributes, key table)
* @param len Length of the buffer
*/
void sec_microdog40_init(const uint8_t* key_data, size_t len);
/**
* Execute a transaction on the dongle
*
* @param transaction Transaction containing the request. The response is
* written to it after successfully processing the request
* @return True if the request was successfully processed and a response was
* written, false on failure
*/
bool sec_microdog40_do_transaction(struct sec_microdog40_transaction* transaction);
#endif
+109
View File
@@ -0,0 +1,109 @@
#define LOG_MODULE "sec-microdog40d"
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>
#include "sec/microdog40/microdog40.h"
#include "util/log.h"
static const char* sec_microdog40d_sock_path = "/var/run/microdog/u.daemon";
static bool sec_microdog40d_run_d;
static bool sec_microdog40d_is_running_d;
void sec_microdog40d_init(const uint8_t* key_data, size_t len)
{
sec_microdog40_init(key_data, len);
sec_microdog40d_run_d = true;
sec_microdog40d_is_running_d = false;
}
void sec_microdog40d_run(void)
{
int fd;
struct sec_microdog40_transaction transaction;
struct sockaddr_un peer_addr;
socklen_t peer_addr_len;
int retval;
sec_microdog40d_is_running_d = true;
fd = -1;
peer_addr_len = sizeof(peer_addr);
retval = 0;
unlink(sec_microdog40d_sock_path);
/* make sure /var/run/microdog folder exists */
mkdir("/var/run/microdog", 0700);
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (fd == -1) {
log_error("Opening socket failed: %s", strerror(errno));
sec_microdog40d_is_running_d = false;
return;
}
memset(&peer_addr, 0, sizeof(struct sockaddr_un));
peer_addr.sun_family = AF_UNIX;
strcpy(peer_addr.sun_path, sec_microdog40d_sock_path);
retval = bind(fd, (struct sockaddr *) &peer_addr,
sizeof(struct sockaddr_un));
if (retval == -1) {
log_error("Binding socket failed: %s", strerror(errno));
sec_microdog40d_is_running_d = false;
return;
}
while (sec_microdog40d_run_d) {
peer_addr_len = sizeof(peer_addr);
retval = recvfrom(fd, &transaction,
sizeof(struct sec_microdog40_transaction), 0,
(struct sockaddr *) &peer_addr, &peer_addr_len);
if (retval == -1) {
if (errno == EBADF) {
break;
} else {
log_error("Receiving data failed: %s", strerror(errno));
sec_microdog40d_is_running_d = false;
return;
}
} else if (retval != sizeof(struct sec_microdog40_transaction)) {
log_warn("Package too short, expected %d bytes, got %d bytes",
sizeof(struct sec_microdog40_transaction), retval);
} else {
if (sec_microdog40_do_transaction(&transaction)) {
sendto(fd, &transaction,
sizeof(struct sec_microdog40_transaction), 0,
(struct sockaddr *) &peer_addr, peer_addr_len);
} else {
log_error("Transaction failed.");
}
}
}
// cleanup
close(fd);
unlink(sec_microdog40d_sock_path);
sec_microdog40d_is_running_d = false;
}
bool sec_microdog40d_is_running(void)
{
return sec_microdog40d_is_running_d;
}
void sec_microdog40d_shutdown(void)
{
sec_microdog40d_run_d = false;
}
+35
View File
@@ -0,0 +1,35 @@
/**
* Microdog 4.0 daemon module
*/
#ifndef SEC_MICRODOG40D_H
#define SEC_MICRODOG40D_H
#include <stdbool.h>
#include <stdint.h>
/**
* Initialize the microdog (4.0) daemon module. This just initializes the
* dongle emulator module
*
* @param key_data Pointer to loaded key data (dog attributes, key table)
* @param len Length of the buffer
*/
void sec_microdog40d_init(const uint8_t* key_data, size_t len);
/**
* Run the daemon. This call blocks until the daemon is shut down.
* Recommended to run this in a separate thread.
*/
void sec_microdog40d_run(void);
/**
* Check if the daemon is running
*/
bool sec_microdog40d_is_running(void);
/**
* Signal a shut down to the daemon
*/
void sec_microdog40d_shutdown(void);
#endif