Browse Source

Merge pull request #450 from libtom/pr/ecdsa-der-attempt1

Fix #449 (ECDSA forcing DER/ASN.1)
Steffen Jaeckel 7 months ago
parent
commit
a6b9aff7aa

+ 97 - 53
doc/crypt.tex

@@ -1,4 +1,5 @@
 \documentclass[synpaper]{book}
+\usepackage[T1]{fontenc}
 \usepackage{geometry}
 \usepackage{hyperref}
 \usepackage{makeidx}
@@ -44,6 +45,7 @@
 \def\C{{\mathbb C}}
 \def\Q{{\mathbb Q}}
 \definecolor{DGray}{gray}{0.5}
+\newcommand{\code}[1]{\texttt{\textit{#1}}}
 \newcommand{\emailaddr}[1]{\mbox{$<${#1}$>$}}
 \def\twiddle{\raisebox{0.3ex}{\mbox{\tiny $\sim$}}}
 \def\gap{\vspace{0.5ex}}
@@ -5801,8 +5803,14 @@ The imported key is stored in the ECC key pointed to by \textit{key}.  The funct
 
 
 \mysection{Signatures (ECDSA)}
-There are also functions to sign and verify messages. They use the ANSI X9.62 ECDSA algorithm to generate and verify signatures in the
-ANSI X9.62 format.
+There are also functions to sign and verify messages. They use the \textit{ANSI X9.62} \textit{ECDSA} algorithm to generate and verify signatures in the
+\textit{ANSI X9.62} format.
+
+\textbf{BEWARE:} With \textit{ECC} if you try to sign a hash that is bigger than your \textit{ECC} key you can run into problems. The math
+will still work, and in effect the signature will still work.  With \textit{ECC} keys the strength of the signature is limited
+by the size of the hash, or the size of the key, whichever is smaller.  For example, if you sign with SHA256 and a
+P--192 key, you have in effect 96--bits of security. The library will not warn you if you make this mistake, so it
+is important to check yourself before using the signatures.
 
 \subsection{Signature Generation}
 To sign a message digest (hash) use the following function:
@@ -5815,12 +5823,12 @@ int ecc_sign_hash(const unsigned char *in,
                         unsigned long *outlen,
                            prng_state *prng,
                                   int  wprng,
-                              ecc_key *key);
+                  const       ecc_key *key);
 \end{verbatim}
 
-This function will ECDSA sign the message digest stored in the array pointed to by \textit{in} of length \textit{inlen} octets.  The signature
-will be stored in the array pointed to by \textit{out} of length \textit{outlen} octets.  The function requires a properly seeded PRNG, and
-the ECC \textit{key} provided must be a private key.
+This function will \textit{ECDSA} sign the message digest stored in the array pointed to by \code{in} of length \code{inlen} octets.  The signature
+will be stored in the array pointed to by \code{out} of length \code{outlen} octets.  The function requires a properly seeded \textit{PRNG}, and
+the \textit{ECC} \code{key} provided must be a private key.
 
 \index{ecc\_sign\_hash\_rfc7518()}
 \begin{verbatim}
@@ -5830,27 +5838,53 @@ int ecc_sign_hash_rfc7518(const unsigned char *in,
                                 unsigned long *outlen,
                                    prng_state *prng,
                                           int  wprng,
-                                      ecc_key *key);
+                          const       ecc_key *key);
 \end{verbatim}
 
-This function creates the same ECDSA signature as \textit{ecc\_sign\_hash} only the output format is different.
+This function creates the same \textit{ECDSA} signature as \code{ecc\_sign\_hash()} only the output format is different.
 The format follows \url{https://tools.ietf.org/html/rfc7518#section-3.4}, sometimes it is also called plain signature.
 
-\index{ecc\_sign\_hash\_ex()}
+\index{ecc\_sign\_hash\_rfc7518\_ex()}
 \begin{verbatim}
-int ecc_sign_hash_ex(const unsigned char *in,
-                           unsigned long  inlen,
-                           unsigned char *out,
-                           unsigned long *outlen,
-                              prng_state *prng,
-                                     int  wprng,
-                      ecc_signature_type  sigformat,
-                                     int *recid,
-                                 ecc_key *key);
+int ecc_sign_hash_rfc7518_ex(const unsigned char *in,
+                                   unsigned long  inlen,
+                                   unsigned char *out,
+                                   unsigned long *outlen,
+                                      prng_state *prng,
+                                             int  wprng,
+                                             int *recid,
+                             const       ecc_key *key);
+\end{verbatim}
+
+This function is an extended version of the \textit{ECDSA} signature in \code{ecc\_sign\_hash\_rfc7518()}, but with an additional output of the recovery ID
+for use with \code{ecc\_recover\_key()}.
+
+\index{ecc\_sign\_hash\_rfc5656()}
+\begin{verbatim}
+int ecc_sign_hash_rfc5656(const unsigned char *in,
+                                unsigned long  inlen,
+                                unsigned char *out,
+                                unsigned long *outlen,
+                                   prng_state *prng,
+                                          int  wprng,
+                          const       ecc_key *key);
+\end{verbatim}
+
+This function creates an \textit{ECDSA} signature and the output format is according to \textit{RFC5656}, i.e. \textit{SSH} compatible.
+
+\index{ecc\_sign\_hash\_eth27()}
+\begin{verbatim}
+int ecc_sign_hash_eth27(const unsigned char *in,
+                              unsigned long  inlen,
+                              unsigned char *out,
+                              unsigned long *outlen,
+                                 prng_state *prng,
+                                        int  wprng,
+                        const       ecc_key *key);
 \end{verbatim}
 
-This function is an extended version of the ECDSA signature in \textit{ecc\_sign\_hash}, but with a choice of output formats
-and an optional output of the recovery ID for use with \textit{ecc\_recover\_key}.
+This function creates an \textit{ECDSA} signature and the output format is according to the Ethereum format.
+With this API the curve is limited to \textit{secp256k1}.
 
 \subsection{Signature Verification}
 \index{ecc\_verify\_hash()}
@@ -5860,14 +5894,14 @@ int ecc_verify_hash(const unsigned char *sig,
                     const unsigned char *hash,
                           unsigned long  hashlen,
                                     int *stat,
-                                ecc_key *key);
+                    const       ecc_key *key);
 \end{verbatim}
 
-This function will verify the ECDSA signature in the array pointed to by \textit{sig} of length \textit{siglen} octets, against the message digest
-pointed to by the array \textit{hash} of length \textit{hashlen}. It will store a non--zero value in \textit{stat} if the signature is valid.  Note:
+This function will verify the \textit{ECDSA} signature in the array pointed to by \code{sig} of length \code{siglen} octets, against the message digest
+pointed to by the array \code{hash} of length \code{hashlen}. It will store a non--zero value in \code{stat} if the signature is valid.  Note:
 the function will not return an error if the signature is invalid. It will return an error, if the actual signature payload is an invalid format.
-The ECC \textit{key} must be the public (or private) ECC key corresponding to the key that performed the signature.
-The function \textit{ecc\_verify\_hash} implements signature format according to X9.62 ECDSA, and the output is compliant for GF(p) curves.
+The \textit{ECC} \code{key} must be the public (or private) \textit{ECC} key corresponding to the key that performed the signature.
+The function \code{ecc\_verify\_hash()} implements signature format according to \textit{ANSI X9.62} EC\textit{DSA}, and the output is compliant for GF(p) curves.
 
 \index{ecc\_verify\_hash\_rfc7518()}
 \begin{verbatim}
@@ -5876,30 +5910,36 @@ int ecc_verify_hash_rfc7518(const unsigned char *sig,
                             const unsigned char *hash,
                                   unsigned long  hashlen,
                                             int *stat,
-                                        ecc_key *key);
+                            const       ecc_key *key);
 \end{verbatim}
 
-This function validate the ECDSA signature as \textit{ecc\_verify\_hash} only the signature input format
+This function validates the \textit{ECDSA} signature as \code{ecc\_verify\_hash()}, only the signature input format
 follows \url{https://tools.ietf.org/html/rfc7518#section-3.4}.
 
-\index{ecc\_verify\_hash\_ex()}
+\index{ecc\_verify\_hash\_rfc5656()}
 \begin{verbatim}
-int ecc_verify_hash_ex(const unsigned char *sig,
-                             unsigned long  siglen,
-                       const unsigned char *hash,
-                             unsigned long  hashlen,
-                        ecc_signature_type  sigformat,
-                                       int *stat,
-                                   ecc_key *key);
+int ecc_verify_hash_rfc5656(const unsigned char *sig,
+                                  unsigned long  siglen,
+                            const unsigned char *hash,
+                                  unsigned long  hashlen,
+                                            int *stat,
+                            const       ecc_key *key);
 \end{verbatim}
 
-This function validates an ECDSA signature as \textit{ecc\_verify\_hash} but with a choice of signature formats.
+This function validates the \textit{ECDSA} signature according to the format defined in \textit{RFC5656}, i.e. \textit{SSH} compatible.
 
-{\bf BEWARE:} With ECC if you try to sign a hash that is bigger than your ECC key you can run into problems. The math
-will still work, and in effect the signature will still work.  With ECC keys the strength of the signature is limited
-by the size of the hash, or the size of the key, whichever is smaller.  For example, if you sign with SHA256 and a
-P--192 key, you have in effect 96--bits of security. The library will not warn you if you make this mistake, so it
-is important to check yourself before using the signatures.
+
+\index{ecc\_verify\_hash\_eth27()}
+\begin{verbatim}
+int ecc_verify_hash_eth27(const unsigned char *sig,
+                                unsigned long  siglen,
+                          const unsigned char *hash,
+                                unsigned long  hashlen,
+                                          int *stat,
+                          const       ecc_key *key);
+\end{verbatim}
+
+This function validates the \textit{ECDSA} signature according to the Ethereum format.
 
 \subsection{Public Key Recovery}
 \index{ecc\_recover\_key()}
@@ -5913,18 +5953,18 @@ int ecc_recover_key(const unsigned char *sig,
                                 ecc_key *key);
 \end{verbatim}
 
-This function will recover (a) public key from the ECDSA signature in the array pointed to by \textit{sig} of length \textit{siglen} octets, the message digest
-pointed to by the array \textit{hash} of length \textit{hashlen}, and the recovery id \textit{recid}. It will store the recovered
-key into \textit{key} and return CRYPT\_OK if recovery succeeds, or an error if recovery fails.
+This function will recover (a) public key from the \textit{ECDSA} signature in the array pointed to by \code{sig} of length \code{siglen} octets, the message digest
+pointed to by the array \code{hash} of length \code{hashlen}, and the recovery id \code{recid}. It will store the recovered
+key into \code{key} and return \code{CRYPT\_OK} if recovery succeeds, or an error if recovery fails.
 This is for compatibility with the (v,r,s) signatures used in Ethereum, where public keys are not explicitly shared,
-only the parity of the public key. For curves like secp256k1, recid will take values of 0 or 1, corresponding to the
-parity of the public key's y coordinate. For curves like secp112r2, with a cofactor of 4, values 0..7 are possible,
+only the parity of the public key. For curves like \textit{secp256k1}, \code{recid} will take values of 0 or 1, corresponding to the
+parity of the public key's y coordinate. For curves like \textit{secp112r2}, with a cofactor of 4, values 0..7 are possible,
 with the low bit corresponding to the parity and the higher bits specifying the public key's x coordinate's multiple
 of the curve's order.
-If the signature format contains the recovery id (currently only \textit{LTC\_ECCSIG\_ETH27}), \textit{recid} can be -1
+If the signature format contains the recovery id (currently only \code{LTC\_ECCSIG\_ETH27}), \code{recid} can be -1
 which signals that the recovery id from the signature blob should be used. This means an application does not need to
 extract the recovery id from such a signature in order to use this function.
-The function \textit{ecc\_recover\_key} implements multiple signature formats, and the output is compliant for GF(p) curves.
+The function \code{ecc\_recover\_key()} implements multiple signature formats, and the output is compliant for GF(p) curves.
 
 \subsection{Signature Formats}
 The following signature formats are suported:
@@ -5935,10 +5975,10 @@ The following signature formats are suported:
 \begin{center}
 \begin{tabular}{|l|l|}
 \hline \textbf{sigformat} & \textbf{description} \\
-\hline LTC\_ECCSIG\_ANSIX962 & ASN.1 encoded, ANSI X9.62 \\
-\hline LTC\_ECCSIG\_RFC7518 & raw R, S values as defined in RFC7518 \\
+\hline LTC\_ECCSIG\_ANSIX962 & ASN.1 encoded, \textit{ANSI X9.62} \\
+\hline LTC\_ECCSIG\_RFC7518 & raw R, S values as defined in \textit{RFC7518} \\
 \hline LTC\_ECCSIG\_ETH27 & raw R, S, V values (V has 27 added) \\
-\hline LTC\_ECCSIG\_RFC5656 & SSH+ECDSA format as defined in RFC5656 \\
+\hline LTC\_ECCSIG\_RFC5656 & \textit{SSH+ECDSA} format as defined in \textit{RFC5656} \\
 \hline
 \end{tabular}
 \end{center}
@@ -5947,9 +5987,13 @@ The following signature formats are suported:
 \label{fig:sigformat}
 \end{figure}
 
-The \textit{LTC\_ECCSIG\_ETH27} format is based on the Ethereum Yellow Paper, see \url{https://github.com/ethereum/yellowpaper}
+The \code{LTC\_ECCSIG\_ETH27} format is based on the Ethereum Yellow Paper, see \url{https://github.com/ethereum/yellowpaper}
 (Appendix F). However, convention allows the use of v=0,1 as equivalent to v=27,28 and both are accepted by
-\textit{ecc\_recover\_key}.
+\code{ecc\_recover\_key()}.
+
+\textbf{NOTE:} If you're using a tailored version of libtomcrypt, it is possible to disable \code{LTC\_DER} which will disable
+the option to use \code{LTC\_ECCSIG\_ANSIX962}. Also it is possible to disable \code{LTC\_SSH} which will disable
+the option to use \code{LTC\_ECCSIG\_RFC5656}.
 
 \mysection{Shared Secret (ECDH)}
 To construct a Diffie-Hellman shared secret with a private and public ECC key, use the following function:

+ 32 - 0
libtomcrypt_VS2008.vcproj

@@ -2510,6 +2510,22 @@
 					RelativePath="src\pk\ecc\ecc_sign_hash.c"
 					>
 				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_sign_hash_eth27.c"
+					>
+				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_sign_hash_internal.c"
+					>
+				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_sign_hash_rfc5656.c"
+					>
+				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_sign_hash_rfc7518.c"
+					>
+				</File>
 				<File
 					RelativePath="src\pk\ecc\ecc_sizes.c"
 					>
@@ -2522,6 +2538,22 @@
 					RelativePath="src\pk\ecc\ecc_verify_hash.c"
 					>
 				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_verify_hash_eth27.c"
+					>
+				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_verify_hash_internal.c"
+					>
+				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_verify_hash_rfc5656.c"
+					>
+				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_verify_hash_rfc7518.c"
+					>
+				</File>
 				<File
 					RelativePath="src\pk\ecc\ltc_ecc_export_point.c"
 					>

+ 6 - 2
makefile.mingw

@@ -193,8 +193,12 @@ src/pk/ecc/ecc_get_size.o src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.
 src/pk/ecc/ecc_import_pkcs8.o src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o \
 src/pk/ecc/ecc_recover_key.o src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o \
 src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o \
-src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o \
-src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
+src/pk/ecc/ecc_sign_hash_eth27.o src/pk/ecc/ecc_sign_hash_internal.o \
+src/pk/ecc/ecc_sign_hash_rfc5656.o src/pk/ecc/ecc_sign_hash_rfc7518.o src/pk/ecc/ecc_sizes.o \
+src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o src/pk/ecc/ecc_verify_hash_eth27.o \
+src/pk/ecc/ecc_verify_hash_internal.o src/pk/ecc/ecc_verify_hash_rfc5656.o \
+src/pk/ecc/ecc_verify_hash_rfc7518.o src/pk/ecc/ltc_ecc_export_point.o \
+src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
 src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
 src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
 src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \

+ 6 - 2
makefile.msvc

@@ -186,8 +186,12 @@ src/pk/ecc/ecc_get_size.obj src/pk/ecc/ecc_import.obj src/pk/ecc/ecc_import_open
 src/pk/ecc/ecc_import_pkcs8.obj src/pk/ecc/ecc_import_x509.obj src/pk/ecc/ecc_make_key.obj \
 src/pk/ecc/ecc_recover_key.obj src/pk/ecc/ecc_set_curve.obj src/pk/ecc/ecc_set_curve_internal.obj \
 src/pk/ecc/ecc_set_key.obj src/pk/ecc/ecc_shared_secret.obj src/pk/ecc/ecc_sign_hash.obj \
-src/pk/ecc/ecc_sizes.obj src/pk/ecc/ecc_ssh_ecdsa_encode_name.obj src/pk/ecc/ecc_verify_hash.obj \
-src/pk/ecc/ltc_ecc_export_point.obj src/pk/ecc/ltc_ecc_import_point.obj src/pk/ecc/ltc_ecc_is_point.obj \
+src/pk/ecc/ecc_sign_hash_eth27.obj src/pk/ecc/ecc_sign_hash_internal.obj \
+src/pk/ecc/ecc_sign_hash_rfc5656.obj src/pk/ecc/ecc_sign_hash_rfc7518.obj src/pk/ecc/ecc_sizes.obj \
+src/pk/ecc/ecc_ssh_ecdsa_encode_name.obj src/pk/ecc/ecc_verify_hash.obj src/pk/ecc/ecc_verify_hash_eth27.obj \
+src/pk/ecc/ecc_verify_hash_internal.obj src/pk/ecc/ecc_verify_hash_rfc5656.obj \
+src/pk/ecc/ecc_verify_hash_rfc7518.obj src/pk/ecc/ltc_ecc_export_point.obj \
+src/pk/ecc/ltc_ecc_import_point.obj src/pk/ecc/ltc_ecc_is_point.obj \
 src/pk/ecc/ltc_ecc_is_point_at_infinity.obj src/pk/ecc/ltc_ecc_map.obj src/pk/ecc/ltc_ecc_mul2add.obj \
 src/pk/ecc/ltc_ecc_mulmod.obj src/pk/ecc/ltc_ecc_mulmod_timing.obj src/pk/ecc/ltc_ecc_points.obj \
 src/pk/ecc/ltc_ecc_projective_add_point.obj src/pk/ecc/ltc_ecc_projective_dbl_point.obj \

+ 6 - 2
makefile.unix

@@ -207,8 +207,12 @@ src/pk/ecc/ecc_get_size.o src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.
 src/pk/ecc/ecc_import_pkcs8.o src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o \
 src/pk/ecc/ecc_recover_key.o src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o \
 src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o \
-src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o \
-src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
+src/pk/ecc/ecc_sign_hash_eth27.o src/pk/ecc/ecc_sign_hash_internal.o \
+src/pk/ecc/ecc_sign_hash_rfc5656.o src/pk/ecc/ecc_sign_hash_rfc7518.o src/pk/ecc/ecc_sizes.o \
+src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o src/pk/ecc/ecc_verify_hash_eth27.o \
+src/pk/ecc/ecc_verify_hash_internal.o src/pk/ecc/ecc_verify_hash_rfc5656.o \
+src/pk/ecc/ecc_verify_hash_rfc7518.o src/pk/ecc/ltc_ecc_export_point.o \
+src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
 src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
 src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
 src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \

+ 6 - 2
makefile_include.mk

@@ -369,8 +369,12 @@ src/pk/ecc/ecc_get_size.o src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.
 src/pk/ecc/ecc_import_pkcs8.o src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o \
 src/pk/ecc/ecc_recover_key.o src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o \
 src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o \
-src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o \
-src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
+src/pk/ecc/ecc_sign_hash_eth27.o src/pk/ecc/ecc_sign_hash_internal.o \
+src/pk/ecc/ecc_sign_hash_rfc5656.o src/pk/ecc/ecc_sign_hash_rfc7518.o src/pk/ecc/ecc_sizes.o \
+src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o src/pk/ecc/ecc_verify_hash_eth27.o \
+src/pk/ecc/ecc_verify_hash_internal.o src/pk/ecc/ecc_verify_hash_rfc5656.o \
+src/pk/ecc/ecc_verify_hash_rfc7518.o src/pk/ecc/ltc_ecc_export_point.o \
+src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
 src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
 src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
 src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \

+ 8 - 0
sources.cmake

@@ -426,9 +426,17 @@ src/pk/ecc/ecc_set_curve_internal.c
 src/pk/ecc/ecc_set_key.c
 src/pk/ecc/ecc_shared_secret.c
 src/pk/ecc/ecc_sign_hash.c
+src/pk/ecc/ecc_sign_hash_eth27.c
+src/pk/ecc/ecc_sign_hash_internal.c
+src/pk/ecc/ecc_sign_hash_rfc5656.c
+src/pk/ecc/ecc_sign_hash_rfc7518.c
 src/pk/ecc/ecc_sizes.c
 src/pk/ecc/ecc_ssh_ecdsa_encode_name.c
 src/pk/ecc/ecc_verify_hash.c
+src/pk/ecc/ecc_verify_hash_eth27.c
+src/pk/ecc/ecc_verify_hash_internal.c
+src/pk/ecc/ecc_verify_hash_rfc5656.c
+src/pk/ecc/ecc_verify_hash_rfc7518.c
 src/pk/ecc/ltc_ecc_export_point.c
 src/pk/ecc/ltc_ecc_import_point.c
 src/pk/ecc/ltc_ecc_is_point.c

+ 4 - 2
src/headers/tomcrypt_custom.h

@@ -622,9 +622,11 @@
    #define LTC_PKCS_8
 #endif
 
-#ifdef LTC_PKCS_8
+#if defined(LTC_PKCS_8) && defined(LTC_DER)
    #define LTC_PADDING
    #define LTC_PBES
+#else
+   #undef LTC_PKCS_8
 #endif
 
 #if defined(LTC_CLEAN_STACK)
@@ -664,7 +666,7 @@
    #error ASN.1 DER requires MPI functionality
 #endif
 
-#if (defined(LTC_MDSA) || defined(LTC_MRSA) || defined(LTC_MECC)) && !defined(LTC_DER)
+#if (defined(LTC_MDSA) || defined(LTC_MRSA)) && !defined(LTC_DER)
    #error PK requires ASN.1 DER functionality, make sure LTC_DER is enabled
 #endif
 

+ 87 - 29
src/headers/tomcrypt_pk.h

@@ -312,22 +312,25 @@ int  ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key);
 int  ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_curve *cu);
 void ecc_free(ecc_key *key);
 
+#if defined(LTC_DER)
 int  ecc_export(unsigned char *out, unsigned long *outlen, int type, const ecc_key *key);
 int  ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key);
 int  ecc_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_curve *cu);
 
-int ecc_ansi_x963_export(const ecc_key *key, unsigned char *out, unsigned long *outlen);
-int ecc_ansi_x963_import(const unsigned char *in, unsigned long inlen, ecc_key *key);
-int ecc_ansi_x963_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_curve *cu);
+int  ecc_export_openssl(unsigned char *out, unsigned long *outlen, int type, const ecc_key *key);
+int  ecc_import_openssl(const unsigned char *in, unsigned long inlen, ecc_key *key);
+int  ecc_import_pkcs8(const unsigned char *in, unsigned long inlen, const password_ctx *pw_ctx, ecc_key *key);
+int  ecc_import_x509(const unsigned char *in, unsigned long inlen, ecc_key *key);
+#endif
 
-int ecc_export_openssl(unsigned char *out, unsigned long *outlen, int type, const ecc_key *key);
-int ecc_import_openssl(const unsigned char *in, unsigned long inlen, ecc_key *key);
-int ecc_import_pkcs8(const unsigned char *in, unsigned long inlen, const password_ctx *pw_ctx, ecc_key *key);
-int ecc_import_x509(const unsigned char *in, unsigned long inlen, ecc_key *key);
+int  ecc_ansi_x963_export(const ecc_key *key, unsigned char *out, unsigned long *outlen);
+int  ecc_ansi_x963_import(const unsigned char *in, unsigned long inlen, ecc_key *key);
+int  ecc_ansi_x963_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_curve *cu);
 
 int  ecc_shared_secret(const ecc_key *private_key, const ecc_key *public_key,
                        unsigned char *out, unsigned long *outlen);
 
