cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

zcrypt_msgtype50.c (16754B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 *  Copyright IBM Corp. 2001, 2012
      4 *  Author(s): Robert Burroughs
      5 *	       Eric Rossman (edrossma@us.ibm.com)
      6 *
      7 *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
      8 *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
      9 *				  Ralph Wuerthner <rwuerthn@de.ibm.com>
     10 *  MSGTYPE restruct:		  Holger Dengler <hd@linux.vnet.ibm.com>
     11 */
     12
     13#define KMSG_COMPONENT "zcrypt"
     14#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
     15
     16#include <linux/module.h>
     17#include <linux/slab.h>
     18#include <linux/init.h>
     19#include <linux/err.h>
     20#include <linux/atomic.h>
     21#include <linux/uaccess.h>
     22
     23#include "ap_bus.h"
     24#include "zcrypt_api.h"
     25#include "zcrypt_error.h"
     26#include "zcrypt_msgtype50.h"
     27
     28/* >= CEX3A: 4096 bits */
     29#define CEX3A_MAX_MOD_SIZE 512
     30
     31/* CEX2A: max outputdatalength + type80_hdr */
     32#define CEX2A_MAX_RESPONSE_SIZE 0x110
     33
     34/* >= CEX3A: 512 bit modulus, (max outputdatalength) + type80_hdr */
     35#define CEX3A_MAX_RESPONSE_SIZE 0x210
     36
     37MODULE_AUTHOR("IBM Corporation");
     38MODULE_DESCRIPTION("Cryptographic Accelerator (message type 50), " \
     39		   "Copyright IBM Corp. 2001, 2012");
     40MODULE_LICENSE("GPL");
     41
     42/*
     43 * The type 50 message family is associated with a CEXxA cards.
     44 *
     45 * The four members of the family are described below.
     46 *
     47 * Note that all unsigned char arrays are right-justified and left-padded
     48 * with zeroes.
     49 *
     50 * Note that all reserved fields must be zeroes.
     51 */
     52struct type50_hdr {
     53	unsigned char	reserved1;
     54	unsigned char	msg_type_code;	/* 0x50 */
     55	unsigned short	msg_len;
     56	unsigned char	reserved2;
     57	unsigned char	ignored;
     58	unsigned short	reserved3;
     59} __packed;
     60
     61#define TYPE50_TYPE_CODE	0x50
     62
     63#define TYPE50_MEB1_FMT		0x0001
     64#define TYPE50_MEB2_FMT		0x0002
     65#define TYPE50_MEB3_FMT		0x0003
     66#define TYPE50_CRB1_FMT		0x0011
     67#define TYPE50_CRB2_FMT		0x0012
     68#define TYPE50_CRB3_FMT		0x0013
     69
     70/* Mod-Exp, with a small modulus */
     71struct type50_meb1_msg {
     72	struct type50_hdr header;
     73	unsigned short	keyblock_type;	/* 0x0001 */
     74	unsigned char	reserved[6];
     75	unsigned char	exponent[128];
     76	unsigned char	modulus[128];
     77	unsigned char	message[128];
     78} __packed;
     79
     80/* Mod-Exp, with a large modulus */
     81struct type50_meb2_msg {
     82	struct type50_hdr header;
     83	unsigned short	keyblock_type;	/* 0x0002 */
     84	unsigned char	reserved[6];
     85	unsigned char	exponent[256];
     86	unsigned char	modulus[256];
     87	unsigned char	message[256];
     88} __packed;
     89
     90/* Mod-Exp, with a larger modulus */
     91struct type50_meb3_msg {
     92	struct type50_hdr header;
     93	unsigned short	keyblock_type;	/* 0x0003 */
     94	unsigned char	reserved[6];
     95	unsigned char	exponent[512];
     96	unsigned char	modulus[512];
     97	unsigned char	message[512];
     98} __packed;
     99
    100/* CRT, with a small modulus */
    101struct type50_crb1_msg {
    102	struct type50_hdr header;
    103	unsigned short	keyblock_type;	/* 0x0011 */
    104	unsigned char	reserved[6];
    105	unsigned char	p[64];
    106	unsigned char	q[64];
    107	unsigned char	dp[64];
    108	unsigned char	dq[64];
    109	unsigned char	u[64];
    110	unsigned char	message[128];
    111} __packed;
    112
    113/* CRT, with a large modulus */
    114struct type50_crb2_msg {
    115	struct type50_hdr header;
    116	unsigned short	keyblock_type;	/* 0x0012 */
    117	unsigned char	reserved[6];
    118	unsigned char	p[128];
    119	unsigned char	q[128];
    120	unsigned char	dp[128];
    121	unsigned char	dq[128];
    122	unsigned char	u[128];
    123	unsigned char	message[256];
    124} __packed;
    125
    126/* CRT, with a larger modulus */
    127struct type50_crb3_msg {
    128	struct type50_hdr header;
    129	unsigned short	keyblock_type;	/* 0x0013 */
    130	unsigned char	reserved[6];
    131	unsigned char	p[256];
    132	unsigned char	q[256];
    133	unsigned char	dp[256];
    134	unsigned char	dq[256];
    135	unsigned char	u[256];
    136	unsigned char	message[512];
    137} __packed;
    138
    139/*
    140 * The type 80 response family is associated with a CEXxA cards.
    141 *
    142 * Note that all unsigned char arrays are right-justified and left-padded
    143 * with zeroes.
    144 *
    145 * Note that all reserved fields must be zeroes.
    146 */
    147
    148#define TYPE80_RSP_CODE 0x80
    149
    150struct type80_hdr {
    151	unsigned char	reserved1;
    152	unsigned char	type;		/* 0x80 */
    153	unsigned short	len;
    154	unsigned char	code;		/* 0x00 */
    155	unsigned char	reserved2[3];
    156	unsigned char	reserved3[8];
    157} __packed;
    158
    159int get_rsa_modex_fc(struct ica_rsa_modexpo *mex, int *fcode)
    160{
    161	if (!mex->inputdatalength)
    162		return -EINVAL;
    163
    164	if (mex->inputdatalength <= 128)	/* 1024 bit */
    165		*fcode = MEX_1K;
    166	else if (mex->inputdatalength <= 256)	/* 2048 bit */
    167		*fcode = MEX_2K;
    168	else					/* 4096 bit */
    169		*fcode = MEX_4K;
    170
    171	return 0;
    172}
    173
    174int get_rsa_crt_fc(struct ica_rsa_modexpo_crt *crt, int *fcode)
    175{
    176	if (!crt->inputdatalength)
    177		return -EINVAL;
    178
    179	if (crt->inputdatalength <= 128)	/* 1024 bit */
    180		*fcode = CRT_1K;
    181	else if (crt->inputdatalength <= 256)	/* 2048 bit */
    182		*fcode = CRT_2K;
    183	else					/* 4096 bit */
    184		*fcode = CRT_4K;
    185
    186	return 0;
    187}
    188
    189/*
    190 * Convert a ICAMEX message to a type50 MEX message.
    191 *
    192 * @zq: crypto queue pointer
    193 * @ap_msg: crypto request pointer
    194 * @mex: pointer to user input data
    195 *
    196 * Returns 0 on success or -EFAULT.
    197 */
    198static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq,
    199				       struct ap_message *ap_msg,
    200				       struct ica_rsa_modexpo *mex)
    201{
    202	unsigned char *mod, *exp, *inp;
    203	int mod_len;
    204
    205	mod_len = mex->inputdatalength;
    206
    207	if (mod_len <= 128) {
    208		struct type50_meb1_msg *meb1 = ap_msg->msg;
    209
    210		memset(meb1, 0, sizeof(*meb1));
    211		ap_msg->len = sizeof(*meb1);
    212		meb1->header.msg_type_code = TYPE50_TYPE_CODE;
    213		meb1->header.msg_len = sizeof(*meb1);
    214		meb1->keyblock_type = TYPE50_MEB1_FMT;
    215		mod = meb1->modulus + sizeof(meb1->modulus) - mod_len;
    216		exp = meb1->exponent + sizeof(meb1->exponent) - mod_len;
    217		inp = meb1->message + sizeof(meb1->message) - mod_len;
    218	} else if (mod_len <= 256) {
    219		struct type50_meb2_msg *meb2 = ap_msg->msg;
    220
    221		memset(meb2, 0, sizeof(*meb2));
    222		ap_msg->len = sizeof(*meb2);
    223		meb2->header.msg_type_code = TYPE50_TYPE_CODE;
    224		meb2->header.msg_len = sizeof(*meb2);
    225		meb2->keyblock_type = TYPE50_MEB2_FMT;
    226		mod = meb2->modulus + sizeof(meb2->modulus) - mod_len;
    227		exp = meb2->exponent + sizeof(meb2->exponent) - mod_len;
    228		inp = meb2->message + sizeof(meb2->message) - mod_len;
    229	} else if (mod_len <= 512) {
    230		struct type50_meb3_msg *meb3 = ap_msg->msg;
    231
    232		memset(meb3, 0, sizeof(*meb3));
    233		ap_msg->len = sizeof(*meb3);
    234		meb3->header.msg_type_code = TYPE50_TYPE_CODE;
    235		meb3->header.msg_len = sizeof(*meb3);
    236		meb3->keyblock_type = TYPE50_MEB3_FMT;
    237		mod = meb3->modulus + sizeof(meb3->modulus) - mod_len;
    238		exp = meb3->exponent + sizeof(meb3->exponent) - mod_len;
    239		inp = meb3->message + sizeof(meb3->message) - mod_len;
    240	} else {
    241		return -EINVAL;
    242	}
    243
    244	if (copy_from_user(mod, mex->n_modulus, mod_len) ||
    245	    copy_from_user(exp, mex->b_key, mod_len) ||
    246	    copy_from_user(inp, mex->inputdata, mod_len))
    247		return -EFAULT;
    248
    249#ifdef CONFIG_ZCRYPT_DEBUG
    250	if (ap_msg->fi.flags & AP_FI_FLAG_TOGGLE_SPECIAL)
    251		ap_msg->flags ^= AP_MSG_FLAG_SPECIAL;
    252#endif
    253
    254	return 0;
    255}
    256
    257/*
    258 * Convert a ICACRT message to a type50 CRT message.
    259 *
    260 * @zq: crypto queue pointer
    261 * @ap_msg: crypto request pointer
    262 * @crt: pointer to user input data
    263 *
    264 * Returns 0 on success or -EFAULT.
    265 */
    266static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq,
    267				       struct ap_message *ap_msg,
    268				       struct ica_rsa_modexpo_crt *crt)
    269{
    270	int mod_len, short_len;
    271	unsigned char *p, *q, *dp, *dq, *u, *inp;
    272
    273	mod_len = crt->inputdatalength;
    274	short_len = (mod_len + 1) / 2;
    275
    276	/*
    277	 * CEX2A and CEX3A w/o FW update can handle requests up to
    278	 * 256 byte modulus (2k keys).
    279	 * CEX3A with FW update and newer CEXxA cards are able to handle
    280	 * 512 byte modulus (4k keys).
    281	 */
    282	if (mod_len <= 128) {		/* up to 1024 bit key size */
    283		struct type50_crb1_msg *crb1 = ap_msg->msg;
    284
    285		memset(crb1, 0, sizeof(*crb1));
    286		ap_msg->len = sizeof(*crb1);
    287		crb1->header.msg_type_code = TYPE50_TYPE_CODE;
    288		crb1->header.msg_len = sizeof(*crb1);
    289		crb1->keyblock_type = TYPE50_CRB1_FMT;
    290		p = crb1->p + sizeof(crb1->p) - short_len;
    291		q = crb1->q + sizeof(crb1->q) - short_len;
    292		dp = crb1->dp + sizeof(crb1->dp) - short_len;
    293		dq = crb1->dq + sizeof(crb1->dq) - short_len;
    294		u = crb1->u + sizeof(crb1->u) - short_len;
    295		inp = crb1->message + sizeof(crb1->message) - mod_len;
    296	} else if (mod_len <= 256) {	/* up to 2048 bit key size */
    297		struct type50_crb2_msg *crb2 = ap_msg->msg;
    298
    299		memset(crb2, 0, sizeof(*crb2));
    300		ap_msg->len = sizeof(*crb2);
    301		crb2->header.msg_type_code = TYPE50_TYPE_CODE;
    302		crb2->header.msg_len = sizeof(*crb2);
    303		crb2->keyblock_type = TYPE50_CRB2_FMT;
    304		p = crb2->p + sizeof(crb2->p) - short_len;
    305		q = crb2->q + sizeof(crb2->q) - short_len;
    306		dp = crb2->dp + sizeof(crb2->dp) - short_len;
    307		dq = crb2->dq + sizeof(crb2->dq) - short_len;
    308		u = crb2->u + sizeof(crb2->u) - short_len;
    309		inp = crb2->message + sizeof(crb2->message) - mod_len;
    310	} else if ((mod_len <= 512) &&	/* up to 4096 bit key size */
    311		   (zq->zcard->max_mod_size == CEX3A_MAX_MOD_SIZE)) {
    312		struct type50_crb3_msg *crb3 = ap_msg->msg;
    313
    314		memset(crb3, 0, sizeof(*crb3));
    315		ap_msg->len = sizeof(*crb3);
    316		crb3->header.msg_type_code = TYPE50_TYPE_CODE;
    317		crb3->header.msg_len = sizeof(*crb3);
    318		crb3->keyblock_type = TYPE50_CRB3_FMT;
    319		p = crb3->p + sizeof(crb3->p) - short_len;
    320		q = crb3->q + sizeof(crb3->q) - short_len;
    321		dp = crb3->dp + sizeof(crb3->dp) - short_len;
    322		dq = crb3->dq + sizeof(crb3->dq) - short_len;
    323		u = crb3->u + sizeof(crb3->u) - short_len;
    324		inp = crb3->message + sizeof(crb3->message) - mod_len;
    325	} else {
    326		return -EINVAL;
    327	}
    328
    329	/*
    330	 * correct the offset of p, bp and mult_inv according zcrypt.h
    331	 * block size right aligned (skip the first byte)
    332	 */
    333	if (copy_from_user(p, crt->np_prime + MSGTYPE_ADJUSTMENT, short_len) ||
    334	    copy_from_user(q, crt->nq_prime, short_len) ||
    335	    copy_from_user(dp, crt->bp_key + MSGTYPE_ADJUSTMENT, short_len) ||
    336	    copy_from_user(dq, crt->bq_key, short_len) ||
    337	    copy_from_user(u, crt->u_mult_inv + MSGTYPE_ADJUSTMENT, short_len) ||
    338	    copy_from_user(inp, crt->inputdata, mod_len))
    339		return -EFAULT;
    340
    341#ifdef CONFIG_ZCRYPT_DEBUG
    342	if (ap_msg->fi.flags & AP_FI_FLAG_TOGGLE_SPECIAL)
    343		ap_msg->flags ^= AP_MSG_FLAG_SPECIAL;
    344#endif
    345
    346	return 0;
    347}
    348
    349/*
    350 * Copy results from a type 80 reply message back to user space.
    351 *
    352 * @zq: crypto device pointer
    353 * @reply: reply AP message.
    354 * @data: pointer to user output data
    355 * @length: size of user output data
    356 *
    357 * Returns 0 on success or -EFAULT.
    358 */
    359static int convert_type80(struct zcrypt_queue *zq,
    360			  struct ap_message *reply,
    361			  char __user *outputdata,
    362			  unsigned int outputdatalength)
    363{
    364	struct type80_hdr *t80h = reply->msg;
    365	unsigned char *data;
    366
    367	if (t80h->len < sizeof(*t80h) + outputdatalength) {
    368		/* The result is too short, the CEXxA card may not do that.. */
    369		zq->online = 0;
    370		pr_err("Crypto dev=%02x.%04x code=0x%02x => online=0 rc=EAGAIN\n",
    371		       AP_QID_CARD(zq->queue->qid),
    372		       AP_QID_QUEUE(zq->queue->qid), t80h->code);
    373		ZCRYPT_DBF_ERR("%s dev=%02x.%04x code=0x%02x => online=0 rc=EAGAIN\n",
    374			       __func__, AP_QID_CARD(zq->queue->qid),
    375			       AP_QID_QUEUE(zq->queue->qid), t80h->code);
    376		ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
    377		return -EAGAIN;
    378	}
    379	if (zq->zcard->user_space_type == ZCRYPT_CEX2A)
    380		BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE);
    381	else
    382		BUG_ON(t80h->len > CEX3A_MAX_RESPONSE_SIZE);
    383	data = reply->msg + t80h->len - outputdatalength;
    384	if (copy_to_user(outputdata, data, outputdatalength))
    385		return -EFAULT;
    386	return 0;
    387}
    388
    389static int convert_response_cex2a(struct zcrypt_queue *zq,
    390				  struct ap_message *reply,
    391				  char __user *outputdata,
    392				  unsigned int outputdatalength)
    393{
    394	/* Response type byte is the second byte in the response. */
    395	unsigned char rtype = ((unsigned char *)reply->msg)[1];
    396
    397	switch (rtype) {
    398	case TYPE82_RSP_CODE:
    399	case TYPE88_RSP_CODE:
    400		return convert_error(zq, reply);
    401	case TYPE80_RSP_CODE:
    402		return convert_type80(zq, reply,
    403				      outputdata, outputdatalength);
    404	default: /* Unknown response type, this should NEVER EVER happen */
    405		zq->online = 0;
    406		pr_err("Crypto dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n",
    407		       AP_QID_CARD(zq->queue->qid),
    408		       AP_QID_QUEUE(zq->queue->qid),
    409		       (int)rtype);
    410		ZCRYPT_DBF_ERR(
    411			"%s dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n",
    412			__func__, AP_QID_CARD(zq->queue->qid),
    413			AP_QID_QUEUE(zq->queue->qid), (int)rtype);
    414		ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
    415		return -EAGAIN;
    416	}
    417}
    418
    419/*
    420 * This function is called from the AP bus code after a crypto request
    421 * "msg" has finished with the reply message "reply".
    422 * It is called from tasklet context.
    423 * @aq: pointer to the AP device
    424 * @msg: pointer to the AP message
    425 * @reply: pointer to the AP reply message
    426 */
    427static void zcrypt_cex2a_receive(struct ap_queue *aq,
    428				 struct ap_message *msg,
    429				 struct ap_message *reply)
    430{
    431	static struct error_hdr error_reply = {
    432		.type = TYPE82_RSP_CODE,
    433		.reply_code = REP82_ERROR_MACHINE_FAILURE,
    434	};
    435	struct type80_hdr *t80h;
    436	int len;
    437
    438	/* Copy the reply message to the request message buffer. */
    439	if (!reply)
    440		goto out;	/* ap_msg->rc indicates the error */
    441	t80h = reply->msg;
    442	if (t80h->type == TYPE80_RSP_CODE) {
    443		len = t80h->len;
    444		if (len > reply->bufsize || len > msg->bufsize) {
    445			msg->rc = -EMSGSIZE;
    446		} else {
    447			memcpy(msg->msg, reply->msg, len);
    448			msg->len = len;
    449		}
    450	} else {
    451		memcpy(msg->msg, reply->msg, sizeof(error_reply));
    452	}
    453out:
    454	complete((struct completion *)msg->private);
    455}
    456
    457static atomic_t zcrypt_step = ATOMIC_INIT(0);
    458
    459/*
    460 * The request distributor calls this function if it picked the CEXxA
    461 * device to handle a modexpo request.
    462 * @zq: pointer to zcrypt_queue structure that identifies the
    463 *	CEXxA device to the request distributor
    464 * @mex: pointer to the modexpo request buffer
    465 */
    466static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq,
    467				 struct ica_rsa_modexpo *mex,
    468				 struct ap_message *ap_msg)
    469{
    470	struct completion work;
    471	int rc;
    472
    473	ap_msg->bufsize = (zq->zcard->user_space_type == ZCRYPT_CEX2A) ?
    474		MSGTYPE50_CRB2_MAX_MSG_SIZE : MSGTYPE50_CRB3_MAX_MSG_SIZE;
    475	ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
    476	if (!ap_msg->msg)
    477		return -ENOMEM;
    478	ap_msg->receive = zcrypt_cex2a_receive;
    479	ap_msg->psmid = (((unsigned long long)current->pid) << 32) +
    480		atomic_inc_return(&zcrypt_step);
    481	ap_msg->private = &work;
    482	rc = ICAMEX_msg_to_type50MEX_msg(zq, ap_msg, mex);
    483	if (rc)
    484		goto out;
    485	init_completion(&work);
    486	rc = ap_queue_message(zq->queue, ap_msg);
    487	if (rc)
    488		goto out;
    489	rc = wait_for_completion_interruptible(&work);
    490	if (rc == 0) {
    491		rc = ap_msg->rc;
    492		if (rc == 0)
    493			rc = convert_response_cex2a(zq, ap_msg,
    494						    mex->outputdata,
    495						    mex->outputdatalength);
    496	} else {
    497		/* Signal pending. */
    498		ap_cancel_message(zq->queue, ap_msg);
    499	}
    500
    501out:
    502	ap_msg->private = NULL;
    503	if (rc)
    504		ZCRYPT_DBF_DBG("%s send me cprb at dev=%02x.%04x rc=%d\n",
    505			       __func__, AP_QID_CARD(zq->queue->qid),
    506			       AP_QID_QUEUE(zq->queue->qid), rc);
    507	return rc;
    508}
    509
    510/*
    511 * The request distributor calls this function if it picked the CEXxA
    512 * device to handle a modexpo_crt request.
    513 * @zq: pointer to zcrypt_queue structure that identifies the
    514 *	CEXxA device to the request distributor
    515 * @crt: pointer to the modexpoc_crt request buffer
    516 */
    517static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq,
    518				     struct ica_rsa_modexpo_crt *crt,
    519				     struct ap_message *ap_msg)
    520{
    521	struct completion work;
    522	int rc;
    523
    524	ap_msg->bufsize = (zq->zcard->user_space_type == ZCRYPT_CEX2A) ?
    525		MSGTYPE50_CRB2_MAX_MSG_SIZE : MSGTYPE50_CRB3_MAX_MSG_SIZE;
    526	ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
    527	if (!ap_msg->msg)
    528		return -ENOMEM;
    529	ap_msg->receive = zcrypt_cex2a_receive;
    530	ap_msg->psmid = (((unsigned long long)current->pid) << 32) +
    531		atomic_inc_return(&zcrypt_step);
    532	ap_msg->private = &work;
    533	rc = ICACRT_msg_to_type50CRT_msg(zq, ap_msg, crt);
    534	if (rc)
    535		goto out;
    536	init_completion(&work);
    537	rc = ap_queue_message(zq->queue, ap_msg);
    538	if (rc)
    539		goto out;
    540	rc = wait_for_completion_interruptible(&work);
    541	if (rc == 0) {
    542		rc = ap_msg->rc;
    543		if (rc == 0)
    544			rc = convert_response_cex2a(zq, ap_msg,
    545						    crt->outputdata,
    546						    crt->outputdatalength);
    547	} else {
    548		/* Signal pending. */
    549		ap_cancel_message(zq->queue, ap_msg);
    550	}
    551
    552out:
    553	ap_msg->private = NULL;
    554	if (rc)
    555		ZCRYPT_DBF_DBG("%s send crt cprb at dev=%02x.%04x rc=%d\n",
    556			       __func__, AP_QID_CARD(zq->queue->qid),
    557			       AP_QID_QUEUE(zq->queue->qid), rc);
    558	return rc;
    559}
    560
    561/*
    562 * The crypto operations for message type 50.
    563 */
    564static struct zcrypt_ops zcrypt_msgtype50_ops = {
    565	.rsa_modexpo = zcrypt_cex2a_modexpo,
    566	.rsa_modexpo_crt = zcrypt_cex2a_modexpo_crt,
    567	.owner = THIS_MODULE,
    568	.name = MSGTYPE50_NAME,
    569	.variant = MSGTYPE50_VARIANT_DEFAULT,
    570};
    571
    572void __init zcrypt_msgtype50_init(void)
    573{
    574	zcrypt_msgtype_register(&zcrypt_msgtype50_ops);
    575}
    576
    577void __exit zcrypt_msgtype50_exit(void)
    578{
    579	zcrypt_msgtype_unregister(&zcrypt_msgtype50_ops);
    580}