diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2023-03-22 16:44:03 +0100 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2023-03-22 16:44:03 +0100 |
commit | aa83760418f5ed5ce35a9add6517b2ca98ccb5bd (patch) | |
tree | 784d5e108ea31e20c5183cc9508d695f35e626bc | |
parent | ba6815ef8fb8ae472412b5af2837a7caba2799c2 (diff) |
Add crypto sources for future use.add/crypto
* the goal is to support AES-CBC-HMAC-SHA as AEAD cipher
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rw-r--r-- | Makefile | 27 | ||||
-rw-r--r-- | crypto/aes.c | 572 | ||||
-rw-r--r-- | crypto/aes.h | 91 | ||||
-rw-r--r-- | crypto/hmac.c | 37 | ||||
-rw-r--r-- | crypto/hmac.h | 22 | ||||
-rw-r--r-- | crypto/pkcs7_padding.c | 56 | ||||
-rw-r--r-- | crypto/pkcs7_padding.h | 24 | ||||
-rw-r--r-- | crypto/sha1.c | 518 | ||||
-rw-r--r-- | crypto/sha1.h | 61 | ||||
-rwxr-xr-x | crypto/update.sh | 14 |
10 files changed, 1417 insertions, 5 deletions
@@ -4,16 +4,27 @@ endif include $(DPP_ROOT)/Makefile.inc +SOCKET_HEADERS = ksocket/berkeley.h ksocket/helper.hpp ksocket/ksocket.h ksocket/wsk.h +SOCKET_OBJECTS = ksocket/ksocket.o ksocket/berkeley.o + +PROTOB_HEADERS = protobuf-c/protobuf-c.h +PROTOB_OBJECTS = protobuf-c/protobuf-c.o + +CRYPTO_HEADERS = +CRYPTO_OBJECTS = crypto/aes.o crypto/hmac.o crypto/sha1.o crypto/pkcs7_padding.o + +STATIC_LIB_OBJS = $(SOCKET_OBJECTS) $(PROTOB_OBJECTS) $(CRYPTO_OBJECTS) + DRIVER0_NAME = driver -DRIVER0_OBJECTS = examples/$(DRIVER0_NAME).o ksocket/ksocket.o ksocket/berkeley.o +DRIVER0_OBJECTS = examples/$(DRIVER0_NAME).o $(SOCKET_OBJECTS) DRIVER0_TARGET = $(DRIVER0_NAME).sys DRIVER1_NAME = driver-protobuf-c -DRIVER1_OBJECTS = examples/$(DRIVER1_NAME).o protobuf-c/protobuf-c.o examples/example.pb-c.o +DRIVER1_OBJECTS = examples/$(DRIVER1_NAME).o $(PROTOB_OBJECTS) examples/example.pb-c.o DRIVER1_TARGET = $(DRIVER1_NAME).sys DRIVER2_NAME = driver-protobuf-c-tcp -DRIVER2_OBJECTS = examples/$(DRIVER2_NAME).o ksocket/ksocket.o ksocket/berkeley.o protobuf-c/protobuf-c.o examples/example.pb-c.o +DRIVER2_OBJECTS = examples/$(DRIVER2_NAME).o $(SOCKET_OBJECTS) $(PROTOB_OBJECTS) examples/example.pb-c.o DRIVER2_TARGET = $(DRIVER2_NAME).sys USERSPACE0_NAME = userspace_client @@ -21,7 +32,7 @@ USERSPACE0_OBJECTS = examples/$(USERSPACE0_NAME).o USERSPACE0_TARGET = $(USERSPACE0_NAME).exe USERSPACE1_NAME = userspace_client_protobuf -USERSPACE1_OBJECTS = examples/$(USERSPACE1_NAME).o protobuf-c/protobuf-c.o examples/example.pb-c.o +USERSPACE1_OBJECTS = examples/$(USERSPACE1_NAME).o $(PROTOB_OBJECTS) examples/example.pb-c.o USERSPACE1_TARGET = $(USERSPACE1_NAME).exe # mingw-w64-dpp related @@ -71,7 +82,13 @@ install: $(DRIVER0_TARGET) $(DRIVER1_TARGET) $(DRIVER2_TARGET) $(USERSPACE0_TARG $(INSTALL) 'examples/$(DRIVER1_NAME).bat' '$(DESTDIR)/' $(INSTALL) 'examples/$(DRIVER2_NAME).bat' '$(DESTDIR)/' +package: $(SOCKET_HEADERS) $(PROTOB_HEADERS) $(STATIC_LIB_OBJS) + $(call INSTALL_HEADERS,ksocket,$(SOCKET_HEADERS),package) + $(call INSTALL_HEADERS,protobuf-c,$(PROTOB_HEADERS),package) + $(call PACKAGE,ksocket,$(STATIC_LIB_OBJS),package) + clean: + rm -f $(STATIC_LIB_OBJS) rm -f $(DRIVER0_OBJECTS) $(DRIVER1_OBJECTS) $(DRIVER2_OBJECTS) rm -f $(DRIVER0_TARGET) $(DRIVER0_TARGET).map \ $(DRIVER1_TARGET) $(DRIVER1_TARGET).map \ @@ -80,5 +97,5 @@ clean: rm -f $(USERSPACE0_TARGET) $(USERSPACE1_TARGET) .NOTPARALLEL: clean -.PHONY: all install clean +.PHONY: all install package clean .DEFAULT_GOAL := all diff --git a/crypto/aes.c b/crypto/aes.c new file mode 100644 index 0000000..4481f7b --- /dev/null +++ b/crypto/aes.c @@ -0,0 +1,572 @@ +/* + +This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode. +Block size can be chosen in aes.h - available choices are AES128, AES192, AES256. + +The implementation is verified against the test vectors in: + National Institute of Standards and Technology Special Publication 800-38A 2001 ED + +ECB-AES128 +---------- + + plain-text: + 6bc1bee22e409f96e93d7e117393172a + ae2d8a571e03ac9c9eb76fac45af8e51 + 30c81c46a35ce411e5fbc1191a0a52ef + f69f2445df4f9b17ad2b417be66c3710 + + key: + 2b7e151628aed2a6abf7158809cf4f3c + + resulting cipher + 3ad77bb40d7a3660a89ecaf32466ef97 + f5d3d58503b9699de785895a96fdbaaf + 43b1cd7f598ece23881b00e3ed030688 + 7b0c785e27e8ad3f8223207104725dd4 + + +NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) + You should pad the end of the string with zeros if this is not the case. + For AES192/256 the key size is proportionally larger. + +*/ + + +/*****************************************************************************/ +/* Includes: */ +/*****************************************************************************/ +#include <string.h> // CBC mode, for memset +#include "aes.h" + +/*****************************************************************************/ +/* Defines: */ +/*****************************************************************************/ +// The number of columns comprising a state in AES. This is a constant in AES. Value=4 +#define Nb 4 + +#if defined(AES256) && (AES256 == 1) + #define Nk 8 + #define Nr 14 +#elif defined(AES192) && (AES192 == 1) + #define Nk 6 + #define Nr 12 +#else + #define Nk 4 // The number of 32 bit words in a key. + #define Nr 10 // The number of rounds in AES Cipher. +#endif + +// jcallan@github points out that declaring Multiply as a function +// reduces code size considerably with the Keil ARM compiler. +// See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3 +#ifndef MULTIPLY_AS_A_FUNCTION + #define MULTIPLY_AS_A_FUNCTION 0 +#endif + + + + +/*****************************************************************************/ +/* Private variables: */ +/*****************************************************************************/ +// state - array holding the intermediate results during decryption. +typedef uint8_t state_t[4][4]; + + + +// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM +// The numbers below can be computed dynamically trading ROM for RAM - +// This can be useful in (embedded) bootloader applications, where ROM is often limited. +static const uint8_t sbox[256] = { + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; + +#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) +static const uint8_t rsbox[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; +#endif + +// The round constant word array, Rcon[i], contains the values given by +// x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) +static const uint8_t Rcon[11] = { + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; + +/* + * Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12), + * that you can remove most of the elements in the Rcon array, because they are unused. + * + * From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon + * + * "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed), + * up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm." + */ + + +/*****************************************************************************/ +/* Private functions: */ +/*****************************************************************************/ +/* +static uint8_t getSBoxValue(uint8_t num) +{ + return sbox[num]; +} +*/ +#define getSBoxValue(num) (sbox[(num)]) + +// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. +static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) +{ + unsigned i, j, k; + uint8_t tempa[4]; // Used for the column/row operations + + // The first round key is the key itself. + for (i = 0; i < Nk; ++i) + { + RoundKey[(i * 4) + 0] = Key[(i * 4) + 0]; + RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; + RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; + RoundKey[(i * 4) + 3] = Key[(i * 4) + 3]; + } + + // All other round keys are found from the previous round keys. + for (i = Nk; i < Nb * (Nr + 1); ++i) + { + { + k = (i - 1) * 4; + tempa[0]=RoundKey[k + 0]; + tempa[1]=RoundKey[k + 1]; + tempa[2]=RoundKey[k + 2]; + tempa[3]=RoundKey[k + 3]; + + } + + if (i % Nk == 0) + { + // This function shifts the 4 bytes in a word to the left once. + // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] + + // Function RotWord() + { + const uint8_t u8tmp = tempa[0]; + tempa[0] = tempa[1]; + tempa[1] = tempa[2]; + tempa[2] = tempa[3]; + tempa[3] = u8tmp; + } + + // SubWord() is a function that takes a four-byte input word and + // applies the S-box to each of the four bytes to produce an output word. + + // Function Subword() + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + + tempa[0] = tempa[0] ^ Rcon[i/Nk]; + } +#if defined(AES256) && (AES256 == 1) + if (i % Nk == 4) + { + // Function Subword() + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + } +#endif + j = i * 4; k=(i - Nk) * 4; + RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0]; + RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1]; + RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2]; + RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3]; + } +} + +void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key) +{ + KeyExpansion(ctx->RoundKey, key); +} +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) +void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) +{ + KeyExpansion(ctx->RoundKey, key); + memcpy (ctx->Iv, iv, AES_BLOCKLEN); +} +void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv) +{ + memcpy (ctx->Iv, iv, AES_BLOCKLEN); +} +#endif + +// This function adds the round key to state. +// The round key is added to the state by an XOR function. +static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey) +{ + uint8_t i,j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j]; + } + } +} + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +static void SubBytes(state_t* state) +{ + uint8_t i, j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[j][i] = getSBoxValue((*state)[j][i]); + } + } +} + +// The ShiftRows() function shifts the rows in the state to the left. +// Each row is shifted with different offset. +// Offset = Row number. So the first row is not shifted. +static void ShiftRows(state_t* state) +{ + uint8_t temp; + + // Rotate first row 1 columns to left + temp = (*state)[0][1]; + (*state)[0][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[3][1]; + (*state)[3][1] = temp; + + // Rotate second row 2 columns to left + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + // Rotate third row 3 columns to left + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[3][3]; + (*state)[3][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[1][3]; + (*state)[1][3] = temp; +} + +static uint8_t xtime(uint8_t x) +{ + return ((x<<1) ^ (((x>>7) & 1) * 0x1b)); +} + +// MixColumns function mixes the columns of the state matrix +static void MixColumns(state_t* state) +{ + uint8_t i; + uint8_t Tmp, Tm, t; + for (i = 0; i < 4; ++i) + { + t = (*state)[i][0]; + Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ; + Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ; + Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ; + Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ; + Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ; + } +} + +// Multiply is used to multiply numbers in the field GF(2^8) +// Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary +// The compiler seems to be able to vectorize the operation better this way. +// See https://github.com/kokke/tiny-AES-c/pull/34 +#if MULTIPLY_AS_A_FUNCTION +static uint8_t Multiply(uint8_t x, uint8_t y) +{ + return (((y & 1) * x) ^ + ((y>>1 & 1) * xtime(x)) ^ + ((y>>2 & 1) * xtime(xtime(x))) ^ + ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ + ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */ + } +#else +#define Multiply(x, y) \ + ( ((y & 1) * x) ^ \ + ((y>>1 & 1) * xtime(x)) ^ \ + ((y>>2 & 1) * xtime(xtime(x))) ^ \ + ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \ + ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \ + +#endif + +#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) +/* +static uint8_t getSBoxInvert(uint8_t num) +{ + return rsbox[num]; +} +*/ +#define getSBoxInvert(num) (rsbox[(num)]) + +// MixColumns function mixes the columns of the state matrix. +// The method used to multiply may be difficult to understand for the inexperienced. +// Please use the references to gain more information. +static void InvMixColumns(state_t* state) +{ + int i; + uint8_t a, b, c, d; + for (i = 0; i < 4; ++i) + { + a = (*state)[i][0]; + b = (*state)[i][1]; + c = (*state)[i][2]; + d = (*state)[i][3]; + + (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); + (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); + (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); + (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); + } +} + + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +static void InvSubBytes(state_t* state) +{ + uint8_t i, j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[j][i] = getSBoxInvert((*state)[j][i]); + } + } +} + +static void InvShiftRows(state_t* state) +{ + uint8_t temp; + + // Rotate first row 1 columns to right + temp = (*state)[3][1]; + (*state)[3][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[0][1]; + (*state)[0][1] = temp; + + // Rotate second row 2 columns to right + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + // Rotate third row 3 columns to right + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[1][3]; + (*state)[1][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[3][3]; + (*state)[3][3] = temp; +} +#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) + +// Cipher is the main function that encrypts the PlainText. +static void Cipher(state_t* state, const uint8_t* RoundKey) +{ + uint8_t round = 0; + + // Add the First round key to the state before starting the rounds. + AddRoundKey(0, state, RoundKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr rounds are executed in the loop below. + // Last one without MixColumns() + for (round = 1; ; ++round) + { + SubBytes(state); + ShiftRows(state); + if (round == Nr) { + break; + } + MixColumns(state); + AddRoundKey(round, state, RoundKey); + } + // Add round key to last round + AddRoundKey(Nr, state, RoundKey); +} + +#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) +static void InvCipher(state_t* state, const uint8_t* RoundKey) +{ + uint8_t round = 0; + + // Add the First round key to the state before starting the rounds. + AddRoundKey(Nr, state, RoundKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr rounds are executed in the loop below. + // Last one without InvMixColumn() + for (round = (Nr - 1); ; --round) + { + InvShiftRows(state); + InvSubBytes(state); + AddRoundKey(round, state, RoundKey); + if (round == 0) { + break; + } + InvMixColumns(state); + } + +} +#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) + +/*****************************************************************************/ +/* Public functions: */ +/*****************************************************************************/ +#if defined(ECB) && (ECB == 1) + + +void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf) +{ + // The next function call encrypts the PlainText with the Key using AES algorithm. + Cipher((state_t*)buf, ctx->RoundKey); +} + +void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf) +{ + // The next function call decrypts the PlainText with the Key using AES algorithm. + InvCipher((state_t*)buf, ctx->RoundKey); +} + + +#endif // #if defined(ECB) && (ECB == 1) + + + + + +#if defined(CBC) && (CBC == 1) + + +static void XorWithIv(uint8_t* buf, const uint8_t* Iv) +{ + uint8_t i; + for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size + { + buf[i] ^= Iv[i]; + } +} + +void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t* buf, size_t length) +{ + size_t i; + uint8_t *Iv = ctx->Iv; + for (i = 0; i < length; i += AES_BLOCKLEN) + { + XorWithIv(buf, Iv); + Cipher((state_t*)buf, ctx->RoundKey); + Iv = buf; + buf += AES_BLOCKLEN; + } + /* store Iv in ctx for next call */ + memcpy(ctx->Iv, Iv, AES_BLOCKLEN); +} + +void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) +{ + size_t i; + uint8_t storeNextIv[AES_BLOCKLEN]; + for (i = 0; i < length; i += AES_BLOCKLEN) + { + memcpy(storeNextIv, buf, AES_BLOCKLEN); + InvCipher((state_t*)buf, ctx->RoundKey); + XorWithIv(buf, ctx->Iv); + memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN); + buf += AES_BLOCKLEN; + } + +} + +#endif // #if defined(CBC) && (CBC == 1) + + + +#if defined(CTR) && (CTR == 1) + +/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */ +void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) +{ + uint8_t buffer[AES_BLOCKLEN]; + + size_t i; + int bi; + for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi) + { + if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */ + { + + memcpy(buffer, ctx->Iv, AES_BLOCKLEN); + Cipher((state_t*)buffer,ctx->RoundKey); + + /* Increment Iv and handle overflow */ + for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi) + { + /* inc will overflow */ + if (ctx->Iv[bi] == 255) + { + ctx->Iv[bi] = 0; + continue; + } + ctx->Iv[bi] += 1; + break; + } + bi = 0; + } + + buf[i] = (buf[i] ^ buffer[bi]); + } +} + +#endif // #if defined(CTR) && (CTR == 1) + diff --git a/crypto/aes.h b/crypto/aes.h new file mode 100644 index 0000000..b29b668 --- /dev/null +++ b/crypto/aes.h @@ -0,0 +1,91 @@ +#ifndef _AES_H_ +#define _AES_H_ + +#include <stdint.h> +#include <stddef.h> + +// #define the macros below to 1/0 to enable/disable the mode of operation. +// +// CBC enables AES encryption in CBC-mode of operation. +// CTR enables encryption in counter-mode. +// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously. + +// The #ifndef-guard allows it to be configured before #include'ing or at compile time. +#ifndef CBC + #define CBC 1 +#endif + +#ifndef ECB + #define ECB 1 +#endif + +#ifndef CTR + #define CTR 1 +#endif + + +#define AES128 1 +//#define AES192 1 +//#define AES256 1 + +#define AES_BLOCKLEN 16 // Block length in bytes - AES is 128b block only + +#if defined(AES256) && (AES256 == 1) + #define AES_KEYLEN 32 + #define AES_keyExpSize 240 +#elif defined(AES192) && (AES192 == 1) + #define AES_KEYLEN 24 + #define AES_keyExpSize 208 +#else + #define AES_KEYLEN 16 // Key length in bytes + #define AES_keyExpSize 176 +#endif + +struct AES_ctx +{ + uint8_t RoundKey[AES_keyExpSize]; +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) + uint8_t Iv[AES_BLOCKLEN]; +#endif +}; + +void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key); +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) +void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv); +void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv); +#endif + +#if defined(ECB) && (ECB == 1) +// buffer size is exactly AES_BLOCKLEN bytes; +// you need only AES_init_ctx as IV is not used in ECB +// NB: ECB is considered insecure for most uses +void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf); +void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf); + +#endif // #if defined(ECB) && (ECB == !) + + +#if defined(CBC) && (CBC == 1) +// buffer size MUST be mutile of AES_BLOCKLEN; +// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme +// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv() +// no IV should ever be reused with the same key +void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); +void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); + +#endif // #if defined(CBC) && (CBC == 1) + + +#if defined(CTR) && (CTR == 1) + +// Same function for encrypting as for decrypting. +// IV is incremented for every block, and used after encryption as XOR-compliment for output +// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme +// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv() +// no IV should ever be reused with the same key +void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); + +#endif // #if defined(CTR) && (CTR == 1) + + +#endif // _AES_H_ diff --git a/crypto/hmac.c b/crypto/hmac.c new file mode 100644 index 0000000..f9b81c1 --- /dev/null +++ b/crypto/hmac.c @@ -0,0 +1,37 @@ +#include "hmac.h" + +/* function doing the HMAC-SHA-1 calculation */ +void hmac_sha1(const uint8_t* key, const uint32_t keysize, const uint8_t* msg, const uint32_t msgsize, uint8_t* output) +{ + struct sha1 outer, inner; + uint8_t tmp; + + sha1_reset(&outer); + sha1_reset(&inner); + + uint32_t i; + for (i = 0; i < keysize; ++i) + { + tmp = key[i] ^ 0x5C; + sha1_input(&outer, &tmp, 1); + tmp = key[i] ^ 0x36; + sha1_input(&inner, &tmp, 1); + } + for (; i < 64; ++i) + { + tmp = 0x5C; + sha1_input(&outer, &tmp, 1); + tmp = 0x36; + sha1_input(&inner, &tmp, 1); + } + + sha1_input(&inner, msg, msgsize); + sha1_result(&inner, output); + + sha1_input(&outer, output, HMAC_SHA1_HASH_SIZE); + sha1_result(&outer, output); +} + + + + diff --git a/crypto/hmac.h b/crypto/hmac.h new file mode 100644 index 0000000..2c2d437 --- /dev/null +++ b/crypto/hmac.h @@ -0,0 +1,22 @@ +#ifndef __HMAC_H__ +#define __HMAC_H__ + +#include <stdint.h> +#include "sha1.h" + +#define HMAC_SHA1_HASH_SIZE 20 + +/***********************************************************************' + * HMAC(K,m) : HMAC SHA1 + * @param key : secret key + * @param keysize : key-length ín bytes + * @param msg : msg to calculate HMAC over + * @param msgsize : msg-length in bytes + * @param output : writeable buffer with at least 20 bytes available + */ +void hmac_sha1(const uint8_t* key, const uint32_t keysize, const uint8_t* msg, const uint32_t msgsize, uint8_t* output); + + +#endif /* __HMAC_H__ */ + + diff --git a/crypto/pkcs7_padding.c b/crypto/pkcs7_padding.c new file mode 100644 index 0000000..512f6b6 --- /dev/null +++ b/crypto/pkcs7_padding.c @@ -0,0 +1,56 @@ +#include "pkcs7_padding.h" + +int pkcs7_padding_pad_buffer( uint8_t *buffer, size_t data_length, size_t buffer_size, uint8_t modulus ){ + uint8_t pad_byte = modulus - ( data_length % modulus ) ; + if( data_length + pad_byte > buffer_size ){ + return -pad_byte; + } + int i = 0; + while( i < pad_byte){ + buffer[data_length+i] = pad_byte; + i++; + } + return pad_byte; +} + +int pkcs7_padding_valid( uint8_t *buffer, size_t data_length, size_t buffer_size, uint8_t modulus ){ + uint8_t expected_pad_byte = modulus - ( data_length % modulus ) ; + if( data_length + expected_pad_byte > buffer_size ){ + return 0; + } + int i = 0; + while( i < expected_pad_byte ){ + if( buffer[data_length + i] != expected_pad_byte){ + return 0; + } + i++; + } + return 1; +} + +size_t pkcs7_padding_data_length( uint8_t * buffer, size_t buffer_size, uint8_t modulus ){ + /* test for valid buffer size */ + if( buffer_size % modulus != 0 || + buffer_size < modulus ){ + return 0; + } + uint8_t padding_value; + padding_value = buffer[buffer_size-1]; + /* test for valid padding value */ + if( padding_value < 1 || padding_value > modulus ){ + return 0; + } + /* buffer must be at least padding_value + 1 in size */ + if( buffer_size < padding_value + 1 ){ + return 0; + } + uint8_t count = 1; + buffer_size --; + for( ; count < padding_value ; count++){ + buffer_size --; + if( buffer[buffer_size] != padding_value ){ + return 0; + } + } + return buffer_size; +}
\ No newline at end of file diff --git a/crypto/pkcs7_padding.h b/crypto/pkcs7_padding.h new file mode 100644 index 0000000..bdd6c21 --- /dev/null +++ b/crypto/pkcs7_padding.h @@ -0,0 +1,24 @@ +#ifndef _PKCS7_PADDING_H_ +#define _PKCS7_PADDING_H_ + +#include <stdint.h> +#include <stddef.h> + +/* Pad a buffer with bytes as defined in PKCS#7 + * Returns the number of pad bytes added, or zero if + * the buffer size is not large enough to hold the correctly padded data + */ +int pkcs7_padding_pad_buffer( uint8_t *buffer, size_t data_length, size_t buffer_size, uint8_t modulus ); + +int pkcs7_padding_valid( uint8_t *buffer, size_t data_length, size_t buffer_size, uint8_t modulus ); + +/* Given a block of pkcs7 padded data, return the actual data length in the block based on the padding applied. + * buffer_size must be a multiple of modulus + * last byte 'x' in buffer must be between 1 and modulus + * buffer_size must be at least x + 1 in size + * last 'x' bytes in buffer must be same as 'x' + * returned size will be buffer_size - 'x' + */ +size_t pkcs7_padding_data_length( uint8_t * buffer, size_t buffer_size, uint8_t modulus ); + +#endif
\ No newline at end of file diff --git a/crypto/sha1.c b/crypto/sha1.c new file mode 100644 index 0000000..ea2bf70 --- /dev/null +++ b/crypto/sha1.c @@ -0,0 +1,518 @@ +/* + * sha1.c + * + * Description: + * This file implements the Secure Hashing Algorithm 1 as + * defined in FIPS PUB 180-1 published April 17, 1995. + * + * The SHA-1, produces a 160-bit message digest for a given + * data stream. It should take about 2**n steps to find a + * message with the same digest as a given message and + * 2**(n/2) to find any two messages with the same digest, + * when n is the digest size in bits. Therefore, this + * algorithm can serve as a means of providing a + * "fingerprint" for a message. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. Although SHA-1 allows a message digest to be generated + * for messages of any number of bits less than 2^64, this + * implementation only works with messages with a length that is + * a multiple of the size of an 8-bit character. + * + */ + +#include "sha1.h" + +/* Local Function Prototyptes */ +static void _pad_block(struct sha1*); +static void _process_block(struct sha1*); + +/* SHA1 circular left shift */ +static uint32_t _circular_shift(const uint32_t nbits, const uint32_t word) +{ + return ((word << nbits) | (word >> (32 - nbits))); +} + +/* + * sha1_reset + * + * Description: + * This function will initialize the SHA1-context in preparation + * for computing a new SHA1 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int sha1_reset(struct sha1* context) +{ + if (context == 0) + { + return shaNull; + } + + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Intermediate_Hash[0] = 0x67452301; + context->Intermediate_Hash[1] = 0xEFCDAB89; + context->Intermediate_Hash[2] = 0x98BADCFE; + context->Intermediate_Hash[3] = 0x10325476; + context->Intermediate_Hash[4] = 0xC3D2E1F0; + + context->flags = 0; + + return shaSuccess; +} + +/* + * sha1_result + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 19th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int sha1_result(struct sha1* context, uint8_t Message_Digest[SHA1HashSize]) +{ + int i; + + if ( (context == 0) + || (Message_Digest == 0)) + { + return shaNull; + } + + if ((context->flags & FLAG_CORRUPTED) != 0) + { + return shaStateError; + } + + if ((context->flags & FLAG_COMPUTED) == 0) + { + _pad_block(context); + + for (i = 0; i < 64; ++i) + { + /* message may be sensitive, clear it out */ + context->Message_Block[i] = 0; + } + context->Length_Low = 0; /* and clear length */ + context->Length_High = 0; + context->flags |= FLAG_COMPUTED; + } + + for (i = 0; i < SHA1HashSize; ++i) + { + Message_Digest[i] = (context->Intermediate_Hash[i >> 2] >> (8 * (3 - (i & 0x03)))); + } + + return shaSuccess; +} + +/* + * sha1_input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int sha1_input(struct sha1* context, const uint8_t* message_array, unsigned length) +{ + if (length == 0) + { + return shaSuccess; + } + + if ( (context == 0) + || (message_array == 0)) + { + return shaNull; + } + + if ((context->flags & FLAG_COMPUTED) != 0) + { + context->flags |= FLAG_CORRUPTED; + return shaStateError; + } + + if ((context->flags & FLAG_CORRUPTED) != 0) + { + return shaStateError; + } + + while ( (length != 0) + && (context->flags == 0)) + { + context->Message_Block[context->Message_Block_Index] = (*message_array); + + context->Message_Block_Index += 1; + context->Length_Low += 8; + + if (context->Length_Low == 0) + { + context->Length_High += 1; + + if (context->Length_High == 0) + { + /* Message is too long */ + context->flags |= FLAG_CORRUPTED; + } + } + + if (context->Message_Block_Index == 64) + { + _process_block(context); + } + + message_array += 1; + length -= 1; + } + + return shaSuccess; +} + +/* + * _process_block + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the publication. + * + * + */ +#if 0 // original code +static void _process_block(struct sha1 *context) +{ + const uint32_t K[] = /* Constants defined in SHA-1 */ + { + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + uint32_t t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ + uint32_t W[80]; /* Word sequence */ + uint32_t A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for (t = 0; t < 16; ++t) + { + W[t] = context->Message_Block[(t * 4) + 0] << 24; + W[t] |= context->Message_Block[(t * 4) + 1] << 16; + W[t] |= context->Message_Block[(t * 4) + 2] << 8; + W[t] |= context->Message_Block[(t * 4) + 3] << 0; + } + + for (t = 16; t < 80; ++t) + { + W[t] = _circular_shift(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); + } + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + + for (t = 0; t < 20; ++t) + { + temp = _circular_shift(5, A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + E = D; + D = C; + C = _circular_shift(30, B); + B = A; + A = temp; + } + + for (; t < 40; ++t) + { + temp = _circular_shift(5, A) + (B ^ C ^ D) + E + W[t] + K[1]; + E = D; + D = C; + C = _circular_shift(30, B); + B = A; + A = temp; + } + + for (; t < 60; ++t) + { + temp = _circular_shift(5, A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + E = D; + D = C; + C = _circular_shift(30, B); + B = A; + A = temp; + } + + for (; t < 80; ++t) + { + temp = _circular_shift(5, A) + (B ^ C ^ D) + E + W[t] + K[3]; + E = D; + D = C; + C = _circular_shift(30, B); + B = A; + A = temp; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + + context->Message_Block_Index = 0; +} + +#else + +//#define METHOD2 + void _process_block(struct sha1 *context) + { + const uint32_t K[] = /* Constants defined in SHA-1 */ + { + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + uint8_t t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ +#ifdef METHOD2 + uint8_t s; + uint32_t W[16]; +#else + uint32_t W[80]; /* Word sequence */ +#endif + uint32_t A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for (t = 0; t < 16; ++t) + { + W[t] = ((uint32_t)context->Message_Block[t * 4 + 0]) << 24; + W[t] |= ((uint32_t)context->Message_Block[t * 4 + 1]) << 16; + W[t] |= ((uint32_t)context->Message_Block[t * 4 + 2]) << 8; + W[t] |= ((uint32_t)context->Message_Block[t * 4 + 3]) << 0; + } + +#ifndef METHOD2 + for (t = 16; t < 80; ++t) + { + W[t] = _circular_shift(1, (W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16])); + } +#endif + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + + for (t = 0; t < 20; ++t) + { +#ifdef METHOD2 + s = t & 0x0f; + if (t >= 16) + { + W[s] = _circular_shift(1, (W[(s + 13) & 0x0f] ^ W[(s + 8) & 0x0f] ^ W[(s + 2) & 0x0f] ^ W[s])); + } + temp = _circular_shift(5, A) + ((B & C) | ((~B) & D)) + E + W[s] + K[0]; +#else + temp = _circular_shift(5, A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; +#endif + E = D; + D = C; + C = _circular_shift(30, B); + B = A; + A = temp; + } + + for (t = 20; t < 40; ++t) + { +#ifdef METHOD2 + s = (t & 0x0f); + W[s] = _circular_shift(1, (W[(s + 13) & 0x0f] ^ W[(s + 8) & 0x0f] ^ W[(s + 2) & 0x0f] ^ W[s])); + temp = _circular_shift(5, A) + (B ^ C ^ D) + E + W[s] + K[1]; +#else + temp = _circular_shift(5, A) + (B ^ C ^ D) + E + W[t] + K[1]; +#endif + E = D; + D = C; + C = _circular_shift(30, B); + B = A; + A = temp; + } + + for (t = 40; t < 60; ++t) + { +#ifdef METHOD2 + s = (t & 0x0f); + W[s] = _circular_shift(1, (W[(s + 13) & 0x0f] ^ W[(s + 8) & 0x0f] ^ W[(s + 2) & 0x0f] ^ W[s])); + temp = _circular_shift(5, A) + ((B & C) | (B & D) | (C & D)) + E + W[s] + K[2]; +#else + temp = _circular_shift(5, A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; +#endif + E = D; + D = C; + C = _circular_shift(30, B); + B = A; + A = temp; + } + + for (t = 60; t < 80; ++t) + { +#ifdef METHOD2 + s = (t & 0x0f); + W[s] = _circular_shift(1, (W[(s + 13) & 0x0f] ^ W[(s + 8) & 0x0f] ^ W[(s + 2) & 0x0f] ^ W[s])); + temp = _circular_shift(5, A) + (B ^ C ^ D) + E + W[s] + K[3]; +#else + temp = _circular_shift(5, A) + (B ^ C ^ D) + E + W[t] + K[3]; +#endif + E = D; + D = C; + C = _circular_shift(30, B); + B = A; + A = temp; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + + context->Message_Block_Index = 0; + } + +#endif + + +/* + * _pad_block + * + * Description: + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call the ProcessMessageBlock function + * provided appropriately. When it returns, it can be assumed that + * the message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * ProcessMessageBlock: [in] + * The appropriate SHA*ProcessMessageBlock function + * Returns: + * Nothing. + * + */ +static void _pad_block(struct sha1* context) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index > 55) + { + context->Message_Block[context->Message_Block_Index] = 0x80; + context->Message_Block_Index += 1; + + while (context->Message_Block_Index < 64) + { + context->Message_Block[context->Message_Block_Index] = 0; + context->Message_Block_Index += 1; + } + + _process_block(context); + + while (context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index] = 0; + context->Message_Block_Index += 1; + } + } + else + { + context->Message_Block[context->Message_Block_Index] = 0x80; + context->Message_Block_Index += 1; + + while (context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index] = 0; + context->Message_Block_Index += 1; + } + } + + /* + * Store the message length as the last 8 bytes + */ + context->Message_Block[56] = context->Length_High >> 24; + context->Message_Block[57] = context->Length_High >> 16; + context->Message_Block[58] = context->Length_High >> 8; + context->Message_Block[59] = context->Length_High >> 0; + context->Message_Block[60] = context->Length_Low >> 24; + context->Message_Block[61] = context->Length_Low >> 16; + context->Message_Block[62] = context->Length_Low >> 8; + context->Message_Block[63] = context->Length_Low >> 0; + + _process_block(context); +} + + + + + diff --git a/crypto/sha1.h b/crypto/sha1.h new file mode 100644 index 0000000..58817ce --- /dev/null +++ b/crypto/sha1.h @@ -0,0 +1,61 @@ +/* + * sha1.h + * + * Description: + * This is the header file for code which implements the Secure + * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published + * April 17, 1995. + * + * Many of the variable names in this code, especially the + * single character names, were used because those were the names + * used in the publication. + * + * Please read the file sha1.c for more information. + * + */ + +#ifndef _SHA1_H_ +#define _SHA1_H_ + +#include <stdint.h> + +#define SHA1HashSize 20 + +enum +{ + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError /* called Input after Result */ +}; + +#define FLAG_COMPUTED 1 +#define FLAG_CORRUPTED 2 + +/* + * Data structure holding contextual information about the SHA-1 hash + */ +struct sha1 +{ + uint8_t Message_Block[64]; /* 512-bit message blocks */ + uint32_t Intermediate_Hash[5]; /* Message Digest */ + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + uint16_t Message_Block_Index; /* Index into message block array */ + uint8_t flags; +}; + + + +/* + * Public API + */ +int sha1_reset (struct sha1* context); +int sha1_input (struct sha1* context, const uint8_t* message_array, unsigned length); +int sha1_result(struct sha1* context, uint8_t Message_Digest[SHA1HashSize]); + + + +#endif /* #ifndef _SHA1_H_ */ + + diff --git a/crypto/update.sh b/crypto/update.sh new file mode 100755 index 0000000..c9cd37a --- /dev/null +++ b/crypto/update.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env sh + +set -e +set -x + +MYDIR="$(dirname ${0})" +wget 'https://raw.githubusercontent.com/kokke/tiny-AES-c/master/aes.c' -O "${MYDIR}/aes.c" +wget 'https://raw.githubusercontent.com/kokke/tiny-AES-c/master/aes.h' -O "${MYDIR}/aes.h" +wget 'https://raw.githubusercontent.com/kokke/tiny-HMAC-c/main/src/hmac.c' -O "${MYDIR}/hmac.c" +wget 'https://raw.githubusercontent.com/kokke/tiny-HMAC-c/main/src/hmac.h' -O "${MYDIR}/hmac.h" +wget 'https://raw.githubusercontent.com/kokke/tiny-HMAC-c/main/src/sha1.c' -O "${MYDIR}/sha1.c" +wget 'https://raw.githubusercontent.com/kokke/tiny-HMAC-c/main/src/sha1.h' -O "${MYDIR}/sha1.h" +wget 'https://raw.githubusercontent.com/bonybrown/tiny-AES128-C/master/pkcs7_padding.c' -O "${MYDIR}/pkcs7_padding.c" +wget 'https://raw.githubusercontent.com/bonybrown/tiny-AES128-C/master/pkcs7_padding.h' -O "${MYDIR}/pkcs7_padding.h" |