+#if defined(LTC_DER)
 int  ecc_encrypt_key(const unsigned char *in,   unsigned long inlen,
                            unsigned char *out,  unsigned long *outlen,
                            prng_state *prng, int wprng, int hash,
@@ -337,30 +340,85 @@ int  ecc_decrypt_key(const unsigned char *in,  unsigned long  inlen,
                            unsigned char *out, unsigned long *outlen,
                            const ecc_key *key);
 
-#define ecc_sign_hash_rfc7518(in_, inlen_, out_, outlen_, prng_, wprng_, key_) \
-   ecc_sign_hash_ex(in_, inlen_, out_, outlen_, prng_, wprng_, LTC_ECCSIG_RFC7518, NULL, key_)
-
-#define ecc_sign_hash(in_, inlen_, out_, outlen_, prng_, wprng_, key_) \
-   ecc_sign_hash_ex(in_, inlen_, out_, outlen_, prng_, wprng_, LTC_ECCSIG_ANSIX962, NULL, key_)
-
-#define ecc_verify_hash_rfc7518(sig_, siglen_, hash_, hashlen_, stat_, key_) \
-   ecc_verify_hash_ex(sig_, siglen_, hash_, hashlen_, LTC_ECCSIG_RFC7518, stat_, key_)
-
-#define ecc_verify_hash(sig_, siglen_, hash_, hashlen_, stat_, key_) \
-   ecc_verify_hash_ex(sig_, siglen_, hash_, hashlen_, LTC_ECCSIG_ANSIX962, stat_, key_)
-
-int  ecc_sign_hash_ex(const unsigned char *in,  unsigned long inlen,
-                            unsigned char *out, unsigned long *outlen,
-                            prng_state *prng, int wprng, ecc_signature_type sigformat,
-                            int *recid, const ecc_key *key);
+int ecc_sign_hash(const unsigned char *in,
+                        unsigned long  inlen,
+                        unsigned char *out,
+                        unsigned long *outlen,
+                           prng_state *prng,
+                                  int  wprng,
+                  const       ecc_key *key);
+
+int ecc_verify_hash(const unsigned char *sig,
+                          unsigned long  siglen,
+                    const unsigned char *hash,
+                          unsigned long  hashlen,
+                                    int *stat,
+                    const       ecc_key *key);
+#endif
 
-int  ecc_verify_hash_ex(const unsigned char *sig,  unsigned long siglen,
-                        const unsigned char *hash, unsigned long hashlen,
-                        ecc_signature_type sigformat, int *stat, const ecc_key *key);
+int ecc_sign_hash_rfc7518(const unsigned char *in,
+                                unsigned long  inlen,
+                                unsigned char *out,
+                                unsigned long *outlen,
+                                   prng_state *prng,
+                                          int  wprng,
+                          const       ecc_key *key);
+
+int ecc_sign_hash_rfc7518_ex(const unsigned char *in,
+                                   unsigned long  inlen,
+                                   unsigned char *out,
+                                   unsigned long *outlen,
+                                      prng_state *prng,
+                                             int  wprng,
+                                             int *recid,
+                             const       ecc_key *key);
+
+int ecc_verify_hash_rfc7518(const unsigned char *sig,
+                                  unsigned long  siglen,
+                            const unsigned char *hash,
+                                  unsigned long  hashlen,
+                                            int *stat,
+                            const       ecc_key *key);
+
+#if defined(LTC_SSH)
+int ecc_sign_hash_rfc5656(const unsigned char *in,
+                                unsigned long  inlen,
+                                unsigned char *out,
+                                unsigned long *outlen,
+                                   prng_state *prng,
+                                          int  wprng,
+                          const       ecc_key *key);
+
+int ecc_verify_hash_rfc5656(const unsigned char *sig,
+                                  unsigned long  siglen,
+                            const unsigned char *hash,
+                                  unsigned long  hashlen,
+                                            int *stat,
+                            const       ecc_key *key);
+#endif
 
-int  ecc_recover_key(const unsigned char *sig,  unsigned long siglen,
-                     const unsigned char *hash, unsigned long hashlen,
-                     int recid, ecc_signature_type sigformat, ecc_key *key);
+int ecc_sign_hash_eth27(const unsigned char *in,
+                              unsigned long  inlen,
+                              unsigned char *out,
+                              unsigned long *outlen,
+                                 prng_state *prng,
+                                        int  wprng,
+                        const       ecc_key *key);
+
+int ecc_verify_hash_eth27(const unsigned char *sig,
+                                unsigned long  siglen,
+                          const unsigned char *hash,
+                                unsigned long  hashlen,
+                                          int *stat,
+                          const       ecc_key *key);
+
+int  ecc_recover_key(const unsigned char *sig,
+                           unsigned long  siglen,
+                     const unsigned char *hash,
+                           unsigned long  hashlen,
+                                     int  recid,
+                      ecc_signature_type  sigformat,
+                                 ecc_key *key);
 
 #endif
 

+ 20 - 1
src/headers/tomcrypt_private.h

@@ -84,6 +84,7 @@ typedef int (*fn_kdf_t)(const struct password *pwd,
                               int iteration_count,  int hash_idx,
                               unsigned char *out,   unsigned long *outlen);
 
+#if defined(LTC_PBES)
 typedef struct {
    /* KDF */
    fn_kdf_t kdf;
@@ -107,6 +108,7 @@ typedef struct
    /* only used for RC2 */
    unsigned long key_bits;
 } pbes_arg;
+#endif
 
 typedef struct {
    const pbes_properties *data;
@@ -362,11 +364,14 @@ struct get_char {
 void copy_or_zeromem(const unsigned char* src, unsigned char* dest, unsigned long len, int coz);
 void password_free(struct password *pw, const struct password_ctx *ctx);
 
+#if defined(LTC_PBES)
 int pbes_decrypt(const pbes_arg  *arg, unsigned char *dec_data, unsigned long *dec_size);
 
 int pbes1_extract(const ltc_asn1_list *s, pbes_arg *res);
 int pbes2_extract(const ltc_asn1_list *s, pbes_arg *res);
+#endif
 
+#ifdef LTC_PEM
 int pem_decrypt(unsigned char *data, unsigned long *datalen,
                 unsigned char *key,  unsigned long keylen,
                 unsigned char *iv,   unsigned long ivlen,
@@ -378,6 +383,7 @@ int pem_get_char_from_file(struct get_char *g);
 #endif /* LTC_NO_FILE */
 int pem_get_char_from_buf(struct get_char *g);
 int pem_read(void *pem, unsigned long *w, struct pem_headers *hdr, struct get_char *g);
+#endif
 
 /* tomcrypt_pk.h */
 
@@ -387,10 +393,14 @@ int rand_bn_upto(void *N, void *limit, prng_state *prng, int wprng);
 int pk_get_oid(enum ltc_oid_id id, const char **st);
 int pk_get_pka_id(enum ltc_oid_id id, enum ltc_pka_id *pka);
 int pk_get_oid_id(enum ltc_pka_id pka, enum ltc_oid_id *oid);
+#ifdef LTC_DER
 int pk_get_oid_from_asn1(const ltc_asn1_list *oid, enum ltc_oid_id *id);
+#endif
 int pk_oid_str_to_num(const char *OID, unsigned long *oid, unsigned long *oidlen);
 int pk_oid_num_to_str(const unsigned long *oid, unsigned long oidlen, char *OID, unsigned long *outlen);
 
+int pk_oid_cmp_with_ulong(const char *o1, const unsigned long *o2, unsigned long o2size);
+
 /* ---- DH Routines ---- */
 #ifdef LTC_MRSA
 int rsa_init(rsa_key *key);
@@ -416,10 +426,20 @@ int ecc_set_curve_from_mpis(void *a, void *b, void *prime, void *order, void *gx
 int ecc_copy_curve(const ecc_key *srckey, ecc_key *key);
 int ecc_set_curve_by_size(int size, ecc_key *key);
 int ecc_import_subject_public_key_info(const unsigned char *in, unsigned long inlen, ecc_key *key);
+#ifdef LTC_DER
 int ecc_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, ecc_key *key);
+#endif
 int ecc_import_with_curve(const unsigned char *in, unsigned long inlen, int type, ecc_key *key);
 int ecc_import_with_oid(const unsigned char *in, unsigned long inlen, unsigned long *oid, unsigned long oid_len, int type, ecc_key *key);
 
+int ecc_sign_hash_internal(const unsigned char *in,  unsigned long inlen,
+                           void *r, void *s, prng_state *prng, int wprng,
+                           int *recid, const ecc_key *key);
+
+int ecc_verify_hash_internal(void *r, void *s,
+                             const unsigned char *hash, unsigned long hashlen,
+                             int *stat, const ecc_key *key);
+
 #ifdef LTC_SSH
 int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key *key);
 #endif
@@ -604,7 +624,6 @@ int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long i
         enum ltc_oid_id algorithm, void *public_key, unsigned long *public_key_len,
         ltc_asn1_type parameters_type, ltc_asn1_list* parameters, unsigned long *parameters_len);
 
-int pk_oid_cmp_with_ulong(const char *o1, const unsigned long *o2, unsigned long o2size);
 int pk_oid_cmp_with_asn1(const char *o1, const ltc_asn1_list *o2);
 
 #endif /* LTC_DER */

+ 2 - 2
src/pk/asn1/oid/pk_oid_cmp.c

@@ -2,8 +2,6 @@
 /* SPDX-License-Identifier: Unlicense */
 #include "tomcrypt_private.h"
 
-#ifdef LTC_DER
-
 /*
    Compare an OID string to an array of `unsigned long`.
    @return CRYPT_OK if equal
@@ -28,6 +26,8 @@ int pk_oid_cmp_with_ulong(const char *o1, const unsigned long *o2, unsigned long
    return CRYPT_OK;
 }
 
+#ifdef LTC_DER
+
 /*
    Compare an OID string to an OID element decoded from ASN.1.
    @return CRYPT_OK if equal

+ 1 - 1
src/pk/ecc/ecc_decrypt_key.c

@@ -8,7 +8,7 @@
   ECC Crypto, Tom St Denis
 */
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 /**
   Decrypt an ECC encrypted key

+ 1 - 1
src/pk/ecc/ecc_encrypt_key.c

@@ -8,7 +8,7 @@
   ECC Crypto, Tom St Denis
 */
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 /**
   Encrypt a symmetric key with ECC

+ 1 - 1
src/pk/ecc/ecc_export.c

@@ -8,7 +8,7 @@
   ECC Crypto, Tom St Denis
 */
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 /**
   Export an ECC key as a binary packet

+ 1 - 1
src/pk/ecc/ecc_export_openssl.c

@@ -3,7 +3,7 @@
 
 #include "tomcrypt_private.h"
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 /**
   Export an ECC key as a binary packet

+ 1 - 1
src/pk/ecc/ecc_import.c

@@ -8,7 +8,7 @@
   ECC Crypto, Tom St Denis
 */
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 /**
   Import an ECC key from a binary packet

+ 1 - 1
src/pk/ecc/ecc_import_openssl.c

@@ -3,7 +3,7 @@
 
 #include "tomcrypt_private.h"
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 static int s_ecc_import_private_with_oid(const unsigned char *in, unsigned long inlen, ecc_key *key)
 {

+ 1 - 1
src/pk/ecc/ecc_import_pkcs8.c

@@ -3,7 +3,7 @@
 
 #include "tomcrypt_private.h"
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 int ecc_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, ecc_key *key)
 {

+ 1 - 1
src/pk/ecc/ecc_import_x509.c

@@ -2,7 +2,7 @@
 /* SPDX-License-Identifier: Unlicense */
 #include "tomcrypt_private.h"
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 static int s_ecc_import_x509_with_oid(const unsigned char *in, unsigned long inlen, ecc_key *key)
 {

+ 12 - 13
src/pk/ecc/ecc_recover_key.c

@@ -3,9 +3,7 @@
 
 #include "tomcrypt_private.h"
 
-#ifdef LTC_MECC
-
-#ifdef LTC_ECC_SHAMIR
+#if defined(LTC_MECC) && defined(LTC_ECC_SHAMIR)
 
 /**
   @file ecc_recover_key.c
@@ -67,14 +65,7 @@ int ecc_recover_key(const unsigned char *sig,  unsigned long siglen,
       goto error;
    }
 
-   if (sigformat == LTC_ECCSIG_ANSIX962) {
-      /* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) }  */
-      if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
-                                     LTC_ASN1_INTEGER, 1UL, r,
-                                     LTC_ASN1_INTEGER, 1UL, s,
-                                     LTC_ASN1_EOL, 0UL, LTC_NULL)) != CRYPT_OK)                         { goto error; }
-   }
-   else if (sigformat == LTC_ECCSIG_RFC7518) {
+   if (sigformat == LTC_ECCSIG_RFC7518) {
       /* RFC7518 format - raw (r,s) */
       i = ltc_mp_unsigned_bin_size(key->dp.order);
       if (siglen != (2*i)) {
@@ -105,6 +96,15 @@ int ecc_recover_key(const unsigned char *sig,  unsigned long siglen,
       if ((err = ltc_mp_read_unsigned_bin(r, sig,  32)) != CRYPT_OK)                                    { goto error; }
       if ((err = ltc_mp_read_unsigned_bin(s, sig+32, 32)) != CRYPT_OK)                                  { goto error; }
    }
+#ifdef LTC_DER
+   else if (sigformat == LTC_ECCSIG_ANSIX962) {
+         /* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) }  */
+         if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
+                                                 LTC_ASN1_INTEGER, 1UL, r,
+                                                 LTC_ASN1_INTEGER, 1UL, s,
+                                                 LTC_ASN1_EOL, 0UL, LTC_NULL)) != CRYPT_OK)             { goto error; }
+   }
+#endif
 #ifdef LTC_SSH
    else if (sigformat == LTC_ECCSIG_RFC5656) {
       char name[64], name2[64];
@@ -116,7 +116,7 @@ int ecc_recover_key(const unsigned char *sig,  unsigned long siglen,
                                            LTC_SSHDATA_STRING, name, &namelen,
                                            LTC_SSHDATA_MPINT,  r,
                                            LTC_SSHDATA_MPINT,  s,
-                                           LTC_SSHDATA_EOL,    NULL)) != CRYPT_OK)                      { goto error; }
+                                           LTC_SSHDATA_EOL,    LTC_NULL)) != CRYPT_OK)                  { goto error; }
 
 
       /* Check curve matches identifier string */
