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
-
-
-
-
-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
-
-
-
-
-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;
-}