summaryrefslogtreecommitdiff
path: root/lib/librte_ipsec/crypto.h
blob: 3e9a8f41ca6c77de3078f974c5919db8ffd6c248 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright(c) 2018 Intel Corporation
 */

#ifndef _CRYPTO_H_
#define _CRYPTO_H_

/**
 * @file crypto.h
 * Contains crypto specific functions/structures/macros used internally
 * by ipsec library.
 */

/*
 * AES-CTR counter block format.
 */

struct aesctr_cnt_blk {
	uint32_t nonce;
	uint64_t iv;
	uint32_t cnt;
} __attribute__((packed));

 /*
  * AES-GCM devices have some specific requirements for IV and AAD formats.
  * Ideally that to be done by the driver itself.
  */

struct aead_gcm_iv {
	uint32_t salt;
	uint64_t iv;
	uint32_t cnt;
} __attribute__((packed));

struct aead_gcm_aad {
	uint32_t spi;
	/*
	 * RFC 4106, section 5:
	 * Two formats of the AAD are defined:
	 * one for 32-bit sequence numbers, and one for 64-bit ESN.
	 */
	union {
		uint32_t u32[2];
		uint64_t u64;
	} sqn;
	uint32_t align0; /* align to 16B boundary */
} __attribute__((packed));

struct gcm_esph_iv {
	struct esp_hdr esph;
	uint64_t iv;
} __attribute__((packed));

static inline void
aes_ctr_cnt_blk_fill(struct aesctr_cnt_blk *ctr, uint64_t iv, uint32_t nonce)
{
	ctr->nonce = nonce;
	ctr->iv = iv;
	ctr->cnt = rte_cpu_to_be_32(1);
}

static inline void
aead_gcm_iv_fill(struct aead_gcm_iv *gcm, uint64_t iv, uint32_t salt)
{
	gcm->salt = salt;
	gcm->iv = iv;
	gcm->cnt = rte_cpu_to_be_32(1);
}

/*
 * RFC 4106, 5 AAD Construction
 * spi and sqn should already be converted into network byte order.
 * Make sure that not used bytes are zeroed.
 */
static inline void
aead_gcm_aad_fill(struct aead_gcm_aad *aad, rte_be32_t spi, rte_be64_t sqn,
	int esn)
{
	aad->spi = spi;
	if (esn)
		aad->sqn.u64 = sqn;
	else {
		aad->sqn.u32[0] = sqn_low32(sqn);
		aad->sqn.u32[1] = 0;
	}
	aad->align0 = 0;
}

static inline void
gen_iv(uint64_t iv[IPSEC_MAX_IV_QWORD], rte_be64_t sqn)
{
	iv[0] = sqn;
	iv[1] = 0;
}

/*
 * Helper routine to copy IV
 * Righ now we support only algorithms with IV length equals 0/8/16 bytes.
 */
static inline void
copy_iv(uint64_t dst[IPSEC_MAX_IV_QWORD],
	const uint64_t src[IPSEC_MAX_IV_QWORD], uint32_t len)
{
	RTE_BUILD_BUG_ON(IPSEC_MAX_IV_SIZE != 2 * sizeof(uint64_t));

	switch (len) {
	case IPSEC_MAX_IV_SIZE:
		dst[1] = src[1];
		/* fallthrough */
	case sizeof(uint64_t):
		dst[0] = src[0];
		/* fallthrough */
	case 0:
		break;
	default:
		/* should never happen */
		RTE_ASSERT(NULL);
	}
}

/*
 * from RFC 4303 3.3.2.1.4:
 * If the ESN option is enabled for the SA, the high-order 32
 * bits of the sequence number are appended after the Next Header field
 * for purposes of this computation, but are not transmitted.
 */

/*
 * Helper function that moves ICV by 4B below, and inserts SQN.hibits.
 * icv parameter points to the new start of ICV.
 */
static inline void
insert_sqh(uint32_t sqh, void *picv, uint32_t icv_len)
{
	uint32_t *icv;
	int32_t i;

	RTE_ASSERT(icv_len % sizeof(uint32_t) == 0);

	icv = picv;
	icv_len = icv_len / sizeof(uint32_t);
	for (i = icv_len; i-- != 0; icv[i] = icv[i - 1])
		;

	icv[i] = sqh;
}

/*
 * Helper function that moves ICV by 4B up, and removes SQN.hibits.
 * icv parameter points to the new start of ICV.
 */
static inline void
remove_sqh(void *picv, uint32_t icv_len)
{
	uint32_t i, *icv;

	RTE_ASSERT(icv_len % sizeof(uint32_t) == 0);

	icv = picv;
	icv_len = icv_len / sizeof(uint32_t);
	for (i = 0; i != icv_len; i++)
		icv[i] = icv[i + 1];
}

/*
 * setup crypto ops for LOOKASIDE_NONE (pure crypto) type of devices.
 */
static inline void
lksd_none_cop_prepare(struct rte_crypto_op *cop,
	struct rte_cryptodev_sym_session *cs, struct rte_mbuf *mb)
{
	struct rte_crypto_sym_op *sop;

	sop = cop->sym;
	cop->type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
	cop->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
	cop->sess_type = RTE_CRYPTO_OP_WITH_SESSION;
	sop->m_src = mb;
	__rte_crypto_sym_op_attach_sym_session(sop, cs);
}

#endif /* _CRYPTO_H_ */