Răsfoiți Sursa

Add support for more types of encrypted PEM files

1. ChaCha20, two-key 3DES and DES-X encrypted OpenSSL PEM files

2. AES-GCM and Chacha20+Poly1305 encrypted SSH keys

* OpenSSH uses a slightly different algorithm for its
  `[email protected]` than defined in the RFC.
  Therefore add an `openssh_compat` flag to
  `chacha20poly1305_state`.
* Add the option to give a 16byte IV and no counter, when calling
  `chacha20poly1305_memory()`
* Add support for DES-X

Signed-off-by: Steffen Jaeckel <[email protected]>
Steffen Jaeckel 1 an în urmă
părinte
comite
c0be0aa0bf
51 a modificat fișierele cu 638 adăugiri și 208 ștergeri
  1. 24 8
      demos/pem-info.c
  2. 97 79
      doc/crypt.tex
  3. 54 0
      notes/cipher_tv.txt
  4. 19 0
      notes/eax_tv.txt
  5. 19 0
      notes/ocb_tv.txt
  6. 19 0
      notes/omac_tv.txt
  7. 19 0
      notes/pmac_tv.txt
  8. 156 7
      src/ciphers/des.c
  9. 8 6
      src/encauth/chachapoly/chacha20poly1305_done.c
  10. 1 0
      src/encauth/chachapoly/chacha20poly1305_init.c
  11. 4 0
      src/encauth/chachapoly/chacha20poly1305_memory.c
  12. 13 1
      src/headers/tomcrypt_cipher.h
  13. 4 3
      src/headers/tomcrypt_mac.h
  14. 14 1
      src/headers/tomcrypt_private.h
  15. 2 0
      src/misc/crypt/crypt.c
  16. 1 0
      src/misc/crypt/crypt_register_all_ciphers.c
  17. 107 54
      src/misc/pem/pem.c
  18. 2 6
      src/misc/pem/pem_pkcs.c
  19. 57 38
      src/misc/pem/pem_ssh.c
  20. 15 5
      src/stream/chacha/chacha_memory.c
  21. 0 0
      tests/pem/pkcs/rsa-chacha20.pem
  22. 0 0
      tests/pem/pkcs/rsa-des-ede-cbc.pem
  23. 0 0
      tests/pem/pkcs/rsa-des-ede-cfb.pem
  24. 0 0
      tests/pem/pkcs/rsa-des-ede-ofb.pem
  25. 0 0
      tests/pem/pkcs/rsa-desx-cbc.pem
  26. 0 0
      tests/pem/pubkeys/authorized_keys/ssh_dsa_1024_openssh.pub
  27. 0 0
      tests/pem/pubkeys/authorized_keys/ssh_ecdsa_256_openssh.pub
  28. 0 0
      tests/pem/pubkeys/authorized_keys/ssh_ecdsa_384_openssh.pub
  29. 0 0
      tests/pem/pubkeys/authorized_keys/ssh_ecdsa_521_openssh.pub
  30. 0 0
      tests/pem/pubkeys/authorized_keys/ssh_ed25519_openssh.pub
  31. 0 0
      tests/pem/pubkeys/authorized_keys/ssh_rsa_1024_openssh.pub
  32. 0 0
      tests/pem/pubkeys/authorized_keys/ssh_rsa_1536_openssh.pub
  33. 0 0
      tests/pem/pubkeys/authorized_keys/ssh_rsa_2048_openssh.pub
  34. 0 0
      tests/pem/pubkeys/authorized_keys/ssh_rsa_4096_openssh.pub
  35. 0 0
      tests/pem/pubkeys/authorized_keys/ssh_rsa_768_openssh.pub
  36. 0 0
      tests/pem/pubkeys/authorized_keys/ssh_rsa_8192_openssh.pub
  37. 0 0
      tests/pem/ssh/authorized_keys/ssh-rsa-3des-cbc.pub
  38. 0 0
      tests/pem/ssh/authorized_keys/ssh-rsa-aes128-cbc.pub
  39. 0 0
      tests/pem/ssh/authorized_keys/ssh-rsa-aes128-ctr.pub
  40. 0 0
      tests/pem/ssh/authorized_keys/ssh-rsa-aes128-gcm.pub
  41. 0 0
      tests/pem/ssh/authorized_keys/ssh-rsa-aes192-cbc.pub
  42. 0 0
      tests/pem/ssh/authorized_keys/ssh-rsa-aes192-ctr.pub
  43. 0 0
      tests/pem/ssh/authorized_keys/ssh-rsa-aes256-cbc.pub
  44. 0 0
      tests/pem/ssh/authorized_keys/ssh-rsa-aes256-ctr.pub
  45. 0 0
      tests/pem/ssh/authorized_keys/ssh-rsa-aes256-gcm.pub
  46. 0 0
      tests/pem/ssh/authorized_keys/ssh-rsa-chacha20-poly1305.pub
  47. 0 0
      tests/pem/ssh/ssh-rsa-aes128-gcm
  48. 0 0
      tests/pem/ssh/ssh-rsa-aes256-gcm
  49. 0 0
      tests/pem/ssh/ssh-rsa-chacha20-poly1305
  50. 2 0
      tests/pem_test.c
  51. 1 0
      tests/test.c

+ 24 - 8
demos/pem-info.c

@@ -16,10 +16,13 @@ static const struct {
    { "", "none" },
    { "", "none" },
    { "aes", "AES" },
    { "aes", "AES" },
    { "blowfish", "Blowfish" },
    { "blowfish", "Blowfish" },
+   { "c20p1305", "ChaCha20Poly1305" },
    { "camellia", "Camellia" },
    { "camellia", "Camellia" },
    { "cast5", "CAST5" },
    { "cast5", "CAST5" },
+   { "chacha20", "ChaCha20" },
    { "3des", "3DES (EDE)" },
    { "3des", "3DES (EDE)" },
    { "des", "DES" },
    { "des", "DES" },
+   { "desx", "DES-X" },
    { "idea", "IDEA" },
    { "idea", "IDEA" },
    { "rc5", "RC5" },
    { "rc5", "RC5" },
    { "rc2", "RC2" },
    { "rc2", "RC2" },
@@ -39,14 +42,27 @@ static const char *s_map_cipher(const char *name)
    exit(1);
    exit(1);
 }
 }
 
 
-static const char *cipher_mode_map[] = {
-   "none", "CBC", "CFB", "CTR", "OFB", "STREAM", "GCM"
+static const struct {
+   enum cipher_mode mode;
+   const char *name;
+} cipher_mode_map[] = {
+   { cm_none,   "none",   },
+   { cm_cbc,    "CBC",    },
+   { cm_cfb,    "CFB",    },
+   { cm_ctr,    "CTR",    },
+   { cm_ofb,    "OFB",    },
+   { cm_stream, "STREAM", },
+   { cm_gcm,    "GCM",    },
 };
 };
 
 
 static const char *s_map_mode(enum cipher_mode mode)
 static const char *s_map_mode(enum cipher_mode mode)
 {
 {
-   if (mode >= 0 && mode <= sizeof(cipher_mode_map)/sizeof(cipher_mode_map[0]))
-      return cipher_mode_map[mode];
+   size_t n;
+   mode &= cm_modes;
+   for (n = 0; n < sizeof(cipher_mode_map)/sizeof(cipher_mode_map[0]); ++n) {
+      if (cipher_mode_map[n].mode == mode)
+         return cipher_mode_map[n].name;
+   }
    fprintf(stderr, "Error: Can't map cipher_mode %d\n", mode);
    fprintf(stderr, "Error: Can't map cipher_mode %d\n", mode);
    exit(1);
    exit(1);
 }
 }
@@ -56,11 +72,11 @@ int main(void)
    unsigned long n;
    unsigned long n;
    printf("PEM ciphers:\n\n");
    printf("PEM ciphers:\n\n");
    for (n = 0; n < pem_dek_infos_num; ++n) {
    for (n = 0; n < pem_dek_infos_num; ++n) {
-      char nbuf[20] = {0};
+      char nbuf[32] = {0};
       size_t nlen = strlen(pem_dek_infos[n].name);
       size_t nlen = strlen(pem_dek_infos[n].name);
       memcpy(nbuf, pem_dek_infos[n].name, nlen);
       memcpy(nbuf, pem_dek_infos[n].name, nlen);
       nbuf[nlen-1] = '}';
       nbuf[nlen-1] = '}';
-      printf("\\hline \\texttt{%-18s & %-15s & %-25ld & %s \\\\\n",
+      printf("\\hline \\texttt{%-18s & %-15s & %-25ld & %-6s \\\\\n",
                                nbuf, s_map_cipher(pem_dek_infos[n].algo),
                                nbuf, s_map_cipher(pem_dek_infos[n].algo),
                                               pem_dek_infos[n].keylen * 8,
                                               pem_dek_infos[n].keylen * 8,
                                                        s_map_mode(pem_dek_infos[n].mode));
                                                        s_map_mode(pem_dek_infos[n].mode));
@@ -68,11 +84,11 @@ int main(void)
 
 
    printf("\nSSH ciphers:\n\n");
    printf("\nSSH ciphers:\n\n");
    for (n = 0; n < ssh_ciphers_num; ++n) {
    for (n = 0; n < ssh_ciphers_num; ++n) {
-      char nbuf[20] = {0};
+      char nbuf[32] = {0};
       size_t nlen = strlen(ssh_ciphers[n].name);
       size_t nlen = strlen(ssh_ciphers[n].name);
       memcpy(nbuf, ssh_ciphers[n].name, nlen);
       memcpy(nbuf, ssh_ciphers[n].name, nlen);
       nbuf[nlen] = '}';
       nbuf[nlen] = '}';
-      printf("\\hline \\texttt{%-18s & %-15s & %-25ld & %-4s \\\\\n",
+      printf("\\hline \\texttt{%-30s & %-16s & %-24ld & %-6s \\\\\n",
                                nbuf, s_map_cipher(ssh_ciphers[n].algo),
                                nbuf, s_map_cipher(ssh_ciphers[n].algo),
                                ssh_ciphers[n].keylen * 8,
                                ssh_ciphers[n].keylen * 8,
                                                        s_map_mode(ssh_ciphers[n].mode));
                                                        s_map_mode(ssh_ciphers[n].mode));

+ 97 - 79
doc/crypt.tex

@@ -2422,9 +2422,15 @@ int main(void)
 \end{small}
 \end{small}
 
 
 \mysection{ChaCha20--Poly1305}
 \mysection{ChaCha20--Poly1305}
+\label{chacha20poly1305}
 
 
-This authenticated encryption is based on ChaCha20 stream cipher and Poly1305 authenticator.
-It is defined by \url{https://tools.ietf.org/html/rfc7539}.
+This authenticated encryption is based on the ChaCha20 stream cipher and Poly1305 authenticator.
+It is defined by \url{https://tools.ietf.org/html/rfc8439}.
+
+IMPORTANT NOTICE: The Chacha20--Poly1305 implementation of LibTomCrypt is compliant to \textbf{RFC8439}, which differs slightly
+to what OpenSSH defined as \textbf{[email protected]}. The OpenSSH compatibility mode can be enabled
+by setting the \textit{openssh\_compat} element of \textit{chacha20poly1305\_state} to \textit{1},
+after calling \textit{chacha20poly1305\_init()}.
 
 
 \subsection{Initialization}
 \subsection{Initialization}
 To initialize the ChaCha20--Poly1305 context with a secret key call the following function.
 To initialize the ChaCha20--Poly1305 context with a secret key call the following function.
@@ -2529,9 +2535,13 @@ encrypt (\textit{direction} equals \textbf{CHACHA20POLY1305\_ENCRYPT}) or decryp
 \textbf{CHACHA20POLY1305\_DECRYPT}) the message text and store the final message tag. The definition of the
 \textbf{CHACHA20POLY1305\_DECRYPT}) the message text and store the final message tag. The definition of the
 variables is the same as it is for all the manual functions.
 variables is the same as it is for all the manual functions.
 
 
-IMPORTANT NOTICE: for \textit{direction == CHACHA20POLY1305\_DECRYPT} the caller has to fill \textit{tag} and \textit{taglen} with expected
+IMPORTANT NOTICE 1: for \textit{direction == CHACHA20POLY1305\_DECRYPT} the caller has to fill \textit{tag} and \textit{taglen} with expected
 tag value. The \textit{chacha20poly1305\_memory} in decrypt mode validates the \textit{tag} value and returns \textit{CRYPT\_ERROR} on mismatch.
 tag value. The \textit{chacha20poly1305\_memory} in decrypt mode validates the \textit{tag} value and returns \textit{CRYPT\_ERROR} on mismatch.
 
 
+IMPORTANT NOTICE 2: As mentioned in \ref{chacha20poly1305} there exists a discrepancy between the RFC and OpenSSH versions of the algorithm.
+In order to enable OpenSSH compatibility, the flag \textit{CHACHA20POLY1305\_OPENSSH\_COMPAT} has to be \textbf{OR}'ed into
+the \textit{direction} parameter.
+
 \chapter{One-Way Cryptographic Hash Functions}
 \chapter{One-Way Cryptographic Hash Functions}
 \mysection{Core Functions}
 \mysection{Core Functions}
 Like the ciphers, there are hash core functions and a universal data type to hold the hash state called \textit{hash\_state}.  To initialize hash
 Like the ciphers, there are hash core functions and a universal data type to hold the hash state called \textit{hash\_state}.  To initialize hash
@@ -7563,56 +7573,61 @@ When dealing with PEM formatted private keys the following encryption algorithms
 \begin{small}
 \begin{small}
 \begin{tabular}{|l|l|l|l|}
 \begin{tabular}{|l|l|l|l|}
 \hline \textbf{Identifier}        & \textbf{Cipher} & \textbf{Key size in bits} & \textbf{Mode} \\
 \hline \textbf{Identifier}        & \textbf{Cipher} & \textbf{Key size in bits} & \textbf{Mode} \\
-\hline \texttt{AES-128-CBC}       & AES             & 128                       & CBC \\
-\hline \texttt{AES-192-CBC}       & AES             & 192                       & CBC \\
-\hline \texttt{AES-256-CBC}       & AES             & 256                       & CBC \\
-\hline \texttt{AES-128-CFB}       & AES             & 128                       & CFB \\
-\hline \texttt{AES-192-CFB}       & AES             & 192                       & CFB \\
-\hline \texttt{AES-256-CFB}       & AES             & 256                       & CFB \\
-\hline \texttt{AES-128-CTR}       & AES             & 128                       & CTR \\
-\hline \texttt{AES-192-CTR}       & AES             & 192                       & CTR \\
-\hline \texttt{AES-256-CTR}       & AES             & 256                       & CTR \\
-\hline \texttt{AES-128-OFB}       & AES             & 128                       & OFB \\
-\hline \texttt{AES-192-OFB}       & AES             & 192                       & OFB \\
-\hline \texttt{AES-256-OFB}       & AES             & 256                       & OFB \\
-\hline \texttt{BF-CBC}            & Blowfish        & 128                       & CBC \\
-\hline \texttt{BF-CFB}            & Blowfish        & 128                       & CFB \\
-\hline \texttt{BF-OFB}            & Blowfish        & 128                       & OFB \\
-\hline \texttt{CAMELLIA-128-CBC}  & Camellia        & 128                       & CBC \\
-\hline \texttt{CAMELLIA-192-CBC}  & Camellia        & 192                       & CBC \\
-\hline \texttt{CAMELLIA-256-CBC}  & Camellia        & 256                       & CBC \\
-\hline \texttt{CAMELLIA-128-CFB}  & Camellia        & 128                       & CFB \\
-\hline \texttt{CAMELLIA-192-CFB}  & Camellia        & 192                       & CFB \\
-\hline \texttt{CAMELLIA-256-CFB}  & Camellia        & 256                       & CFB \\
-\hline \texttt{CAMELLIA-128-CTR}  & Camellia        & 128                       & CTR \\
-\hline \texttt{CAMELLIA-192-CTR}  & Camellia        & 192                       & CTR \\
-\hline \texttt{CAMELLIA-256-CTR}  & Camellia        & 256                       & CTR \\
-\hline \texttt{CAMELLIA-128-OFB}  & Camellia        & 128                       & OFB \\
-\hline \texttt{CAMELLIA-192-OFB}  & Camellia        & 192                       & OFB \\
-\hline \texttt{CAMELLIA-256-OFB}  & Camellia        & 256                       & OFB \\
-\hline \texttt{CAST5-CBC}         & CAST5           & 128                       & CBC \\
-\hline \texttt{CAST5-CFB}         & CAST5           & 128                       & CFB \\
-\hline \texttt{CAST5-OFB}         & CAST5           & 128                       & OFB \\
-\hline \texttt{DES-EDE3-CBC}      & 3DES (EDE)      & 192                       & CBC \\
-\hline \texttt{DES-EDE3-CFB}      & 3DES (EDE)      & 192                       & CFB \\
-\hline \texttt{DES-EDE3-OFB}      & 3DES (EDE)      & 192                       & OFB \\
-\hline \texttt{DES-CBC}           & DES             & 64                        & CBC \\
-\hline \texttt{DES-CFB}           & DES             & 64                        & CFB \\
-\hline \texttt{DES-OFB}           & DES             & 64                        & OFB \\
-\hline \texttt{IDEA-CBC}          & IDEA            & 128                       & CBC \\
-\hline \texttt{IDEA-CFB}          & IDEA            & 128                       & CFB \\
-\hline \texttt{IDEA-OFB}          & IDEA            & 128                       & OFB \\
-\hline \texttt{RC5-CBC}           & RC5             & 128                       & CBC \\
-\hline \texttt{RC5-CFB}           & RC5             & 128                       & CFB \\
-\hline \texttt{RC5-OFB}           & RC5             & 128                       & OFB \\
-\hline \texttt{RC2-40-CBC}        & RC2             & 40                        & CBC \\
-\hline \texttt{RC2-64-CBC}        & RC2             & 64                        & CBC \\
-\hline \texttt{RC2-CBC}           & RC2             & 128                       & CBC \\
-\hline \texttt{RC2-CFB}           & RC2             & 128                       & CFB \\
-\hline \texttt{RC2-OFB}           & RC2             & 128                       & OFB \\
-\hline \texttt{SEED-CBC}          & SEED            & 128                       & CBC \\
-\hline \texttt{SEED-CFB}          & SEED            & 128                       & CFB \\
-\hline \texttt{SEED-OFB}          & SEED            & 128                       & OFB \\
+\hline \texttt{AES-128-CBC}       & AES             & 128                       & CBC    \\
+\hline \texttt{AES-192-CBC}       & AES             & 192                       & CBC    \\
+\hline \texttt{AES-256-CBC}       & AES             & 256                       & CBC    \\
+\hline \texttt{AES-128-CFB}       & AES             & 128                       & CFB    \\
+\hline \texttt{AES-192-CFB}       & AES             & 192                       & CFB    \\
+\hline \texttt{AES-256-CFB}       & AES             & 256                       & CFB    \\
+\hline \texttt{AES-128-CTR}       & AES             & 128                       & CTR    \\
+\hline \texttt{AES-192-CTR}       & AES             & 192                       & CTR    \\
+\hline \texttt{AES-256-CTR}       & AES             & 256                       & CTR    \\
+\hline \texttt{AES-128-OFB}       & AES             & 128                       & OFB    \\
+\hline \texttt{AES-192-OFB}       & AES             & 192                       & OFB    \\
+\hline \texttt{AES-256-OFB}       & AES             & 256                       & OFB    \\
+\hline \texttt{BF-CBC}            & Blowfish        & 128                       & CBC    \\
+\hline \texttt{BF-CFB}            & Blowfish        & 128                       & CFB    \\
+\hline \texttt{BF-OFB}            & Blowfish        & 128                       & OFB    \\
+\hline \texttt{CAMELLIA-128-CBC}  & Camellia        & 128                       & CBC    \\
+\hline \texttt{CAMELLIA-192-CBC}  & Camellia        & 192                       & CBC    \\
+\hline \texttt{CAMELLIA-256-CBC}  & Camellia        & 256                       & CBC    \\
+\hline \texttt{CAMELLIA-128-CFB}  & Camellia        & 128                       & CFB    \\
+\hline \texttt{CAMELLIA-192-CFB}  & Camellia        & 192                       & CFB    \\
+\hline \texttt{CAMELLIA-256-CFB}  & Camellia        & 256                       & CFB    \\
+\hline \texttt{CAMELLIA-128-CTR}  & Camellia        & 128                       & CTR    \\
+\hline \texttt{CAMELLIA-192-CTR}  & Camellia        & 192                       & CTR    \\
+\hline \texttt{CAMELLIA-256-CTR}  & Camellia        & 256                       & CTR    \\
+\hline \texttt{CAMELLIA-128-OFB}  & Camellia        & 128                       & OFB    \\
+\hline \texttt{CAMELLIA-192-OFB}  & Camellia        & 192                       & OFB    \\
+\hline \texttt{CAMELLIA-256-OFB}  & Camellia        & 256                       & OFB    \\
+\hline \texttt{CAST5-CBC}         & CAST5           & 128                       & CBC    \\
+\hline \texttt{CAST5-CFB}         & CAST5           & 128                       & CFB    \\
+\hline \texttt{CAST5-OFB}         & CAST5           & 128                       & OFB    \\
+\hline \texttt{ChaCha20}          & ChaCha20        & 256                       & STREAM \\
+\hline \texttt{DES-EDE-CBC}       & 3DES (EDE)      & 128                       & CBC    \\
+\hline \texttt{DES-EDE-CFB}       & 3DES (EDE)      & 128                       & CFB    \\
+\hline \texttt{DES-EDE-OFB}       & 3DES (EDE)      & 128                       & OFB    \\
+\hline \texttt{DES-EDE3-CBC}      & 3DES (EDE)      & 192                       & CBC    \\
+\hline \texttt{DES-EDE3-CFB}      & 3DES (EDE)      & 192                       & CFB    \\
+\hline \texttt{DES-EDE3-OFB}      & 3DES (EDE)      & 192                       & OFB    \\
+\hline \texttt{DES-CBC}           & DES             & 64                        & CBC    \\
+\hline \texttt{DES-CFB}           & DES             & 64                        & CFB    \\
+\hline \texttt{DES-OFB}           & DES             & 64                        & OFB    \\
+\hline \texttt{DESX-CBC}          & DES-X           & 192                       & CBC    \\
+\hline \texttt{IDEA-CBC}          & IDEA            & 128                       & CBC    \\
+\hline \texttt{IDEA-CFB}          & IDEA            & 128                       & CFB    \\
+\hline \texttt{IDEA-OFB}          & IDEA            & 128                       & OFB    \\
+\hline \texttt{RC5-CBC}           & RC5             & 128                       & CBC    \\
+\hline \texttt{RC5-CFB}           & RC5             & 128                       & CFB    \\
+\hline \texttt{RC5-OFB}           & RC5             & 128                       & OFB    \\
+\hline \texttt{RC2-40-CBC}        & RC2             & 40                        & CBC    \\
+\hline \texttt{RC2-64-CBC}        & RC2             & 64                        & CBC    \\
+\hline \texttt{RC2-CBC}           & RC2             & 128                       & CBC    \\
+\hline \texttt{RC2-CFB}           & RC2             & 128                       & CFB    \\
+\hline \texttt{RC2-OFB}           & RC2             & 128                       & OFB    \\
+\hline \texttt{SEED-CBC}          & SEED            & 128                       & CBC    \\
+\hline \texttt{SEED-CFB}          & SEED            & 128                       & CFB    \\
+\hline \texttt{SEED-OFB}          & SEED            & 128                       & OFB    \\
 \hline
 \hline
 \end{tabular}
 \end{tabular}
 \end{small}
 \end{small}
@@ -7657,32 +7672,35 @@ When dealing with SSH formatted private keys the following encryption algorithms
 \begin{table}[H]
 \begin{table}[H]
 \begin{small}
 \begin{small}
 \begin{tabular}{|l|l|l|l|}
 \begin{tabular}{|l|l|l|l|}
-\hline \textbf{Identifier}        & \textbf{Cipher} & \textbf{Key size in bits} & \textbf{Mode} \\
-\hline \texttt{none}              & none            & 0                         & none \\
-\hline \texttt{aes128-cbc}        & AES             & 128                       & CBC  \\
-\hline \texttt{aes128-ctr}        & AES             & 128                       & CTR  \\
-\hline \texttt{aes192-cbc}        & AES             & 192                       & CBC  \\
-\hline \texttt{aes192-ctr}        & AES             & 192                       & CTR  \\
-\hline \texttt{aes256-cbc}        & AES             & 256                       & CBC  \\
-\hline \texttt{aes256-ctr}        & AES             & 256                       & CTR  \\
-\hline \texttt{blowfish128-cbc}   & Blowfish        & 128                       & CBC  \\
-\hline \texttt{blowfish128-ctr}   & Blowfish        & 128                       & CTR  \\
-\hline \texttt{des-cbc}           & DES             & 64                        & CBC  \\
-\hline \texttt{3des-cbc}          & 3DES (EDE)      & 192                       & CBC  \\
-\hline \texttt{3des-ctr}          & 3DES (EDE)      & 192                       & CTR  \\
-\hline \texttt{serpent128-cbc}    & Serpent         & 128                       & CBC  \\
-\hline \texttt{serpent128-ctr}    & Serpent         & 128                       & CTR  \\
-\hline \texttt{serpent192-cbc}    & Serpent         & 192                       & CBC  \\
-\hline \texttt{serpent192-ctr}    & Serpent         & 192                       & CTR  \\
-\hline \texttt{serpent256-cbc}    & Serpent         & 256                       & CBC  \\
-\hline \texttt{serpent256-ctr}    & Serpent         & 256                       & CTR  \\
-\hline \texttt{twofish128-cbc}    & Twofish         & 128                       & CBC  \\
-\hline \texttt{twofish128-ctr}    & Twofish         & 128                       & CTR  \\
-\hline \texttt{twofish192-cbc}    & Twofish         & 192                       & CBC  \\
-\hline \texttt{twofish192-ctr}    & Twofish         & 192                       & CTR  \\
-\hline \texttt{twofish-cbc}       & Twofish         & 256                       & CBC  \\
-\hline \texttt{twofish256-cbc}    & Twofish         & 256                       & CBC  \\
-\hline \texttt{twofish256-ctr}    & Twofish         & 256                       & CTR  \\
+\hline \textbf{Identifier}                    & \textbf{Cipher} & \textbf{Key size in bits} & \textbf{Mode} \\
+\hline \texttt{none}                          & none             & 0                        & none   \\
+\hline \texttt{aes128-cbc}                    & AES              & 128                      & CBC    \\
+\hline \texttt{aes128-ctr}                    & AES              & 128                      & CTR    \\
+\hline \texttt{aes192-cbc}                    & AES              & 192                      & CBC    \\
+\hline \texttt{aes192-ctr}                    & AES              & 192                      & CTR    \\
+\hline \texttt{aes256-cbc}                    & AES              & 256                      & CBC    \\
+\hline \texttt{aes256-ctr}                    & AES              & 256                      & CTR    \\
+\hline \texttt{[email protected]}        & AES              & 128                      & GCM    \\
+\hline \texttt{[email protected]}        & AES              & 256                      & GCM    \\
+\hline \texttt{blowfish128-cbc}               & Blowfish         & 128                      & CBC    \\
+\hline \texttt{blowfish128-ctr}               & Blowfish         & 128                      & CTR    \\
+\hline \texttt{[email protected]} & ChaCha20Poly1305 & 256                      & STREAM \\
+\hline \texttt{des-cbc}                       & DES              & 64                       & CBC    \\
+\hline \texttt{3des-cbc}                      & 3DES (EDE)       & 192                      & CBC    \\
+\hline \texttt{3des-ctr}                      & 3DES (EDE)       & 192                      & CTR    \\
+\hline \texttt{serpent128-cbc}                & Serpent          & 128                      & CBC    \\
+\hline \texttt{serpent128-ctr}                & Serpent          & 128                      & CTR    \\
+\hline \texttt{serpent192-cbc}                & Serpent          & 192                      & CBC    \\
+\hline \texttt{serpent192-ctr}                & Serpent          & 192                      & CTR    \\
+\hline \texttt{serpent256-cbc}                & Serpent          & 256                      & CBC    \\
+\hline \texttt{serpent256-ctr}                & Serpent          & 256                      & CTR    \\
+\hline \texttt{twofish128-cbc}                & Twofish          & 128                      & CBC    \\
+\hline \texttt{twofish128-ctr}                & Twofish          & 128                      & CTR    \\
+\hline \texttt{twofish192-cbc}                & Twofish          & 192                      & CBC    \\
+\hline \texttt{twofish192-ctr}                & Twofish          & 192                      & CTR    \\
+\hline \texttt{twofish-cbc}                   & Twofish          & 256                      & CBC    \\
+\hline \texttt{twofish256-cbc}                & Twofish          & 256                      & CBC    \\
+\hline \texttt{twofish256-ctr}                & Twofish          & 256                      & CTR    \\
 \hline
 \hline
 \end{tabular}
 \end{tabular}
 \end{small}
 \end{small}

+ 54 - 0
notes/cipher_tv.txt

@@ -1433,6 +1433,60 @@ Key Size: 8 bytes
 49: 6B901B2B79B6950C
 49: 6B901B2B79B6950C
 
 
 
 
+Cipher: desx
+Key Size: 24 bytes
+ 0: F490BAC08301C6C9
+ 1: 5668E3676102907F
+ 2: 5BA2BFCC35AED470
+ 3: B2CC7DBA467E62C6
+ 4: B4BF359A876FAC3E
+ 5: 2EF94EA88C1ACE79
+ 6: 9C175106D3484502
+ 7: 38F466A89DFA587F
+ 8: 745F3EB5BEDE929C
+ 9: 9EBA1D104A86E113
+10: 561DC144F7A2CB5F
+11: E1EBF96BD996F292
+12: 4D96B8CD7D26DA9C
+13: DA59711131B18AF3
+14: F5EEC897F79D3597
+15: 3A39A7F0060373CB
+16: DA95839AA553147F
+17: 8A0BBA6804BDFFF2
+18: B0A0881F389062B5
+19: C6878531FF4888EC
+20: 9C73653BDB9EBFFD
+21: EF81557E5B539A4C
+22: 959ADE9663CC395D
+23: D22C6460C0580E1B
+24: E3B7EFC7DC2EEB28
+25: ACF66715DFE81D84
+26: CD2FC182D9A0F565
+27: 34F6DED980E437FA
+28: 313DE7369F9D1BB9
+29: 554A743622A42A3D
+30: 6F460E480078F091
+31: E752181D34A8FED2
+32: E0C7F0F53F84830B
+33: 1159C652EB6460E1
+34: 2A68847D986CBF7D
+35: B3CB050C29C86EFC
+36: 2C0EB50DBCA918EA
+37: CA1D0D17D185D9BE
+38: 3CB9EB47E1E05CC1
+39: 2AA3DE0A38F3A0F5
+40: EA43C7125932D2A7
+41: 79A23C0EA9E6C11E
+42: B711BFC1DE05D9B0
+43: BCF5ADD7751EED39
+44: 7A41A2FE64720CA2
+45: DC43A35EB0489FE9
+46: 9353A9FBD060B991
+47: 19DD74A5D948AC15
+48: F0E3B7B2D6E328F5
+49: 77C25E387D80E071
+
+
 Cipher: 3des
 Cipher: 3des
 Key Size: 16 bytes
 Key Size: 16 bytes
  0: DF0B6C9C31CD0CE4
  0: DF0B6C9C31CD0CE4

+ 19 - 0
notes/eax_tv.txt

@@ -313,6 +313,25 @@ EAX-des (8 byte key)
  15: 8D1A1E888BBB8648E638C4E74E11B8, 685E006C441448B8
  15: 8D1A1E888BBB8648E638C4E74E11B8, 685E006C441448B8
  16: 93AE906B8BE4EAC8ED6D8F48F04A7AFF, 71DD7AF752FE28FB
  16: 93AE906B8BE4EAC8ED6D8F48F04A7AFF, 71DD7AF752FE28FB
 
 
+EAX-desx (24 byte key)
+  0: , FA66F07E473109A2
+  1: 4B, 576970495248BB09
+  2: D81C, 3AE9E470ABFBEEB1
+  3: 5B2442, F6B3BDC55CBD01A2
+  4: B1A495A8, AAD2D78BC0525DA2
+  5: 7723413A8D, 51D3134CBC32AD9B
+  6: 6F9D40815E10, 552C146A7A769E9E
+  7: B3292E406C9B92, D3ACE79B2D69877B
+  8: EF7513D71D52C33A, 64935E1AE8C416B1
+  9: 068AEDE3E0E1B0DC11, 2C5698925FFC70BF
+ 10: 76A5664A3D5DF553BAC4, 52B9D560C0D9BB0D
+ 11: CC6128B6BD0035354CF3A3, A8BA535862B221BD
+ 12: CB499A58CF55D016B79192EF, 76842391A45C6674
+ 13: 4903FBC696A256D4AC16A3EFD2, 39978842103FE097
+ 14: 9CD5671BEDF4EB8D519A72310A37, F00809AA017E81C5
+ 15: 9F62AB705A285EBF998FCF401166BA, 506244F55C4EAD84
+ 16: 110161EEF9B3CE543DB12EA8682866D4, 7A12BE4371963521
+
 EAX-3des (24 byte key)
 EAX-3des (24 byte key)
   0: , 8914311BB990B725
   0: , 8914311BB990B725
   1: D8, 2094EDC5D03E54B1
   1: D8, 2094EDC5D03E54B1

+ 19 - 0
notes/ocb_tv.txt

@@ -313,6 +313,25 @@ OCB-des (8 byte key)
  15: FB3BCC650B29F418930A467EA4FB73, 64D12723E100F08B
  15: FB3BCC650B29F418930A467EA4FB73, 64D12723E100F08B
  16: DE1C27E9B3C391AF5DF403291F2C084A, 6BADE4638AE46BE2
  16: DE1C27E9B3C391AF5DF403291F2C084A, 6BADE4638AE46BE2
 
 
+OCB-desx (24 byte key)
+  0: , 972B4CC480AEA6A9
+  1: CB, C46CC58DE9615963
+  2: 2911, 9B5117BF9530018F
+  3: 844501, 308F0F36D3313B67
+  4: 0C8CB549, 3F72789FB54CC9B1
+  5: 581FA34114, 1B86E66203EBF9EE
+  6: D0BBE3E43961, 59F730D5ABF13265
+  7: 046529AB0EDD17, 240FF6134AA5327B
+  8: FF4F32C3A96D61D9, 5DE9B81CC39ACC61
+  9: E94A99D609BE5B1A6D, 443F4948DE64E6A0
+ 10: B3E783B59853EE1EBD36, F04B41EAAB9CDE18
+ 11: 0BB36CE35BB8050169F6F2, 598A0705C800BC04
+ 12: BE946B1CB03E7E5DA1CC12B8, 288B827CEA810662
+ 13: 3FEC137C657FF1F2B34F4C5E56, F9248F59D1033253
+ 14: 626DC4527055E80E68A6A1FE0F78, D8AA67D5ABD0B6A5
+ 15: 476247537A509BC42BCD6DEC7F9506, 2C2D0385066B4815
+ 16: 5D32BFE0B9ACB62B6AC29D43A0535A25, DE247F5F809C6CEC
+
 OCB-3des (24 byte key)
 OCB-3des (24 byte key)
   0: , 9CB7074F93CD37DD
   0: , 9CB7074F93CD37DD
   1: 4D, 51541A838A154E0B
   1: 4D, 51541A838A154E0B

+ 19 - 0
notes/omac_tv.txt

@@ -313,6 +313,25 @@ OMAC-des (8 byte key)
  15: 7FB7CE0862958B37
  15: 7FB7CE0862958B37
  16: 55097816B10C549B
  16: 55097816B10C549B
 
 
+OMAC-desx (24 byte key)
+  0: 3DCD366D8E4D6EB8
+  1: AD1DF426B344F922
+  2: C50DD51B953E37EF
+  3: F732DD355496D72F
+  4: B8A9D3819024AD6E
+  5: 7C4624125A33C0DF
+  6: 378D83372E82296F
+  7: 974C7613AF191E95
+  8: C856C3F7B1A944FA
+  9: F7898CFD34AFECE2
+ 10: 9B5B09251EB0F44B
+ 11: 369D0AC2E71641E8
+ 12: B798AFD13EDFD831
+ 13: 066207F46EA9B6F2
+ 14: 4083189F5CE42C5F
+ 15: 6D04E4B9E2ECA8DB
+ 16: 9D9EE9A8B5AC27C2
+
 OMAC-3des (24 byte key)
 OMAC-3des (24 byte key)
   0: 7F07A9EA8ECEDF9E
   0: 7F07A9EA8ECEDF9E
   1: 4E2A652EB5FBF5F8
   1: 4E2A652EB5FBF5F8

+ 19 - 0
notes/pmac_tv.txt

@@ -313,6 +313,25 @@ PMAC-des (8 byte key)
  15: FCE22E6CAD528B49
  15: FCE22E6CAD528B49
  16: 993884FB9B3FB620
  16: 993884FB9B3FB620
 
 
+PMAC-desx (24 byte key)
+  0: CFC3AC7F6B9BC6C4
+  1: 15F83A2E582CA5DB
+  2: 648B0A54C2A44D96
+  3: 76BD5FCA60D3E0D8
+  4: 59E994CED4C82509
+  5: 15B6B80165023A25
+  6: 095AEDA02E235237
+  7: FDEEF329DD64EE7D
+  8: 1FE317FD5338ADEF
+  9: 0E0530FC5984E574
+ 10: 7D670A434BDF5E6E
+ 11: AD0C2D07F449969F
+ 12: 023D921C2523A41D
+ 13: E98F2BE666A5749D
+ 14: FA9DB0029446CA31
+ 15: AF3350DCF2A5D6AC
+ 16: E72861AE67EF88E2
+
 PMAC-3des (24 byte key)
 PMAC-3des (24 byte key)
   0: E42CCBC9C9457DF6
   0: E42CCBC9C9457DF6
   1: FE766F7930557708
   1: FE766F7930557708

+ 156 - 7
src/ciphers/des.c

@@ -40,6 +40,20 @@ const struct ltc_cipher_descriptor des3_desc =
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 };
 
 
+const struct ltc_cipher_descriptor desx_desc =
+{
+    "desx",
+    27,
+    24, 24, 8, 16,
+    &desx_setup,
+    &desx_ecb_encrypt,
+    &desx_ecb_decrypt,
+    &desx_test,
+    &desx_done,
+    &desx_keysize,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
 static const ulong32 bytebit[8] =
 static const ulong32 bytebit[8] =
 {
 {
     0200, 0100, 040, 020, 010, 04, 02, 01
     0200, 0100, 040, 020, 010, 04, 02, 01
@@ -1511,7 +1525,7 @@ static void desfunc(ulong32 *block, const ulong32 *keys)
 #endif
 #endif
 
 
  /**
  /**
-    Initialize the LTC_DES block cipher
+    Initialize the DES block cipher
     @param key The symmetric key you wish to pass
     @param key The symmetric key you wish to pass
     @param keylen The key length in bytes
     @param keylen The key length in bytes
     @param num_rounds The number of rounds desired (0 for default)
     @param num_rounds The number of rounds desired (0 for default)
@@ -1538,7 +1552,36 @@ int des_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_ke
 }
 }
 
 
  /**
  /**
-    Initialize the 3LTC_DES-EDE block cipher
+    Initialize the DES-X block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+int desx_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   if(num_rounds != 0 && num_rounds != 16) {
+       return CRYPT_INVALID_ROUNDS;
+   }
+
+   if (keylen != 24) {
+       return CRYPT_INVALID_KEYSIZE;
+   }
+
+   deskey(key, EN0, skey->desx.ek);
+   deskey(key, DE1, skey->desx.dk);
+
+   LOAD32H(skey->desx.k[0][0], key + 8);
+   LOAD32H(skey->desx.k[0][1], key + 12);
+   LOAD32H(skey->desx.k[1][0], key + 16);
+   LOAD32H(skey->desx.k[1][1], key + 20);
+
+   return CRYPT_OK;
+}
+
+ /**
+    Initialize the 3DES-EDE block cipher
     @param key The symmetric key you wish to pass
     @param key The symmetric key you wish to pass
     @param keylen The key length in bytes
     @param keylen The key length in bytes
     @param num_rounds The number of rounds desired (0 for default)
     @param num_rounds The number of rounds desired (0 for default)
@@ -1580,7 +1623,7 @@ int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_k
 }
 }
 
 
 /**
 /**
-  Encrypts a block of text with LTC_DES
+  Encrypts a block of text with DES
   @param pt The input plaintext (8 bytes)
   @param pt The input plaintext (8 bytes)
   @param ct The output ciphertext (8 bytes)
   @param ct The output ciphertext (8 bytes)
   @param skey The key as scheduled
   @param skey The key as scheduled
@@ -1601,7 +1644,7 @@ int des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric_
 }
 }
 
 
 /**
 /**
-  Decrypts a block of text with LTC_DES
+  Decrypts a block of text with DES
   @param ct The input ciphertext (8 bytes)
   @param ct The input ciphertext (8 bytes)
   @param pt The output plaintext (8 bytes)
   @param pt The output plaintext (8 bytes)
   @param skey The key as scheduled
   @param skey The key as scheduled
@@ -1622,7 +1665,57 @@ int des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_
 }
 }
 
 
 /**
 /**
-  Encrypts a block of text with 3LTC_DES-EDE
+  Encrypts a block of text with DES-X
+  @param pt The input plaintext (8 bytes)
+  @param ct The output ciphertext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int desx_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric_key *skey)
+{
+    ulong32 work[2];
+    LTC_ARGCHK(pt   != NULL);
+    LTC_ARGCHK(ct   != NULL);
+    LTC_ARGCHK(skey != NULL);
+    LOAD32H(work[0], pt+0);
+    LOAD32H(work[1], pt+4);
+    work[0] ^= skey->desx.k[0][0];
+    work[1] ^= skey->desx.k[0][1];
+    desfunc(work, skey->desx.ek);
+    work[0] ^= skey->desx.k[1][0];
+    work[1] ^= skey->desx.k[1][1];
+    STORE32H(work[0],ct+0);
+    STORE32H(work[1],ct+4);
+    return CRYPT_OK;
+}
+
+/**
+  Decrypts a block of text with DES-X
+  @param ct The input ciphertext (8 bytes)
+  @param pt The output plaintext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int desx_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_key *skey)
+{
+    ulong32 work[2];
+    LTC_ARGCHK(pt   != NULL);
+    LTC_ARGCHK(ct   != NULL);
+    LTC_ARGCHK(skey != NULL);
+    LOAD32H(work[0], ct+0);
+    LOAD32H(work[1], ct+4);
+    work[0] ^= skey->desx.k[1][0];
+    work[1] ^= skey->desx.k[1][1];
+    desfunc(work, skey->des.dk);
+    work[0] ^= skey->desx.k[0][0];
+    work[1] ^= skey->desx.k[0][1];
+    STORE32H(work[0],pt+0);
+    STORE32H(work[1],pt+4);
+    return CRYPT_OK;
+}
+
+/**
+  Encrypts a block of text with 3DES-EDE
   @param pt The input plaintext (8 bytes)
   @param pt The input plaintext (8 bytes)
   @param ct The output ciphertext (8 bytes)
   @param ct The output ciphertext (8 bytes)
   @param skey The key as scheduled
   @param skey The key as scheduled
@@ -1646,7 +1739,7 @@ int des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric
 }
 }
 
 
 /**
 /**
-  Decrypts a block of text with 3LTC_DES-EDE
+  Decrypts a block of text with 3DES-EDE
   @param ct The input ciphertext (8 bytes)
   @param ct The input ciphertext (8 bytes)
   @param pt The output plaintext (8 bytes)
   @param pt The output plaintext (8 bytes)
   @param skey The key as scheduled
   @param skey The key as scheduled
@@ -1669,7 +1762,7 @@ int des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric
 }
 }
 
 
 /**
 /**
-  Performs a self-test of the LTC_DES block cipher
+  Performs a self-test of the DES block cipher
   @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
   @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
 */
 */
 int des_test(void)
 int des_test(void)
@@ -1964,6 +2057,39 @@ int des_test(void)
   #endif
   #endif
 }
 }
 
 
+int desx_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+    unsigned char key[24], pt[8], tmp[8];
+    symmetric_key skey;
+    int i, err;
+
+    if ((err = des_test()) != CRYPT_OK) {
+        return err;
+    }
+
+    /* See if we can encrypt all zero bytes 1000 times, decrypt and come back to where we started */
+
+    for (i = 0; i < 24; i++) key[i] = i;
+
+    if ((err = desx_setup(key, 24, 0, &skey)) != CRYPT_OK) {
+        return err;
+    }
+
+    for (i = 0; i < 8; i++) pt[i] = tmp[i] = 0;
+    for (i = 0; i < 1000; i++) desx_ecb_encrypt(tmp, tmp, &skey);
+    for (i = 0; i < 1000; i++) desx_ecb_decrypt(tmp, tmp, &skey);
+
+    if (compare_testvector(tmp, 8, pt, 8, "DES-X", 0) != 0) {
+        return CRYPT_FAIL_TESTVECTOR;
+    }
+
+    return CRYPT_OK;
+ #endif
+}
+
 int des3_test(void)
 int des3_test(void)
 {
 {
  #ifndef LTC_TEST
  #ifndef LTC_TEST
@@ -2046,6 +2172,14 @@ void des_done(symmetric_key *skey)
   LTC_UNUSED_PARAM(skey);
   LTC_UNUSED_PARAM(skey);
 }
 }
 
 
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void desx_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
 /** Terminate the context
 /** Terminate the context
    @param skey    The scheduled key
    @param skey    The scheduled key
 */
 */
@@ -2070,6 +2204,21 @@ int des_keysize(int *keysize)
     return CRYPT_OK;
     return CRYPT_OK;
 }
 }
 
 
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int desx_keysize(int *keysize)
+{
+    LTC_ARGCHK(keysize != NULL);
+    if(*keysize < 24) {
+        return CRYPT_INVALID_KEYSIZE;
+    }
+    *keysize = 24;
+    return CRYPT_OK;
+}
+
 /**
 /**
   Gets suitable key size
   Gets suitable key size
   @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
   @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.

+ 8 - 6
src/encauth/chachapoly/chacha20poly1305_done.c

@@ -21,13 +21,15 @@ int chacha20poly1305_done(chacha20poly1305_state *st, unsigned char *tag, unsign
 
 
    LTC_ARGCHK(st != NULL);
    LTC_ARGCHK(st != NULL);
 
 
-   padlen = 16 - (unsigned long)(st->ctlen % 16);
-   if (padlen < 16) {
-     if ((err = poly1305_process(&st->poly, padzero, padlen)) != CRYPT_OK) return err;
+   if (!st->openssh_compat) {
+      padlen = 16 - (unsigned long)(st->ctlen % 16);
+      if (padlen < 16) {
+        if ((err = poly1305_process(&st->poly, padzero, padlen)) != CRYPT_OK) return err;
+      }
+      STORE64L(st->aadlen, buf);
+      STORE64L(st->ctlen, buf + 8);
+      if ((err = poly1305_process(&st->poly, buf, 16)) != CRYPT_OK)           return err;
    }
    }
-   STORE64L(st->aadlen, buf);
-   STORE64L(st->ctlen, buf + 8);
-   if ((err = poly1305_process(&st->poly, buf, 16)) != CRYPT_OK)           return err;
    if ((err = poly1305_done(&st->poly, tag, taglen)) != CRYPT_OK)          return err;
    if ((err = poly1305_done(&st->poly, tag, taglen)) != CRYPT_OK)          return err;
    if ((err = chacha_done(&st->chacha)) != CRYPT_OK)                       return err;
    if ((err = chacha_done(&st->chacha)) != CRYPT_OK)                       return err;
    return CRYPT_OK;
    return CRYPT_OK;

+ 1 - 0
src/encauth/chachapoly/chacha20poly1305_init.c

@@ -14,6 +14,7 @@
 */
 */
 int chacha20poly1305_init(chacha20poly1305_state *st, const unsigned char *key, unsigned long keylen)
 int chacha20poly1305_init(chacha20poly1305_state *st, const unsigned char *key, unsigned long keylen)
 {
 {
+   XMEMSET(st, 0, sizeof(*st));
    return chacha_setup(&st->chacha, key, keylen, 20);
    return chacha_setup(&st->chacha, key, keylen, 20);
 }
 }
 
 

+ 4 - 0
src/encauth/chachapoly/chacha20poly1305_memory.c

@@ -40,6 +40,10 @@ int chacha20poly1305_memory(const unsigned char *key, unsigned long keylen,
    LTC_ARGCHK(taglen != NULL);
    LTC_ARGCHK(taglen != NULL);
 
 
    if ((err = chacha20poly1305_init(&st, key, keylen)) != CRYPT_OK)          { goto LBL_ERR; }
    if ((err = chacha20poly1305_init(&st, key, keylen)) != CRYPT_OK)          { goto LBL_ERR; }
+
+   st.openssh_compat = (direction & CHACHA20POLY1305_OPENSSH_COMPAT) ? 1 : 0;
+   direction &= ~(CHACHA20POLY1305_OPENSSH_COMPAT);
+
    if ((err = chacha20poly1305_setiv(&st, iv, ivlen)) != CRYPT_OK)           { goto LBL_ERR; }
    if ((err = chacha20poly1305_setiv(&st, iv, ivlen)) != CRYPT_OK)           { goto LBL_ERR; }
    if (aad && aadlen > 0) {
    if (aad && aadlen > 0) {
       if ((err = chacha20poly1305_add_aad(&st, aad, aadlen)) != CRYPT_OK)    { goto LBL_ERR; }
       if ((err = chacha20poly1305_add_aad(&st, aad, aadlen)) != CRYPT_OK)    { goto LBL_ERR; }

+ 13 - 1
src/headers/tomcrypt_cipher.h

@@ -97,6 +97,11 @@ struct des_key {
     ulong32 ek[32], dk[32];
     ulong32 ek[32], dk[32];
 };
 };
 
 
+struct desx_key {
+    ulong32 ek[32], dk[32];
+    ulong32 k[2][2];
+};
+
 struct des3_key {
 struct des3_key {
     ulong32 ek[3][32], dk[3][32];
     ulong32 ek[3][32], dk[3][32];
 };
 };
@@ -176,6 +181,7 @@ struct tea_key {
 typedef union Symmetric_key {
 typedef union Symmetric_key {
 #ifdef LTC_DES
 #ifdef LTC_DES
    struct des_key des;
    struct des_key des;
+   struct desx_key desx;
    struct des3_key des3;
    struct des3_key des3;
 #endif
 #endif
 #ifdef LTC_RC2
 #ifdef LTC_RC2
@@ -757,13 +763,19 @@ int des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_
 int des_test(void);
 int des_test(void);
 void des_done(symmetric_key *skey);
 void des_done(symmetric_key *skey);
 int des_keysize(int *keysize);
 int des_keysize(int *keysize);
+int desx_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int desx_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric_key *skey);
+int desx_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_key *skey);
+int desx_test(void);
+void desx_done(symmetric_key *skey);
+int desx_keysize(int *keysize);
 int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
 int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
 int des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric_key *skey);
 int des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric_key *skey);
 int des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_key *skey);
 int des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_key *skey);
 int des3_test(void);
 int des3_test(void);
 void des3_done(symmetric_key *skey);
 void des3_done(symmetric_key *skey);
 int des3_keysize(int *keysize);
 int des3_keysize(int *keysize);
