mirror of
https://github.com/libtom/libtomcrypt
synced 2026-08-25 20:26:07 -04:00
Ed448 + X448
This commit is contained in:
parent
c80285ba04
commit
076a11037a
43 changed files with 3057 additions and 11 deletions
262
doc/crypt.tex
262
doc/crypt.tex
|
|
@ -5933,16 +5933,21 @@ ECCEncrypt ::= SEQUENCE {
|
|||
\mysection{Introduction}
|
||||
|
||||
The library provides functionality for \textit{Curve25519}-based \textit{X25519} Diffie-Hellman shared secrets
|
||||
and \textit{EdDSA} a.k.a \textit{Ed25519} signature schemes.
|
||||
and \textit{EdDSA} a.k.a \textit{Ed25519} signature schemes as well as the corresponding
|
||||
\textit{Curve448}/\textit{ec448}-based \textit{X448} and \textit{Ed448} algorithms.
|
||||
|
||||
The implementation is based on the \textit{tweetnacl}\footnote{\url{https://tweetnacl.cr.yp.to/}} reference implementation
|
||||
The Curve25519 implementation is based on the \textit{tweetnacl}\footnote{\url{https://tweetnacl.cr.yp.to/}} reference implementation
|
||||
as provided by Daniel J. Bernstein et.al. and only slightly modified to better fit in the library.
|
||||
The Curve448/\textit{ec448} implementation follows the same overall code structure and arithmetic layout pattern.
|
||||
|
||||
Both algorithms share the key structure called \textit{curve25519\_key} which is used by all Curve25519 functions.
|
||||
The Curve25519 family shares the key structure called \textit{curve25519\_key} which is used by all
|
||||
Curve25519 functions. The Curve448 family uses the \textit{curve448\_key} structure.
|
||||
|
||||
As Curve25519 and Ed25519 are based on the same elliptic curve, but use different mathematics, the keys are not
|
||||
compatible to each other.
|
||||
|
||||
Likewise X448 and Ed448 keys are not compatible to each other.
|
||||
|
||||
It is possible to convert a Curve-Key to an Ed-Key and vice-versa, but this is not provided (yet).
|
||||
|
||||
|
||||
|
|
@ -5961,7 +5966,7 @@ int x25519_make_key( prng_state *prng,
|
|||
curve25519_key *key);
|
||||
\end{verbatim}
|
||||
|
||||
To generate a fresh X25529 key, one can use \textit{x25519\_make\_key} which will create a private\&public key-pair.
|
||||
To generate a fresh X25519 key, one can use \textit{x25519\_make\_key} which will create a private\&public key-pair.
|
||||
\index{x25519\_import}
|
||||
\begin{verbatim}
|
||||
int x25519_import(const unsigned char *in,
|
||||
|
|
@ -6056,7 +6061,7 @@ int ed25519_make_key( prng_state *prng,
|
|||
curve25519_key *key);
|
||||
\end{verbatim}
|
||||
|
||||
To generate a fresh Ed25529 key, one can use \textit{ed25519\_make\_key} which will create a private\&public key-pair.
|
||||
To generate a fresh Ed25519 key, one can use \textit{ed25519\_make\_key} which will create a private\&public key-pair.
|
||||
|
||||
\index{ed25519\_import}
|
||||
\begin{verbatim}
|
||||
|
|
@ -6172,6 +6177,232 @@ These functions will verify the EdDSA signature in the array pointed to by \text
|
|||
pointed to by the array \textit{msg} of length \textit{msglen}. It will store a non--zero value in \textit{stat} if the signature is valid. Note:
|
||||
the function will not return an error if the signature is invalid. It will only return an error if the actual signature payload is an invalid format.
|
||||
|
||||
\mysection{Curve448-based Diffie-Hellman Key Exchange - X448}
|
||||
|
||||
The library provides the Diffie-Hellman Key Exchange algorithm \textit{X448} for curve448 as specified in RFC 7748.
|
||||
|
||||
\subsection{X448 Key Operations}
|
||||
|
||||
The \textit{X448} algorithm API provides the following set of functions to create, import and export keys.
|
||||
|
||||
\index{x448\_make\_key}
|
||||
\begin{verbatim}
|
||||
int x448_make_key( prng_state *prng,
|
||||
int wprng,
|
||||
curve448_key *key);
|
||||
\end{verbatim}
|
||||
|
||||
To generate a fresh X448 key, one can use \textit{x448\_make\_key} which will create a private\&public key-pair.
|
||||
\index{x448\_import}
|
||||
\begin{verbatim}
|
||||
int x448_import(const unsigned char *in,
|
||||
unsigned long inlen,
|
||||
curve448_key *key);
|
||||
\end{verbatim}
|
||||
|
||||
The \textit{x448\_import} function can be used to import a public key in DER-encoded \textit{SubjectPublicKeyInfo} format.
|
||||
|
||||
\index{x448\_import\_raw}
|
||||
\begin{verbatim}
|
||||
int x448_import_raw(const unsigned char *in,
|
||||
unsigned long inlen,
|
||||
int which,
|
||||
curve448_key *key);
|
||||
\end{verbatim}
|
||||
|
||||
To import a public or private key in raw format, one can use the function \textit{x448\_import\_raw}.
|
||||
|
||||
\index{x448\_import\_x509}
|
||||
\begin{verbatim}
|
||||
int x448_import_x509(const unsigned char *in,
|
||||
unsigned long inlen,
|
||||
curve448_key *key);
|
||||
\end{verbatim}
|
||||
|
||||
To import a public key from a DER-encoded \textit{X.509} certificate, one can use the function \textit{x448\_import\_x509}.
|
||||
|
||||
\index{x448\_import\_pkcs8}
|
||||
\begin{verbatim}
|
||||
int x448_import_pkcs8(const unsigned char *in,
|
||||
unsigned long inlen,
|
||||
const password_ctx *pw_ctx,
|
||||
curve448_key *key);
|
||||
\end{verbatim}
|
||||
|
||||
To import a private key in the \textit{OneAsymmetricKey} a.k.a \textit{PKCS \#8} format, either plain or PBES encrypted,
|
||||
one can use the function \textit{x448\_import\_pkcs8}.
|
||||
|
||||
\index{x448\_export}
|
||||
\begin{verbatim}
|
||||
int x448_export( unsigned char *out,
|
||||
unsigned long *outlen,
|
||||
int which,
|
||||
const curve448_key *key);
|
||||
\end{verbatim}
|
||||
|
||||
To export a key, the function \textit{x448\_export} is provided.
|
||||
|
||||
It has support for the following output formats:
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{center}
|
||||
\begin{tabular}{|c|c|}
|
||||
\hline \textbf{which} & \textbf{output format} \\
|
||||
\hline PK\_PRIVATE & Raw \\
|
||||
\hline PK\_PRIVATE \& PK\_STD & PKCS \#8 \\
|
||||
\hline PK\_PUBLIC & Raw \\
|
||||
\hline PK\_PUBLIC \& PK\_STD & SubjectPublicKeyInfo \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
\caption{Possible x448\_export() output formats}
|
||||
\end{figure}
|
||||
|
||||
\subsection{X448 Cryptographic Operations}
|
||||
|
||||
To construct a Diffie-Hellman shared secret with a private and a public X448 key, use the following function:
|
||||
|
||||
\index{x448\_shared\_secret}
|
||||
\begin{verbatim}
|
||||
int x448_shared_secret(const curve448_key *private_key,
|
||||
const curve448_key *public_key,
|
||||
unsigned char *out,
|
||||
unsigned long *outlen);
|
||||
\end{verbatim}
|
||||
|
||||
This will construct the shared secret between the private- and the public-key and store the result in \textit{out} of length \textit{outlen}.
|
||||
|
||||
\mysection{Curve448-based EdDSA Signature Scheme - Ed448}
|
||||
|
||||
The library provides the EdDSA algorithm for the edwards448 curve in the PureEdDSA variant as specified in RFC 8032.
|
||||
|
||||
\subsection{Ed448 Key Operations}
|
||||
|
||||
The \textit{Ed448} algorithm API provides the following set of functions to create, import and export keys.
|
||||
|
||||
\index{ed448\_make\_key}
|
||||
\begin{verbatim}
|
||||
int ed448_make_key( prng_state *prng,
|
||||
int wprng,
|
||||
curve448_key *key);
|
||||
\end{verbatim}
|
||||
|
||||
To generate a fresh Ed448 key, one can use \textit{ed448\_make\_key} which will create a private\&public key-pair.
|
||||
|
||||
\index{ed448\_import}
|
||||
\begin{verbatim}
|
||||
int ed448_import(const unsigned char *in,
|
||||
unsigned long inlen,
|
||||
curve448_key *key);
|
||||
\end{verbatim}
|
||||
|
||||
The \textit{ed448\_import} function can be used to import a public key in DER-encoded \textit{SubjectPublicKeyInfo} format.
|
||||
|
||||
\index{ed448\_import\_raw}
|
||||
\begin{verbatim}
|
||||
int ed448_import_raw(const unsigned char *in,
|
||||
unsigned long inlen,
|
||||
int which,
|
||||
curve448_key *key);
|
||||
\end{verbatim}
|
||||
|
||||
To import a public or private key in raw format, one can use the function \textit{ed448\_import\_raw}.
|
||||
|
||||
\index{ed448\_import\_x509}
|
||||
\begin{verbatim}
|
||||
int ed448_import_x509(const unsigned char *in,
|
||||
unsigned long inlen,
|
||||
curve448_key *key);
|
||||
\end{verbatim}
|
||||
|
||||
To import a public key from a DER-encoded \textit{X.509} certificate, one can use the function \textit{ed448\_import\_x509}.
|
||||
|
||||
\index{ed448\_import\_pkcs8}
|
||||
\begin{verbatim}
|
||||
int ed448_import_pkcs8(const unsigned char *in,
|
||||
unsigned long inlen,
|
||||
const password_ctx *pw_ctx,
|
||||
curve448_key *key);
|
||||
\end{verbatim}
|
||||
|
||||
To import a private key in the \textit{OneAsymmetricKey} a.k.a \textit{PKCS \#8} format, either plain or PBES encrypted,
|
||||
one can use the function \textit{ed448\_import\_pkcs8}.
|
||||
|
||||
\index{ed448\_export}
|
||||
\begin{verbatim}
|
||||
int ed448_export( unsigned char *out,
|
||||
unsigned long *outlen,
|
||||
int which,
|
||||
const curve448_key *key);
|
||||
\end{verbatim}
|
||||
|
||||
To export a key, the function \textit{ed448\_export} is provided.
|
||||
|
||||
It has support for the following output formats:
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{center}
|
||||
\begin{tabular}{|c|c|}
|
||||
\hline \textbf{which} & \textbf{output format} \\
|
||||
\hline PK\_PRIVATE & Raw \\
|
||||
\hline PK\_PRIVATE \& PK\_STD & PKCS \#8 \\
|
||||
\hline PK\_PUBLIC & Raw \\
|
||||
\hline PK\_PUBLIC \& PK\_STD & SubjectPublicKeyInfo \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
\caption{Possible ed448\_export() output formats}
|
||||
\end{figure}
|
||||
|
||||
\subsection{Ed448 Cryptographic Operations}
|
||||
|
||||
To sign and/or verify a message use the following functions:
|
||||
|
||||
\index{ed448\_sign}
|
||||
\index{ed448ctx\_sign}
|
||||
\index{ed448ph\_sign}
|
||||
\begin{verbatim}
|
||||
int ed448_sign(const unsigned char *msg, unsigned long msglen,
|
||||
unsigned char *sig, unsigned long *siglen,
|
||||
const curve448_key *private_key);
|
||||
int ed448ctx_sign(const unsigned char *msg, unsigned long msglen,
|
||||
unsigned char *sig, unsigned long *siglen,
|
||||
const unsigned char *ctx, unsigned long ctxlen,
|
||||
const curve448_key *private_key);
|
||||
int ed448ph_sign(const unsigned char *msg, unsigned long msglen,
|
||||
unsigned char *sig, unsigned long *siglen,
|
||||
const unsigned char *ctx, unsigned long ctxlen,
|
||||
const curve448_key *private_key);
|
||||
\end{verbatim}
|
||||
|
||||
These functions will EdDSA sign the message stored in the array pointed to by \textit{msg} of length \textit{msglen} octets. The signature
|
||||
will be stored in the array pointed to by \textit{sig} of length \textit{siglen} octets. The \texttt{ctx} and \texttt{ph} variants also
|
||||
allow passing a context \textit{ctx} of length \textit{ctxlen} octets. This context is allowed to be max. 255 octets long.
|
||||
|
||||
\index{ed448\_verify}
|
||||
\index{ed448ctx\_verify}
|
||||
\index{ed448ph\_verify}
|
||||
\begin{verbatim}
|
||||
int ed448_verify(const unsigned char *msg, unsigned long msglen,
|
||||
const unsigned char *sig, unsigned long siglen,
|
||||
int *stat,
|
||||
const curve448_key *public_key);
|
||||
int ed448ctx_verify(const unsigned char *msg, unsigned long msglen,
|
||||
const unsigned char *sig, unsigned long siglen,
|
||||
const unsigned char *ctx, unsigned long ctxlen,
|
||||
int *stat,
|
||||
const curve448_key *public_key);
|
||||
int ed448ph_verify(const unsigned char *msg, unsigned long msglen,
|
||||
const unsigned char *sig, unsigned long siglen,
|
||||
const unsigned char *ctx, unsigned long ctxlen,
|
||||
int *stat,
|
||||
const curve448_key *public_key);
|
||||
\end{verbatim}
|
||||
|
||||
These functions will verify the EdDSA signature in the array pointed to by \textit{sig} of length \textit{siglen} octets, against the message
|
||||
pointed to by the array \textit{msg} of length \textit{msglen}. It will store a non--zero value in \textit{stat} if the signature is valid. Note:
|
||||
the function will not return an error if the signature is invalid. It will only return an error if the actual signature payload is an invalid format.
|
||||
|
||||
|
||||
\chapter{Digital Signature Algorithm}
|
||||
\mysection{Introduction}
|
||||
|
|
@ -6477,6 +6708,8 @@ enum ltc_pka_id {
|
|||
LTC_PKA_X25519,
|
||||
LTC_PKA_ED25519,
|
||||
LTC_PKA_DH,
|
||||
LTC_PKA_X448,
|
||||
LTC_PKA_ED448,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -6485,6 +6718,10 @@ typedef struct {
|
|||
curve25519_key x25519;
|
||||
curve25519_key ed25519;
|
||||
#endif
|
||||
#ifdef LTC_CURVE448
|
||||
curve448_key x448;
|
||||
curve448_key ed448;
|
||||
#endif
|
||||
#ifdef LTC_MDH
|
||||
dh_key dh;
|
||||
#endif
|
||||
|
|
@ -7766,14 +8003,14 @@ The identifiers in the PEM headers recognized are as follows:
|
|||
\begin{table}[H]
|
||||
\begin{minipage}{\textwidth}
|
||||
\begin{small}
|
||||
\begin{tabular}{|l|l|l|l|l|}
|
||||
\begin{tabular}{|l|l|l|l|p{4.1cm}|}
|
||||
\hline \textbf{Identifier} & \textbf{Key type} & \textbf{File content} & \textbf{Standard} & \textbf{Algorithm} \\
|
||||
\hline \texttt{BEGIN CERTIFICATE} & Public & Plain & \texttt{X.509} & DH, DSA, ECC, Ed25519, RSA, X25519 \\
|
||||
\hline \texttt{BEGIN CERTIFICATE} & Public & Plain & \texttt{X.509} & DH, DSA, ECC, Ed25519, Ed448, RSA, X25519, X448 \\
|
||||
\hline \texttt{BEGIN DSA PRIVATE KEY} & Private & Maybe encrypted & \texttt{OpenSSL\footnote{There are two de-facto standard for DSA private key structures, LibTomCrypt implements OpenSSL's}} & DSA \\
|
||||
\hline \texttt{BEGIN EC PRIVATE KEY} & Private & Maybe encrypted & \texttt{RFC 5915} & ECC \\
|
||||
\hline \texttt{BEGIN ENCRYPTED PRIVATE KEY} & Private & Encrypted & \texttt{PKCS \#8} & DH, DSA, ECC, Ed25519, RSA, X25519 \\
|
||||
\hline \texttt{BEGIN PRIVATE KEY} & Private & Plain & \texttt{PKCS \#8} & DH, DSA, ECC, Ed25519, RSA, X25519 \\
|
||||
\hline \texttt{BEGIN PUBLIC KEY} & Public & Plain & \texttt{X.509\footnote{Specifically, SubjectPublicKeyInfo}} & DH, DSA, ECC, Ed25519, RSA, X25519 \\
|
||||
\hline \texttt{BEGIN ENCRYPTED PRIVATE KEY} & Private & Encrypted & \texttt{PKCS \#8} & DH, DSA, ECC, Ed25519, Ed448, RSA, X25519, X448 \\
|
||||
\hline \texttt{BEGIN PRIVATE KEY} & Private & Plain & \texttt{PKCS \#8} & DH, DSA, ECC, Ed25519, Ed448, RSA, X25519, X448 \\
|
||||
\hline \texttt{BEGIN PUBLIC KEY} & Public & Plain & \texttt{X.509\footnote{Specifically, SubjectPublicKeyInfo}} & DH, DSA, ECC, Ed25519, Ed448, RSA, X25519, X448 \\
|
||||
\hline \texttt{BEGIN RSA PRIVATE KEY} & Private & Maybe encrypted & \texttt{PKCS \#1} & RSA \\
|
||||
\hline \texttt{BEGIN RSA PUBLIC KEY} & Public & Plain & \texttt{PKCS \#1} & RSA \\
|
||||
\hline
|
||||
|
|
@ -8240,8 +8477,11 @@ static const char *pka_algos[] = {
|
|||
"RSA",
|
||||
"DSA",
|
||||
"ECC",
|
||||
"Curve25519",
|
||||
"X25519",
|
||||
"Ed25519",
|
||||
"DH",
|
||||
"X448",
|
||||
"Ed448",
|
||||
};
|
||||
|
||||
static int password_get(void **p, unsigned long *l, void *u)
|
||||
|
|
|
|||
|
|
@ -454,6 +454,9 @@
|
|||
/* Ed25519 & X25519 */
|
||||
#define LTC_CURVE25519
|
||||
|
||||
/* Ed448 & X448 */
|
||||
#define LTC_CURVE448
|
||||
|
||||
/* ECC */
|
||||
#define LTC_MECC
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ enum ltc_pka_id {
|
|||
LTC_PKA_ED25519,
|
||||
LTC_PKA_DH,
|
||||
LTC_PKA_RSA_PSS,
|
||||
LTC_PKA_X448,
|
||||
LTC_PKA_ED448,
|
||||
LTC_PKA_NUM
|
||||
};
|
||||
|
||||
|
|
@ -629,6 +631,80 @@ int x25519_shared_secret(const curve25519_key *private_key,
|
|||
|
||||
#endif /* LTC_CURVE25519 */
|
||||
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
typedef struct {
|
||||
/** Type of key, PK_PRIVATE or PK_PUBLIC */
|
||||
enum public_key_type type;
|
||||
/** Algorithm: LTC_PKA_X448 or LTC_PKA_ED448 */
|
||||
enum ltc_pka_id pka;
|
||||
/** The private key (56 bytes for X448, 57 bytes for Ed448) */
|
||||
unsigned char priv[57];
|
||||
/** The public key (56 bytes for X448, 57 bytes for Ed448) */
|
||||
unsigned char pub[57];
|
||||
} curve448_key;
|
||||
|
||||
/** X448 Diffie-Hellman key exchange */
|
||||
int x448_make_key(prng_state *prng, int wprng, curve448_key *key);
|
||||
|
||||
int x448_export( unsigned char *out, unsigned long *outlen,
|
||||
int which,
|
||||
const curve448_key *key);
|
||||
|
||||
int x448_import(const unsigned char *in, unsigned long inlen, curve448_key *key);
|
||||
int x448_import_raw(const unsigned char *in, unsigned long inlen, int which, curve448_key *key);
|
||||
int x448_import_x509(const unsigned char *in, unsigned long inlen, curve448_key *key);
|
||||
int x448_import_pkcs8(const unsigned char *in, unsigned long inlen,
|
||||
const password_ctx *pw_ctx,
|
||||
curve448_key *key);
|
||||
|
||||
int x448_shared_secret(const curve448_key *private_key,
|
||||
const curve448_key *public_key,
|
||||
unsigned char *out, unsigned long *outlen);
|
||||
|
||||
/** Ed448 Signature API */
|
||||
int ed448_make_key(prng_state *prng, int wprng, curve448_key *key);
|
||||
|
||||
int ed448_export( unsigned char *out, unsigned long *outlen,
|
||||
int which,
|
||||
const curve448_key *key);
|
||||
|
||||
int ed448_import(const unsigned char *in, unsigned long inlen, curve448_key *key);
|
||||
int ed448_import_raw(const unsigned char *in, unsigned long inlen, int which, curve448_key *key);
|
||||
int ed448_import_x509(const unsigned char *in, unsigned long inlen, curve448_key *key);
|
||||
int ed448_import_pkcs8(const unsigned char *in, unsigned long inlen,
|
||||
const password_ctx *pw_ctx,
|
||||
curve448_key *key);
|
||||
|
||||
int ed448_sign(const unsigned char *msg, unsigned long msglen,
|
||||
unsigned char *sig, unsigned long *siglen,
|
||||
const curve448_key *private_key);
|
||||
int ed448ctx_sign(const unsigned char *msg, unsigned long msglen,
|
||||
unsigned char *sig, unsigned long *siglen,
|
||||
const unsigned char *ctx, unsigned long ctxlen,
|
||||
const curve448_key *private_key);
|
||||
int ed448ph_sign(const unsigned char *msg, unsigned long msglen,
|
||||
unsigned char *sig, unsigned long *siglen,
|
||||
const unsigned char *ctx, unsigned long ctxlen,
|
||||
const curve448_key *private_key);
|
||||
int ed448_verify(const unsigned char *msg, unsigned long msglen,
|
||||
const unsigned char *sig, unsigned long siglen,
|
||||
int *stat,
|
||||
const curve448_key *public_key);
|
||||
int ed448ctx_verify(const unsigned char *msg, unsigned long msglen,
|
||||
const unsigned char *sig, unsigned long siglen,
|
||||
const unsigned char *ctx, unsigned long ctxlen,
|
||||
int *stat,
|
||||
const curve448_key *public_key);
|
||||
int ed448ph_verify(const unsigned char *msg, unsigned long msglen,
|
||||
const unsigned char *sig, unsigned long siglen,
|
||||
const unsigned char *ctx, unsigned long ctxlen,
|
||||
int *stat,
|
||||
const curve448_key *public_key);
|
||||
|
||||
#endif /* LTC_CURVE448 */
|
||||
|
||||
#ifdef LTC_MDSA
|
||||
|
||||
/* Max diff between group and modulus size in bytes (max case: L=8192bits, N=256bits) */
|
||||
|
|
@ -724,6 +800,10 @@ typedef struct {
|
|||
curve25519_key x25519;
|
||||
curve25519_key ed25519;
|
||||
#endif
|
||||
#ifdef LTC_CURVE448
|
||||
curve448_key x448;
|
||||
curve448_key ed448;
|
||||
#endif
|
||||
#ifdef LTC_MDH
|
||||
dh_key dh;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ enum ltc_oid_id {
|
|||
LTC_OID_EC_PRIMEF,
|
||||
LTC_OID_X25519,
|
||||
LTC_OID_ED25519,
|
||||
LTC_OID_X448,
|
||||
LTC_OID_ED448,
|
||||
LTC_OID_DH,
|
||||
LTC_OID_RSA_OAEP,
|
||||
LTC_OID_RSA_MGF1,
|
||||
|
|
@ -713,6 +715,33 @@ int ec25519_crypto_ctx( unsigned char *out, unsigned long *outlen,
|
|||
const unsigned char *ctx, unsigned long ctxlen);
|
||||
#endif /* LTC_CURVE25519 */
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
int ec448_export(unsigned char *out, unsigned long *outlen, int which, const curve448_key *key);
|
||||
int ec448_import_pkcs8(const unsigned char *in, unsigned long inlen,
|
||||
const password_ctx *pw_ctx, enum ltc_oid_id id, curve448_key *key);
|
||||
int ec448_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key,
|
||||
enum ltc_oid_id id, curve448_key *key);
|
||||
int x448_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key,
|
||||
curve448_key *key);
|
||||
int ec448_keypair_internal(prng_state *prng, int wprng, unsigned char *pk, unsigned char *sk);
|
||||
int ec448_sk_to_pk_internal(unsigned char *pk, const unsigned char *sk);
|
||||
int ec448_sign_internal(unsigned char *sm, unsigned long long *smlen,
|
||||
const unsigned char *m, unsigned long long mlen,
|
||||
const unsigned char *sk, const unsigned char *pk,
|
||||
const unsigned char *ctx, unsigned long long cs);
|
||||
int ec448_verify_internal(int *stat, unsigned char *m, unsigned long long *mlen,
|
||||
const unsigned char *sm, unsigned long long smlen,
|
||||
const unsigned char *ctx, unsigned long long cs,
|
||||
const unsigned char *pk);
|
||||
int ec448_prehash_internal(unsigned char *out, const unsigned char *msg, unsigned long long msglen);
|
||||
int ec448_crypto_ctx(unsigned char *out, unsigned long *outlen, unsigned char flag,
|
||||
const unsigned char *ctx, unsigned long ctxlen);
|
||||
int ec448_scalarmult_internal(unsigned char *out, const unsigned char *scalar, const unsigned char *point);
|
||||
int ec448_scalarmult_base_internal(unsigned char *out, const unsigned char *scalar);
|
||||
int ed448_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key,
|
||||
curve448_key *key);
|
||||
#endif /* LTC_CURVE448 */
|
||||
|
||||
#ifdef LTC_DER
|
||||
|
||||
#define LTC_ASN1_IS_TYPE(e, t) (((e) != NULL) && ((e)->type == (t)))
|
||||
|
|
|
|||
|
|
@ -384,6 +384,10 @@ const char *crypt_build_settings =
|
|||
" X25519\n"
|
||||
#endif
|
||||
#endif
|
||||
#if defined(LTC_CURVE448)
|
||||
" Ed448\n"
|
||||
" X448\n"
|
||||
#endif
|
||||
#if defined(LTC_PK_MAX_RETRIES)
|
||||
" "NAME_VALUE(LTC_PK_MAX_RETRIES)"\n"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -63,6 +63,10 @@ static const struct {
|
|||
[LTC_OID_X25519] = { LTC_PKA_X25519, (pkcs8_import_fn)x25519_import_pkcs8_asn1 },
|
||||
[LTC_OID_ED25519] = { LTC_PKA_ED25519, (pkcs8_import_fn)ed25519_import_pkcs8_asn1 },
|
||||
#endif
|
||||
#ifdef LTC_CURVE448
|
||||
[LTC_OID_X448] = { LTC_PKA_X448, (pkcs8_import_fn)x448_import_pkcs8_asn1 },
|
||||
[LTC_OID_ED448] = { LTC_PKA_ED448, (pkcs8_import_fn)ed448_import_pkcs8_asn1 },
|
||||
#endif
|
||||
};
|
||||
|
||||
static int s_import_pkcs8(unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k, const password_ctx *pw_ctx)
|
||||
|
|
@ -122,6 +126,10 @@ static const import_fn s_import_openssl_fns[LTC_PKA_NUM] = {
|
|||
[LTC_PKA_X25519] = (import_fn)x25519_import,
|
||||
[LTC_PKA_ED25519] = (import_fn)ed25519_import,
|
||||
#endif
|
||||
#ifdef LTC_CURVE448
|
||||
[LTC_PKA_X448] = (import_fn)x448_import,
|
||||
[LTC_PKA_ED448] = (import_fn)ed448_import,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_ctx)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ static const oid_table_entry pka_oids[] = {
|
|||
{ LTC_OID_EC_PRIMEF, LTC_PKA_EC, NULL, "1.2.840.10045.1.1" },
|
||||
{ LTC_OID_X25519, LTC_PKA_X25519, NULL, "1.3.101.110" },
|
||||
{ LTC_OID_ED25519, LTC_PKA_ED25519, NULL, "1.3.101.112" },
|
||||
{ LTC_OID_X448, LTC_PKA_X448, NULL, "1.3.101.111" },
|
||||
{ LTC_OID_ED448, LTC_PKA_ED448, NULL, "1.3.101.113" },
|
||||
{ LTC_OID_DH, LTC_PKA_DH, NULL, "1.2.840.113549.1.3.1" },
|
||||
{ LTC_OID_RSA_OAEP, LTC_PKA_RSA, NULL, "1.2.840.113549.1.1.7" },
|
||||
{ LTC_OID_RSA_MGF1, LTC_PKA_RSA, NULL, "1.2.840.113549.1.1.8" },
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@ static const import_fn s_import_spki_fns[LTC_PKA_NUM] = {
|
|||
[LTC_PKA_X25519] = (import_fn)s_x25519_import_spki,
|
||||
[LTC_PKA_ED25519] = (import_fn)s_ed25519_import_spki,
|
||||
#endif
|
||||
#ifdef LTC_CURVE448
|
||||
[LTC_PKA_X448] = (import_fn)x448_import_x509,
|
||||
[LTC_PKA_ED448] = (import_fn)ed448_import_x509,
|
||||
#endif
|
||||
};
|
||||
|
||||
int x509_import_spki(const unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k, ltc_asn1_list **root)
|
||||
|
|
|
|||
937
src/pk/ec448/ec448_common.c
Normal file
937
src/pk/ec448/ec448_common.c
Normal file
|
|
@ -0,0 +1,937 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file ec448_common.c
|
||||
Shared field arithmetic and primitives for Ed448 and X448
|
||||
Field arithmetic over p = 2^448 - 2^224 - 1 (Goldilocks prime)
|
||||
Edwards curve: x^2 + y^2 = 1 + d*x^2*y^2, d = -39081
|
||||
RFC 8032 Section 5.2
|
||||
|
||||
The field representation (16 limbs of 28 bits in long64) and the overall
|
||||
code structure follow the TweetNaCl pattern used for Curve25519 in
|
||||
ec25519/tweetnacl.c. TweetNaCl uses 16 limbs of 16 bits for GF(2^255-19);
|
||||
here the limb width is scaled to 28 bits so that 16 * 28 = 448. This keeps
|
||||
the same loop bounds, carry propagation shape and multiplication layout,
|
||||
trading performance for code simplicity.
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
/* Field element: 16 limbs of 28 bits each (16 * 28 = 448)
|
||||
Each limb nominally fits in 28 bits but may temporarily exceed that
|
||||
during computation; we use long64 for headroom
|
||||
*/
|
||||
typedef long64 gf448[16];
|
||||
|
||||
/* field constants */
|
||||
static const gf448 gf448_0 = {0};
|
||||
static const gf448 gf448_1 = {1};
|
||||
|
||||
/* d = -39081 mod p = p - 39081
|
||||
p in 28-bit limbs: all 0x0FFFFFFF except limb 8 = 0x0FFFFFFE
|
||||
d: limb 0 = 0x0FFFFFFF - 39081 = 0x0FFF6756, limb 8 = 0x0FFFFFFE, rest 0x0FFFFFFF
|
||||
*/
|
||||
static const gf448 ed448_d = {
|
||||
0x0FFF6756, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF,
|
||||
0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF,
|
||||
0x0FFFFFFE, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF,
|
||||
0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF
|
||||
};
|
||||
|
||||
/* Ed448 base point in compressed bytes (57 bytes, little-endian y, sign bit in top of last byte) */
|
||||
static const unsigned char ed448_base_point[57] = {
|
||||
0x14, 0xfa, 0x30, 0xf2, 0x5b, 0x79, 0x08, 0x98,
|
||||
0xad, 0xc8, 0xd7, 0x4e, 0x2c, 0x13, 0xbd, 0xfd,
|
||||
0xc4, 0x39, 0x7c, 0xe6, 0x1c, 0xff, 0xd3, 0x3a,
|
||||
0xd7, 0xc2, 0xa0, 0x05, 0x1e, 0x9c, 0x78, 0x87,
|
||||
0x40, 0x98, 0xa3, 0x6c, 0x73, 0x73, 0xea, 0x4b,
|
||||
0x62, 0xc7, 0xc9, 0x56, 0x37, 0x20, 0x76, 0x88,
|
||||
0x24, 0xbc, 0xb6, 0x6e, 0x71, 0x46, 0x3f, 0x69,
|
||||
0x00
|
||||
};
|
||||
|
||||
/* Group order L (little-endian, 57 bytes) */
|
||||
static const unsigned char ed448_order[57] = {
|
||||
0xf3, 0x44, 0x58, 0xab, 0x92, 0xc2, 0x78, 0x23,
|
||||
0x55, 0x8f, 0xc5, 0x8d, 0x72, 0xc2, 0x6c, 0x21,
|
||||
0x90, 0x36, 0xd6, 0xae, 0x49, 0xdb, 0x4e, 0xc4,
|
||||
0xe9, 0x23, 0xca, 0x7c, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
|
||||
0x00
|
||||
};
|
||||
|
||||
/* Group order L as ulong64 array for modular reduction (byte-wise) */
|
||||
static const ulong64 L448[57] = {
|
||||
0xf3, 0x44, 0x58, 0xab, 0x92, 0xc2, 0x78, 0x23,
|
||||
0x55, 0x8f, 0xc5, 0x8d, 0x72, 0xc2, 0x6c, 0x21,
|
||||
0x90, 0x36, 0xd6, 0xae, 0x49, 0xdb, 0x4e, 0xc4,
|
||||
0xe9, 0x23, 0xca, 0x7c, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
|
||||
0x00
|
||||
};
|
||||
|
||||
/* Field arithmetic for GF(2^448 - 2^224 - 1) - 16 limbs, 28 bits each */
|
||||
|
||||
static LTC_INLINE void s_gf448_copy(gf448 r, const gf448 a)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 16; ++i) r[i] = a[i];
|
||||
}
|
||||
|
||||
/* Carry propagation
|
||||
Overflow from limb[15] wraps: 2^448 == 2^224 + 1 (mod p)
|
||||
So excess from limb 15 adds to limb 0 and limb 8
|
||||
*/
|
||||
static void s_gf448_carry(gf448 o)
|
||||
{
|
||||
int i;
|
||||
long64 c;
|
||||
/* propagate carries from limb 0 to 14 */
|
||||
for (i = 0; i < 15; ++i) {
|
||||
c = o[i] >> 28;
|
||||
o[i+1] += c;
|
||||
o[i] -= c << 28;
|
||||
}
|
||||
/* limb 15 overflow: 2^(28*16) = 2^448 == 2^224 + 1 */
|
||||
c = o[15] >> 28;
|
||||
o[0] += c; /* + c * 1 */
|
||||
o[8] += c; /* + c * 2^224 */
|
||||
o[15] -= c << 28;
|
||||
/* one more pass to settle the extra from limb 0 and 8 */
|
||||
for (i = 0; i < 15; ++i) {
|
||||
c = o[i] >> 28;
|
||||
o[i+1] += c;
|
||||
o[i] -= c << 28;
|
||||
}
|
||||
c = o[15] >> 28;
|
||||
o[0] += c;
|
||||
o[8] += c;
|
||||
o[15] -= c << 28;
|
||||
}
|
||||
|
||||
/* Conditional swap: if b==1, swap p and q; if b==0, no-op. Constant-time */
|
||||
static void s_gf448_cswap(gf448 p, gf448 q, int b)
|
||||
{
|
||||
long64 t, i, mask = ~((long64)b - 1);
|
||||
for (i = 0; i < 16; ++i) {
|
||||
t = mask & (p[i] ^ q[i]);
|
||||
p[i] ^= t;
|
||||
q[i] ^= t;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pack a field element into 56 bytes (little-endian); fully reduces mod p first */
|
||||
static void s_gf448_encode(unsigned char *o, const gf448 n)
|
||||
{
|
||||
int i, j;
|
||||
long64 b;
|
||||
gf448 m, t;
|
||||
for (i = 0; i < 16; ++i) t[i] = n[i];
|
||||
|
||||
/* carry 3 times to ensure all limbs in [0, 2^28) */
|
||||
s_gf448_carry(t);
|
||||
s_gf448_carry(t);
|
||||
s_gf448_carry(t);
|
||||
|
||||
/* Subtract p and check borrow p: limbs 0..7 = 0x0FFFFFFF, limb 8 = 0x0FFFFFFE, limbs 9..15 = 0x0FFFFFFF */
|
||||
for (j = 0; j < 2; ++j) {
|
||||
m[0] = t[0] - (long64)0x0FFFFFFF;
|
||||
for (i = 1; i < 16; i++) {
|
||||
long64 sub;
|
||||
if (i == 8) sub = (long64)0x0FFFFFFE;
|
||||
else sub = (long64)0x0FFFFFFF;
|
||||
m[i] = t[i] - sub - ((m[i-1] >> 28) & 1);
|
||||
m[i-1] &= 0x0FFFFFFF;
|
||||
}
|
||||
b = (m[15] >> 28) & 1;
|
||||
m[15] &= 0x0FFFFFFF;
|
||||
s_gf448_cswap(t, m, 1 - (int)b);
|
||||
}
|
||||
|
||||
/* Serialize: 16 limbs * 28 bits = 448 bits = 56 bytes
|
||||
each limb contributes 28 bits = 3.5 bytes
|
||||
Limb i holds bits [28*i .. 28*i+27]
|
||||
Byte j holds bits [8*j .. 8*j+7]
|
||||
*/
|
||||
XMEMSET(o, 0, 56);
|
||||
for (i = 0; i < 16; i++) {
|
||||
/* limb i holds bits starting at bit_offset = 28*i */
|
||||
unsigned long bit_off = (unsigned long)i * 28;
|
||||
unsigned long byte_off = bit_off / 8;
|
||||
unsigned long bit_shift = bit_off % 8;
|
||||
/* We need to spread 28 bits starting at byte_off, bit_shift */
|
||||
ulong64 val = (ulong64)(t[i] & 0x0FFFFFFF);
|
||||
val <<= bit_shift;
|
||||
for (j = 0; j < 5 && byte_off + (unsigned long)j < 56; j++) {
|
||||
o[byte_off + j] |= (unsigned char)(val & 0xFF);
|
||||
val >>= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Unpack 56 bytes (little-endian) into a field element */
|
||||
static void s_gf448_decode(gf448 o, const unsigned char *n)
|
||||
{
|
||||
int i;
|
||||
XMEMSET(o, 0, sizeof(gf448));
|
||||
for (i = 0; i < 16; i++) {
|
||||
unsigned long bit_off = (unsigned long)i * 28;
|
||||
unsigned long byte_off = bit_off / 8;
|
||||
unsigned long bit_shift = bit_off % 8;
|
||||
ulong64 val = 0;
|
||||
int j;
|
||||
for (j = 0; j < 5 && byte_off + (unsigned long)j < 56; j++) {
|
||||
val |= ((ulong64)n[byte_off + j]) << (8 * (unsigned long)j);
|
||||
}
|
||||
val >>= bit_shift;
|
||||
o[i] = (long64)(val & 0x0FFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
/* constant-time equality check */
|
||||
static int s_gf448_neq(const gf448 a, const gf448 b)
|
||||
{
|
||||
unsigned char c[56], d[56];
|
||||
int i;
|
||||
ulong32 diff = 0;
|
||||
s_gf448_encode(c, a);
|
||||
s_gf448_encode(d, b);
|
||||
for (i = 0; i < 56; ++i) diff |= (ulong32)(c[i] ^ d[i]);
|
||||
return (1 & ((diff - 1) >> 8)) - 1;
|
||||
}
|
||||
|
||||
/* return parity (low bit) of field element */
|
||||
static unsigned char s_gf448_parity(const gf448 a)
|
||||
{
|
||||
unsigned char d[56];
|
||||
s_gf448_encode(d, a);
|
||||
return d[0] & 1;
|
||||
}
|
||||
|
||||
/* Addition */
|
||||
static LTC_INLINE void s_gf448_add(gf448 o, const gf448 a, const gf448 b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 16; ++i) o[i] = a[i] + b[i];
|
||||
}
|
||||
|
||||
/* Subtraction */
|
||||
static LTC_INLINE void s_gf448_sub(gf448 o, const gf448 a, const gf448 b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 16; ++i) o[i] = a[i] - b[i];
|
||||
}
|
||||
|
||||
/* Multiplication: o = a * b mod p
|
||||
Schoolbook 16x16 -> 31 limbs, then reduce using Goldilocks
|
||||
2^448 == 2^224 + 1, so for product limbs t[16..30]:
|
||||
t[i] += t[i+16] (the "1" part)
|
||||
t[i+8] += t[i+16] (the "2^224" part, since limb 8 = 224 bits)
|
||||
Then carry
|
||||
*/
|
||||
static void s_gf448_mul(gf448 o, const gf448 a, const gf448 b)
|
||||
{
|
||||
long64 i, j;
|
||||
long64 t[31];
|
||||
for (i = 0; i < 31; ++i) t[i] = 0;
|
||||
for (i = 0; i < 16; ++i)
|
||||
for (j = 0; j < 16; ++j)
|
||||
t[i + j] += a[i] * b[j];
|
||||
|
||||
/* reduce t[16..30] */
|
||||
for (i = 14; i >= 0; --i) {
|
||||
t[i] += t[i + 16];
|
||||
t[i + 8] += t[i + 16];
|
||||
t[i + 16] = 0;
|
||||
}
|
||||
/* Now t[0..15] holds the result, but t[8..15] may have gotten extra from
|
||||
t[16..23] additions. t[15] overflow wraps via Goldilocks
|
||||
*/
|
||||
for (i = 0; i < 16; ++i) o[i] = t[i];
|
||||
s_gf448_carry(o);
|
||||
s_gf448_carry(o);
|
||||
}
|
||||
|
||||
/* Squaring */
|
||||
static LTC_INLINE void s_gf448_sqr(gf448 o, const gf448 a)
|
||||
{
|
||||
s_gf448_mul(o, a, a);
|
||||
}
|
||||
|
||||
/* Inversion: o = a^(p-2) mod p
|
||||
p-2 = 2^448 - 2^224 - 3
|
||||
|
||||
p-2 in binary (bit 447 to bit 0):
|
||||
bits 447..225: all 1 (223 ones)
|
||||
bit 224: 0
|
||||
bits 223..2: all 1 (222 ones)
|
||||
bit 1: 0
|
||||
bit 0: 1
|
||||
|
||||
Square-and-multiply from MSB: start with a^1, then for each bit:
|
||||
square, then multiply by a if bit is 1
|
||||
*/
|
||||
static void s_gf448_inv(gf448 o, const gf448 inp)
|
||||
{
|
||||
gf448 t;
|
||||
int i;
|
||||
|
||||
s_gf448_copy(t, inp);
|
||||
|
||||
/* Process from bit 446 down (bit 447 is the leading 1, we start with a^1) */
|
||||
/* bits 446..225: all 1 (222 bits) */
|
||||
for (i = 0; i < 222; i++) {
|
||||
s_gf448_sqr(t, t);
|
||||
s_gf448_mul(t, t, inp);
|
||||
}
|
||||
|
||||
/* bit 224: 0 -> just square */
|
||||
s_gf448_sqr(t, t);
|
||||
|
||||
/* bits 223..2: all 1 (222 bits) */
|
||||
for (i = 0; i < 222; i++) {
|
||||
s_gf448_sqr(t, t);
|
||||
s_gf448_mul(t, t, inp);
|
||||
}
|
||||
|
||||
/* bit 1: 0 -> just square */
|
||||
s_gf448_sqr(t, t);
|
||||
|
||||
/* bit 0: 1 -> square and multiply */
|
||||
s_gf448_sqr(t, t);
|
||||
s_gf448_mul(t, t, inp);
|
||||
|
||||
s_gf448_copy(o, t);
|
||||
}
|
||||
|
||||
/* Square root: o = a^((p+1)/4) mod p
|
||||
Since p == 3 (mod 4), this gives the square root of a when it exists
|
||||
(p+1)/4 = 2^446 - 2^222 = 2^222 * (2^224 - 1)
|
||||
In binary: 224 ones (bits 445..222) followed by 222 zeros (bits 221..0)
|
||||
*/
|
||||
static void s_gf448_sqrt(gf448 o, const gf448 inp)
|
||||
{
|
||||
gf448 t;
|
||||
int i;
|
||||
|
||||
s_gf448_copy(t, inp);
|
||||
|
||||
/* bit 445 is the MSB; we start with a^1. bits 444..222: all 1 (223 bits) */
|
||||
for (i = 0; i < 223; i++) {
|
||||
s_gf448_sqr(t, t);
|
||||
s_gf448_mul(t, t, inp);
|
||||
}
|
||||
|
||||
/* bits 221..0: all 0 (222 bits) -> just square 222 times */
|
||||
for (i = 0; i < 222; i++) {
|
||||
s_gf448_sqr(t, t);
|
||||
}
|
||||
|
||||
s_gf448_copy(o, t);
|
||||
}
|
||||
|
||||
|
||||
/* Edwards curve point operations
|
||||
Curve: x^2 + y^2 = 1 + d*x^2*y^2 (a = 1)
|
||||
Extended coordinates: (X : Y : Z : T) where x = X/Z, y = Y/Z, T = X*Y/Z
|
||||
*/
|
||||
|
||||
/* Unified point addition (works for doubling too)
|
||||
Extended coordinates on x^2 + y^2 = 1 + d*x^2*y^2 (a=1):
|
||||
A = X1*X2, B = Y1*Y2, C = d*T1*T2, D = Z1*Z2
|
||||
E = (X1+Y1)(X2+Y2) - A - B
|
||||
F = D - C, G = D + C, H = B - A
|
||||
X3 = E*F, Y3 = G*H, T3 = E*H, Z3 = F*G
|
||||
*/
|
||||
static void s_ed448_point_add(gf448 p[4], gf448 q[4])
|
||||
{
|
||||
gf448 a, b, c, d, e, f, g, h, t;
|
||||
|
||||
s_gf448_mul(a, p[0], q[0]); /* A = X1*X2 */
|
||||
s_gf448_mul(b, p[1], q[1]); /* B = Y1*Y2 */
|
||||
s_gf448_mul(c, p[3], q[3]);
|
||||
s_gf448_mul(c, c, ed448_d); /* C = d*T1*T2 */
|
||||
s_gf448_mul(d, p[2], q[2]); /* D = Z1*Z2 */
|
||||
|
||||
s_gf448_add(t, p[0], p[1]); /* X1+Y1 */
|
||||
s_gf448_add(e, q[0], q[1]); /* X2+Y2 */
|
||||
s_gf448_mul(e, t, e); /* (X1+Y1)(X2+Y2) */
|
||||
s_gf448_sub(e, e, a); /* - A */
|
||||
s_gf448_sub(e, e, b); /* - B -> E */
|
||||
|
||||
s_gf448_sub(f, d, c); /* F = D - C */
|
||||
s_gf448_add(g, d, c); /* G = D + C */
|
||||
s_gf448_sub(h, b, a); /* H = B - A (since a=1) */
|
||||
|
||||
s_gf448_mul(p[0], e, f); /* X3 = E*F */
|
||||
s_gf448_mul(p[1], g, h); /* Y3 = G*H */
|
||||
s_gf448_mul(p[2], f, g); /* Z3 = F*G */
|
||||
s_gf448_mul(p[3], e, h); /* T3 = E*H */
|
||||
}
|
||||
|
||||
/* Conditional swap of two points (constant time) */
|
||||
static void s_ed448_point_cswap(gf448 p[4], gf448 q[4], unsigned char b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) s_gf448_cswap(p[i], q[i], b);
|
||||
}
|
||||
|
||||
/* Ed448 encoding: 57 bytes = 456 bits
|
||||
Bytes 0..55 contain the 448-bit little-endian y-coordinate.
|
||||
Bits 0..6 of byte 56 are zero for canonical encodings.
|
||||
Bit 7 of byte 56 stores the parity/sign bit of x.
|
||||
*/
|
||||
static void s_ed448_point_encode(unsigned char *r, gf448 p[4])
|
||||
{
|
||||
gf448 tx, ty, zi;
|
||||
s_gf448_inv(zi, p[2]);
|
||||
s_gf448_mul(tx, p[0], zi);
|
||||
s_gf448_mul(ty, p[1], zi);
|
||||
s_gf448_encode(r, ty);
|
||||
/* bit 455 = bit 7 of byte 56 = sign of x */
|
||||
r[56] = 0;
|
||||
r[56] |= s_gf448_parity(tx) << 7;
|
||||
}
|
||||
|
||||
/* Scalar multiplication: p = [s] * q; Constant-time double-and-add with conditional swap */
|
||||
static void s_ed448_scalarmult(gf448 p[4], gf448 q[4], const unsigned char *s)
|
||||
{
|
||||
int i;
|
||||
/* p = identity = (0, 1, 1, 0) */
|
||||
s_gf448_copy(p[0], gf448_0);
|
||||
s_gf448_copy(p[1], gf448_1);
|
||||
s_gf448_copy(p[2], gf448_1);
|
||||
s_gf448_copy(p[3], gf448_0);
|
||||
|
||||
/* Ed448 scalars are 456 bits (57 bytes), but the group order is ~446 bits
|
||||
Clamped scalar has at most 448 bits (a[56]=0, a[55]|=0x80 sets bit 447)
|
||||
We scan all 456 bits to be safe
|
||||
*/
|
||||
for (i = 455; i >= 0; --i) {
|
||||
unsigned char b = (s[i / 8] >> (i & 7)) & 1;
|
||||
s_ed448_point_cswap(p, q, b);
|
||||
s_ed448_point_add(q, p);
|
||||
s_ed448_point_add(p, p);
|
||||
s_ed448_point_cswap(p, q, b);
|
||||
}
|
||||
}
|
||||
|
||||
/* Scalar base multiplication: p = [s] * B */
|
||||
static void s_ed448_scalarmult_base(gf448 p[4], const unsigned char *s)
|
||||
{
|
||||
gf448 q[4];
|
||||
|
||||
/* decode base point: unpack y from first 56 bytes */
|
||||
s_gf448_decode(q[1], ed448_base_point);
|
||||
|
||||
/* set Z = 1 */
|
||||
s_gf448_copy(q[2], gf448_1);
|
||||
|
||||
/* recover x from y:
|
||||
x^2 + y^2 = 1 + d*x^2*y^2 => x^2 = (1 - y^2) / (1 - d*y^2) */
|
||||
{
|
||||
gf448 y2, num, den, den_inv, x2, x_cand;
|
||||
s_gf448_sqr(y2, q[1]); /* y^2 */
|
||||
s_gf448_sub(num, gf448_1, y2); /* 1 - y^2 */
|
||||
s_gf448_mul(den, y2, ed448_d); /* d * y^2 */
|
||||
s_gf448_sub(den, gf448_1, den); /* 1 - d*y^2 */
|
||||
s_gf448_inv(den_inv, den);
|
||||
s_gf448_mul(x2, num, den_inv); /* x^2 */
|
||||
|
||||
/* x = x2^((p+1)/4) -- works since p == 3 mod 4 */
|
||||
s_gf448_sqrt(x_cand, x2);
|
||||
|
||||
/* Check sign bit. The base point encoding has sign bit = 0 */
|
||||
if (s_gf448_parity(x_cand) != ((ed448_base_point[56] >> 7) & 1)) {
|
||||
/* negate x */
|
||||
s_gf448_sub(x_cand, gf448_0, x_cand);
|
||||
}
|
||||
s_gf448_copy(q[0], x_cand);
|
||||
}
|
||||
|
||||
/* T = X * Y */
|
||||
s_gf448_mul(q[3], q[0], q[1]);
|
||||
|
||||
s_ed448_scalarmult(p, q, s);
|
||||
}
|
||||
|
||||
/* Decode a point from 57-byte encoding; returns 0 on success, -1 on failure */
|
||||
static int s_ed448_point_decode(gf448 r[4], const unsigned char p[57])
|
||||
{
|
||||
gf448 y2, num, den, den_inv, x2, x_cand, chk;
|
||||
unsigned char sign_bit;
|
||||
|
||||
/* y from the first 56 bytes (448 bits) */
|
||||
s_gf448_decode(r[1], p);
|
||||
/* bit 7 of byte 56 is the x sign bit */
|
||||
sign_bit = (p[56] >> 7) & 1;
|
||||
|
||||
s_gf448_copy(r[2], gf448_1);
|
||||
|
||||
/* x^2 = (1 - y^2) / (1 - d*y^2) */
|
||||
s_gf448_sqr(y2, r[1]);
|
||||
s_gf448_sub(num, gf448_1, y2); /* 1 - y^2 */
|
||||
s_gf448_mul(den, y2, ed448_d); /* d * y^2 */
|
||||
s_gf448_sub(den, gf448_1, den); /* 1 - d*y^2 */
|
||||
s_gf448_inv(den_inv, den);
|
||||
s_gf448_mul(x2, num, den_inv);
|
||||
|
||||
/* Compute square root candidate */
|
||||
s_gf448_sqrt(x_cand, x2);
|
||||
|
||||
/* Verify: x_cand^2 == x2 ? */
|
||||
s_gf448_sqr(chk, x_cand);
|
||||
if (s_gf448_neq(chk, x2)) {
|
||||
/* Not a valid point */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Adjust sign */
|
||||
if (s_gf448_parity(x_cand) != sign_bit) {
|
||||
s_gf448_sub(x_cand, gf448_0, x_cand);
|
||||
}
|
||||
|
||||
s_gf448_copy(r[0], x_cand);
|
||||
s_gf448_mul(r[3], r[0], r[1]); /* T = X * Y */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Scalar arithmetic modulo L (group order) */
|
||||
|
||||
/* Reduce x[0..113] modulo L, store 57-byte result in r
|
||||
|
||||
Uses the relation 2^448 == 4*c (mod L), where c = 2^446 - L is a 28-byte number
|
||||
Byte position i (for i >= 56) represents 2^(8*i) = 2^(8*(i-56)) * 2^448
|
||||
== 2^(8*(i-56)) * 4*c (mod L)
|
||||
So x[i] for i >= 56 folds into positions (i-56)..(i-56+27) as 4*x[i]*c[j]
|
||||
*/
|
||||
static void s_sc448_reduce(unsigned char *r, long64 x[114])
|
||||
{
|
||||
long64 carry, i, j;
|
||||
int round;
|
||||
|
||||
/* c = 2^446 - L (28 bytes, little-endian) */
|
||||
static const long64 C448[28] = {
|
||||
0x0D, 0xBB, 0xA7, 0x54, 0x6D, 0x3D, 0x87, 0xDC,
|
||||
0xAA, 0x70, 0x3A, 0x72, 0x8D, 0x3D, 0x93, 0xDE,
|
||||
0x6F, 0xC9, 0x29, 0x51, 0xB6, 0x24, 0xB1, 0x3B,
|
||||
0x16, 0xDC, 0x35, 0x83
|
||||
};
|
||||
|
||||
/* Perform up to 4 rounds of folding to guarantee full reduction */
|
||||
for (round = 0; round < 4; round++) {
|
||||
/* Fold bytes 56..113 into lower positions */
|
||||
for (i = 113; i >= 56; --i) {
|
||||
if (x[i] == 0) continue;
|
||||
for (j = 0; j < 28; j++) {
|
||||
x[i - 56 + j] += 4 * x[i] * C448[j];
|
||||
}
|
||||
x[i] = 0;
|
||||
}
|
||||
|
||||
/* Carry normalize from 0 to 113 */
|
||||
carry = 0;
|
||||
for (i = 0; i < 114; i++) {
|
||||
x[i] += carry;
|
||||
carry = x[i] >> 8;
|
||||
x[i] &= 255;
|
||||
}
|
||||
/* If no overflow into high bytes, we can stop early */
|
||||
if (carry == 0) {
|
||||
int done = 1;
|
||||
for (i = 56; i < 114; i++) {
|
||||
if (x[i] != 0) { done = 0; break; }
|
||||
}
|
||||
if (done) break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now x[0..55] holds the value, x[56..113] should be zero
|
||||
Up to 4 conditional subtractions of L ensure x < L */
|
||||
for (round = 0; round < 4; round++) {
|
||||
long64 t[57], borrow;
|
||||
borrow = 0;
|
||||
for (i = 0; i < 57; i++) {
|
||||
t[i] = x[i] - (long64)L448[i] - borrow;
|
||||
borrow = (t[i] >> 63) & 1;
|
||||
t[i] &= 255;
|
||||
}
|
||||
/* If borrow=0 => x >= L, replace x with t. If borrow=1 => x < L, keep x */
|
||||
if (borrow == 0) {
|
||||
for (i = 0; i < 57; i++) x[i] = t[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 57; i++) {
|
||||
r[i] = (unsigned char)(x[i] & 255);
|
||||
}
|
||||
}
|
||||
|
||||
static void s_sc448_reduce_buf(unsigned char *r)
|
||||
{
|
||||
long64 x[114];
|
||||
int i;
|
||||
for (i = 0; i < 114; ++i) x[i] = (ulong64)r[i];
|
||||
for (i = 0; i < 114; ++i) r[i] = 0;
|
||||
s_sc448_reduce(r, x);
|
||||
}
|
||||
|
||||
/* Check if scalar s < L (group order); returns 1 if s < L, 0 otherwise */
|
||||
static int s_sc448_lt_order(const unsigned char *s)
|
||||
{
|
||||
int i;
|
||||
/* s and ed448_order are both 57 bytes LE */
|
||||
for (i = 56; i >= 0; i--) {
|
||||
if (s[i] < ed448_order[i]) return 1;
|
||||
if (s[i] > ed448_order[i]) return 0;
|
||||
}
|
||||
return 0; /* equal means not strictly less */
|
||||
}
|
||||
|
||||
/* Ed448 internal API functions */
|
||||
|
||||
/**
|
||||
Derive public key from secret key
|
||||
RFC 8032 Section 5.2.5:
|
||||
1. SHAKE256(sk, 57) -> 114 bytes
|
||||
2. Clamp first 57 bytes: a[0] &= 0xFC, a[55] |= 0x80, a[56] = 0
|
||||
3. pk = [a]B
|
||||
*/
|
||||
int ec448_sk_to_pk_internal(unsigned char *pk, const unsigned char *sk)
|
||||
{
|
||||
unsigned char az[114];
|
||||
gf448 p[4];
|
||||
int err;
|
||||
|
||||
{ unsigned long azlen = 114; if ((err = sha3_shake_memory(256, sk, 57, az, &azlen)) != CRYPT_OK) return err; }
|
||||
|
||||
/* clamp */
|
||||
az[0] &= 0xFC;
|
||||
az[55] |= 0x80;
|
||||
az[56] = 0;
|
||||
|
||||
s_ed448_scalarmult_base(p, az);
|
||||
s_ed448_point_encode(pk, p);
|
||||
|
||||
zeromem(az, sizeof(az));
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Generate Ed448 keypair
|
||||
*/
|
||||
int ec448_keypair_internal(prng_state *prng, int wprng, unsigned char *pk, unsigned char *sk)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = prng_is_valid(wprng)) != CRYPT_OK) return err;
|
||||
|
||||
if (prng_descriptor[wprng].read(sk, 57, prng) != 57) {
|
||||
return CRYPT_ERROR_READPRNG;
|
||||
}
|
||||
|
||||
if ((err = ec448_sk_to_pk_internal(pk, sk)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Ed448 sign
|
||||
|
||||
RFC 8032 Section 5.2.6:
|
||||
1. SHAKE256(sk, 57) -> (a, prefix) where a is clamped first 57 bytes
|
||||
2. r = SHAKE256(DOM4(0,ctx) || prefix || msg) mod L
|
||||
3. R = [r]B encoded
|
||||
4. h = SHAKE256(DOM4(0,ctx) || R || pk || msg) mod L
|
||||
5. S = (r + h*a) mod L
|
||||
6. sig = R || S (114 bytes)
|
||||
|
||||
The sm buffer receives R || S || msg (smlen = mlen + 114)
|
||||
ctx/cs: DOM4 context; for plain Ed448, ctx=NULL, cs=0 but DOM4 is still prepended
|
||||
*/
|
||||
int ec448_sign_internal(unsigned char *sm, unsigned long long *smlen,
|
||||
const unsigned char *m, unsigned long long mlen,
|
||||
const unsigned char *sk, const unsigned char *pk,
|
||||
const unsigned char *ctx, unsigned long long cs)
|
||||
{
|
||||
unsigned char az[114], nonce[114], hram[114];
|
||||
long64 x[114];
|
||||
long64 i, j;
|
||||
gf448 p[4];
|
||||
int err;
|
||||
|
||||
/* ctx/cs is a pre-built DOM4 prefix that gets prepended to all hashes
|
||||
The wrapper functions build it:
|
||||
ed448_sign -> DOM4(0, "")
|
||||
ed448ctx_sign -> DOM4(0, ctx)
|
||||
ed448ph_sign -> DOM4(1, ctx)
|
||||
*/
|
||||
|
||||
/* Hash secret key */
|
||||
{ unsigned long azlen = 114; if ((err = sha3_shake_memory(256, sk, 57, az, &azlen)) != CRYPT_OK) return err; }
|
||||
|
||||
/* Clamp scalar a */
|
||||
az[0] &= 0xFC;
|
||||
az[55] |= 0x80;
|
||||
az[56] = 0;
|
||||
|
||||
/* Compute nonce r = SHAKE256(ctx || prefix || msg) mod L */
|
||||
/* ctx already contains DOM4 prefix from the wrapper */
|
||||
*smlen = mlen + 114;
|
||||
|
||||
if (ctx != NULL && cs > 0) {
|
||||
hash_state md;
|
||||
if ((err = sha3_shake_init(&md, 256)) != CRYPT_OK) goto cleanup;
|
||||
if ((err = sha3_shake_process(&md, ctx, (unsigned long)cs)) != CRYPT_OK) goto cleanup;
|
||||
if ((err = sha3_shake_process(&md, az + 57, 57)) != CRYPT_OK) goto cleanup;
|
||||
if ((err = sha3_shake_process(&md, m, (unsigned long)mlen)) != CRYPT_OK) goto cleanup;
|
||||
if ((err = sha3_shake_done(&md, nonce, 114)) != CRYPT_OK) goto cleanup;
|
||||
}
|
||||
else {
|
||||
hash_state md;
|
||||
if ((err = sha3_shake_init(&md, 256)) != CRYPT_OK) goto cleanup;
|
||||
if ((err = sha3_shake_process(&md, az + 57, 57)) != CRYPT_OK) goto cleanup;
|
||||
if ((err = sha3_shake_process(&md, m, (unsigned long)mlen)) != CRYPT_OK) goto cleanup;
|
||||
if ((err = sha3_shake_done(&md, nonce, 114)) != CRYPT_OK) goto cleanup;
|
||||
}
|
||||
|
||||
s_sc448_reduce_buf(nonce);
|
||||
|
||||
/* R = [r]B */
|
||||
s_ed448_scalarmult_base(p, nonce);
|
||||
s_ed448_point_encode(sm, p); /* sm[0..56] = R */
|
||||
|
||||
/* Compute h = SHAKE256(ctx || R || pk || msg) mod L */
|
||||
{
|
||||
hash_state md;
|
||||
if ((err = sha3_shake_init(&md, 256)) != CRYPT_OK) goto cleanup;
|
||||
if (ctx != NULL && cs > 0) {
|
||||
if ((err = sha3_shake_process(&md, ctx, (unsigned long)cs)) != CRYPT_OK) goto cleanup;
|
||||
}
|
||||
if ((err = sha3_shake_process(&md, sm, 57)) != CRYPT_OK) goto cleanup; /* R */
|
||||
if ((err = sha3_shake_process(&md, pk, 57)) != CRYPT_OK) goto cleanup; /* pk */
|
||||
if ((err = sha3_shake_process(&md, m, (unsigned long)mlen)) != CRYPT_OK) goto cleanup; /* msg */
|
||||
if ((err = sha3_shake_done(&md, hram, 114)) != CRYPT_OK) goto cleanup;
|
||||
}
|
||||
s_sc448_reduce_buf(hram);
|
||||
|
||||
/* S = (r + h * a) mod L */
|
||||
for (i = 0; i < 114; ++i) x[i] = 0;
|
||||
for (i = 0; i < 57; ++i) x[i] = (ulong64)nonce[i];
|
||||
for (i = 0; i < 57; ++i)
|
||||
for (j = 0; j < 57; ++j)
|
||||
x[i + j] += (long64)hram[i] * (long64)(ulong64)az[j];
|
||||
s_sc448_reduce(sm + 57, x); /* sm[57..113] = S */
|
||||
|
||||
err = CRYPT_OK;
|
||||
|
||||
cleanup:
|
||||
zeromem(az, sizeof(az));
|
||||
zeromem(nonce, sizeof(nonce));
|
||||
zeromem(hram, sizeof(hram));
|
||||
zeromem(x, sizeof(x));
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
Ed448 verify
|
||||
|
||||
RFC 8032 Section 5.2.7:
|
||||
1. Parse sig as R (57 bytes) || S (57 bytes)
|
||||
2. Decode R, pk as points
|
||||
3. Check S < L
|
||||
4. h = SHAKE256(DOM4(0,ctx) || R || pk || msg) mod L
|
||||
5. Check [S]B == R + [h]A
|
||||
|
||||
sm = sig || msg (smlen = siglen + msglen, siglen = 114)
|
||||
Returns stat=1 if valid, stat=0 if invalid
|
||||
*/
|
||||
int ec448_verify_internal(int *stat, unsigned char *m, unsigned long long *mlen,
|
||||
const unsigned char *sm, unsigned long long smlen,
|
||||
const unsigned char *ctx, unsigned long long cs,
|
||||
const unsigned char *pk)
|
||||
{
|
||||
unsigned char hram[114];
|
||||
unsigned char t[57];
|
||||
gf448 p[4], q[4], r_point[4];
|
||||
unsigned long long i;
|
||||
int err;
|
||||
unsigned char s_bytes[57];
|
||||
|
||||
*stat = 0;
|
||||
|
||||
if (*mlen < smlen) return CRYPT_BUFFER_OVERFLOW;
|
||||
*mlen = (unsigned long long)-1;
|
||||
if (smlen < 114) return CRYPT_INVALID_ARG;
|
||||
|
||||
/* Decode public key A */
|
||||
if (s_ed448_point_decode(q, pk) != 0) return CRYPT_ERROR;
|
||||
|
||||
/* Copy sm to m for manipulation */
|
||||
XMEMMOVE(m, sm, (unsigned long)smlen);
|
||||
|
||||
/* Extract S (bytes 57..113 of signature) */
|
||||
XMEMCPY(s_bytes, m + 57, 57);
|
||||
|
||||
/* Check S < L */
|
||||
if (!s_sc448_lt_order(s_bytes)) {
|
||||
for (i = 0; i < smlen - 114; ++i) m[i] = 0;
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* Decode R (bytes 0..56 of signature) */
|
||||
if (s_ed448_point_decode(r_point, m) != 0) {
|
||||
for (i = 0; i < smlen - 114; ++i) m[i] = 0;
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* Replace S in m with pk for hashing: m = R || pk || msg */
|
||||
XMEMCPY(m + 57, pk, 57);
|
||||
|
||||
/* h = SHAKE256(ctx || R || pk || msg) mod L */
|
||||
{
|
||||
hash_state md;
|
||||
if ((err = sha3_shake_init(&md, 256)) != CRYPT_OK) return err;
|
||||
if (ctx != NULL && cs > 0) {
|
||||
if ((err = sha3_shake_process(&md, ctx, (unsigned long)cs)) != CRYPT_OK) return err;
|
||||
}
|
||||
if ((err = sha3_shake_process(&md, m, (unsigned long)smlen)) != CRYPT_OK) return err;
|
||||
if ((err = sha3_shake_done(&md, hram, 114)) != CRYPT_OK) return err;
|
||||
}
|
||||
s_sc448_reduce_buf(hram);
|
||||
|
||||
/* Compute [h]A */
|
||||
s_ed448_scalarmult(p, q, hram);
|
||||
|
||||
/* Add R: p = R + [h]A */
|
||||
s_ed448_point_add(p, r_point);
|
||||
|
||||
/* Compute [S]B */
|
||||
s_ed448_scalarmult_base(q, s_bytes);
|
||||
|
||||
/* Compare: [S]B == R + [h]A */
|
||||
s_ed448_point_encode(t, q);
|
||||
{
|
||||
unsigned char t2[57];
|
||||
s_ed448_point_encode(t2, p);
|
||||
|
||||
/* Constant-time comparison */
|
||||
{
|
||||
ulong32 diff = 0;
|
||||
int idx;
|
||||
for (idx = 0; idx < 57; idx++) diff |= (ulong32)(t[idx] ^ t2[idx]);
|
||||
if (diff == 0) {
|
||||
*stat = 1;
|
||||
smlen -= 114;
|
||||
XMEMMOVE(m, m + 114, (unsigned long)smlen);
|
||||
*mlen = smlen;
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < smlen - 114; ++i) m[i] = 0;
|
||||
zeromem(m, (unsigned long)(smlen - 114));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* Ed448 prehash: SHAKE256(msg) truncated to 64 bytes */
|
||||
int ec448_prehash_internal(unsigned char *out, const unsigned char *msg, unsigned long long msglen)
|
||||
{
|
||||
unsigned long phlen = 64;
|
||||
return sha3_shake_memory(256, msg, (unsigned long)msglen, out, &phlen);
|
||||
}
|
||||
|
||||
|
||||
/* X448 scalar multiplication (RFC 7748 Montgomery ladder) */
|
||||
int ec448_scalarmult_internal(unsigned char *out, const unsigned char *scalar, const unsigned char *point)
|
||||
{
|
||||
unsigned char sk[56];
|
||||
gf448 x1, x2, z2, x3, z3;
|
||||
gf448 a, aa, b, bb, e, c, d, da, cb, t;
|
||||
static const gf448 a24 = {39081};
|
||||
int i;
|
||||
unsigned char swap = 0;
|
||||
|
||||
/* clamp scalar */
|
||||
XMEMCPY(sk, scalar, 56);
|
||||
sk[0] &= 252;
|
||||
sk[55] |= 128;
|
||||
|
||||
/* decode u-coordinate */
|
||||
s_gf448_decode(x1, point);
|
||||
|
||||
/* x_2 = 1, z_2 = 0, x_3 = u, z_3 = 1 */
|
||||
s_gf448_copy(x3, x1);
|
||||
s_gf448_copy(x2, gf448_1);
|
||||
s_gf448_copy(z2, gf448_0);
|
||||
s_gf448_copy(z3, gf448_1);
|
||||
|
||||
for (i = 447; i >= 0; --i) {
|
||||
unsigned char k_t = (sk[i / 8] >> (i & 7)) & 1;
|
||||
swap ^= k_t;
|
||||
s_gf448_cswap(x2, x3, swap);
|
||||
s_gf448_cswap(z2, z3, swap);
|
||||
swap = k_t;
|
||||
|
||||
s_gf448_add(a, x2, z2); /* A = x_2 + z_2 */
|
||||
s_gf448_sqr(aa, a); /* AA = A^2 */
|
||||
s_gf448_sub(b, x2, z2); /* B = x_2 - z_2 */
|
||||
s_gf448_sqr(bb, b); /* BB = B^2 */
|
||||
s_gf448_sub(e, aa, bb); /* E = AA - BB */
|
||||
s_gf448_add(c, x3, z3); /* C = x_3 + z_3 */
|
||||
s_gf448_sub(d, x3, z3); /* D = x_3 - z_3 */
|
||||
s_gf448_mul(da, d, a); /* DA = D * A */
|
||||
s_gf448_mul(cb, c, b); /* CB = C * B */
|
||||
|
||||
s_gf448_add(x3, da, cb); /* x_3 = (DA + CB)^2 */
|
||||
s_gf448_sqr(x3, x3);
|
||||
|
||||
s_gf448_sub(z3, da, cb); /* z_3 = x_1*(DA-CB)^2 */
|
||||
s_gf448_sqr(z3, z3);
|
||||
s_gf448_mul(z3, x1, z3);
|
||||
|
||||
s_gf448_mul(x2, aa, bb); /* x_2 = AA * BB */
|
||||
|
||||
s_gf448_mul(t, a24, e); /* z_2 = E*(AA + a24*E) */
|
||||
s_gf448_add(t, aa, t);
|
||||
s_gf448_mul(z2, e, t);
|
||||
}
|
||||
|
||||
s_gf448_cswap(x2, x3, swap);
|
||||
s_gf448_cswap(z2, z3, swap);
|
||||
|
||||
s_gf448_inv(t, z2);
|
||||
s_gf448_mul(x2, x2, t);
|
||||
|
||||
s_gf448_encode(out, x2);
|
||||
|
||||
zeromem(sk, sizeof(sk));
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* X448 scalar multiplication with base point u=5 */
|
||||
static const unsigned char s_x448_basepoint[56] = {
|
||||
5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
int ec448_scalarmult_base_internal(unsigned char *out, const unsigned char *scalar)
|
||||
{
|
||||
ec448_scalarmult_internal(out, scalar, s_x448_basepoint);
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
51
src/pk/ec448/ec448_crypto_ctx.c
Normal file
51
src/pk/ec448/ec448_crypto_ctx.c
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file ec448_crypto_ctx.c
|
||||
Build DOM4 context prefix for Ed448ctx / Ed448ph (RFC 8032, Section 5.2).
|
||||
DOM4(x, y) = "SigEd448" || octet(x) || octet(OLEN(y)) || y
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
/**
|
||||
@param out [out] Destination buffer
|
||||
@param outlen [in/out] Max size / resulting size
|
||||
@param flag 0 for Ed448/Ed448ctx, 1 for Ed448ph
|
||||
@param ctx Context string (may be NULL if ctxlen==0)
|
||||
@param ctxlen Length of context (0..255)
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int ec448_crypto_ctx(unsigned char *out, unsigned long *outlen, unsigned char flag,
|
||||
const unsigned char *ctx, unsigned long ctxlen)
|
||||
{
|
||||
unsigned char *buf = out;
|
||||
|
||||
const char *prefix = "SigEd448";
|
||||
const unsigned long prefix_len = 8;
|
||||
const unsigned char ctxlen8 = (unsigned char)ctxlen;
|
||||
|
||||
if (ctxlen > 255u) return CRYPT_INPUT_TOO_LONG;
|
||||
if (*outlen < prefix_len + 2u + ctxlen) return CRYPT_BUFFER_OVERFLOW;
|
||||
|
||||
XMEMCPY(buf, prefix, prefix_len);
|
||||
buf += prefix_len;
|
||||
XMEMCPY(buf, &flag, 1);
|
||||
buf++;
|
||||
XMEMCPY(buf, &ctxlen8, 1);
|
||||
buf++;
|
||||
|
||||
if (ctxlen > 0u) {
|
||||
LTC_ARGCHK(ctx != NULL);
|
||||
XMEMCPY(buf, ctx, ctxlen);
|
||||
buf += ctxlen;
|
||||
}
|
||||
|
||||
*outlen = (unsigned long)(buf - out);
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
98
src/pk/ec448/ec448_export.c
Normal file
98
src/pk/ec448/ec448_export.c
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file ec448_export.c
|
||||
Generic export of a Curve448 key to a binary packet
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
/**
|
||||
Generic export of a Curve448 key to a binary packet
|
||||
@param out [out] The destination for the key
|
||||
@param outlen [in/out] The max size and resulting size of the key
|
||||
@param which Which type of key (PK_PRIVATE, PK_PUBLIC|PK_STD or PK_PUBLIC)
|
||||
@param key The key you wish to export
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int ec448_export( unsigned char *out, unsigned long *outlen,
|
||||
int which,
|
||||
const curve448_key *key)
|
||||
{
|
||||
int err, std;
|
||||
const char* OID;
|
||||
unsigned long oid[16], oidlen;
|
||||
ltc_asn1_list alg_id[1];
|
||||
enum ltc_oid_id oid_id;
|
||||
unsigned char private_key[59];
|
||||
unsigned long version, private_key_len = sizeof(private_key);
|
||||
unsigned long key_sz;
|
||||
|
||||
LTC_ARGCHK(out != NULL);
|
||||
LTC_ARGCHK(outlen != NULL);
|
||||
LTC_ARGCHK(key != NULL);
|
||||
|
||||
std = which & PK_STD;
|
||||
which &= ~PK_STD;
|
||||
if ((err = pk_get_oid_id(key->pka, &oid_id)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* X448 keys are 56 bytes, Ed448 keys are 57 bytes */
|
||||
key_sz = (key->pka == LTC_PKA_ED448) ? 57uL : 56uL;
|
||||
|
||||
if (which == PK_PRIVATE) {
|
||||
if(key->type != PK_PRIVATE) return CRYPT_PK_INVALID_TYPE;
|
||||
|
||||
if (std == PK_STD) {
|
||||
if ((err = pk_get_oid(oid_id, &OID)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
oidlen = LTC_ARRAY_SIZE(oid);
|
||||
if ((err = pk_oid_str_to_num(OID, oid, &oidlen)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid, oidlen);
|
||||
|
||||
/* encode private key as PKCS#8 */
|
||||
if ((err = der_encode_octet_string(key->priv, key_sz, private_key, &private_key_len)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
version = 0;
|
||||
err = der_encode_sequence_multi(out, outlen,
|
||||
LTC_ASN1_SHORT_INTEGER, 1uL, &version,
|
||||
LTC_ASN1_SEQUENCE, 1uL, alg_id,
|
||||
LTC_ASN1_OCTET_STRING, private_key_len, private_key,
|
||||
LTC_ASN1_EOL, 0uL, NULL);
|
||||
} else {
|
||||
if (*outlen < key_sz) {
|
||||
err = CRYPT_BUFFER_OVERFLOW;
|
||||
} else {
|
||||
XMEMCPY(out, key->priv, key_sz);
|
||||
err = CRYPT_OK;
|
||||
}
|
||||
*outlen = key_sz;
|
||||
}
|
||||
} else {
|
||||
if (std == PK_STD) {
|
||||
/* encode public key as SubjectPublicKeyInfo */
|
||||
err = x509_encode_subject_public_key_info(out, outlen, oid_id, key->pub, key_sz, LTC_ASN1_EOL, NULL, 0);
|
||||
} else {
|
||||
if (*outlen < key_sz) {
|
||||
err = CRYPT_BUFFER_OVERFLOW;
|
||||
} else {
|
||||
XMEMCPY(out, key->pub, key_sz);
|
||||
err = CRYPT_OK;
|
||||
}
|
||||
*outlen = key_sz;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
86
src/pk/ec448/ec448_import_pkcs8.c
Normal file
86
src/pk/ec448/ec448_import_pkcs8.c
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file ec448_import_pkcs8.c
|
||||
Generic import of a Curve448 private key in PKCS#8 format
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
typedef int (*sk_to_pk)(unsigned char *pk, const unsigned char *sk);
|
||||
|
||||
int ec448_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key,
|
||||
enum ltc_oid_id id,
|
||||
curve448_key *key)
|
||||
{
|
||||
int err;
|
||||
unsigned long key_len;
|
||||
sk_to_pk fp;
|
||||
|
||||
LTC_ARGCHK(key != NULL);
|
||||
LTC_ARGCHK(ltc_mp.name != NULL);
|
||||
|
||||
LTC_UNUSED_PARAM(alg_id);
|
||||
|
||||
switch (id) {
|
||||
case LTC_OID_X448:
|
||||
fp = ec448_scalarmult_base_internal;
|
||||
break;
|
||||
case LTC_OID_ED448:
|
||||
fp = ec448_sk_to_pk_internal;
|
||||
break;
|
||||
default:
|
||||
return CRYPT_PK_INVALID_TYPE;
|
||||
}
|
||||
|
||||
key_len = sizeof(key->priv);
|
||||
if ((err = der_decode_octet_string(priv_key->data, priv_key->size, key->priv, &key_len)) == CRYPT_OK) {
|
||||
fp(key->pub, key->priv);
|
||||
key->type = PK_PRIVATE;
|
||||
err = pk_get_pka_id(id, &key->pka);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
Generic import of a Curve448 private key in PKCS#8 format
|
||||
@param in The packet to import from
|
||||
@param inlen It's length (octets)
|
||||
@param pw_ctx The password context when decrypting the private key
|
||||
@param id The type of the private key
|
||||
@param key [out] Destination for newly imported key
|
||||
@return CRYPT_OK if successful, on error all allocated memory is freed automatically
|
||||
*/
|
||||
int ec448_import_pkcs8(const unsigned char *in, unsigned long inlen,
|
||||
const password_ctx *pw_ctx,
|
||||
enum ltc_oid_id id,
|
||||
curve448_key *key)
|
||||
{
|
||||
int err;
|
||||
ltc_asn1_list *l = NULL;
|
||||
ltc_asn1_list *alg_id, *priv_key;
|
||||
enum ltc_oid_id pka;
|
||||
|
||||
LTC_ARGCHK(in != NULL);
|
||||
|
||||
err = pkcs8_decode_flexi(in, inlen, pw_ctx, &l);
|
||||
if (err != CRYPT_OK) return err;
|
||||
|
||||
if ((err = pkcs8_get_children(l, &pka, &alg_id, &priv_key)) != CRYPT_OK) {
|
||||
goto LBL_DER_FREE;
|
||||
}
|
||||
if (pka != id) {
|
||||
err = CRYPT_INVALID_PACKET;
|
||||
goto LBL_DER_FREE;
|
||||
}
|
||||
|
||||
err = ec448_import_pkcs8_asn1(alg_id, priv_key, id, key);
|
||||
|
||||
LBL_DER_FREE:
|
||||
der_free_sequence_flexi(l);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
31
src/pk/ed448/ed448_export.c
Normal file
31
src/pk/ed448/ed448_export.c
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file ed448_export.c
|
||||
Export an Ed448 key to a binary packet, Steffen Jaeckel
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
/**
|
||||
Export an Ed448 key to a binary packet
|
||||
@param out [out] The destination for the key
|
||||
@param outlen [in/out] The max size and resulting size of the Ed448 key
|
||||
@param which Which type of key (PK_PRIVATE, PK_PUBLIC|PK_STD or PK_PUBLIC)
|
||||
@param key The key you wish to export
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int ed448_export( unsigned char *out, unsigned long *outlen,
|
||||
int which,
|
||||
const curve448_key *key)
|
||||
{
|
||||
LTC_ARGCHK(key != NULL);
|
||||
|
||||
if (key->pka != LTC_PKA_ED448) return CRYPT_PK_INVALID_TYPE;
|
||||
|
||||
return ec448_export(out, outlen, which, key);
|
||||
}
|
||||
|
||||
#endif
|
||||
35
src/pk/ed448/ed448_import.c
Normal file
35
src/pk/ed448/ed448_import.c
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file ed448_import.c
|
||||
Import an Ed448 key from a SubjectPublicKeyInfo, Steffen Jaeckel
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
/**
|
||||
Import an Ed448 public key
|
||||
@param in The packet to read
|
||||
@param inlen The length of the input packet
|
||||
@param key [out] Where to import the key to
|
||||
@return CRYPT_OK if successful, on error all allocated memory is freed automatically
|
||||
*/
|
||||
int ed448_import(const unsigned char *in, unsigned long inlen, curve448_key *key)
|
||||
{
|
||||
int err;
|
||||
unsigned long key_len;
|
||||
|
||||
LTC_ARGCHK(in != NULL);
|
||||
LTC_ARGCHK(key != NULL);
|
||||
|
||||
key_len = sizeof(key->pub);
|
||||
if ((err = x509_decode_subject_public_key_info(in, inlen, LTC_OID_ED448, key->pub, &key_len, LTC_ASN1_EOL, NULL, 0uL)) == CRYPT_OK) {
|
||||
key->type = PK_PUBLIC;
|
||||
key->pka = LTC_PKA_ED448;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
33
src/pk/ed448/ed448_import_pkcs8.c
Normal file
33
src/pk/ed448/ed448_import_pkcs8.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file ed448_import_pkcs8.c
|
||||
Import an Ed448 key in PKCS#8 format, Steffen Jaeckel
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
int ed448_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key,
|
||||
curve448_key *key)
|
||||
{
|
||||
return ec448_import_pkcs8_asn1(alg_id, priv_key, LTC_OID_ED448, key);
|
||||
}
|
||||
|
||||
/**
|
||||
Import an Ed448 private key in PKCS#8 format
|
||||
@param in The packet to import from
|
||||
@param inlen It's length (octets)
|
||||
@param pw_ctx The password context when decrypting the private key
|
||||
@param key [out] Destination for newly imported key
|
||||
@return CRYPT_OK if successful, on error all allocated memory is freed automatically
|
||||
*/
|
||||
int ed448_import_pkcs8(const unsigned char *in, unsigned long inlen,
|
||||
const password_ctx *pw_ctx,
|
||||
curve448_key *key)
|
||||
{
|
||||
return ec448_import_pkcs8(in, inlen, pw_ctx, LTC_OID_ED448, key);
|
||||
}
|
||||
|
||||
#endif
|
||||
42
src/pk/ed448/ed448_import_raw.c
Normal file
42
src/pk/ed448/ed448_import_raw.c
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file ed448_import_raw.c
|
||||
Set the parameters of an Ed448 key, Steffen Jaeckel
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
/**
|
||||
Set the parameters of an Ed448 key
|
||||
|
||||
@param in The key
|
||||
@param inlen The length of the key
|
||||
@param which Which type of key (PK_PRIVATE or PK_PUBLIC)
|
||||
@param key [out] Destination of the key
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int ed448_import_raw(const unsigned char *in, unsigned long inlen, int which, curve448_key *key)
|
||||
{
|
||||
LTC_ARGCHK(in != NULL);
|
||||
LTC_ARGCHK(key != NULL);
|
||||
|
||||
if (which == PK_PRIVATE) {
|
||||
LTC_ARGCHK(inlen == 57uL);
|
||||
XMEMCPY(key->priv, in, sizeof(key->priv));
|
||||
ec448_sk_to_pk_internal(key->pub, key->priv);
|
||||
} else if (which == PK_PUBLIC) {
|
||||
LTC_ARGCHK(inlen == 57uL);
|
||||
XMEMCPY(key->pub, in, sizeof(key->pub));
|
||||
} else {
|
||||
return CRYPT_INVALID_ARG;
|
||||
}
|
||||
key->pka = LTC_PKA_ED448;
|
||||
key->type = which;
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
45
src/pk/ed448/ed448_import_x509.c
Normal file
45
src/pk/ed448/ed448_import_x509.c
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file ed448_import_x509.c
|
||||
Import an Ed448 key from a X.509 certificate, Steffen Jaeckel
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
static int s_ed448_decode(const unsigned char *in, unsigned long inlen, curve448_key *key)
|
||||
{
|
||||
if (inlen != sizeof(key->pub)) return CRYPT_PK_INVALID_SIZE;
|
||||
XMEMCPY(key->pub, in, sizeof(key->pub));
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Import an Ed448 public key from a X.509 certificate
|
||||
@param in The DER encoded X.509 certificate
|
||||
@param inlen The length of the certificate
|
||||
@param key [out] Where to import the key to
|
||||
@return CRYPT_OK if successful, on error all allocated memory is freed automatically
|
||||
*/
|
||||
int ed448_import_x509(const unsigned char *in, unsigned long inlen, curve448_key *key)
|
||||
{
|
||||
int err;
|
||||
|
||||
LTC_ARGCHK(in != NULL);
|
||||
LTC_ARGCHK(key != NULL);
|
||||
|
||||
if ((err = x509_decode_public_key_from_certificate(in, inlen,
|
||||
LTC_OID_ED448,
|
||||
LTC_ASN1_EOL, NULL, NULL,
|
||||
(public_key_decode_cb)s_ed448_decode, key)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
key->type = PK_PUBLIC;
|
||||
key->pka = LTC_PKA_ED448;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
36
src/pk/ed448/ed448_make_key.c
Normal file
36
src/pk/ed448/ed448_make_key.c
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file ed448_make_key.c
|
||||
Create an Ed448 key, Steffen Jaeckel
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
/**
|
||||
Create an Ed448 key
|
||||
@param prng An active PRNG state
|
||||
@param wprng The index of the PRNG desired
|
||||
@param key [out] Destination of a newly created private key pair
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int ed448_make_key(prng_state *prng, int wprng, curve448_key *key)
|
||||
{
|
||||
int err;
|
||||
|
||||
LTC_ARGCHK(prng != NULL);
|
||||
LTC_ARGCHK(key != NULL);
|
||||
|
||||
if ((err = ec448_keypair_internal(prng, wprng, key->pub, key->priv)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
key->type = PK_PRIVATE;
|
||||
key->pka = LTC_PKA_ED448;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
136
src/pk/ed448/ed448_sign.c
Normal file
136
src/pk/ed448/ed448_sign.c
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file ed448_sign.c
|
||||
Create an Ed448 signature, Steffen Jaeckel
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
static int s_ed448_sign(const unsigned char *msg, unsigned long msglen,
|
||||
unsigned char *sig, unsigned long *siglen,
|
||||
const unsigned char *ctx, unsigned long ctxlen,
|
||||
const curve448_key *private_key)
|
||||
{
|
||||
unsigned char *s;
|
||||
unsigned long long smlen;
|
||||
int err;
|
||||
|
||||
LTC_ARGCHK(msg != NULL);
|
||||
LTC_ARGCHK(sig != NULL);
|
||||
LTC_ARGCHK(siglen != NULL);
|
||||
LTC_ARGCHK(private_key != NULL);
|
||||
|
||||
if (private_key->pka != LTC_PKA_ED448) return CRYPT_PK_INVALID_TYPE;
|
||||
if (private_key->type != PK_PRIVATE) return CRYPT_PK_INVALID_TYPE;
|
||||
|
||||
if (*siglen < 114uL) {
|
||||
*siglen = 114uL;
|
||||
return CRYPT_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
smlen = msglen + 114;
|
||||
s = XMALLOC((unsigned long)smlen);
|
||||
if (s == NULL) return CRYPT_MEM;
|
||||
|
||||
err = ec448_sign_internal(s, &smlen,
|
||||
msg, msglen,
|
||||
private_key->priv, private_key->pub,
|
||||
ctx, ctxlen);
|
||||
|
||||
XMEMCPY(sig, s, 114uL);
|
||||
*siglen = 114uL;
|
||||
|
||||
#ifdef LTC_CLEAN_STACK
|
||||
zeromem(s, (unsigned long)smlen);
|
||||
#endif
|
||||
XFREE(s);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
Create an Ed448ctx signature.
|
||||
@param msg The data to be signed
|
||||
@param msglen [in] The size of the data to be signed
|
||||
@param sig [out] The destination of the signature
|
||||
@param siglen [in/out] The max size and resulting size of the signature
|
||||
@param ctx [in] The context
|
||||
@param ctxlen [in] The size of the context
|
||||
@param private_key The private Ed448 key in the pair
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int ed448ctx_sign(const unsigned char *msg, unsigned long msglen,
|
||||
unsigned char *sig, unsigned long *siglen,
|
||||
const unsigned char *ctx, unsigned long ctxlen,
|
||||
const curve448_key *private_key)
|
||||
{
|
||||
int err;
|
||||
unsigned char ctx_prefix[266];
|
||||
unsigned long ctx_prefix_size = sizeof(ctx_prefix);
|
||||
|
||||
LTC_ARGCHK(ctx != NULL);
|
||||
|
||||
if ((err = ec448_crypto_ctx(ctx_prefix, &ctx_prefix_size, 0, ctx, ctxlen)) != CRYPT_OK)
|
||||
return err;
|
||||
|
||||
return s_ed448_sign(msg, msglen, sig, siglen, ctx_prefix, ctx_prefix_size, private_key);
|
||||
}
|
||||
|
||||
/**
|
||||
Create an Ed448ph signature.
|
||||
@param msg The data to be signed
|
||||
@param msglen [in] The size of the data to be signed
|
||||
@param sig [out] The destination of the signature
|
||||
@param siglen [in/out] The max size and resulting size of the signature
|
||||
@param ctx [in] The context
|
||||
@param ctxlen [in] The size of the context
|
||||
@param private_key The private Ed448 key in the pair
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int ed448ph_sign(const unsigned char *msg, unsigned long msglen,
|
||||
unsigned char *sig, unsigned long *siglen,
|
||||
const unsigned char *ctx, unsigned long ctxlen,
|
||||
const curve448_key *private_key)
|
||||
{
|
||||
int err;
|
||||
unsigned char msg_hash[64];
|
||||
unsigned char ctx_prefix[266];
|
||||
unsigned long ctx_prefix_size = sizeof(ctx_prefix);
|
||||
|
||||
if ((err = ec448_crypto_ctx(ctx_prefix, &ctx_prefix_size, 1, ctx, ctxlen)) != CRYPT_OK)
|
||||
return err;
|
||||
|
||||
if ((err = ec448_prehash_internal(msg_hash, msg, msglen)) != CRYPT_OK)
|
||||
return err;
|
||||
|
||||
return s_ed448_sign(msg_hash, sizeof(msg_hash), sig, siglen, ctx_prefix, ctx_prefix_size, private_key);
|
||||
}
|
||||
|
||||
/**
|
||||
Create an Ed448 signature (pure mode).
|
||||
@param msg The data to be signed
|
||||
@param msglen [in] The size of the data to be signed
|
||||
@param sig [out] The destination of the signature
|
||||
@param siglen [in/out] The max size and resulting size of the signature
|
||||
@param private_key The private Ed448 key in the pair
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int ed448_sign(const unsigned char *msg, unsigned long msglen,
|
||||
unsigned char *sig, unsigned long *siglen,
|
||||
const curve448_key *private_key)
|
||||
{
|
||||
int err;
|
||||
unsigned char ctx_prefix[266];
|
||||
unsigned long ctx_prefix_size = sizeof(ctx_prefix);
|
||||
|
||||
/* Pure Ed448 still uses DOM4 with flag=0 and empty context */
|
||||
if ((err = ec448_crypto_ctx(ctx_prefix, &ctx_prefix_size, 0, NULL, 0)) != CRYPT_OK)
|
||||
return err;
|
||||
|
||||
return s_ed448_sign(msg, msglen, sig, siglen, ctx_prefix, ctx_prefix_size, private_key);
|
||||
}
|
||||
|
||||
#endif
|
||||
143
src/pk/ed448/ed448_verify.c
Normal file
143
src/pk/ed448/ed448_verify.c
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file ed448_verify.c
|
||||
Verify an Ed448 signature, Steffen Jaeckel
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
static int s_ed448_verify(const unsigned char *msg, unsigned long msglen,
|
||||
const unsigned char *sig, unsigned long siglen,
|
||||
const unsigned char *ctx, unsigned long ctxlen,
|
||||
int *stat,
|
||||
const curve448_key *public_key)
|
||||
{
|
||||
unsigned char *m;
|
||||
unsigned long long mlen;
|
||||
int err;
|
||||
|
||||
LTC_ARGCHK(msg != NULL);
|
||||
LTC_ARGCHK(sig != NULL);
|
||||
LTC_ARGCHK(stat != NULL);
|
||||
LTC_ARGCHK(public_key != NULL);
|
||||
|
||||
*stat = 0;
|
||||
|
||||
if (siglen != 114uL) return CRYPT_INVALID_ARG;
|
||||
if (public_key->pka != LTC_PKA_ED448) return CRYPT_PK_INVALID_TYPE;
|
||||
|
||||
mlen = msglen + siglen;
|
||||
if ((mlen < msglen) || (mlen < siglen)) return CRYPT_OVERFLOW;
|
||||
|
||||
m = XMALLOC((unsigned long)mlen);
|
||||
if (m == NULL) return CRYPT_MEM;
|
||||
|
||||
XMEMCPY(m, sig, siglen);
|
||||
XMEMCPY(m + siglen, msg, msglen);
|
||||
|
||||
err = ec448_verify_internal(stat,
|
||||
m, &mlen,
|
||||
m, mlen,
|
||||
ctx, ctxlen,
|
||||
public_key->pub);
|
||||
|
||||
#ifdef LTC_CLEAN_STACK
|
||||
zeromem(m, msglen + siglen);
|
||||
#endif
|
||||
XFREE(m);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
Verify an Ed448ctx signature.
|
||||
@param msg [in] The data to be verified
|
||||
@param msglen [in] The size of the data to be verified
|
||||
@param sig [in] The signature to be verified
|
||||
@param siglen [in] The size of the signature to be verified
|
||||
@param ctx [in] The context
|
||||
@param ctxlen [in] The size of the context
|
||||
@param stat [out] The result of the signature verification, 1==valid, 0==invalid
|
||||
@param public_key [in] The public Ed448 key in the pair
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int ed448ctx_verify(const unsigned char *msg, unsigned long msglen,
|
||||
const unsigned char *sig, unsigned long siglen,
|
||||
const unsigned char *ctx, unsigned long ctxlen,
|
||||
int *stat,
|
||||
const curve448_key *public_key)
|
||||
{
|
||||
int err;
|
||||
unsigned char ctx_prefix[266];
|
||||
unsigned long ctx_prefix_size = sizeof(ctx_prefix);
|
||||
|
||||
LTC_ARGCHK(ctx != NULL);
|
||||
|
||||
if ((err = ec448_crypto_ctx(ctx_prefix, &ctx_prefix_size, 0, ctx, ctxlen)) != CRYPT_OK)
|
||||
return err;
|
||||
|
||||
return s_ed448_verify(msg, msglen, sig, siglen, ctx_prefix, ctx_prefix_size, stat, public_key);
|
||||
}
|
||||
|
||||
/**
|
||||
Verify an Ed448ph signature.
|
||||
@param msg [in] The data to be verified
|
||||
@param msglen [in] The size of the data to be verified
|
||||
@param sig [in] The signature to be verified
|
||||
@param siglen [in] The size of the signature to be verified
|
||||
@param ctx [in] The context
|
||||
@param ctxlen [in] The size of the context
|
||||
@param stat [out] The result of the signature verification, 1==valid, 0==invalid
|
||||
@param public_key [in] The public Ed448 key in the pair
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int ed448ph_verify(const unsigned char *msg, unsigned long msglen,
|
||||
const unsigned char *sig, unsigned long siglen,
|
||||
const unsigned char *ctx, unsigned long ctxlen,
|
||||
int *stat,
|
||||
const curve448_key *public_key)
|
||||
{
|
||||
int err;
|
||||
unsigned char msg_hash[64];
|
||||
unsigned char ctx_prefix[266];
|
||||
unsigned long ctx_prefix_size = sizeof(ctx_prefix);
|
||||
|
||||
if ((err = ec448_crypto_ctx(ctx_prefix, &ctx_prefix_size, 1, ctx, ctxlen)) != CRYPT_OK)
|
||||
return err;
|
||||
|
||||
if ((err = ec448_prehash_internal(msg_hash, msg, msglen)) != CRYPT_OK)
|
||||
return err;
|
||||
|
||||
return s_ed448_verify(msg_hash, sizeof(msg_hash), sig, siglen, ctx_prefix, ctx_prefix_size, stat, public_key);
|
||||
}
|
||||
|
||||
/**
|
||||
Verify an Ed448 signature (pure mode).
|
||||
@param msg [in] The data to be verified
|
||||
@param msglen [in] The size of the data to be verified
|
||||
@param sig [in] The signature to be verified
|
||||
@param siglen [in] The size of the signature to be verified
|
||||
@param stat [out] The result of the signature verification, 1==valid, 0==invalid
|
||||
@param public_key [in] The public Ed448 key in the pair
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int ed448_verify(const unsigned char *msg, unsigned long msglen,
|
||||
const unsigned char *sig, unsigned long siglen,
|
||||
int *stat,
|
||||
const curve448_key *public_key)
|
||||
{
|
||||
int err;
|
||||
unsigned char ctx_prefix[266];
|
||||
unsigned long ctx_prefix_size = sizeof(ctx_prefix);
|
||||
|
||||
/* Pure Ed448 still uses DOM4 with flag=0 and empty context */
|
||||
if ((err = ec448_crypto_ctx(ctx_prefix, &ctx_prefix_size, 0, NULL, 0)) != CRYPT_OK)
|
||||
return err;
|
||||
|
||||
return s_ed448_verify(msg, msglen, sig, siglen, ctx_prefix, ctx_prefix_size, stat, public_key);
|
||||
}
|
||||
|
||||
#endif
|
||||
31
src/pk/x448/x448_export.c
Normal file
31
src/pk/x448/x448_export.c
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file x448_export.c
|
||||
Export a X448 key to a binary packet
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
/**
|
||||
Export a X448 key to a binary packet
|
||||
@param out [out] The destination for the key
|
||||
@param outlen [in/out] The max size and resulting size of the X448 key
|
||||
@param which Which type of key (PK_PRIVATE, PK_PUBLIC|PK_STD or PK_PUBLIC)
|
||||
@param key The key you wish to export
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int x448_export( unsigned char *out, unsigned long *outlen,
|
||||
int which,
|
||||
const curve448_key *key)
|
||||
{
|
||||
LTC_ARGCHK(key != NULL);
|
||||
|
||||
if (key->pka != LTC_PKA_X448) return CRYPT_PK_INVALID_TYPE;
|
||||
|
||||
return ec448_export(out, outlen, which, key);
|
||||
}
|
||||
|
||||
#endif
|
||||
35
src/pk/x448/x448_import.c
Normal file
35
src/pk/x448/x448_import.c
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file x448_import.c
|
||||
Import a X448 key from a SubjectPublicKeyInfo
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
/**
|
||||
Import a X448 key
|
||||
@param in The packet to read
|
||||
@param inlen The length of the input packet
|
||||
@param key [out] Where to import the key to
|
||||
@return CRYPT_OK if successful, on error all allocated memory is freed automatically
|
||||
*/
|
||||
int x448_import(const unsigned char *in, unsigned long inlen, curve448_key *key)
|
||||
{
|
||||
int err;
|
||||
unsigned long key_len;
|
||||
|
||||
LTC_ARGCHK(in != NULL);
|
||||
LTC_ARGCHK(key != NULL);
|
||||
|
||||
key_len = 56uL;
|
||||
if ((err = x509_decode_subject_public_key_info(in, inlen, LTC_OID_X448, key->pub, &key_len, LTC_ASN1_EOL, NULL, 0uL)) == CRYPT_OK) {
|
||||
key->type = PK_PUBLIC;
|
||||
key->pka = LTC_PKA_X448;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
33
src/pk/x448/x448_import_pkcs8.c
Normal file
33
src/pk/x448/x448_import_pkcs8.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file x448_import_pkcs8.c
|
||||
Import a X448 key in PKCS#8 format
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
int x448_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key,
|
||||
curve448_key *key)
|
||||
{
|
||||
return ec448_import_pkcs8_asn1(alg_id, priv_key, LTC_OID_X448, key);
|
||||
}
|
||||
|
||||
/**
|
||||
Import a X448 private key in PKCS#8 format
|
||||
@param in The packet to import from
|
||||
@param inlen It's length (octets)
|
||||
@param pw_ctx The password context when decrypting the private key
|
||||
@param key [out] Destination for newly imported key
|
||||
@return CRYPT_OK if successful, on error all allocated memory is freed automatically
|
||||
*/
|
||||
int x448_import_pkcs8(const unsigned char *in, unsigned long inlen,
|
||||
const password_ctx *pw_ctx,
|
||||
curve448_key *key)
|
||||
{
|
||||
return ec448_import_pkcs8(in, inlen, pw_ctx, LTC_OID_X448, key);
|
||||
}
|
||||
|
||||
#endif
|
||||
41
src/pk/x448/x448_import_raw.c
Normal file
41
src/pk/x448/x448_import_raw.c
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file x448_import_raw.c
|
||||
Set the parameters of a X448 key
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
/**
|
||||
Set the parameters of a X448 key
|
||||
|
||||
@param in The key
|
||||
@param inlen The length of the key
|
||||
@param which Which type of key (PK_PRIVATE or PK_PUBLIC)
|
||||
@param key [out] Destination of the key
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int x448_import_raw(const unsigned char *in, unsigned long inlen, int which, curve448_key *key)
|
||||
{
|
||||
LTC_ARGCHK(in != NULL);
|
||||
LTC_ARGCHK(inlen == 56uL);
|
||||
LTC_ARGCHK(key != NULL);
|
||||
|
||||
if (which == PK_PRIVATE) {
|
||||
XMEMCPY(key->priv, in, 56uL);
|
||||
ec448_scalarmult_base_internal(key->pub, key->priv);
|
||||
} else if (which == PK_PUBLIC) {
|
||||
XMEMCPY(key->pub, in, 56uL);
|
||||
} else {
|
||||
return CRYPT_INVALID_ARG;
|
||||
}
|
||||
key->pka = LTC_PKA_X448;
|
||||
key->type = which;
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
45
src/pk/x448/x448_import_x509.c
Normal file
45
src/pk/x448/x448_import_x509.c
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file x448_import_x509.c
|
||||
Import a X448 key from a X.509 certificate
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
static int s_x448_decode(const unsigned char *in, unsigned long inlen, curve448_key *key)
|
||||
{
|
||||
if (inlen != 56uL) return CRYPT_PK_INVALID_SIZE;
|
||||
XMEMCPY(key->pub, in, 56uL);
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Import a X448 public key from a X.509 certificate
|
||||
@param in The DER encoded X.509 certificate
|
||||
@param inlen The length of the certificate
|
||||
@param key [out] Where to import the key to
|
||||
@return CRYPT_OK if successful, on error all allocated memory is freed automatically
|
||||
*/
|
||||
int x448_import_x509(const unsigned char *in, unsigned long inlen, curve448_key *key)
|
||||
{
|
||||
int err;
|
||||
|
||||
LTC_ARGCHK(in != NULL);
|
||||
LTC_ARGCHK(key != NULL);
|
||||
|
||||
if ((err = x509_decode_public_key_from_certificate(in, inlen,
|
||||
LTC_OID_X448,
|
||||
LTC_ASN1_EOL, NULL, NULL,
|
||||
(public_key_decode_cb)s_x448_decode, key)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
key->type = PK_PUBLIC;
|
||||
key->pka = LTC_PKA_X448;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
42
src/pk/x448/x448_make_key.c
Normal file
42
src/pk/x448/x448_make_key.c
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file x448_make_key.c
|
||||
Create a X448 key
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
/**
|
||||
Create a X448 key
|
||||
@param prng An active PRNG state
|
||||
@param wprng The index of the PRNG desired
|
||||
@param key [out] Destination of a newly created private key pair
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int x448_make_key(prng_state *prng, int wprng, curve448_key *key)
|
||||
{
|
||||
int err;
|
||||
|
||||
LTC_ARGCHK(prng != NULL);
|
||||
LTC_ARGCHK(key != NULL);
|
||||
|
||||
if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (prng_descriptor[wprng].read(key->priv, 56uL, prng) != 56uL) {
|
||||
return CRYPT_ERROR_READPRNG;
|
||||
}
|
||||
|
||||
ec448_scalarmult_base_internal(key->pub, key->priv);
|
||||
|
||||
key->type = PK_PRIVATE;
|
||||
key->pka = LTC_PKA_X448;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
43
src/pk/x448/x448_shared_secret.c
Normal file
43
src/pk/x448/x448_shared_secret.c
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_private.h"
|
||||
|
||||
/**
|
||||
@file x448_shared_secret.c
|
||||
Create a X448 shared secret
|
||||
*/
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
/**
|
||||
Create a X448 shared secret.
|
||||
@param private_key The private X448 key in the pair
|
||||
@param public_key The public X448 key in the pair
|
||||
@param out [out] The destination of the shared data
|
||||
@param outlen [in/out] The max size and resulting size of the shared data.
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int x448_shared_secret(const curve448_key *private_key,
|
||||
const curve448_key *public_key,
|
||||
unsigned char *out, unsigned long *outlen)
|
||||
{
|
||||
LTC_ARGCHK(private_key != NULL);
|
||||
LTC_ARGCHK(public_key != NULL);
|
||||
LTC_ARGCHK(out != NULL);
|
||||
LTC_ARGCHK(outlen != NULL);
|
||||
|
||||
if (public_key->pka != LTC_PKA_X448) return CRYPT_PK_INVALID_TYPE;
|
||||
if (private_key->type != PK_PRIVATE) return CRYPT_PK_INVALID_TYPE;
|
||||
|
||||
if (*outlen < 56uL) {
|
||||
*outlen = 56uL;
|
||||
return CRYPT_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
ec448_scalarmult_internal(out, private_key->priv, public_key->pub);
|
||||
*outlen = 56uL;
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
439
tests/ed448_test.c
Normal file
439
tests/ed448_test.c
Normal file
|
|
@ -0,0 +1,439 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_test.h"
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
typedef struct {
|
||||
const char *secret_key;
|
||||
const char *public_key;
|
||||
const char *message;
|
||||
const char *signature;
|
||||
const char *context;
|
||||
} rfc_8032_t;
|
||||
|
||||
static int s_ed448_keygen_sign_verify(void)
|
||||
{
|
||||
curve448_key key, pubkey;
|
||||
const unsigned char msg[] = "test message";
|
||||
unsigned char sig[114], pk_buf[57];
|
||||
unsigned long siglen, pklen;
|
||||
int stat, prng_idx;
|
||||
|
||||
prng_idx = find_prng("yarrow");
|
||||
|
||||
/* keygen */
|
||||
DO(ed448_make_key(&yarrow_prng, prng_idx, &key));
|
||||
ENSURE(key.type == PK_PRIVATE);
|
||||
ENSURE(key.pka == LTC_PKA_ED448);
|
||||
|
||||
/* sign */
|
||||
siglen = sizeof(sig);
|
||||
DO(ed448_sign(msg, sizeof(msg), sig, &siglen, &key));
|
||||
ENSURE(siglen == 114);
|
||||
|
||||
/* export/import public key */
|
||||
pklen = sizeof(pk_buf);
|
||||
DO(ed448_export(pk_buf, &pklen, PK_PUBLIC, &key));
|
||||
DO(ed448_import_raw(pk_buf, pklen, PK_PUBLIC, &pubkey));
|
||||
|
||||
/* verify */
|
||||
stat = 0;
|
||||
DO(ed448_verify(msg, sizeof(msg), sig, siglen, &stat, &pubkey));
|
||||
ENSURE(stat == 1);
|
||||
|
||||
/* corrupted sig must fail */
|
||||
sig[0] ^= 1;
|
||||
stat = 1;
|
||||
DO(ed448_verify(msg, sizeof(msg), sig, siglen, &stat, &pubkey));
|
||||
ENSURE(stat == 0);
|
||||
|
||||
/* sign with context */
|
||||
siglen = sizeof(sig);
|
||||
DO(ed448ctx_sign(msg, sizeof(msg), sig, &siglen,
|
||||
(const unsigned char *)"ctx", 3, &key));
|
||||
stat = 0;
|
||||
DO(ed448ctx_verify(msg, sizeof(msg), sig, siglen,
|
||||
(const unsigned char *)"ctx", 3, &stat, &pubkey));
|
||||
ENSURE(stat == 1);
|
||||
|
||||
/* wrong context must fail */
|
||||
stat = 1;
|
||||
DO(ed448ctx_verify(msg, sizeof(msg), sig, siglen,
|
||||
(const unsigned char *)"bad", 3, &stat, &pubkey));
|
||||
ENSURE(stat == 0);
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* RFC 8032 Section 5.2.6 - Ed448 (pure, no context) */
|
||||
static int s_rfc_8032_5_2_6_pure_test(void)
|
||||
{
|
||||
const rfc_8032_t vectors[] = {
|
||||
{
|
||||
/* 1: empty message */
|
||||
"6c82a562cb808d10d632be89c8513ebf6c929f34ddfa8c9f63c9960ef6e348a3"
|
||||
"528c8a3fcc2f044e39a3fc5b94492f8f032e7549a20098f95b",
|
||||
"5fd7449b59b461fd2ce787ec616ad46a1da1342485a70e1f8a0ea75d80e96778"
|
||||
"edf124769b46c7061bd6783df1e50f6cd1fa1abeafe8256180",
|
||||
"",
|
||||
"533a37f6bbe457251f023c0d88f976ae2dfb504a843e34d2074fd823d41a591f"
|
||||
"2b233f034f628281f2fd7a22ddd47d7828c59bd0a21bfd3980ff0d2028d4b18a"
|
||||
"9df63e006c5d1c2d345b925d8dc00b4104852db99ac5c7cdda8530a113a0f4db"
|
||||
"b61149f05a7363268c71d95808ff2e652600",
|
||||
NULL
|
||||
},
|
||||
{
|
||||
/* 2: 1 byte message */
|
||||
"c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463a"
|
||||
"fbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e",
|
||||
"43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c086"
|
||||
"6aea01eb00742802b8438ea4cb82169c235160627b4c3a9480",
|
||||
"03",
|
||||
"26b8f91727bd62897af15e41eb43c377efb9c610d48f2335cb0bd0087810f435"
|
||||
"2541b143c4b981b7e18f62de8ccdf633fc1bf037ab7cd779805e0dbcc0aae1cb"
|
||||
"cee1afb2e027df36bc04dcecbf154336c19f0af7e0a6472905e799f1953d2a0f"
|
||||
"f3348ab21aa4adafd1d234441cf807c03a00",
|
||||
NULL
|
||||
},
|
||||
{
|
||||
/* 4: 11 byte message */
|
||||
"cd23d24f714274e744343237b93290f511f6425f98e64459ff203e8985083ffd"
|
||||
"f60500553abc0e05cd02184bdb89c4ccd67e187951267eb328",
|
||||
"dcea9e78f35a1bf3499a831b10b86c90aac01cd84b67a0109b55a36e9328b1e3"
|
||||
"65fce161d71ce7131a543ea4cb5f7e9f1d8b00696447001400",
|
||||
"0c3e544074ec63b0265e0c",
|
||||
"1f0a8888ce25e8d458a21130879b840a9089d999aaba039eaf3e3afa090a09d3"
|
||||
"89dba82c4ff2ae8ac5cdfb7c55e94d5d961a29fe0109941e00b8dbdeea6d3b05"
|
||||
"1068df7254c0cdc129cbe62db2dc957dbb47b51fd3f213fb8698f064774250a5"
|
||||
"028961c9bf8ffd973fe5d5c206492b140e00",
|
||||
NULL
|
||||
},
|
||||
{
|
||||
/* 5: 12 byte message */
|
||||
"258cdd4ada32ed9c9ff54e63756ae582fb8fab2ac721f2c8e676a72768513d93"
|
||||
"9f63dddb55609133f29adf86ec9929dccb52c1c5fd2ff7e21b",
|
||||
"3ba16da0c6f2cc1f30187740756f5e798d6bc5fc015d7c63cc9510ee3fd44adc"
|
||||
"24d8e968b6e46e6f94d19b945361726bd75e149ef09817f580",
|
||||
"64a65f3cdedcdd66811e2915",
|
||||
"7eeeab7c4e50fb799b418ee5e3197ff6bf15d43a14c34389b59dd1a7b1b85b4a"
|
||||
"e90438aca634bea45e3a2695f1270f07fdcdf7c62b8efeaf00b45c2c96ba457e"
|
||||
"b1a8bf075a3db28e5c24f6b923ed4ad747c3c9e03c7079efb87cb110d3a99861"
|
||||
"e72003cbae6d6b8b827e4e6c143064ff3c00",
|
||||
NULL
|
||||
},
|
||||
{
|
||||
/* 6: 13 byte message */
|
||||
"7ef4e84544236752fbb56b8f31a23a10e42814f5f55ca037cdcc11c64c9a3b29"
|
||||
"49c1bb60700314611732a6c2fea98eebc0266a11a93970100e",
|
||||
"b3da079b0aa493a5772029f0467baebee5a8112d9d3a22532361da294f7bb381"
|
||||
"5c5dc59e176b4d9f381ca0938e13c6c07b174be65dfa578e80",
|
||||
"64a65f3cdedcdd66811e2915e7",
|
||||
"6a12066f55331b6c22acd5d5bfc5d71228fbda80ae8dec26bdd306743c5027cb"
|
||||
"4890810c162c027468675ecf645a83176c0d7323a2ccde2d80efe5a1268e8aca"
|
||||
"1d6fbc194d3f77c44986eb4ab4177919ad8bec33eb47bbb5fc6e28196fd1caf5"
|
||||
"6b4e7e0ba5519234d047155ac727a1053100",
|
||||
NULL
|
||||
},
|
||||
{
|
||||
/* 7: 64 byte message */
|
||||
"d65df341ad13e008567688baedda8e9dcdc17dc024974ea5b4227b6530e339bf"
|
||||
"f21f99e68ca6968f3cca6dfe0fb9f4fab4fa135d5542ea3f01",
|
||||
"df9705f58edbab802c7f8363cfe5560ab1c6132c20a9f1dd163483a26f8ac53a"
|
||||
"39d6808bf4a1dfbd261b099bb03b3fb50906cb28bd8a081f00",
|
||||
"bd0f6a3747cd561bdddf4640a332461a4a30a12a434cd0bf40d766d9c6d458e5"
|
||||
"512204a30c17d1f50b5079631f64eb3112182da3005835461113718d1a5ef944",
|
||||
"554bc2480860b49eab8532d2a533b7d578ef473eeb58c98bb2d0e1ce488a98b1"
|
||||
"8dfde9b9b90775e67f47d4a1c3482058efc9f40d2ca033a0801b63d45b3b722e"
|
||||
"f552bad3b4ccb667da350192b61c508cf7b6b5adadc2c8d9a446ef003fb05cba"
|
||||
"5f30e88e36ec2703b349ca229c2670833900",
|
||||
NULL
|
||||
},
|
||||
{
|
||||
/* 8: 256 byte message */
|
||||
"2ec5fe3c17045abdb136a5e6a913e32ab75ae68b53d2fc149b77e504132d3756"
|
||||
"9b7e766ba74a19bd6162343a21c8590aa9cebca9014c636df5",
|
||||
"79756f014dcfe2079f5dd9e718be4171e2ef2486a08f25186f6bff43a9936b9b"
|
||||
"fe12402b08ae65798a3d81e22e9ec80e7690862ef3d4ed3a00",
|
||||
"15777532b0bdd0d1389f636c5f6b9ba734c90af572877e2d272dd078aa1e567c"
|
||||
"fa80e12928bb542330e8409f3174504107ecd5efac61ae7504dabe2a602ede89"
|
||||
"e5cca6257a7c77e27a702b3ae39fc769fc54f2395ae6a1178cab4738e543072f"
|
||||
"c1c177fe71e92e25bf03e4ecb72f47b64d0465aaea4c7fad372536c8ba516a60"
|
||||
"39c3c2a39f0e4d832be432dfa9a706a6e5c7e19f397964ca4258002f7c0541b5"
|
||||
"90316dbc5622b6b2a6fe7a4abffd96105eca76ea7b98816af0748c10df048ce0"
|
||||
"12d901015a51f189f3888145c03650aa23ce894c3bd889e030d565071c59f409"
|
||||
"a9981b51878fd6fc110624dcbcde0bf7a69ccce38fabdf86f3bef6044819de11",
|
||||
"c650ddbb0601c19ca11439e1640dd931f43c518ea5bea70d3dcde5f4191fe53f"
|
||||
"00cf966546b72bcc7d58be2b9badef28743954e3a44a23f880e8d4f1cfce2d7a"
|
||||
"61452d26da05896f0a50da66a239a8a188b6d825b3305ad77b73fbac0836ecc6"
|
||||
"0987fd08527c1a8e80d5823e65cafe2a3d00",
|
||||
NULL
|
||||
},
|
||||
{
|
||||
/* 9: 1023 byte message */
|
||||
"872d093780f5d3730df7c212664b37b8a0f24f56810daa8382cd4fa3f77634ec"
|
||||
"44dc54f1c2ed9bea86fafb7632d8be199ea165f5ad55dd9ce8",
|
||||
"a81b2e8a70a5ac94ffdbcc9badfc3feb0801f258578bb114ad44ece1ec0e799d"
|
||||
"a08effb81c5d685c0c56f64eecaef8cdf11cc38737838cf400",
|
||||
"6ddf802e1aae4986935f7f981ba3f0351d6273c0a0c22c9c0e8339168e675412"
|
||||
"a3debfaf435ed651558007db4384b650fcc07e3b586a27a4f7a00ac8a6fec2cd"
|
||||
"86ae4bf1570c41e6a40c931db27b2faa15a8cedd52cff7362c4e6e23daec0fbc"
|
||||
"3a79b6806e316efcc7b68119bf46bc76a26067a53f296dafdbdc11c77f7777e9"
|
||||
"72660cf4b6a9b369a6665f02e0cc9b6edfad136b4fabe723d2813db3136cfde9"
|
||||
"b6d044322fee2947952e031b73ab5c603349b307bdc27bc6cb8b8bbd7bd32321"
|
||||
"9b8033a581b59eadebb09b3c4f3d2277d4f0343624acc817804728b25ab79717"
|
||||
"2b4c5c21a22f9c7839d64300232eb66e53f31c723fa37fe387c7d3e50bdf9813"
|
||||
"a30e5bb12cf4cd930c40cfb4e1fc622592a49588794494d56d24ea4b40c89fc0"
|
||||
"596cc9ebb961c8cb10adde976a5d602b1c3f85b9b9a001ed3c6a4d3b1437f520"
|
||||
"96cd1956d042a597d561a596ecd3d1735a8d570ea0ec27225a2c4aaff26306d1"
|
||||
"526c1af3ca6d9cf5a2c98f47e1c46db9a33234cfd4d81f2c98538a09ebe76998"
|
||||
"d0d8fd25997c7d255c6d66ece6fa56f11144950f027795e653008f4bd7ca2dee"
|
||||
"85d8e90f3dc315130ce2a00375a318c7c3d97be2c8ce5b6db41a6254ff264fa6"
|
||||
"155baee3b0773c0f497c573f19bb4f4240281f0b1f4f7be857a4e59d416c06b4"
|
||||
"c50fa09e1810ddc6b1467baeac5a3668d11b6ecaa901440016f389f80acc4db9"
|
||||
"77025e7f5924388c7e340a732e554440e76570f8dd71b7d640b3450d1fd5f041"
|
||||
"0a18f9a3494f707c717b79b4bf75c98400b096b21653b5d217cf3565c9597456"
|
||||
"f70703497a078763829bc01bb1cbc8fa04eadc9a6e3f6699587a9e75c94e5bab"
|
||||
"0036e0b2e711392cff0047d0d6b05bd2a588bc109718954259f1d86678a579a3"
|
||||
"120f19cfb2963f177aeb70f2d4844826262e51b80271272068ef5b3856fa8535"
|
||||
"aa2a88b2d41f2a0e2fda7624c2850272ac4a2f561f8f2f7a318bfd5caf969614"
|
||||
"9e4ac824ad3460538fdc25421beec2cc6818162d06bbed0c40a387192349db67"
|
||||
"a118bada6cd5ab0140ee273204f628aad1c135f770279a651e24d8c14d75a605"
|
||||
"9d76b96a6fd857def5e0b354b27ab937a5815d16b5fae407ff18222c6d1ed263"
|
||||
"be68c95f32d908bd895cd76207ae726487567f9a67dad79abec316f683b17f2d"
|
||||
"02bf07e0ac8b5bc6162cf94697b3c27cd1fea49b27f23ba2901871962506520c"
|
||||
"392da8b6ad0d99f7013fbc06c2c17a569500c8a7696481c1cd33e9b14e40b82e"
|
||||
"79a5f5db82571ba97bae3ad3e0479515bb0e2b0f3bfcd1fd33034efc6245eddd"
|
||||
"7ee2086ddae2600d8ca73e214e8c2b0bdb2b047c6a464a562ed77b73d2d841c4"
|
||||
"b34973551257713b753632efba348169abc90a68f42611a40126d7cb21b58695"
|
||||
"568186f7e569d2ff0f9e745d0487dd2eb997cafc5abf9dd102e62ff66cba87",
|
||||
"e301345a41a39a4d72fff8df69c98075a0cc082b802fc9b2b6bc503f926b65bd"
|
||||
"df7f4c8f1cb49f6396afc8a70abe6d8aef0db478d4c6b2970076c6a0484fe76d"
|
||||
"76b3a97625d79f1ce240e7c576750d295528286f719b413de9ada3e8eb78ed57"
|
||||
"3603ce30d8bb761785dc30dbc320869e1a00",
|
||||
NULL
|
||||
}
|
||||
};
|
||||
unsigned int n;
|
||||
unsigned long mlen, slen, plen, siglen, buflen;
|
||||
unsigned char msg[1024], sec[57], pub[57], sig[114], buf[114];
|
||||
curve448_key key, key2;
|
||||
int ret;
|
||||
const int should = 1;
|
||||
|
||||
for (n = 0; n < sizeof(vectors)/sizeof(vectors[0]); ++n) {
|
||||
slen = sizeof(sec);
|
||||
DO(base16_decode(vectors[n].secret_key, XSTRLEN(vectors[n].secret_key), sec, &slen));
|
||||
plen = sizeof(pub);
|
||||
DO(base16_decode(vectors[n].public_key, XSTRLEN(vectors[n].public_key), pub, &plen));
|
||||
if (XSTRLEN(vectors[n].message) > 0) {
|
||||
mlen = sizeof(msg);
|
||||
DO(base16_decode(vectors[n].message, XSTRLEN(vectors[n].message), msg, &mlen));
|
||||
} else {
|
||||
mlen = 0;
|
||||
}
|
||||
siglen = sizeof(sig);
|
||||
DO(base16_decode(vectors[n].signature, XSTRLEN(vectors[n].signature), sig, &siglen));
|
||||
|
||||
/* sign with private key and compare */
|
||||
DO(ed448_import_raw(sec, slen, PK_PRIVATE, &key));
|
||||
buflen = sizeof(buf);
|
||||
DO(ed448_sign(msg, mlen, buf, &buflen, &key));
|
||||
COMPARE_TESTVECTOR(buf, buflen, sig, siglen, "Ed448 RFC8032 5.2.6 - sign", n);
|
||||
|
||||
/* verify with private key */
|
||||
DO(ed448_verify(msg, mlen, sig, siglen, &ret, &key));
|
||||
COMPARE_TESTVECTOR(&ret, sizeof(ret), &should, sizeof(should), "Ed448 RFC8032 5.2.6 - verify w/ privkey", n);
|
||||
|
||||
/* verify with public key only */
|
||||
DO(ed448_import_raw(pub, plen, PK_PUBLIC, &key2));
|
||||
DO(ed448_verify(msg, mlen, sig, siglen, &ret, &key2));
|
||||
COMPARE_TESTVECTOR(&ret, sizeof(ret), &should, sizeof(should), "Ed448 RFC8032 5.2.6 - verify w/ pubkey", n);
|
||||
|
||||
zeromem(&key, sizeof(key));
|
||||
zeromem(&key2, sizeof(key2));
|
||||
}
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* RFC 8032 Section 5.2.6 - Ed448 with context (vector 3) */
|
||||
static int s_rfc_8032_5_2_6_ctx_test(void)
|
||||
{
|
||||
const rfc_8032_t vectors[] = {
|
||||
{
|
||||
/* 3: 1 byte message, context "foo" */
|
||||
"c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463a"
|
||||
"fbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e",
|
||||
"43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c086"
|
||||
"6aea01eb00742802b8438ea4cb82169c235160627b4c3a9480",
|
||||
"03",
|
||||
"d4f8f6131770dd46f40867d6fd5d5055de43541f8c5e35abbcd001b32a89f7d2"
|
||||
"151f7647f11d8ca2ae279fb842d607217fce6e042f6815ea000c85741de5c8da"
|
||||
"1144a6a1aba7f96de42505d7a7298524fda538fccbbb754f578c1cad10d54d0d"
|
||||
"5428407e85dcbc98a49155c13764e66c3c00",
|
||||
"666f6f"
|
||||
}
|
||||
};
|
||||
unsigned int n;
|
||||
unsigned long mlen, slen, plen, siglen, buflen, ctxlen;
|
||||
unsigned char msg[1024], sec[57], pub[57], sig[114], buf[114], ctx[64];
|
||||
curve448_key key, key2;
|
||||
int ret;
|
||||
const int should = 1;
|
||||
|
||||
for (n = 0; n < sizeof(vectors)/sizeof(vectors[0]); ++n) {
|
||||
slen = sizeof(sec);
|
||||
DO(base16_decode(vectors[n].secret_key, XSTRLEN(vectors[n].secret_key), sec, &slen));
|
||||
plen = sizeof(pub);
|
||||
DO(base16_decode(vectors[n].public_key, XSTRLEN(vectors[n].public_key), pub, &plen));
|
||||
mlen = sizeof(msg);
|
||||
DO(base16_decode(vectors[n].message, XSTRLEN(vectors[n].message), msg, &mlen));
|
||||
siglen = sizeof(sig);
|
||||
DO(base16_decode(vectors[n].signature, XSTRLEN(vectors[n].signature), sig, &siglen));
|
||||
ctxlen = sizeof(ctx);
|
||||
DO(base16_decode(vectors[n].context, XSTRLEN(vectors[n].context), ctx, &ctxlen));
|
||||
|
||||
/* sign with context and compare */
|
||||
DO(ed448_import_raw(sec, slen, PK_PRIVATE, &key));
|
||||
buflen = sizeof(buf);
|
||||
DO(ed448ctx_sign(msg, mlen, buf, &buflen, ctx, ctxlen, &key));
|
||||
COMPARE_TESTVECTOR(buf, buflen, sig, siglen, "Ed448ctx RFC8032 5.2.6 - sign", n);
|
||||
|
||||
/* verify with private key */
|
||||
DO(ed448ctx_verify(msg, mlen, sig, siglen, ctx, ctxlen, &ret, &key));
|
||||
COMPARE_TESTVECTOR(&ret, sizeof(ret), &should, sizeof(should), "Ed448ctx RFC8032 5.2.6 - verify w/ privkey", n);
|
||||
|
||||
/* verify with public key only */
|
||||
DO(ed448_import_raw(pub, plen, PK_PUBLIC, &key2));
|
||||
DO(ed448ctx_verify(msg, mlen, sig, siglen, ctx, ctxlen, &ret, &key2));
|
||||
COMPARE_TESTVECTOR(&ret, sizeof(ret), &should, sizeof(should), "Ed448ctx RFC8032 5.2.6 - verify w/ pubkey", n);
|
||||
|
||||
zeromem(&key, sizeof(key));
|
||||
zeromem(&key2, sizeof(key2));
|
||||
}
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* RFC 8032 Section 5.2.6 - Ed448ph (prehash) */
|
||||
static int s_rfc_8032_5_2_6_ph_test(void)
|
||||
{
|
||||
const rfc_8032_t vectors[] = {
|
||||
{
|
||||
/* Ed448ph without context */
|
||||
"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"
|
||||
"ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49",
|
||||
"259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743"
|
||||
"c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880",
|
||||
"616263",
|
||||
"822f6901f7480f3d5f562c592994d9693602875614483256505600bbc281ae38"
|
||||
"1f54d6bce2ea911574932f52a4e6cadd78769375ec3ffd1b801a0d9b3f4030cd"
|
||||
"433964b6457ea39476511214f97469b57dd32dbc560a9a94d00bff07620464a3"
|
||||
"ad203df7dc7ce360c3cd3696d9d9fab90f00",
|
||||
NULL
|
||||
},
|
||||
{
|
||||
/* Ed448ph with context "foo" */
|
||||
"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"
|
||||
"ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49",
|
||||
"259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743"
|
||||
"c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880",
|
||||
"616263",
|
||||
"c32299d46ec8ff02b54540982814dce9a05812f81962b649d528095916a2aa48"
|
||||
"1065b1580423ef927ecf0af5888f90da0f6a9a85ad5dc3f280d91224ba9911a3"
|
||||
"653d00e484e2ce232521481c8658df304bb7745a73514cdb9bf3e15784ab7128"
|
||||
"4f8d0704a608c54a6b62d97beb511d132100",
|
||||
"666f6f"
|
||||
}
|
||||
};
|
||||
unsigned int n;
|
||||
unsigned long mlen, slen, plen, siglen, buflen, ctxlen;
|
||||
unsigned char msg[1024], sec[57], pub[57], sig[114], buf[114], ctx[64];
|
||||
curve448_key key;
|
||||
int ret;
|
||||
const int should = 1;
|
||||
|
||||
for (n = 0; n < sizeof(vectors)/sizeof(vectors[0]); ++n) {
|
||||
slen = sizeof(sec);
|
||||
DO(base16_decode(vectors[n].secret_key, XSTRLEN(vectors[n].secret_key), sec, &slen));
|
||||
plen = sizeof(pub);
|
||||
DO(base16_decode(vectors[n].public_key, XSTRLEN(vectors[n].public_key), pub, &plen));
|
||||
mlen = sizeof(msg);
|
||||
DO(base16_decode(vectors[n].message, XSTRLEN(vectors[n].message), msg, &mlen));
|
||||
siglen = sizeof(sig);
|
||||
DO(base16_decode(vectors[n].signature, XSTRLEN(vectors[n].signature), sig, &siglen));
|
||||
|
||||
if (vectors[n].context != NULL) {
|
||||
ctxlen = sizeof(ctx);
|
||||
DO(base16_decode(vectors[n].context, XSTRLEN(vectors[n].context), ctx, &ctxlen));
|
||||
} else {
|
||||
ctxlen = 0;
|
||||
}
|
||||
|
||||
DO(ed448_import_raw(sec, slen, PK_PRIVATE, &key));
|
||||
buflen = sizeof(buf);
|
||||
DO(ed448ph_sign(msg, mlen, buf, &buflen, ctx, ctxlen, &key));
|
||||
COMPARE_TESTVECTOR(buf, buflen, sig, siglen, "Ed448ph RFC8032 5.2.6 - sign", n);
|
||||
|
||||
DO(ed448ph_verify(msg, mlen, sig, siglen, ctx, ctxlen, &ret, &key));
|
||||
COMPARE_TESTVECTOR(&ret, sizeof(ret), &should, sizeof(should), "Ed448ph RFC8032 5.2.6 - verify", n);
|
||||
|
||||
zeromem(&key, sizeof(key));
|
||||
}
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* Export/import round-trip for Ed448 (requires MPI for DER/PKCS8) */
|
||||
static int s_ed448_compat_test(void)
|
||||
{
|
||||
curve448_key priv, pub, imported;
|
||||
unsigned char buf[1024];
|
||||
unsigned long buflen;
|
||||
int prng_idx = find_prng("yarrow");
|
||||
|
||||
XMEMSET(&priv, 0, sizeof(priv));
|
||||
XMEMSET(&pub, 0, sizeof(pub));
|
||||
XMEMSET(&imported, 0, sizeof(imported));
|
||||
|
||||
DO(ed448_make_key(&yarrow_prng, prng_idx, &priv));
|
||||
|
||||
/* private PKCS#8 export -> import */
|
||||
buflen = sizeof(buf);
|
||||
DO(ed448_export(buf, &buflen, PK_PRIVATE | PK_STD, &priv));
|
||||
DO(ed448_import_pkcs8(buf, buflen, NULL, &imported));
|
||||
COMPARE_TESTVECTOR(&priv, sizeof(priv), &imported, sizeof(imported), "Ed448 priv pkcs8 round-trip", __LINE__);
|
||||
XMEMSET(&imported, 0, sizeof(imported));
|
||||
|
||||
/* public raw export -> import */
|
||||
buflen = sizeof(buf);
|
||||
DO(ed448_export(buf, &buflen, PK_PUBLIC, &priv));
|
||||
DO(ed448_import_raw(buf, buflen, PK_PUBLIC, &pub));
|
||||
|
||||
/* public DER export -> import */
|
||||
buflen = sizeof(buf);
|
||||
DO(ed448_export(buf, &buflen, PK_PUBLIC | PK_STD, &priv));
|
||||
DO(ed448_import(buf, buflen, &imported));
|
||||
COMPARE_TESTVECTOR(&pub, sizeof(pub), &imported, sizeof(imported), "Ed448 pub DER round-trip", __LINE__);
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
int ed448_test(void)
|
||||
{
|
||||
DO(s_ed448_keygen_sign_verify());
|
||||
DO(s_rfc_8032_5_2_6_pure_test());
|
||||
DO(s_rfc_8032_5_2_6_ctx_test());
|
||||
DO(s_rfc_8032_5_2_6_ph_test());
|
||||
if (ltc_mp.name != NULL) {
|
||||
DO(s_ed448_compat_test());
|
||||
}
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int ed448_test(void)
|
||||
{
|
||||
return CRYPT_NOP;
|
||||
}
|
||||
|
||||
#endif
|
||||
4
tests/pem/openssl_ed448_pk.pem
Normal file
4
tests/pem/openssl_ed448_pk.pem
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
-----BEGIN PUBLIC KEY-----
|
||||
MEMwBQYDK2VxAzoAZkavwN2Jb7JwbSR79T0JZUDV1VOCgm1AlFdsW9dV+O57w7E2
|
||||
+y9O4Ejkhya86byArbdRsOk7ovqA
|
||||
-----END PUBLIC KEY-----
|
||||
4
tests/pem/openssl_ed448_sk.pem
Normal file
4
tests/pem/openssl_ed448_sk.pem
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MEcCAQAwBQYDK2VxBDsEOe/w/F8aSpwuG9cBnsAkhloXWhPJEVhCxzWdXebe27Tu
|
||||
f1R24A1BP7pjIihNdlXTsxv+sFuKWMR5ng==
|
||||
-----END PRIVATE KEY-----
|
||||
11
tests/pem/openssl_ed448_x509.pem
Normal file
11
tests/pem/openssl_ed448_x509.pem
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIBhDCCAQSgAwIBAgIUA30c9xlNmn6aa6MeW/sattDShU8wBQYDK2VxMBExDzAN
|
||||
BgNVBAMMBkNyeXB0WDAgFw0yNjA0MTQxMjAwMDNaGA8yMzAwMDEyNzEyMDAwM1ow
|
||||
ETEPMA0GA1UEAwwGQ3J5cHRYMEMwBQYDK2VxAzoAZkavwN2Jb7JwbSR79T0JZUDV
|
||||
1VOCgm1AlFdsW9dV+O57w7E2+y9O4Ejkhya86byArbdRsOk7ovqAo1MwUTAdBgNV
|
||||
HQ4EFgQUrowTD38+WWdAZuwA1WLZu/7xsGIwHwYDVR0jBBgwFoAUrowTD38+WWdA
|
||||
ZuwA1WLZu/7xsGIwDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXEDcwDD6A7cE22i0417
|
||||
jNIVCCMPxY09OkC5yFLXV3MilpvyWyUQFz/J4XWxpnRyWYaap6EeZLzowTtPFgCH
|
||||
uPj4rCSVFQkBRaMkBv1zsFUXz7mAg01aNZFu7aDO+n+ctpl/8+BLw1+lQm4BiOGw
|
||||
47xwywstBgA=
|
||||
-----END CERTIFICATE-----
|
||||
4
tests/pem/openssl_x448_pk.pem
Normal file
4
tests/pem/openssl_x448_pk.pem
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
-----BEGIN PUBLIC KEY-----
|
||||
MEIwBQYDK2VvAzkApScinIzW1CGVm4zV1j6fw7GsbeHGFy8QY7JLd8tXGiaXzr+/
|
||||
OwJqRZ9X1QhfEYso6no4d1fP9N0=
|
||||
-----END PUBLIC KEY-----
|
||||
4
tests/pem/openssl_x448_sk.pem
Normal file
4
tests/pem/openssl_x448_sk.pem
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MEYCAQAwBQYDK2VvBDoEOPBQlJ/c83DaT71qCGj25lKh7rr3q6pRBIqHCjExTXD0
|
||||
vM82EulDzmjR9WU9zaS00j2LU4XXKpvV
|
||||
-----END PRIVATE KEY-----
|
||||
4
tests/pem/pkcs/openssl_ed448_sk.pk8
Normal file
4
tests/pem/pkcs/openssl_ed448_sk.pk8
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MEcCAQAwBQYDK2VxBDsEOe/w/F8aSpwuG9cBnsAkhloXWhPJEVhCxzWdXebe27Tu
|
||||
f1R24A1BP7pjIihNdlXTsxv+sFuKWMR5ng==
|
||||
-----END PRIVATE KEY-----
|
||||
5
tests/pem/pkcs/openssl_ed448_sk_pbes1.pk8
Normal file
5
tests/pem/pkcs/openssl_ed448_sk_pbes1.pk8
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MHAwHAYKKoZIhvcNAQwBAzAOBAjJ1wdj8L5FKgICCAAEUFrnEEVG1fA7XOx15h9T
|
||||
H0TLtbCm/UYnFLh8GDGVjM+q/OYrfnTv5a6P5G/Ze7tMVsSCpgZBlSL9/Q6NJ37P
|
||||
2X/Jd5vwyJSRzm+qeugIci5d
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
6
tests/pem/pkcs/openssl_ed448_sk_pbes2.pk8
Normal file
6
tests/pem/pkcs/openssl_ed448_sk_pbes2.pk8
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIGrMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAhhZGWQAxrkOAICCAAw
|
||||
DAYIKoZIhvcNAgsFADAdBglghkgBZQMEASoEEBWa/IgJqnE1O2ibVuIkqVwEUIEG
|
||||
2Wj76gtauZF1wEIts6PN/of37CQjdI8qBT95f0NemnXA9KWhqdT7zCVoZykdwTtr
|
||||
QveA4USScJ1NjGRCgLcoh+RW0/7pQLI1s06UIptb
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
4
tests/pem/pkcs/openssl_x448_sk.pk8
Normal file
4
tests/pem/pkcs/openssl_x448_sk.pk8
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MEYCAQAwBQYDK2VvBDoEOPBQlJ/c83DaT71qCGj25lKh7rr3q6pRBIqHCjExTXD0
|
||||
vM82EulDzmjR9WU9zaS00j2LU4XXKpvV
|
||||
-----END PRIVATE KEY-----
|
||||
5
tests/pem/pkcs/openssl_x448_sk_pbes1.pk8
Normal file
5
tests/pem/pkcs/openssl_x448_sk_pbes1.pk8
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MHAwHAYKKoZIhvcNAQwBAzAOBAgZ7uqzZ0UIPAICCAAEUIoyzd9lPvjne3Bg7lk9
|
||||
PIHPqflbG9jCtk9192bVNj8+QHA1+XMEB9Ay3/Ljr+hQwiTS1tVELbzqyOoNYxpF
|
||||
H91YfGjRZDrh2+k/K5MtLFUh
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
6
tests/pem/pkcs/openssl_x448_sk_pbes2.pk8
Normal file
6
tests/pem/pkcs/openssl_x448_sk_pbes2.pk8
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIGrMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAhzD7h+saEo1gICCAAw
|
||||
DAYIKoZIhvcNAgsFADAdBglghkgBZQMEASoEEFcOyy6Y7TG3Z8wklZO14U8EUKKD
|
||||
vdlVxsVBpoMpRTbYKen6rbSnAhysBG24K5AVyMAcsTXL1uzGHTIrV3xSjW4W8NV2
|
||||
N1MjPECNVcxH5HvsCOZ0lqYrj4IdSk4hL1+9Jrzz
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
|
|
@ -86,6 +86,8 @@ static int s_key_cmp(ltc_pka_key *key)
|
|||
case LTC_PKA_ED25519:
|
||||
case LTC_PKA_X25519:
|
||||
case LTC_PKA_DH:
|
||||
case LTC_PKA_X448:
|
||||
case LTC_PKA_ED448:
|
||||
return CRYPT_OK;
|
||||
default:
|
||||
return CRYPT_INVALID_ARG;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ static const test_function test_functions[] =
|
|||
LTC_TEST_FN(dsa_test),
|
||||
LTC_TEST_FN(ed25519_test),
|
||||
LTC_TEST_FN(x25519_test),
|
||||
LTC_TEST_FN(ed448_test),
|
||||
LTC_TEST_FN(x448_test),
|
||||
LTC_TEST_FN(file_test),
|
||||
LTC_TEST_FN(multi_test),
|
||||
LTC_TEST_FN(pem_test),
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ int prng_test(void);
|
|||
int mpi_test(void);
|
||||
int padding_test(void);
|
||||
int x25519_test(void);
|
||||
int x448_test(void);
|
||||
int ed25519_test(void);
|
||||
int ed448_test(void);
|
||||
int ssh_test(void);
|
||||
int argon2_test(void);
|
||||
int bcrypt_test(void);
|
||||
|
|
|
|||
231
tests/x448_test.c
Normal file
231
tests/x448_test.c
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
#include "tomcrypt_test.h"
|
||||
|
||||
#ifdef LTC_CURVE448
|
||||
|
||||
/* RFC 7748 Section 5.2 - X448 scalar multiplication test vectors */
|
||||
static int s_x448_rfc7748_scalarmult_test(void)
|
||||
{
|
||||
/* First test vector */
|
||||
static const unsigned char k1[56] = {
|
||||
0x3d, 0x26, 0x2f, 0xdd, 0xf9, 0xec, 0x8e, 0x88,
|
||||
0x49, 0x52, 0x66, 0xfe, 0xa1, 0x9a, 0x34, 0xd2,
|
||||
0x88, 0x82, 0xac, 0xef, 0x04, 0x51, 0x04, 0xd0,
|
||||
0xd1, 0xaa, 0xe1, 0x21, 0x70, 0x0a, 0x77, 0x9c,
|
||||
0x98, 0x4c, 0x24, 0xf8, 0xcd, 0xd7, 0x8f, 0xbf,
|
||||
0xf4, 0x49, 0x43, 0xeb, 0xa3, 0x68, 0xf5, 0x4b,
|
||||
0x29, 0x25, 0x9a, 0x4f, 0x1c, 0x60, 0x0a, 0xd3
|
||||
};
|
||||
static const unsigned char u1[56] = {
|
||||
0x06, 0xfc, 0xe6, 0x40, 0xfa, 0x34, 0x87, 0xbf,
|
||||
0xda, 0x5f, 0x6c, 0xf2, 0xd5, 0x26, 0x3f, 0x8a,
|
||||
0xad, 0x88, 0x33, 0x4c, 0xbd, 0x07, 0x43, 0x7f,
|
||||
0x02, 0x0f, 0x08, 0xf9, 0x81, 0x4d, 0xc0, 0x31,
|
||||
0xdd, 0xbd, 0xc3, 0x8c, 0x19, 0xc6, 0xda, 0x25,
|
||||
0x83, 0xfa, 0x54, 0x29, 0xdb, 0x94, 0xad, 0xa1,
|
||||
0x8a, 0xa7, 0xa7, 0xfb, 0x4e, 0xf8, 0xa0, 0x86
|
||||
};
|
||||
static const unsigned char expected1[56] = {
|
||||
0xce, 0x3e, 0x4f, 0xf9, 0x5a, 0x60, 0xdc, 0x66,
|
||||
0x97, 0xda, 0x1d, 0xb1, 0xd8, 0x5e, 0x6a, 0xfb,
|
||||
0xdf, 0x79, 0xb5, 0x0a, 0x24, 0x12, 0xd7, 0x54,
|
||||
0x6d, 0x5f, 0x23, 0x9f, 0xe1, 0x4f, 0xba, 0xad,
|
||||
0xeb, 0x44, 0x5f, 0xc6, 0x6a, 0x01, 0xb0, 0x77,
|
||||
0x9d, 0x98, 0x22, 0x39, 0x61, 0x11, 0x1e, 0x21,
|
||||
0x76, 0x62, 0x82, 0xf7, 0x3d, 0xd9, 0x6b, 0x6f
|
||||
};
|
||||
|
||||
/* Second test vector */
|
||||
static const unsigned char k2[56] = {
|
||||
0x20, 0x3d, 0x49, 0x44, 0x28, 0xb8, 0x39, 0x93,
|
||||
0x52, 0x66, 0x5d, 0xdc, 0xa4, 0x2f, 0x9d, 0xe8,
|
||||
0xfe, 0xf6, 0x00, 0x90, 0x8e, 0x0d, 0x46, 0x1c,
|
||||
0xb0, 0x21, 0xf8, 0xc5, 0x38, 0x34, 0x5d, 0xd7,
|
||||
0x7c, 0x3e, 0x48, 0x06, 0xe2, 0x5f, 0x46, 0xd3,
|
||||
0x31, 0x5c, 0x44, 0xe0, 0xa5, 0xb4, 0x37, 0x12,
|
||||
0x82, 0xdd, 0x2c, 0x8d, 0x5b, 0xe3, 0x09, 0x5b
|
||||
};
|
||||
static const unsigned char u2[56] = {
|
||||
0x0f, 0xbc, 0xc2, 0xf9, 0x93, 0xcd, 0x56, 0xd3,
|
||||
0x30, 0x5b, 0x0b, 0x7d, 0x9e, 0x55, 0xd4, 0xc1,
|
||||
0xa8, 0xfb, 0x5d, 0xbb, 0x52, 0xf8, 0xe9, 0xa1,
|
||||
0xe9, 0xb6, 0x20, 0x1b, 0x16, 0x5d, 0x01, 0x58,
|
||||
0x94, 0xe5, 0x6c, 0x4d, 0x35, 0x70, 0xbe, 0xe5,
|
||||
0x2f, 0xe2, 0x05, 0xe2, 0x8a, 0x78, 0xb9, 0x1c,
|
||||
0xdf, 0xbd, 0xe7, 0x1c, 0xe8, 0xd1, 0x57, 0xdb
|
||||
};
|
||||
static const unsigned char expected2[56] = {
|
||||
0xe4, 0x3a, 0x6e, 0x84, 0xc5, 0x41, 0x24, 0x19,
|
||||
0x69, 0xe1, 0xbc, 0x13, 0xaf, 0xae, 0xba, 0x34,
|
||||
0xe8, 0xe0, 0x91, 0x22, 0xaf, 0x0f, 0xaf, 0x6a,
|
||||
0x45, 0xf8, 0xd2, 0x51, 0x38, 0xb4, 0x80, 0x0f,
|
||||
0x07, 0xc8, 0x62, 0xd8, 0x04, 0xac, 0xaf, 0x18,
|
||||
0xd2, 0xc5, 0xf5, 0x02, 0x76, 0xcd, 0xf0, 0xbd,
|
||||
0x06, 0x8e, 0x95, 0x73, 0x73, 0xd3, 0x52, 0x97
|
||||
};
|
||||
|
||||
unsigned char out[56];
|
||||
|
||||
ec448_scalarmult_internal(out, k1, u1);
|
||||
COMPARE_TESTVECTOR(out, 56, expected1, 56, "X448 RFC7748 5.2 #1", 0);
|
||||
|
||||
ec448_scalarmult_internal(out, k2, u2);
|
||||
COMPARE_TESTVECTOR(out, 56, expected2, 56, "X448 RFC7748 5.2 #2", 1);
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* RFC 7748 Section 5.2 - X448 iterative scalar multiplication test
|
||||
*
|
||||
* Start with k = u = 5 (as 56-byte little-endian).
|
||||
* Each iteration: out = X448(k, u), then u = old_k, k = out.
|
||||
*/
|
||||
static int s_x448_rfc7748_iter_test(void)
|
||||
{
|
||||
/* Expected result after 1 iteration */
|
||||
static const unsigned char expected_1[56] = {
|
||||
0x3f, 0x48, 0x2c, 0x8a, 0x9f, 0x19, 0xb0, 0x1e,
|
||||
0x6c, 0x46, 0xee, 0x97, 0x11, 0xd9, 0xdc, 0x14,
|
||||
0xfd, 0x4b, 0xf6, 0x7a, 0xf3, 0x07, 0x65, 0xc2,
|
||||
0xae, 0x2b, 0x84, 0x6a, 0x4d, 0x23, 0xa8, 0xcd,
|
||||
0x0d, 0xb8, 0x97, 0x08, 0x62, 0x39, 0x49, 0x2c,
|
||||
0xaf, 0x35, 0x0b, 0x51, 0xf8, 0x33, 0x86, 0x8b,
|
||||
0x9b, 0xc2, 0xb3, 0xbc, 0xa9, 0xcf, 0x41, 0x13
|
||||
};
|
||||
|
||||
/* Expected result after 1000 iterations */
|
||||
static const unsigned char expected_1000[56] = {
|
||||
0xaa, 0x3b, 0x47, 0x49, 0xd5, 0x5b, 0x9d, 0xaf,
|
||||
0x1e, 0x5b, 0x00, 0x28, 0x88, 0x26, 0xc4, 0x67,
|
||||
0x27, 0x4c, 0xe3, 0xeb, 0xbd, 0xd5, 0xc1, 0x7b,
|
||||
0x97, 0x5e, 0x09, 0xd4, 0xaf, 0x6c, 0x67, 0xcf,
|
||||
0x10, 0xd0, 0x87, 0x20, 0x2d, 0xb8, 0x82, 0x86,
|
||||
0xe2, 0xb7, 0x9f, 0xce, 0xea, 0x3e, 0xc3, 0x53,
|
||||
0xef, 0x54, 0xfa, 0xa2, 0x6e, 0x21, 0x9f, 0x38
|
||||
};
|
||||
|
||||
unsigned char k[56], u[56], out[56], tmp[56];
|
||||
unsigned long i;
|
||||
|
||||
/* k = u = 5 (little-endian) */
|
||||
XMEMSET(k, 0, 56);
|
||||
XMEMSET(u, 0, 56);
|
||||
k[0] = 5;
|
||||
u[0] = 5;
|
||||
|
||||
/* 1 iteration */
|
||||
ec448_scalarmult_internal(out, k, u);
|
||||
XMEMCPY(u, k, 56);
|
||||
XMEMCPY(k, out, 56);
|
||||
COMPARE_TESTVECTOR(k, 56, expected_1, 56, "X448 RFC7748 iter=1", 0);
|
||||
|
||||
/* Continue to 1000 iterations (we already did 1) */
|
||||
for (i = 1; i < 1000; i++) {
|
||||
ec448_scalarmult_internal(out, k, u);
|
||||
XMEMCPY(tmp, k, 56);
|
||||
XMEMCPY(k, out, 56);
|
||||
XMEMCPY(u, tmp, 56);
|
||||
}
|
||||
COMPARE_TESTVECTOR(k, 56, expected_1000, 56, "X448 RFC7748 iter=1000", 1);
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int s_x448_keygen_dh_test(void)
|
||||
{
|
||||
curve448_key alice, bob;
|
||||
unsigned char ss_a[56], ss_b[56];
|
||||
unsigned long sslen;
|
||||
int prng_idx;
|
||||
|
||||
prng_idx = find_prng("yarrow");
|
||||
|
||||
/* Generate two key pairs */
|
||||
DO(x448_make_key(&yarrow_prng, prng_idx, &alice));
|
||||
DO(x448_make_key(&yarrow_prng, prng_idx, &bob));
|
||||
ENSURE(alice.type == PK_PRIVATE);
|
||||
ENSURE(alice.pka == LTC_PKA_X448);
|
||||
|
||||
/* DH: both sides compute the same shared secret */
|
||||
sslen = sizeof(ss_a);
|
||||
DO(x448_shared_secret(&alice, &bob, ss_a, &sslen));
|
||||
ENSURE(sslen == 56);
|
||||
|
||||
sslen = sizeof(ss_b);
|
||||
DO(x448_shared_secret(&bob, &alice, ss_b, &sslen));
|
||||
ENSURE(sslen == 56);
|
||||
|
||||
COMPARE_TESTVECTOR(ss_a, 56, ss_b, 56, "X448 DH shared secret", 0);
|
||||
|
||||
/* Export/import raw round-trip */
|
||||
{
|
||||
curve448_key imported;
|
||||
unsigned char buf[56];
|
||||
unsigned long buflen = sizeof(buf);
|
||||
|
||||
DO(x448_export(buf, &buflen, PK_PUBLIC, &alice));
|
||||
ENSURE(buflen == 56);
|
||||
DO(x448_import_raw(buf, buflen, PK_PUBLIC, &imported));
|
||||
ENSURE(imported.type == PK_PUBLIC);
|
||||
ENSURE(imported.pka == LTC_PKA_X448);
|
||||
COMPARE_TESTVECTOR(imported.pub, 56, alice.pub, 56, "X448 import_raw pub", 0);
|
||||
}
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/* Export/import round-trip (requires MPI for DER/PKCS8) */
|
||||
static int s_x448_compat_test(void)
|
||||
{
|
||||
curve448_key priv, pub, imported;
|
||||
unsigned char buf[1024];
|
||||
unsigned long buflen;
|
||||
int prng_idx = find_prng("yarrow");
|
||||
|
||||
XMEMSET(&priv, 0, sizeof(priv));
|
||||
XMEMSET(&pub, 0, sizeof(pub));
|
||||
XMEMSET(&imported, 0, sizeof(imported));
|
||||
|
||||
DO(x448_make_key(&yarrow_prng, prng_idx, &priv));
|
||||
|
||||
/* private PKCS#8 export -> import */
|
||||
buflen = sizeof(buf);
|
||||
DO(x448_export(buf, &buflen, PK_PRIVATE | PK_STD, &priv));
|
||||
DO(x448_import_pkcs8(buf, buflen, NULL, &imported));
|
||||
COMPARE_TESTVECTOR(&priv, sizeof(priv), &imported, sizeof(imported), "X448 priv pkcs8 round-trip", __LINE__);
|
||||
XMEMSET(&imported, 0, sizeof(imported));
|
||||
|
||||
/* public raw export -> import */
|
||||
buflen = sizeof(buf);
|
||||
DO(x448_export(buf, &buflen, PK_PUBLIC, &priv));
|
||||
DO(x448_import_raw(buf, buflen, PK_PUBLIC, &pub));
|
||||
|
||||
/* public DER export -> import */
|
||||
buflen = sizeof(buf);
|
||||
DO(x448_export(buf, &buflen, PK_PUBLIC | PK_STD, &priv));
|
||||
DO(x448_import(buf, buflen, &imported));
|
||||
COMPARE_TESTVECTOR(&pub, sizeof(pub), &imported, sizeof(imported), "X448 pub DER round-trip", __LINE__);
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
int x448_test(void)
|
||||
{
|
||||
DO(s_x448_rfc7748_scalarmult_test());
|
||||
DO(s_x448_rfc7748_iter_test());
|
||||
DO(s_x448_keygen_dh_test());
|
||||
if (ltc_mp.name != NULL) {
|
||||
DO(s_x448_compat_test());
|
||||
}
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int x448_test(void)
|
||||
{
|
||||
return CRYPT_NOP;
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue