From 5621b579e9238ad619019a75a8f13b2318294a53 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Fri, 22 Sep 2023 20:21:39 -0400 Subject: [PATCH] Update libcotp, and add it as a submodule --- .gitmodules | 3 + external/CMakeLists.txt | 1 - external/libbaseencode/.gitignore | 37 --- external/libbaseencode/CMakeLists.txt | 24 -- external/libbaseencode/LICENSE | 201 -------------- external/libbaseencode/README.md | 41 --- external/libbaseencode/SECURITY.md | 18 -- external/libbaseencode/src/base32.c | 201 -------------- external/libbaseencode/src/base64.c | 174 ------------ external/libbaseencode/src/baseencode.h | 28 -- external/libbaseencode/src/common.h | 50 ---- external/libcotp | 1 + external/libcotp/.gitignore | 36 --- external/libcotp/CMakeLists.txt | 34 --- external/libcotp/LICENSE | 202 -------------- external/libcotp/README.md | 61 ----- external/libcotp/SECURITY.md | 20 -- external/libcotp/cmake/FindGcrypt.cmake | 31 --- external/libcotp/src/cotp.h | 65 ----- external/libcotp/src/otp.c | 335 ------------------------ 20 files changed, 4 insertions(+), 1559 deletions(-) create mode 100644 .gitmodules delete mode 100644 external/libbaseencode/.gitignore delete mode 100644 external/libbaseencode/CMakeLists.txt delete mode 100644 external/libbaseencode/LICENSE delete mode 100644 external/libbaseencode/README.md delete mode 100644 external/libbaseencode/SECURITY.md delete mode 100644 external/libbaseencode/src/base32.c delete mode 100644 external/libbaseencode/src/base64.c delete mode 100644 external/libbaseencode/src/baseencode.h delete mode 100644 external/libbaseencode/src/common.h create mode 160000 external/libcotp delete mode 100644 external/libcotp/.gitignore delete mode 100644 external/libcotp/CMakeLists.txt delete mode 100644 external/libcotp/LICENSE delete mode 100644 external/libcotp/README.md delete mode 100644 external/libcotp/SECURITY.md delete mode 100644 external/libcotp/cmake/FindGcrypt.cmake delete mode 100644 external/libcotp/src/cotp.h delete mode 100644 external/libcotp/src/otp.c diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..0ee555f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "external/libcotp"] + path = external/libcotp + url = https://github.com/paolostivanin/libcotp.git diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 5032e86..e592ad0 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -3,7 +3,6 @@ set(BUILD_SHARED_LIBS OFF) -add_subdirectory(libbaseencode) add_subdirectory(libcotp) find_package(Corrosion REQUIRED) diff --git a/external/libbaseencode/.gitignore b/external/libbaseencode/.gitignore deleted file mode 100644 index e599a98..0000000 --- a/external/libbaseencode/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -.idea/ -cmake-build-debug/ -build/ - -# Object files -*.o -*.ko -*.obj -*.elf - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su diff --git a/external/libbaseencode/CMakeLists.txt b/external/libbaseencode/CMakeLists.txt deleted file mode 100644 index 60f8572..0000000 --- a/external/libbaseencode/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -cmake_minimum_required(VERSION 3.5) -project(baseencode) - -include(GNUInstallDirs) - -# set up versioning. -set(BUILD_MAJOR "1") -set(BUILD_MINOR "0") -set(BUILD_VERSION "14") -set(BUILD_VERSION ${BUILD_MAJOR}.${BUILD_MINOR}.${BUILD_VERSION}) - -set(CMAKE_C_STANDARD 11) - -set(BASEENCODE_HEADERS src/baseencode.h) -set(SOURCE_FILES src/base32.c src/base64.c) - -set(CMAKE_C_FLAGS "-Wall -Werror -fPIC") - -add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) - -target_link_libraries(${PROJECT_NAME} ${PROJECT_LIBS}) -target_include_directories(${PROJECT_NAME} PUBLIC src) - -set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${BUILD_VERSION} SOVERSION ${BUILD_MAJOR}) \ No newline at end of file diff --git a/external/libbaseencode/LICENSE b/external/libbaseencode/LICENSE deleted file mode 100644 index 0e580dd..0000000 --- a/external/libbaseencode/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018 Paolo Stivanin - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/external/libbaseencode/README.md b/external/libbaseencode/README.md deleted file mode 100644 index aa65cb6..0000000 --- a/external/libbaseencode/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# libbaseencode - - Coverity Scan Build Status - - -Library written in C for encoding and decoding data using base32 or base64 according to [RFC-4648](https://tools.ietf.org/html/rfc4648) - -# Requiremens -- GCC or Clang -- CMake - -# Build and Install -``` -$ git clone https://github.com/paolostivanin/libbaseencode.git -$ cd libbaseencode -$ mkdir build && cd $_ -$ cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ../ -$ make -# make install -``` - -# How To Use It -``` -char *b32_encoded = base32_encode(unsigned char *input, size_t input_length, baseencode_error_t *err); - -unsigned char *b32_decoded = base32_decode(char *input, size_t input_length, baseencode_error_t *err); - -char *b64_encoded = base64_encode(unsigned char *input, size_t input_length, baseencode_error_t *err); - -unsigned char *b64_decoded = base64_decode(char *input, size_t input_length, baseencode_error_t *err); -``` -Please note that all the returned value **must be freed** once not needed any more. - -## Errors -In case of errors, `NULL` is returned and `err` is set to either one of: -``` -INVALID_INPUT, EMPTY_STRING, INPUT_TOO_BIG, INVALID_B32_DATA, INVALID_B64_DATA, MEMORY_ALLOCATION, -``` -otherwise, `err` is set to `SUCCESS` - diff --git a/external/libbaseencode/SECURITY.md b/external/libbaseencode/SECURITY.md deleted file mode 100644 index 6439793..0000000 --- a/external/libbaseencode/SECURITY.md +++ /dev/null @@ -1,18 +0,0 @@ -# Security Policy - -## Supported Versions - -The following list describes whether a version is eligible or not for security updates. - -| Version | Supported | EOL | -| ------- | ------------------ |-------------| -| 1.0.x | :heavy_check_mark: | - | - -## Reporting a Vulnerability - -Should you find a vulnerability, please report it privately to me via [e-mail](mailto:paolostivanin@users.noreply.github.com). -The following is the workflow: -- security issue is found, an e-mail is sent to me -- within 24 hours I will reply to your e-mail with some info like, for example, whether it actually is a security issue and how serious it is -- within 7 days I will develop and ship a fix -- once the update is out I will open a [security advisory](https://github.com/paolostivanin/OTPClient/security/advisories) diff --git a/external/libbaseencode/src/base32.c b/external/libbaseencode/src/base32.c deleted file mode 100644 index 096f043..0000000 --- a/external/libbaseencode/src/base32.c +++ /dev/null @@ -1,201 +0,0 @@ -#include -#include -#include -#include -#include "common.h" - - -static int is_valid_b32_input(const char *user_data, size_t data_len); - -static int get_char_index(unsigned char c); - -static const unsigned char b32_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; - - -// The encoding process represents 40-bit groups of input bits as output strings of 8 encoded characters. The input data must be null terminated. -char * -base32_encode(const unsigned char *user_data, size_t data_len, baseencode_error_t *err) -{ - baseencode_error_t error; - check_input(user_data, data_len, MAX_ENCODE_INPUT_LEN, &error); - if (error != SUCCESS) { - *err = error; - if (error == EMPTY_STRING) { - return strdup(""); - } else { - return NULL; - } - } - - size_t user_data_chars = 0, total_bits = 0; - int num_of_equals = 0; - for (int i = 0; i < data_len; i++) { - // As it's not known whether data_len is with or without the +1 for the null byte, a manual check is required. - // Check for null byte only at the end of the user given length, otherwise issue#23 may occur - if (user_data[i] == '\0' && i == data_len-1) { - break; - } else { - total_bits += 8; - user_data_chars += 1; - } - } - switch (total_bits % 40) { - case 8: - num_of_equals = 6; - break; - case 16: - num_of_equals = 4; - break; - case 24: - num_of_equals = 3; - break; - case 32: - num_of_equals = 1; - break; - default: - break; - } - - size_t output_length = (user_data_chars * 8 + 4) / 5; - char *encoded_data = calloc(output_length + num_of_equals + 1, 1); - if (encoded_data == NULL) { - *err = MEMORY_ALLOCATION; - return NULL; - } - - uint64_t first_octet, second_octet, third_octet, fourth_octet, fifth_octet; - uint64_t quintuple; - for (int i = 0, j = 0; i < user_data_chars;) { - first_octet = i < user_data_chars ? user_data[i++] : 0; - second_octet = i < user_data_chars ? user_data[i++] : 0; - third_octet = i < user_data_chars ? user_data[i++] : 0; - fourth_octet = i < user_data_chars ? user_data[i++] : 0; - fifth_octet = i < user_data_chars ? user_data[i++] : 0; - quintuple = - ((first_octet >> 3) << 35) + - ((((first_octet & 0x7) << 2) | (second_octet >> 6)) << 30) + - (((second_octet & 0x3F) >> 1) << 25) + - ((((second_octet & 0x01) << 4) | (third_octet >> 4)) << 20) + - ((((third_octet & 0xF) << 1) | (fourth_octet >> 7)) << 15) + - (((fourth_octet & 0x7F) >> 2) << 10) + - ((((fourth_octet & 0x3) << 3) | (fifth_octet >> 5)) << 5) + - (fifth_octet & 0x1F); - - encoded_data[j++] = b32_alphabet[(quintuple >> 35) & 0x1F]; - encoded_data[j++] = b32_alphabet[(quintuple >> 30) & 0x1F]; - encoded_data[j++] = b32_alphabet[(quintuple >> 25) & 0x1F]; - encoded_data[j++] = b32_alphabet[(quintuple >> 20) & 0x1F]; - encoded_data[j++] = b32_alphabet[(quintuple >> 15) & 0x1F]; - encoded_data[j++] = b32_alphabet[(quintuple >> 10) & 0x1F]; - encoded_data[j++] = b32_alphabet[(quintuple >> 5) & 0x1F]; - encoded_data[j++] = b32_alphabet[(quintuple >> 0) & 0x1F]; - } - - for (int i = 0; i < num_of_equals; i++) { - encoded_data[output_length + i] = '='; - } - encoded_data[output_length + num_of_equals] = '\0'; - - *err = SUCCESS; - return encoded_data; -} - - -unsigned char * -base32_decode(const char *user_data_untrimmed, size_t data_len, baseencode_error_t *err) -{ - baseencode_error_t error; - check_input((unsigned char *)user_data_untrimmed, data_len, MAX_DECODE_BASE32_INPUT_LEN, &error); - if (error != SUCCESS) { - *err = error; - if (error == EMPTY_STRING) { - return (unsigned char *) strdup(""); - } else { - return NULL; - } - } - - char *user_data = strdup(user_data_untrimmed); - data_len -= strip_char(user_data, ' '); - - if (!is_valid_b32_input(user_data, data_len)) { - *err = INVALID_B32_DATA; - free(user_data); - return NULL; - } - - size_t user_data_chars = 0; - for (int i = 0; i < data_len; i++) { - // As it's not known whether data_len is with or without the +1 for the null byte, a manual check is required. - if (user_data[i] != '=' && user_data[i] != '\0') { - user_data_chars += 1; - } - } - - size_t output_length = (size_t) ((user_data_chars + 1.6 + 1) / 1.6); // round up - unsigned char *decoded_data = calloc(output_length + 1, 1); - if (decoded_data == NULL) { - *err = MEMORY_ALLOCATION; - free(user_data); - return NULL; - } - - uint8_t mask = 0, current_byte = 0; - int bits_left = 8; - for (int i = 0, j = 0; i < user_data_chars; i++) { - int char_index = get_char_index((unsigned char)user_data[i]); - if (bits_left > BITS_PER_B32_BLOCK) { - mask = (uint8_t) char_index << (bits_left - BITS_PER_B32_BLOCK); - current_byte = (uint8_t) (current_byte | mask); - bits_left -= BITS_PER_B32_BLOCK; - } else { - mask = (uint8_t) char_index >> (BITS_PER_B32_BLOCK - bits_left); - current_byte = (uint8_t) (current_byte | mask); - decoded_data[j++] = current_byte; - current_byte = (uint8_t) (char_index << (BITS_PER_BYTE - BITS_PER_B32_BLOCK + bits_left)); - bits_left += BITS_PER_BYTE - BITS_PER_B32_BLOCK; - } - } - decoded_data[output_length] = '\0'; - - free(user_data); - - *err = SUCCESS; - return decoded_data; -} - - -static int -is_valid_b32_input(const char *user_data, size_t data_len) -{ - size_t found = 0, b32_alphabet_len = sizeof(b32_alphabet); - for (int i = 0; i < data_len; i++) { - if (user_data[i] == '\0') { - found++; - break; - } - for(int j = 0; j < b32_alphabet_len; j++) { - if(user_data[i] == b32_alphabet[j] || user_data[i] == '=') { - found++; - break; - } - } - } - if (found != data_len) { - return 0; - } else { - return 1; - } -} - - -static int -get_char_index(unsigned char c) -{ - for (int i = 0; i < sizeof(b32_alphabet); i++) { - if (b32_alphabet[i] == c) { - return i; - } - } - return -1; -} diff --git a/external/libbaseencode/src/base64.c b/external/libbaseencode/src/base64.c deleted file mode 100644 index 5b729dd..0000000 --- a/external/libbaseencode/src/base64.c +++ /dev/null @@ -1,174 +0,0 @@ -#include -#include -#include -#include -#include -#include "common.h" - -static int is_valid_b64_input(const char *user_data, size_t data_len); - -static int get_char_index(unsigned char c); - -static const unsigned char b64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - -char * -base64_encode(const unsigned char *user_data, size_t data_len, baseencode_error_t *err) -{ - baseencode_error_t error; - check_input(user_data, data_len, MAX_ENCODE_INPUT_LEN, &error); - if (error != SUCCESS) { - *err = error; - if (error == EMPTY_STRING) { - return strdup(""); - } else { - return NULL; - } - } - - size_t user_data_chars = 0, total_bits = 0; - int num_of_equals = 0; - for (int i = 0; i < data_len; i++) { - // As it's not known whether data_len is with or without the +1 for the null byte, a manual check is required. - if (user_data[i] != '\0') { - total_bits += 8; - user_data_chars += 1; - } else { - break; - } - } - switch (total_bits % 24) { - case 8: - num_of_equals = 2; - break; - case 16: - num_of_equals = 1; - break; - default: - break; - } - - size_t output_length = (user_data_chars * 8 + 4) / 6; - char *encoded_data = calloc(output_length + num_of_equals + 1 + 3, 1); - if (encoded_data == NULL) { - *err = MEMORY_ALLOCATION; - return NULL; - } - - uint8_t first_octet, second_octet, third_octet; - for (int i = 0, j = 0, triple = 0; i < user_data_chars + 1;) { - first_octet = (uint8_t) (i < user_data_chars+1 ? user_data[i++] : 0); - second_octet = (uint8_t) (i < user_data_chars+1 ? user_data[i++] : 0); - third_octet = (uint8_t) (i < user_data_chars+1 ? user_data[i++] : 0); - triple = (first_octet << 0x10) + (second_octet << 0x08) + third_octet; - - encoded_data[j++] = b64_alphabet[(triple >> 0x12) & 0x3F]; - encoded_data[j++] = b64_alphabet[(triple >> 0x0C) & 0x3F]; - encoded_data[j++] = b64_alphabet[(triple >> 0x06) & 0x3F]; - encoded_data[j++] = b64_alphabet[(triple >> 0x00) & 0x3F]; - } - - for (int i = 0; i < num_of_equals; i++) { - encoded_data[output_length + i] = '='; - } - encoded_data[output_length + num_of_equals] = '\0'; - - *err = SUCCESS; - return encoded_data; -} - - -unsigned char * -base64_decode(const char *user_data_untrimmed, size_t data_len, baseencode_error_t *err) -{ - baseencode_error_t error; - check_input((unsigned char *)user_data_untrimmed, data_len, MAX_DECODE_BASE64_INPUT_LEN, &error); - if (error != SUCCESS) { - *err = error; - if (error == EMPTY_STRING) { - return (unsigned char *) strdup(""); - } else { - return NULL; - } - } - - char *user_data = strdup(user_data_untrimmed); - data_len -= strip_char(user_data, ' '); - - if (!is_valid_b64_input(user_data, data_len)) { - *err = INVALID_B64_DATA; - free(user_data); - return NULL; - } - - size_t user_data_chars = 0; - for (int z = 0; z < data_len; z++) { - // As it's not known whether data_len is with or without the +1 for the null byte, a manual check is required. - if (user_data[z] != '=' && user_data[z] != '\0') { - user_data_chars += 1; - } - } - - size_t output_length = data_len / 4 * 3; - unsigned char *decoded_data = calloc(output_length + 1, 1); - if (decoded_data == NULL) { - *err = MEMORY_ALLOCATION; - free(user_data); - return NULL; - } - - uint8_t mask = 0, current_byte = 0; - int bits_left = 8; - for (int i = 0, j = 0; i < user_data_chars; i++) { - int char_index = get_char_index((unsigned char)user_data[i]); - if (bits_left > BITS_PER_B64_BLOCK) { - mask = (uint8_t) char_index << (bits_left - BITS_PER_B64_BLOCK); - current_byte = (uint8_t) (current_byte | mask); - bits_left -= BITS_PER_B64_BLOCK; - } else { - mask = (uint8_t) char_index >> (BITS_PER_B64_BLOCK - bits_left); - current_byte = (uint8_t) (current_byte | mask); - decoded_data[j++] = current_byte; - current_byte = (uint8_t) (char_index << (BITS_PER_BYTE - BITS_PER_B64_BLOCK + bits_left)); - bits_left += BITS_PER_BYTE - BITS_PER_B64_BLOCK; - } - } - decoded_data[output_length] = '\0'; - - free(user_data); - - *err = SUCCESS; - return decoded_data; -} - - -static int -is_valid_b64_input(const char *user_data, size_t data_len) -{ - size_t found = 0, b64_alphabet_len = sizeof(b64_alphabet); - for (int i = 0; i < data_len; i++) { - for(int j = 0; j < b64_alphabet_len; j++) { - if(user_data[i] == b64_alphabet[j] || user_data[i] == '=') { - found++; - break; - } - } - } - if (found != data_len) { - return 0; - } else { - return 1; - } -} - - -static int -get_char_index(unsigned char c) -{ - for (int i = 0; i < sizeof(b64_alphabet); i++) { - if (b64_alphabet[i] == c) { - return i; - } - } - return -1; -} diff --git a/external/libbaseencode/src/baseencode.h b/external/libbaseencode/src/baseencode.h deleted file mode 100644 index 8c86ed1..0000000 --- a/external/libbaseencode/src/baseencode.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -typedef enum _baseencode_errno { - SUCCESS = 0, - INVALID_INPUT = 1, - EMPTY_STRING = 2, - INPUT_TOO_BIG = 3, - INVALID_B32_DATA = 4, - INVALID_B64_DATA = 5, - MEMORY_ALLOCATION = 6, -} baseencode_error_t; - - -char *base32_encode (const unsigned char *user_data, - size_t data_len, - baseencode_error_t *err); - -unsigned char *base32_decode (const char *user_data, - size_t data_len, - baseencode_error_t *err); - -char *base64_encode (const unsigned char *input_string, - size_t input_length, - baseencode_error_t *err); - -unsigned char *base64_decode (const char *input_string, - size_t input_length, - baseencode_error_t *err); \ No newline at end of file diff --git a/external/libbaseencode/src/common.h b/external/libbaseencode/src/common.h deleted file mode 100644 index be716cb..0000000 --- a/external/libbaseencode/src/common.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include "baseencode.h" - -#define BITS_PER_BYTE 8 -#define BITS_PER_B32_BLOCK 5 -#define BITS_PER_B64_BLOCK 6 - -// 64 MB should be more than enough -#define MAX_ENCODE_INPUT_LEN 64*1024*1024 -// if 64 MB of data is encoded than it should be also possible to decode it. That's why a bigger input is allowed for decoding -#define MAX_DECODE_BASE32_INPUT_LEN ((MAX_ENCODE_INPUT_LEN * 8 + 4) / 5) -#define MAX_DECODE_BASE64_INPUT_LEN ((MAX_ENCODE_INPUT_LEN * 8 + 4) / 6) - - -static int -strip_char(char *str, char strip) -{ - int found = 0; - char *p, *q; - for (q = p = str; *p; p++) { - if (*p != strip) { - *q++ = *p; - } else { - found++; - } - } - *q = '\0'; - return found; -} - - -static void -check_input(const unsigned char *user_data, size_t data_len, int max_len, baseencode_error_t *err) -{ - if (user_data == NULL || (data_len == 0 && user_data[0] != '\0')) { - *err = INVALID_INPUT; - return; - } else if (user_data[0] == '\0') { - *err = EMPTY_STRING; - return; - } - - if (data_len > max_len) { - *err = INPUT_TOO_BIG; - return; - } - - *err = SUCCESS; -} \ No newline at end of file diff --git a/external/libcotp b/external/libcotp new file mode 160000 index 0000000..f88829c --- /dev/null +++ b/external/libcotp @@ -0,0 +1 @@ +Subproject commit f88829ca931b040d37a1040f2796c1a5901d2246 diff --git a/external/libcotp/.gitignore b/external/libcotp/.gitignore deleted file mode 100644 index c648f9d..0000000 --- a/external/libcotp/.gitignore +++ /dev/null @@ -1,36 +0,0 @@ -.idea/ -cmake-build-debug/ -build/ - -# Object files -*.o -*.ko -*.obj -*.elf - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ diff --git a/external/libcotp/CMakeLists.txt b/external/libcotp/CMakeLists.txt deleted file mode 100644 index 81d228f..0000000 --- a/external/libcotp/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -cmake_minimum_required(VERSION 3.5) -project(cotp) - -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) - -include(GNUInstallDirs) - -find_package(PkgConfig REQUIRED) -find_package(Gcrypt 1.6.0 REQUIRED) - -include_directories(${GCRYPT_INCLUDE_DIR}) - -link_directories(${GCRYPT_LIBRARY_DIRS}) - -# set up versioning. -set(BUILD_MAJOR "1") -set(BUILD_MINOR "2") -set(BUILD_VERSION "6") -set(BUILD_VERSION ${BUILD_MAJOR}.${BUILD_MINOR}.${BUILD_VERSION}) - -set(CMAKE_C_STANDARD 11) - -set(COTP_HEADERS src/cotp.h) -set(SOURCE_FILES src/otp.c) - -set(CMAKE_C_FLAGS "-Wall -Wextra -O3 -Wno-format-truncation -fstack-protector-strong -fPIC") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3") - -add_library(cotp STATIC ${SOURCE_FILES}) - -target_link_libraries(cotp ${GCRYPT_LIBRARIES} baseencode) -target_include_directories(cotp PUBLIC src) - -set_target_properties(cotp PROPERTIES VERSION ${BUILD_VERSION} SOVERSION ${BUILD_MAJOR}${BUILD_MINOR}) \ No newline at end of file diff --git a/external/libcotp/LICENSE b/external/libcotp/LICENSE deleted file mode 100644 index 1c6a7eb..0000000 --- a/external/libcotp/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018 Paolo Stivanin - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/external/libcotp/README.md b/external/libcotp/README.md deleted file mode 100644 index 24c8ecc..0000000 --- a/external/libcotp/README.md +++ /dev/null @@ -1,61 +0,0 @@ -# libcotp - - Coverity Scan Build Status - - -C library that generates TOTP and HOTP according to [RFC-6238](https://tools.ietf.org/html/rfc6238) - -## Requirements -- [libbaseencode](https://github.com/paolostivanin/libbaseencode) -- GCC/Clang and CMake to build the library -- libgcrypt - -## Build and Install -``` -$ git clone https://github.com/paolostivanin/libcotp.git -$ cd libcotp -$ mkdir build && cd $_ -$ cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ../ # add -DBUILD_TESTING=ON if you want to compile also the tests -$ make -# make install -``` - -## How To Use It -``` -char *totp = get_totp (const char *base32_encoded_secret, int digits, int period, int algo, cotp_error_t *err); -free (totp); - -char *steam_totp = get_steam_totp (const char *secret, int period, cotp_error_t *err) - -char *hotp = get_hotp (const char *base32_encoded_secret, long counter, int digits, int algo, cotp_error_t *err); -free (hotp); - -char *get_totp_at (const char *base32_encoded_secret, long target_date, int digits, int algo, cotp_error_t *err) - -int is_valid = totp_verify (const har *base32_encoded_secret, const char *totp, int digits, int period, int algo, cotp_error_t *err); - -int is_valid = hotp_verify (const char *base32_encoded_secret, long counter, digits, char *hotp, int algo, cotp_error_t *err); -``` - -where: -- `secret_key` is the **base32 encoded** secret. Usually, a website gives you the secret already base32 encoded, so you should pay attention to not encode the secret again. -The format of the secret can either be `hxdm vjec jjws` or `HXDMVJECJJWS`. In the first case, the library will normalize the secret to second format before computing the OTP. -- `digits` is between `3` and `10` inclusive -- `period` is between `1` and `120` inclusive -- `counter` is a value decided with the server -- `target_date` is the target date specified as the unix epoch format in seconds -- `algo` is either `SHA1`, `SHA256` or `SHA512` - -## Errors -`get_totp`, `get_hotp` and `get_totp_at` return `NULL` if an error occurs and `err` is set accordingly. The following errors are currently supported: -- `GCRYPT_VERSION_MISMATCH`, set if the installed Gcrypt library is too old -- `INVALID_B32_INPUT`, set if the given input is not valid base32 text -- `INVALID_ALGO`, set if the given algo is not supported by the library -- `INVALID_PERIOD`, set if `period` is `<= 0` or `> 120` seconds -- `INVALID_DIGITS`, set if `digits` is `< 3` or `> 10` - -`totp_verify` and `hotp_verify` can return, in addition to one of the previous code, also the error `INVALID_OTP` if the given OTP doesn't match the computed one. - -In case of success, the value returned by `get_totp`, `get_hotp` and `get_totp_at` **must be freed** once no longer needed. - diff --git a/external/libcotp/SECURITY.md b/external/libcotp/SECURITY.md deleted file mode 100644 index 9cb1169..0000000 --- a/external/libcotp/SECURITY.md +++ /dev/null @@ -1,20 +0,0 @@ -# Security Policy - -## Supported Versions - -The following list describes whether a version is eligible or not for security updates. - -| Version | Supported | EOL | -| ------- | ------------------ |-------------| -| 1.2.x | :heavy_check_mark: | - | -| 1.1.x | :x: | 31-Dec-2021 | -| 1.0.x | :x: | 31-Dec-2021 | - -## Reporting a Vulnerability - -Should you find a vulnerability, please report it privately to me via [e-mail](mailto:paolostivanin@users.noreply.github.com). -The following is the workflow: -- security issue is found, an e-mail is sent to me -- within 24 hours I will reply to your e-mail with some info like, for example, whether it actually is a security issue and how serious it is -- within 7 days I will develop and ship a fix -- once the update is out I will open a [security advisory](https://github.com/paolostivanin/OTPClient/security/advisories) diff --git a/external/libcotp/cmake/FindGcrypt.cmake b/external/libcotp/cmake/FindGcrypt.cmake deleted file mode 100644 index 0775704..0000000 --- a/external/libcotp/cmake/FindGcrypt.cmake +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (C) 2011 Felix Geyer -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 or (at your option) -# version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -find_path(GCRYPT_INCLUDE_DIR gcrypt.h) - -find_library(GCRYPT_LIBRARIES gcrypt) - -mark_as_advanced(GCRYPT_LIBRARIES GCRYPT_INCLUDE_DIR) - -if(GCRYPT_INCLUDE_DIR AND EXISTS "${GCRYPT_INCLUDE_DIR}/gcrypt.h") - file(STRINGS "${GCRYPT_INCLUDE_DIR}/gcrypt.h" GCRYPT_H REGEX "^#define GCRYPT_VERSION \"[^\"]*\"$") - string(REGEX REPLACE "^.*GCRYPT_VERSION \"([0-9]+).*$" "\\1" GCRYPT_VERSION_MAJOR "${GCRYPT_H}") - string(REGEX REPLACE "^.*GCRYPT_VERSION \"[0-9]+\\.([0-9]+).*$" "\\1" GCRYPT_VERSION_MINOR "${GCRYPT_H}") - string(REGEX REPLACE "^.*GCRYPT_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" GCRYPT_VERSION_PATCH "${GCRYPT_H}") - set(GCRYPT_VERSION_STRING "${GCRYPT_VERSION_MAJOR}.${GCRYPT_VERSION_MINOR}.${GCRYPT_VERSION_PATCH}") -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Gcrypt DEFAULT_MSG GCRYPT_LIBRARIES GCRYPT_INCLUDE_DIR) diff --git a/external/libcotp/src/cotp.h b/external/libcotp/src/cotp.h deleted file mode 100644 index 47e6238..0000000 --- a/external/libcotp/src/cotp.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once -#include - -#define SHA1 GCRY_MD_SHA1 -#define SHA256 GCRY_MD_SHA256 -#define SHA512 GCRY_MD_SHA512 - -typedef enum _cotp_errno { - VALID = 0, - GCRYPT_VERSION_MISMATCH = 1, - INVALID_B32_INPUT = 2, - INVALID_ALGO = 3, - INVALID_OTP = 4, - INVALID_DIGITS = 5, - INVALID_PERIOD = 6 -} cotp_error_t; - -#ifdef __cplusplus -extern "C" { -#endif -char *get_hotp (const char *base32_encoded_secret, - long counter, - int digits, - int sha_algo, - cotp_error_t *err_code); - -char *get_totp (const char *base32_encoded_secret, - int digits, - int period, - int sha_algo, - cotp_error_t *err_code); - -char *get_steam_totp (const char *base32_encoded_secret, - int period, - cotp_error_t *err_code); - - -char *get_totp_at (const char *base32_encoded_secret, - long time, - int digits, - int period, - int sha_algo, - cotp_error_t *err_code); - -char *get_steam_totp_at (const char *base32_encoded_secret, - long timestamp, - int period, - cotp_error_t *err_code); - -int totp_verify (const char *base32_encoded_secret, - const char *user_totp, - int digits, - int period, - int sha_algo); - -int hotp_verify (const char *base32_encoded_secret, - long counter, - int digits, - const char *user_hotp, - int sha_algo); - - -#ifdef __cplusplus -} -#endif diff --git a/external/libcotp/src/otp.c b/external/libcotp/src/otp.c deleted file mode 100644 index 22ce63f..0000000 --- a/external/libcotp/src/otp.c +++ /dev/null @@ -1,335 +0,0 @@ -#include -#include -#include -#include -#include -#include "cotp.h" - -#define SHA1_DIGEST_SIZE 20 -#define SHA256_DIGEST_SIZE 32 -#define SHA512_DIGEST_SIZE 64 - -static long long int DIGITS_POWER[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000}; - - -static int -check_gcrypt() -{ - if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) { - if (!gcry_check_version("1.6.0")) { - fprintf(stderr, "libgcrypt v1.6.0 and above is required\n"); - return -1; - } - gcry_control(GCRYCTL_DISABLE_SECMEM, 0); - gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); - } - return 0; -} - - -static char * -normalize_secret (const char *K) -{ - char *nK = calloc (1, strlen (K) + 1); - if (nK == NULL) { - fprintf (stderr, "Error during memory allocation\n"); - return nK; - } - - int i = 0, j = 0; - while (K[i] != '\0') { - if (K[i] != ' ') { - if (K[i] >= 'a' && K[i] <= 'z') { - nK[j++] = (char) (K[i] - 32); - } else { - nK[j++] = K[i]; - } - } - i++; - } - return nK; -} - - -static char * -get_steam_code(unsigned const char *hmac) -{ - int offset = (hmac[SHA1_DIGEST_SIZE-1] & 0x0f); - - // Starting from the offset, take the successive 4 bytes while stripping the topmost bit to prevent it being handled as a signed integer - int bin_code = ((hmac[offset] & 0x7f) << 24) | ((hmac[offset + 1] & 0xff) << 16) | ((hmac[offset + 2] & 0xff) << 8) | ((hmac[offset + 3] & 0xff)); - - const char steam_alphabet[] = "23456789BCDFGHJKMNPQRTVWXY"; - - char code[6]; - size_t steam_alphabet_len = strlen(steam_alphabet); - for (int i = 0; i < 5; i++) { - int mod = bin_code % steam_alphabet_len; - bin_code = bin_code / steam_alphabet_len; - code[i] = steam_alphabet[mod]; - } - code[5] = '\0'; - - return strdup(code); -} - - -static int -truncate(unsigned const char *hmac, int digits_length, int algo) -{ - // take the lower four bits of the last byte - int offset = 0; - switch (algo) { - case SHA1: - offset = (hmac[SHA1_DIGEST_SIZE-1] & 0x0f); - break; - case SHA256: - offset = (hmac[SHA256_DIGEST_SIZE-1] & 0x0f); - break; - case SHA512: - offset = (hmac[SHA512_DIGEST_SIZE-1] & 0x0f); - break; - default: - break; - } - - // Starting from the offset, take the successive 4 bytes while stripping the topmost bit to prevent it being handled as a signed integer - int bin_code = ((hmac[offset] & 0x7f) << 24) | ((hmac[offset + 1] & 0xff) << 16) | ((hmac[offset + 2] & 0xff) << 8) | ((hmac[offset + 3] & 0xff)); - - int token = bin_code % DIGITS_POWER[digits_length]; - - return token; -} - - -static unsigned char * -compute_hmac(const char *K, long C, int algo) -{ - baseencode_error_t err; - size_t secret_len = (size_t) ((strlen(K) + 1.6 - 1) / 1.6); - - char *normalized_K = normalize_secret (K); - if (normalized_K == NULL) { - return NULL; - } - unsigned char *secret = base32_decode(normalized_K, strlen(normalized_K), &err); - free (normalized_K); - if (secret == NULL) { - return NULL; - } - - unsigned char C_reverse_byte_order[8]; - int j, i; - for (j = 0, i = 7; j < 8 && i >= 0; j++, i--) - C_reverse_byte_order[i] = ((unsigned char *) &C)[j]; - - gcry_md_hd_t hd; - gcry_md_open(&hd, algo, GCRY_MD_FLAG_HMAC); - gcry_md_setkey(hd, secret, secret_len); - gcry_md_write(hd, C_reverse_byte_order, sizeof(C_reverse_byte_order)); - gcry_md_final (hd); - unsigned char *hmac = gcry_md_read(hd, algo); - - free(secret); - - return hmac; -} - - -static char * -finalize(int digits_length, int tk) -{ - char *token = malloc((size_t)digits_length + 1); - if (token == NULL) { - fprintf (stderr, "Error during memory allocation\n"); - return token; - } else { - int extra_char = digits_length < 10 ? 0 : 1; - char *fmt = calloc(1, 5 + extra_char); - if (fmt == NULL) { - fprintf (stderr, "Error during memory allocation\n"); - free (token); - return fmt; - } - memcpy (fmt, "%.", 3); - snprintf (fmt + 2, 2 + extra_char, "%d", digits_length); - memcpy (fmt + 3 + extra_char, "d", 2); - snprintf (token, digits_length + 1, fmt, tk); - free (fmt); - } - return token; -} - - -static int -check_period(int period) -{ - if (period <= 0 || period > 120) { - return INVALID_PERIOD; - } - return VALID; -} - - -static int -check_otp_len(int digits_length) -{ - if (digits_length < 3 || digits_length > 10) { - return INVALID_DIGITS; - } - return VALID; -} - - -static int -check_algo(int algo) -{ - if (algo != SHA1 && algo != SHA256 && algo != SHA512) { - return INVALID_ALGO; - } else { - return VALID; - } -} - - -char * -get_hotp(const char *secret, long timestamp, int digits, int algo, cotp_error_t *err_code) -{ - if (check_gcrypt() == -1) { - *err_code = GCRYPT_VERSION_MISMATCH; - return NULL; - } - - if (check_algo(algo) == INVALID_ALGO) { - *err_code = INVALID_ALGO; - return NULL; - } - - if (check_otp_len(digits) == INVALID_DIGITS) { - *err_code = INVALID_DIGITS; - return NULL; - } - - unsigned char *hmac = compute_hmac(secret, timestamp, algo); - if (hmac == NULL) { - *err_code = INVALID_B32_INPUT; - return NULL; - } - int tk = truncate(hmac, digits, algo); - char *token = finalize(digits, tk); - return token; -} - - -char * -get_totp(const char *secret, int digits, int period, int algo, cotp_error_t *err_code) -{ - return get_totp_at(secret, (long)time(NULL), digits, period, algo, err_code); -} - - -char * -get_steam_totp (const char *secret, int period, cotp_error_t *err_code) -{ - // AFAIK, the secret is stored base64 encoded on the device. As I don't have time to waste on reverse engineering - // this non-standard solution, the user is responsible for decoding the secret in whatever format this is and then - // providing the library with the secret base32 encoded. - return get_steam_totp_at (secret, (long)time(NULL), period, err_code); -} - - -char * -get_totp_at(const char *secret, long current_timestamp, int digits, int period, int algo, cotp_error_t *err_code) -{ - if (check_gcrypt() == -1) { - *err_code = GCRYPT_VERSION_MISMATCH; - return NULL; - } - - if (check_otp_len(digits) == INVALID_DIGITS) { - *err_code = INVALID_DIGITS; - return NULL; - } - - if (check_period(period) == INVALID_PERIOD) { - *err_code = INVALID_PERIOD; - return NULL; - } - - long timestamp = current_timestamp / period; - - cotp_error_t err; - char *token = get_hotp(secret, timestamp, digits, algo, &err); - if (token == NULL) { - *err_code = err; - return NULL; - } - return token; -} - - -char * -get_steam_totp_at (const char *secret, long current_timestamp, int period, cotp_error_t *err_code) -{ - if (check_gcrypt() == -1) { - *err_code = GCRYPT_VERSION_MISMATCH; - return NULL; - } - - if (check_period(period) == INVALID_PERIOD) { - *err_code = INVALID_PERIOD; - return NULL; - } - - long timestamp = current_timestamp / period; - - unsigned char *hmac = compute_hmac(secret, timestamp, SHA1); - if (hmac == NULL) { - *err_code = INVALID_B32_INPUT; - return NULL; - } - - return get_steam_code(hmac); -} - - -int -totp_verify(const char *secret, const char *user_totp, int digits, int period, int algo) -{ - cotp_error_t err; - char *current_totp = get_totp(secret, digits, period, algo, &err); - if (current_totp == NULL) { - return err; - } - - int token_status; - if (strcmp(current_totp, user_totp) != 0) { - token_status = INVALID_OTP; - } else { - token_status = VALID; - } - free(current_totp); - - return token_status; -} - - -int -hotp_verify(const char *K, long C, int N, const char *user_hotp, int algo) -{ - cotp_error_t err; - char *current_hotp = get_hotp(K, C, N, algo, &err); - if (current_hotp == NULL) { - return err; - } - - int token_status; - if (strcmp(current_hotp, user_hotp) != 0) { - token_status = INVALID_OTP; - } else { - token_status = VALID; - } - free(current_hotp); - - return token_status; -}