@@ -257,4 +257,3 @@ error:
 }
 
 #endif
-#endif

+ 15 - 154
src/pk/ecc/ecc_sign_hash.c

@@ -3,178 +3,39 @@
 
 #include "tomcrypt_private.h"
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 /**
-  @file ecc_sign_hash.c
-  ECC Crypto, Tom St Denis
-*/
-
-/**
-  Sign a message digest
+  Sign a message digest (ANSI X9.62 format)
   @param in        The message digest to sign
   @param inlen     The length of the digest
   @param out       [out] The destination for the signature
   @param outlen    [in/out] The max size and resulting size of the signature
   @param prng      An active PRNG state
   @param wprng     The index of the PRNG you wish to use
-  @param sigformat The format of the signature to generate (ecc_signature_type)
-  @param recid     [out] The recovery ID for this signature (optional)
   @param key       A private ECC key
   @return CRYPT_OK if successful
 */
-int ecc_sign_hash_ex(const unsigned char *in,  unsigned long inlen,
-                     unsigned char *out, unsigned long *outlen,
-                     prng_state *prng, int wprng, ecc_signature_type sigformat,
-                     int *recid, const ecc_key *key)
+int ecc_sign_hash(const unsigned char *in,  unsigned long inlen,
+                  unsigned char *out, unsigned long *outlen,
+                  prng_state *prng, int wprng, const ecc_key *key)
 {
-   ecc_key       pubkey;
-   void          *r, *s, *e, *p, *b;
-   int           v = 0;
-   int           err, max_iterations = LTC_PK_MAX_RETRIES;
-   unsigned long pbits, pbytes, i, shift_right;
-   unsigned char ch, buf[MAXBLOCKSIZE];
+   int err;
+   void *r, *s;
 
-   LTC_ARGCHK(in     != NULL);
    LTC_ARGCHK(out    != NULL);
    LTC_ARGCHK(outlen != NULL);
-   LTC_ARGCHK(key    != NULL);
-
-   /* is this a private key? */
-   if (key->type != PK_PRIVATE) {
-      return CRYPT_PK_NOT_PRIVATE;
-   }
-
-   /* init the bignums */
-   if ((err = ltc_mp_init_multi(&r, &s, &e, &b, LTC_NULL)) != CRYPT_OK) {
-      return err;
-   }
-
-   /* get the hash and load it as a bignum into 'e' */
-   p = key->dp.order;
-   pbits = ltc_mp_count_bits(p);
-   pbytes = (pbits+7) >> 3;
-   if (pbits > inlen*8) {
-      if ((err = ltc_mp_read_unsigned_bin(e, in, inlen)) != CRYPT_OK)    { goto errnokey; }
-   }
-   else if (pbits % 8 == 0) {
-      if ((err = ltc_mp_read_unsigned_bin(e, in, pbytes)) != CRYPT_OK)   { goto errnokey; }
-   }
-   else {
-      shift_right = 8 - pbits % 8;
-      for (i=0, ch=0; i<pbytes; i++) {
-        buf[i] = ch;
-        ch = (in[i] << (8-shift_right));
-        buf[i] = buf[i] ^ (in[i] >> shift_right);
-      }
-      if ((err = ltc_mp_read_unsigned_bin(e, buf, pbytes)) != CRYPT_OK)  { goto errnokey; }
-   }
-
-   /* make up a key and export the public copy */
-   do {
-      if ((err = ecc_copy_curve(key, &pubkey)) != CRYPT_OK)                { goto errnokey; }
-      if ((err = ecc_generate_key(prng, wprng, &pubkey)) != CRYPT_OK)      { goto errnokey; }
 
-      /* find r = x1 mod n */
-      if ((err = ltc_mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK)               { goto error; }
-
-      if (recid || sigformat==LTC_ECCSIG_ETH27) {
-         /* find recovery ID (if needed) */
-         v = 0;
-         if (ltc_mp_copy(pubkey.pubkey.x, s) != CRYPT_OK)                      { goto error; }
-         while (ltc_mp_cmp_d(s, 0) == LTC_MP_GT && ltc_mp_cmp(s, p) != LTC_MP_LT) {
-            /* Compute x1 div n... this will almost never be reached for curves with order 1 */
-            v += 2;
-            if ((err = ltc_mp_sub(s, p, s)) != CRYPT_OK)                       { goto error; }
-         }
-         if (ltc_mp_isodd(pubkey.pubkey.y)) v += 1;
-      }
-
-      if (ltc_mp_iszero(r) == LTC_MP_YES) {
-         ecc_free(&pubkey);
-      } else {
-         if ((err = rand_bn_upto(b, p, prng, wprng)) != CRYPT_OK)          { goto error; } /* b = blinding value */
-         /* find s = (e + xr)/k */
-         if ((err = ltc_mp_mulmod(pubkey.k, b, p, pubkey.k)) != CRYPT_OK)      { goto error; } /* k = kb */
-         if ((err = ltc_mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK)         { goto error; } /* k = 1/kb */
-         if ((err = ltc_mp_mulmod(key->k, r, p, s)) != CRYPT_OK)               { goto error; } /* s = xr */
-         if ((err = ltc_mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK)             { goto error; } /* s = xr/kb */
-         if ((err = ltc_mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK)             { goto error; } /* e = e/kb */
-         if ((err = ltc_mp_add(e, s, s)) != CRYPT_OK)                          { goto error; } /* s = e/kb + xr/kb */
-         if ((err = ltc_mp_mulmod(s, b, p, s)) != CRYPT_OK)                    { goto error; } /* s = b(e/kb + xr/kb) = (e + xr)/k */
-         ecc_free(&pubkey);
-         if (ltc_mp_iszero(s) == LTC_MP_NO) {
-            break;
-         }
-      }
-   } while (--max_iterations > 0);
-
-   if (max_iterations == 0) {
-      goto errnokey;
-   }
-
-   if (recid) *recid = v;
-
-   if (sigformat == LTC_ECCSIG_ANSIX962) {
-      /* store as ASN.1 SEQUENCE { r, s -- integer } */
-      err = der_encode_sequence_multi(out, outlen,
-                               LTC_ASN1_INTEGER, 1UL, r,
-                               LTC_ASN1_INTEGER, 1UL, s,
-                               LTC_ASN1_EOL, 0UL, NULL);
-   }
-   else if (sigformat == LTC_ECCSIG_RFC7518) {
-      /* RFC7518 format - raw (r,s) */
-      if (*outlen < 2*pbytes) { err = CRYPT_MEM; goto errnokey; }
-      zeromem(out, 2*pbytes);
-      i = ltc_mp_unsigned_bin_size(r);
-      if ((err = ltc_mp_to_unsigned_bin(r, out + (pbytes - i)))   != CRYPT_OK) { goto errnokey; }
-      i = ltc_mp_unsigned_bin_size(s);
-      if ((err = ltc_mp_to_unsigned_bin(s, out + (2*pbytes - i))) != CRYPT_OK) { goto errnokey; }
-      *outlen = 2*pbytes;
-      err = CRYPT_OK;
-   }
-   else if (sigformat == LTC_ECCSIG_ETH27) {
-      /* Ethereum (v,r,s) format */
-      if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
-         /* Only valid for secp256k1 - OID 1.3.132.0.10 */
-         err = CRYPT_ERROR; goto errnokey;
-      }
-      if (*outlen < 65) { err = CRYPT_MEM; goto errnokey; }
-      zeromem(out, 65);
-      i = ltc_mp_unsigned_bin_size(r);
-      if ((err = ltc_mp_to_unsigned_bin(r, out + 32 - i)) != CRYPT_OK) { goto errnokey; }
-      i = ltc_mp_unsigned_bin_size(s);
-      if ((err = ltc_mp_to_unsigned_bin(s, out + 64 - i)) != CRYPT_OK) { goto errnokey; }
-      out[64] = (unsigned char)(v + 27); /* Recovery ID is 27/28 for Ethereum */
-      *outlen = 65;
-      err = CRYPT_OK;
-   }
-#ifdef LTC_SSH
-   else if (sigformat == LTC_ECCSIG_RFC5656) {
-      /* Get identifier string */
-      char name[64];
-      unsigned long namelen = sizeof(name);
-      if ((err = ecc_ssh_ecdsa_encode_name(name, &namelen, key)) != CRYPT_OK) { goto errnokey; }
-
-      /* Store as SSH data sequence, per RFC4251 */
-      err = ssh_encode_sequence_multi(out, outlen,
-                                      LTC_SSHDATA_STRING, name, namelen,
-                                      LTC_SSHDATA_MPINT,  r,
-                                      LTC_SSHDATA_MPINT,  s,
-                                      LTC_SSHDATA_EOL,    NULL);
-   }
-#endif
-   else {
-      /* Unknown signature format */
-      err = CRYPT_ERROR;
-      goto error;
-   }
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+   if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, NULL, key)) != CRYPT_OK) goto error;
 
-   goto errnokey;
+   /* store as ASN.1 SEQUENCE { r, s -- integer } */
+   err = der_encode_sequence_multi(out, outlen,
+                                   LTC_ASN1_INTEGER, 1UL, r,
+                                   LTC_ASN1_INTEGER, 1UL, s,
+                                   LTC_ASN1_EOL, 0UL, NULL);
 error:
-   ecc_free(&pubkey);
-errnokey:
-   ltc_mp_deinit_multi(r, s, e, b, LTC_NULL);
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
    return err;
 }
 

