/** *--------------------------------------------------------------------\n * HSLU T&A Hochschule Luzern Technik+Architektur \n *--------------------------------------------------------------------\n * * \brief n size number computation - ASYD * \file * \author Stefano Nicora, stefano.nicora@hslu.ch * \date 17.05.2022 * *-------------------------------------------------------------------- */ #include #include #include /* calloc, malloc, free, etc. */ #include #include #include "encryptionArithmetic.h" /* link two numbers via a mathematical addition */ t_encryptionArithmetic* encryptionArithmetic_ADD(uint32_t* number1, uint32_t* number2, t_encryptionArithmetic* result, uint16_t size); /* link two numbers via a mathematical subtraction */ t_encryptionArithmetic* encryptionArithmetic_SUB(uint32_t* number1, uint32_t* number2, t_encryptionArithmetic* result, uint16_t size); /* link two numbers via a mathematical division */ t_encryptionArithmetic* encryptionArithmetic_DIV(uint32_t* number1, uint32_t* number2, t_encryptionArithmetic* result, uint16_t size); /* link two numbers via a mathematical multiplication */ t_encryptionArithmetic* encryptionArithmetic_MUL(uint32_t* number1, uint32_t* number2, t_encryptionArithmetic* result, uint16_t size); /* link two numbers via logical AND */ t_encryptionArithmetic* encryptionArithmetic_AND(uint32_t* number1, uint32_t* number2, t_encryptionArithmetic* result, uint16_t size); /* link two numbers via logical OR */ t_encryptionArithmetic* encryptionArithmetic_OR(uint32_t* number1, uint32_t* number2, t_encryptionArithmetic* result, uint16_t size); /* link two numbers via logical XOR */ t_encryptionArithmetic* encryptionArithmetic_XOR(uint32_t* number1, uint32_t* number2, t_encryptionArithmetic* result, uint16_t size); /* shift number by amount to the left */ void encryptionArithmetic_LSL(uint32_t* number, uint8_t amount, uint16_t size); /* empty an existing number of its content */ void encryptionArithmetic_clearNumber(uint32_t* number, uint16_t size); /** * Computes the computed result of two numbers while specifying the operation with an OPCODE * * Usage: * Arrays with uint32_t sized entries (number1 and number2) hold the wanted values which get computed bitwise * from LSB to MSB starting at index 0. Data gets stored as "little Endian". * array[0] = [X X X X X X X X X] * MSB LSB * * Example: * uint32_t Number1[10] = { Number }; * uint32_t Number2[10] = { Number }; * t_encryptionArithmetic *result, number; * result = &number; * encryptionArithmetic_Init(result, size); * encryptionArithmetic(Number1, Number2, result, size, ADD); * encryptionArithmetic_DeInit(result->number); * * @param [in] number1 * pointer to the memory location of the first number (stored in 32bit-chunks) * @param [in] number2 * pointer to the memory location of the second number (stored in 32bit-chunks) * @param [in] result * pointer to the memory location of the address which holds the computed number afterwards * @param [in] size * Size is in bits * @param [in] OPCODE * defines the desired operation that gets computed * Available operand: ADD, SUB, DIV, MUL, AND, OR, XOR * @return * pointer to the memory address of the struct */ /* Important: The library takes massively advantage of pointers and memory allocation * Even though there has been done a lot of testing in regard to memory & buffer overflows * they might still happen if you aren't careful. You should rather allocate too much memory than * too little and risk the corruption of data outside your desired working area. */ //03.02: deinit-counter added uint16_t deinitCounter = 0; t_encryptionArithmetic* encryptionArithmetic(uint32_t* number1, uint32_t* number2, t_encryptionArithmetic* result, uint16_t size, t_operation OPCODE) { switch (OPCODE) { case ADD: return encryptionArithmetic_ADD(&(*number1), &(*number2), &(*result), size); break; case SUB: return encryptionArithmetic_SUB(&(*number1), &(*number2), &(*result), size); break; case DIV: return encryptionArithmetic_DIV(&(*number1), &(*number2), &(*result), size); break; case MUL: return encryptionArithmetic_MUL(&(*number1), &(*number2), &(*result), size); break; case AND: return encryptionArithmetic_AND(&(*number1), &(*number2), &(*result), size); break; case OR: return encryptionArithmetic_OR(&(*number1), &(*number2), &(*result), size); break; case XOR: return encryptionArithmetic_XOR(&(*number1), &(*number2), &(*result), size); break; default: printf("OPCODE not recognized. Please select an available one\n"); return 0; break; } } t_encryptionArithmetic* encryptionArithmetic_AND(uint32_t* number1, uint32_t* number2, t_encryptionArithmetic* result, uint16_t size) { uint8_t imm = 0; uint32_t lsl1; uint32_t lsl2; uint32_t lsr1; uint32_t lsr2; for (uint16_t j = 0; j < size / 32; j++) { for (uint8_t i = 0; i < 32; i++) { lsl1 = (*(number1 + imm)) << (31 - i); lsl2 = (*(number2 + imm)) << (31 - i); lsr1 = lsl1 >> (31); lsr2 = lsl2 >> (31); if (lsr1 & lsr2) { *(result->number + imm) |= 1 << i; } } imm++; } result->compSuccess = true; return result; } t_encryptionArithmetic* encryptionArithmetic_XOR(uint32_t* number1, uint32_t* number2, t_encryptionArithmetic* result, uint16_t size) { uint8_t imm = 0; uint32_t lsl1; uint32_t lsl2; uint32_t lsr1; uint32_t lsr2; for (uint16_t j = 0; j < size / 32; j++) { for (uint8_t i = 0; i < 32; i++) { lsl1 = (*(number1 + imm)) << (31 - i); lsl2 = (*(number2 + imm)) << (31 - i); lsr1 = lsl1 >> (31); lsr2 = lsl2 >> (31); if (lsr1 ^ lsr2) { *(result->number + imm) |= 1 << i; } } imm++; } result->compSuccess = true; return result; } t_encryptionArithmetic* encryptionArithmetic_OR(uint32_t* number1, uint32_t* number2, t_encryptionArithmetic* result, uint16_t size) { uint8_t imm = 0; uint32_t lsl1; uint32_t lsl2; uint32_t lsr1; uint32_t lsr2; for (uint16_t j = 0; j < size / 32; j++) { for (uint8_t i = 0; i < 32; i++) { lsl1 = (*(number1 + imm)) << (31 - i); lsl2 = (*(number2 + imm)) << (31 - i); lsr1 = lsl1 >> (31); lsr2 = lsl2 >> (31); if (lsr1 | lsr2) { *(result->number + imm) |= 1 << i; } } imm++; } result->compSuccess = true; return result; } t_encryptionArithmetic* encryptionArithmetic_ADD(uint32_t* number1, uint32_t* number2, t_encryptionArithmetic* result, uint16_t size) { uint8_t imm = 0; /* allocate memory */ result->remainder = 0; if (result->memAllocSuccess == false) { result->number = (uint32_t*)calloc(size / 32 + 1, sizeof(uint32_t)); } if (result->number == NULL) { printf("Cannot allocate memory"); result->memAllocSuccess = false; result->compSuccess = false; return result; } result->memAllocSuccess = true; /* Add the first 32 bits together while omitting the carry bit */ *(result->number + imm) = *(number1 + imm) + *(number2 + imm); imm++; for (uint16_t j = 1; j < size / 32 + 1; j++) { if (*(result->number + imm - 1) < *(number1 + imm - 1)) /* check for omitted carry bit */ { result->hasOverflown = true; } else { result->hasOverflown = false; } *(result->number + imm) = *(number1 + imm) + *(number2 + imm); //Adds the next 32 bit chunk of numbers together *(result->number + imm) = *(result->number + imm) + result->hasOverflown; //checks for the presence of a carry bit and adds it to the number imm++; } result->compSuccess = true; return result; } t_encryptionArithmetic* encryptionArithmetic_SUB(uint32_t* minuend, uint32_t* subtrahend, t_encryptionArithmetic* result, uint16_t size) { /* based on the 1's complement subtraction */ /* https://electricalbaba.com/1s-complement-subtraction-explained-with-examples/ */ /* https://atozmath.com/NumberSubComp.aspx */ /* allocate memory */ if (result->memAllocSuccess == false) { result->number = (uint32_t*)calloc(size / 32 + 1, sizeof(uint32_t)); } if (result->number == NULL) { printf("Cannot allocate memory"); result->memAllocSuccess = false; result->compSuccess = false; return result; } result->memAllocSuccess = true; /* get actual size of the subtrahend */ uint16_t subtrahendSize = encryptionArithmetic_numberSize(subtrahend, size); /* get actual size of the minuend */ uint16_t minuendSize = encryptionArithmetic_numberSize(minuend, size); /* allocate memory */ /* in order to facilitate the iterative usage of the function we need to make sure * that the result is always empty when doing the calculations. Therefore both temp-pointers are needed */ uint32_t* tempMinuend = (uint32_t*)calloc((minuendSize) / 32 + 3, sizeof(uint32_t)); /* + 2 to handle the possible overflow */ //02.02: size -> minuendSize //03.02: 32 + 2 -> 32 + 3 uint32_t* tempSubtrahend = (uint32_t*)calloc((subtrahendSize) / 32 + 3, sizeof(uint32_t)); /* + 2 to handle the possible overflow */ //02.02: size -> subtrahendSize if (tempMinuend == NULL || tempSubtrahend == NULL) { if (tempMinuend != NULL) { free(tempMinuend); } if (tempSubtrahend != NULL) { free(tempSubtrahend); } printf("Cannot allocate memory"); result->memAllocSuccess = false; result->compSuccess = false; return result; } memmove(tempMinuend, minuend, (minuendSize <= 4) ? (1) : (minuendSize / 8) + 1); /* size / 8 + 1 = number of bytes including error for int calulation */ memmove(tempSubtrahend, subtrahend, (subtrahendSize <= 4) ? (1) : (subtrahendSize / 8) + 1);/* size / 8 + 1 = number of bytes including error for int calulation */ result->memAllocSuccess = true; /* there is no sense in generating the 1's complement if we substract 0 from another number */ if (!subtrahendSize || !minuendSize) { if (!subtrahendSize) { /* copy number from minuend into result */ for (uint8_t imm = 0; imm < (minuendSize / 32 + 1); imm++) { //02.02: (size / 32) -> (minuendSize / 32 + 1) *(result->number + imm) = *(tempMinuend + imm); } } else { /* copy number from subtrahend into result */ for (uint8_t imm = 0; imm < (subtrahendSize / 32 + 1); imm++) { //02.02: (size / 32) -> (subtrahendSize / 32 + 1) *(result->number + imm) = *(tempSubtrahend + imm); } } free(tempMinuend); free(tempSubtrahend); result->compSuccess = true; return result; } /* generate the 1's complement out of the subtrahend */ uint8_t cnt = 0; for (uint8_t i = 0; i < (subtrahendSize / 32) + 1; i++) { /* +1 to circumvent division by 0 */ *(tempSubtrahend + i) = ~(*(subtrahend + i)); cnt++; } /* clear any false set bit that occurs during 1's complement generation */ if (subtrahendSize == 32 * (cnt - 1)) { *(tempSubtrahend + cnt - 1) = 0; } else if (subtrahendSize >= 32) { *(tempSubtrahend + cnt - 1) = *(tempSubtrahend + cnt - 1) & (0xFFFFFFFF >> ((32 * cnt) - subtrahendSize)); } else { *(tempSubtrahend + cnt - 1) = *(tempSubtrahend + cnt - 1) & (0xFFFFFFFF >> (32 - subtrahendSize)); } /* Add the first 32 bits together while omitting the carry bit */ encryptionArithmetic_clearNumber(result->number, size); *(result->number) = *(tempMinuend) + *(tempSubtrahend); uint8_t imm = 1; for (uint16_t j = 1; j < minuendSize / 32 + 1; j++) // 02.02: +1 -> +2 | size -> minuendSize { if (*(result->number + imm - 1) < *(tempMinuend + imm - 1)) /* check for omitted carry bit */ { result->hasOverflown = true; } else { result->hasOverflown = false; } *(result->number + imm) = *(tempMinuend + imm) + *(tempSubtrahend + imm); /* Adds the next 32 bit chunk of numbers together */ *(result->number + imm) = *(result->number + imm) + result->hasOverflown; /* checks for the presence of a carry bit and adds it to the number */ imm++; } /* get actual size of the number to catch overflows */ uint16_t numberSize = encryptionArithmetic_numberSize(result->number, size); if (numberSize > minuendSize || numberSize > subtrahendSize) { result->hasOverflown = true; } else { result->hasOverflown = false; } /* if an overflow has occured (= result is positive), we need to add that bit to the LSB while omitting it as the MSB */ if (result->hasOverflown) { /* can't simply be a single uint32_t variable, as there would be out of boundary memory access through the ADD function */ uint32_t* carry = (uint32_t*)calloc((numberSize) / 32 + 2, sizeof(uint32_t)); //02.02: size -> numberSize uint32_t* cache = (uint32_t*)calloc((numberSize) / 32 + 2, sizeof(uint32_t)); //02.02: size -> numberSize if (cache == NULL || carry == NULL) { if (cache != NULL) { free(cache); } if (carry != NULL) { free(carry); } printf("Cannot allocate memory"); result->memAllocSuccess = false; result->compSuccess = false; return result; } *carry = 1; result->memAllocSuccess = true; for (int i = 0; i < (numberSize / 32) + 1; i++) { *(cache + i) = *(result->number + i); } /* remove overflow-MSB */ if (numberSize <= 32) { *(cache) ^= 1 << (numberSize - 1); } else { if (!(numberSize % 32)) /* numberSize is a multiple of 32 */ { *(cache + (numberSize / 32) - 1) ^= 1 << 31; } else { *(cache + (numberSize / 32)) ^= 1 << (numberSize - 1 - ((numberSize / 32) * 32)); } } encryptionArithmetic_clearNumber(result->number, size); encryptionArithmetic_ADD(&(*cache), &(*carry), &(*result), size); free(cache); free(carry); } else { /* generate the 1's complement out of the result as it is negative */ cnt = 0; for (uint8_t i = 0; i < (numberSize / 32) + 1; i++) { /* +1 to circumvent division by 0 */ *(result->number + i) = ~(*(result->number + i)); cnt++; } if (numberSize == 32 * (cnt - 1)) { *(result->number + cnt - 1) = 0; } else if (numberSize >= 32) { *(result->number + cnt - 1) = *(result->number + cnt - 1) & (0xFFFFFFFF >> ((32 * cnt) - numberSize)); } else { *(result->number + cnt - 1) = *(result->number + cnt - 1) & (0xFFFFFFFF >> (32 - numberSize)); } } free(tempMinuend); free(tempSubtrahend); result->compSuccess = true; return result; } t_encryptionArithmetic* encryptionArithmetic_DIV(uint32_t* dividend, uint32_t* divisor, t_encryptionArithmetic* result, uint16_t size) { /* based on long division */ /* https://www.cuemath.com/numbers/long-division/ */ /* allocate memory */ t_encryptionArithmetic* remainder, remainder2; remainder = &remainder2; encryptionArithmetic_Init(remainder, size); result->remainder = 0; bool stateFloat = false, state1 = false, isLarger = false, isEqual = false; /* get actual size of dividend */ uint16_t dividendSize = encryptionArithmetic_numberSize(dividend, size); /* get actual size of divisor */ uint16_t divisorSize = encryptionArithmetic_numberSize(divisor, size); /* basic tests to catch unwanted states */ if (divisorSize == 0) { printf("Divisor is 0!\n"); result->compSuccess = false; return result; } //for (uint16_t i = 0; i < (dividendSize > divisorSize ? dividendSize / 32 + 1 : divisorSize / 32 + 1); i++) for (int16_t i = (dividendSize > divisorSize ? dividendSize / 32 : divisorSize / 32); i >= 0 ; i--) { /* division result = 1 */ if (*(divisor + i) == *(dividend + i)) { state1 = true; stateFloat = false; } /* would result in floating point operation */ else if (*(dividend + i) < *(divisor + i)) { state1 = false; stateFloat = true; break; } else { state1 = false; stateFloat = false; break; } } if (state1) { /* division result = 1 */ *(result->number) = 1; result->remainder = 0; encryptionArithmetic_DeInit(remainder); result->compSuccess = true; return result; } else if (stateFloat) { /* would result in floating point operation */ printf("Divisor is larger than dividend. Floating point operations aren't supported. Result = 0\n"); *(result->number) = 0; result->remainder = 0; encryptionArithmetic_DeInit(remainder); result->compSuccess = true; return result; } /* get the bit we are currently focused on (move from MSB to LSB) */ /* get the offset and focused bit inside the right data chunk */ uint16_t focusPos = 0; /* holds the current "active" bit position we add to our remainder */ uint8_t imm = 0; /* holds the offset relative to the size of our data */ uint8_t focusPosInsideDataChunk = 0; /* holds the read position relative to the address (imm) offset */ uint8_t cnt = 0; /* holds the number of '0' that have to be added to the result starting from the LSB */ uint16_t loopDivisorSize = 0; /* holds the the loop value to catch the wrong state if divisorSize % 32 == 0 */ if (divisorSize % 32 == 0) { loopDivisorSize = (divisorSize / 32) - 1; } else { loopDivisorSize = divisorSize / 32; } for (uint16_t k = 0; k < dividendSize; k++) { focusPos = dividendSize - 1 - k; /* -1 is needed, as the nth bit sits at position n-1 */ imm = focusPos / 32; focusPosInsideDataChunk = focusPos - imm * 32; /* if the remainder is larger than the divisor, we can safely conduct the subtraction w/o the need to check for an over/underflow */ //if (*(remainder->number + (divisorSize / 32)) >= *(divisor + (divisorSize / 32))) //if (*(remainder->number + (divisorSize / 32)) > *(divisor + (divisorSize / 32))) if (*(remainder->number + loopDivisorSize) > *(divisor + loopDivisorSize) || *(remainder->number + loopDivisorSize + 1) > *(divisor + loopDivisorSize + 1)) /* TODO: work here -> check why it fails here */ { encryptionArithmetic_SUB(remainder->number, divisor, remainder, size); /* store subtraction of remainder and divisor inside remainder */ encryptionArithmetic_LSL(result->number, cnt, size); /* shift data to the left to add the next bit */ *(result->number) |= 1; /* add a logical "1" as LSB to the result */ k--; /* keep the read position on the same level, as it would skip one otherwise */ cnt = 0; } else if (*(remainder->number + loopDivisorSize) == *(divisor + loopDivisorSize) && *(remainder->number + loopDivisorSize + 1) == *(divisor + loopDivisorSize + 1)) { /* check if both numbers are actually equal and not only the MSB-chunks of data */ isEqual = false; for (uint16_t i = 0; i <= loopDivisorSize; i++) { if (*(remainder->number + i) == *(divisor + i)) { /* add a logical "1" as LSB to the result */ isEqual = true; } else { /* remainder isn't == divisor and we need to execute the "else" part of the first if-statement */ encryptionArithmetic_LSL(remainder->number, 1, size); /* shift data one step to the left to add the next bit */ *remainder->number |= ((*(dividend + imm) >> (focusPosInsideDataChunk) & 1) ? 1 : 0); /* add next bit (0 or 1) to existing remainder */ cnt++; isEqual = false; break; } } if (isEqual) { /* remainder == divisor and therefore the result is 1 */ encryptionArithmetic_clearNumber(remainder->number, size); *(remainder->number) = 1; } } /* as the remainder is smaller than the divisor, we would get an overflow when subtracting. * Put next bit from the dividend at the end of remainder (new LSB) and try again */ else { encryptionArithmetic_LSL(remainder->number, 1, size); /* shift data one step to the left to add the next bit */ *remainder->number |= ((*(dividend + imm) >> (focusPosInsideDataChunk) & 1) ? 1 : 0); /* add next bit (0 or 1) to existing remainder */ cnt++; } } /* legacy code */ //for (uint16_t k = 0; k < dividendSize; k++) //{ // focusPos = dividendSize - 1 - k; /* -1 is needed, as the nth bit sits at position n-1 */ // imm = focusPos / 32; // focusPosInsideDataChunk = focusPos - imm * 32; // /* if the remainder is larger than the divisor, we can safely conduct the subtraction w/o the need to check for an over/underflow */ // if (result->remainder >= *divisor) // { // result->remainder = result->remainder - *divisor; /* store subtraction of remainder and divisor inside remainder */ // *(result->number + imm) = *(result->number + imm) << cnt | 1; /* add a logical "1" as LSB to the result */ // k--; /* keep the read position on the same level, as it would skip one otherwise */ // cnt = 0; // } // /* as the remainder is smaller than the divisor, we would get an overflow when subtracting. // * Put next bit from the dividend at the end of remainder (new LSB) and try again */ // else // { // result->remainder = (result->remainder << 1) /* shift data each cycle one step to the left to add the next bit */ // | ((*(dividend + imm) >> (focusPosInsideDataChunk) & 1) ? 1 : 0); /* add next bit (0 or 1) to existing remainder */ // cnt++; // } //} /* legacy code end */ /* get actual size of the temporary remainder */ uint16_t remainderSize = encryptionArithmetic_numberSize(remainder->number, size); /* defines the amounts of loops necessary */ uint16_t loopLength = 0; if (remainderSize > divisorSize) { if (!(remainderSize % 32)) /* remainder is a multiple of 32 */ { loopLength = remainderSize / 32 - 1; } else { loopLength = remainderSize / 32; } } else { if (!(divisorSize % 32)) /* remainder is a multiple of 32 */ { loopLength = divisorSize / 32 - 1; } else { loopLength = divisorSize / 32; } } isLarger = false; isEqual = false; for (uint16_t i = 0; i <= loopLength; i++) { if (*(remainder->number + i) > *(divisor + i)) { /* store subtraction of remainder and divisor inside remainder */ isLarger = true; isEqual = false; } else if (*(remainder->number + i) == *(divisor + i)) { /* add a logical "1" as LSB to the result */ isLarger = false; isEqual = true; } } encryptionArithmetic_LSL(result->number, cnt, size); /* shift data cnt-amount to the left */ if (isLarger && !isEqual) /* store subtraction of remainder and divisor inside remainder */ { encryptionArithmetic_SUB(remainder->number, divisor, remainder, size); result->remainder = *remainder->number; /* store subtraction of remainder and divisor inside remainder */ *(result->number) |= 1; /* add a logical "1" as LSB to the result */ } else if (!isLarger && isEqual) /* add a logical "1" as LSB to the result */ { result->remainder = 0; /* no remainder left */ *(result->number) |= 1; /* add a logical "1" as LSB to the result */ } else { result->remainder = *remainder->number; /* store local remainder inside outbound remainder */ } encryptionArithmetic_DeInit(remainder); result->compSuccess = true; return result; } t_encryptionArithmetic* encryptionArithmetic_MUL(uint32_t* multiplicand, uint32_t* multiplier, t_encryptionArithmetic* result, uint16_t size) { /* based on the shift and add algorithm https://users.utcluj.ro/~baruch/book_ssce/SSCE-Shift-Mult.pdf */ uint8_t imm = 0; /* holds the immediate value to keep track of how many chunks of data we traversed */ uint8_t readPos = 0; /* current readable bit position */ /* get actual size of the multiplicand */ uint16_t multiplicandSize = encryptionArithmetic_numberSize(multiplicand, size); /* get actual size of the multiplier */ uint16_t multiplierSize = encryptionArithmetic_numberSize(multiplier, size); /* allocate memory */ /* in order to facilitate the iterative usage of the function we need to make sure * that the result is always empty when doing the calculations. Therefore both temp-pointers are needed */ uint32_t* cache = (uint32_t*)calloc((size) / 32 * 3 + 2, sizeof(uint32_t)); /* Has to be double the size to be able to store all bits + 2 to handle the possible overflow */ uint32_t* tempMultiplicand; /* allocation is done below */ uint32_t* tempMultiplier; /* allocation is done below */ /* for some reason (has to be investigated in the future) multiplying a number with a smaller number results in a limited amount of flipped bits * current workaround: swap multiplier and multiplicand if multiplicand > multiplier */ if (multiplicandSize + 4 > multiplierSize) { tempMultiplicand = (uint32_t*)calloc((multiplicandSize) / 32 * 4 + 2, sizeof(uint32_t)); /* Has to be double the size to be able to store all bits + 2 to handle the possible overflow */ //02.02: size -> multiplicandSize tempMultiplier = (uint32_t*)calloc((multiplicandSize) / 32 * 4 + 2, sizeof(uint32_t)); /* Has to be double the size to be able to store all bits + 2 to handle the possible overflow */ //02.02: size -> multiplierSize if (cache == NULL || tempMultiplicand == NULL || tempMultiplier == NULL) { if (cache != NULL) { free(cache); } if (tempMultiplicand != NULL) { free(tempMultiplicand); } if (tempMultiplier != NULL) { free(tempMultiplier); } printf("Cannot allocate memory"); result->memAllocSuccess = false; result->compSuccess = false; return result; } memmove(tempMultiplier, multiplicand, (multiplicandSize <= 4) ? (1) : (multiplicandSize / 8) + 1); /* size / 8 = number of bytes */ memmove(tempMultiplicand, multiplier, (multiplicandSize <= 4) ? (1) : (multiplicandSize / 8) + 1); /* size / 8 = number of bytes */ /* as the numbers have swapped places, a size recalculation is needed */ multiplicandSize = encryptionArithmetic_numberSize(multiplier, size); multiplierSize = encryptionArithmetic_numberSize(multiplicand, size); } else { /* used to be the default way */ tempMultiplicand = (uint32_t*)calloc((multiplicandSize) / 32 * 4 + 2, sizeof(uint32_t)); /* Has to be double the size to be able to store all bits + 2 to handle the possible overflow */ //02.02: size -> multiplicandSize tempMultiplier = (uint32_t*)calloc((multiplierSize) / 32 * 4 + 2, sizeof(uint32_t)); /* Has to be double the size to be able to store all bits + 2 to handle the possible overflow */ //02.02: size -> multiplierSize if (cache == NULL || tempMultiplicand == NULL || tempMultiplier == NULL) { if (cache != NULL) { free(cache); } if (tempMultiplicand != NULL) { free(tempMultiplicand); } if (tempMultiplier != NULL) { free(tempMultiplier); } printf("Cannot allocate memory"); result->memAllocSuccess = false; result->compSuccess = false; return result; } memmove(tempMultiplicand, multiplicand, (multiplicandSize <= 4) ? (1) : (multiplicandSize / 8) + 1); /* size / 8 = number of bytes */ memmove(tempMultiplier, multiplier, (multiplierSize <= 4) ? (1) : (multiplierSize / 8) + 1); /* size / 8 = number of bytes */ } //memmove(tempMultiplicand, multiplicand, (multiplicandSize <= 4) ? (1) : (multiplicandSize / 8) + 1); /* size / 8 = number of bytes */ //memmove(tempMultiplier, multiplier, (multiplierSize <= 4) ? (1) : (multiplierSize / 8) + 1); /* size / 8 = number of bytes */ result->memAllocSuccess = true; /* clear result for next operation */ encryptionArithmetic_clearNumber(result->number, size); /* traverse the saved number in 32bit chunks */ for (uint16_t j = 0; j <= multiplierSize; j++) //02.02: size -> multiplierSize { if ((j / (imm + 1)) == 32) { /* +1 to prevent division by 0 */ readPos = 0; imm++; } /* check if the current LSB is '1', skip if not */ if ((*(tempMultiplier + imm) >> readPos) & 1) { //for (uint8_t m = 0; m <= ((multiplicandSize > multiplierSize) ? (multiplicandSize / 32 + 1) : (multiplierSize / 32 + 1)); m++) //02.02: /32 -> /32 + 1 & size -> ?: //for (uint8_t m = 0; m <= 7; m++) for (uint8_t m = 0; m <= ((multiplicandSize + multiplierSize) / 32); m++) { /* shift the 32bit number "chunk" according the the layer of addition we are currently on and store in cache */ if (readPos == 0) { *(cache + (m + (j / 32))) += *(tempMultiplicand + m); /* assign bits depending on current readPos */ } else { *(cache + (m + j / 32)) += *(tempMultiplicand + m) << readPos; /* assign bits depending on current readPos */ *(cache + (m + j / 32) + 1) += *(tempMultiplicand + m) >> (32 - readPos); /* assign bits that would be lost in shift operation to the next "chunk" */ } /* add the previous result to the new layer including any overflowing that might occur */ *(result->number + m) += *(cache + m) + result->hasOverflown; //*(result->number + m + (j / 32)) += *(cache + m + (j / 32)) + result->hasOverflown; //03.02 /* if the addition generated an overflow, the stored result will be smaller than the number we added to it */ if ((*(result->number + m) < *(cache + m))) { //if ((*(result->number + m) < *(cache + m)) || (*(result->number + m) == 0xFFFFFFFF) && (*(cache + m) == 0xFFFFFFFF)) { //03.02 //if ((*(result->number + m + (j / 32)) < *(cache + m + (j / 32))) || (*(result->number + m + (j / 32)) == 0xFFFFFFFF) && (*(cache + m + (j / 32)) == 0xFFFFFFFF)) { //03.02 //if ((*(result->number + m + (j / 32)) < *(cache + m)) || (*(result->number + m + (j / 32)) == 0xFFFFFFFF) && (*(cache + m) == 0xFFFFFFFF)) { //04.02 //if ((*(result->number + m) < *(cache + m)) || (*(result->number + m + 1) == 0xFFFFFFFF) && (*(cache + m + 1) == 0xFFFFFFFF)) { //05.02 +m -> m + 1 result->hasOverflown = true; } else { result->hasOverflown = false; } } /* clearing the cache for the next addition operation */ encryptionArithmetic_clearNumber(cache, size); } readPos++; } free(cache); free(tempMultiplicand); free(tempMultiplier); result->compSuccess = true; return result; } void encryptionArithmetic_LSL(uint32_t* number, uint8_t amount, uint16_t size) { uint32_t overflowBit1 = 0, overflowBit2 = 0; /* get actual size of number */ uint16_t numberSize = encryptionArithmetic_numberSize(number, size); overflowBit1 = *number >> (32 - amount); /* store MSB from first block */ *number = *number << amount; /* perform lsl-operation of first block */ if (numberSize + amount >= 32) { for (uint8_t i = 1; i <= (numberSize + amount) / 32; i++) { overflowBit2 = *(number + i) >> (32 - amount); /* store MSB from current block */ *(number + i) = *(number + i) << amount; /* perform lsl-operation of current block */ *(number + i) |= overflowBit1; /* add MSB of last block to current block */ overflowBit1 = overflowBit2; /* store current MSB for next iteration */ } } } t_encryptionArithmetic* encryptionArithmetic_Init(t_encryptionArithmetic* result, uint16_t size) { result->number = (uint32_t*)calloc((size) / 32 * 4 + 1, sizeof(uint32_t)); /* has to be this size to accommodate all types of computations, including multiplication */ if (result->number == NULL) { printf("Cannot allocate memory"); result->memAllocSuccess = false; result->compSuccess = false; return result; } result->memAllocSuccess = true; result->compSuccess = false; *(result->number) = 0; result->remainder = 0; result->hasOverflown = false; return result; } void encryptionArithmetic_DeInit(t_encryptionArithmetic* ptr) { deinitCounter++; free(ptr->number); } uint16_t encryptionArithmetic_numberSize(uint32_t *number, uint16_t size) { uint8_t cnt = 0; uint16_t sizeCache = size * 3, actualLength = size * 3; //02.02: *2 -> *3 while ((*(number + (sizeCache / 32) - 1)) >> (31 - cnt) != 1) { cnt++; actualLength--; if (cnt == 32) { cnt = 0; sizeCache -= 32; } if (!actualLength) { break; } } return actualLength; } void encryptionArithmetic_clearNumber(uint32_t* number, uint16_t size) { uint16_t numberSize = encryptionArithmetic_numberSize(number, size); uint16_t loopNumberSize = 0; if (numberSize % 32) { loopNumberSize = numberSize - 1; } else { loopNumberSize = numberSize; } for (uint16_t i = 0; i <= loopNumberSize / 32; i++) { *(number + i) = 0; } } /* returns true if first number is larger than the second one */ bool encryptionArithmetic_isLarger(uint32_t* number1, uint32_t* number2, uint16_t size) { uint16_t divisorSize = encryptionArithmetic_numberSize(number2, size); bool isLarger = false; for (int16_t i = (divisorSize / 32); i >= 0; i--) { /* i has to be signed to access 0 */ if (*(number1 + i) > *(number2 + i)) { isLarger = true; } else { isLarger = false; } } return isLarger; } bool encryptionArithmetic_stringToHex(char* src, uint32_t* dest, uint16_t length) { /* holds the amount of characters that are stored in src */ uint16_t stringLength = 0; /* clear destination in order to facilitate iterative use or generally the same pointer */ encryptionArithmetic_clearNumber(dest, length); /* get actual string length without the '\0' character and convert any lowercase characters */ for (stringLength = 0; src[stringLength] != '\0'; ++stringLength) { switch (src[stringLength]) { case 'a': src[stringLength] = 'A'; break; case 'b': src[stringLength] = 'B'; break; case 'c': src[stringLength] = 'C'; break; case 'd': src[stringLength] = 'D'; break; case 'e': src[stringLength] = 'E'; break; case 'f': src[stringLength] = 'F'; break; default: break; } if (src[stringLength] < 48 || (src[stringLength] > 57 && src[stringLength] < 65) || src[stringLength] > 70) { /* 0...9, A...F */ printf("Abort, as input string contains values other than 0-9, A-F\n"); return false; } } if (!stringLength) { /* string is empty */ return false; } if (stringLength * 4 > length) { printf("Abort, as stringLength > maxAllocatedSpace and would result in faulty memory access\n"); return false; } /* store conversion of string in destination while reversing the sequence */ uint16_t imm = stringLength / 8; /* 8*char == 32 bit */ uint8_t cnt; if (!(stringLength % 8)) { imm = stringLength / 8 - 1; } else { imm = stringLength / 8; } cnt = stringLength - (imm * 8) - 1; for (uint16_t cntUp = 0; cntUp < stringLength; cntUp++) { if (src[cntUp] >= 48 && src[cntUp] <= 57) { /* 0...9 */ *(dest + imm) |= (src[cntUp] - 0x30) << (cnt * 4); } else { /* A...F */ *(dest + imm) |= (src[cntUp] - 0x37) << (cnt * 4); } if (cnt == 0) { cnt = 8; imm--; } cnt--; } return true; } void encryptionArithmetic_copyNumber(uint32_t* src, uint32_t* dest, uint16_t length) { encryptionArithmetic_clearNumber(dest, length); uint32_t srcSize = encryptionArithmetic_numberSize(src, length); memmove(dest, src, (srcSize <= 4) ? (1) : (srcSize / 8) + 1); /* size / 8 + 1 = number of bytes including error for int calulation */ //06.02: +1 -> + 0 }