#include "globals.h" #ifdef READER_DGCRYPT #include "reader-common.h" #define DEBUG 0 static const uint8_t dgcrypt_atr[8] = { 0x3B, 0xE9, 0x00, 0x00, 0x81, 0x31, 0xC3, 0x45 }; static const uint8_t cmd_CWKEY[5] = { 0x81, 0xD0, 0x00, 0x01, 0x08 }; static const uint8_t cmd_CAID[5] = { 0x81, 0xC0, 0x00, 0x01, 0x0A }; static const uint8_t cmd_SERIAL[5] = { 0x81, 0xD1, 0x00, 0x01, 0x10 }; static const uint8_t cmd_CARD_ID[5] = { 0x81, 0xD4, 0x00, 0x01, 0x05 }; static const uint8_t cmd_LABEL[5] = { 0x81, 0xD2, 0x00, 0x01, 0x10 }; //static const uint8_t cmd_SUBSYS[5] = { 0x81, 0xDD, 0x00, 0x10, 0x04 }; static const uint8_t cmd_ECM[3] = { 0x80, 0xEA, 0x80 }; static const uint8_t cmd_EMM[3] = { 0x80, 0xEB, 0x80 }; struct dgcrypt_data { uint8_t session_key[16]; uint8_t cardid[5]; }; static int32_t dgcrypt_cmd(struct s_reader *rdr, const uint8_t *buf, const int32_t buflen, uint8_t *response, uint16_t *response_length, uint16_t min_response_len) { rdr->ifsc = 195; rdr->ns = 1; if(DEBUG) { char tmp[512]; rdr_log(rdr, "SEND -> %s(%d)", cs_hexdump(1, buf, buflen, tmp, sizeof(tmp)), buflen); } int32_t ret = reader_cmd2icc(rdr, buf, buflen, response, response_length); if(DEBUG) { char tmp[512]; rdr_log(rdr, "RECV <- %s(%d) ret=%d", cs_hexdump(1, response, *response_length, tmp, sizeof(tmp)), *response_length, ret); } // reader_cmd2icc retuns ERROR=1, OK=0 - the opposite of OK and ERROR defines in reader-common.h if(ret) { rdr_log(rdr, "ERROR: reader_cmd2icc() ret=%d", ret); return ERROR; } if(*response_length < 2 || *response_length < min_response_len) { if (response[0] == 0x6b && response[1] == 0x01) rdr_log(rdr, "ERROR: card has expired, please update your card"); else rdr_log(rdr, "ERROR: response_length=%d < min_response_length=%d", *response_length, min_response_len); return ERROR; // Response is two short } if(response[*response_length - 2] != 0x90 || (response[*response_length - 1] != 0x00 && response[*response_length - 1] != 0x17)) { rdr_log(rdr, "ERROR: response[-2] != 0x90 its 0x%02X", response[*response_length - 2]); rdr_log(rdr, "ERROR: response[-1] != 0x00 or 0x17 its 0x%02X", response[*response_length - 1]); return ERROR; // The reader responded with "command not OK" } return OK; } static int32_t dgcrypt_card_init(struct s_reader *rdr, ATR *newatr) { def_resp get_atr if(atr_size < sizeof(dgcrypt_atr)) { return ERROR; } // Full ATR: 3B E9 00 00 81 31 C3 45 99 63 74 69 19 99 12 56 10 EC if(memcmp(atr, dgcrypt_atr, sizeof(dgcrypt_atr)) != 0) { return ERROR; } if(!cs_malloc(&rdr->csystem_data, sizeof(struct dgcrypt_data))) { return ERROR; } struct dgcrypt_data *csystem_data = rdr->csystem_data; rdr_log(rdr, "[dgcrypt-reader] card detected."); memset(rdr->sa, 0, sizeof(rdr->sa)); memset(rdr->prid, 0, sizeof(rdr->prid)); memset(rdr->hexserial, 0, sizeof(rdr->hexserial)); rdr->nprov = 1; // rdr->caid = 0x4ABF; // Get session key // Send: 81 D0 00 01 08 // Recv: 32 86 17 D5 2C 66 61 14 90 00 if(!dgcrypt_cmd(rdr, cmd_CWKEY, sizeof(cmd_CWKEY), cta_res, &cta_lr, 8)) { return ERROR; } memcpy(csystem_data->session_key + 0, cta_res, 8); memcpy(csystem_data->session_key + 8, cta_res, 8); // Get CAID // Send: 81 C0 00 01 0A // Recv: 4A BF 90 00 if (!dgcrypt_cmd(rdr, cmd_CAID, sizeof(cmd_CAID), cta_res, &cta_lr, 2)) { return ERROR; } rdr->caid = (cta_res[0] << 8) | cta_res[1]; // Get serial number // Send: 81 D1 00 01 10 // Recv: 00 0D DB 08 71 0D D5 0C 30 30 30 30 30 30 30 30 90 00 if(!dgcrypt_cmd(rdr, cmd_SERIAL, sizeof(cmd_SERIAL), cta_res, &cta_lr, 8)) { return ERROR; } memcpy(rdr->hexserial, cta_res + 1, 7); // Get card id // Send: 81 D4 00 01 05 // Recv: 00 00 00 76 AC 90 00 if(!dgcrypt_cmd(rdr, cmd_CARD_ID, sizeof(cmd_CARD_ID), cta_res, &cta_lr, 5)) { return ERROR; } memcpy(csystem_data->cardid, cta_res, 5); // Get LABEL // Send: 81 D2 00 01 10 // Recv: 50 61 79 5F 54 56 5F 43 61 72 64 00 00 00 00 00 90 00 // Txt: P a y _ T V _ C a r d if(!dgcrypt_cmd(rdr, cmd_LABEL, sizeof(cmd_LABEL), cta_res, &cta_lr, 16)) { return ERROR; } char label[17]; memset(label, 0, sizeof(label)); memcpy(label, cta_res, 16); // Get subsystem - !FIXME! We are not using the answer of this command! // Send: 81 DD 00 10 04 // Recv: 00 55 00 55 90 00, also 00 8F 00 8F 90 00 // if(!dgcrypt_cmd(rdr, cmd_LABEL, sizeof(cmd_LABEL), cta_res, &cta_lr, 4)) // { return ERROR; } rdr_log_sensitive(rdr, "CAID: 0x%04X, Serial: {%"PRIu64"} HexSerial: {%02X %02X %02X %02X %02X %02X %02X} Card Id: {%02X %02X %02X %02X %02X} Label: {%s}", rdr->caid, b2ll(7, rdr->hexserial), rdr->hexserial[0], rdr->hexserial[1], rdr->hexserial[2], rdr->hexserial[3], rdr->hexserial[4], rdr->hexserial[5], rdr->hexserial[6], csystem_data->cardid[0], csystem_data->cardid[1], csystem_data->cardid[2], csystem_data->cardid[3], csystem_data->cardid[4], label); return OK; } static int32_t dgcrypt_do_ecm(struct s_reader *rdr, const ECM_REQUEST *er, struct s_ecm_answer *ea) { def_resp uint8_t cmd_buffer[256]; struct dgcrypt_data *csystem_data = rdr->csystem_data; memcpy(cmd_buffer, er->ecm, er->ecm[2] + 3); // Replace The first 3 bytes of the ECM with the command memcpy(cmd_buffer, cmd_ECM, sizeof(cmd_ECM)); // Write ECM // Send: 80 EA 80 00 55 00 00 3F 90 03 00 00 18 5D 82 4E 01 C4 2D 60 12 ED 34 37 ED 72 .. .. .. // Recv: 72 25 8D A1 0D 0D D2 44 EE ED 51 2F 3B 5D 19 63 E6 90 00 if(!dgcrypt_cmd(rdr, cmd_buffer, er->ecm[2] + 3, cta_res, &cta_lr, 17)) { return ERROR; } if(cta_res[0] != 0x72) // CW response MUST start with 0x72 { return ERROR; } int i; for(i = 0; i < 16; i++) { ea->cw[i] = cta_res[1 + i] ^ csystem_data->session_key[i]; } return OK; } static int32_t dgcrypt_do_emm(struct s_reader *rdr, EMM_PACKET *ep) { def_resp uint8_t cmd_buffer[256]; int32_t emm_length = ep->emm[2] + 3 + 2; // add 2 bytes for header memcpy(cmd_buffer + 2, ep->emm, emm_length); // Replace The first 3 bytes of the EMM with the command memcpy(cmd_buffer, cmd_EMM, sizeof(cmd_EMM)); // Write EMM // Send: 80 EB 80 00 54 00 00 00 00 76 AC 00 8F 82 4A 90 03 00 00 .. .. .. // Recv: 90 17 if(!dgcrypt_cmd(rdr, cmd_buffer, emm_length, cta_res, &cta_lr, 2)) { return ERROR; } return OK; } static int32_t dgcrypt_get_emm_type(EMM_PACKET *ep, struct s_reader *rdr) { rdr_log_dbg(rdr, D_EMM, "Entered dgcrypt_get_emm_type ep->emm[0]=%x", ep->emm[0]); char tmp_dbg[10]; struct dgcrypt_data *csystem_data = rdr->csystem_data; switch(ep->emm[0]) { case 0x82: ep->type = UNIQUE; memset(ep->hexserial, 0, 8); memcpy(ep->hexserial, ep->emm + 4, 5); rdr_log_dbg_sensitive(rdr, D_EMM, "UNIQUE, ep->hexserial = {%s}", cs_hexdump(1, ep->hexserial, 5, tmp_dbg, sizeof(tmp_dbg))); rdr_log_dbg_sensitive(rdr, D_EMM, "UNIQUE, csystem_data->cardid = {%s}", cs_hexdump(1, csystem_data->cardid, 5, tmp_dbg, sizeof(tmp_dbg))); return (!memcmp(csystem_data->cardid, ep->hexserial, 5)); break; // Unknown EMM types, but allready subbmited to dev's // FIXME: Drop EMM's until there are implemented default: ep->type = UNKNOWN; return 1; } } static int32_t dgcrypt_get_emm_filter(struct s_reader *rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count) { struct dgcrypt_data *csystem_data = rdr->csystem_data; if(*emm_filters == NULL) { // need more info //--|-|len|--|card id 5 byte| const |len|const|-------------- //82 00 54 00 00 00 00 xx xx 00 8f 82 4a 90 03 ... tested, works //82 00 64 00 00 00 00 00 00 00 8f 82 5a ff ff ... ? filler //82 00 34 00 00 00 00 xx xx 00 8f 82 2a 90 03 ... ? //82 00 37 00 00 00 00 xx xx 00 8f 82 2d 90 03 ... ? const unsigned int max_filter_count = 1; // fixme if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) { return ERROR; } struct s_csystem_emm_filter *filters = *emm_filters; int32_t idx = 0; filters[idx].type = EMM_UNIQUE; filters[idx].enabled = 1; filters[idx].filter[0] = 0x82; filters[idx].mask[0] = 0xFF; memcpy(&filters[idx].filter[2], csystem_data->cardid, 5); memset(&filters[idx].mask[2], 0xFF, 5); idx++; /* // I've never seen it filters[idx].type = EMM_GLOBAL; filters[idx].enabled = 1; filters[idx].filter[0] = 0x83; filters[idx].mask[0] = 0xFF; idx++; */ *filter_count = idx; } return OK; } const struct s_cardsystem reader_dgcrypt = { .desc = "dgcrypt", .caids = (uint16_t[]){ 0x4AB0, 0x4ABF, 0 }, .card_init = dgcrypt_card_init, .do_emm = dgcrypt_do_emm, .do_ecm = dgcrypt_do_ecm, .get_emm_type = dgcrypt_get_emm_type, .get_emm_filter = dgcrypt_get_emm_filter, }; #endif