xref: /netbsd-src/crypto/external/bsd/openssh/dist/cipher-ctr-mt.c (revision d91f98a8715141154279122ae81737cb65179572)
1*d91f98a8Spgoyette /*	$NetBSD: cipher-ctr-mt.c,v 1.10 2019/01/27 02:08:33 pgoyette Exp $	*/
2313c6c94Schristos /*
3313c6c94Schristos  * OpenSSH Multi-threaded AES-CTR Cipher
4313c6c94Schristos  *
5313c6c94Schristos  * Author: Benjamin Bennett <ben@psc.edu>
6313c6c94Schristos  * Copyright (c) 2008 Pittsburgh Supercomputing Center. All rights reserved.
7313c6c94Schristos  *
8313c6c94Schristos  * Based on original OpenSSH AES-CTR cipher. Small portions remain unchanged,
9313c6c94Schristos  * Copyright (c) 2003 Markus Friedl <markus@openbsd.org>
10313c6c94Schristos  *
11313c6c94Schristos  * Permission to use, copy, modify, and distribute this software for any
12313c6c94Schristos  * purpose with or without fee is hereby granted, provided that the above
13313c6c94Schristos  * copyright notice and this permission notice appear in all copies.
14313c6c94Schristos  *
15313c6c94Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16313c6c94Schristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17313c6c94Schristos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18313c6c94Schristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19313c6c94Schristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20313c6c94Schristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21313c6c94Schristos  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22313c6c94Schristos  */
23313c6c94Schristos #include "includes.h"
24*d91f98a8Spgoyette __RCSID("$NetBSD: cipher-ctr-mt.c,v 1.10 2019/01/27 02:08:33 pgoyette Exp $");
25313c6c94Schristos 
26313c6c94Schristos #include <sys/types.h>
27313c6c94Schristos 
28313c6c94Schristos #include <stdarg.h>
29313c6c94Schristos #include <string.h>
30313c6c94Schristos 
31313c6c94Schristos #include <openssl/evp.h>
32313c6c94Schristos 
33313c6c94Schristos #include "xmalloc.h"
34313c6c94Schristos #include "log.h"
35313c6c94Schristos 
36313c6c94Schristos #ifndef USE_BUILTIN_RIJNDAEL
37313c6c94Schristos #include <openssl/aes.h>
38313c6c94Schristos #endif
39313c6c94Schristos 
40313c6c94Schristos #include <pthread.h>
41313c6c94Schristos 
42313c6c94Schristos /*-------------------- TUNABLES --------------------*/
43313c6c94Schristos /* Number of pregen threads to use */
44313c6c94Schristos #define CIPHER_THREADS	2
45313c6c94Schristos 
46313c6c94Schristos /* Number of keystream queues */
47313c6c94Schristos #define NUMKQ		(CIPHER_THREADS + 2)
48313c6c94Schristos 
49313c6c94Schristos /* Length of a keystream queue */
50313c6c94Schristos #define KQLEN		4096
51313c6c94Schristos 
52313c6c94Schristos /* Processor cacheline length */
53313c6c94Schristos #define CACHELINE_LEN	64
54313c6c94Schristos 
55313c6c94Schristos /* Collect thread stats and print at cancellation when in debug mode */
56313c6c94Schristos /* #define CIPHER_THREAD_STATS */
57313c6c94Schristos 
58313c6c94Schristos /* Use single-byte XOR instead of 8-byte XOR */
59313c6c94Schristos /* #define CIPHER_BYTE_XOR */
60313c6c94Schristos /*-------------------- END TUNABLES --------------------*/
61313c6c94Schristos 
62313c6c94Schristos #ifdef AES_CTR_MT
63313c6c94Schristos 
64313c6c94Schristos 
65313c6c94Schristos const EVP_CIPHER *evp_aes_ctr_mt(void);
66313c6c94Schristos 
67313c6c94Schristos #ifdef CIPHER_THREAD_STATS
68313c6c94Schristos /*
69313c6c94Schristos  * Struct to collect thread stats
70313c6c94Schristos  */
71313c6c94Schristos struct thread_stats {
72313c6c94Schristos 	u_int	fills;
73313c6c94Schristos 	u_int	skips;
74313c6c94Schristos 	u_int	waits;
75313c6c94Schristos 	u_int	drains;
76313c6c94Schristos };
77313c6c94Schristos 
78313c6c94Schristos /*
79313c6c94Schristos  * Debug print the thread stats
80313c6c94Schristos  * Use with pthread_cleanup_push for displaying at thread cancellation
81313c6c94Schristos  */
82313c6c94Schristos static void
thread_loop_stats(void * x)83313c6c94Schristos thread_loop_stats(void *x)
84313c6c94Schristos {
85313c6c94Schristos 	struct thread_stats *s = x;
86313c6c94Schristos 
87313c6c94Schristos 	debug("tid %lu - %u fills, %u skips, %u waits", pthread_self(),
88313c6c94Schristos 			s->fills, s->skips, s->waits);
89313c6c94Schristos }
90313c6c94Schristos 
91aef795aaSadam  #define STATS_STRUCT(s)	struct thread_stats s
92aef795aaSadam  #define STATS_INIT(s)		{ memset(&s, 0, sizeof(s)); }
93aef795aaSadam  #define STATS_FILL(s)		{ s.fills++; }
94aef795aaSadam  #define STATS_SKIP(s)		{ s.skips++; }
95aef795aaSadam  #define STATS_WAIT(s)		{ s.waits++; }
96aef795aaSadam  #define STATS_DRAIN(s)		{ s.drains++; }
97313c6c94Schristos #else
98313c6c94Schristos  #define STATS_STRUCT(s)
99313c6c94Schristos  #define STATS_INIT(s)
100313c6c94Schristos  #define STATS_FILL(s)
101313c6c94Schristos  #define STATS_SKIP(s)
102313c6c94Schristos  #define STATS_WAIT(s)
103313c6c94Schristos  #define STATS_DRAIN(s)
104313c6c94Schristos #endif
105313c6c94Schristos 
106313c6c94Schristos /* Keystream Queue state */
107313c6c94Schristos enum {
108313c6c94Schristos 	KQINIT,
109313c6c94Schristos 	KQEMPTY,
110313c6c94Schristos 	KQFILLING,
111313c6c94Schristos 	KQFULL,
112313c6c94Schristos 	KQDRAINING
113313c6c94Schristos };
114313c6c94Schristos 
115313c6c94Schristos /* Keystream Queue struct */
116313c6c94Schristos struct kq {
117313c6c94Schristos 	u_char		keys[KQLEN][AES_BLOCK_SIZE];
118313c6c94Schristos 	u_char		ctr[AES_BLOCK_SIZE];
119313c6c94Schristos 	u_char		pad0[CACHELINE_LEN];
120313c6c94Schristos 	volatile int	qstate;
121313c6c94Schristos 	pthread_mutex_t	lock;
122313c6c94Schristos 	pthread_cond_t	cond;
123313c6c94Schristos 	u_char		pad1[CACHELINE_LEN];
124313c6c94Schristos };
125313c6c94Schristos 
126313c6c94Schristos /* Context struct */
127313c6c94Schristos struct ssh_aes_ctr_ctx
128313c6c94Schristos {
129313c6c94Schristos 	struct kq	q[NUMKQ];
130313c6c94Schristos 	AES_KEY		aes_ctx;
131aef795aaSadam 	STATS_STRUCT(stats);
132313c6c94Schristos 	u_char		aes_counter[AES_BLOCK_SIZE];
133313c6c94Schristos 	pthread_t	tid[CIPHER_THREADS];
134313c6c94Schristos 	int		state;
135313c6c94Schristos 	int		qidx;
136313c6c94Schristos 	int		ridx;
137313c6c94Schristos };
138313c6c94Schristos 
139313c6c94Schristos /* <friedl>
140313c6c94Schristos  * increment counter 'ctr',
141313c6c94Schristos  * the counter is of size 'len' bytes and stored in network-byte-order.
142313c6c94Schristos  * (LSB at ctr[len-1], MSB at ctr[0])
143313c6c94Schristos  */
144313c6c94Schristos static void
ssh_ctr_inc(u_char * ctr,u_int len)145313c6c94Schristos ssh_ctr_inc(u_char *ctr, u_int len)
146313c6c94Schristos {
147313c6c94Schristos 	int i;
148313c6c94Schristos 
149313c6c94Schristos 	for (i = len - 1; i >= 0; i--)
150313c6c94Schristos 		if (++ctr[i])	/* continue on overflow */
151313c6c94Schristos 			return;
152313c6c94Schristos }
153313c6c94Schristos 
154313c6c94Schristos /*
155313c6c94Schristos  * Add num to counter 'ctr'
156313c6c94Schristos  */
157313c6c94Schristos static void
ssh_ctr_add(u_char * ctr,uint32_t num,u_int len)158313c6c94Schristos ssh_ctr_add(u_char *ctr, uint32_t num, u_int len)
159313c6c94Schristos {
160313c6c94Schristos 	int i;
161313c6c94Schristos 	uint16_t n;
162313c6c94Schristos 
163313c6c94Schristos 	for (n = 0, i = len - 1; i >= 0 && (num || n); i--) {
164313c6c94Schristos 		n = ctr[i] + (num & 0xff) + n;
165313c6c94Schristos 		num >>= 8;
166313c6c94Schristos 		ctr[i] = n & 0xff;
167313c6c94Schristos 		n >>= 8;
168313c6c94Schristos 	}
169313c6c94Schristos }
170313c6c94Schristos 
171313c6c94Schristos /*
172313c6c94Schristos  * Threads may be cancelled in a pthread_cond_wait, we must free the mutex
173313c6c94Schristos  */
174313c6c94Schristos static void
thread_loop_cleanup(void * x)175313c6c94Schristos thread_loop_cleanup(void *x)
176313c6c94Schristos {
177313c6c94Schristos 	pthread_mutex_unlock((pthread_mutex_t *)x);
178313c6c94Schristos }
179313c6c94Schristos 
180313c6c94Schristos /*
181313c6c94Schristos  * The life of a pregen thread:
182313c6c94Schristos  *    Find empty keystream queues and fill them using their counter.
183313c6c94Schristos  *    When done, update counter for the next fill.
184313c6c94Schristos  */
185313c6c94Schristos static void *
thread_loop(void * x)186313c6c94Schristos thread_loop(void *x)
187313c6c94Schristos {
188313c6c94Schristos 	AES_KEY key;
189aef795aaSadam 	STATS_STRUCT(stats);
190313c6c94Schristos 	struct ssh_aes_ctr_ctx *c = x;
191313c6c94Schristos 	struct kq *q;
192313c6c94Schristos 	int i;
193313c6c94Schristos 	int qidx;
194313c6c94Schristos 
195313c6c94Schristos 	/* Threads stats on cancellation */
196313c6c94Schristos 	STATS_INIT(stats);
197313c6c94Schristos #ifdef CIPHER_THREAD_STATS
198313c6c94Schristos 	pthread_cleanup_push(thread_loop_stats, &stats);
199313c6c94Schristos #endif
200313c6c94Schristos 
201313c6c94Schristos 	/* Thread local copy of AES key */
202313c6c94Schristos 	memcpy(&key, &c->aes_ctx, sizeof(key));
203313c6c94Schristos 
204313c6c94Schristos 	/*
205313c6c94Schristos 	 * Handle the special case of startup, one thread must fill
206313c6c94Schristos  	 * the first KQ then mark it as draining. Lock held throughout.
207313c6c94Schristos  	 */
208313c6c94Schristos 	if (pthread_equal(pthread_self(), c->tid[0])) {
209313c6c94Schristos 		q = &c->q[0];
210313c6c94Schristos 		pthread_mutex_lock(&q->lock);
211313c6c94Schristos 		if (q->qstate == KQINIT) {
212313c6c94Schristos 			for (i = 0; i < KQLEN; i++) {
213313c6c94Schristos 				AES_encrypt(q->ctr, q->keys[i], &key);
214313c6c94Schristos 				ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE);
215313c6c94Schristos 			}
216313c6c94Schristos 			ssh_ctr_add(q->ctr, KQLEN * (NUMKQ - 1), AES_BLOCK_SIZE);
217313c6c94Schristos 			q->qstate = KQDRAINING;
218313c6c94Schristos 			STATS_FILL(stats);
219313c6c94Schristos 			pthread_cond_broadcast(&q->cond);
220313c6c94Schristos 		}
221313c6c94Schristos 		pthread_mutex_unlock(&q->lock);
222313c6c94Schristos 	}
223313c6c94Schristos 	else
224313c6c94Schristos 		STATS_SKIP(stats);
225313c6c94Schristos 
226313c6c94Schristos 	/*
227313c6c94Schristos  	 * Normal case is to find empty queues and fill them, skipping over
228313c6c94Schristos  	 * queues already filled by other threads and stopping to wait for
229313c6c94Schristos  	 * a draining queue to become empty.
230313c6c94Schristos  	 *
231313c6c94Schristos  	 * Multiple threads may be waiting on a draining queue and awoken
232313c6c94Schristos  	 * when empty.  The first thread to wake will mark it as filling,
233313c6c94Schristos  	 * others will move on to fill, skip, or wait on the next queue.
234313c6c94Schristos  	 */
235313c6c94Schristos 	for (qidx = 1;; qidx = (qidx + 1) % NUMKQ) {
236313c6c94Schristos 		/* Check if I was cancelled, also checked in cond_wait */
237313c6c94Schristos 		pthread_testcancel();
238313c6c94Schristos 
239313c6c94Schristos 		/* Lock queue and block if its draining */
240313c6c94Schristos 		q = &c->q[qidx];
241313c6c94Schristos 		pthread_mutex_lock(&q->lock);
242313c6c94Schristos 		pthread_cleanup_push(thread_loop_cleanup, &q->lock);
243313c6c94Schristos 		while (q->qstate == KQDRAINING || q->qstate == KQINIT) {
244313c6c94Schristos 			STATS_WAIT(stats);
245313c6c94Schristos 			pthread_cond_wait(&q->cond, &q->lock);
246313c6c94Schristos 		}
247313c6c94Schristos 		pthread_cleanup_pop(0);
248313c6c94Schristos 
249313c6c94Schristos 		/* If filling or full, somebody else got it, skip */
250313c6c94Schristos 		if (q->qstate != KQEMPTY) {
251313c6c94Schristos 			pthread_mutex_unlock(&q->lock);
252313c6c94Schristos 			STATS_SKIP(stats);
253313c6c94Schristos 			continue;
254313c6c94Schristos 		}
255313c6c94Schristos 
256313c6c94Schristos 		/*
257313c6c94Schristos  		 * Empty, let's fill it.
258313c6c94Schristos  		 * Queue lock is relinquished while we do this so others
259313c6c94Schristos  		 * can see that it's being filled.
260313c6c94Schristos  		 */
261313c6c94Schristos 		q->qstate = KQFILLING;
262313c6c94Schristos 		pthread_mutex_unlock(&q->lock);
263313c6c94Schristos 		for (i = 0; i < KQLEN; i++) {
264313c6c94Schristos 			AES_encrypt(q->ctr, q->keys[i], &key);
265313c6c94Schristos 			ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE);
266313c6c94Schristos 		}
267313c6c94Schristos 
268313c6c94Schristos 		/* Re-lock, mark full and signal consumer */
269313c6c94Schristos 		pthread_mutex_lock(&q->lock);
270313c6c94Schristos 		ssh_ctr_add(q->ctr, KQLEN * (NUMKQ - 1), AES_BLOCK_SIZE);
271313c6c94Schristos 		q->qstate = KQFULL;
272313c6c94Schristos 		STATS_FILL(stats);
273313c6c94Schristos 		pthread_cond_signal(&q->cond);
274313c6c94Schristos 		pthread_mutex_unlock(&q->lock);
275313c6c94Schristos 	}
276313c6c94Schristos 
277313c6c94Schristos #ifdef CIPHER_THREAD_STATS
278313c6c94Schristos 	/* Stats */
279313c6c94Schristos 	pthread_cleanup_pop(1);
280313c6c94Schristos #endif
281313c6c94Schristos 
282313c6c94Schristos 	return NULL;
283313c6c94Schristos }
284313c6c94Schristos 
285313c6c94Schristos static int
ssh_aes_ctr(EVP_CIPHER_CTX * ctx,u_char * dest,const u_char * src,u_int len)286313c6c94Schristos ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
287313c6c94Schristos     u_int len)
288313c6c94Schristos {
289313c6c94Schristos 	struct ssh_aes_ctr_ctx *c;
290313c6c94Schristos 	struct kq *q, *oldq;
291313c6c94Schristos 	int ridx;
292313c6c94Schristos 	u_char *buf;
293313c6c94Schristos 
294313c6c94Schristos 	if (len == 0)
295313c6c94Schristos 		return (1);
296313c6c94Schristos 	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL)
297313c6c94Schristos 		return (0);
298313c6c94Schristos 
299313c6c94Schristos 	q = &c->q[c->qidx];
300313c6c94Schristos 	ridx = c->ridx;
301313c6c94Schristos 
302313c6c94Schristos 	/* src already padded to block multiple */
303313c6c94Schristos 	while (len > 0) {
304313c6c94Schristos 		buf = q->keys[ridx];
305313c6c94Schristos 
306313c6c94Schristos #ifdef CIPHER_BYTE_XOR
307313c6c94Schristos 		dest[0] = src[0] ^ buf[0];
308313c6c94Schristos 		dest[1] = src[1] ^ buf[1];
309313c6c94Schristos 		dest[2] = src[2] ^ buf[2];
310313c6c94Schristos 		dest[3] = src[3] ^ buf[3];
311313c6c94Schristos 		dest[4] = src[4] ^ buf[4];
312313c6c94Schristos 		dest[5] = src[5] ^ buf[5];
313313c6c94Schristos 		dest[6] = src[6] ^ buf[6];
314313c6c94Schristos 		dest[7] = src[7] ^ buf[7];
315313c6c94Schristos 		dest[8] = src[8] ^ buf[8];
316313c6c94Schristos 		dest[9] = src[9] ^ buf[9];
317313c6c94Schristos 		dest[10] = src[10] ^ buf[10];
318313c6c94Schristos 		dest[11] = src[11] ^ buf[11];
319313c6c94Schristos 		dest[12] = src[12] ^ buf[12];
320313c6c94Schristos 		dest[13] = src[13] ^ buf[13];
321313c6c94Schristos 		dest[14] = src[14] ^ buf[14];
322313c6c94Schristos 		dest[15] = src[15] ^ buf[15];
323313c6c94Schristos #else
324313c6c94Schristos 		*(uint64_t *)dest = *(uint64_t *)src ^ *(uint64_t *)buf;
325313c6c94Schristos 		*(uint64_t *)(dest + 8) = *(uint64_t *)(src + 8) ^
326313c6c94Schristos 						*(uint64_t *)(buf + 8);
327313c6c94Schristos #endif
328313c6c94Schristos 
329313c6c94Schristos 		dest += 16;
330313c6c94Schristos 		src += 16;
331313c6c94Schristos 		len -= 16;
332313c6c94Schristos 		ssh_ctr_inc(ctx->iv, AES_BLOCK_SIZE);
333313c6c94Schristos 
334313c6c94Schristos 		/* Increment read index, switch queues on rollover */
335313c6c94Schristos 		if ((ridx = (ridx + 1) % KQLEN) == 0) {
336313c6c94Schristos 			oldq = q;
337313c6c94Schristos 
338313c6c94Schristos 			/* Mark next queue draining, may need to wait */
339313c6c94Schristos 			c->qidx = (c->qidx + 1) % NUMKQ;
340313c6c94Schristos 			q = &c->q[c->qidx];
341313c6c94Schristos 			pthread_mutex_lock(&q->lock);
342313c6c94Schristos 			while (q->qstate != KQFULL) {
343313c6c94Schristos 				STATS_WAIT(c->stats);
344313c6c94Schristos 				pthread_cond_wait(&q->cond, &q->lock);
345313c6c94Schristos 			}
346313c6c94Schristos 			q->qstate = KQDRAINING;
347313c6c94Schristos 			pthread_mutex_unlock(&q->lock);
348313c6c94Schristos 
349313c6c94Schristos 			/* Mark consumed queue empty and signal producers */
350313c6c94Schristos 			pthread_mutex_lock(&oldq->lock);
351313c6c94Schristos 			oldq->qstate = KQEMPTY;
352313c6c94Schristos 			STATS_DRAIN(c->stats);
353313c6c94Schristos 			pthread_cond_broadcast(&oldq->cond);
354313c6c94Schristos 			pthread_mutex_unlock(&oldq->lock);
355313c6c94Schristos 		}
356313c6c94Schristos 	}
357313c6c94Schristos 	c->ridx = ridx;
358313c6c94Schristos 	return (1);
359313c6c94Schristos }
360313c6c94Schristos 
361313c6c94Schristos #define HAVE_NONE       0
362313c6c94Schristos #define HAVE_KEY        1
363313c6c94Schristos #define HAVE_IV         2
364313c6c94Schristos static int
ssh_aes_ctr_init(EVP_CIPHER_CTX * ctx,const u_char * key,const u_char * iv,int enc)365313c6c94Schristos ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
366313c6c94Schristos     int enc)
367313c6c94Schristos {
368313c6c94Schristos 	struct ssh_aes_ctr_ctx *c;
369313c6c94Schristos 	int i;
370313c6c94Schristos 
371313c6c94Schristos 	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
372313c6c94Schristos 		c = xmalloc(sizeof(*c));
373313c6c94Schristos 
374313c6c94Schristos 		c->state = HAVE_NONE;
375313c6c94Schristos 		for (i = 0; i < NUMKQ; i++) {
376313c6c94Schristos 			pthread_mutex_init(&c->q[i].lock, NULL);
377313c6c94Schristos 			pthread_cond_init(&c->q[i].cond, NULL);
378313c6c94Schristos 		}
379313c6c94Schristos 
380313c6c94Schristos 		STATS_INIT(c->stats);
381313c6c94Schristos 
382313c6c94Schristos 		EVP_CIPHER_CTX_set_app_data(ctx, c);
383313c6c94Schristos 	}
384313c6c94Schristos 
385313c6c94Schristos 	if (c->state == (HAVE_KEY | HAVE_IV)) {
386313c6c94Schristos 		/* Cancel pregen threads */
387313c6c94Schristos 		for (i = 0; i < CIPHER_THREADS; i++)
388313c6c94Schristos 			pthread_cancel(c->tid[i]);
389313c6c94Schristos 		for (i = 0; i < CIPHER_THREADS; i++)
390313c6c94Schristos 			pthread_join(c->tid[i], NULL);
391313c6c94Schristos 		/* Start over getting key & iv */
392313c6c94Schristos 		c->state = HAVE_NONE;
393313c6c94Schristos 	}
394313c6c94Schristos 
395313c6c94Schristos 	if (key != NULL) {
396313c6c94Schristos 		AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
397313c6c94Schristos 		    &c->aes_ctx);
398313c6c94Schristos 		c->state |= HAVE_KEY;
399313c6c94Schristos 	}
400313c6c94Schristos 
401313c6c94Schristos 	if (iv != NULL) {
402313c6c94Schristos 		memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
403313c6c94Schristos 		c->state |= HAVE_IV;
404313c6c94Schristos 	}
405313c6c94Schristos 
406313c6c94Schristos 	if (c->state == (HAVE_KEY | HAVE_IV)) {
407313c6c94Schristos 		/* Clear queues */
408313c6c94Schristos 		memcpy(c->q[0].ctr, ctx->iv, AES_BLOCK_SIZE);
409313c6c94Schristos 		c->q[0].qstate = KQINIT;
410313c6c94Schristos 		for (i = 1; i < NUMKQ; i++) {
411313c6c94Schristos 			memcpy(c->q[i].ctr, ctx->iv, AES_BLOCK_SIZE);
412313c6c94Schristos 			ssh_ctr_add(c->q[i].ctr, i * KQLEN, AES_BLOCK_SIZE);
413313c6c94Schristos 			c->q[i].qstate = KQEMPTY;
414313c6c94Schristos 		}
415313c6c94Schristos 		c->qidx = 0;
416313c6c94Schristos 		c->ridx = 0;
417313c6c94Schristos 
418313c6c94Schristos 		/* Start threads */
419313c6c94Schristos 		for (i = 0; i < CIPHER_THREADS; i++) {
420313c6c94Schristos 			pthread_create(&c->tid[i], NULL, thread_loop, c);
421313c6c94Schristos 		}
422313c6c94Schristos 		pthread_mutex_lock(&c->q[0].lock);
423313c6c94Schristos 		while (c->q[0].qstate != KQDRAINING)
424313c6c94Schristos 			pthread_cond_wait(&c->q[0].cond, &c->q[0].lock);
425313c6c94Schristos 		pthread_mutex_unlock(&c->q[0].lock);
426313c6c94Schristos 
427313c6c94Schristos 	}
428313c6c94Schristos 	return (1);
429313c6c94Schristos }
430313c6c94Schristos 
431313c6c94Schristos static int
ssh_aes_ctr_cleanup(EVP_CIPHER_CTX * ctx)432313c6c94Schristos ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx)
433313c6c94Schristos {
434313c6c94Schristos 	struct ssh_aes_ctr_ctx *c;
435313c6c94Schristos 	int i;
436313c6c94Schristos 
437313c6c94Schristos 	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
438313c6c94Schristos #ifdef CIPHER_THREAD_STATS
439313c6c94Schristos 		debug("main thread: %u drains, %u waits", c->stats.drains,
440313c6c94Schristos 				c->stats.waits);
441313c6c94Schristos #endif
442313c6c94Schristos 		/* Cancel pregen threads */
443313c6c94Schristos 		for (i = 0; i < CIPHER_THREADS; i++)
444313c6c94Schristos 			pthread_cancel(c->tid[i]);
445313c6c94Schristos 		for (i = 0; i < CIPHER_THREADS; i++)
446313c6c94Schristos 			pthread_join(c->tid[i], NULL);
447313c6c94Schristos 
448313c6c94Schristos 		memset(c, 0, sizeof(*c));
44900a838c4Schristos 		free(c);
450313c6c94Schristos 		EVP_CIPHER_CTX_set_app_data(ctx, NULL);
451313c6c94Schristos 	}
452313c6c94Schristos 	return (1);
453313c6c94Schristos }
454313c6c94Schristos 
455313c6c94Schristos /* <friedl> */
456313c6c94Schristos const EVP_CIPHER *
evp_aes_ctr_mt(void)457313c6c94Schristos evp_aes_ctr_mt(void)
458313c6c94Schristos {
459313c6c94Schristos 	static EVP_CIPHER aes_ctr;
460313c6c94Schristos 
461313c6c94Schristos 	memset(&aes_ctr, 0, sizeof(EVP_CIPHER));
462313c6c94Schristos 	aes_ctr.nid = NID_undef;
463313c6c94Schristos 	aes_ctr.block_size = AES_BLOCK_SIZE;
464313c6c94Schristos 	aes_ctr.iv_len = AES_BLOCK_SIZE;
465313c6c94Schristos 	aes_ctr.key_len = 16;
466313c6c94Schristos 	aes_ctr.init = ssh_aes_ctr_init;
467313c6c94Schristos 	aes_ctr.cleanup = ssh_aes_ctr_cleanup;
468313c6c94Schristos 	aes_ctr.do_cipher = ssh_aes_ctr;
469313c6c94Schristos #ifndef SSH_OLD_EVP
470313c6c94Schristos 	aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
471313c6c94Schristos 	    EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV;
472313c6c94Schristos #endif
473313c6c94Schristos 	return (&aes_ctr);
474313c6c94Schristos }
475aef795aaSadam #endif /* AES_CTR_MT */
476