+ 57 - 0
src/pk/ecc/ecc_sign_hash_eth27.c

@@ -0,0 +1,57 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MECC
+
+/**
+  Sign a message digest (Ethereum format with recovery_id+27)
+  @param in        The message digest to sign
+  @param inlen     The length of the digest
+  @param out       [out] The destination for the signature
+  @param outlen    [in/out] The max size and resulting size of the signature
+  @param prng      An active PRNG state
+  @param wprng     The index of the PRNG you wish to use
+  @param key       A private ECC key
+  @return CRYPT_OK if successful
+*/
+int ecc_sign_hash_eth27(const unsigned char *in,  unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen,
+                        prng_state *prng, int wprng, const ecc_key *key)
+{
+   int err, recid;
+   void *r, *s;
+   unsigned long i;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   /* Only valid for secp256k1 - OID 1.3.132.0.10 */
+   if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
+      return CRYPT_ERROR;
+   }
+   if (*outlen < 65) {
+      *outlen = 65;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+   if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, &recid, key)) != CRYPT_OK) goto error;
+
+   zeromem(out, 65);
+   *outlen = 65;
+   i = ltc_mp_unsigned_bin_size(r);
+   if ((err = ltc_mp_to_unsigned_bin(r, out + 32 - i)) != CRYPT_OK) goto error;
+   i = ltc_mp_unsigned_bin_size(s);
+   if ((err = ltc_mp_to_unsigned_bin(s, out + 64 - i)) != CRYPT_OK) goto error;
+   out[64] = (unsigned char)(recid + 27); /* Recovery ID is 27/28 for Ethereum */
+   err = CRYPT_OK;
+
+error:
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
+   return err;
+}
+
+#endif

+ 111 - 0
src/pk/ecc/ecc_sign_hash_internal.c

@@ -0,0 +1,111 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MECC
+
+int ecc_sign_hash_internal(const unsigned char *in,  unsigned long inlen,
+                           void *r, void *s, prng_state *prng, int wprng,
+                           int *recid, const ecc_key *key)
+{
+   ecc_key       pubkey;
+   void          *e, *p, *b;
+   int           v = 0;
+   int           err, max_iterations = LTC_PK_MAX_RETRIES;
+   unsigned long pbits, pbytes, i, shift_right;
+   unsigned char ch, buf[MAXBLOCKSIZE];
+
+   LTC_ARGCHK(r      != NULL);
+   LTC_ARGCHK(s      != NULL);
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   /* is this a private key? */
+   if (key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* init the bignums */
+   if ((err = ltc_mp_init_multi(&e, &b, LTC_NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* get the hash and load it as a bignum into 'e' */
+   p = key->dp.order;
+   pbits = ltc_mp_count_bits(p);
+   pbytes = (pbits+7) >> 3;
+   if (pbits > inlen*8) {
+      if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)in, inlen)) != CRYPT_OK)    { goto errnokey; }
+   }
+   else if (pbits % 8 == 0) {
+      if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)in, pbytes)) != CRYPT_OK)   { goto errnokey; }
+   }
+   else {
+      if (pbytes >= MAXBLOCKSIZE) {
+         err = CRYPT_BUFFER_OVERFLOW;
+         goto error;
+      }
+      shift_right = 8 - pbits % 8;
+      for (i=0, ch=0; i<pbytes; i++) {
+        buf[i] = ch;
+        ch = (in[i] << (8-shift_right));
+        buf[i] = buf[i] ^ (in[i] >> shift_right);
+      }
+      if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)buf, pbytes)) != CRYPT_OK)  { goto errnokey; }
+   }
+
+   /* make up a key and export the public copy */
+   do {
+      if ((err = ecc_copy_curve(key, &pubkey)) != CRYPT_OK)                { goto errnokey; }
+      if ((err = ecc_generate_key(prng, wprng, &pubkey)) != CRYPT_OK)      { goto errnokey; }
+
+      /* find r = x1 mod n */
+      if ((err = ltc_mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK)               { goto error; }
+
+      if (recid) {
+         /* find recovery ID (if needed) */
+         v = 0;
+         if (ltc_mp_copy(pubkey.pubkey.x, s) != CRYPT_OK)                      { goto error; }
+         while (ltc_mp_cmp_d(s, 0) == LTC_MP_GT && ltc_mp_cmp(s, p) != LTC_MP_LT) {
+            /* Compute x1 div n... this will almost never be reached for curves with order 1 */
+            v += 2;
+            if ((err = ltc_mp_sub(s, p, s)) != CRYPT_OK)                       { goto error; }
+         }
+         if (ltc_mp_isodd(pubkey.pubkey.y)) v += 1;
+      }
+
+      if (ltc_mp_iszero(r) == LTC_MP_YES) {
+         ecc_free(&pubkey);
+      } else {
+         if ((err = rand_bn_upto(b, p, prng, wprng)) != CRYPT_OK)          { goto error; } /* b = blinding value */
+         /* find s = (e + xr)/k */
+         if ((err = ltc_mp_mulmod(pubkey.k, b, p, pubkey.k)) != CRYPT_OK)      { goto error; } /* k = kb */
+         if ((err = ltc_mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK)         { goto error; } /* k = 1/kb */
+         if ((err = ltc_mp_mulmod(key->k, r, p, s)) != CRYPT_OK)               { goto error; } /* s = xr */
+         if ((err = ltc_mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK)             { goto error; } /* s = xr/kb */
+         if ((err = ltc_mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK)             { goto error; } /* e = e/kb */
+         if ((err = ltc_mp_add(e, s, s)) != CRYPT_OK)                          { goto error; } /* s = e/kb + xr/kb */
+         if ((err = ltc_mp_mulmod(s, b, p, s)) != CRYPT_OK)                    { goto error; } /* s = b(e/kb + xr/kb) = (e + xr)/k */
+         ecc_free(&pubkey);
+         if (ltc_mp_iszero(s) == LTC_MP_NO) {
+            break;
+         }
+      }
+   } while (--max_iterations > 0);
+
+   if (max_iterations == 0) {
+      goto errnokey;
+   }
+
+   if (recid) *recid = v;
+
+   goto errnokey;
+error:
+   ecc_free(&pubkey);
+errnokey:
+   ltc_mp_deinit_multi(e, b, LTC_NULL);
+   return err;
+}
+
+#endif

+ 48 - 0
src/pk/ecc/ecc_sign_hash_rfc5656.c

@@ -0,0 +1,48 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#if defined(LTC_MECC) && defined(LTC_SSH)
+
+/**
+  Sign a message digest (RFC5656 / SSH format)
+  @param in        The message digest to sign
+  @param inlen     The length of the digest
+  @param out       [out] The destination for the signature
+  @param outlen    [in/out] The max size and resulting size of the signature
+  @param prng      An active PRNG state
+  @param wprng     The index of the PRNG you wish to use
+  @param key       A private ECC key
+  @return CRYPT_OK if successful
+*/
+int ecc_sign_hash_rfc5656(const unsigned char *in,  unsigned long inlen,
+                          unsigned char *out, unsigned long *outlen,
+                          prng_state *prng, int wprng, const ecc_key *key)
+{
+   int err;
+   void *r, *s;
+   char name[64];
+   unsigned long namelen = sizeof(name);
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* Get identifier string */
+   if ((err = ecc_ssh_ecdsa_encode_name(name, &namelen, key)) != CRYPT_OK) return err;
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+   if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, NULL, key)) != CRYPT_OK) goto error;
+
+   /* Store as SSH data sequence, per RFC4251 */
+   err = ssh_encode_sequence_multi(out, outlen,
+                                   LTC_SSHDATA_STRING, name, namelen,
+                                   LTC_SSHDATA_MPINT,  r,
+                                   LTC_SSHDATA_MPINT,  s,
+                                   LTC_SSHDATA_EOL,    LTC_NULL);
+error:
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
+   return err;
+}
+
+#endif