-extern const struct ltc_cipher_descriptor des_desc, des3_desc;
+extern const struct ltc_cipher_descriptor des_desc, desx_desc, des3_desc;
 #endif
 #endif
 
 
 #ifdef LTC_CAST5
 #ifdef LTC_CAST5

+ 4 - 3
src/headers/tomcrypt_mac.h

@@ -541,11 +541,12 @@ typedef struct {
    chacha_state chacha;
    chacha_state chacha;
    ulong64 aadlen;
    ulong64 aadlen;
    ulong64 ctlen;
    ulong64 ctlen;
-   int aadflg;
+   int aadflg, openssh_compat;
 } chacha20poly1305_state;
 } chacha20poly1305_state;
 
 
-#define CHACHA20POLY1305_ENCRYPT LTC_ENCRYPT
-#define CHACHA20POLY1305_DECRYPT LTC_DECRYPT
+#define CHACHA20POLY1305_ENCRYPT          LTC_ENCRYPT
+#define CHACHA20POLY1305_DECRYPT          LTC_DECRYPT
+#define CHACHA20POLY1305_OPENSSH_COMPAT   2
 
 
 int chacha20poly1305_init(chacha20poly1305_state *st, const unsigned char *key, unsigned long keylen);
 int chacha20poly1305_init(chacha20poly1305_state *st, const unsigned char *key, unsigned long keylen);
 int chacha20poly1305_setiv(chacha20poly1305_state *st, const unsigned char *iv, unsigned long ivlen);
 int chacha20poly1305_setiv(chacha20poly1305_state *st, const unsigned char *iv, unsigned long ivlen);

