⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 card-gpk.c

📁 读写Smart卡加解密接口的程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	struct sc_apdu	apdu;	unsigned int	count, chain, len;	int		r;	chain = 0x01;	for (count = 0; count < datalen; count += len) {		unsigned char	buffer[GPK_HASH_CHUNK+2];		if ((len = datalen - count) > GPK_HASH_CHUNK)			len = GPK_HASH_CHUNK;		else			chain |= 0x10;		buffer[0] = 0x55;		buffer[1] = len;		memcpy(buffer+2, data + count, len);		memset(&apdu, 0, sizeof(apdu));		apdu.cse = SC_APDU_CASE_3_SHORT;		apdu.cla = 0x80;		apdu.ins = 0xDA;		apdu.p1  = chain;		apdu.p2  = len;		apdu.lc  = len + 2;		apdu.data= buffer;		apdu.datalen = len + 2;		r = sc_transmit_apdu(card, &apdu);		SC_TEST_RET(card->ctx, r, "APDU transmit failed");		r = sc_check_sw(card, apdu.sw1, apdu.sw2);		SC_TEST_RET(card->ctx, r, "Card returned error");		chain = 0;	}	return 0;}#endif/* * Send the hashed data to the card. */static intgpk_init_hashed(struct sc_card *card, const u8 *digest, unsigned int len){	struct sc_apdu	apdu;	u8		tsegid[64];	int		r;	r = reverse(tsegid, sizeof(tsegid), digest, len);	SC_TEST_RET(card->ctx, r, "Failed to reverse buffer");	memset(&apdu, 0, sizeof(apdu));	apdu.cse = SC_APDU_CASE_3_SHORT;	apdu.cla = 0x80;	apdu.ins = 0xEA;	apdu.lc  = len;	apdu.data= tsegid;	apdu.datalen = len;	r = sc_transmit_apdu(card, &apdu);	SC_TEST_RET(card->ctx, r, "APDU transmit failed");	r = sc_check_sw(card, apdu.sw1, apdu.sw2);	SC_TEST_RET(card->ctx, r, "Card returned error");	return r;}/* * Compute a signature. * Note we hash everything manually and send it to the card. */static intgpk_compute_signature(struct sc_card *card, const u8 *data,		size_t data_len, u8 * out, size_t outlen){	struct gpk_private_data *priv = DRVDATA(card);	struct sc_apdu	apdu;	u8		cardsig[1024/8];	int		r;	if (data_len > priv->sec_mod_len) {		sc_error(card->ctx,			"Data length (%u) does not match key modulus %u.\n",			data_len, priv->sec_mod_len);		return SC_ERROR_INTERNAL;	}	if (sizeof(cardsig) < priv->sec_mod_len)		return SC_ERROR_BUFFER_TOO_SMALL;	r = gpk_init_hashed(card, data, data_len);	SC_TEST_RET(card->ctx, r, "Failed to send hash to card");	/* Now sign the hash.	 * The GPK has Internal Authenticate and PK_Sign. I am not	 * sure what the difference between the two is. */	memset(&apdu, 0, sizeof(apdu));	apdu.cse = SC_APDU_CASE_2_SHORT;	apdu.cla = 0x80;	apdu.ins = 0x86;#if 0	/* Don't know why I did this. It conflicts with the spec	 * (but it worked with the gpk4k, strange). --okir */	apdu.p1  = priv->sec_padding;	apdu.p2  = priv->sec_mod_len;#else	apdu.p2  = priv->sec_padding;#endif	apdu.resp= cardsig;	apdu.resplen = sizeof(cardsig);	apdu.le  = priv->sec_mod_len;	r = sc_transmit_apdu(card, &apdu);	SC_TEST_RET(card->ctx, r, "APDU transmit failed");	r = sc_check_sw(card, apdu.sw1, apdu.sw2);	SC_TEST_RET(card->ctx, r, "Card returned error");	/* The GPK returns the signature as little endian numbers.	 * Need to revert these */	r = reverse(out, outlen, cardsig, apdu.resplen);	SC_TEST_RET(card->ctx, r, "Failed to reverse signature");	return r;}/* * Decrypt some RSA encrypted piece of data. * Due to legal restrictions, the GPK will not let you see the * full cleartext block, just the last N bytes. * The GPK documentation refers to N as the MaxSessionKey size, * probably because this feature limits the maximum size of an * SSL session key you will be able to decrypt using this card. */static intgpk_decipher(struct sc_card *card, const u8 *in, size_t inlen,		u8 *out, size_t outlen){	struct gpk_private_data *priv = DRVDATA(card);	struct sc_apdu	apdu;	u8		buffer[256];	int		r;	if (inlen != priv->sec_mod_len) {		sc_error(card->ctx,			"Data length (%u) does not match key modulus %u.\n",			inlen, priv->sec_mod_len);		return SC_ERROR_INVALID_ARGUMENTS;	}	/* First revert the cryptogram */	r = reverse(buffer, sizeof(buffer), in, inlen);	SC_TEST_RET(card->ctx, r, "Cryptogram too large");	in = buffer;	memset(&apdu, 0, sizeof(apdu));	apdu.cse = SC_APDU_CASE_3_SHORT;	apdu.cla = 0x80;	apdu.ins = 0x1C;	apdu.p2  = 0;		/* PKCS1 padding */	apdu.lc  = inlen;	apdu.data= in;	apdu.datalen = inlen;	apdu.resp= buffer;	apdu.resplen = sizeof(buffer);	apdu.sensitive = 1;	r = sc_transmit_apdu(card, &apdu);	SC_TEST_RET(card->ctx, r, "APDU transmit failed");	r = sc_check_sw(card, apdu.sw1, apdu.sw2);	SC_TEST_RET(card->ctx, r, "Card returned error");	/* Reverse the data we got back */	r = reverse(out, outlen, buffer, apdu.resplen);	SC_TEST_RET(card->ctx, r, "Failed to reverse buffer");	return r;}/* * Erase card */static intgpk_erase_card(struct sc_card *card){	struct gpk_private_data *priv = DRVDATA(card);	struct sc_apdu	apdu;	u8		offset;	int		r;	SC_FUNC_CALLED(card->ctx, 1);	switch (priv->variant) {	case GPK4000_su256:	case GPK4000_sdo:		offset = 0x6B;  /* courtesy gemplus hotline */		break;	case GPK4000_s:		offset = 7;		break;	case GPK8000:	case GPK8000_8K:	case GPK8000_16K:	case GPK16000:		offset = 0;		break;	default:		return SC_ERROR_NOT_SUPPORTED;	}	memset(&apdu, 0, sizeof(apdu));	apdu.cse = SC_APDU_CASE_1;	apdu.cla = 0xDB;	apdu.ins = 0xDE;	apdu.p2  = offset;	r = sc_transmit_apdu(card, &apdu);	SC_TEST_RET(card->ctx, r, "APDU transmit failed");	r = sc_check_sw(card, apdu.sw1, apdu.sw2);	SC_TEST_RET(card->ctx, r, "Card returned error");	priv->key_set = 0;	SC_FUNC_RETURN(card->ctx, 2, r);}/* * Lock a file Access Condition. * * File must be selected, and we assume that any authentication * that needs to be presented in order to allow this operation * have been presented (ACs from the DF; AC1 for sensitive files, * AC2 for normal files). */static intgpk_lock(struct sc_card *card, struct sc_cardctl_gpk_lock *args){	struct gpk_private_data *priv = DRVDATA(card);	struct sc_file	*file = args->file;	struct sc_apdu	apdu;	u8		data[8], crycks[3], resp[3];	int		r;	if (card->ctx->debug)		sc_debug(card->ctx, "gpk_lock(0x%04X, %u)\n",				file->id, args->operation);	memset(data, 0, sizeof(data));	data[0] = file->id >> 8;	data[1] = file->id;	switch (args->operation) {	case SC_AC_OP_UPDATE:		data[2] = 0x40; break;	case SC_AC_OP_WRITE:		data[3] = 0x40; break;	case SC_AC_OP_READ:		data[4] = 0x40; break;	default:		return SC_ERROR_INVALID_ARGUMENTS;	}	memset(&apdu, 0, sizeof(apdu));	apdu.cse = SC_APDU_CASE_3_SHORT;	apdu.cla = 0x80;	apdu.ins = 0x16;	apdu.p1  = (file->type == SC_FILE_TYPE_DF)? 1 : 2;	apdu.p2  = 0;	apdu.lc  = 5;	apdu.datalen = 5;	apdu.data = data;	if (priv->key_set) {		apdu.cla = 0x84;		apdu.cse = SC_APDU_CASE_4_SHORT;		r = gpk_compute_crycks(card, &apdu, crycks);		if (r)			return r;		apdu.resp = resp;		apdu.resplen = sizeof(resp); /* XXX? */	}	r = sc_transmit_apdu(card, &apdu);	SC_TEST_RET(card->ctx, r, "APDU transmit failed");	r = sc_check_sw(card, apdu.sw1, apdu.sw2);	SC_TEST_RET(card->ctx, r, "Card returned error");	if (priv->key_set)		r = gpk_verify_crycks(card, &apdu, crycks);	return r;}/* * Initialize the private portion of a public key file */static intgpk_pkfile_init(struct sc_card *card, struct sc_cardctl_gpk_pkinit *args){	struct sc_apdu	apdu;	int		r;	if (card->ctx->debug)		sc_debug(card->ctx, "gpk_pkfile_init(%u)\n", args->privlen);	memset(&apdu, 0, sizeof(apdu));	apdu.cse = SC_APDU_CASE_1;	apdu.cla = 0x80;	apdu.ins = 0x12;	apdu.p1  = args->file->id & 0x1F;	apdu.p2  = args->privlen / 4;	r = sc_transmit_apdu(card, &apdu);	SC_TEST_RET(card->ctx, r, "APDU transmit failed");	r = sc_check_sw(card, apdu.sw1, apdu.sw2);	SC_TEST_RET(card->ctx, r, "Card returned error");	return r;}/* * Store a privat key component */static intgpk_pkfile_load(struct sc_card *card, struct sc_cardctl_gpk_pkload *args){	struct gpk_private_data *priv = DRVDATA(card);	des_key_schedule k1, k2;	struct sc_apdu	apdu;	unsigned int	n;	u8		temp[256];	int		r;	sc_debug(card->ctx, "gpk_pkfile_load(fid=%04x, len=%d, datalen=%d)\n",			args->file->id, args->len, args->datalen);#if 0	if (card->ctx->debug > 5) {		char buf[2048];		sc_hex_dump(card->ctx, args->data, args->datalen,				buf, sizeof(buf));		sc_debug(card->ctx, "Sending %d bytes (cleartext):\n%s",				args->datalen, buf);	}#endif	memset(&apdu, 0, sizeof(apdu));	apdu.cse = SC_APDU_CASE_3_SHORT;	apdu.cla = 0x80;	apdu.ins = 0x18;	apdu.p1  = args->file->id & 0x1F;	apdu.p2  = args->len;	apdu.lc  = args->datalen;	apdu.sensitive = 1;	/* encrypt the private key material */	assert(args->datalen <= sizeof(temp));	if (!priv->key_set) {		sc_error(card->ctx, "No secure messaging key set!\n");		return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;	}	DES_set_key_unchecked((des_cblock *) priv->key, &k1);	DES_set_key_unchecked((des_cblock *) (priv->key+8), &k2);	for (n = 0; n < args->datalen; n += 8) {		des_ecb2_encrypt((des_cblock *) (args->data + n),				 (des_cblock *) (temp + n),				 k1, k2, DES_ENCRYPT);	}	apdu.data = temp;	apdu.datalen = args->datalen;	/* Forget the key. The card seems to forget it, too :) */	priv->key_set = 0;	r = sc_transmit_apdu(card, &apdu);	SC_TEST_RET(card->ctx, r, "APDU transmit failed");	r = sc_check_sw(card, apdu.sw1, apdu.sw2);	SC_TEST_RET(card->ctx, r, "Card returned error");	SC_FUNC_RETURN(card->ctx, 1, r);}/* * This function lets pkcs15init query for the transport key */static intgpk_get_default_key(struct sc_card *card, struct sc_cardctl_default_key *data){	if (data->method == SC_AC_PRO && data->key_ref == 1) {		if (data->len < 16)			return SC_ERROR_BUFFER_TOO_SMALL;		memcpy(data->key_data, "TEST KEYTEST KEY", 16);		data->len = 16;		return 0;	}	return SC_ERROR_NO_DEFAULT_KEY;}/* * Get the maximum size of a session key the card is * willing to decrypt */#if 0static intgpk_max_session_key(struct sc_card *card){	struct gpk_private_data *priv = DRVDATA(card);	struct sc_path	path;	u8		value;	int		r;	if (priv->max_session_key)		return priv->max_session_key;	/* GPK cards limit the amount of data they're willing	 * to RSA decrypt. This data is stored in EFMaxSessionKey */	sc_format_path("01000001", &path);	if ((r = sc_select_file(card, &path, NULL)) < 0	 || (r = sc_read_binary(card, 0, &value, 1, 0)) < 0)		return r;	priv->max_session_key = value;	return value;}#endif/* * GetInfo call */intgpk_get_info(struct sc_card *card, u8 p1, u8 p2, u8 *buf, size_t buflen){	struct sc_apdu	apdu;	int	r;	memset(&apdu, 0, sizeof(apdu));	apdu.cse = SC_APDU_CASE_2_SHORT;	apdu.cla = 0x80;	apdu.ins = 0xC0;	apdu.p1  = p1;	apdu.p2  = p2;	apdu.le  = buflen;	apdu.resp = buf;	apdu.resplen = buflen;	r = sc_transmit_apdu(card, &apdu);	SC_TEST_RET(card->ctx, r, "APDU transmit failed");	r = sc_check_sw(card, apdu.sw1, apdu.sw2);	SC_TEST_RET(card->ctx, r, "Card returned error");	return r;}/* * Dispatch card_ctl calls */static intgpk_card_ctl(struct sc_card *card, unsigned long cmd, void *ptr){	switch (cmd) {	case SC_CARDCTL_ERASE_CARD:		return gpk_erase_card(card);	case SC_CARDCTL_GET_DEFAULT_KEY:		return gpk_get_default_key(card,				(struct sc_cardctl_default_key *) ptr);	case SC_CARDCTL_GPK_VARIANT:		*(int *) ptr = DRVDATA(card)->variant;		return 0;	case SC_CARDCTL_GPK_LOCK:		return gpk_lock(card, (struct sc_cardctl_gpk_lock *) ptr);	case SC_CARDCTL_GPK_PKINIT:		return gpk_pkfile_init(card,			       (struct sc_cardctl_gpk_pkinit *) ptr);	case SC_CARDCTL_GPK_PKLOAD:		return gpk_pkfile_load(card,			       (struct sc_cardctl_gpk_pkload *) ptr);	case SC_CARDCTL_GPK_IS_LOCKED:		*(int *) ptr = DRVDATA(card)->locked;		return 0;	}	return SC_ERROR_NOT_SUPPORTED;}static intgpk_build_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, struct sc_pin_cmd_data *data){	static u8	sbuf[8];	int		r;	if (data->pin_type != SC_AC_CHV)		return SC_ERROR_INVALID_ARGUMENTS;	/* XXX deal with secure messaging here */	memset(apdu, 0, sizeof(*apdu));	apdu->cse	= SC_APDU_CASE_3_SHORT;	data->flags |= SC_PIN_CMD_NEED_PADDING;	switch (data->cmd) {	case SC_PIN_CMD_VERIFY:		/* Copy PIN to buffer and pad */		data->pin1.encoding = SC_PIN_ENCODING_ASCII;		data->pin1.pad_length = 8;		data->pin1.pad_char = 0x00;		data->pin1.offset = 5;		r = sc_build_pin(sbuf, 8, &data->pin1, 1);		if (r < 0)			return r;		apdu->cla = 0x00;		apdu->ins = 0x20;		apdu->p1  = 0x00;		break;	case SC_PIN_CMD_CHANGE:	case SC_PIN_CMD_UNBLOCK:		/* Copy PINs to buffer, BCD-encoded, and pad */		data->pin1.encoding = SC_PIN_ENCODING_BCD;		data->pin1.pad_length = 8;		data->pin1.pad_char = 0x00;		data->pin1.offset = 5;		data->pin2.encoding = SC_PIN_ENCODING_BCD;		data->pin2.pad_length = 8;		data->pin2.pad_char = 0x00;		data->pin2.offset = 5 + 4;		if ((r = sc_build_pin(sbuf, 4, &data->pin1, 1)) < 0		 || (r = sc_build_pin(sbuf + 4, 4, &data->pin2, 1)) < 0)			return r;		apdu->cla = 0x80;		apdu->ins = 0x24;		apdu->p1  = (data->cmd == SC_PIN_CMD_CHANGE)? 0x00 : 0x01;		break;	default:		return SC_ERROR_NOT_SUPPORTED;	}	apdu->p2	= data->pin_reference & 7;	apdu->lc	= 8;	apdu->datalen	= 8;	apdu->data	= sbuf;	apdu->sensitive	= 1;	return 0;}static intgpk_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left){	struct sc_apdu apdu;	int r;	/* Special case - External Authenticate */	if (data->cmd == SC_PIN_CMD_VERIFY	 && data->pin_type == SC_AC_PRO)		return gpk_select_key(card,				data->pin_reference,				data->pin1.data,				data->pin1.len);	r = gpk_build_pin_apdu(card, &apdu, data);	if (r < 0)		return r;	data->apdu = &apdu;	return iso_ops->pin_cmd(card, data, tries_left);}/* * Initialize the driver struct */static struct sc_card_driver *sc_get_driver(){	if (gpk_ops.match_card == NULL) {		struct sc_card_driver *iso_drv;		iso_drv = sc_get_iso7816_driver();		iso_ops = iso_drv->ops;		gpk_ops = *iso_ops;		gpk_ops.match_card	= gpk_match;		gpk_ops.init		= gpk_init;		gpk_ops.finish		= gpk_finish;		gpk_ops.select_file	= gpk_select_file;		gpk_ops.read_binary	= gpk_read_binary;		gpk_ops.write_binary	= gpk_write_binary;		gpk_ops.update_binary	= gpk_update_binary;		gpk_ops.create_file	= gpk_create_file;		/* gpk_ops.check_sw	= gpk_check_sw; */		gpk_ops.card_ctl	= gpk_card_ctl;		gpk_ops.set_security_env= gpk_set_security_env;		gpk_ops.restore_security_env= gpk_restore_security_env;		gpk_ops.compute_signature= gpk_compute_signature;		gpk_ops.decipher	= gpk_decipher;		gpk_ops.pin_cmd		= gpk_pin_cmd;	}	return &gpk_drv;}struct sc_card_driver *sc_get_gpk_driver(){	return sc_get_driver();}#endif /* HAVE_OPENSSL */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -