diff --git a/wolfcrypt/src/ed25519.c b/wolfcrypt/src/ed25519.c index de6f705dd..279b46ff8 100644 --- a/wolfcrypt/src/ed25519.c +++ b/wolfcrypt/src/ed25519.c @@ -45,6 +45,12 @@ #include #endif +#if defined(HAVE_ED25519_SIGN) || defined(HAVE_ED25519_VERIFY) +#define ED25519CTX_SIZE 32 + +static const byte ed25519Ctx[ED25519CTX_SIZE] = + "SigEd25519 no Ed25519 collisions"; +#endif int wc_ed25519_make_public(ed25519_key* key, unsigned char* pubKey, word32 pubKeySz) @@ -117,16 +123,20 @@ int wc_ed25519_make_key(WC_RNG* rng, int keySz, ed25519_key* key) #ifdef HAVE_ED25519_SIGN /* - in contains the message to sign - inlen is the length of the message to sign - out is the buffer to write the signature - outLen [in/out] input size of out buf - output gets set as the final length of out - key is the ed25519 key to use when signing + in contains the message to sign + inLen is the length of the message to sign + out is the buffer to write the signature + outLen [in/out] input size of out buf + output gets set as the final length of out + key is the ed25519 key to use when signing + type one of Ed25519, Ed25519ctx or Ed25519ph + context extra signing data + contextLen length of extra signing data return 0 on success */ -int wc_ed25519_sign_msg(const byte* in, word32 inlen, byte* out, - word32 *outLen, ed25519_key* key) +static int ed25519_sign_msg(const byte* in, word32 inLen, byte* out, + word32 *outLen, ed25519_key* key, byte type, + const byte* context, byte contextLen) { #ifdef FREESCALE_LTC_ECC byte tempBuf[ED25519_PRV_KEY_SIZE]; @@ -140,8 +150,10 @@ int wc_ed25519_sign_msg(const byte* in, word32 inlen, byte* out, int ret; /* sanity check on arguments */ - if (in == NULL || out == NULL || outLen == NULL || key == NULL) + if (in == NULL || out == NULL || outLen == NULL || key == NULL || + (context == NULL && contextLen != 0)) { return BAD_FUNC_ARG; + } if (!key->pubKeySet) return BAD_FUNC_ARG; @@ -166,9 +178,19 @@ int wc_ed25519_sign_msg(const byte* in, word32 inlen, byte* out, ret = wc_InitSha512(&sha); if (ret != 0) return ret; - ret = wc_Sha512Update(&sha, az + ED25519_KEY_SIZE, ED25519_KEY_SIZE); + if (type == Ed25519ctx || type == Ed25519ph) { + ret = wc_Sha512Update(&sha, ed25519Ctx, ED25519CTX_SIZE); + if (ret == 0) + ret = wc_Sha512Update(&sha, &type, sizeof(type)); + if (ret == 0) + ret = wc_Sha512Update(&sha, &contextLen, sizeof(contextLen)); + if (ret == 0 && context != NULL) + ret = wc_Sha512Update(&sha, context, contextLen); + } if (ret == 0) - ret = wc_Sha512Update(&sha, in, inlen); + ret = wc_Sha512Update(&sha, az + ED25519_KEY_SIZE, ED25519_KEY_SIZE); + if (ret == 0) + ret = wc_Sha512Update(&sha, in, inLen); if (ret == 0) ret = wc_Sha512Final(&sha, nonce); wc_Sha512Free(&sha); @@ -180,7 +202,8 @@ int wc_ed25519_sign_msg(const byte* in, word32 inlen, byte* out, ltcPoint.X = &tempBuf[0]; ltcPoint.Y = &tempBuf[32]; LTC_PKHA_sc_reduce(nonce); - LTC_PKHA_Ed25519_PointMul(LTC_PKHA_Ed25519_BasePoint(), nonce, ED25519_KEY_SIZE, <cPoint, kLTC_Ed25519 /* result on Ed25519 */); + LTC_PKHA_Ed25519_PointMul(LTC_PKHA_Ed25519_BasePoint(), nonce, + ED25519_KEY_SIZE, <cPoint, kLTC_Ed25519 /* result on Ed25519 */); LTC_PKHA_Ed25519_Compress(<cPoint, out); #else sc_reduce(nonce); @@ -196,11 +219,21 @@ int wc_ed25519_sign_msg(const byte* in, word32 inlen, byte* out, ret = wc_InitSha512(&sha); if (ret != 0) return ret; - ret = wc_Sha512Update(&sha, out, ED25519_SIG_SIZE/2); + if (type == Ed25519ctx || type == Ed25519ph) { + ret = wc_Sha512Update(&sha, ed25519Ctx, ED25519CTX_SIZE); + if (ret == 0) + ret = wc_Sha512Update(&sha, &type, sizeof(type)); + if (ret == 0) + ret = wc_Sha512Update(&sha, &contextLen, sizeof(contextLen)); + if (ret == 0 && context != NULL) + ret = wc_Sha512Update(&sha, context, contextLen); + } + if (ret == 0) + ret = wc_Sha512Update(&sha, out, ED25519_SIG_SIZE/2); if (ret == 0) ret = wc_Sha512Update(&sha, key->p, ED25519_PUB_KEY_SIZE); if (ret == 0) - ret = wc_Sha512Update(&sha, in, inlen); + ret = wc_Sha512Update(&sha, in, inLen); if (ret == 0) ret = wc_Sha512Final(&sha, hram); wc_Sha512Free(&sha); @@ -218,20 +251,100 @@ int wc_ed25519_sign_msg(const byte* in, word32 inlen, byte* out, return ret; } +/* + in contains the message to sign + inLen is the length of the message to sign + out is the buffer to write the signature + outLen [in/out] input size of out buf + output gets set as the final length of out + key is the ed25519 key to use when signing + return 0 on success + */ +int wc_ed25519_sign_msg(const byte* in, word32 inLen, byte* out, + word32 *outLen, ed25519_key* key) +{ + return ed25519_sign_msg(in, inLen, out, outLen, key, Ed25519, NULL, 0); +} + +/* + in contains the message to sign + inLen is the length of the message to sign + out is the buffer to write the signature + outLen [in/out] input size of out buf + output gets set as the final length of out + key is the ed25519 key to use when signing + context extra signing data + contextLen length of extra signing data + return 0 on success + */ +int wc_ed25519ctx_sign_msg(const byte* in, word32 inLen, byte* out, + word32 *outLen, ed25519_key* key, + const byte* context, byte contextLen) +{ + return ed25519_sign_msg(in, inLen, out, outLen, key, Ed25519ctx, context, + contextLen); +} + +/* + hash contains the SHA-512 hash of the message to sign + hashLen is the length of the SHA-512 hash of the message to sign + out is the buffer to write the signature + outLen [in/out] input size of out buf + output gets set as the final length of out + key is the ed25519 key to use when signing + context extra signing data + contextLen length of extra signing data + return 0 on success + */ +int wc_ed25519ph_sign_hash(const byte* hash, word32 hashLen, byte* out, + word32 *outLen, ed25519_key* key, + const byte* context, byte contextLen) +{ + return ed25519_sign_msg(hash, hashLen, out, outLen, key, Ed25519ph, context, + contextLen); +} + +/* + in contains the message to sign + inLen is the length of the message to sign + out is the buffer to write the signature + outLen [in/out] input size of out buf + output gets set as the final length of out + key is the ed25519 key to use when signing + context extra signing data + contextLen length of extra signing data + return 0 on success + */ +int wc_ed25519ph_sign_msg(const byte* in, word32 inLen, byte* out, + word32 *outLen, ed25519_key* key, + const byte* context, byte contextLen) +{ + int ret; + byte hash[WC_SHA512_DIGEST_SIZE]; + + ret = wc_Sha512Hash(in, inLen, hash); + if (ret != 0) + return ret; + + return wc_ed25519ph_sign_hash(hash, sizeof(hash), out, outLen, key, context, + contextLen); +} #endif /* HAVE_ED25519_SIGN */ #ifdef HAVE_ED25519_VERIFY /* sig is array of bytes containing the signature - siglen is the length of sig byte array + sigLen is the length of sig byte array msg the array of bytes containing the message - msglen length of msg array + msgLen length of msg array res will be 1 on successful verify and 0 on unsuccessful + key Ed25519 public key return 0 and res of 1 on success */ -int wc_ed25519_verify_msg(const byte* sig, word32 siglen, const byte* msg, - word32 msglen, int* res, ed25519_key* key) +static int ed25519_verify_msg(const byte* sig, word32 sigLen, const byte* msg, + word32 msgLen, int* res, ed25519_key* key, + byte type, const byte* context, byte contextLen) { byte rcheck[ED25519_KEY_SIZE]; byte h[WC_SHA512_DIGEST_SIZE]; @@ -243,14 +356,16 @@ int wc_ed25519_verify_msg(const byte* sig, word32 siglen, const byte* msg, wc_Sha512 sha; /* sanity check on arguments */ - if (sig == NULL || msg == NULL || res == NULL || key == NULL) + if (sig == NULL || msg == NULL || res == NULL || key == NULL || + (context == NULL && contextLen != 0)) { return BAD_FUNC_ARG; + } /* set verification failed by default */ *res = 0; /* check on basics needed to verify signature */ - if (siglen < ED25519_SIG_SIZE || (sig[ED25519_SIG_SIZE-1] & 224)) + if (sigLen < ED25519_SIG_SIZE || (sig[ED25519_SIG_SIZE-1] & 224)) return BAD_FUNC_ARG; /* uncompress A (public key), test if valid, and negate it */ @@ -263,11 +378,21 @@ int wc_ed25519_verify_msg(const byte* sig, word32 siglen, const byte* msg, ret = wc_InitSha512(&sha); if (ret != 0) return ret; - ret = wc_Sha512Update(&sha, sig, ED25519_SIG_SIZE/2); + if (type == Ed25519ctx || type == Ed25519ph) { + ret = wc_Sha512Update(&sha, ed25519Ctx, ED25519CTX_SIZE); + if (ret == 0) + ret = wc_Sha512Update(&sha, &type, sizeof(type)); + if (ret == 0) + ret = wc_Sha512Update(&sha, &contextLen, sizeof(contextLen)); + if (ret == 0 && context != NULL) + ret = wc_Sha512Update(&sha, context, contextLen); + } + if (ret == 0) + ret = wc_Sha512Update(&sha, sig, ED25519_SIG_SIZE/2); if (ret == 0) ret = wc_Sha512Update(&sha, key->p, ED25519_PUB_KEY_SIZE); if (ret == 0) - ret = wc_Sha512Update(&sha, msg, msglen); + ret = wc_Sha512Update(&sha, msg, msgLen); if (ret == 0) ret = wc_Sha512Final(&sha, h); wc_Sha512Free(&sha); @@ -302,6 +427,85 @@ int wc_ed25519_verify_msg(const byte* sig, word32 siglen, const byte* msg, return ret; } +/* + sig is array of bytes containing the signature + sigLen is the length of sig byte array + msg the array of bytes containing the message + msgLen length of msg array + res will be 1 on successful verify and 0 on unsuccessful + key Ed25519 public key + return 0 and res of 1 on success +*/ +int wc_ed25519_verify_msg(const byte* sig, word32 sigLen, const byte* msg, + word32 msgLen, int* res, ed25519_key* key) +{ + return ed25519_verify_msg(sig, sigLen, msg, msgLen, res, key, Ed25519, NULL, + 0); +} + +/* + sig is array of bytes containing the signature + sigLen is the length of sig byte array + msg the array of bytes containing the message + msgLen length of msg array + res will be 1 on successful verify and 0 on unsuccessful + key Ed25519 public key + context extra sigining data + contextLen length of extra sigining data + return 0 and res of 1 on success +*/ +int wc_ed25519ctx_verify_msg(const byte* sig, word32 sigLen, const byte* msg, + word32 msgLen, int* res, ed25519_key* key, + const byte* context, byte contextLen) +{ + return ed25519_verify_msg(sig, sigLen, msg, msgLen, res, key, Ed25519ctx, + context, contextLen); +} + +/* + sig is array of bytes containing the signature + sigLen is the length of sig byte array + hash the array of bytes containing the SHA-512 hash of the message + hashLen length of hash array + res will be 1 on successful verify and 0 on unsuccessful + key Ed25519 public key + context extra sigining data + contextLen length of extra sigining data + return 0 and res of 1 on success +*/ +int wc_ed25519ph_verify_hash(const byte* sig, word32 sigLen, const byte* hash, + word32 hashLen, int* res, ed25519_key* key, + const byte* context, byte contextLen) +{ + return ed25519_verify_msg(sig, sigLen, hash, hashLen, res, key, Ed25519ph, + context, contextLen); +} + +/* + sig is array of bytes containing the signature + sigLen is the length of sig byte array + msg the array of bytes containing the message + msgLen length of msg array + res will be 1 on successful verify and 0 on unsuccessful + key Ed25519 public key + context extra sigining data + contextLen length of extra sigining data + return 0 and res of 1 on success +*/ +int wc_ed25519ph_verify_msg(const byte* sig, word32 sigLen, const byte* msg, + word32 msgLen, int* res, ed25519_key* key, + const byte* context, byte contextLen) +{ + int ret; + byte hash[WC_SHA512_DIGEST_SIZE]; + + ret = wc_Sha512Hash(msg, msgLen, hash); + if (ret != 0) + return ret; + + return wc_ed25519ph_verify_hash(sig, sigLen, hash, sizeof(hash), res, key, + context, contextLen); +} #endif /* HAVE_ED25519_VERIFY */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 6878357c0..e009286dc 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -18531,6 +18531,20 @@ int ed25519_test(void) static const byte* sKeys[] = {sKey1, sKey2, sKey3, sKey4, sKey5, sKey6}; + static const byte sKeyCtx1[] = { + 0x03,0x05,0x33,0x4e,0x38,0x1a,0xf7,0x8f, + 0x14,0x1c,0xb6,0x66,0xf6,0x19,0x9f,0x57, + 0xbc,0x34,0x95,0x33,0x5a,0x25,0x6a,0x95, + 0xbd,0x2a,0x55,0xbf,0x54,0x66,0x63,0xf6 + }; + + static const byte sKeyPh1[] = { + 0x83,0x3f,0xe6,0x24,0x09,0x23,0x7b,0x9d, + 0x62,0xec,0x77,0x58,0x75,0x20,0x91,0x1e, + 0x9a,0x75,0x9c,0xec,0x1d,0x19,0x75,0x5b, + 0x7d,0xa9,0x01,0xb9,0x6d,0xca,0x3d,0x42 + }; + static const byte pKey1[] = { 0xd7,0x5a,0x98,0x01,0x82,0xb1,0x0a,0xb7, 0xd5,0x4b,0xfe,0xd3,0xc9,0x64,0x07,0x3a, @@ -18584,6 +18598,22 @@ int ed25519_test(void) static const byte pKeySz[] = {sizeof(pKey1), sizeof(pKey2), sizeof(pKey3), sizeof(pKey4), sizeof(pKey5), sizeof(pKey6)}; + + static const byte pKeyCtx1[] = { + 0xdf,0xc9,0x42,0x5e,0x4f,0x96,0x8f,0x7f, + 0x0c,0x29,0xf0,0x25,0x9c,0xf5,0xf9,0xae, + 0xd6,0x85,0x1c,0x2b,0xb4,0xad,0x8b,0xfb, + 0x86,0x0c,0xfe,0xe0,0xab,0x24,0x82,0x92 + }; + + static const byte pKeyPh1[] = { + 0xec,0x17,0x2b,0x93,0xad,0x5e,0x56,0x3b, + 0xf4,0x93,0x2c,0x70,0xe1,0x24,0x50,0x34, + 0xc3,0x54,0x67,0xef,0x2e,0xfd,0x4d,0x64, + 0xeb,0xf8,0x19,0x68,0x34,0x67,0xe2,0xbf + + }; + static const byte sig1[] = { 0xe5,0x56,0x43,0x00,0xc3,0x60,0xac,0x72, 0x90,0x86,0xe2,0xcc,0x80,0x6e,0x82,0x8a, @@ -18654,6 +18684,28 @@ int ed25519_test(void) static const byte* sigs[] = {sig1, sig2, sig3, sig4, sig5, sig6}; + static const byte sigCtx1[] = { + 0x55,0xa4,0xcc,0x2f,0x70,0xa5,0x4e,0x04, + 0x28,0x8c,0x5f,0x4c,0xd1,0xe4,0x5a,0x7b, + 0xb5,0x20,0xb3,0x62,0x92,0x91,0x18,0x76, + 0xca,0xda,0x73,0x23,0x19,0x8d,0xd8,0x7a, + 0x8b,0x36,0x95,0x0b,0x95,0x13,0x00,0x22, + 0x90,0x7a,0x7f,0xb7,0xc4,0xe9,0xb2,0xd5, + 0xf6,0xcc,0xa6,0x85,0xa5,0x87,0xb4,0xb2, + 0x1f,0x4b,0x88,0x8e,0x4e,0x7e,0xdb,0x0d + }; + + static const byte sigPh1[] = { + 0x98,0xa7,0x02,0x22,0xf0,0xb8,0x12,0x1a, + 0xa9,0xd3,0x0f,0x81,0x3d,0x68,0x3f,0x80, + 0x9e,0x46,0x2b,0x46,0x9c,0x7f,0xf8,0x76, + 0x39,0x49,0x9b,0xb9,0x4e,0x6d,0xae,0x41, + 0x31,0xf8,0x50,0x42,0x46,0x3c,0x2a,0x35, + 0x5a,0x20,0x03,0xd0,0x62,0xad,0xf5,0xaa, + 0xa1,0x0b,0x8c,0x61,0xe6,0x36,0x06,0x2a, + 0xaa,0xd1,0x1c,0x2a,0x26,0x08,0x34,0x06 + }; + static const byte msg1[] = {0x0 }; static const byte msg2[] = {0x72}; static const byte msg3[] = {0xAF,0x82}; @@ -18798,6 +18850,19 @@ int ed25519_test(void) 0 /*sizeof(msg1)*/, sizeof(msg4) }; + + static const byte msgCtx1[] = { + 0xf7,0x26,0x93,0x6d,0x19,0xc8,0x00,0x49, + 0x4e,0x3f,0xda,0xff,0x20,0xb2,0x76,0xa8 + }; + + static const byte msgPh1[] = { + 0x61,0x62,0x63 + }; + + static const byte contextCtx1[] = { + 0x66,0x6f,0x6f + }; #ifndef NO_ASN static byte privateEd25519[] = { 0x30,0x2e,0x02,0x01,0x00,0x30,0x05,0x06, @@ -18916,6 +18981,64 @@ int ed25519_test(void) #endif /* HAVE_ED25519_VERIFY */ } + outlen = sizeof(out); + XMEMSET(out, 0, sizeof(out)); + + if (wc_ed25519_import_private_key(sKeyCtx1, ED25519_KEY_SIZE, pKeyCtx1, + sizeof(pKeyCtx1), &key) != 0) + return -9020; + + if (wc_ed25519ctx_sign_msg(msgCtx1, sizeof(msgCtx1), out, &outlen, &key, + contextCtx1, sizeof(contextCtx1)) != 0) + return -9021; + + if (XMEMCMP(out, sigCtx1, 64)) + return -9022; + +#if defined(HAVE_ED25519_VERIFY) + /* test verify on good msg */ + if (wc_ed25519ctx_verify_msg(out, outlen, msgCtx1, sizeof(msgCtx1), &verify, + &key, contextCtx1, sizeof(contextCtx1)) != 0 || + verify != 1) + return -9023; + + /* test verify on bad msg */ + out[outlen-1] = out[outlen-1] + 1; + if (wc_ed25519ctx_verify_msg(out, outlen, msgCtx1, sizeof(msgCtx1), &verify, + &key, contextCtx1, sizeof(contextCtx1)) == 0 || + verify == 1) + return -9024; +#endif + + outlen = sizeof(out); + XMEMSET(out, 0, sizeof(out)); + + if (wc_ed25519_import_private_key(sKeyPh1, ED25519_KEY_SIZE, pKeyPh1, + sizeof(pKeyPh1), &key) != 0) + return -9025; + + if (wc_ed25519ph_sign_msg(msgPh1, sizeof(msgPh1), out, &outlen, &key, NULL, + 0) != 0) + return -9026; + + if (XMEMCMP(out, sigPh1, 64)) + return -9027; + +#if defined(HAVE_ED25519_VERIFY) + /* test verify on good msg */ + if (wc_ed25519ph_verify_msg(out, outlen, msgPh1, sizeof(msgPh1), &verify, + &key, NULL, 0) != 0 || + verify != 1) + return -9028; + + /* test verify on bad msg */ + out[outlen-1] = out[outlen-1] + 1; + if (wc_ed25519ph_verify_msg(out, outlen, msgPh1, sizeof(msgPh1), &verify, + &key, NULL, 0) == 0 || + verify == 1) + return -9029; +#endif + #ifndef NO_ASN /* Try ASN.1 encoded private-only key and public key. */ idx = 0; diff --git a/wolfssl/wolfcrypt/ed25519.h b/wolfssl/wolfcrypt/ed25519.h index f3338b3bb..3e858bf12 100644 --- a/wolfssl/wolfcrypt/ed25519.h +++ b/wolfssl/wolfcrypt/ed25519.h @@ -63,6 +63,12 @@ #define ED25519_PRV_KEY_SIZE (ED25519_PUB_KEY_SIZE+ED25519_KEY_SIZE) +enum { + Ed25519 = -1, + Ed25519ctx = 0, + Ed25519ph = 1, +}; + #ifndef WC_ED25519KEY_TYPE_DEFINED typedef struct ed25519_key ed25519_key; #define WC_ED25519KEY_TYPE_DEFINED @@ -90,11 +96,35 @@ int wc_ed25519_make_public(ed25519_key* key, unsigned char* pubKey, WOLFSSL_API int wc_ed25519_make_key(WC_RNG* rng, int keysize, ed25519_key* key); WOLFSSL_API -int wc_ed25519_sign_msg(const byte* in, word32 inlen, byte* out, - word32 *outlen, ed25519_key* key); +int wc_ed25519_sign_msg(const byte* in, word32 inLen, byte* out, + word32 *outLen, ed25519_key* key); WOLFSSL_API -int wc_ed25519_verify_msg(const byte* sig, word32 siglen, const byte* msg, - word32 msglen, int* stat, ed25519_key* key); +int wc_ed25519ctx_sign_msg(const byte* in, word32 inLen, byte* out, + word32 *outLen, ed25519_key* key, + const byte* context, byte contextLen); +WOLFSSL_API +int wc_ed25519ph_sign_hash(const byte* hash, word32 hashLen, byte* out, + word32 *outLen, ed25519_key* key, + const byte* context, byte contextLen); +WOLFSSL_API +int wc_ed25519ph_sign_msg(const byte* in, word32 inLen, byte* out, + word32 *outLen, ed25519_key* key, const byte* context, + byte contextLen); +WOLFSSL_API +int wc_ed25519_verify_msg(const byte* sig, word32 sigLen, const byte* msg, + word32 msgLen, int* stat, ed25519_key* key); +WOLFSSL_API +int wc_ed25519ctx_verify_msg(const byte* sig, word32 sigLen, const byte* msg, + word32 msgLen, int* stat, ed25519_key* key, + const byte* context, byte contextLen); +WOLFSSL_API +int wc_ed25519ph_verify_hash(const byte* sig, word32 sigLen, const byte* hash, + word32 hashLen, int* stat, ed25519_key* key, + const byte* context, byte contextLen); +WOLFSSL_API +int wc_ed25519ph_verify_msg(const byte* sig, word32 sigLen, const byte* msg, + word32 msgLen, int* stat, ed25519_key* key, + const byte* context, byte contextLen); WOLFSSL_API int wc_ed25519_init(ed25519_key* key); WOLFSSL_API