+ 14 - 1
src/headers/tomcrypt_private.h

@@ -263,7 +263,19 @@ int base64_encode_pem(const unsigned char *in,  unsigned long inlen,
 
 
 #ifdef LTC_PEM
 #ifdef LTC_PEM
 enum cipher_mode {
 enum cipher_mode {
-   cm_none, cm_cbc, cm_cfb, cm_ctr, cm_ofb, cm_stream, cm_gcm
+   cm_modes =           0x00ff,
+   cm_flags =           0xff00,
+   /* Flags */
+   cm_openssh =         0x0100,
+   /* Modes */
+   cm_none =            0x0000,
+   cm_cbc =             0x0001,
+   cm_cfb =             0x0002,
+   cm_ctr =             0x0003,
+   cm_ofb =             0x0004,
+   cm_stream =          0x0005,
+   cm_gcm =             0x0006,
+   cm_stream_openssh =  cm_stream | cm_openssh,
 };
 };
 
 
 struct blockcipher_info {
 struct blockcipher_info {
@@ -350,6 +362,7 @@ int pbes2_extract(const ltc_asn1_list *s, pbes_arg *res);
 int pem_decrypt(unsigned char *data, unsigned long *datalen,
 int pem_decrypt(unsigned char *data, unsigned long *datalen,
                 unsigned char *key,  unsigned long keylen,
                 unsigned char *key,  unsigned long keylen,
                 unsigned char *iv,   unsigned long ivlen,
                 unsigned char *iv,   unsigned long ivlen,
+                unsigned char *tag,  unsigned long taglen,
                 const struct blockcipher_info *info,
                 const struct blockcipher_info *info,
                 enum padding_type padding);
                 enum padding_type padding);
 #ifndef LTC_NO_FILE
 #ifndef LTC_NO_FILE

+ 2 - 0
src/misc/crypt/crypt.c

@@ -84,6 +84,8 @@ const char *crypt_build_settings =
 #endif
 #endif
 #if defined(LTC_DES)
 #if defined(LTC_DES)
    "   DES\n"
    "   DES\n"
+   "   DES-X\n"
+   "   3DES\n"
 #endif
 #endif
 #if defined(LTC_CAST5)
 #if defined(LTC_CAST5)
    "   CAST5\n"
    "   CAST5\n"

+ 1 - 0
src/misc/crypt/crypt_register_all_ciphers.c

@@ -58,6 +58,7 @@ int register_all_ciphers(void)
 #endif
 #endif
 #ifdef LTC_DES
 #ifdef LTC_DES
    REGISTER_CIPHER(&des_desc);
    REGISTER_CIPHER(&des_desc);
+   REGISTER_CIPHER(&desx_desc);
    REGISTER_CIPHER(&des3_desc);
    REGISTER_CIPHER(&des3_desc);
 #endif
 #endif
 #ifdef LTC_CAST5
 #ifdef LTC_CAST5

+ 107 - 54
src/misc/pem/pem.c

@@ -75,66 +75,72 @@ const struct str pem_ssh_comment = { SET_CSTR(, "Comment: ") };
 const struct str pem_dek_info_start = { SET_CSTR(, "DEK-Info: ") };
 const struct str pem_dek_info_start = { SET_CSTR(, "DEK-Info: ") };
 const struct blockcipher_info pem_dek_infos[] =
 const struct blockcipher_info pem_dek_infos[] =
    {
    {
-      { .name = "AES-128-CBC,",      .algo = "aes",      .keylen = 128 / 8, .mode = cm_cbc, },
-      { .name = "AES-192-CBC,",      .algo = "aes",      .keylen = 192 / 8, .mode = cm_cbc, },
-      { .name = "AES-256-CBC,",      .algo = "aes",      .keylen = 256 / 8, .mode = cm_cbc, },
-      { .name = "AES-128-CFB,",      .algo = "aes",      .keylen = 128 / 8, .mode = cm_cfb, },
-      { .name = "AES-192-CFB,",      .algo = "aes",      .keylen = 192 / 8, .mode = cm_cfb, },
-      { .name = "AES-256-CFB,",      .algo = "aes",      .keylen = 256 / 8, .mode = cm_cfb, },
-      { .name = "AES-128-CTR,",      .algo = "aes",      .keylen = 128 / 8, .mode = cm_ctr, },
-      { .name = "AES-192-CTR,",      .algo = "aes",      .keylen = 192 / 8, .mode = cm_ctr, },
-      { .name = "AES-256-CTR,",      .algo = "aes",      .keylen = 256 / 8, .mode = cm_ctr, },
-      { .name = "AES-128-OFB,",      .algo = "aes",      .keylen = 128 / 8, .mode = cm_ofb, },
-      { .name = "AES-192-OFB,",      .algo = "aes",      .keylen = 192 / 8, .mode = cm_ofb, },
-      { .name = "AES-256-OFB,",      .algo = "aes",      .keylen = 256 / 8, .mode = cm_ofb, },
-      { .name = "BF-CBC,",           .algo = "blowfish", .keylen = 128 / 8, .mode = cm_cbc, },
-      { .name = "BF-CFB,",           .algo = "blowfish", .keylen = 128 / 8, .mode = cm_cfb, },
-      { .name = "BF-OFB,",           .algo = "blowfish", .keylen = 128 / 8, .mode = cm_ofb, },
-      { .name = "CAMELLIA-128-CBC,", .algo = "camellia", .keylen = 128 / 8, .mode = cm_cbc, },
-      { .name = "CAMELLIA-192-CBC,", .algo = "camellia", .keylen = 192 / 8, .mode = cm_cbc, },
-      { .name = "CAMELLIA-256-CBC,", .algo = "camellia", .keylen = 256 / 8, .mode = cm_cbc, },
-      { .name = "CAMELLIA-128-CFB,", .algo = "camellia", .keylen = 128 / 8, .mode = cm_cfb, },
-      { .name = "CAMELLIA-192-CFB,", .algo = "camellia", .keylen = 192 / 8, .mode = cm_cfb, },
-      { .name = "CAMELLIA-256-CFB,", .algo = "camellia", .keylen = 256 / 8, .mode = cm_cfb, },
-      { .name = "CAMELLIA-128-CTR,", .algo = "camellia", .keylen = 128 / 8, .mode = cm_ctr, },
-      { .name = "CAMELLIA-192-CTR,", .algo = "camellia", .keylen = 192 / 8, .mode = cm_ctr, },
-      { .name = "CAMELLIA-256-CTR,", .algo = "camellia", .keylen = 256 / 8, .mode = cm_ctr, },
-      { .name = "CAMELLIA-128-OFB,", .algo = "camellia", .keylen = 128 / 8, .mode = cm_ofb, },
-      { .name = "CAMELLIA-192-OFB,", .algo = "camellia", .keylen = 192 / 8, .mode = cm_ofb, },
-      { .name = "CAMELLIA-256-OFB,", .algo = "camellia", .keylen = 256 / 8, .mode = cm_ofb, },
-      { .name = "CAST5-CBC,",        .algo = "cast5",    .keylen = 128 / 8, .mode = cm_cbc, },
-      { .name = "CAST5-CFB,",        .algo = "cast5",    .keylen = 128 / 8, .mode = cm_cfb, },
-      { .name = "CAST5-OFB,",        .algo = "cast5",    .keylen = 128 / 8, .mode = cm_ofb, },
-      { .name = "DES-EDE3-CBC,",     .algo = "3des",     .keylen = 192 / 8, .mode = cm_cbc, },
-      { .name = "DES-EDE3-CFB,",     .algo = "3des",     .keylen = 192 / 8, .mode = cm_cfb, },
-      { .name = "DES-EDE3-OFB,",     .algo = "3des",     .keylen = 192 / 8, .mode = cm_ofb, },
-      { .name = "DES-CBC,",          .algo = "des",      .keylen =  64 / 8, .mode = cm_cbc, },
-      { .name = "DES-CFB,",          .algo = "des",      .keylen =  64 / 8, .mode = cm_cfb, },
-      { .name = "DES-OFB,",          .algo = "des",      .keylen =  64 / 8, .mode = cm_ofb, },
-      { .name = "IDEA-CBC,",         .algo = "idea",     .keylen = 128 / 8, .mode = cm_cbc, },
-      { .name = "IDEA-CFB,",         .algo = "idea",     .keylen = 128 / 8, .mode = cm_cfb, },
-      { .name = "IDEA-OFB,",         .algo = "idea",     .keylen = 128 / 8, .mode = cm_ofb, },
-      { .name = "RC5-CBC,",          .algo = "rc5",      .keylen = 128 / 8, .mode = cm_cbc, },
-      { .name = "RC5-CFB,",          .algo = "rc5",      .keylen = 128 / 8, .mode = cm_cfb, },
-      { .name = "RC5-OFB,",          .algo = "rc5",      .keylen = 128 / 8, .mode = cm_ofb, },
-      { .name = "RC2-40-CBC,",       .algo = "rc2",      .keylen =  40 / 8, .mode = cm_cbc, },
-      { .name = "RC2-64-CBC,",       .algo = "rc2",      .keylen =  64 / 8, .mode = cm_cbc, },
-      { .name = "RC2-CBC,",          .algo = "rc2",      .keylen = 128 / 8, .mode = cm_cbc, },
-      { .name = "RC2-CFB,",          .algo = "rc2",      .keylen = 128 / 8, .mode = cm_cfb, },
-      { .name = "RC2-OFB,",          .algo = "rc2",      .keylen = 128 / 8, .mode = cm_ofb, },
-      { .name = "SEED-CBC,",         .algo = "seed",     .keylen = 128 / 8, .mode = cm_cbc, },
-      { .name = "SEED-CFB,",         .algo = "seed",     .keylen = 128 / 8, .mode = cm_cfb, },
-      { .name = "SEED-OFB,",         .algo = "seed",     .keylen = 128 / 8, .mode = cm_ofb, },
+      { .name = "AES-128-CBC,",      .algo = "aes",      .keylen = 128 / 8, .mode = cm_cbc,    },
+      { .name = "AES-192-CBC,",      .algo = "aes",      .keylen = 192 / 8, .mode = cm_cbc,    },
+      { .name = "AES-256-CBC,",      .algo = "aes",      .keylen = 256 / 8, .mode = cm_cbc,    },
+      { .name = "AES-128-CFB,",      .algo = "aes",      .keylen = 128 / 8, .mode = cm_cfb,    },
+      { .name = "AES-192-CFB,",      .algo = "aes",      .keylen = 192 / 8, .mode = cm_cfb,    },
+      { .name = "AES-256-CFB,",      .algo = "aes",      .keylen = 256 / 8, .mode = cm_cfb,    },
+      { .name = "AES-128-CTR,",      .algo = "aes",      .keylen = 128 / 8, .mode = cm_ctr,    },
+      { .name = "AES-192-CTR,",      .algo = "aes",      .keylen = 192 / 8, .mode = cm_ctr,    },
+      { .name = "AES-256-CTR,",      .algo = "aes",      .keylen = 256 / 8, .mode = cm_ctr,    },
+      { .name = "AES-128-OFB,",      .algo = "aes",      .keylen = 128 / 8, .mode = cm_ofb,    },
+      { .name = "AES-192-OFB,",      .algo = "aes",      .keylen = 192 / 8, .mode = cm_ofb,    },
+      { .name = "AES-256-OFB,",      .algo = "aes",      .keylen = 256 / 8, .mode = cm_ofb,    },
+      { .name = "BF-CBC,",           .algo = "blowfish", .keylen = 128 / 8, .mode = cm_cbc,    },
+      { .name = "BF-CFB,",           .algo = "blowfish", .keylen = 128 / 8, .mode = cm_cfb,    },
+      { .name = "BF-OFB,",           .algo = "blowfish", .keylen = 128 / 8, .mode = cm_ofb,    },
+      { .name = "CAMELLIA-128-CBC,", .algo = "camellia", .keylen = 128 / 8, .mode = cm_cbc,    },
+      { .name = "CAMELLIA-192-CBC,", .algo = "camellia", .keylen = 192 / 8, .mode = cm_cbc,    },
+      { .name = "CAMELLIA-256-CBC,", .algo = "camellia", .keylen = 256 / 8, .mode = cm_cbc,    },
+      { .name = "CAMELLIA-128-CFB,", .algo = "camellia", .keylen = 128 / 8, .mode = cm_cfb,    },
+      { .name = "CAMELLIA-192-CFB,", .algo = "camellia", .keylen = 192 / 8, .mode = cm_cfb,    },
+      { .name = "CAMELLIA-256-CFB,", .algo = "camellia", .keylen = 256 / 8, .mode = cm_cfb,    },
+      { .name = "CAMELLIA-128-CTR,", .algo = "camellia", .keylen = 128 / 8, .mode = cm_ctr,    },
+      { .name = "CAMELLIA-192-CTR,", .algo = "camellia", .keylen = 192 / 8, .mode = cm_ctr,    },
+      { .name = "CAMELLIA-256-CTR,", .algo = "camellia", .keylen = 256 / 8, .mode = cm_ctr,    },
+      { .name = "CAMELLIA-128-OFB,", .algo = "camellia", .keylen = 128 / 8, .mode = cm_ofb,    },
+      { .name = "CAMELLIA-192-OFB,", .algo = "camellia", .keylen = 192 / 8, .mode = cm_ofb,    },
+      { .name = "CAMELLIA-256-OFB,", .algo = "camellia", .keylen = 256 / 8, .mode = cm_ofb,    },
+      { .name = "CAST5-CBC,",        .algo = "cast5",    .keylen = 128 / 8, .mode = cm_cbc,    },
+      { .name = "CAST5-CFB,",        .algo = "cast5",    .keylen = 128 / 8, .mode = cm_cfb,    },
+      { .name = "CAST5-OFB,",        .algo = "cast5",    .keylen = 128 / 8, .mode = cm_ofb,    },
+      { .name = "ChaCha20,",         .algo = "chacha20", .keylen = 256 / 8, .mode = cm_stream, },
+      { .name = "DES-EDE-CBC,",      .algo = "3des",     .keylen = 128 / 8, .mode = cm_cbc,    },
+      { .name = "DES-EDE-CFB,",      .algo = "3des",     .keylen = 128 / 8, .mode = cm_cfb,    },
+      { .name = "DES-EDE-OFB,",      .algo = "3des",     .keylen = 128 / 8, .mode = cm_ofb,    },
+      { .name = "DES-EDE3-CBC,",     .algo = "3des",     .keylen = 192 / 8, .mode = cm_cbc,    },
+      { .name = "DES-EDE3-CFB,",     .algo = "3des",     .keylen = 192 / 8, .mode = cm_cfb,    },
+      { .name = "DES-EDE3-OFB,",     .algo = "3des",     .keylen = 192 / 8, .mode = cm_ofb,    },
+      { .name = "DES-CBC,",          .algo = "des",      .keylen =  64 / 8, .mode = cm_cbc,    },
+      { .name = "DES-CFB,",          .algo = "des",      .keylen =  64 / 8, .mode = cm_cfb,    },
+      { .name = "DES-OFB,",          .algo = "des",      .keylen =  64 / 8, .mode = cm_ofb,    },
+      { .name = "DESX-CBC,",         .algo = "desx",     .keylen = 192 / 8, .mode = cm_cbc,    },
+      { .name = "IDEA-CBC,",         .algo = "idea",     .keylen = 128 / 8, .mode = cm_cbc,    },
+      { .name = "IDEA-CFB,",         .algo = "idea",     .keylen = 128 / 8, .mode = cm_cfb,    },
+      { .name = "IDEA-OFB,",         .algo = "idea",     .keylen = 128 / 8, .mode = cm_ofb,    },
+      { .name = "RC5-CBC,",          .algo = "rc5",      .keylen = 128 / 8, .mode = cm_cbc,    },
+      { .name = "RC5-CFB,",          .algo = "rc5",      .keylen = 128 / 8, .mode = cm_cfb,    },
+      { .name = "RC5-OFB,",          .algo = "rc5",      .keylen = 128 / 8, .mode = cm_ofb,    },
+      { .name = "RC2-40-CBC,",       .algo = "rc2",      .keylen =  40 / 8, .mode = cm_cbc,    },
+      { .name = "RC2-64-CBC,",       .algo = "rc2",      .keylen =  64 / 8, .mode = cm_cbc,    },
+      { .name = "RC2-CBC,",          .algo = "rc2",      .keylen = 128 / 8, .mode = cm_cbc,    },
+      { .name = "RC2-CFB,",          .algo = "rc2",      .keylen = 128 / 8, .mode = cm_cfb,    },
+      { .name = "RC2-OFB,",          .algo = "rc2",      .keylen = 128 / 8, .mode = cm_ofb,    },
+      { .name = "SEED-CBC,",         .algo = "seed",     .keylen = 128 / 8, .mode = cm_cbc,    },
+      { .name = "SEED-CFB,",         .algo = "seed",     .keylen = 128 / 8, .mode = cm_cfb,    },
+      { .name = "SEED-OFB,",         .algo = "seed",     .keylen = 128 / 8, .mode = cm_ofb,    },
    };
    };
 const unsigned long pem_dek_infos_num = sizeof(pem_dek_infos)/sizeof(pem_dek_infos[0]);
 const unsigned long pem_dek_infos_num = sizeof(pem_dek_infos)/sizeof(pem_dek_infos[0]);
 
 
 int pem_decrypt(unsigned char *data, unsigned long *datalen,
 int pem_decrypt(unsigned char *data, unsigned long *datalen,
                 unsigned char *key,  unsigned long keylen,
                 unsigned char *key,  unsigned long keylen,
                 unsigned char *iv,   unsigned long ivlen,
                 unsigned char *iv,   unsigned long ivlen,
+                unsigned char *tag,  unsigned long taglen,
                 const struct blockcipher_info *info,
                 const struct blockcipher_info *info,
                 enum padding_type padding)
                 enum padding_type padding)
 {
 {
-   int err, cipher;
+   int err, cipher = -1;
    struct {
    struct {
       union {
       union {
 #ifdef LTC_CBC_MODE
 #ifdef LTC_CBC_MODE
@@ -151,10 +157,13 @@ int pem_decrypt(unsigned char *data, unsigned long *datalen,
 #endif
 #endif
       } ctx;
       } ctx;
    } s;
    } s;
+   enum cipher_mode mode = info->mode & cm_modes;
 
 
-   cipher = find_cipher(info->algo);
-   if (cipher == -1) {
-      return CRYPT_INVALID_CIPHER;
+   if (mode != cm_stream) {
+      cipher = find_cipher(info->algo);
+      if (cipher == -1) {
+         return CRYPT_INVALID_CIPHER;
+      }
    }
    }
 
 
    switch (info->mode) {
    switch (info->mode) {
@@ -222,6 +231,50 @@ int pem_decrypt(unsigned char *data, unsigned long *datalen,
          }
          }
 #else
 #else
          return CRYPT_INVALID_CIPHER;
          return CRYPT_INVALID_CIPHER;
+#endif
+         break;
+      case cm_gcm:
+#ifdef LTC_GCM_MODE
+         if ((err = gcm_memory(cipher,
+                               key, keylen,
+                               iv, ivlen,
+                               NULL, 0,
+                               data, *datalen, data,
+                               tag, &taglen,
+                               GCM_DECRYPT)) != CRYPT_OK) {
+            goto error_out;
+         }
+#else
+         LTC_UNUSED_PARAM(tag);
+         LTC_UNUSED_PARAM(taglen);
+         return CRYPT_INVALID_CIPHER;
+#endif
+         break;
+      case cm_stream:
+#ifdef LTC_CHACHA
+         LTC_ARGCHK(ivlen == 16);
+
+         if ((err = chacha_memory(key, keylen, 20,
+                                  iv, ivlen, 0,
+                                  data, *datalen, data)) != CRYPT_OK) {
+            goto error_out;
+         }
+#else
+         return CRYPT_INVALID_CIPHER;
+#endif
+         break;
+      case cm_stream_openssh:
+#ifdef LTC_CHACHA20POLY1305_MODE
+         if ((err = chacha20poly1305_memory(key, 32,
+                                            iv, ivlen,
+                                            NULL, 0,
+                                            data, *datalen, data,
+                                            tag, &taglen,
+                                            CHACHA20POLY1305_DECRYPT | CHACHA20POLY1305_OPENSSH_COMPAT)) != CRYPT_OK) {
+            goto error_out;
+         }
+#else
+         return CRYPT_INVALID_CIPHER;
 #endif
 #endif
          break;
          break;
       default:
       default:

+ 2 - 6
src/misc/pem/pem_pkcs.c

@@ -16,12 +16,8 @@ static int s_decrypt_pem(unsigned char *pem, unsigned long *l, const struct pem_
 {
 {
    unsigned char iv[MAXBLOCKSIZE], key[MAXBLOCKSIZE];
    unsigned char iv[MAXBLOCKSIZE], key[MAXBLOCKSIZE];
    unsigned long ivlen, klen;
    unsigned long ivlen, klen;
-   int err, cipher;
+   int err;
 
 
-   cipher = find_cipher(hdr->info.algo);
-   if (cipher == -1) {
-      return CRYPT_INVALID_CIPHER;
-   }
    if (hdr->info.keylen > sizeof(key)) {
    if (hdr->info.keylen > sizeof(key)) {
       return CRYPT_BUFFER_OVERFLOW;
       return CRYPT_BUFFER_OVERFLOW;
    }
    }
@@ -38,7 +34,7 @@ static int s_decrypt_pem(unsigned char *pem, unsigned long *l, const struct pem_
       return err;
       return err;
    }
    }
 
 
-   err = pem_decrypt(pem, l, key, klen, iv, ivlen, &hdr->info, LTC_PAD_PKCS7);
+   err = pem_decrypt(pem, l, key, klen, iv, ivlen, NULL, 0, &hdr->info, LTC_PAD_PKCS7);
 
 
    zeromem(key, sizeof(key));
    zeromem(key, sizeof(key));
    zeromem(iv, sizeof(iv));
    zeromem(iv, sizeof(iv));

+ 57 - 38
src/misc/pem/pem_ssh.c

@@ -17,31 +17,35 @@
  */
  */
 const struct blockcipher_info ssh_ciphers[] =
 const struct blockcipher_info ssh_ciphers[] =
 {
 {
-   { .name = "none",            .algo = "",         .keylen = 0,       .mode = cm_none },
-   { .name = "aes128-cbc",      .algo = "aes",      .keylen = 128 / 8, .mode = cm_cbc  },
-   { .name = "aes128-ctr",      .algo = "aes",      .keylen = 128 / 8, .mode = cm_ctr  },
-   { .name = "aes192-cbc",      .algo = "aes",      .keylen = 192 / 8, .mode = cm_cbc  },
-   { .name = "aes192-ctr",      .algo = "aes",      .keylen = 192 / 8, .mode = cm_ctr  },
-   { .name = "aes256-cbc",      .algo = "aes",      .keylen = 256 / 8, .mode = cm_cbc  },
-   { .name = "aes256-ctr",      .algo = "aes",      .keylen = 256 / 8, .mode = cm_ctr  },
-   { .name = "blowfish128-cbc", .algo = "blowfish", .keylen = 128 / 8, .mode = cm_cbc  },
-   { .name = "blowfish128-ctr", .algo = "blowfish", .keylen = 128 / 8, .mode = cm_ctr  },
-   { .name = "des-cbc",         .algo = "des",      .keylen = 64 / 8,  .mode = cm_cbc  },
-   { .name = "3des-cbc",        .algo = "3des",     .keylen = 192 / 8, .mode = cm_cbc  },
-   { .name = "3des-ctr",        .algo = "3des",     .keylen = 192 / 8, .mode = cm_ctr  },
-   { .name = "serpent128-cbc",  .algo = "serpent",  .keylen = 128 / 8, .mode = cm_cbc  },
-   { .name = "serpent128-ctr",  .algo = "serpent",  .keylen = 128 / 8, .mode = cm_ctr  },
-   { .name = "serpent192-cbc",  .algo = "serpent",  .keylen = 192 / 8, .mode = cm_cbc  },
-   { .name = "serpent192-ctr",  .algo = "serpent",  .keylen = 192 / 8, .mode = cm_ctr  },
-   { .name = "serpent256-cbc",  .algo = "serpent",  .keylen = 256 / 8, .mode = cm_cbc  },
-   { .name = "serpent256-ctr",  .algo = "serpent",  .keylen = 256 / 8, .mode = cm_ctr  },
-   { .name = "twofish128-cbc",  .algo = "twofish",  .keylen = 128 / 8, .mode = cm_cbc  },
-   { .name = "twofish128-ctr",  .algo = "twofish",  .keylen = 128 / 8, .mode = cm_ctr  },
-   { .name = "twofish192-cbc",  .algo = "twofish",  .keylen = 192 / 8, .mode = cm_cbc  },
-   { .name = "twofish192-ctr",  .algo = "twofish",  .keylen = 192 / 8, .mode = cm_ctr  },
-   { .name = "twofish-cbc",     .algo = "twofish",  .keylen = 256 / 8, .mode = cm_cbc  },
-   { .name = "twofish256-cbc",  .algo = "twofish",  .keylen = 256 / 8, .mode = cm_cbc  },
-   { .name = "twofish256-ctr",  .algo = "twofish",  .keylen = 256 / 8, .mode = cm_ctr  },
+   { .name = "none",                          .algo = "",         .keylen = 0,       .mode = cm_none                },
+   { .name = "aes128-cbc",                    .algo = "aes",      .keylen = 128 / 8, .mode = cm_cbc                 },
+   { .name = "aes128-ctr",                    .algo = "aes",      .keylen = 128 / 8, .mode = cm_ctr                 },
+   { .name = "aes192-cbc",                    .algo = "aes",      .keylen = 192 / 8, .mode = cm_cbc                 },
+   { .name = "aes192-ctr",                    .algo = "aes",      .keylen = 192 / 8, .mode = cm_ctr                 },
+   { .name = "aes256-cbc",                    .algo = "aes",      .keylen = 256 / 8, .mode = cm_cbc                 },
+   { .name = "aes256-ctr",                    .algo = "aes",      .keylen = 256 / 8, .mode = cm_ctr                 },
+   { .name = "[email protected]",        .algo = "aes",      .keylen = 128 / 8, .mode = cm_gcm                 },
+   { .name = "[email protected]",        .algo = "aes",      .keylen = 256 / 8, .mode = cm_gcm                 },
+   { .name = "blowfish128-cbc",               .algo = "blowfish", .keylen = 128 / 8, .mode = cm_cbc                 },
+   { .name = "blowfish128-ctr",               .algo = "blowfish", .keylen = 128 / 8, .mode = cm_ctr                 },
+   /* The algo name doesn't matter, it's only used in pem-info */
+   { .name = "[email protected]", .algo = "c20p1305", .keylen = 256 / 8, .mode = cm_stream | cm_openssh },
+   { .name = "des-cbc",                       .algo = "des",      .keylen = 64 / 8,  .mode = cm_cbc                 },
+   { .name = "3des-cbc",                      .algo = "3des",     .keylen = 192 / 8, .mode = cm_cbc                 },
+   { .name = "3des-ctr",                      .algo = "3des",     .keylen = 192 / 8, .mode = cm_ctr                 },
+   { .name = "serpent128-cbc",                .algo = "serpent",  .keylen = 128 / 8, .mode = cm_cbc                 },
+   { .name = "serpent128-ctr",                .algo = "serpent",  .keylen = 128 / 8, .mode = cm_ctr                 },
+   { .name = "serpent192-cbc",                .algo = "serpent",  .keylen = 192 / 8, .mode = cm_cbc                 },
+   { .name = "serpent192-ctr",                .algo = "serpent",  .keylen = 192 / 8, .mode = cm_ctr                 },
+   { .name = "serpent256-cbc",                .algo = "serpent",  .keylen = 256 / 8, .mode = cm_cbc                 },
+   { .name = "serpent256-ctr",                .algo = "serpent",  .keylen = 256 / 8, .mode = cm_ctr                 },
+   { .name = "twofish128-cbc",                .algo = "twofish",  .keylen = 128 / 8, .mode = cm_cbc                 },
+   { .name = "twofish128-ctr",                .algo = "twofish",  .keylen = 128 / 8, .mode = cm_ctr                 },
+   { .name = "twofish192-cbc",                .algo = "twofish",  .keylen = 192 / 8, .mode = cm_cbc                 },
+   { .name = "twofish192-ctr",                .algo = "twofish",  .keylen = 192 / 8, .mode = cm_ctr                 },
+   { .name = "twofish-cbc",                   .algo = "twofish",  .keylen = 256 / 8, .mode = cm_cbc                 },
+   { .name = "twofish256-cbc",                .algo = "twofish",  .keylen = 256 / 8, .mode = cm_cbc                 },
+   { .name = "twofish256-ctr",                .algo = "twofish",  .keylen = 256 / 8, .mode = cm_ctr                 },
 };
 };
 const unsigned long ssh_ciphers_num = sizeof(ssh_ciphers)/sizeof(ssh_ciphers[0]);
 const unsigned long ssh_ciphers_num = sizeof(ssh_ciphers)/sizeof(ssh_ciphers[0]);
 
 
@@ -403,21 +407,33 @@ static int s_decode_key(const unsigned char *in, unsigned long *inlen, ltc_pka_k
    return remaining ? padding_depad(p, &remaining, LTC_PAD_SSH) : CRYPT_OK;
    return remaining ? padding_depad(p, &remaining, LTC_PAD_SSH) : CRYPT_OK;
 }
 }
 
 
-static int s_decrypt_private_keys(unsigned char *in, unsigned long *inlen, struct kdf_options *opts)
+static int s_decrypt_private_keys(unsigned char *in, unsigned long *inlen,
+                                  unsigned char *tag, unsigned long taglen,
+                                  struct kdf_options *opts)
 {
 {
    int err, cipher;
    int err, cipher;
-   unsigned long symkey_len;
-   unsigned char symkey[MAXBLOCKSIZE];
+   unsigned long symkey_len, iv_len;
+   unsigned char symkey[MAXBLOCKSIZE], *iv, iv_[8] = { 0 };
+   enum cipher_mode mode = opts->cipher->mode & cm_modes;
 
 
    LTC_ARGCHK(in    != NULL);
    LTC_ARGCHK(in    != NULL);
    LTC_ARGCHK(inlen != NULL);
    LTC_ARGCHK(inlen != NULL);
    LTC_ARGCHK(opts  != NULL);
    LTC_ARGCHK(opts  != NULL);
 
 
-   cipher = find_cipher(opts->cipher->algo);
-   if (cipher == -1) {
-      return CRYPT_INVALID_CIPHER;
+   if (mode != cm_stream) {
+      cipher = find_cipher(opts->cipher->algo);
+      if (cipher == -1) {
+         return CRYPT_INVALID_CIPHER;
+      }
+
+      iv = symkey + opts->cipher->keylen;
+      iv_len = mode == cm_gcm ? 12 : cipher_descriptor[cipher].block_length;
+      symkey_len = opts->cipher->keylen + iv_len;
+   } else {
+      iv = iv_;
+      iv_len = sizeof(iv_);
+      symkey_len = 64;
    }
    }
-   symkey_len = opts->cipher->keylen + cipher_descriptor[cipher].block_length;
 
 
    if (sizeof(symkey) < symkey_len) {
    if (sizeof(symkey) < symkey_len) {
       return CRYPT_OVERFLOW;
       return CRYPT_OVERFLOW;
@@ -427,12 +443,11 @@ static int s_decrypt_private_keys(unsigned char *in, unsigned long *inlen, struc
                                    opts->num_rounds, find_hash("sha512"), symkey, &symkey_len)) != CRYPT_OK) {
                                    opts->num_rounds, find_hash("sha512"), symkey, &symkey_len)) != CRYPT_OK) {
       return err;
       return err;
    }
    }
-
    err = pem_decrypt(in, inlen,
    err = pem_decrypt(in, inlen,
                      symkey, opts->cipher->keylen,
                      symkey, opts->cipher->keylen,
-                     symkey + opts->cipher->keylen, cipher_descriptor[cipher].block_length,
+                     iv, iv_len,
+                     tag, taglen,
                      opts->cipher, LTC_PAD_SSH);
                      opts->cipher, LTC_PAD_SSH);
-
    zeromem(symkey, sizeof(symkey));
    zeromem(symkey, sizeof(symkey));
 
 
    return err;
    return err;
@@ -522,8 +537,8 @@ static const unsigned long pem_openssh_num = sizeof(pem_openssh)/sizeof(pem_open
 
 
 static int s_decode_openssh(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_ctx)
 static int s_decode_openssh(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_ctx)
 {
 {
-   unsigned char *pem = NULL, *p, *privkey = NULL;
-   unsigned long n, w, l, privkey_len;
+   unsigned char *pem = NULL, *p, *privkey = NULL, *tag;
+   unsigned long n, w, l, privkey_len, taglen;
    int err;
    int err;
    struct pem_headers hdr;
    struct pem_headers hdr;
    struct kdf_options opts = { 0 };
    struct kdf_options opts = { 0 };
@@ -575,8 +590,12 @@ retry:
             err = CRYPT_ERROR;
             err = CRYPT_ERROR;
             goto cleanup;
             goto cleanup;
          }
          }
+         tag = p + w;
+         taglen = l - w;
          w = privkey_len;
          w = privkey_len;
-         if ((err = s_decrypt_private_keys(privkey, &privkey_len, &opts)) != CRYPT_OK) {
+         if ((err = s_decrypt_private_keys(privkey, &privkey_len,
+                                           tag, taglen,
+                                           &opts)) != CRYPT_OK) {
             goto cleanup;
             goto cleanup;
          }
          }
          zeromem(opts.pw.pw, opts.pw.l);
          zeromem(opts.pw.pw, opts.pw.l);

+ 15 - 5
src/stream/chacha/chacha_memory.c

@@ -9,11 +9,12 @@
    Encrypt (or decrypt) bytes of ciphertext (or plaintext) with ChaCha
    Encrypt (or decrypt) bytes of ciphertext (or plaintext) with ChaCha
    @param key     The key
    @param key     The key
    @param keylen  The key length
    @param keylen  The key length
+   @param rounds  The number of rounds
    @param iv      The initial vector
    @param iv      The initial vector
    @param ivlen   The initial vector length
    @param ivlen   The initial vector length
+   @param counter initial counter value, either ignored, 32- or 64-bit, depending on ivlen
    @param datain  The plaintext (or ciphertext)
    @param datain  The plaintext (or ciphertext)
    @param datalen The length of the input and output (octets)
    @param datalen The length of the input and output (octets)
-   @param rounds  The number of rounds
    @param dataout [out] The ciphertext (or plaintext)
    @param dataout [out] The ciphertext (or plaintext)
    @return CRYPT_OK if successful
    @return CRYPT_OK if successful
 */
 */
@@ -23,14 +24,23 @@ int chacha_memory(const unsigned char *key,    unsigned long keylen,  unsigned l
 {
 {
    chacha_state st;
    chacha_state st;
    int err;
    int err;
+   const unsigned char *iv_ = iv;
+   unsigned long ivlen_ = ivlen;
+   ulong64 counter_ = counter;
+
+   if (ivlen == 16) {
+      LOAD64L(counter_, iv);
+      iv_ += 8;
+      ivlen_ -=8;
+   }
 
 
-   LTC_ARGCHK(ivlen <= 8 || counter < 4294967296);       /* 2**32 */
+   LTC_ARGCHK(ivlen_ <= 8 || counter_ < CONST64(4294967296));       /* 2**32 */
 
 
    if ((err = chacha_setup(&st, key, keylen, rounds))       != CRYPT_OK) goto WIPE_KEY;
    if ((err = chacha_setup(&st, key, keylen, rounds))       != CRYPT_OK) goto WIPE_KEY;
-   if (ivlen > 8) {
-        if ((err = chacha_ivctr32(&st, iv, ivlen, (ulong32)counter)) != CRYPT_OK) goto WIPE_KEY;
+   if (ivlen_ > 8) {
+        if ((err = chacha_ivctr32(&st, iv_, ivlen_, (ulong32)counter_)) != CRYPT_OK) goto WIPE_KEY;
    } else {
    } else {
-        if ((err = chacha_ivctr64(&st, iv, ivlen, counter)) != CRYPT_OK) goto WIPE_KEY;
+        if ((err = chacha_ivctr64(&st, iv_, ivlen_, counter_)) != CRYPT_OK) goto WIPE_KEY;
    }
    }
    err = chacha_crypt(&st, datain, datalen, dataout);
    err = chacha_crypt(&st, datain, datalen, dataout);
 WIPE_KEY:
 WIPE_KEY:

+ 0 - 0
tests/pem/pkcs/unsupported/rsa-chacha20.pem → tests/pem/pkcs/rsa-chacha20.pem


+ 0 - 0
tests/pem/pkcs/unsupported/rsa-des-ede-cbc.pem → tests/pem/pkcs/rsa-des-ede-cbc.pem


+ 0 - 0
tests/pem/pkcs/unsupported/rsa-des-ede-cfb.pem → tests/pem/pkcs/rsa-des-ede-cfb.pem


+ 0 - 0
tests/pem/pkcs/unsupported/rsa-des-ede-ofb.pem → tests/pem/pkcs/rsa-des-ede-ofb.pem


+ 0 - 0
tests/pem/pkcs/unsupported/rsa-desx-cbc.pem → tests/pem/pkcs/rsa-desx-cbc.pem


+ 0 - 0
tests/pem/pubkeys/ssh_dsa_1024_openssh.pub → tests/pem/pubkeys/authorized_keys/ssh_dsa_1024_openssh.pub


+ 0 - 0
tests/pem/pubkeys/ssh_ecdsa_256_openssh.pub → tests/pem/pubkeys/authorized_keys/ssh_ecdsa_256_openssh.pub


+ 0 - 0
tests/pem/pubkeys/ssh_ecdsa_384_openssh.pub → tests/pem/pubkeys/authorized_keys/ssh_ecdsa_384_openssh.pub


+ 0 - 0
tests/pem/pubkeys/ssh_ecdsa_521_openssh.pub → tests/pem/pubkeys/authorized_keys/ssh_ecdsa_521_openssh.pub


+ 0 - 0
tests/pem/pubkeys/ssh_ed25519_openssh.pub → tests/pem/pubkeys/authorized_keys/ssh_ed25519_openssh.pub


+ 0 - 0
tests/pem/pubkeys/ssh_rsa_1024_openssh.pub → tests/pem/pubkeys/authorized_keys/ssh_rsa_1024_openssh.pub


+ 0 - 0
tests/pem/pubkeys/ssh_rsa_1536_openssh.pub → tests/pem/pubkeys/authorized_keys/ssh_rsa_1536_openssh.pub


+ 0 - 0
tests/pem/pubkeys/ssh_rsa_2048_openssh.pub → tests/pem/pubkeys/authorized_keys/ssh_rsa_2048_openssh.pub


+ 0 - 0
tests/pem/pubkeys/ssh_rsa_4096_openssh.pub → tests/pem/pubkeys/authorized_keys/ssh_rsa_4096_openssh.pub


+ 0 - 0
tests/pem/pubkeys/ssh_rsa_768_openssh.pub → tests/pem/pubkeys/authorized_keys/ssh_rsa_768_openssh.pub


+ 0 - 0
tests/pem/pubkeys/ssh_rsa_8192_openssh.pub → tests/pem/pubkeys/authorized_keys/ssh_rsa_8192_openssh.pub


+ 0 - 0
tests/pem/ssh/unsupported/ssh-rsa-3des-cbc.pub → tests/pem/ssh/authorized_keys/ssh-rsa-3des-cbc.pub


+ 0 - 0
tests/pem/ssh/unsupported/ssh-rsa-aes128-cbc.pub → tests/pem/ssh/authorized_keys/ssh-rsa-aes128-cbc.pub


+ 0 - 0
tests/pem/ssh/unsupported/ssh-rsa-aes128-ctr.pub → tests/pem/ssh/authorized_keys/ssh-rsa-aes128-ctr.pub


+ 0 - 0
tests/pem/ssh/unsupported/ssh-rsa-aes128-gcm.pub → tests/pem/ssh/authorized_keys/ssh-rsa-aes128-gcm.pub


+ 0 - 0
tests/pem/ssh/unsupported/ssh-rsa-aes192-cbc.pub → tests/pem/ssh/authorized_keys/ssh-rsa-aes192-cbc.pub


+ 0 - 0
tests/pem/ssh/unsupported/ssh-rsa-aes192-ctr.pub → tests/pem/ssh/authorized_keys/ssh-rsa-aes192-ctr.pub


+ 0 - 0
tests/pem/ssh/unsupported/ssh-rsa-aes256-cbc.pub → tests/pem/ssh/authorized_keys/ssh-rsa-aes256-cbc.pub


+ 0 - 0
tests/pem/ssh/unsupported/ssh-rsa-aes256-ctr.pub → tests/pem/ssh/authorized_keys/ssh-rsa-aes256-ctr.pub


+ 0 - 0
tests/pem/ssh/unsupported/ssh-rsa-aes256-gcm.pub → tests/pem/ssh/authorized_keys/ssh-rsa-aes256-gcm.pub


+ 0 - 0
tests/pem/ssh/unsupported/ssh-rsa-chacha20-poly1305.pub → tests/pem/ssh/authorized_keys/ssh-rsa-chacha20-poly1305.pub


+ 0 - 0
tests/pem/ssh/unsupported/ssh-rsa-aes128-gcm → tests/pem/ssh/ssh-rsa-aes128-gcm


+ 0 - 0
tests/pem/ssh/unsupported/ssh-rsa-aes256-gcm → tests/pem/ssh/ssh-rsa-aes256-gcm


+ 0 - 0
tests/pem/ssh/unsupported/ssh-rsa-chacha20-poly1305 → tests/pem/ssh/ssh-rsa-chacha20-poly1305


+ 2 - 0
tests/pem_test.c

@@ -141,6 +141,8 @@ int pem_test(void)
    DO(test_process_dir("tests/pem/ssh", &key, s_pem_decode_ssh, NULL, (dir_cleanup_cb)pka_key_free, "pem_ssh_test"));
    DO(test_process_dir("tests/pem/ssh", &key, s_pem_decode_ssh, NULL, (dir_cleanup_cb)pka_key_free, "pem_ssh_test"));
    DO(test_process_dir("tests/pem/ssh", &key, NULL, s_pem_decode_ssh_f, (dir_cleanup_cb)pka_key_free, "pem_ssh_test_filehandle"));
    DO(test_process_dir("tests/pem/ssh", &key, NULL, s_pem_decode_ssh_f, (dir_cleanup_cb)pka_key_free, "pem_ssh_test_filehandle"));
    DO(test_process_dir("tests/pem/ssh/extra", &key, s_pem_decode_ssh, NULL, (dir_cleanup_cb)pka_key_free, "pem_ssh_test+extra"));
    DO(test_process_dir("tests/pem/ssh/extra", &key, s_pem_decode_ssh, NULL, (dir_cleanup_cb)pka_key_free, "pem_ssh_test+extra"));
+   DO(test_process_dir("tests/pem/pubkeys", &key, s_pem_only_decode, NULL, (dir_cleanup_cb)pka_key_free, "pem_pubkeys_test"));
+   DO(test_process_dir("tests/pem/pubkeys", &key, NULL, s_pem_only_decode_f, (dir_cleanup_cb)pka_key_free, "pem_pubkeys_test_filehandle"));
 #endif
 #endif
    DO(test_process_dir("tests/pem", &key, s_pem_only_decode, NULL, (dir_cleanup_cb)pka_key_free, "pem_test"));
    DO(test_process_dir("tests/pem", &key, s_pem_only_decode, NULL, (dir_cleanup_cb)pka_key_free, "pem_test"));
    DO(test_process_dir("tests/pem", &key, NULL, s_pem_only_decode_f, (dir_cleanup_cb)pka_key_free, "pem_test_filehandle"));
    DO(test_process_dir("tests/pem", &key, NULL, s_pem_only_decode_f, (dir_cleanup_cb)pka_key_free, "pem_test_filehandle"));

+ 1 - 0
tests/test.c

@@ -149,6 +149,7 @@ static void s_unregister_all(void)
 #endif
 #endif
 #ifdef LTC_DES
 #ifdef LTC_DES
   unregister_cipher(&des_desc);
   unregister_cipher(&des_desc);
+  unregister_cipher(&desx_desc);
   unregister_cipher(&des3_desc);
   unregister_cipher(&des3_desc);
 #endif
 #endif
 #ifdef LTC_CAST5
 #ifdef LTC_CAST5