summaryrefslogtreecommitdiff
path: root/crypto/df_sp80090a.c
blob: dc63b31a93fc2daff63fc8fe4bc9aa56e78eacf8 (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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// SPDX-License-Identifier: GPL-2.0

/*
 * NIST SP800-90A DRBG derivation function
 *
 * Copyright (C) 2014, Stephan Mueller <smueller@chronox.de>
 */

#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <crypto/aes.h>
#include <crypto/df_sp80090a.h>
#include <crypto/internal/drbg.h>

static void drbg_kcapi_symsetkey(struct crypto_aes_ctx *aesctx,
				 const unsigned char *key,
				 u8 keylen);
static void drbg_kcapi_symsetkey(struct crypto_aes_ctx *aesctx,
				 const unsigned char *key, u8 keylen)
{
	aes_expandkey(aesctx, key, keylen);
}

static void drbg_kcapi_sym(struct crypto_aes_ctx *aesctx,
			   unsigned char *outval,
			   const struct drbg_string *in, u8 blocklen_bytes)
{
	/* there is only component in *in */
	BUG_ON(in->len < blocklen_bytes);
	aes_encrypt(aesctx, outval, in->buf);
}

/* BCC function for CTR DRBG as defined in 10.4.3 */

static void drbg_ctr_bcc(struct crypto_aes_ctx *aesctx,
			 unsigned char *out, const unsigned char *key,
			 struct list_head *in,
			 u8 blocklen_bytes,
			 u8 keylen)
{
	struct drbg_string *curr = NULL;
	struct drbg_string data;
	short cnt = 0;

	drbg_string_fill(&data, out, blocklen_bytes);

	/* 10.4.3 step 2 / 4 */
	drbg_kcapi_symsetkey(aesctx, key, keylen);
	list_for_each_entry(curr, in, list) {
		const unsigned char *pos = curr->buf;
		size_t len = curr->len;
		/* 10.4.3 step 4.1 */
		while (len) {
			/* 10.4.3 step 4.2 */
			if (blocklen_bytes == cnt) {
				cnt = 0;
				drbg_kcapi_sym(aesctx, out, &data, blocklen_bytes);
			}
			out[cnt] ^= *pos;
			pos++;
			cnt++;
			len--;
		}
	}
	/* 10.4.3 step 4.2 for last block */
	if (cnt)
		drbg_kcapi_sym(aesctx, out, &data, blocklen_bytes);
}

/*
 * scratchpad usage: drbg_ctr_update is interlinked with crypto_drbg_ctr_df
 * (and drbg_ctr_bcc, but this function does not need any temporary buffers),
 * the scratchpad is used as follows:
 * drbg_ctr_update:
 *	temp
 *		start: drbg->scratchpad
 *		length: drbg_statelen(drbg) + drbg_blocklen(drbg)
 *			note: the cipher writing into this variable works
 *			blocklen-wise. Now, when the statelen is not a multiple
 *			of blocklen, the generateion loop below "spills over"
 *			by at most blocklen. Thus, we need to give sufficient
 *			memory.
 *	df_data
 *		start: drbg->scratchpad +
 *				drbg_statelen(drbg) + drbg_blocklen(drbg)
 *		length: drbg_statelen(drbg)
 *
 * crypto_drbg_ctr_df:
 *	pad
 *		start: df_data + drbg_statelen(drbg)
 *		length: drbg_blocklen(drbg)
 *	iv
 *		start: pad + drbg_blocklen(drbg)
 *		length: drbg_blocklen(drbg)
 *	temp
 *		start: iv + drbg_blocklen(drbg)
 *		length: drbg_satelen(drbg) + drbg_blocklen(drbg)
 *			note: temp is the buffer that the BCC function operates
 *			on. BCC operates blockwise. drbg_statelen(drbg)
 *			is sufficient when the DRBG state length is a multiple
 *			of the block size. For AES192 (and maybe other ciphers)
 *			this is not correct and the length for temp is
 *			insufficient (yes, that also means for such ciphers,
 *			the final output of all BCC rounds are truncated).
 *			Therefore, add drbg_blocklen(drbg) to cover all
 *			possibilities.
 * refer to crypto_drbg_ctr_df_datalen() to get required length
 */

/* Derivation Function for CTR DRBG as defined in 10.4.2 */
int crypto_drbg_ctr_df(struct crypto_aes_ctx *aesctx,
		       unsigned char *df_data, size_t bytes_to_return,
		       struct list_head *seedlist,
		       u8 blocklen_bytes,
		       u8 statelen)
{
	unsigned char L_N[8];
	/* S3 is input */
	struct drbg_string S1, S2, S4, cipherin;
	LIST_HEAD(bcc_list);
	unsigned char *pad = df_data + statelen;
	unsigned char *iv = pad + blocklen_bytes;
	unsigned char *temp = iv + blocklen_bytes;
	size_t padlen = 0;
	unsigned int templen = 0;
	/* 10.4.2 step 7 */
	unsigned int i = 0;
	/* 10.4.2 step 8 */
	const unsigned char *K = (unsigned char *)
			   "\x00\x01\x02\x03\x04\x05\x06\x07"
			   "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
			   "\x10\x11\x12\x13\x14\x15\x16\x17"
			   "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f";
	unsigned char *X;
	size_t generated_len = 0;
	size_t inputlen = 0;
	struct drbg_string *seed = NULL;
	u8 keylen;

	memset(pad, 0, blocklen_bytes);
	memset(iv, 0, blocklen_bytes);
	keylen = statelen - blocklen_bytes;
	/* 10.4.2 step 1 is implicit as we work byte-wise */

	/* 10.4.2 step 2 */
	if ((512 / 8) < bytes_to_return)
		return -EINVAL;

	/* 10.4.2 step 2 -- calculate the entire length of all input data */
	list_for_each_entry(seed, seedlist, list)
		inputlen += seed->len;
	drbg_cpu_to_be32(inputlen, &L_N[0]);

	/* 10.4.2 step 3 */
	drbg_cpu_to_be32(bytes_to_return, &L_N[4]);

	/* 10.4.2 step 5: length is L_N, input_string, one byte, padding */
	padlen = (inputlen + sizeof(L_N) + 1) % (blocklen_bytes);
	/* wrap the padlen appropriately */
	if (padlen)
		padlen = blocklen_bytes - padlen;
	/*
	 * pad / padlen contains the 0x80 byte and the following zero bytes.
	 * As the calculated padlen value only covers the number of zero
	 * bytes, this value has to be incremented by one for the 0x80 byte.
	 */
	padlen++;
	pad[0] = 0x80;

	/* 10.4.2 step 4 -- first fill the linked list and then order it */
	drbg_string_fill(&S1, iv, blocklen_bytes);
	list_add_tail(&S1.list, &bcc_list);
	drbg_string_fill(&S2, L_N, sizeof(L_N));
	list_add_tail(&S2.list, &bcc_list);
	list_splice_tail(seedlist, &bcc_list);
	drbg_string_fill(&S4, pad, padlen);
	list_add_tail(&S4.list, &bcc_list);

	/* 10.4.2 step 9 */
	while (templen < (keylen + (blocklen_bytes))) {
		/*
		 * 10.4.2 step 9.1 - the padding is implicit as the buffer
		 * holds zeros after allocation -- even the increment of i
		 * is irrelevant as the increment remains within length of i
		 */
		drbg_cpu_to_be32(i, iv);
		/* 10.4.2 step 9.2 -- BCC and concatenation with temp */
		drbg_ctr_bcc(aesctx, temp + templen, K, &bcc_list,
			     blocklen_bytes, keylen);
		/* 10.4.2 step 9.3 */
		i++;
		templen += blocklen_bytes;
	}

	/* 10.4.2 step 11 */
	X = temp + (keylen);
	drbg_string_fill(&cipherin, X, blocklen_bytes);

	/* 10.4.2 step 12: overwriting of outval is implemented in next step */

	/* 10.4.2 step 13 */
	drbg_kcapi_symsetkey(aesctx, temp, keylen);
	while (generated_len < bytes_to_return) {
		short blocklen = 0;
		/*
		 * 10.4.2 step 13.1: the truncation of the key length is
		 * implicit as the key is only drbg_blocklen in size based on
		 * the implementation of the cipher function callback
		 */
		drbg_kcapi_sym(aesctx, X, &cipherin, blocklen_bytes);
		blocklen = (blocklen_bytes <
				(bytes_to_return - generated_len)) ?
			    blocklen_bytes :
				(bytes_to_return - generated_len);
		/* 10.4.2 step 13.2 and 14 */
		memcpy(df_data + generated_len, X, blocklen);
		generated_len += blocklen;
	}

	memset(iv, 0, blocklen_bytes);
	memset(temp, 0, statelen + blocklen_bytes);
	memset(pad, 0, blocklen_bytes);
	return 0;
}
EXPORT_SYMBOL_GPL(crypto_drbg_ctr_df);

MODULE_IMPORT_NS("CRYPTO_INTERNAL");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
MODULE_DESCRIPTION("Derivation Function conformant to SP800-90A");