static crypto_error_t crypto_pad(bytestring_t *dst, const bytestring_t *ctx,const bytestring_t *src) { unsigned char e; bytestring_copy(dst,src); bytestring_get_element(&e,ctx,1); switch (((unsigned)e)<<8) { case CRYPTO_PAD_OPT_80_ZERO: if ((bytestring_get_size(dst)&0x7)==0) break; case CRYPTO_PAD_ISO9797_P2: bytestring_pushback(dst,0x80); bytestring_pad_right(dst,8,0); break; case CRYPTO_PAD_ZERO: bytestring_pad_right(dst,8,0); break; default: bytestring_clear(dst); return CRYPTO_ERROR_UNKNOWN_PADDING_METHOD; } return CRYPTO_OK; }
static int verify_signature(const bytestring_t *source, const bytestring_t *signature) { static const char *pubkey_value = CARDPEEK_PUBLIC_KEY; BIO *bp; RSA* pubkey; int retval; unsigned char digest[SHA256_DIGEST_LENGTH]; SHA256_CTX sha256; if ((bp = BIO_new_mem_buf((void*)pubkey_value,strlen(pubkey_value)))==NULL) { log_printf(LOG_ERROR,"Failed to build BIO for memory object"); return 0; } if ((pubkey = PEM_read_bio_RSA_PUBKEY(bp, NULL, NULL, NULL))==NULL) { log_printf(LOG_ERROR,"Failed to load public in memory"); BIO_free(bp); return 0; } BIO_free(bp); SHA256_Init(&sha256); SHA256_Update(&sha256,bytestring_get_data(source),bytestring_get_size(source)); SHA256_Final(digest,&sha256); retval= RSA_verify(NID_sha256, digest, SHA256_DIGEST_LENGTH, (unsigned char *)bytestring_get_data(signature), bytestring_get_size(signature), pubkey); if (retval==0) { log_printf(LOG_ERROR, "Signature verification failed for update information (%s)\n", ERR_error_string(ERR_get_error(),NULL)); } RSA_free(pubkey); return retval; }
crypto_error_t crypto_create_context(bytestring_t *ctx, crypto_alg_t alg_type, const bytestring_t *key_bin) { DES_key_schedule ks; bytestring_clear(ctx); bytestring_pushback(ctx,ALG_TYPE(alg_type)); bytestring_pushback(ctx,PAD_TYPE(alg_type)>>8); switch (ALG_TYPE(alg_type)) { case CRYPTO_ALG_DES_ECB: case CRYPTO_ALG_DES_CBC: if (key_bin==NULL || bytestring_get_size(key_bin)!=8 || key_bin->width!=8) return CRYPTO_ERROR_BAD_KEY_FORMAT; DES_set_key_unchecked((const_DES_cblock *)key_bin->data,&ks); bytestring_append_data(ctx,DES_KS_SIZE,(unsigned char *)&ks); break; case CRYPTO_ALG_DES2_EDE_ECB: case CRYPTO_ALG_DES2_EDE_CBC: case CRYPTO_ALG_ISO9797_M3: if (key_bin==NULL || bytestring_get_size(key_bin)!=16 || key_bin->width!=8) return CRYPTO_ERROR_BAD_KEY_FORMAT; DES_set_key_unchecked((const_DES_cblock *)key_bin->data,&ks); bytestring_append_data(ctx,DES_KS_SIZE,(unsigned char *)&ks); DES_set_key_unchecked((const_DES_cblock *)(key_bin->data+8),&ks); bytestring_append_data(ctx,DES_KS_SIZE,(unsigned char *)&ks); break; case CRYPTO_ALG_SHA1: /* nothing else to do */ break; default: return CRYPTO_ERROR_UNKNOWN_KEY_TYPE; } return CRYPTO_OK; }
crypto_error_t crypto_mac(bytestring_t *dst, const bytestring_t *ctx, const bytestring_t *src) { unsigned u,v; unsigned char tmp[8]; unsigned char clr[8]; unsigned char alg; crypto_error_t retval; bytestring_t *padded_src; DES_key_schedule key_schedule; DES_key_schedule key_schedule2; bytestring_get_element(&alg,ctx,0); if (alg==CRYPTO_ALG_ISO9797_M3) { padded_src = bytestring_new(8); retval = crypto_pad(padded_src,ctx,src); if (retval!=CRYPTO_OK) { bytestring_free(padded_src); return retval; } memset(tmp,0,8); memcpy(&key_schedule,ctx->data+KS_HEADER_SIZE,DES_KS_SIZE); memcpy(&key_schedule2,ctx->data+KS_HEADER_SIZE+DES_KS_SIZE,DES_KS_SIZE); for (u=0; u<bytestring_get_size(padded_src)/8; u++) { for (v=0; v<8; v++) clr[v]=padded_src->data[u*8+v]^tmp[v]; DES_ecb_encrypt((const_DES_cblock *)clr, (DES_cblock *)tmp, &key_schedule, DES_ENCRYPT); } memcpy(clr,tmp,8); DES_ecb_encrypt((const_DES_cblock *)clr, (DES_cblock *)tmp, &key_schedule2, DES_DECRYPT); memcpy(clr,tmp,8); DES_ecb_encrypt((const_DES_cblock *)clr, (DES_cblock *)tmp, &key_schedule, DES_ENCRYPT); bytestring_assign_data(dst,8,tmp); bytestring_free(padded_src); } else return CRYPTO_ERROR_UNKNOWN_ALGORITHM; return CRYPTO_OK; }
const bytestring_t *cardreader_last_atr(cardreader_t *reader) { const bytestring_t *atr = reader->last_atr(reader); char *tmp; if (atr) { tmp = bytestring_to_format("%D",atr); log_printf(LOG_INFO,"ATR is %i bytes: %s",bytestring_get_size(atr),tmp); free(tmp); } return atr; }
crypto_error_t crypto_digest(bytestring_t *dst, const bytestring_t *ctx, const bytestring_t *src) { unsigned char alg; bytestring_get_element(&alg,ctx,0); if (alg==CRYPTO_ALG_SHA1) { bytestring_resize(dst,SHA_DIGEST_LENGTH); SHA1(src->data,bytestring_get_size(src),dst->data); } else return CRYPTO_ERROR_UNKNOWN_ALGORITHM; return CRYPTO_OK; }
crypto_error_t crypto_encrypt(bytestring_t *dst, const bytestring_t *ctx, const bytestring_t *src, const bytestring_t *iv) { unsigned pad_type; bytestring_t *padded_src; crypto_error_t retval; bytestring_get_element((unsigned char *)&pad_type,ctx,1); if (pad_type==0 && (bytestring_get_size(src)&0x7)==0) return crypto_cipher(dst,ctx,src,iv,DES_ENCRYPT); padded_src=bytestring_new(8); retval = crypto_pad(padded_src,ctx,src); if (retval==CRYPTO_OK) { retval = crypto_cipher(dst,ctx,padded_src,iv,DES_ENCRYPT); } bytestring_free(padded_src); return retval; }
static const char* hex_pretty_print(int indent, const bytestring_t *bs,int add_ascii) { static char retval[1500]; int i; int offset; int line; int sizebs=bytestring_get_size(bs); int linesize=indent+48+4+16+1; unsigned char e; if (sizebs==0) return "(nil)\n"; for (i=0;i<sizebs;i++) { offset = (i&0x0F); line = (i&0xFFF0)>>4; if (offset==0) { memset(retval+line*linesize,' ',linesize); retval[line*linesize+linesize-1]='\n'; retval[line*linesize+linesize]=0; } bytestring_get_element(&e,bs,i); retval[line*linesize+indent+offset*3]=HEX_CHAR[(e>>4)]; retval[line*linesize+indent+offset*3+1]=HEX_CHAR[e&0xF]; if (add_ascii) { if (e>=' ' && e<=126) retval[line*linesize+indent+52+offset]=e; else retval[line*linesize+indent+52+offset]='.'; } } return retval+indent; }
/* static void update_dump(update_t *update, FILE* out) { update_item_t *item = update->items; fprintf(out,"Update version %s\n",update->update_version); while (item) { update_item_dump(item,out); item = item->next; } } */ static int update_load(update_t *update, const char *data, unsigned data_len) { char *ptr = (char *)data; unsigned ptr_len = data_len; char *data_end; char *value; update_item_t *item = NULL; bytestring_t *signature; bytestring_t *source; int signature_verified; #define fail_update(m) { log_printf(LOG_ERROR,"Failed to parse update information: %s",m); \ goto update_new_fail; } if ((value = tokenizer_get_record(&ptr,&ptr_len))==NULL) fail_update("Missing header"); if (strcmp(value,"header")!=0) fail_update("Incorrect header"); g_free(value); if ((value = tokenizer_get_field("version",&ptr,&ptr_len))==NULL) fail_update("missing version"); update->update_version = value; /* don't free value */ data_end = ptr; while ((value = tokenizer_get_record(&ptr,&ptr_len))!=NULL) { if (strcmp(value,"update")!=0) break; g_free(value); item = update_item_new(); if ((value = tokenizer_get_field("file",&ptr,&ptr_len))==NULL) fail_update("missing file name"); item->file = value; if ((value = tokenizer_get_field("url",&ptr,&ptr_len))==NULL) fail_update("missing url"); item->url = value; if ((value = tokenizer_get_field("required_version",&ptr,&ptr_len))==NULL) fail_update("missing required version"); item->required_version = value; if ((value = tokenizer_get_field("digest",&ptr,&ptr_len))==NULL) fail_update("missing digest"); bytestring_assign_digit_string(&item->digest,value); g_free(value); if (bytestring_get_size(&item->digest)!=SHA256_DIGEST_LENGTH) fail_update("incorrect digest length"); if ((value = tokenizer_get_field("message",&ptr,&ptr_len))==NULL) fail_update("missing message"); item->message = value; update->item_count++; item->next = update->items; update->items = item; item = NULL; data_end = ptr; } if (value==NULL) fail_update("missing section"); if (strcmp(value,"authentication")!=0) fail_update("missing authentication"); g_free(value); if ((value = tokenizer_get_field("signature",&ptr,&ptr_len))==NULL) fail_update("missing signature"); signature = bytestring_new(8); bytestring_assign_digit_string(signature,value); g_free(value); log_printf(LOG_DEBUG,"Verifying %d bit signature on update information (%d bytes), representing %d files.", bytestring_get_size(signature)*8,data_end-data,update->item_count); source = bytestring_new(8); bytestring_assign_data(source,data_end-data,(const unsigned char *)data); if (verify_signature(source,signature)==0) { log_printf(LOG_ERROR,"Signature verification failed on update information."); signature_verified = 0; update_clear(update); } else { log_printf(LOG_INFO,"Signature verification succeeded on update information."); signature_verified = 1; } bytestring_free(signature); bytestring_free(source); return signature_verified; update_new_fail: if (value) g_free(value); if (update) update_clear(update); if (item) update_item_free(item); return 0; }
static unsigned short pcsc_transmit(cardreader_t* cr, const bytestring_t* command, bytestring_t* result) { pcsc_data_t* pcsc = cr->extra_data; BYTE REC_DAT[MAX_PCSC_READ_LENGTH]; DWORD REC_LEN=MAX_PCSC_READ_LENGTH; unsigned short SW; if (cr->protocol==SCARD_PROTOCOL_T0) { pcsc->status = SCardTransmit(pcsc->hcard,SCARD_PCI_T0, bytestring_get_data(command), bytestring_get_size(command), SCARD_PCI_NULL, REC_DAT,&REC_LEN); } else if (cr->protocol==SCARD_PROTOCOL_T1) { pcsc->status = SCardTransmit(pcsc->hcard,SCARD_PCI_T1, bytestring_get_data(command), bytestring_get_size(command), SCARD_PCI_NULL, REC_DAT,&REC_LEN); } else { log_printf(LOG_ERROR,"Unknown smartcard protocol: %i",cr->protocol); return CARDPEEK_ERROR_SW; } if (pcsc->status!=SCARD_S_SUCCESS) { log_printf(LOG_ERROR,"Failed to transmit command to card: %s (error 0x%08x).", pcsc_stringify_error(pcsc->status), pcsc->status ); return CARDPEEK_ERROR_SW; } if (REC_LEN>=2) { bytestring_assign_data(result,REC_LEN-2,REC_DAT); SW = (REC_DAT[REC_LEN-2]<<8)|REC_DAT[REC_LEN-1]; } else if (REC_LEN==1) { bytestring_clear(result); SW = REC_DAT[0]; } else { log_printf(LOG_ERROR,"Transmited %i bytes to the card (%s), but recieved a response of length %i, without any status word included.", bytestring_get_size(command), pcsc_stringify_protocol(cr->protocol), REC_LEN); return CARDPEEK_ERROR_SW; } return SW; }
static crypto_error_t crypto_cipher(bytestring_t *dst, const bytestring_t *ctx, const bytestring_t *src, const bytestring_t *iv, int enc) { unsigned u; unsigned char alg; DES_key_schedule key_schedule; DES_key_schedule key_schedule2; if (bytestring_get_element(&alg,ctx,0)!=BYTESTRING_OK) return CRYPTO_ERROR_UNKNOWN; if ((bytestring_get_size(src)&0x7)!=0) return CRYPTO_ERROR_BAD_CLEARTEXT_LENGTH; switch (alg) { case CRYPTO_ALG_DES_ECB: bytestring_resize(dst,bytestring_get_size(src)); memcpy(&key_schedule,ctx->data+KS_HEADER_SIZE,DES_KS_SIZE); for (u=0; u<bytestring_get_size(src)/8; u++) DES_ecb_encrypt((const_DES_cblock *)(src->data+u*8), (DES_cblock *)(dst->data+u*8), &key_schedule, enc); break; case CRYPTO_ALG_DES_CBC: if (iv==NULL || bytestring_get_size(iv)!=8) return CRYPTO_ERROR_BAD_IV_LENGTH; bytestring_resize(dst,bytestring_get_size(src)); memcpy(&key_schedule,ctx->data+KS_HEADER_SIZE,DES_KS_SIZE); DES_ncbc_encrypt(src->data, dst->data, bytestring_get_size(src), &key_schedule, (DES_cblock *)(iv->data), enc); break; case CRYPTO_ALG_DES2_EDE_ECB: bytestring_resize(dst,bytestring_get_size(src)); memcpy(&key_schedule,ctx->data+KS_HEADER_SIZE,DES_KS_SIZE); memcpy(&key_schedule2,ctx->data+KS_HEADER_SIZE+DES_KS_SIZE,DES_KS_SIZE); for (u=0; u<bytestring_get_size(src)/8; u++) DES_ecb2_encrypt((const_DES_cblock *)(src->data+u*8), (DES_cblock *)(dst->data+u*8), &key_schedule, &key_schedule2, enc); break; case CRYPTO_ALG_DES2_EDE_CBC: if (iv==NULL || bytestring_get_size(iv)!=8) return CRYPTO_ERROR_BAD_IV_LENGTH; bytestring_resize(dst,bytestring_get_size(src)); memcpy(&key_schedule,ctx->data+KS_HEADER_SIZE,DES_KS_SIZE); memcpy(&key_schedule2,ctx->data+KS_HEADER_SIZE+DES_KS_SIZE,DES_KS_SIZE); DES_ede2_cbc_encrypt(src->data, dst->data, bytestring_get_size(src), &key_schedule, &key_schedule2, (DES_cblock *)(iv->data), enc); break; default: return CRYPTO_ERROR_UNKNOWN_ALGORITHM; } return CRYPTO_OK; }