/** *--------------------------------------------------------------------\n * HSLU T&A Hochschule Luzern Technik+Architektur \n *--------------------------------------------------------------------\n * * \brief ASYD assignment crypto 05 * \file * \author Basil Estermann, basil.estermann@stud.hslu.ch * Simon Frei, simon.frei@stud.hslu.ch * Jonas Arnold, jonas.arnold@stud.hslu.ch * \date 23.03.2023 * *-------------------------------------------------------------------- */ #include #include #include #include #include #define VALUE_LENGTH 32 #define MESSAGE_DIGEST_LENGTH 160 #define BLOCK_LENGTH (512/8) #define INPUT_MESSAGE ("Lorem ipsum dolor sit amet, consetetur sadipscing.") #pragma region Macros #define INT_64_LOW_BYTE(input) (input & 0xff) #define INT_64_HIGH_BYTE(input) ((input>>8) & 0xff) #pragma endregion #pragma region SHA1-Constants // initial hash values #define H0 0x67452301 #define H1 0xEFCDAB89 #define H2 0x98BADCFE #define H3 0x10325476 #define H4 0xC3D2E1F0 // constants Kt #define K1 0x5A827999 #define K2 0x6ED9EBA1 #define K3 0x8F1BBCDC #define K4 0xCA62C1D6 #pragma endregion void printBits(size_t const size, void const* const ptr); uint32_t leftRotate(uint32_t n, uint32_t d); uint32_t SHA1_f1(uint32_t b, uint32_t c, uint32_t d); uint32_t SHA1_f2(uint32_t b, uint32_t c, uint32_t d); uint32_t SHA1_f3(uint32_t b, uint32_t c, uint32_t d); uint32_t SHA1_f4(uint32_t b, uint32_t c, uint32_t d); void main(void) { int result = 0; printf("****** SHA1 preprocessing ******\n\n"); #pragma region Preprocessing printf("------ Set initial hash value ------\n\n"); #pragma region Initial Hash values uint32_t a, b, c, d, e; uint32_t h[5] = { H0, H1, H2, H3, H4 }; uint32_t k[5] = { 0, K1, K2, K3, K4 }; // 5 so the array can be accessed by 1, 2, 3, 4 a = h[0]; b = h[1]; c = h[2]; d = h[3]; e = h[4]; #pragma endregion if (sizeof(INPUT_MESSAGE) * 8 > 447) { printf("Message too long!"); return 1000002; } printf("------ Padding message ------\n\n"); #pragma region Padding // print information about message without padding unsigned char messageNoPadding[] = INPUT_MESSAGE; int numBytesMessage = (sizeof(INPUT_MESSAGE) - 1); // -1 because of '\0' at end of the string printf("Size of message without padding: %i bits\n", numBytesMessage*8); printf("Message without padding\n"); printBits(sizeof(messageNoPadding), &messageNoPadding); unsigned char message[BLOCK_LENGTH] = ""; // fill in message for (uint32_t i = 0; i < numBytesMessage; i++) { message[i] = INPUT_MESSAGE[i]; } // set bit message[numBytesMessage] = 0b10000000; printf("\nMessage after adding 1: \n"); printBits(sizeof(message), &message); // add length with high and low byte (length is 64bit) message[BLOCK_LENGTH - 1] = INT_64_LOW_BYTE(numBytesMessage * 8); message[BLOCK_LENGTH - 2] = INT_64_HIGH_BYTE(numBytesMessage * 8); printf("\nMessage after adding length: \n"); printBits(sizeof(message), &message); #pragma endregion #pragma endregion printf("\n\n****** Hash computation ******\n\n"); #pragma region Hash computation printf("\n------ Prepare message schedule ------\n\n"); #pragma region Prepare message schedule uint32_t WordArray[80] = { 0 }; for (uint32_t i = 0; i < 16; i++) { uint32_t currentbyte = message[i] << 24; uint32_t tmp = (uint32_t)(((uint8_t)(message[i * 4]) << 24) + ((uint8_t)(message[4 * i + 1]) << 16) + ((uint8_t)(message[4 * i + 2]) << 8) + (uint8_t)(message[4 * i + 3])); WordArray[i] = tmp; } for (uint32_t i = 16; i < 80; i++) { WordArray[i] = leftRotate((WordArray[i - 3] ^ WordArray[i - 8] ^ WordArray[i - 14] ^ WordArray[i - 16]), 1); } #pragma endregion printf("\n------ Stages ------\n\n"); #pragma region Stages calculations uint32_t (*f_ptr)(uint32_t, uint32_t, uint32_t) = &SHA1_f1; // use: (*f_ptr)(b,c,d); uint8_t stage = 1; // print header row printf("\tA\t\tB\t\tC\t\tD\t\tE\n"); // stage 1...4 for (uint32_t t = 0; t < 80; t++) { uint32_t T = leftRotate(a, 5) + ((*f_ptr)(b, c, d)) + e + k[stage] + WordArray[t]; e = d; d = c; c = leftRotate(b, 30); b = a; a = T; // print row printf("t= %02d:\t%08X\t%08X\t%08X\t%08X\t%08X\t\n", t, a, b, c, d, e); // switch stages if (t == 19) { f_ptr = SHA1_f2; stage = 2; printf("Switched to stage 2.\n"); } else if (t == 39) { f_ptr = SHA1_f3; stage = 3; printf("Switched to stage 3.\n"); } else if (t == 59) { f_ptr = SHA1_f4; stage = 4; printf("Switched to stage 4.\n"); } } #pragma endregion printf("\n------ Intermediate hash calculation ------\n\n"); #pragma region intermediate hash calculation uint32_t summand[5] = { a, b, c, d, e }; for (uint8_t i = 0; i < 5; i++) { // calculate uint32_t h_new = summand[i] + h[i]; // print printf("H[%i] = %08X + %08X = %08X\n", i, summand[i], h[i], h_new); // set value h[i] = h_new; } #pragma endregion #pragma endregion printf("\n****** Resulting hash ******\n\n"); for (uint8_t i = 0; i < 5; i++) { printf("%X ", h[i]); } printf("\n\n"); return 0; } uint32_t SHA1_f1(uint32_t b, uint32_t c, uint32_t d) { return (b & c) | (~b & d); } uint32_t SHA1_f2(uint32_t b, uint32_t c, uint32_t d) { return b ^ c ^ d; } uint32_t SHA1_f3(uint32_t b, uint32_t c, uint32_t d) { return (b & c) | (b & d) | (c & d); } uint32_t SHA1_f4(uint32_t b, uint32_t c, uint32_t d) { return b ^ c ^ d; } uint32_t leftRotate(uint32_t n, uint32_t d) { /* In n<>(INT_BITS - d) */ return (n << d) | (n >> (VALUE_LENGTH - d)); } // Assumes little endian void printBits(size_t const size, void const* const ptr) { unsigned char* b = (unsigned char*)ptr; unsigned char byte; int i, j; for (i = 0; i < size; i++) { for (j = 7; j >= 0; j--) { byte = (b[i] >> j) & 1; printf("%u", byte); } } /*original: for (i = size - 1; i >= 0; i--) { for (j = 7; j >= 0; j--) { byte = (b[i] >> j) & 1; printf("%u", byte); } }*/ puts(""); }