/** * @file decaf/strobe.h * @copyright * Copyright (c) 2015-2016 Cryptography Research, Inc. \n * Released under the MIT License. See LICENSE.txt for license information. * @author Mike Hamburg * @brief STROBE experimental protocol framework. * @warning EXPERIMENTAL! The names, parameter orders etc are likely to change. */ #ifndef __DECAF_STROBE_H__ #define __DECAF_STROBE_H__ #include #ifdef __cplusplus extern "C" { #endif /** Keccak STROBE structure as struct. */ typedef struct { decaf_keccak_sponge_t sponge; /**< Internal sponge object. */ } keccak_decaf_TOY_strobe_s; /** Keccak STROBE structure as one-element array */ typedef keccak_decaf_TOY_strobe_s keccak_decaf_TOY_strobe_t[1]; /** STROBE parameters, 128-bit estimated security for hashing and encryption */ extern const struct decaf_kparams_s STROBE_128 API_VIS; /** STROBE parameters, 256-bit estimated security for hashing and encryption */ extern const struct decaf_kparams_s STROBE_256 API_VIS; /** STROBE parameters, 128-bit estimated security for encryption only (not hashing) */ extern const struct decaf_kparams_s STROBE_KEYED_128 API_VIS; /** STROBE parameters, 256-bit estimated security for encryption only (not hashing) */ extern const struct decaf_kparams_s STROBE_KEYED_256 API_VIS; /** Initialize Strobe protocol context. */ void decaf_TOY_strobe_init ( keccak_decaf_TOY_strobe_t strobe, /**< [out] The uninitialized strobe object. */ const struct decaf_kparams_s *params, /**< [in] Parameter set descriptor. */ const char *proto, /**< [in] Unique identifier for the protocol. TODO: define namespaces for this */ uint8_t am_client /**< [in] Nonzero if this party. */ ) NONNULL API_VIS; /** Run a transaction against a STROBE state. */ void decaf_TOY_strobe_transact ( keccak_decaf_TOY_strobe_t strobe, /**< [inout] The initialized STROBE object. */ unsigned char *out, /**< [out] The output. */ const unsigned char *in, /**< [in] The input. */ size_t len, /**< [in] The length of the input/output. */ uint32_t cw_flags /**< [in] The control word with flags. */ ) __attribute__((nonnull(1))) API_VIS; /** Record a message sent in plaintext */ static INLINE UNUSED NONNULL void decaf_TOY_strobe_plaintext ( keccak_decaf_TOY_strobe_t strobe, /**< [inout] The STROBE object */ const unsigned char *in, /**< [in] The message. */ uint16_t len, /**< [in] The length of the message. */ uint8_t iSent /**< [in] If nonzero, I sent the message. */ ); /** Report authenticated data in strobe context. */ static INLINE UNUSED NONNULL void decaf_TOY_strobe_ad ( keccak_decaf_TOY_strobe_t strobe, /**< [inout] The strobe object. */ const unsigned char *in, /**< [in] The plaintext. */ size_t len /**< [in] The length of the ad. */ ); /** Set nonce in strobe context. */ static INLINE UNUSED NONNULL void decaf_TOY_strobe_nonce ( keccak_decaf_TOY_strobe_t strobe, /**< [inout] The initialized strobe object. */ const unsigned char *in, /**< [in] The nonce. */ uint16_t len /**< [in] The length of the nonce. */ ); /** Set fixed key in strobe context. */ static INLINE UNUSED NONNULL void decaf_TOY_strobe_fixed_key ( keccak_decaf_TOY_strobe_t strobe, /**< [inout] The initialized strobe object. */ const unsigned char *in, /**< [in] The key. */ uint16_t len /**< [in] The length of the key. */ ); /** Set Diffie-Hellman key in strobe context. */ static INLINE UNUSED NONNULL void decaf_TOY_strobe_dh_key ( keccak_decaf_TOY_strobe_t strobe, /**< [inout] The initialized strobe object. */ const unsigned char *in, /**< [in] The key. */ uint16_t len /**< [in] The length of the key. */ ); /** The maximum number of bytes that decaf_TOY_strobe_produce_auth can spit out. */ #define STROBE_MAX_AUTH_BYTES 32 /** Produce an authenticator. */ static INLINE UNUSED NONNULL void decaf_TOY_strobe_produce_auth ( keccak_decaf_TOY_strobe_t strobe, /**< [inout] The Strobe protocol context. */ unsigned char *out, /**< [out] The authenticator. */ uint16_t len /**< [in] The length, at most STROBE_MAX_AUTH_BYTES. */ ); /** * @brief Verify an authenticator. * @retval DECAF_SUCCESS The operation applied successfully. * @retval DECAF_FAILURE The operation failed because of a * bad validator (or because you aren't keyed) */ decaf_error_t decaf_TOY_strobe_verify_auth ( keccak_decaf_TOY_strobe_t strobe, /**< [inout] The Strobe protocol context */ const unsigned char *in, /**< [in] The authenticator */ uint16_t len /**< [in] The length, at most STROBE_MAX_AUTH_BYTES. */ ) WARN_UNUSED NONNULL API_VIS; /** * @brief Encrypt bytes from in to out. * @warning Doesn't produce an auth tag. */ static INLINE UNUSED NONNULL void decaf_TOY_strobe_encrypt ( keccak_decaf_TOY_strobe_t strobe, /**< [inout] strobe The Strobe protocol context. */ unsigned char *out, /**< [out] The ciphertext. */ const unsigned char *in, /**< [in] The plaintext. */ uint16_t len /**< [in] The length of plaintext and ciphertext. */ ); /** * Decrypt bytes from in to out. * @warning Doesn't check an auth tag. */ static INLINE UNUSED NONNULL void decaf_TOY_strobe_decrypt ( keccak_decaf_TOY_strobe_t strobe, /**< [inout] The Strobe protocol context. */ unsigned char *out, /**< [out] The plaintext. */ const unsigned char *in, /**< [in] The ciphertext. */ uint16_t len /**< [in] The length of plaintext and ciphertext. */ ); /** * @brief Produce a session-bound pseudorandom value. * * @warning This "prng" value is NOT suitable for * refreshing forward secrecy! It's to replace things * like TCP session hash. */ static inline void NONNULL decaf_TOY_strobe_prng ( keccak_decaf_TOY_strobe_t strobe, /**< [inout] The Strobe protocol context */ unsigned char *out, /**< [out] The output random data. */ uint16_t len /**< The length. */ ); /** Respecify Strobe protocol object's crypto. */ void decaf_TOY_strobe_respec ( keccak_decaf_TOY_strobe_t strobe, /**< [inout] The initialized strobe context. */ const struct decaf_kparams_s *params /**< [in] Strobe parameter descriptor. */ ) NONNULL API_VIS; /** Securely destroy a STROBE object by overwriting it. */ static INLINE UNUSED NONNULL void decaf_TOY_strobe_destroy ( keccak_decaf_TOY_strobe_t doomed /**< [in] The object to destroy. */ ); /** @cond internal */ /************************************************************************/ /* Declarations of various constants and operating modes, for extension */ /************************************************************************/ /** STROBE modes of operation */ typedef enum { STROBE_MODE_ABSORB = 0, STROBE_MODE_DUPLEX = 1, STROBE_MODE_ABSORB_R = 2, STROBE_MODE_DUPLEX_R = 3, /* FIXME: no bits allocated in .py version */ STROBE_MODE_PLAINTEXT = 4, STROBE_MODE_SQUEEZE = 5, STROBE_MODE_FORGET = 6, STROBE_MODE_SQUEEZE_R = 7 } decaf_TOY_strobe_mode_t; #define STROBE_FLAG_CLIENT_SENT (1<<8) /**< Set if the client this message. */ #define STROBE_FLAG_IMPLICIT (1<<9) /**< Set if nobody set this message. */ #define STROBE_FLAG_FORGET (1<<12) /**< After this operation, destroy bytes to prevent rollback. */ /* TODO: maybe just make STROBE heavy non-invertible? */ #define STROBE_FLAG_NO_LENGTH (1<<15) /**< This operation has an unknown length (for streaming). */ /* After 1<<16, flags don't go to the sponge anymore, they just affect the handling */ #define STROBE_FLAG_RECV (1<<16) /**< I received this packet, so reverse directions. */ #define STROBE_FLAG_RUN_F (1<<17) /**< Must run F between control word and data. */ #define STROBE_FLAG_MORE (1<<18) /**< Set for all operations in an unknown-length streaming operation after the first */ #define STROBE_FLAG_LENGTH_64 (1<<19) /**< Length is a 64-bit word instead of a 16-bit one. */ #define STROBE_FLAG_NONDIR (STROBE_FLAG_IMPLICIT) /** Automatic flags implied by the mode */ /* NB: SQUEEZE_R is treated as directional because its' MAC. * can of course override by orring in IMPLICIT|NONDIR */ #define STROBE_AUTO_FLAGS(_mode) \ ( (((_mode)&1) ? STROBE_FLAG_RUN_F : 0) \ | (( ((_mode) & ~2) == STROBE_MODE_ABSORB \ || (_mode) == STROBE_MODE_SQUEEZE \ || (_mode) == STROBE_MODE_FORGET \ ) ? STROBE_FLAG_IMPLICIT|STROBE_FLAG_NONDIR : 0) \ ) /**@ Define a control word for STROBE protocols. */ #define STROBE_CONTROL_WORD(_name,_id,_mode,_flags) \ static const uint32_t _name = _id | (_mode<<10) | (_mode<<29) | _flags | STROBE_AUTO_FLAGS(_mode) STROBE_CONTROL_WORD(STROBE_CW_INIT, 0x00, STROBE_MODE_ABSORB, 0); /**< Initialization with protocol name */ /* Ciphers */ STROBE_CONTROL_WORD(STROBE_CW_FIXED_KEY, 0x10, STROBE_MODE_ABSORB, 0); /**< Fixed symmetric/preshared key */ STROBE_CONTROL_WORD(STROBE_CW_STATIC_PUB, 0x11, STROBE_MODE_PLAINTEXT, 0); /**< Static public key of other party */ STROBE_CONTROL_WORD(STROBE_CW_DH_EPH, 0x12, STROBE_MODE_PLAINTEXT, 0); /**< DH ephemeral key on the wire */ STROBE_CONTROL_WORD(STROBE_CW_DH_KEY, 0x13, STROBE_MODE_ABSORB, 0); /**< DH shared secret key */ STROBE_CONTROL_WORD(STROBE_CW_PRNG, 0x18, STROBE_MODE_SQUEEZE, STROBE_FLAG_FORGET); /**< Generate random bits (for PRNG) */ STROBE_CONTROL_WORD(STROBE_CW_SESSION_HASH, 0x19, STROBE_MODE_SQUEEZE, 0); /**< Generate session hash */ /* Reuse for PRNG */ STROBE_CONTROL_WORD(STROBE_CW_PRNG_INITIAL_SEED, 0x10, STROBE_MODE_ABSORB, STROBE_FLAG_NO_LENGTH); /**< Initial seeding for PRNG */ STROBE_CONTROL_WORD(STROBE_CW_PRNG_RESEED, 0x11, STROBE_MODE_ABSORB, STROBE_FLAG_NO_LENGTH); /**< Later seeding for PRNG */ STROBE_CONTROL_WORD(STROBE_CW_PRNG_CPU_SEED, 0x12, STROBE_MODE_ABSORB, 0); /**< Seed from CPU-builin RNG */ STROBE_CONTROL_WORD(STROBE_CW_PRNG_USER_SEED, 0x13, STROBE_MODE_ABSORB, STROBE_FLAG_LENGTH_64); /**< Seed from user */ STROBE_CONTROL_WORD(STROBE_CW_PRNG_PRNG, 0x14, STROBE_MODE_SQUEEZE, STROBE_FLAG_LENGTH_64 | STROBE_FLAG_FORGET); /**< Call to generate bits */ /* Signatures */ STROBE_CONTROL_WORD(STROBE_CW_SIG_SCHEME, 0x20, STROBE_MODE_ABSORB, 0); /**< Name of the signature scheme we're using. */ STROBE_CONTROL_WORD(STROBE_CW_SIG_PK, 0x21, STROBE_MODE_ABSORB, 0); /**< Public (verification key) */ STROBE_CONTROL_WORD(STROBE_CW_SIG_EPH, 0x22, STROBE_MODE_PLAINTEXT, 0); /**< Schnorr ephemeral. */ STROBE_CONTROL_WORD(STROBE_CW_SIG_CHAL, 0x23, STROBE_MODE_SQUEEZE, 0); /**< Schnorr challenge. */ STROBE_CONTROL_WORD(STROBE_CW_SIG_RESP, 0x24, STROBE_MODE_DUPLEX, 0); /**< Schnoll response. */ /* Payloads and encrypted data */ STROBE_CONTROL_WORD(STROBE_CW_PAYLOAD_PLAINTEXT, 0x30, STROBE_MODE_PLAINTEXT, 0); STROBE_CONTROL_WORD(STROBE_CW_PAYLOAD_CIPHERTEXT, 0x31, STROBE_MODE_DUPLEX, 0); STROBE_CONTROL_WORD(STROBE_CW_MAC, 0x32, STROBE_MODE_SQUEEZE_R, STROBE_FLAG_FORGET); STROBE_CONTROL_WORD(STROBE_CW_AD_EXPLICIT, 0x34, STROBE_MODE_PLAINTEXT, 0); STROBE_CONTROL_WORD(STROBE_CW_AD_IMPLICIT, 0x35, STROBE_MODE_ABSORB, 0); STROBE_CONTROL_WORD(STROBE_CW_NONCE_EXPLICIT, 0x36, STROBE_MODE_PLAINTEXT, 0); STROBE_CONTROL_WORD(STROBE_CW_NONCE_IMPLICIT, 0x37, STROBE_MODE_ABSORB, 0); STROBE_CONTROL_WORD(STROBE_CW_STREAMING_PLAINTEXT,0x30, STROBE_MODE_PLAINTEXT, STROBE_FLAG_NO_LENGTH); /* TODO: orly? */ /* Change spec, control flow, etc */ STROBE_CONTROL_WORD(STROBE_CW_COMPRESS, 0x40, STROBE_MODE_ABSORB_R, 0); /* FIXME: adjust this respec logic */ STROBE_CONTROL_WORD(STROBE_CW_RESPEC_INFO, 0x41, STROBE_MODE_ABSORB, STROBE_FLAG_RUN_F | STROBE_FLAG_FORGET); STROBE_CONTROL_WORD(STROBE_CW_RESPEC, 0x42, STROBE_MODE_ABSORB_R, STROBE_FLAG_RUN_F); STROBE_CONTROL_WORD(STROBE_CW_FORK, 0x43, STROBE_MODE_ABSORB_R, STROBE_FLAG_RUN_F | STROBE_FLAG_FORGET); /* FIXME: instance can be rolled back to recover other INSTANCEs */ STROBE_CONTROL_WORD(STROBE_CW_INSTANCE, 0x44, STROBE_MODE_ABSORB_R, STROBE_FLAG_FORGET); STROBE_CONTROL_WORD(STROBE_CW_ACKNOWLEDGE, 0x45, STROBE_MODE_PLAINTEXT, 0); /** Reverse a keyword because it's being received instead of sent */ static INLINE UNUSED WARN_UNUSED uint32_t decaf_TOY_strobe_cw_recv(uint32_t cw) { uint32_t recv_toggle = (cw & STROBE_FLAG_NONDIR) ? 0 : STROBE_FLAG_RECV; if (cw & STROBE_FLAG_IMPLICIT) { return cw ^ recv_toggle; } else { uint32_t modes_2[8] = { /* Note: most of these really shouldn't happen... */ STROBE_MODE_ABSORB, STROBE_MODE_DUPLEX_R, STROBE_MODE_ABSORB_R, STROBE_MODE_DUPLEX, STROBE_MODE_PLAINTEXT, STROBE_MODE_SQUEEZE, STROBE_MODE_FORGET, STROBE_MODE_ABSORB }; return ((cw & ((1<<29)-1)) | (modes_2[cw>>29]<<29)) ^ recv_toggle; } } /***************************************/ /* Implementations of inline functions */ /***************************************/ void decaf_TOY_strobe_plaintext(keccak_decaf_TOY_strobe_t strobe, const unsigned char *in, uint16_t len, uint8_t iSent) { decaf_TOY_strobe_transact( strobe, NULL, in, len, iSent ? STROBE_CW_PAYLOAD_PLAINTEXT : decaf_TOY_strobe_cw_recv(STROBE_CW_PAYLOAD_PLAINTEXT) ); } void decaf_TOY_strobe_ad(keccak_decaf_TOY_strobe_t strobe, const unsigned char *in, size_t len) { decaf_TOY_strobe_transact( strobe, NULL, in, len, STROBE_CW_AD_EXPLICIT ); } void decaf_TOY_strobe_nonce (keccak_decaf_TOY_strobe_t strobe, const unsigned char *in, uint16_t len) { decaf_TOY_strobe_transact( strobe, NULL, in, len, STROBE_CW_NONCE_EXPLICIT ); } void decaf_TOY_strobe_fixed_key (keccak_decaf_TOY_strobe_t strobe, const unsigned char *in, uint16_t len) { decaf_TOY_strobe_transact( strobe, NULL, in, len, STROBE_CW_FIXED_KEY ); } void decaf_TOY_strobe_dh_key (keccak_decaf_TOY_strobe_t strobe, const unsigned char *in, uint16_t len) { decaf_TOY_strobe_transact( strobe, NULL, in, len, STROBE_CW_DH_KEY ); } void decaf_TOY_strobe_produce_auth (keccak_decaf_TOY_strobe_t strobe, unsigned char *out, uint16_t len) { decaf_TOY_strobe_transact( strobe, out, NULL, len, STROBE_CW_MAC ); } void decaf_TOY_strobe_encrypt (keccak_decaf_TOY_strobe_t strobe, unsigned char *out, const unsigned char *in, uint16_t len) { decaf_TOY_strobe_transact(strobe, out, in, len, STROBE_CW_PAYLOAD_CIPHERTEXT); } void decaf_TOY_strobe_decrypt(keccak_decaf_TOY_strobe_t strobe, unsigned char *out, const unsigned char *in, uint16_t len) { decaf_TOY_strobe_transact(strobe, out, in, len, decaf_TOY_strobe_cw_recv(STROBE_CW_PAYLOAD_CIPHERTEXT)); } void decaf_TOY_strobe_prng(keccak_decaf_TOY_strobe_t strobe, unsigned char *out, uint16_t len) { decaf_TOY_strobe_transact( strobe, out, NULL, len, STROBE_CW_PRNG ); } void decaf_TOY_strobe_destroy (keccak_decaf_TOY_strobe_t doomed) { decaf_sponge_destroy(doomed->sponge); } /** @endcond */ /* internal */ #ifdef __cplusplus } /* extern "C" */ #endif #endif /* __DECAF_STROBE_H__ */