diff --git a/Inc/crypto/vernam_cipher.h b/Inc/crypto/vernam_cipher.h new file mode 100644 index 0000000..828f47c --- /dev/null +++ b/Inc/crypto/vernam_cipher.h @@ -0,0 +1,62 @@ +/**************************************************************************** + * + * Copyright (c) 2024 IMProject Development Team. All rights reserved. + * Authors: Juraj Ciberlin + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name IMProject nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef VERNAM_CIPHER_H_ +#define VERNAM_CIPHER_H_ + +#include "typedefs.h" + +/** + * @brief Encryption using Vernam cipher/One Time Pad algorithm. + * + * @param[in/out] *msg Pointer to message that will be encrypted. + * @param[in] *key Pointer to key string. + * @param[in] key_length Key length. + * + * @return Status of encryption function. True if message size is higher than or equal to key length, otherwise false. + */ +bool VernamCipher_encrypt(char* msg, const char* key, int32_t key_length); + +/** + * @brief Decryption using Vernam cipher/One Time Pad algorithm. + * + * @param[in/out] *msg Pointer to message that will be decrypted. + * @param[in] *key Pointer to key string. + * @param[in] key_length Key length. + * + * @return Status of decryption function. True if message size is higher than or equal to key length, otherwise false. + */ +bool VernamCipher_decrypt(char* msg, const char* key, int32_t key_length); + +#endif /* VERNAM_CIPHER_H_ */ diff --git a/Makefile b/Makefile index dd861d9..76d9dea 100644 --- a/Makefile +++ b/Makefile @@ -107,6 +107,7 @@ IMUTILITY_FILES=\ Src/crc/crc32_variants/crc32_xfer.c \ Src/crypto/caesar_cipher.c \ Src/crypto/chacha20.c \ + Src/crypto/vernam_cipher.c \ Src/sort/bubble_sort.c \ Src/sort/heap_sort.c \ Src/sort/insertion_sort.c \ @@ -139,7 +140,8 @@ SRC_FILES+=$(IMUTILITY_FILES) \ Tests/test_queue.c \ Tests/test_scheduler.c \ Tests/test_selection_sort.c \ - Tests/test_utils.c + Tests/test_utils.c \ + Tests/test_vernam_cipher.c INC_DIRS_CODE= \ -IInc \ diff --git a/README.md b/README.md index 205195f..a67d612 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,8 @@ Join us on the Discord channel https://discord.gg/R6nZxZqDH3 - CaesarCipher_encrypt - CaesarCipher_decrypt - Chacha20_crypt +- VernamCipher_encrypt +- VernamCipher_decrypt ### JSON - Json_startString diff --git a/Src/crypto/vernam_cipher.c b/Src/crypto/vernam_cipher.c new file mode 100644 index 0000000..5137c8e --- /dev/null +++ b/Src/crypto/vernam_cipher.c @@ -0,0 +1,105 @@ +/**************************************************************************** + * + * Copyright (c) 2024 IMProject Development Team. All rights reserved. + * Authors: Juraj Ciberlin + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name IMProject nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include "vernam_cipher.h" + +#include + +#include "utils.h" + +#define UPPER_A_ASCII (65) +#define LOWER_A_ASCII (97) +#define NUM_OF_ALPHA (26) + +bool +VernamCipher_encrypt(char* msg, const char* key, int32_t key_length) { + bool status = false; + const size_t msg_length = strlen(msg); + if ((int32_t)msg_length == key_length) { + for (int32_t i = 0; i < key_length; ++i) { + if (Utils_isAlpha(msg[i])) { + int8_t c; + if (Utils_isLowerChar(key[i])) { + c = LOWER_A_ASCII; + } else { + c = UPPER_A_ASCII; + } + + int32_t ascii_val; + if (Utils_isUpperChar(msg[i])) { + ascii_val = UPPER_A_ASCII; + } else { + ascii_val = LOWER_A_ASCII; + } + + int32_t temp = (((int8_t)msg[i] - ascii_val + (int8_t)key[i] - c) % NUM_OF_ALPHA); + int32_t cipher = temp + ascii_val; + msg[i] = (char)cipher; + } + } + status = true; + } + return status; +} + +bool +VernamCipher_decrypt(char* msg, const char* key, int32_t key_length) { + bool status = false; + const size_t msg_length = strlen(msg); + if ((int32_t)msg_length == key_length) { + for (int32_t i = 0; i < key_length; ++i) { + if (Utils_isAlpha(msg[i])) { + int8_t c; + if (Utils_isLowerChar(key[i])) { + c = LOWER_A_ASCII; + } else { + c = UPPER_A_ASCII; + } + + int32_t ascii_val; + if (Utils_isUpperChar(msg[i])) { + ascii_val = UPPER_A_ASCII; + } else { + ascii_val = LOWER_A_ASCII; + } + + int32_t cipher = ((msg[i] - ascii_val) - (key[i] - c)); + cipher = (cipher < 0) ? (cipher + NUM_OF_ALPHA + ascii_val) : (cipher + ascii_val); + msg[i] = (char)cipher; + } + } + status = true; + } + return status; +} diff --git a/Tests/test_main.c b/Tests/test_main.c index dcebf44..69065f4 100644 --- a/Tests/test_main.c +++ b/Tests/test_main.c @@ -20,6 +20,7 @@ RunAllTests(void) { RUN_TEST_GROUP(Scheduler); RUN_TEST_GROUP(SelectionSort); RUN_TEST_GROUP(Utils); + RUN_TEST_GROUP(VernamCipher); } int diff --git a/Tests/test_vernam_cipher.c b/Tests/test_vernam_cipher.c new file mode 100644 index 0000000..139adee --- /dev/null +++ b/Tests/test_vernam_cipher.c @@ -0,0 +1,35 @@ +#include "vernam_cipher.h" + +#include + +#include "unity.h" +#include "unity_fixture.h" + +TEST_GROUP(VernamCipher); + +TEST_SETUP(VernamCipher) { +} + +TEST_TEAR_DOWN(VernamCipher) { +} + +TEST_GROUP_RUNNER(VernamCipher) { + RUN_TEST_CASE(VernamCipher, VernamCipher_encryptDecrypt); +} + +TEST(VernamCipher, VernamCipher_encryptDecrypt) { + const char expected_result[] = "ReSuLt1a"; + const char key1[] = "OSIJEK11"; + const char key2[] = "OSijek!/"; + char message[] = "ReSuLt1a"; + TEST_ASSERT_TRUE(VernamCipher_encrypt(message, key1, (int32_t)strlen(key1))); + TEST_ASSERT_TRUE(VernamCipher_decrypt(message, key1, (int32_t)strlen(key1))); + TEST_ASSERT_EQUAL_STRING(expected_result, message); + + TEST_ASSERT_TRUE(VernamCipher_encrypt(message, key2, (int32_t)strlen(key2))); + TEST_ASSERT_TRUE(VernamCipher_decrypt(message, key2, (int32_t)strlen(key2))); + TEST_ASSERT_EQUAL_STRING(expected_result, message); + + TEST_ASSERT_FALSE(VernamCipher_encrypt(message, key1, 3)); + TEST_ASSERT_FALSE(VernamCipher_decrypt(message, key1, 100)); +}