diff --git a/doc/crypt.tex b/doc/crypt.tex
index 98332af20..317fc0e6e 100644
--- a/doc/crypt.tex
+++ b/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 @@ \subsection{ANSI X9.63 Import (deprecated)}
\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 @@ \subsection{Signature Generation}
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 @@ \subsection{Signature Generation}
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 @@ \subsection{Signature Verification}
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 @@ \subsection{Signature Verification}
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 @@ \subsection{Public Key Recovery}
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 @@ \subsection{Signature Formats}
\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 @@ \subsection{Signature Formats}
\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:
diff --git a/libtomcrypt_VS2008.vcproj b/libtomcrypt_VS2008.vcproj
index 84b8555b9..fd493541d 100644
--- a/libtomcrypt_VS2008.vcproj
+++ b/libtomcrypt_VS2008.vcproj
@@ -2510,6 +2510,22 @@
RelativePath="src\pk\ecc\ecc_sign_hash.c"
>
+
+
+
+
+
+
+
+
@@ -2522,6 +2538,22 @@
RelativePath="src\pk\ecc\ecc_verify_hash.c"
>
+
+
+
+
+
+
+
+
diff --git a/makefile.mingw b/makefile.mingw
index 1234941b9..f94253c84 100644
--- a/makefile.mingw
+++ b/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 \
diff --git a/makefile.msvc b/makefile.msvc
index 99782a591..efadaf0a1 100644
--- a/makefile.msvc
+++ b/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 \
diff --git a/makefile.unix b/makefile.unix
index 46afebadc..360c6a472 100644
--- a/makefile.unix
+++ b/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 \
diff --git a/makefile_include.mk b/makefile_include.mk
index ebacc4812..bedc86f9a 100644
--- a/makefile_include.mk
+++ b/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 \
diff --git a/sources.cmake b/sources.cmake
index ee7316437..a82a6ab82 100644
--- a/sources.cmake
+++ b/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
diff --git a/src/headers/tomcrypt_custom.h b/src/headers/tomcrypt_custom.h
index e12740dde..b1731b9a3 100644
--- a/src/headers/tomcrypt_custom.h
+++ b/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
diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h
index dcf714d7d..8ba34d843 100644
--- a/src/headers/tomcrypt_pk.h
+++ b/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
diff --git a/src/headers/tomcrypt_private.h b/src/headers/tomcrypt_private.h
index 78f3d08f5..71a1ed606 100644
--- a/src/headers/tomcrypt_private.h
+++ b/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 */
diff --git a/src/pk/asn1/oid/pk_oid_cmp.c b/src/pk/asn1/oid/pk_oid_cmp.c
index 04a379bff..a62d2c638 100644
--- a/src/pk/asn1/oid/pk_oid_cmp.c
+++ b/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
diff --git a/src/pk/ecc/ecc_decrypt_key.c b/src/pk/ecc/ecc_decrypt_key.c
index ad2d9b135..6697eda00 100644
--- a/src/pk/ecc/ecc_decrypt_key.c
+++ b/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
diff --git a/src/pk/ecc/ecc_encrypt_key.c b/src/pk/ecc/ecc_encrypt_key.c
index 9929ff5af..bac62bf77 100644
--- a/src/pk/ecc/ecc_encrypt_key.c
+++ b/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
diff --git a/src/pk/ecc/ecc_export.c b/src/pk/ecc/ecc_export.c
index edbe4c39e..69b53bc71 100644
--- a/src/pk/ecc/ecc_export.c
+++ b/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
diff --git a/src/pk/ecc/ecc_export_openssl.c b/src/pk/ecc/ecc_export_openssl.c
index 35d83b706..35d8ed05d 100644
--- a/src/pk/ecc/ecc_export_openssl.c
+++ b/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
diff --git a/src/pk/ecc/ecc_import.c b/src/pk/ecc/ecc_import.c
index 48e050639..181fc9a96 100644
--- a/src/pk/ecc/ecc_import.c
+++ b/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
diff --git a/src/pk/ecc/ecc_import_openssl.c b/src/pk/ecc/ecc_import_openssl.c
index 36a1bac94..7023b84f8 100644
--- a/src/pk/ecc/ecc_import_openssl.c
+++ b/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)
{
diff --git a/src/pk/ecc/ecc_import_pkcs8.c b/src/pk/ecc/ecc_import_pkcs8.c
index f9c473b69..9df67890f 100644
--- a/src/pk/ecc/ecc_import_pkcs8.c
+++ b/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)
{
diff --git a/src/pk/ecc/ecc_import_x509.c b/src/pk/ecc/ecc_import_x509.c
index 5217c8508..2b4ea77ab 100644
--- a/src/pk/ecc/ecc_import_x509.c
+++ b/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)
{
diff --git a/src/pk/ecc/ecc_recover_key.c b/src/pk/ecc/ecc_recover_key.c
index a507a7867..3b6332b54 100644
--- a/src/pk/ecc/ecc_recover_key.c
+++ b/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 @@ int ecc_recover_key(const unsigned char *sig, unsigned long siglen,
}
#endif
-#endif
diff --git a/src/pk/ecc/ecc_sign_hash.c b/src/pk/ecc/ecc_sign_hash.c
index b50fa4f12..c9c278b31 100644
--- a/src/pk/ecc/ecc_sign_hash.c
+++ b/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> 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;
}
diff --git a/src/pk/ecc/ecc_sign_hash_eth27.c b/src/pk/ecc/ecc_sign_hash_eth27.c
new file mode 100644
index 000000000..dd06d14cb
--- /dev/null
+++ b/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
diff --git a/src/pk/ecc/ecc_sign_hash_internal.c b/src/pk/ecc/ecc_sign_hash_internal.c
new file mode 100644
index 000000000..ef4628150
--- /dev/null
+++ b/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> 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
diff --git a/src/pk/ecc/ecc_sign_hash_rfc5656.c b/src/pk/ecc/ecc_sign_hash_rfc5656.c
new file mode 100644
index 000000000..fd9f10e24
--- /dev/null
+++ b/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
diff --git a/src/pk/ecc/ecc_sign_hash_rfc7518.c b/src/pk/ecc/ecc_sign_hash_rfc7518.c
new file mode 100644
index 000000000..1faefca15
--- /dev/null
+++ b/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
diff --git a/src/pk/ecc/ecc_verify_hash.c b/src/pk/ecc/ecc_verify_hash.c
index 6c74ca448..494c474e2 100644
--- a/src/pk/ecc/ecc_verify_hash.c
+++ b/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> 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;
}
diff --git a/src/pk/ecc/ecc_verify_hash_eth27.c b/src/pk/ecc/ecc_verify_hash_eth27.c
new file mode 100644
index 000000000..587ecd2da
--- /dev/null
+++ b/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
diff --git a/src/pk/ecc/ecc_verify_hash_internal.c b/src/pk/ecc/ecc_verify_hash_internal.c
new file mode 100644
index 000000000..ae666110d
--- /dev/null
+++ b/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> 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
diff --git a/src/pk/ecc/ecc_verify_hash_rfc5656.c b/src/pk/ecc/ecc_verify_hash_rfc5656.c
new file mode 100644
index 000000000..027e4a70b
--- /dev/null
+++ b/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
diff --git a/src/pk/ecc/ecc_verify_hash_rfc7518.c b/src/pk/ecc/ecc_verify_hash_rfc7518.c
new file mode 100644
index 000000000..b048bdc20
--- /dev/null
+++ b/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
diff --git a/tests/ecc_test.c b/tests/ecc_test.c
index 74c65fcf8..6c15f4a1c 100644
--- a/tests/ecc_test.c
+++ b/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;
}