+ 73 - 0
src/pk/ecc/ecc_sign_hash_rfc7518.c

@@ -0,0 +1,73 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MECC
+
+/**
+  Sign a message digest (RFC7518 format + recovery_id)
+  @param in        The message digest to sign
+  @param inlen     The length of the digest
+  @param out       [out] The destination for the signature
+  @param outlen    [in/out] The max size and resulting size of the signature
+  @param prng      An active PRNG state
+  @param wprng     The index of the PRNG you wish to use
+  @param recid     [out] Recovery ID
+  @param key       A private ECC key
+  @return CRYPT_OK if successful
+*/
+int ecc_sign_hash_rfc7518_ex(const unsigned char *in,  unsigned long inlen,
+                             unsigned char *out, unsigned long *outlen,
+                             prng_state *prng, int wprng,
+                             int *recid, const ecc_key *key)
+{
+   int err;
+   void *r, *s;
+   unsigned long pbytes, i;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   /* RFC7518 format - raw (r,s) */
+   pbytes = ltc_mp_unsigned_bin_size(key->dp.order);
+   if (*outlen < 2 * pbytes) {
+      *outlen = 2 * pbytes;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+   if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, recid, key)) != CRYPT_OK) goto error;
+
+   zeromem(out, 2 * pbytes);
+   *outlen = 2 * pbytes;
+   i = ltc_mp_unsigned_bin_size(r);
+   if ((err = ltc_mp_to_unsigned_bin(r, out + pbytes - i)) != CRYPT_OK) goto error;
+   i = ltc_mp_unsigned_bin_size(s);
+   err = ltc_mp_to_unsigned_bin(s, out + 2 * pbytes - i);
+
+error:
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
+   return err;
+}
+
+/**
+  Sign a message digest (RFC7518 format)
+  @param in        The message digest to sign
+  @param inlen     The length of the digest
+  @param out       [out] The destination for the signature
+  @param outlen    [in/out] The max size and resulting size of the signature
+  @param prng      An active PRNG state
+  @param wprng     The index of the PRNG you wish to use
+  @param key       A private ECC key
+  @return CRYPT_OK if successful
+*/
+int ecc_sign_hash_rfc7518(const unsigned char *in,  unsigned long inlen,
+                          unsigned char *out, unsigned long *outlen,
+                          prng_state *prng, int wprng, const ecc_key *key)
+{
+   return ecc_sign_hash_rfc7518_ex(in, inlen, out, outlen, prng, wprng, NULL, key);
+}
+
+#endif

+ 14 - 173
src/pk/ecc/ecc_verify_hash.c

@@ -3,7 +3,7 @@
 
 #include "tomcrypt_private.h"
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 /**
   @file ecc_verify_hash.c
@@ -11,195 +11,36 @@
 */
 
 /**
-   Verify an ECC signature in RFC7518 format
+   Verify an ECC signature (ANSI X9.62 format)
    @param sig         The signature to verify
    @param siglen      The length of the signature (octets)
    @param hash        The hash (message digest) that was signed
    @param hashlen     The length of the hash (octets)
-   @param sigformat   The format of the signature (ecc_signature_type)
-   @param stat        Result of signature, 1==valid, 0==invalid
+   @param stat        [out] Result of signature, 1==valid, 0==invalid
    @param key         The corresponding public ECC key
    @return CRYPT_OK if successful (even if the signature is not valid)
 */
-int ecc_verify_hash_ex(const unsigned char *sig,  unsigned long siglen,
-                       const unsigned char *hash, unsigned long hashlen,
-                       ecc_signature_type sigformat, int *stat, const ecc_key *key)
+int ecc_verify_hash(const unsigned char *sig,  unsigned long siglen,
+                    const unsigned char *hash, unsigned long hashlen,
+                    int *stat, const ecc_key *key)
 {
-   ecc_point     *mG = NULL, *mQ = NULL;
-   void          *r, *s, *v, *w, *u1, *u2, *e, *p, *m, *a, *a_plus3;
-   void          *mu = NULL, *ma = NULL;
-   void          *mp = NULL;
-   int           err;
-   unsigned long pbits, pbytes, i, shift_right;
-   unsigned char ch, buf[MAXBLOCKSIZE];
+   void *r, *s;
+   int err;
 
-   LTC_ARGCHK(sig  != NULL);
-   LTC_ARGCHK(hash != NULL);
-   LTC_ARGCHK(stat != NULL);
-   LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(sig != NULL);
 
-   /* default to invalid signature */
-   *stat = 0;
+   if ((err = ltc_mp_init_multi(&r, &s, NULL)) != CRYPT_OK) return err;
 
-   /* allocate ints */
-   if ((err = ltc_mp_init_multi(&r, &s, &v, &w, &u1, &u2, &e, &a_plus3, LTC_NULL)) != CRYPT_OK) {
-      return err;
-   }
-
-   p = key->dp.order;
-   m = key->dp.prime;
-   a = key->dp.A;
-   if ((err = ltc_mp_add_d(a, 3, a_plus3)) != CRYPT_OK) {
-      goto error;
-   }
-
-   /* allocate points */
-   mG = ltc_ecc_new_point();
-   mQ = ltc_ecc_new_point();
-   if (mQ  == NULL || mG == NULL) {
-      err = CRYPT_MEM;
-      goto error;
-   }
-
-   if (sigformat == LTC_ECCSIG_ANSIX962) {
-      /* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) }  */
-      if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
+   /* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) }  */
+   if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
                                      LTC_ASN1_INTEGER, 1UL, r,
                                      LTC_ASN1_INTEGER, 1UL, s,
                                      LTC_ASN1_EOL, 0UL, LTC_NULL)) != CRYPT_OK)                         { goto error; }
