ssh_key_material.c
Go to the documentation of this file.
1 /**
2  * @file ssh_key_material.c
3  * @brief Key material generation
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2019-2025 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneSSH Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.5.2
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL SSH_TRACE_LEVEL
33 
34 //Dependencies
35 #include "ssh/ssh.h"
36 #include "ssh/ssh_key_material.h"
37 #include "ssh/ssh_misc.h"
38 #include "debug.h"
39 
40 //Check SSH stack configuration
41 #if (SSH_SUPPORT == ENABLED)
42 
43 
44 /**
45  * @brief Initialize encryption engine
46  * @param[in] connection Pointer to the SSH connection
47  * @param[in] encryptionEngine Pointer to the encryption/decryption engine to
48  * be initialized
49  * @param[in] encAlgo Selected encryption algorithm (NULL-terminated string)
50  * @param[in] macAlgo Selected integrity algorithm (NULL-terminated string)
51  * @param[in] x A single character used to derive keys
52  * @return Error code
53  **/
54 
56  SshEncryptionEngine *encryptionEngine, const char_t *encAlgo,
57  const char_t *macAlgo, uint8_t x)
58 {
59  error_t error;
60 
61  //Select the relevant cipher algorithm
62  error = sshSelectCipherAlgo(encryptionEngine, encAlgo);
63  //Any error to report?
64  if(error)
65  return error;
66 
67  //Select the relevant hash algorithm
68  error = sshSelectHashAlgo(encryptionEngine, encAlgo, macAlgo);
69  //Any error to report?
70  if(error)
71  return error;
72 
73 #if (SSH_STREAM_CIPHER_SUPPORT == ENABLED)
74  //Stream cipher?
75  if(encryptionEngine->cipherMode == CIPHER_MODE_STREAM)
76  {
77  //Compute encryption key
78  error = sshDeriveKey(connection, x + 2, encryptionEngine->encKey,
79  encryptionEngine->encKeyLen);
80  //Any error to report?
81  if(error)
82  return error;
83 
84  //Compute integrity key
85  error = sshDeriveKey(connection, x + 4, encryptionEngine->macKey,
86  encryptionEngine->hashAlgo->digestSize);
87  //Any error to report?
88  if(error)
89  return error;
90 
91  //Initialize stream cipher context
92  error = encryptionEngine->cipherAlgo->init(&encryptionEngine->cipherContext,
93  encryptionEngine->encKey, encryptionEngine->encKeyLen);
94  //Any error to report?
95  if(error)
96  return error;
97 
98  //Improved RC4 mode?
99  if(sshCompareAlgo(encAlgo, "arcfour128") ||
100  sshCompareAlgo(encAlgo, "arcfour256"))
101  {
102  //Discard the first 1536 bytes of keystream so as to ensure that the
103  //cipher's internal state is thoroughly mixed (refer to RFC 4345,
104  //section 1)
105  encryptionEngine->cipherAlgo->encryptStream(
106  &encryptionEngine->cipherContext, NULL, NULL, 1536);
107  }
108 
109  //Initialize HMAC context
110  encryptionEngine->hmacContext = &connection->hmacContext;
111  }
112  else
113 #endif
114 #if (SSH_CBC_CIPHER_SUPPORT == ENABLED || SSH_CTR_CIPHER_SUPPORT == ENABLED)
115  //CBC or CTR block cipher?
116  if(encryptionEngine->cipherMode == CIPHER_MODE_CBC ||
117  encryptionEngine->cipherMode == CIPHER_MODE_CTR)
118  {
119  //Compute initial IV
120  error = sshDeriveKey(connection, x, encryptionEngine->iv,
121  encryptionEngine->cipherAlgo->blockSize);
122  //Any error to report?
123  if(error)
124  return error;
125 
126  //Compute encryption key
127  error = sshDeriveKey(connection, x + 2, encryptionEngine->encKey,
128  encryptionEngine->encKeyLen);
129  //Any error to report?
130  if(error)
131  return error;
132 
133  //Compute integrity key
134  error = sshDeriveKey(connection, x + 4, encryptionEngine->macKey,
135  encryptionEngine->hashAlgo->digestSize);
136  //Any error to report?
137  if(error)
138  return error;
139 
140  //Initialize block cipher context
141  error = encryptionEngine->cipherAlgo->init(&encryptionEngine->cipherContext,
142  encryptionEngine->encKey, encryptionEngine->encKeyLen);
143  //Any error to report?
144  if(error)
145  return error;
146 
147  //Initialize HMAC context
148  encryptionEngine->hmacContext = &connection->hmacContext;
149  }
150  else
151 #endif
152 #if (SSH_GCM_CIPHER_SUPPORT == ENABLED || SSH_RFC5647_SUPPORT == ENABLED)
153  //GCM AEAD cipher?
154  if(encryptionEngine->cipherMode == CIPHER_MODE_GCM)
155  {
156  //AES-GCM requires a 12-octet initial IV
157  error = sshDeriveKey(connection, x, encryptionEngine->iv, 12);
158  //Any error to report?
159  if(error)
160  return error;
161 
162  //AES-GCM requires a encryption key of either 16 or 32 octets
163  error = sshDeriveKey(connection, x + 2, encryptionEngine->encKey,
164  encryptionEngine->encKeyLen);
165  //Any error to report?
166  if(error)
167  return error;
168 
169  //Because an AEAD algorithm such as AES-GCM uses the encryption key to
170  //provide both confidentiality and data integrity, the integrity key is
171  //not used with AES-GCM (refer to RFC 5647, section 5.1)
172  error = encryptionEngine->cipherAlgo->init(&encryptionEngine->cipherContext,
173  encryptionEngine->encKey, encryptionEngine->encKeyLen);
174  //Any error to report?
175  if(error)
176  return error;
177 
178  //Initialize GCM context
179  error = gcmInit(&encryptionEngine->gcmContext, encryptionEngine->cipherAlgo,
180  &encryptionEngine->cipherContext);
181  //Any error to report?
182  if(error)
183  return error;
184  }
185  else
186 #endif
187 #if (SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
188  //ChaCha20Poly1305 AEAD cipher?
189  if(encryptionEngine->cipherMode == CIPHER_MODE_CHACHA20_POLY1305)
190  {
191  //The cipher requires 512 bits of key material as output from the SSH
192  //key exchange. This forms two 256 bit keys (K_1 and K_2), used by two
193  //separate instances of ChaCha20
194  error = sshDeriveKey(connection, x + 2, encryptionEngine->encKey,
195  encryptionEngine->encKeyLen);
196  //Any error to report?
197  if(error)
198  return error;
199  }
200  else
201 #endif
202  //Invalid cipher mode?
203  {
204  //The specified cipher mode is not supported
206  }
207 
208  //Successful processing
209  return NO_ERROR;
210 }
211 
212 
213 /**
214  * @brief Release encryption engine
215  * @param[in] encryptionEngine Pointer to the encryption/decryption engine
216  **/
217 
219 {
220  //Valid cipher context?
221  if(encryptionEngine->cipherAlgo != NULL)
222  {
223  //Erase cipher context
224  encryptionEngine->cipherAlgo->deinit(&encryptionEngine->cipherContext);
225  }
226 
227 #if (SSH_GCM_CIPHER_SUPPORT == ENABLED || SSH_RFC5647_SUPPORT == ENABLED)
228  //Erase GCM context
229  osMemset(&encryptionEngine->gcmContext, 0, sizeof(GcmContext));
230 #endif
231 
232  //Reset encryption parameters
233  encryptionEngine->cipherMode = CIPHER_MODE_NULL;
234  encryptionEngine->cipherAlgo = NULL;
235  encryptionEngine->hashAlgo = NULL;
236  encryptionEngine->hmacContext = NULL;
237  encryptionEngine->macSize = 0;
238  encryptionEngine->etm = FALSE;
239 
240  //Erase IV
241  osMemset(encryptionEngine->iv, 0, SSH_MAX_CIPHER_BLOCK_SIZE);
242 
243  //Erase encryption key
244  osMemset(encryptionEngine->encKey, 0, SSH_MAX_ENC_KEY_SIZE);
245  encryptionEngine->encKeyLen = 0;
246 
247  //Erase integrity key
248  osMemset(encryptionEngine->macKey, 0, SSH_MAX_HASH_DIGEST_SIZE);
249 }
250 
251 
252 /**
253  * @brief Select the relevant cipher algorithm
254  * @param[in] encryptionEngine Pointer to the encryption/decryption engine to
255  * be initialized
256  * @param[in] encAlgo Encryption algorithm name
257  * @return Error code
258  **/
259 
261  const char_t *encAlgo)
262 {
263  error_t error;
264 
265  //Initialize status code
266  error = NO_ERROR;
267 
268 #if (SSH_RC4_SUPPORT == ENABLED && SSH_STREAM_CIPHER_SUPPORT == ENABLED)
269  //Legacy RC4 encryption algorithm?
270  if(sshCompareAlgo(encAlgo, "arcfour"))
271  {
272  //This cipher uses RC4 with a 128-bit key (refer to RFC 4253, section 6.3)
273  encryptionEngine->cipherMode = CIPHER_MODE_STREAM;
274  encryptionEngine->cipherAlgo = RC4_CIPHER_ALGO;
275  encryptionEngine->encKeyLen = 16;
276  }
277  else
278 #endif
279 #if (SSH_RC4_128_SUPPORT == ENABLED && SSH_STREAM_CIPHER_SUPPORT == ENABLED)
280  //RC4 with 128-bit key encryption algorithm?
281  if(sshCompareAlgo(encAlgo, "arcfour128"))
282  {
283  //This cipher uses RC4 with a 128-bit key (refer to RFC 4345, section 4)
284  encryptionEngine->cipherMode = CIPHER_MODE_STREAM;
285  encryptionEngine->cipherAlgo = RC4_CIPHER_ALGO;
286  encryptionEngine->encKeyLen = 16;
287  }
288  else
289 #endif
290 #if (SSH_RC4_256_SUPPORT == ENABLED && SSH_STREAM_CIPHER_SUPPORT == ENABLED)
291  //RC4 with 256-bit key encryption algorithm?
292  if(sshCompareAlgo(encAlgo, "arcfour256"))
293  {
294  //This cipher uses RC4 with a 256-bit key (refer to RFC 4345, section 4)
295  encryptionEngine->cipherMode = CIPHER_MODE_STREAM;
296  encryptionEngine->cipherAlgo = RC4_CIPHER_ALGO;
297  encryptionEngine->encKeyLen = 32;
298  }
299  else
300 #endif
301 #if (SSH_CAST128_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
302  //CAST-128-CBC encryption algorithm?
303  if(sshCompareAlgo(encAlgo, "cast128-cbc"))
304  {
305  //This cipher uses CAST-128 in CBC mode with a 128-bit key (refer to
306  //RFC 4253, section 6.3)
307  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
308  encryptionEngine->cipherAlgo = CAST128_CIPHER_ALGO;
309  encryptionEngine->encKeyLen = 16;
310  }
311  else
312 #endif
313 #if (SSH_CAST128_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
314  //CAST-128-CTR encryption algorithm?
315  if(sshCompareAlgo(encAlgo, "cast128-ctr"))
316  {
317  //This cipher uses CAST-128 in CTR mode with a 128-bit key (refer to
318  //RFC 4344, section 4)
319  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
320  encryptionEngine->cipherAlgo = CAST128_CIPHER_ALGO;
321  encryptionEngine->encKeyLen = 16;
322  }
323  else
324 #endif
325 #if (SSH_IDEA_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
326  //IDEA-CBC encryption algorithm?
327  if(sshCompareAlgo(encAlgo, "idea-cbc"))
328  {
329  //This cipher uses IDEA in CBC mode (refer to RFC 4253, section 6.3)
330  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
331  encryptionEngine->cipherAlgo = IDEA_CIPHER_ALGO;
332  encryptionEngine->encKeyLen = 16;
333  }
334  else
335 #endif
336 #if (SSH_IDEA_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
337  //IDEA-CTR encryption algorithm?
338  if(sshCompareAlgo(encAlgo, "idea-ctr"))
339  {
340  //This cipher uses IDEA in CTR mode (refer to RFC 4344, section 4)
341  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
342  encryptionEngine->cipherAlgo = IDEA_CIPHER_ALGO;
343  encryptionEngine->encKeyLen = 16;
344  }
345  else
346 #endif
347 #if (SSH_BLOWFISH_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
348  //Blowfish-CBC encryption algorithm?
349  if(sshCompareAlgo(encAlgo, "blowfish-cbc"))
350  {
351  //This cipher uses Blowfish in CBC mode with a 128-bit key (refer to
352  //RFC 4253, section 6.3)
353  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
354  encryptionEngine->cipherAlgo = BLOWFISH_CIPHER_ALGO;
355  encryptionEngine->encKeyLen = 16;
356  }
357  else
358 #endif
359 #if (SSH_BLOWFISH_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
360  //Blowfish-CTR encryption algorithm?
361  if(sshCompareAlgo(encAlgo, "blowfish-ctr"))
362  {
363  //This cipher uses Blowfish in CTR mode with a 256-bit key (refer to
364  //RFC 4344, section 4)
365  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
366  encryptionEngine->cipherAlgo = BLOWFISH_CIPHER_ALGO;
367  encryptionEngine->encKeyLen = 32;
368  }
369  else
370 #endif
371 #if (SSH_3DES_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
372  //3DES-CBC encryption algorithm?
373  if(sshCompareAlgo(encAlgo, "3des-cbc"))
374  {
375  //This cipher uses Triple DES EDE in CBC mode (refer to RFC 4253,
376  //section 6.3)
377  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
378  encryptionEngine->cipherAlgo = DES3_CIPHER_ALGO;
379  encryptionEngine->encKeyLen = 24;
380  }
381  else
382 #endif
383 #if (SSH_3DES_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
384  //3DES-CTR encryption algorithm?
385  if(sshCompareAlgo(encAlgo, "3des-ctr"))
386  {
387  //This cipher uses Triple DES EDE in CTR mode (refer to RFC 4344,
388  //section 4)
389  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
390  encryptionEngine->cipherAlgo = DES3_CIPHER_ALGO;
391  encryptionEngine->encKeyLen = 24;
392  }
393  else
394 #endif
395 #if (SSH_AES_128_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
396  //AES-CBC with 128-bit key encryption algorithm?
397  if(sshCompareAlgo(encAlgo, "aes128-cbc"))
398  {
399  //This cipher uses AES in CBC mode with a 128-bit key (refer to
400  //RFC 4253, section 6.3)
401  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
402  encryptionEngine->cipherAlgo = AES_CIPHER_ALGO;
403  encryptionEngine->encKeyLen = 16;
404  }
405  else
406 #endif
407 #if (SSH_AES_192_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
408  //AES-CBC with 192-bit key encryption algorithm?
409  if(sshCompareAlgo(encAlgo, "aes192-cbc"))
410  {
411  //This cipher uses AES in CBC mode with a 192-bit key (refer to
412  //RFC 4253, section 6.3)
413  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
414  encryptionEngine->cipherAlgo = AES_CIPHER_ALGO;
415  encryptionEngine->encKeyLen = 24;
416  }
417  else
418 #endif
419 #if (SSH_AES_256_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
420  //AES-CBC with 256-bit key encryption algorithm?
421  if(sshCompareAlgo(encAlgo, "aes256-cbc"))
422  {
423  //This cipher uses AES in CBC mode with a 256-bit key (refer to
424  //RFC 4253, section 6.3)
425  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
426  encryptionEngine->cipherAlgo = AES_CIPHER_ALGO;
427  encryptionEngine->encKeyLen = 32;
428  }
429  else
430 #endif
431 #if (SSH_AES_128_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
432  //AES-CTR with 128-bit key encryption algorithm?
433  if(sshCompareAlgo(encAlgo, "aes128-ctr"))
434  {
435  //This cipher uses AES in CTR mode with a 128-bit key (refer to
436  //RFC 4344, section 4)
437  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
438  encryptionEngine->cipherAlgo = AES_CIPHER_ALGO;
439  encryptionEngine->encKeyLen = 16;
440  }
441  else
442 #endif
443 #if (SSH_AES_192_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
444  //AES-CTR with 192-bit key encryption algorithm?
445  if(sshCompareAlgo(encAlgo, "aes192-ctr"))
446  {
447  //This cipher uses AES in CTR mode with a 192-bit key (refer to
448  //RFC 4344, section 4)
449  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
450  encryptionEngine->cipherAlgo = AES_CIPHER_ALGO;
451  encryptionEngine->encKeyLen = 24;
452  }
453  else
454 #endif
455 #if (SSH_AES_256_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
456  //AES-CTR with 256-bit key encryption algorithm?
457  if(sshCompareAlgo(encAlgo, "aes256-ctr"))
458  {
459  //This cipher uses AES in CTR mode with a 256-bit key (refer to
460  //RFC 4344, section 4)
461  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
462  encryptionEngine->cipherAlgo = AES_CIPHER_ALGO;
463  encryptionEngine->encKeyLen = 32;
464  }
465  else
466 #endif
467 #if (SSH_TWOFISH_128_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
468  //Twofish-CBC with 128-bit key encryption algorithm?
469  if(sshCompareAlgo(encAlgo, "twofish128-cbc"))
470  {
471  //This cipher uses Twofish in CBC mode with a 128-bit key
472  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
473  encryptionEngine->cipherAlgo = TWOFISH_CIPHER_ALGO;
474  encryptionEngine->encKeyLen = 16;
475  }
476  else
477 #endif
478 #if (SSH_TWOFISH_192_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
479  //Twofish-CBC with 192-bit key encryption algorithm?
480  if(sshCompareAlgo(encAlgo, "twofish192-cbc"))
481  {
482  //This cipher uses Twofish in CBC mode with a 192-bit key
483  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
484  encryptionEngine->cipherAlgo = TWOFISH_CIPHER_ALGO;
485  encryptionEngine->encKeyLen = 24;
486  }
487  else
488 #endif
489 #if (SSH_TWOFISH_256_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
490  //Twofish-CBC with 256-bit key encryption algorithm?
491  if(sshCompareAlgo(encAlgo, "twofish256-cbc") ||
492  sshCompareAlgo(encAlgo, "twofish-cbc"))
493  {
494  //This cipher uses Twofish in CBC mode with a 256-bit key
495  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
496  encryptionEngine->cipherAlgo = TWOFISH_CIPHER_ALGO;
497  encryptionEngine->encKeyLen = 32;
498  }
499  else
500 #endif
501 #if (SSH_TWOFISH_128_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
502  //Twofish-CTR with 128-bit key encryption algorithm?
503  if(sshCompareAlgo(encAlgo, "twofish128-ctr"))
504  {
505  //This cipher uses Twofish in CTR mode with a 128-bit key
506  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
507  encryptionEngine->cipherAlgo = TWOFISH_CIPHER_ALGO;
508  encryptionEngine->encKeyLen = 16;
509  }
510  else
511 #endif
512 #if (SSH_TWOFISH_192_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
513  //Twofish-CTR with 192-bit key encryption algorithm?
514  if(sshCompareAlgo(encAlgo, "twofish192-ctr"))
515  {
516  //This cipher uses Twofish in CTR mode with a 192-bit key
517  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
518  encryptionEngine->cipherAlgo = TWOFISH_CIPHER_ALGO;
519  encryptionEngine->encKeyLen = 24;
520  }
521  else
522 #endif
523 #if (SSH_TWOFISH_256_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
524  //Twofish-CTR with 256-bit key encryption algorithm?
525  if(sshCompareAlgo(encAlgo, "twofish256-ctr"))
526  {
527  //This cipher uses Twofish in CTR mode with a 256-bit key
528  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
529  encryptionEngine->cipherAlgo = TWOFISH_CIPHER_ALGO;
530  encryptionEngine->encKeyLen = 32;
531  }
532  else
533 #endif
534 #if (SSH_SERPENT_128_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
535  //Serpent-CBC with 128-bit key encryption algorithm?
536  if(sshCompareAlgo(encAlgo, "serpent128-cbc"))
537  {
538  //This cipher uses Serpent in CBC mode with a 128-bit key
539  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
540  encryptionEngine->cipherAlgo = SERPENT_CIPHER_ALGO;
541  encryptionEngine->encKeyLen = 16;
542  }
543  else
544 #endif
545 #if (SSH_SERPENT_192_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
546  //Serpent-CBC with 192-bit key encryption algorithm?
547  if(sshCompareAlgo(encAlgo, "serpent192-cbc"))
548  {
549  //This cipher uses Serpent in CBC mode with a 192-bit key
550  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
551  encryptionEngine->cipherAlgo = SERPENT_CIPHER_ALGO;
552  encryptionEngine->encKeyLen = 24;
553  }
554  else
555 #endif
556 #if (SSH_SERPENT_256_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
557  //Serpent-CBC with 256-bit key encryption algorithm?
558  if(sshCompareAlgo(encAlgo, "serpent256-cbc"))
559  {
560  //This cipher uses Serpent in CBC mode with a 256-bit key
561  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
562  encryptionEngine->cipherAlgo = SERPENT_CIPHER_ALGO;
563  encryptionEngine->encKeyLen = 32;
564  }
565  else
566 #endif
567 #if (SSH_SERPENT_128_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
568  //Serpent-CTR with 128-bit key encryption algorithm?
569  if(sshCompareAlgo(encAlgo, "serpent128-ctr"))
570  {
571  //This cipher uses Serpent in CTR mode with a 128-bit key
572  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
573  encryptionEngine->cipherAlgo = SERPENT_CIPHER_ALGO;
574  encryptionEngine->encKeyLen = 16;
575  }
576  else
577 #endif
578 #if (SSH_SERPENT_192_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
579  //Serpent-CTR with 192-bit key encryption algorithm?
580  if(sshCompareAlgo(encAlgo, "serpent192-ctr"))
581  {
582  //This cipher uses Serpent in CTR mode with a 192-bit key
583  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
584  encryptionEngine->cipherAlgo = SERPENT_CIPHER_ALGO;
585  encryptionEngine->encKeyLen = 24;
586  }
587  else
588 #endif
589 #if (SSH_SERPENT_256_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
590  //Serpent-CTR with 256-bit key encryption algorithm?
591  if(sshCompareAlgo(encAlgo, "serpent256-ctr"))
592  {
593  //This cipher uses Serpent in CTR mode with a 256-bit key
594  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
595  encryptionEngine->cipherAlgo = SERPENT_CIPHER_ALGO;
596  encryptionEngine->encKeyLen = 32;
597  }
598  else
599 #endif
600 #if (SSH_CAMELLIA_128_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
601  //Camellia-CBC with 128-bit key encryption algorithm?
602  if(sshCompareAlgo(encAlgo, "camellia128-cbc"))
603  {
604  //This cipher uses Camellia in CBC mode with a 128-bit key
605  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
606  encryptionEngine->cipherAlgo = CAMELLIA_CIPHER_ALGO;
607  encryptionEngine->encKeyLen = 16;
608  }
609  else
610 #endif
611 #if (SSH_CAMELLIA_192_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
612  //Camellia-CBC with 192-bit key encryption algorithm?
613  if(sshCompareAlgo(encAlgo, "camellia192-cbc"))
614  {
615  //This cipher uses Camellia in CBC mode with a 192-bit key
616  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
617  encryptionEngine->cipherAlgo = CAMELLIA_CIPHER_ALGO;
618  encryptionEngine->encKeyLen = 24;
619  }
620  else
621 #endif
622 #if (SSH_CAMELLIA_256_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
623  //Camellia-CBC with 256-bit key encryption algorithm?
624  if(sshCompareAlgo(encAlgo, "camellia256-cbc"))
625  {
626  //This cipher uses Camellia in CBC mode with a 256-bit key
627  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
628  encryptionEngine->cipherAlgo = CAMELLIA_CIPHER_ALGO;
629  encryptionEngine->encKeyLen = 32;
630  }
631  else
632 #endif
633 #if (SSH_CAMELLIA_128_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
634  //Camellia-CTR with 128-bit key encryption algorithm?
635  if(sshCompareAlgo(encAlgo, "camellia128-ctr"))
636  {
637  //This cipher uses Camellia in CTR mode with a 128-bit key
638  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
639  encryptionEngine->cipherAlgo = CAMELLIA_CIPHER_ALGO;
640  encryptionEngine->encKeyLen = 16;
641  }
642  else
643 #endif
644 #if (SSH_CAMELLIA_192_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
645  //Camellia-CTR with 192-bit key encryption algorithm?
646  if(sshCompareAlgo(encAlgo, "camellia192-ctr"))
647  {
648  //This cipher uses Camellia in CTR mode with a 192-bit key
649  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
650  encryptionEngine->cipherAlgo = CAMELLIA_CIPHER_ALGO;
651  encryptionEngine->encKeyLen = 24;
652  }
653  else
654 #endif
655 #if (SSH_CAMELLIA_256_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
656  //Camellia-CTR with 256-bit key encryption algorithm?
657  if(sshCompareAlgo(encAlgo, "camellia256-ctr"))
658  {
659  //This cipher uses Camellia in CTR mode with a 256-bit key
660  encryptionEngine->cipherMode = CIPHER_MODE_CTR;
661  encryptionEngine->cipherAlgo = CAMELLIA_CIPHER_ALGO;
662  encryptionEngine->encKeyLen = 32;
663  }
664  else
665 #endif
666 #if (SSH_SEED_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
667  //SEED-CBC encryption algorithm?
668  if(sshCompareAlgo(encAlgo, "seed-cbc@ssh.com"))
669  {
670  //This cipher uses SEED in CBC mode
671  encryptionEngine->cipherMode = CIPHER_MODE_CBC;
672  encryptionEngine->cipherAlgo = SEED_CIPHER_ALGO;
673  encryptionEngine->encKeyLen = 16;
674  }
675  else
676 #endif
677 #if (SSH_AES_128_SUPPORT == ENABLED && SSH_GCM_CIPHER_SUPPORT == ENABLED)
678  //AES-GCM with 128-bit key encryption algorithm?
679  if(sshCompareAlgo(encAlgo, "aes128-gcm") ||
680  sshCompareAlgo(encAlgo, "aes128-gcm@openssh.com"))
681  {
682  //AEAD algorithms offer both encryption and authentication
683  encryptionEngine->cipherMode = CIPHER_MODE_GCM;
684  encryptionEngine->cipherAlgo = AES_CIPHER_ALGO;
685  encryptionEngine->encKeyLen = 16;
686  }
687  else
688 #endif
689 #if (SSH_AES_256_SUPPORT == ENABLED && SSH_GCM_CIPHER_SUPPORT == ENABLED)
690  //AES-GCM with 256-bit key encryption algorithm?
691  if(sshCompareAlgo(encAlgo, "aes256-gcm") ||
692  sshCompareAlgo(encAlgo, "aes256-gcm@openssh.com"))
693  {
694  //AEAD algorithms offer both encryption and authentication
695  encryptionEngine->cipherMode = CIPHER_MODE_GCM;
696  encryptionEngine->cipherAlgo = AES_CIPHER_ALGO;
697  encryptionEngine->encKeyLen = 32;
698  }
699  else
700 #endif
701 #if (SSH_AES_128_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
702  //AES-GCM with 128-bit key encryption algorithm?
703  if(sshCompareAlgo(encAlgo, "AEAD_AES_128_GCM"))
704  {
705  //AEAD algorithms offer both encryption and authentication
706  encryptionEngine->cipherMode = CIPHER_MODE_GCM;
707  encryptionEngine->cipherAlgo = AES_CIPHER_ALGO;
708  encryptionEngine->encKeyLen = 16;
709  }
710  else
711 #endif
712 #if (SSH_AES_256_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
713  //AES-GCM with 256-bit key encryption algorithm?
714  if(sshCompareAlgo(encAlgo, "AEAD_AES_256_GCM"))
715  {
716  //AEAD algorithms offer both encryption and authentication
717  encryptionEngine->cipherMode = CIPHER_MODE_GCM;
718  encryptionEngine->cipherAlgo = AES_CIPHER_ALGO;
719  encryptionEngine->encKeyLen = 32;
720  }
721  else
722 #endif
723 #if (SSH_CAMELLIA_128_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
724  //Camellia-GCM with 128-bit key encryption algorithm?
725  if(sshCompareAlgo(encAlgo, "AEAD_CAMELLIA_128_GCM"))
726  {
727  //AEAD algorithms offer both encryption and authentication
728  encryptionEngine->cipherMode = CIPHER_MODE_GCM;
729  encryptionEngine->cipherAlgo = CAMELLIA_CIPHER_ALGO;
730  encryptionEngine->encKeyLen = 16;
731  }
732  else
733 #endif
734 #if (SSH_CAMELLIA_256_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
735  //Camellia-GCM with 256-bit key encryption algorithm?
736  if(sshCompareAlgo(encAlgo, "AEAD_CAMELLIA_256_GCM"))
737  {
738  //AEAD algorithms offer both encryption and authentication
739  encryptionEngine->cipherMode = CIPHER_MODE_GCM;
740  encryptionEngine->cipherAlgo = CAMELLIA_CIPHER_ALGO;
741  encryptionEngine->encKeyLen = 32;
742  }
743  else
744 #endif
745 #if (SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
746  //ChaCha20Poly1305 encryption algorithm?
747  if(sshCompareAlgo(encAlgo, "chacha20-poly1305") ||
748  sshCompareAlgo(encAlgo, "chacha20-poly1305@openssh.com"))
749  {
750  //AEAD algorithms offer both encryption and authentication
751  encryptionEngine->cipherMode = CIPHER_MODE_CHACHA20_POLY1305;
752  encryptionEngine->cipherAlgo = NULL;
753  encryptionEngine->encKeyLen = 64;
754  }
755  else
756 #endif
757  //Unknown encryption algorithm?
758  {
759  //Report an error
761  }
762 
763  //Return status code
764  return error;
765 }
766 
767 
768 /**
769  * @brief Select the relevant hash algorithm
770  * @param[in] encryptionEngine Pointer to the encryption/decryption engine to
771  * be initialized
772  * @param[in] encAlgo Encryption algorithm name
773  * @param[in] macAlgo Integrity algorithm name
774  * @return Error code
775  **/
776 
778  const char_t *encAlgo, const char_t *macAlgo)
779 {
780  error_t error;
781 
782  //Initialize status code
783  error = NO_ERROR;
784 
785 #if (SSH_AES_128_SUPPORT == ENABLED && SSH_GCM_CIPHER_SUPPORT == ENABLED)
786  //AES-GCM with 128-bit key authenticated encryption algorithm?
787  if(sshCompareAlgo(encAlgo, "aes128-gcm") ||
788  sshCompareAlgo(encAlgo, "aes128-gcm@openssh.com"))
789  {
790  //AEAD algorithms offer both encryption and authentication
791  encryptionEngine->hashAlgo = NULL;
792  encryptionEngine->macSize = 16;
793  encryptionEngine->etm = FALSE;
794  }
795  else
796 #endif
797 #if (SSH_AES_256_SUPPORT == ENABLED && SSH_GCM_CIPHER_SUPPORT == ENABLED)
798  //AES-GCM with 256-bit key authenticated encryption algorithm?
799  if(sshCompareAlgo(encAlgo, "aes256-gcm") ||
800  sshCompareAlgo(encAlgo, "aes256-gcm@openssh.com"))
801  {
802  //AEAD algorithms offer both encryption and authentication
803  encryptionEngine->hashAlgo = NULL;
804  encryptionEngine->macSize = 16;
805  encryptionEngine->etm = FALSE;
806  }
807  else
808 #endif
809 #if (SSH_AES_128_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
810  //AES-GCM with 128-bit key authenticated encryption algorithm?
811  if(sshCompareAlgo(encAlgo, "AEAD_AES_128_GCM"))
812  {
813  //AEAD algorithms offer both encryption and authentication
814  encryptionEngine->hashAlgo = NULL;
815  encryptionEngine->macSize = 16;
816  encryptionEngine->etm = FALSE;
817  }
818  else
819 #endif
820 #if (SSH_AES_256_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
821  //AES-GCM with 256-bit key authenticated encryption algorithm?
822  if(sshCompareAlgo(encAlgo, "AEAD_AES_256_GCM"))
823  {
824  //AEAD algorithms offer both encryption and authentication
825  encryptionEngine->hashAlgo = NULL;
826  encryptionEngine->macSize = 16;
827  encryptionEngine->etm = FALSE;
828  }
829  else
830 #endif
831 #if (SSH_CAMELLIA_128_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
832  //Camellia-GCM with 128-bit key authenticated encryption algorithm?
833  if(sshCompareAlgo(encAlgo, "AEAD_CAMELLIA_128_GCM"))
834  {
835  //AEAD algorithms offer both encryption and authentication
836  encryptionEngine->hashAlgo = NULL;
837  encryptionEngine->macSize = 16;
838  encryptionEngine->etm = FALSE;
839  }
840  else
841 #endif
842 #if (SSH_CAMELLIA_256_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
843  //Camellia-GCM with 256-bit key authenticated encryption algorithm?
844  if(sshCompareAlgo(encAlgo, "AEAD_CAMELLIA_256_GCM"))
845  {
846  //AEAD algorithms offer both encryption and authentication
847  encryptionEngine->hashAlgo = NULL;
848  encryptionEngine->macSize = 16;
849  encryptionEngine->etm = FALSE;
850  }
851  else
852 #endif
853 #if (SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
854  //ChaCha20Poly1305 authenticated encryption algorithm?
855  if(sshCompareAlgo(encAlgo, "chacha20-poly1305") ||
856  sshCompareAlgo(encAlgo, "chacha20-poly1305@openssh.com"))
857  {
858  //AEAD algorithms offer both encryption and authentication
859  encryptionEngine->hashAlgo = NULL;
860  encryptionEngine->macSize = 16;
861  encryptionEngine->etm = FALSE;
862  }
863  else
864 #endif
865 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_MD5_SUPPORT == ENABLED)
866  //HMAC with MD5 integrity algorithm?
867  if(sshCompareAlgo(macAlgo, "hmac-md5"))
868  {
869  //Select MAC-then-encrypt mode
870  encryptionEngine->hashAlgo = MD5_HASH_ALGO;
871  encryptionEngine->macSize = MD5_DIGEST_SIZE;
872  encryptionEngine->etm = FALSE;
873  }
874  else
875 #endif
876 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_MD5_SUPPORT == ENABLED && \
877  SSH_ETM_SUPPORT == ENABLED)
878  //HMAC with MD5 integrity algorithm (EtM mode)?
879  if(sshCompareAlgo(macAlgo, "hmac-md5-etm@openssh.com"))
880  {
881  //Select encrypt-then-MAC mode
882  encryptionEngine->hashAlgo = MD5_HASH_ALGO;
883  encryptionEngine->macSize = MD5_DIGEST_SIZE;
884  encryptionEngine->etm = TRUE;
885  }
886  else
887 #endif
888 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_MD5_96_SUPPORT == ENABLED)
889  //HMAC with MD5/96 integrity algorithm?
890  if(sshCompareAlgo(macAlgo, "hmac-md5-96"))
891  {
892  //Select MAC-then-encrypt mode
893  encryptionEngine->hashAlgo = MD5_HASH_ALGO;
894  encryptionEngine->macSize = 12;
895  encryptionEngine->etm = FALSE;
896  }
897  else
898 #endif
899 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_MD5_96_SUPPORT == ENABLED && \
900  SSH_ETM_SUPPORT == ENABLED)
901  //HMAC with MD5/96 integrity algorithm (EtM mode)?
902  if(sshCompareAlgo(macAlgo, "hmac-md5-96-etm@openssh.com"))
903  {
904  //Select encrypt-then-MAC mode
905  encryptionEngine->hashAlgo = MD5_HASH_ALGO;
906  encryptionEngine->macSize = 12;
907  encryptionEngine->etm = TRUE;
908  }
909  else
910 #endif
911 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_RIPEMD160_SUPPORT == ENABLED)
912  //HMAC with RIPEMD-160 integrity algorithm?
913  if(sshCompareAlgo(macAlgo, "hmac-ripemd160") ||
914  sshCompareAlgo(macAlgo, "hmac-ripemd160@openssh.com"))
915  {
916  //Select MAC-then-encrypt mode
917  encryptionEngine->hashAlgo = RIPEMD160_HASH_ALGO;
918  encryptionEngine->macSize = RIPEMD160_DIGEST_SIZE;
919  encryptionEngine->etm = FALSE;
920  }
921  else
922 #endif
923 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_RIPEMD160_SUPPORT == ENABLED && \
924  SSH_ETM_SUPPORT == ENABLED)
925  //HMAC with RIPEMD-160 integrity algorithm (EtM mode)?
926  if(sshCompareAlgo(macAlgo, "hmac-ripemd160-etm@openssh.com"))
927  {
928  //Select encrypt-then-MAC mode
929  encryptionEngine->hashAlgo = RIPEMD160_HASH_ALGO;
930  encryptionEngine->macSize = RIPEMD160_DIGEST_SIZE;
931  encryptionEngine->etm = TRUE;
932  }
933  else
934 #endif
935 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA1_SUPPORT == ENABLED)
936  //HMAC with SHA-1 integrity algorithm?
937  if(sshCompareAlgo(macAlgo, "hmac-sha1"))
938  {
939  //Select MAC-then-encrypt mode
940  encryptionEngine->hashAlgo = SHA1_HASH_ALGO;
941  encryptionEngine->macSize = SHA1_DIGEST_SIZE;
942  encryptionEngine->etm = FALSE;
943  }
944  else
945 #endif
946 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA1_SUPPORT == ENABLED && \
947  SSH_ETM_SUPPORT == ENABLED)
948  //HMAC with SHA-1 integrity algorithm (EtM mode)?
949  if(sshCompareAlgo(macAlgo, "hmac-sha1-etm@openssh.com"))
950  {
951  //Select encrypt-then-MAC mode
952  encryptionEngine->hashAlgo = SHA1_HASH_ALGO;
953  encryptionEngine->macSize = SHA1_DIGEST_SIZE;
954  encryptionEngine->etm = TRUE;
955  }
956  else
957 #endif
958 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA1_96_SUPPORT == ENABLED)
959  //HMAC with SHA-1/96 integrity algorithm?
960  if(sshCompareAlgo(macAlgo, "hmac-sha1-96"))
961  {
962  //Select MAC-then-encrypt mode
963  encryptionEngine->hashAlgo = SHA1_HASH_ALGO;
964  encryptionEngine->macSize = 12;
965  encryptionEngine->etm = FALSE;
966  }
967  else
968 #endif
969 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA1_96_SUPPORT == ENABLED && \
970  SSH_ETM_SUPPORT == ENABLED)
971  //HMAC with SHA-1/96 integrity algorithm (EtM mode)?
972  if(sshCompareAlgo(macAlgo, "hmac-sha1-96-etm@openssh.com"))
973  {
974  //Select encrypt-then-MAC mode
975  encryptionEngine->hashAlgo = SHA1_HASH_ALGO;
976  encryptionEngine->macSize = 12;
977  encryptionEngine->etm = TRUE;
978  }
979  else
980 #endif
981 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED)
982  //HMAC with SHA-256 integrity algorithm?
983  if(sshCompareAlgo(macAlgo, "hmac-sha2-256"))
984  {
985  //Select MAC-then-encrypt mode
986  encryptionEngine->hashAlgo = SHA256_HASH_ALGO;
987  encryptionEngine->macSize = SHA256_DIGEST_SIZE;
988  encryptionEngine->etm = FALSE;
989  }
990  else
991 #endif
992 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED && \
993  SSH_ETM_SUPPORT == ENABLED)
994  //HMAC with SHA-256 integrity algorithm (EtM mode)?
995  if(sshCompareAlgo(macAlgo, "hmac-sha2-256-etm@openssh.com"))
996  {
997  //Select encrypt-then-MAC mode
998  encryptionEngine->hashAlgo = SHA256_HASH_ALGO;
999  encryptionEngine->macSize = SHA256_DIGEST_SIZE;
1000  encryptionEngine->etm = TRUE;
1001  }
1002  else
1003 #endif
1004 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED)
1005  //HMAC with SHA-512 integrity algorithm?
1006  if(sshCompareAlgo(macAlgo, "hmac-sha2-512"))
1007  {
1008  //Select MAC-then-encrypt mode
1009  encryptionEngine->hashAlgo = SHA512_HASH_ALGO;
1010  encryptionEngine->macSize = SHA512_DIGEST_SIZE;
1011  encryptionEngine->etm = FALSE;
1012  }
1013  else
1014 #endif
1015 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED && \
1016  SSH_ETM_SUPPORT == ENABLED)
1017  //HMAC with SHA-512 integrity algorithm (EtM mode)?
1018  if(sshCompareAlgo(macAlgo, "hmac-sha2-512-etm@openssh.com"))
1019  {
1020  //Select encrypt-then-MAC mode
1021  encryptionEngine->hashAlgo = SHA512_HASH_ALGO;
1022  encryptionEngine->macSize = SHA512_DIGEST_SIZE;
1023  encryptionEngine->etm = TRUE;
1024  }
1025  else
1026 #endif
1027  //Unknown integrity algorithm?
1028  {
1029  //Report an error
1031  }
1032 
1033  //Return status code
1034  return error;
1035 }
1036 
1037 
1038 /**
1039  * @brief Key derivation function
1040  * @param[in] connection Pointer to the SSH connection
1041  * @param[in] x A single character
1042  * @param[out] output Pointer to the output
1043  * @param[in] outputLen Desired output length
1044  * @return Error code
1045  **/
1046 
1047 error_t sshDeriveKey(SshConnection *connection, uint8_t x, uint8_t *output,
1048  size_t outputLen)
1049 {
1050  error_t error;
1051  size_t i;
1052  size_t n;
1053  const HashAlgo *hashAlgo;
1054  HashContext *hashContext;
1055  uint8_t digest[SSH_MAX_HASH_DIGEST_SIZE];
1056 
1057  //Each key exchange method specifies a hash function that is used in the key
1058  //exchange. The same hash algorithm must be used in key derivation (refer to
1059  //RFC 4253, section 7.2)
1060  hashAlgo = connection->hashAlgo;
1061 
1062  //Make sure the hash algorithm is valid
1063  if(hashAlgo != NULL)
1064  {
1065  //Allocate a memory buffer to hold the hash context
1066  hashContext = sshAllocMem(hashAlgo->contextSize);
1067 
1068  //Successful memory allocation?
1069  if(hashContext != NULL)
1070  {
1071  //Compute K(1) = HASH(K || H || X || session_id)
1072  hashAlgo->init(hashContext);
1073  hashAlgo->update(hashContext, connection->k, connection->kLen);
1074  hashAlgo->update(hashContext, connection->h, connection->hLen);
1075  hashAlgo->update(hashContext, &x, sizeof(x));
1076  hashAlgo->update(hashContext, connection->sessionId, connection->sessionIdLen);
1077  hashAlgo->final(hashContext, digest);
1078 
1079  //Key data must be taken from the beginning of the hash output
1080  for(n = 0; n < hashAlgo->digestSize && n < outputLen; n++)
1081  {
1082  output[n] = digest[n];
1083  }
1084 
1085  //If the key length needed is longer than the output of the HASH, the key
1086  //is extended by computing HASH of the concatenation of K and H and the
1087  //entire key so far, and appending the resulting bytes to the key
1088  while(n < outputLen)
1089  {
1090  //Compute K(n + 1) = HASH(K || H || K(1) || ... || K(n))
1091  hashAlgo->init(hashContext);
1092  hashAlgo->update(hashContext, connection->k, connection->kLen);
1093  hashAlgo->update(hashContext, connection->h, connection->hLen);
1094  hashAlgo->update(hashContext, output, n);
1095  hashAlgo->final(hashContext, digest);
1096 
1097  //This process is repeated until enough key material is available
1098  for(i = 0; i < hashAlgo->digestSize && n < outputLen; i++, n++)
1099  {
1100  output[n] = digest[i];
1101  }
1102  }
1103 
1104  //Release hash context
1105  sshFreeMem(hashContext);
1106 
1107  //Successful processing
1108  error = NO_ERROR;
1109  }
1110  else
1111  {
1112  //Failed to allocate memory
1113  error = ERROR_OUT_OF_MEMORY;
1114  }
1115  }
1116  else
1117  {
1118  //The hash algorithm is not valid
1119  error = ERROR_FAILURE;
1120  }
1121 
1122  //Return status code
1123  return error;
1124 }
1125 
1126 
1127 /**
1128  * @brief Dump secret key (for debugging purpose only)
1129  * @param[in] connection Pointer to the SSH connection
1130  * @param[in] label Identifying label (NULL-terminated string)
1131  * @param[in] key Pointer to the secret key
1132  * @param[in] keyLen Length of the secret key, in bytes
1133  **/
1134 
1135 void sshDumpKey(SshConnection *connection, const char_t *label,
1136  const uint8_t *key, size_t keyLen)
1137 {
1138 #if (SSH_KEY_LOG_SUPPORT == ENABLED)
1139  SshContext *context;
1140 
1141  //Point to the SSH context
1142  context = connection->context;
1143 
1144  //Any registered callback?
1145  if(context->keyLogCallback != NULL)
1146  {
1147  size_t i;
1148  size_t n;
1149  char_t *buffer;
1150 
1151  //Allocate a buffer to hold the formatted string
1152  buffer = sshAllocMem(2 * SSH_COOKIE_SIZE + 2 * keyLen +
1153  osStrlen(label) + 3);
1154 
1155  //Successful memory allocation?
1156  if(buffer != NULL)
1157  {
1158  //Convert the cookie to a hex string
1159  for(i = 0, n = 0; i < SSH_COOKIE_SIZE; i++)
1160  {
1161  //Format current byte
1162  n += osSprintf(buffer + n, "%02" PRIX8, connection->cookie[i]);
1163  }
1164 
1165  //The middle part is a static label indicating the type of key material
1166  //that follows
1167  n += osSprintf(buffer + n, " %s ", label);
1168 
1169  //Convert the shared secret to a hex string
1170  for(i = 0; i < keyLen; i++)
1171  {
1172  //Format current byte
1173  n += osSprintf(buffer + n, "%02" PRIX8, key[i]);
1174  }
1175 
1176  //Properly terminate the string with a NULL character
1177  buffer[n] = '\0';
1178 
1179  //Invoke user callback function
1180  context->keyLogCallback(connection, buffer);
1181 
1182  //Release previously allocated memory
1183  sshFreeMem(buffer);
1184  }
1185  }
1186 #endif
1187 }
1188 
1189 #endif
HashAlgoInit init
Definition: crypto.h:1099
#define TWOFISH_CIPHER_ALGO
Definition: twofish.h:40
Generic hash algorithm context.
#define SHA256_HASH_ALGO
Definition: sha256.h:49
#define SHA1_HASH_ALGO
Definition: sha1.h:49
@ CIPHER_MODE_CBC
Definition: crypto.h:1008
#define SHA512_HASH_ALGO
Definition: sha512.h:49
void sshFreeEncryptionEngine(SshEncryptionEngine *encryptionEngine)
Release encryption engine.
uint8_t macKey[SSH_MAX_HASH_DIGEST_SIZE]
Integrity key.
Definition: ssh.h:1327
#define BLOWFISH_CIPHER_ALGO
Definition: blowfish.h:40
uint8_t iv[SSH_MAX_CIPHER_BLOCK_SIZE]
Initialization vector.
Definition: ssh.h:1324
void sshDumpKey(SshConnection *connection, const char_t *label, const uint8_t *key, size_t keyLen)
Dump secret key (for debugging purpose only)
@ CIPHER_MODE_GCM
Definition: crypto.h:1013
uint8_t x
Definition: lldp_ext_med.h:211
const HashAlgo * hashAlgo
Hash algorithm for MAC operations.
Definition: ssh.h:1320
#define TRUE
Definition: os_port.h:50
size_t digestSize
Definition: crypto.h:1095
GcmContext gcmContext
GCM context.
Definition: ssh.h:1330
HashAlgoUpdate update
Definition: crypto.h:1100
size_t macSize
Size of the MAC tag, in bytes.
Definition: ssh.h:1322
#define IDEA_CIPHER_ALGO
Definition: idea.h:40
size_t blockSize
Definition: crypto.h:1115
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
__weak_func error_t gcmInit(GcmContext *context, const CipherAlgo *cipherAlgo, void *cipherContext)
Initialize GCM context.
Definition: gcm.c:99
#define osStrlen(s)
Definition: os_port.h:168
#define SERPENT_CIPHER_ALGO
Definition: serpent.h:40
@ CIPHER_MODE_CTR
Definition: crypto.h:1011
size_t contextSize
Definition: crypto.h:1093
Encryption engine.
Definition: ssh.h:1316
#define SSH_MAX_CIPHER_BLOCK_SIZE
Definition: ssh.h:752
CipherAlgoInit init
Definition: crypto.h:1116
CipherAlgoEncryptStream encryptStream
Definition: crypto.h:1117
@ ERROR_UNSUPPORTED_CIPHER_MODE
Definition: error.h:128
Key material generation.
#define FALSE
Definition: os_port.h:46
@ ERROR_UNSUPPORTED_HASH_ALGO
Definition: error.h:130
#define SshContext
Definition: ssh.h:870
error_t
Error codes.
Definition: error.h:43
CipherMode cipherMode
Cipher mode of operation.
Definition: ssh.h:1317
#define osSprintf(dest,...)
Definition: os_port.h:234
#define SEED_CIPHER_ALGO
Definition: seed.h:40
bool_t sshCompareAlgo(const char_t *name1, const char_t *name2)
Compare algorithm names.
Definition: ssh_misc.c:1747
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define RIPEMD160_DIGEST_SIZE
Definition: ripemd160.h:40
#define MD5_HASH_ALGO
Definition: md5.h:49
const CipherAlgo * cipherAlgo
Cipher algorithm.
Definition: ssh.h:1318
uint8_t encKey[SSH_MAX_ENC_KEY_SIZE]
Encryption key.
Definition: ssh.h:1325
#define RC4_CIPHER_ALGO
Definition: rc4.h:38
bool_t etm
Encrypt-then-MAC.
Definition: ssh.h:1323
error_t sshInitEncryptionEngine(SshConnection *connection, SshEncryptionEngine *encryptionEngine, const char_t *encAlgo, const char_t *macAlgo, uint8_t x)
Initialize encryption engine.
CipherContext cipherContext
Cipher context.
Definition: ssh.h:1319
#define CAMELLIA_CIPHER_ALGO
Definition: camellia.h:40
@ CIPHER_MODE_STREAM
Definition: crypto.h:1006
error_t sshSelectCipherAlgo(SshEncryptionEngine *encryptionEngine, const char_t *encAlgo)
Select the relevant cipher algorithm.
#define MD5_DIGEST_SIZE
Definition: md5.h:45
#define RIPEMD160_HASH_ALGO
Definition: ripemd160.h:44
#define SSH_MAX_HASH_DIGEST_SIZE
Definition: ssh.h:789
error_t sshSelectHashAlgo(SshEncryptionEngine *encryptionEngine, const char_t *encAlgo, const char_t *macAlgo)
Select the relevant hash algorithm.
HashAlgoFinal final
Definition: crypto.h:1101
char char_t
Definition: compiler_port.h:55
GCM context.
Definition: gcm.h:64
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
#define sshFreeMem(p)
Definition: ssh.h:729
#define SSH_MAX_ENC_KEY_SIZE
Definition: ssh.h:745
@ ERROR_UNSUPPORTED_CIPHER_ALGO
Definition: error.h:129
uint8_t n
#define SshConnection
Definition: ssh.h:874
CipherAlgoDeinit deinit
Definition: crypto.h:1121
error_t sshDeriveKey(SshConnection *connection, uint8_t x, uint8_t *output, size_t outputLen)
Key derivation function.
SSH helper functions.
#define AES_CIPHER_ALGO
Definition: aes.h:45
#define CAST128_CIPHER_ALGO
Definition: cast128.h:40
HmacContext * hmacContext
HMAC context.
Definition: ssh.h:1321
Common interface for hash algorithms.
Definition: crypto.h:1089
#define sshAllocMem(size)
Definition: ssh.h:724
@ CIPHER_MODE_NULL
Definition: crypto.h:1005
@ CIPHER_MODE_CHACHA20_POLY1305
Definition: crypto.h:1015
#define DES3_CIPHER_ALGO
Definition: des3.h:46
#define SSH_COOKIE_SIZE
Definition: ssh.h:859
#define osMemset(p, value, length)
Definition: os_port.h:138
Secure Shell (SSH)
#define SHA256_DIGEST_SIZE
Definition: sha256.h:45
#define SHA512_DIGEST_SIZE
Definition: sha512.h:45
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
size_t encKeyLen
Length of the encryption key, in bytes.
Definition: ssh.h:1326