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-2024 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.4.0
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@openssh.com"))
680  {
681  //AEAD algorithms offer both encryption and authentication
682  encryptionEngine->cipherMode = CIPHER_MODE_GCM;
683  encryptionEngine->cipherAlgo = AES_CIPHER_ALGO;
684  encryptionEngine->encKeyLen = 16;
685  }
686  else
687 #endif
688 #if (SSH_AES_256_SUPPORT == ENABLED && SSH_GCM_CIPHER_SUPPORT == ENABLED)
689  //AES-GCM with 256-bit key encryption algorithm?
690  if(sshCompareAlgo(encAlgo, "aes256-gcm@openssh.com"))
691  {
692  //AEAD algorithms offer both encryption and authentication
693  encryptionEngine->cipherMode = CIPHER_MODE_GCM;
694  encryptionEngine->cipherAlgo = AES_CIPHER_ALGO;
695  encryptionEngine->encKeyLen = 32;
696  }
697  else
698 #endif
699 #if (SSH_AES_128_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
700  //AES-GCM with 128-bit key encryption algorithm?
701  if(sshCompareAlgo(encAlgo, "AEAD_AES_128_GCM"))
702  {
703  //AEAD algorithms offer both encryption and authentication
704  encryptionEngine->cipherMode = CIPHER_MODE_GCM;
705  encryptionEngine->cipherAlgo = AES_CIPHER_ALGO;
706  encryptionEngine->encKeyLen = 16;
707  }
708  else
709 #endif
710 #if (SSH_AES_256_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
711  //AES-GCM with 256-bit key encryption algorithm?
712  if(sshCompareAlgo(encAlgo, "AEAD_AES_256_GCM"))
713  {
714  //AEAD algorithms offer both encryption and authentication
715  encryptionEngine->cipherMode = CIPHER_MODE_GCM;
716  encryptionEngine->cipherAlgo = AES_CIPHER_ALGO;
717  encryptionEngine->encKeyLen = 32;
718  }
719  else
720 #endif
721 #if (SSH_CAMELLIA_128_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
722  //Camellia-GCM with 128-bit key encryption algorithm?
723  if(sshCompareAlgo(encAlgo, "AEAD_CAMELLIA_128_GCM"))
724  {
725  //AEAD algorithms offer both encryption and authentication
726  encryptionEngine->cipherMode = CIPHER_MODE_GCM;
727  encryptionEngine->cipherAlgo = CAMELLIA_CIPHER_ALGO;
728  encryptionEngine->encKeyLen = 16;
729  }
730  else
731 #endif
732 #if (SSH_CAMELLIA_256_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
733  //Camellia-GCM with 256-bit key encryption algorithm?
734  if(sshCompareAlgo(encAlgo, "AEAD_CAMELLIA_256_GCM"))
735  {
736  //AEAD algorithms offer both encryption and authentication
737  encryptionEngine->cipherMode = CIPHER_MODE_GCM;
738  encryptionEngine->cipherAlgo = CAMELLIA_CIPHER_ALGO;
739  encryptionEngine->encKeyLen = 32;
740  }
741  else
742 #endif
743 #if (SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
744  //ChaCha20Poly1305 encryption algorithm?
745  if(sshCompareAlgo(encAlgo, "chacha20-poly1305@openssh.com"))
746  {
747  //AEAD algorithms offer both encryption and authentication
748  encryptionEngine->cipherMode = CIPHER_MODE_CHACHA20_POLY1305;
749  encryptionEngine->cipherAlgo = NULL;
750  encryptionEngine->encKeyLen = 64;
751  }
752  else
753 #endif
754  //Unknown encryption algorithm?
755  {
756  //Report an error
758  }
759 
760  //Return status code
761  return error;
762 }
763 
764 
765 /**
766  * @brief Select the relevant hash algorithm
767  * @param[in] encryptionEngine Pointer to the encryption/decryption engine to
768  * be initialized
769  * @param[in] encAlgo Encryption algorithm name
770  * @param[in] macAlgo Integrity algorithm name
771  * @return Error code
772  **/
773 
775  const char_t *encAlgo, const char_t *macAlgo)
776 {
777  error_t error;
778 
779  //Initialize status code
780  error = NO_ERROR;
781 
782 #if (SSH_AES_128_SUPPORT == ENABLED && SSH_GCM_CIPHER_SUPPORT == ENABLED)
783  //AES-GCM with 128-bit key authenticated encryption algorithm?
784  if(sshCompareAlgo(encAlgo, "aes128-gcm@openssh.com"))
785  {
786  //AEAD algorithms offer both encryption and authentication
787  encryptionEngine->hashAlgo = NULL;
788  encryptionEngine->macSize = 16;
789  encryptionEngine->etm = FALSE;
790  }
791  else
792 #endif
793 #if (SSH_AES_256_SUPPORT == ENABLED && SSH_GCM_CIPHER_SUPPORT == ENABLED)
794  //AES-GCM with 256-bit key authenticated encryption algorithm?
795  if(sshCompareAlgo(encAlgo, "aes256-gcm@openssh.com"))
796  {
797  //AEAD algorithms offer both encryption and authentication
798  encryptionEngine->hashAlgo = NULL;
799  encryptionEngine->macSize = 16;
800  encryptionEngine->etm = FALSE;
801  }
802  else
803 #endif
804 #if (SSH_AES_128_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
805  //AES-GCM with 128-bit key authenticated encryption algorithm?
806  if(sshCompareAlgo(encAlgo, "AEAD_AES_128_GCM"))
807  {
808  //AEAD algorithms offer both encryption and authentication
809  encryptionEngine->hashAlgo = NULL;
810  encryptionEngine->macSize = 16;
811  encryptionEngine->etm = FALSE;
812  }
813  else
814 #endif
815 #if (SSH_AES_256_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
816  //AES-GCM with 256-bit key authenticated encryption algorithm?
817  if(sshCompareAlgo(encAlgo, "AEAD_AES_256_GCM"))
818  {
819  //AEAD algorithms offer both encryption and authentication
820  encryptionEngine->hashAlgo = NULL;
821  encryptionEngine->macSize = 16;
822  encryptionEngine->etm = FALSE;
823  }
824  else
825 #endif
826 #if (SSH_CAMELLIA_128_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
827  //Camellia-GCM with 128-bit key authenticated encryption algorithm?
828  if(sshCompareAlgo(encAlgo, "AEAD_CAMELLIA_128_GCM"))
829  {
830  //AEAD algorithms offer both encryption and authentication
831  encryptionEngine->hashAlgo = NULL;
832  encryptionEngine->macSize = 16;
833  encryptionEngine->etm = FALSE;
834  }
835  else
836 #endif
837 #if (SSH_CAMELLIA_256_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
838  //Camellia-GCM with 256-bit key authenticated encryption algorithm?
839  if(sshCompareAlgo(encAlgo, "AEAD_CAMELLIA_256_GCM"))
840  {
841  //AEAD algorithms offer both encryption and authentication
842  encryptionEngine->hashAlgo = NULL;
843  encryptionEngine->macSize = 16;
844  encryptionEngine->etm = FALSE;
845  }
846  else
847 #endif
848 #if (SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
849  //ChaCha20Poly1305 authenticated encryption algorithm?
850  if(sshCompareAlgo(encAlgo, "chacha20-poly1305@openssh.com"))
851  {
852  //AEAD algorithms offer both encryption and authentication
853  encryptionEngine->hashAlgo = NULL;
854  encryptionEngine->macSize = 16;
855  encryptionEngine->etm = FALSE;
856  }
857  else
858 #endif
859 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_MD5_SUPPORT == ENABLED)
860  //HMAC with MD5 integrity algorithm?
861  if(sshCompareAlgo(macAlgo, "hmac-md5"))
862  {
863  //Select MAC-then-encrypt mode
864  encryptionEngine->hashAlgo = MD5_HASH_ALGO;
865  encryptionEngine->macSize = MD5_DIGEST_SIZE;
866  encryptionEngine->etm = FALSE;
867  }
868  else
869 #endif
870 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_MD5_SUPPORT == ENABLED && \
871  SSH_ETM_SUPPORT == ENABLED)
872  //HMAC with MD5 integrity algorithm (EtM mode)?
873  if(sshCompareAlgo(macAlgo, "hmac-md5-etm@openssh.com"))
874  {
875  //Select encrypt-then-MAC mode
876  encryptionEngine->hashAlgo = MD5_HASH_ALGO;
877  encryptionEngine->macSize = MD5_DIGEST_SIZE;
878  encryptionEngine->etm = TRUE;
879  }
880  else
881 #endif
882 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_MD5_96_SUPPORT == ENABLED)
883  //HMAC with MD5/96 integrity algorithm?
884  if(sshCompareAlgo(macAlgo, "hmac-md5-96"))
885  {
886  //Select MAC-then-encrypt mode
887  encryptionEngine->hashAlgo = MD5_HASH_ALGO;
888  encryptionEngine->macSize = 12;
889  encryptionEngine->etm = FALSE;
890  }
891  else
892 #endif
893 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_MD5_96_SUPPORT == ENABLED && \
894  SSH_ETM_SUPPORT == ENABLED)
895  //HMAC with MD5/96 integrity algorithm (EtM mode)?
896  if(sshCompareAlgo(macAlgo, "hmac-md5-96-etm@openssh.com"))
897  {
898  //Select encrypt-then-MAC mode
899  encryptionEngine->hashAlgo = MD5_HASH_ALGO;
900  encryptionEngine->macSize = 12;
901  encryptionEngine->etm = TRUE;
902  }
903  else
904 #endif
905 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_RIPEMD160_SUPPORT == ENABLED)
906  //HMAC with RIPEMD-160 integrity algorithm?
907  if(sshCompareAlgo(macAlgo, "hmac-ripemd160") ||
908  sshCompareAlgo(macAlgo, "hmac-ripemd160@openssh.com"))
909  {
910  //Select MAC-then-encrypt mode
911  encryptionEngine->hashAlgo = RIPEMD160_HASH_ALGO;
912  encryptionEngine->macSize = RIPEMD160_DIGEST_SIZE;
913  encryptionEngine->etm = FALSE;
914  }
915  else
916 #endif
917 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_RIPEMD160_SUPPORT == ENABLED && \
918  SSH_ETM_SUPPORT == ENABLED)
919  //HMAC with RIPEMD-160 integrity algorithm (EtM mode)?
920  if(sshCompareAlgo(macAlgo, "hmac-ripemd160-etm@openssh.com"))
921  {
922  //Select encrypt-then-MAC mode
923  encryptionEngine->hashAlgo = RIPEMD160_HASH_ALGO;
924  encryptionEngine->macSize = RIPEMD160_DIGEST_SIZE;
925  encryptionEngine->etm = TRUE;
926  }
927  else
928 #endif
929 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA1_SUPPORT == ENABLED)
930  //HMAC with SHA-1 integrity algorithm?
931  if(sshCompareAlgo(macAlgo, "hmac-sha1"))
932  {
933  //Select MAC-then-encrypt mode
934  encryptionEngine->hashAlgo = SHA1_HASH_ALGO;
935  encryptionEngine->macSize = SHA1_DIGEST_SIZE;
936  encryptionEngine->etm = FALSE;
937  }
938  else
939 #endif
940 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA1_SUPPORT == ENABLED && \
941  SSH_ETM_SUPPORT == ENABLED)
942  //HMAC with SHA-1 integrity algorithm (EtM mode)?
943  if(sshCompareAlgo(macAlgo, "hmac-sha1-etm@openssh.com"))
944  {
945  //Select encrypt-then-MAC mode
946  encryptionEngine->hashAlgo = SHA1_HASH_ALGO;
947  encryptionEngine->macSize = SHA1_DIGEST_SIZE;
948  encryptionEngine->etm = TRUE;
949  }
950  else
951 #endif
952 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA1_96_SUPPORT == ENABLED)
953  //HMAC with SHA-1/96 integrity algorithm?
954  if(sshCompareAlgo(macAlgo, "hmac-sha1-96"))
955  {
956  //Select MAC-then-encrypt mode
957  encryptionEngine->hashAlgo = SHA1_HASH_ALGO;
958  encryptionEngine->macSize = 12;
959  encryptionEngine->etm = FALSE;
960  }
961  else
962 #endif
963 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA1_96_SUPPORT == ENABLED && \
964  SSH_ETM_SUPPORT == ENABLED)
965  //HMAC with SHA-1/96 integrity algorithm (EtM mode)?
966  if(sshCompareAlgo(macAlgo, "hmac-sha1-96-etm@openssh.com"))
967  {
968  //Select encrypt-then-MAC mode
969  encryptionEngine->hashAlgo = SHA1_HASH_ALGO;
970  encryptionEngine->macSize = 12;
971  encryptionEngine->etm = TRUE;
972  }
973  else
974 #endif
975 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED)
976  //HMAC with SHA-256 integrity algorithm?
977  if(sshCompareAlgo(macAlgo, "hmac-sha2-256"))
978  {
979  //Select MAC-then-encrypt mode
980  encryptionEngine->hashAlgo = SHA256_HASH_ALGO;
981  encryptionEngine->macSize = SHA256_DIGEST_SIZE;
982  encryptionEngine->etm = FALSE;
983  }
984  else
985 #endif
986 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED && \
987  SSH_ETM_SUPPORT == ENABLED)
988  //HMAC with SHA-256 integrity algorithm (EtM mode)?
989  if(sshCompareAlgo(macAlgo, "hmac-sha2-256-etm@openssh.com"))
990  {
991  //Select encrypt-then-MAC mode
992  encryptionEngine->hashAlgo = SHA256_HASH_ALGO;
993  encryptionEngine->macSize = SHA256_DIGEST_SIZE;
994  encryptionEngine->etm = TRUE;
995  }
996  else
997 #endif
998 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED)
999  //HMAC with SHA-512 integrity algorithm?
1000  if(sshCompareAlgo(macAlgo, "hmac-sha2-512"))
1001  {
1002  //Select MAC-then-encrypt mode
1003  encryptionEngine->hashAlgo = SHA512_HASH_ALGO;
1004  encryptionEngine->macSize = SHA512_DIGEST_SIZE;
1005  encryptionEngine->etm = FALSE;
1006  }
1007  else
1008 #endif
1009 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED && \
1010  SSH_ETM_SUPPORT == ENABLED)
1011  //HMAC with SHA-512 integrity algorithm (EtM mode)?
1012  if(sshCompareAlgo(macAlgo, "hmac-sha2-512-etm@openssh.com"))
1013  {
1014  //Select encrypt-then-MAC mode
1015  encryptionEngine->hashAlgo = SHA512_HASH_ALGO;
1016  encryptionEngine->macSize = SHA512_DIGEST_SIZE;
1017  encryptionEngine->etm = TRUE;
1018  }
1019  else
1020 #endif
1021  //Unknown integrity algorithm?
1022  {
1023  //Report an error
1025  }
1026 
1027  //Return status code
1028  return error;
1029 }
1030 
1031 
1032 /**
1033  * @brief Key derivation function
1034  * @param[in] connection Pointer to the SSH connection
1035  * @param[in] x A single character
1036  * @param[out] output Pointer to the output
1037  * @param[in] outputLen Desired output length
1038  * @return Error code
1039  **/
1040 
1041 error_t sshDeriveKey(SshConnection *connection, uint8_t x, uint8_t *output,
1042  size_t outputLen)
1043 {
1044  error_t error;
1045  size_t i;
1046  size_t n;
1047  const HashAlgo *hashAlgo;
1048  HashContext *hashContext;
1049 
1050  //Each key exchange method specifies a hash function that is used in the key
1051  //exchange. The same hash algorithm must be used in key derivation (refer to
1052  //RFC 4253, section 7.2)
1053  hashAlgo = connection->hashAlgo;
1054 
1055  //Make sure the hash algorithm is valid
1056  if(hashAlgo != NULL)
1057  {
1058  //Allocate a memory buffer to hold the hash context
1059  hashContext = sshAllocMem(hashAlgo->contextSize);
1060 
1061  //Successful memory allocation?
1062  if(hashContext != NULL)
1063  {
1064  //Compute K(1) = HASH(K || H || X || session_id)
1065  hashAlgo->init(hashContext);
1066  hashAlgo->update(hashContext, connection->k, connection->kLen);
1067  hashAlgo->update(hashContext, connection->h, connection->hLen);
1068  hashAlgo->update(hashContext, &x, sizeof(x));
1069  hashAlgo->update(hashContext, connection->sessionId, connection->sessionIdLen);
1070  hashAlgo->final(hashContext, NULL);
1071 
1072  //Key data must be taken from the beginning of the hash output
1073  for(n = 0; n < hashAlgo->digestSize && n < outputLen; n++)
1074  {
1075  output[n] = hashContext->digest[n];
1076  }
1077 
1078  //If the key length needed is longer than the output of the HASH, the key
1079  //is extended by computing HASH of the concatenation of K and H and the
1080  //entire key so far, and appending the resulting bytes to the key
1081  while(n < outputLen)
1082  {
1083  //Compute K(n + 1) = HASH(K || H || K(1) || ... || K(n))
1084  hashAlgo->init(hashContext);
1085  hashAlgo->update(hashContext, connection->k, connection->kLen);
1086  hashAlgo->update(hashContext, connection->h, connection->hLen);
1087  hashAlgo->update(hashContext, output, n);
1088  hashAlgo->final(hashContext, NULL);
1089 
1090  //This process is repeated until enough key material is available
1091  for(i = 0; i < hashAlgo->digestSize && n < outputLen; i++, n++)
1092  {
1093  output[n] = hashContext->digest[i];
1094  }
1095  }
1096 
1097  //Release hash context
1098  sshFreeMem(hashContext);
1099 
1100  //Successful processing
1101  error = NO_ERROR;
1102  }
1103  else
1104  {
1105  //Failed to allocate memory
1106  error = ERROR_OUT_OF_MEMORY;
1107  }
1108  }
1109  else
1110  {
1111  //The hash algorithm is not valid
1112  error = ERROR_FAILURE;
1113  }
1114 
1115  //Return status code
1116  return error;
1117 }
1118 
1119 
1120 /**
1121  * @brief Dump secret key (for debugging purpose only)
1122  * @param[in] connection Pointer to the SSH connection
1123  * @param[in] label Identifying label (NULL-terminated string)
1124  * @param[in] key Pointer to the secret key
1125  * @param[in] keyLen Length of the secret key, in bytes
1126  **/
1127 
1128 void sshDumpKey(SshConnection *connection, const char_t *label,
1129  const uint8_t *key, size_t keyLen)
1130 {
1131 #if (SSH_KEY_LOG_SUPPORT == ENABLED)
1132  SshContext *context;
1133 
1134  //Point to the SSH context
1135  context = connection->context;
1136 
1137  //Any registered callback?
1138  if(context->keyLogCallback != NULL)
1139  {
1140  size_t i;
1141  size_t n;
1142  char_t *buffer;
1143 
1144  //Allocate a buffer to hold the formatted string
1145  buffer = sshAllocMem(2 * SSH_COOKIE_SIZE + 2 * keyLen +
1146  osStrlen(label) + 3);
1147 
1148  //Successful memory allocation?
1149  if(buffer != NULL)
1150  {
1151  //Convert the cookie to a hex string
1152  for(i = 0, n = 0; i < SSH_COOKIE_SIZE; i++)
1153  {
1154  //Format current byte
1155  n += osSprintf(buffer + n, "%02" PRIX8, connection->cookie[i]);
1156  }
1157 
1158  //The middle part is a static label indicating the type of key material
1159  //that follows
1160  n += osSprintf(buffer + n, " %s ", label);
1161 
1162  //Convert the shared secret to a hex string
1163  for(i = 0; i < keyLen; i++)
1164  {
1165  //Format current byte
1166  n += osSprintf(buffer + n, "%02" PRIX8, key[i]);
1167  }
1168 
1169  //Properly terminate the string with a NULL character
1170  buffer[n] = '\0';
1171 
1172  //Invoke user callback function
1173  context->keyLogCallback(connection, buffer);
1174 
1175  //Release previously allocated memory
1176  sshFreeMem(buffer);
1177  }
1178  }
1179 #endif
1180 }
1181 
1182 #endif
#define AES_CIPHER_ALGO
Definition: aes.h:45
#define BLOWFISH_CIPHER_ALGO
Definition: blowfish.h:40
#define CAMELLIA_CIPHER_ALGO
Definition: camellia.h:40
#define CAST128_CIPHER_ALGO
Definition: cast128.h:40
char char_t
Definition: compiler_port.h:48
@ CIPHER_MODE_CHACHA20_POLY1305
Definition: crypto.h:951
@ CIPHER_MODE_CBC
Definition: crypto.h:945
@ CIPHER_MODE_STREAM
Definition: crypto.h:943
@ CIPHER_MODE_CTR
Definition: crypto.h:948
@ CIPHER_MODE_GCM
Definition: crypto.h:950
@ CIPHER_MODE_NULL
Definition: crypto.h:942
Debugging facilities.
#define DES3_CIPHER_ALGO
Definition: des3.h:46
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ ERROR_UNSUPPORTED_CIPHER_ALGO
Definition: error.h:129
@ ERROR_UNSUPPORTED_HASH_ALGO
Definition: error.h:130
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ ERROR_UNSUPPORTED_CIPHER_MODE
Definition: error.h:128
__weak_func error_t gcmInit(GcmContext *context, const CipherAlgo *cipherAlgo, void *cipherContext)
Initialize GCM context.
Definition: gcm.c:99
#define IDEA_CIPHER_ALGO
Definition: idea.h:40
uint8_t x
Definition: lldp_ext_med.h:211
#define MD5_DIGEST_SIZE
Definition: md5.h:45
#define MD5_HASH_ALGO
Definition: md5.h:49
#define osMemset(p, value, length)
Definition: os_port.h:135
#define osStrlen(s)
Definition: os_port.h:165
#define osSprintf(dest,...)
Definition: os_port.h:231
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
#define RC4_CIPHER_ALGO
Definition: rc4.h:38
#define RIPEMD160_DIGEST_SIZE
Definition: ripemd160.h:40
#define RIPEMD160_HASH_ALGO
Definition: ripemd160.h:44
#define SEED_CIPHER_ALGO
Definition: seed.h:40
#define SERPENT_CIPHER_ALGO
Definition: serpent.h:40
#define SHA1_HASH_ALGO
Definition: sha1.h:49
#define SHA1_DIGEST_SIZE
Definition: sha1.h:45
#define SHA256_DIGEST_SIZE
Definition: sha256.h:45
#define SHA256_HASH_ALGO
Definition: sha256.h:49
#define SHA512_HASH_ALGO
Definition: sha512.h:49
#define SHA512_DIGEST_SIZE
Definition: sha512.h:45
Secure Shell (SSH)
#define SSH_MAX_ENC_KEY_SIZE
Definition: ssh.h:752
#define SSH_MAX_HASH_DIGEST_SIZE
Definition: ssh.h:796
#define sshFreeMem(p)
Definition: ssh.h:736
#define SSH_COOKIE_SIZE
Definition: ssh.h:868
#define sshAllocMem(size)
Definition: ssh.h:731
#define SshConnection
Definition: ssh.h:883
#define SshContext
Definition: ssh.h:879
#define SSH_MAX_CIPHER_BLOCK_SIZE
Definition: ssh.h:759
void sshDumpKey(SshConnection *connection, const char_t *label, const uint8_t *key, size_t keyLen)
Dump secret key (for debugging purpose only)
error_t sshInitEncryptionEngine(SshConnection *connection, SshEncryptionEngine *encryptionEngine, const char_t *encAlgo, const char_t *macAlgo, uint8_t x)
Initialize encryption engine.
error_t sshSelectHashAlgo(SshEncryptionEngine *encryptionEngine, const char_t *encAlgo, const char_t *macAlgo)
Select the relevant hash algorithm.
void sshFreeEncryptionEngine(SshEncryptionEngine *encryptionEngine)
Release encryption engine.
error_t sshDeriveKey(SshConnection *connection, uint8_t x, uint8_t *output, size_t outputLen)
Key derivation function.
error_t sshSelectCipherAlgo(SshEncryptionEngine *encryptionEngine, const char_t *encAlgo)
Select the relevant cipher algorithm.
Key material generation.
bool_t sshCompareAlgo(const char_t *name1, const char_t *name2)
Compare algorithm names.
Definition: ssh_misc.c:1653
SSH helper functions.
CipherAlgoDeinit deinit
Definition: crypto.h:1046
size_t blockSize
Definition: crypto.h:1040
CipherAlgoInit init
Definition: crypto.h:1041
CipherAlgoEncryptStream encryptStream
Definition: crypto.h:1042
GCM context.
Definition: gcm.h:64
Common interface for hash algorithms.
Definition: crypto.h:1014
HashAlgoFinal final
Definition: crypto.h:1026
size_t contextSize
Definition: crypto.h:1018
HashAlgoUpdate update
Definition: crypto.h:1025
size_t digestSize
Definition: crypto.h:1020
HashAlgoInit init
Definition: crypto.h:1024
Encryption engine.
Definition: ssh.h:1325
CipherMode cipherMode
Cipher mode of operation.
Definition: ssh.h:1326
size_t macSize
Size of the MAC tag, in bytes.
Definition: ssh.h:1331
uint8_t iv[SSH_MAX_CIPHER_BLOCK_SIZE]
Initialization vector.
Definition: ssh.h:1333
HmacContext * hmacContext
HMAC context.
Definition: ssh.h:1330
const HashAlgo * hashAlgo
Hash algorithm for MAC operations.
Definition: ssh.h:1329
const CipherAlgo * cipherAlgo
Cipher algorithm.
Definition: ssh.h:1327
CipherContext cipherContext
Cipher context.
Definition: ssh.h:1328
bool_t etm
Encrypt-then-MAC.
Definition: ssh.h:1332
uint8_t encKey[SSH_MAX_ENC_KEY_SIZE]
Encryption key.
Definition: ssh.h:1334
GcmContext gcmContext
GCM context.
Definition: ssh.h:1339
size_t encKeyLen
Length of the encryption key, in bytes.
Definition: ssh.h:1335
uint8_t macKey[SSH_MAX_HASH_DIGEST_SIZE]
Integrity key.
Definition: ssh.h:1336
#define TWOFISH_CIPHER_ALGO
Definition: twofish.h:40
Generic hash algorithm context.
uint8_t digest[MAX_HASH_DIGEST_SIZE]