-   }
-   else if (sigformat == LTC_ECCSIG_RFC7518) {
-      /* RFC7518 format - raw (r,s) */
-      i = ltc_mp_unsigned_bin_size(key->dp.order);
-      if (siglen != (2 * i)) {
-         err = CRYPT_INVALID_PACKET;
-         goto error;
-      }
-      if ((err = ltc_mp_read_unsigned_bin(r, sig,   i)) != CRYPT_OK)                                        { goto error; }
-      if ((err = ltc_mp_read_unsigned_bin(s, sig+i, i)) != CRYPT_OK)                                        { goto error; }
-   }
-   else if (sigformat == LTC_ECCSIG_ETH27) {
-      /* Ethereum (v,r,s) format */
-      if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
-         /* Only valid for secp256k1 - OID 1.3.132.0.10 */
-         err = CRYPT_ERROR; goto error;
-      }
-      if (siglen != 65) { /* Only secp256k1 curves use this format, so must be 65 bytes long */
-         err = CRYPT_INVALID_PACKET;
-         goto error;
-      }
-      if ((err = ltc_mp_read_unsigned_bin(r, sig,  32)) != CRYPT_OK)                                        { goto error; }
-      if ((err = ltc_mp_read_unsigned_bin(s, sig+32, 32)) != CRYPT_OK)                                      { goto error; }
-   }
-#ifdef LTC_SSH
-   else if (sigformat == LTC_ECCSIG_RFC5656) {
-      char name[64], name2[64];
-      unsigned long namelen = sizeof(name);
-      unsigned long name2len = sizeof(name2);
-
-      /* Decode as SSH data sequence, per RFC4251 */
-      if ((err = ssh_decode_sequence_multi(sig, &siglen,
-                                           LTC_SSHDATA_STRING, name, &namelen,
-                                           LTC_SSHDATA_MPINT,  r,
-                                           LTC_SSHDATA_MPINT,  s,
-                                           LTC_SSHDATA_EOL,    NULL)) != CRYPT_OK)                      { goto error; }
-
-
-      /* Check curve matches identifier string */
-      if ((err = ecc_ssh_ecdsa_encode_name(name2, &name2len, key)) != CRYPT_OK)                         { goto error; }
-      if ((namelen != name2len) || (XSTRCMP(name, name2) != 0)) {
-         err = CRYPT_INVALID_ARG;
-         goto error;
-      }
-   }
-#endif
-   else {
-      /* Unknown signature format */
-      err = CRYPT_ERROR;
-      goto error;
-   }
-
-   /* check for zero */
-   if (ltc_mp_cmp_d(r, 0) != LTC_MP_GT || ltc_mp_cmp_d(s, 0) != LTC_MP_GT ||
-       ltc_mp_cmp(r, p) != LTC_MP_LT || ltc_mp_cmp(s, p) != LTC_MP_LT) {
-      err = CRYPT_INVALID_PACKET;
-      goto error;
-   }
-
-   /* read hash - truncate if needed */
-   pbits = ltc_mp_count_bits(p);
-   pbytes = (pbits+7) >> 3;
-   if (pbits > hashlen*8) {
-      if ((err = ltc_mp_read_unsigned_bin(e, hash, hashlen)) != CRYPT_OK)                                   { goto error; }
-   }
-   else if (pbits % 8 == 0) {
-      if ((err = ltc_mp_read_unsigned_bin(e, hash, pbytes)) != CRYPT_OK)                                    { goto error; }
-   }
-   else {
-      shift_right = 8 - pbits % 8;
-      for (i=0, ch=0; i<pbytes; i++) {
-        buf[i] = ch;
-        ch = (hash[i] << (8-shift_right));
-        buf[i] = buf[i] ^ (hash[i] >> shift_right);
-      }
-      if ((err = ltc_mp_read_unsigned_bin(e, buf, pbytes)) != CRYPT_OK)                                     { goto error; }
-   }
-
-   /*  w  = s^-1 mod n */
-   if ((err = ltc_mp_invmod(s, p, w)) != CRYPT_OK)                                                          { goto error; }
-
-   /* u1 = ew */
-   if ((err = ltc_mp_mulmod(e, w, p, u1)) != CRYPT_OK)                                                      { goto error; }
-
-   /* u2 = rw */
-   if ((err = ltc_mp_mulmod(r, w, p, u2)) != CRYPT_OK)                                                      { goto error; }
-
-   /* find mG and mQ */
-   if ((err = ltc_ecc_copy_point(&key->dp.base, mG)) != CRYPT_OK)                                       { goto error; }
-   if ((err = ltc_ecc_copy_point(&key->pubkey, mQ)) != CRYPT_OK)                                        { goto error; }
-
-   /* find the montgomery mp */
-   if ((err = ltc_mp_montgomery_setup(m, &mp)) != CRYPT_OK)                                                 { goto error; }
-
-   /* for curves with a == -3 keep ma == NULL */
-   if (ltc_mp_cmp(a_plus3, m) != LTC_MP_EQ) {
-      if ((err = ltc_mp_init_multi(&mu, &ma, LTC_NULL)) != CRYPT_OK)                                        { goto error; }
-      if ((err = ltc_mp_montgomery_normalization(mu, m)) != CRYPT_OK)                                       { goto error; }
-      if ((err = ltc_mp_mulmod(a, mu, m, ma)) != CRYPT_OK)                                                  { goto error; }
-   }
-
-   /* compute u1*mG + u2*mQ = mG */
-   if (ltc_mp.ecc_mul2add == NULL) {
-      if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, a, m, 0)) != CRYPT_OK)                                    { goto error; }
-      if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, a, m, 0)) != CRYPT_OK)                                    { goto error; }
-
-      /* add them */
-      if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, ma, m, mp)) != CRYPT_OK)                                  { goto error; }
-
-      /* reduce */
-      if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK)                                                { goto error; }
-   } else {
-      /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
-      if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, ma, m)) != CRYPT_OK)                            { goto error; }
-   }
-
-   /* v = X_x1 mod n */
-   if ((err = ltc_mp_mod(mG->x, p, v)) != CRYPT_OK)                                                         { goto error; }
 
-   /* does v == r */
-   if (ltc_mp_cmp(v, r) == LTC_MP_EQ) {
-      *stat = 1;
-   }
+   err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
 
-   /* clear up and return */
-   err = CRYPT_OK;
 error:
-   if (mG != NULL) ltc_ecc_del_point(mG);
-   if (mQ != NULL) ltc_ecc_del_point(mQ);
-   if (mu != NULL) ltc_mp_clear(mu);
-   if (ma != NULL) ltc_mp_clear(ma);
-   ltc_mp_deinit_multi(r, s, v, w, u1, u2, e, a_plus3, LTC_NULL);
-   if (mp != NULL) ltc_mp_montgomery_free(mp);
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
    return err;
 }
 

+ 53 - 0
src/pk/ecc/ecc_verify_hash_eth27.c

@@ -0,0 +1,53 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MECC
+
+/**
+  @file ecc_verify_hash.c
+  ECC Crypto, Tom St Denis
+*/
+
+/**
+   Verify an ECC signature (Ethereum format with recovery_id+27)
+   @param sig         The signature to verify
+   @param siglen      The length of the signature (octets)
+   @param hash        The hash (message digest) that was signed
+   @param hashlen     The length of the hash (octets)
+   @param stat        [out] Result of signature, 1==valid, 0==invalid
+   @param key         The corresponding public ECC key
+   @return CRYPT_OK if successful (even if the signature is not valid)
+*/
+int ecc_verify_hash_eth27(const unsigned char *sig,  unsigned long siglen,
+                          const unsigned char *hash, unsigned long hashlen,
+                          int *stat, const ecc_key *key)
+{
+   void *r, *s;
+   int err;
+
+   LTC_ARGCHK(sig != NULL);
+   LTC_ARGCHK(key != NULL);
+
+   /* Only valid for secp256k1 - OID 1.3.132.0.10 */
+   if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
+      return CRYPT_ERROR;
+   }
+   /* Only secp256k1 curves uses this format, so must be 65 bytes long */
+   if (siglen != 65) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+   if ((err = ltc_mp_read_unsigned_bin(r, (unsigned char *)sig, 32)) != CRYPT_OK) goto error;
+   if ((err = ltc_mp_read_unsigned_bin(s, (unsigned char *)sig + 32, 32)) != CRYPT_OK) goto error;
+
+   err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
+
+error:
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
+   return err;
+}
+
+#endif

+ 137 - 0
src/pk/ecc/ecc_verify_hash_internal.c

@@ -0,0 +1,137 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MECC
+
+int ecc_verify_hash_internal(void *r, void *s,
+                             const unsigned char *hash, unsigned long hashlen,
+                             int *stat, const ecc_key *key)
+{
+   ecc_point     *mG = NULL, *mQ = NULL;
+   void          *v, *w, *u1, *u2, *e, *p, *m, *a, *a_plus3;
+   void          *mu = NULL, *ma = NULL;
+   void          *mp = NULL;
+   int           err;
+   unsigned long pbits, pbytes, i, shift_right;
+   unsigned char ch, buf[MAXBLOCKSIZE];
+
+   LTC_ARGCHK(r    != NULL);
+   LTC_ARGCHK(s    != NULL);
+   LTC_ARGCHK(hash != NULL);
+   LTC_ARGCHK(stat != NULL);
+   LTC_ARGCHK(key  != NULL);
+
+   /* default to invalid signature */
+   *stat = 0;
+
+   /* allocate ints */
+   if ((err = ltc_mp_init_multi(&v, &w, &u1, &u2, &e, &a_plus3, LTC_NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   p = key->dp.order;
+   m = key->dp.prime;
+   a = key->dp.A;
+   if ((err = ltc_mp_add_d(a, 3, a_plus3)) != CRYPT_OK) {
+      goto error;
+   }
+
+   /* allocate points */
+   mG = ltc_ecc_new_point();
+   mQ = ltc_ecc_new_point();
+   if (mQ  == NULL || mG == NULL) {
+      err = CRYPT_MEM;
+      goto error;
+   }
+
+   /* check for zero */
+   if (ltc_mp_cmp_d(r, 0) != LTC_MP_GT || ltc_mp_cmp_d(s, 0) != LTC_MP_GT ||
+       ltc_mp_cmp(r, p) != LTC_MP_LT || ltc_mp_cmp(s, p) != LTC_MP_LT) {
+      err = CRYPT_INVALID_PACKET;
+      goto error;
+   }
+
+   /* read hash - truncate if needed */
+   pbits = ltc_mp_count_bits(p);
+   pbytes = (pbits+7) >> 3;
+   if (pbits > hashlen*8) {
+      if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)hash, hashlen)) != CRYPT_OK)                  { goto error; }
+   }
+   else if (pbits % 8 == 0) {
+      if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)hash, pbytes)) != CRYPT_OK)                   { goto error; }
+   }
+   else {
+      if (pbytes >= MAXBLOCKSIZE) {
+         err = CRYPT_BUFFER_OVERFLOW;
+         goto error;
+      }
+      shift_right = 8 - pbits % 8;
+      for (i=0, ch=0; i<pbytes; i++) {
+        buf[i] = ch;
+        ch = (hash[i] << (8-shift_right));
+        buf[i] = buf[i] ^ (hash[i] >> shift_right);
+      }
+      if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)buf, pbytes)) != CRYPT_OK)                    { goto error; }
+   }
+
+   /*  w  = s^-1 mod n */
+   if ((err = ltc_mp_invmod(s, p, w)) != CRYPT_OK)                                                          { goto error; }
+
+   /* u1 = ew */
+   if ((err = ltc_mp_mulmod(e, w, p, u1)) != CRYPT_OK)                                                      { goto error; }
+
+   /* u2 = rw */
+   if ((err = ltc_mp_mulmod(r, w, p, u2)) != CRYPT_OK)                                                      { goto error; }
+
+   /* find mG and mQ */
+   if ((err = ltc_ecc_copy_point(&key->dp.base, mG)) != CRYPT_OK)                                       { goto error; }
+   if ((err = ltc_ecc_copy_point(&key->pubkey, mQ)) != CRYPT_OK)                                        { goto error; }
+
+   /* find the montgomery mp */
+   if ((err = ltc_mp_montgomery_setup(m, &mp)) != CRYPT_OK)                                                 { goto error; }
+
+   /* for curves with a == -3 keep ma == NULL */
+   if (ltc_mp_cmp(a_plus3, m) != LTC_MP_EQ) {
+      if ((err = ltc_mp_init_multi(&mu, &ma, NULL)) != CRYPT_OK)                                            { goto error; }
+      if ((err = ltc_mp_montgomery_normalization(mu, m)) != CRYPT_OK)                                       { goto error; }
+      if ((err = ltc_mp_mulmod(a, mu, m, ma)) != CRYPT_OK)                                                  { goto error; }
+   }
+
+   /* compute u1*mG + u2*mQ = mG */
+   if (ltc_mp.ecc_mul2add == NULL) {
+      if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, a, m, 0)) != CRYPT_OK)                                    { goto error; }
+      if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, a, m, 0)) != CRYPT_OK)                                    { goto error; }
+
+      /* add them */
+      if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, ma, m, mp)) != CRYPT_OK)                                  { goto error; }
+
+      /* reduce */
+      if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK)                                                { goto error; }
+   } else {
+      /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
+      if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, ma, m)) != CRYPT_OK)                            { goto error; }
+   }
+
+   /* v = X_x1 mod n */
+   if ((err = ltc_mp_mod(mG->x, p, v)) != CRYPT_OK)                                                         { goto error; }
+
+   /* does v == r */
+   if (ltc_mp_cmp(v, r) == LTC_MP_EQ) {
+      *stat = 1;
+   }
+
+   /* clear up and return */
+   err = CRYPT_OK;
+error:
+   if (mG != NULL) ltc_ecc_del_point(mG);
+   if (mQ != NULL) ltc_ecc_del_point(mQ);
+   if (mu != NULL) ltc_mp_clear(mu);
+   if (ma != NULL) ltc_mp_clear(ma);
+   ltc_mp_deinit_multi(v, w, u1, u2, e, a_plus3, LTC_NULL);
+   if (mp != NULL) ltc_mp_montgomery_free(mp);
+   return err;
+}
+
+#endif

+ 65 - 0
src/pk/ecc/ecc_verify_hash_rfc5656.c

@@ -0,0 +1,65 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#if defined(LTC_MECC) && defined(LTC_SSH)
+
+/**
+  @file ecc_verify_hash.c
+  ECC Crypto, Tom St Denis
+*/
+
+/**
+   Verify an ECC signature (RFC5656 / SSH format)
+   @param sig         The signature to verify
+   @param siglen      The length of the signature (octets)
+   @param hash        The hash (message digest) that was signed
+   @param hashlen     The length of the hash (octets)
+   @param stat        [out] Result of signature, 1==valid, 0==invalid
+   @param key         The corresponding public ECC key
+   @return CRYPT_OK if successful (even if the signature is not valid)
+*/
+int ecc_verify_hash_rfc5656(const unsigned char *sig,  unsigned long siglen,
+                            const unsigned char *hash, unsigned long hashlen,
+                            int *stat, const ecc_key *key)
+{
+   void *r, *s;
+   int err;
+   char name[64], name2[64];
+   unsigned long namelen = sizeof(name);
+   unsigned long name2len = sizeof(name2);
+   unsigned long slen = siglen;
+
+   LTC_ARGCHK(sig != NULL);
+   LTC_ARGCHK(key != NULL);
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+
+   /* Decode as SSH data sequence, per RFC4251 */
+   if ((err = ssh_decode_sequence_multi(sig, &slen,
+                                        LTC_SSHDATA_STRING, name, &namelen,
+                                        LTC_SSHDATA_MPINT,  r,
+                                        LTC_SSHDATA_MPINT,  s,
+                                        LTC_SSHDATA_EOL,    LTC_NULL)) != CRYPT_OK) goto error;
+
+   if (slen != siglen) {
+      err = CRYPT_INVALID_PACKET;
+      goto error;
+   }
+
+   /* Check curve matches identifier string */
+   if ((err = ecc_ssh_ecdsa_encode_name(name2, &name2len, key)) != CRYPT_OK) goto error;
+   if (XSTRCMP(name,name2) != 0) {
+      err = CRYPT_INVALID_ARG;
+      goto error;
+   }
+
+   err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
+
+error:
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
+   return err;
+}
+
+#endif

+ 52 - 0
src/pk/ecc/ecc_verify_hash_rfc7518.c

@@ -0,0 +1,52 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MECC
+
+/**
+  @file ecc_verify_hash.c
+  ECC Crypto, Tom St Denis
+*/
+
+/**
+   Verify an ECC signature (RFC7518 format)
+   @param sig         The signature to verify
+   @param siglen      The length of the signature (octets)
+   @param hash        The hash (message digest) that was signed
+   @param hashlen     The length of the hash (octets)
+   @param stat        [out] Result of signature, 1==valid, 0==invalid
+   @param key         The corresponding public ECC key
+   @return CRYPT_OK if successful (even if the signature is not valid)
+*/
+int ecc_verify_hash_rfc7518(const unsigned char *sig,  unsigned long siglen,
+                            const unsigned char *hash, unsigned long hashlen,
+                            int *stat, const ecc_key *key)
+{
+   void *r, *s;
+   int err;
+   unsigned long i;
+
+   LTC_ARGCHK(sig != NULL);
+   LTC_ARGCHK(key != NULL);
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+
+   /* RFC7518 format - raw (r,s) */
+   i = ltc_mp_unsigned_bin_size(key->dp.order);
+   if (siglen != (2 * i)) {
+      err = CRYPT_INVALID_PACKET;
+      goto error;
+   }
+   if ((err = ltc_mp_read_unsigned_bin(r, (unsigned char *)sig, i)) != CRYPT_OK) goto error;
+   if ((err = ltc_mp_read_unsigned_bin(s, (unsigned char *)sig + i, i)) != CRYPT_OK) goto error;
+
+   err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
+
+error:
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
+   return err;
+}
+
+#endif

+ 45 - 9
tests/ecc_test.c

@@ -616,10 +616,9 @@ static int s_ecc_new_api(void)
 #ifdef LTC_SSH
       /* test SSH+ECDSA/RFC5656 signature */
       len = sizeof(buf);
-      DO(ecc_sign_hash_ex(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"),
-                          LTC_ECCSIG_RFC5656, NULL, &privkey));
+      DO(ecc_sign_hash_rfc5656(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"), &privkey));
       stat = 0;
-      DO(ecc_verify_hash_ex(buf, len, data16, 16, LTC_ECCSIG_RFC5656, &stat, &pubkey));
+      DO(ecc_verify_hash_rfc5656(buf, len, data16, 16, &stat, &pubkey));
       if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
 #endif
 
@@ -1517,6 +1516,44 @@ static int s_ecc_import_export(void) {
 }
 
 #ifdef LTC_ECC_SHAMIR
+static int s_ecc_test_ethereum(void)
+{
+#ifdef LTC_ECC_SECP256K1
+   int stat;
+   const ltc_ecc_curve* dp;
+   ecc_key key, reckey;
+   unsigned char buf[128];
+   unsigned long len;
+   unsigned char data16[16] = { 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1 };
+
+   DO(ecc_find_curve("SECP256K1", &dp));
+
+   DO(ecc_make_key_ex(&yarrow_prng, find_prng ("yarrow"), &key, dp));
+
+   /* test Ethereum signature */
+   len = sizeof(buf);
+   DO(ecc_sign_hash_eth27(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"), &key));
+   stat = 0;
+   DO(ecc_verify_hash_eth27(buf, len, data16, 16, &stat, &key));
+   if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
+
+   /* XXX-FIXME: TFM does not support sqrtmod_prime */
+   if (strcmp(ltc_mp.name, "TomsFastMath") != 0) {
+      DO(ecc_set_curve(dp, &reckey));
+      DO(ecc_recover_key(buf, len, data16, 16, -1, LTC_ECCSIG_ETH27, &reckey));
+      DO(ecc_key_cmp(PK_PUBLIC, &key, &reckey));
+
+      /* cleanup */
+      ecc_free(&reckey);
+   }
+   /* cleanup */
+   ecc_free(&key);
+   return CRYPT_OK;
+#else
+   return CRYPT_NOP;
+#endif
+}
+
 static int s_ecc_test_recovery(void)
 {
    int i, recid, stat;
@@ -1554,14 +1591,12 @@ static int s_ecc_test_recovery(void)
    DO(ecc_set_key(eth_pubkey, sizeof(eth_pubkey), PK_PUBLIC, &pubkey));
 
    DO(ecc_set_curve(dp, &reckey));
-   stat = ecc_recover_key(eth_sig, sizeof(eth_sig)-1, eth_hash, sizeof(eth_hash), 0, LTC_ECCSIG_RFC7518, &reckey);
-   if (stat != CRYPT_OK) return CRYPT_FAIL_TESTVECTOR;
+   DO(ecc_recover_key(eth_sig, sizeof(eth_sig)-1, eth_hash, sizeof(eth_hash), 0, LTC_ECCSIG_RFC7518, &reckey));
    DO(ecc_key_cmp(PK_PUBLIC, &pubkey, &reckey));
    ecc_free(&reckey);
 
    DO(ecc_set_curve(dp, &reckey));
-   stat = ecc_recover_key(eth_sig, sizeof(eth_sig), eth_hash, sizeof(eth_hash), -1, LTC_ECCSIG_ETH27, &reckey);
-   if (stat != CRYPT_OK) return CRYPT_FAIL_TESTVECTOR;
+   DO(ecc_recover_key(eth_sig, sizeof(eth_sig), eth_hash, sizeof(eth_hash), -1, LTC_ECCSIG_ETH27, &reckey));
    DO(ecc_key_cmp(PK_PUBLIC, &pubkey, &reckey));
    ecc_free(&reckey);
 
@@ -1596,11 +1631,11 @@ static int s_ecc_test_recovery(void)
       /* test signature */
       len = sizeof(buf);
       recid = 0;
-      DO(ecc_sign_hash_ex(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"), LTC_ECCSIG_RFC7518, &recid, &privkey));
+      DO(ecc_sign_hash_rfc7518_ex(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"), &recid, &privkey));
 
       /* test verification */
       stat = 0;
-      DO(ecc_verify_hash_ex(buf, len, data16, 16, LTC_ECCSIG_RFC7518, &stat, &pubkey));
+      DO(ecc_verify_hash_rfc7518(buf, len, data16, 16, &stat, &pubkey));
       if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
 
       /* test recovery */
@@ -1633,6 +1668,7 @@ int ecc_test(void)
 #ifdef LTC_ECC_SHAMIR
    DO(s_ecc_test_shamir());
    DO(s_ecc_test_recovery());
+   DO(s_ecc_test_ethereum());
 #endif
    return CRYPT_OK;
 }