mirror of
https://github.com/Hizenberg469/OTP-rfc4226-rfc6238-rfc4648.git
synced 2026-04-19 18:02:23 +03:00
Working model finished
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
*vsidx
|
||||||
|
*.opendb
|
||||||
|
.vs
|
||||||
|
out
|
||||||
|
CMakePresets.json
|
||||||
136
CMakeLists.txt
Normal file
136
CMakeLists.txt
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
# CMakeList.txt : CMake project for HOTP, include source and define
|
||||||
|
# project specific logic here.
|
||||||
|
#
|
||||||
|
cmake_minimum_required (VERSION 3.8)
|
||||||
|
|
||||||
|
project(HOTP VERSION 1.0.0 LANGUAGES C CXX)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 17)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_C_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
set(OTP_LIBRARY otp_lib)
|
||||||
|
|
||||||
|
set(OTP_EXE genotp)
|
||||||
|
|
||||||
|
|
||||||
|
set(HEADER_DIR "${CMAKE_SOURCE_DIR}/include")
|
||||||
|
set(EXTERNAL_DIR "${CMAKE_SOURCE_DIR}/external")
|
||||||
|
set(SOURCE_DIR "${CMAKE_SOURCE_DIR}/src")
|
||||||
|
|
||||||
|
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
|
||||||
|
include(AddGitSubmodule)
|
||||||
|
|
||||||
|
add_git_submodule(external openssl https://github.com/openssl/openssl.git)
|
||||||
|
|
||||||
|
set(OPENSSL_PATH "${EXTERNAL_DIR}/openssl")
|
||||||
|
|
||||||
|
if (NOT EXISTS "${OPENSSL_PATH}/CMakeLists.txt")
|
||||||
|
|
||||||
|
include(ExternalProject)
|
||||||
|
|
||||||
|
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||||
|
|
||||||
|
# Add the directory containing Perl to the CMAKE_PREFIX_PATH variable
|
||||||
|
list(APPEND CMAKE_PREFIX_PATH "E://Strawberry_Perl//perl//bin")
|
||||||
|
find_package(Perl)
|
||||||
|
|
||||||
|
if(${PERL_FOUND})
|
||||||
|
message(STATUS "Found perl: ${PERL_EXECUTABLE}")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Perl executable not found.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CONFIGURE_COMMAND ${PERL_EXECUTABLE} Configure --prefix=${OPENSSL_PATH}/build --openssldir=${OPENSSL_PATH}/build/ssl )
|
||||||
|
|
||||||
|
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
set(CONFIGURE_COMMAND ./Configure --prefix=${OPENSSL_PATH}/build --openssldir=${OPENSSL_PATH}/build/ssl )
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_program(MAKE_EXE NAMES nmake make)
|
||||||
|
|
||||||
|
if(MAKE_EXE)
|
||||||
|
message(STATUS "Found platform specific make executable: ${MAKE_EXE}")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "nmake not found. Please make sure it is installed.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
if(NOT EXISTS "${OPENSSL_PATH}/build")
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CONFIGURE_COMMAND}
|
||||||
|
WORKING_DIRECTORY ${OPENSSL_PATH}
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if(result)
|
||||||
|
message(FATAL_ERROR "Configuration Command failed.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${MAKE_EXE}
|
||||||
|
WORKING_DIRECTORY ${OPENSSL_PATH}
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
)
|
||||||
|
|
||||||
|
if(result)
|
||||||
|
message(FATAL_ERROR "make Command failed.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(MAKE_EXE_INSTALL ${MAKE_EXE} install)
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${MAKE_EXE_INSTALL}
|
||||||
|
WORKING_DIRECTORY ${OPENSSL_PATH}
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
)
|
||||||
|
|
||||||
|
if(result)
|
||||||
|
message(FATAL_ERROR "make install Command failed.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#This will be executed during build time not CMake Time.
|
||||||
|
#ExternalProject_Add(
|
||||||
|
# OpenSSL_deps
|
||||||
|
# PREFIX ${CMAKE_BINARY_DIR}/external
|
||||||
|
# DOWNLOAD_COMMAND "" # No download command since we're not downloading, assuming Makefile is already present
|
||||||
|
# SOURCE_DIR ${OPENSSL_PATH} # Specify the path to the directory containing the Makefile
|
||||||
|
# BINARY_DIR ${OPENSSL_PATH}/lib #All the build file will be present here, if BUILD_IN_SOURCE is not set.
|
||||||
|
# CONFIGURE_COMMAND ${CONFIGURE_COMMAND} # No configure command needed for Makefile-based projects
|
||||||
|
# BUILD_COMMAND ${MAKE_EXE} # Command to build the project using make
|
||||||
|
# INSTALL_COMMAND "" # No install command needed for Makefile-based projects
|
||||||
|
# BUILD_IN_SOURCE 0 # Build the project in the source directory
|
||||||
|
#)
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
set(OPENSSL_USE_STATIC_LIBS TRUE)
|
||||||
|
find_package(OpenSSL PATHS ${OPENSSL_PATH})
|
||||||
|
|
||||||
|
if( OPENSSL_FOUND )
|
||||||
|
message(STATUS "OpenSSL found: ${OPENSSL_INCLUDE_DIR}")
|
||||||
|
message(STATUS "OpenSSL found: ${OPENSSL_CRYPTO_LIBRARY}")
|
||||||
|
message(STATUS "OpenSSL found: ${OPENSSL_SSL_LIBRARY}")
|
||||||
|
message(STATUS "OpenSSL found: ${OPENSSL_LIBRARIES}")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "OpenSSL not found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(OPENSSL_LIB
|
||||||
|
${OPENSSL_CRYPTO_LIBRARY}
|
||||||
|
${OPENSSL_SSL_LIBRARY}
|
||||||
|
${OPENSSL_LIBRARIES})
|
||||||
|
|
||||||
|
set(OPENSSL_HEADER
|
||||||
|
${OPENSSL_INCLUDE_DIR})
|
||||||
|
|
||||||
|
add_subdirectory(src)
|
||||||
|
add_subdirectory(app)
|
||||||
|
|
||||||
|
# TODO: Add tests and install targets if needed.
|
||||||
8
app/CMakeLists.txt
Normal file
8
app/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
add_executable(${OTP_EXE}
|
||||||
|
"main.c")
|
||||||
|
|
||||||
|
target_include_directories(${OTP_EXE} PUBLIC
|
||||||
|
${HEADER_DIRS})
|
||||||
|
|
||||||
|
target_link_libraries(${OTP_EXE} PUBLIC
|
||||||
|
${OTP_LIBRARY})
|
||||||
217
app/main.c
Normal file
217
app/main.c
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "rfc6238.h"
|
||||||
|
|
||||||
|
#define T0 0
|
||||||
|
#define DIGITS 6
|
||||||
|
#define VALIDITY 30
|
||||||
|
#define TIME 2
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************Code Taken from elsewhere********************************/
|
||||||
|
|
||||||
|
char b32_decode_char(char c);
|
||||||
|
void b32_decode(char** dst, size_t* dstlen, const char* src, size_t srclen);
|
||||||
|
|
||||||
|
void b32_decode(char** dst, size_t* dstlen, const char* src, size_t srclen)
|
||||||
|
{
|
||||||
|
size_t padlen = 0; // Number of ='s in padding
|
||||||
|
size_t lastlen = 0; // Length of last quantum in characters
|
||||||
|
|
||||||
|
*dst = NULL;
|
||||||
|
*dstlen = 0;
|
||||||
|
|
||||||
|
// Check padding
|
||||||
|
for (size_t i = 1; i < srclen; i++)
|
||||||
|
{
|
||||||
|
if (src[srclen - i] == '=')
|
||||||
|
padlen++;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check source material
|
||||||
|
for (size_t i = 0; i < srclen - padlen; i++)
|
||||||
|
{
|
||||||
|
if (b32_decode_char(src[i]) > 0x1F)
|
||||||
|
{
|
||||||
|
// ERROR: one or more characters cannot be decoded
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the length of the last quantum in src
|
||||||
|
lastlen = (srclen - padlen) % 8;
|
||||||
|
|
||||||
|
// How many quantums do we have?
|
||||||
|
size_t qmax = (srclen - padlen) / 8;
|
||||||
|
|
||||||
|
if (lastlen > 0)
|
||||||
|
{
|
||||||
|
// Last quantum is a partial quantum
|
||||||
|
// ... qmax rounded down
|
||||||
|
qmax += 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Last quantum is a full quantum
|
||||||
|
// ... length of last quantum is 8, not 0
|
||||||
|
lastlen = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate dst buffer size
|
||||||
|
*dstlen = ((srclen - padlen) / 8) * 5;
|
||||||
|
|
||||||
|
switch (lastlen)
|
||||||
|
{
|
||||||
|
case 8:
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
*dstlen += 4;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
*dstlen += 3;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*dstlen += 2;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*dstlen += 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// ERROR: Not a multiple of a byte.
|
||||||
|
*dstlen = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dstlen == 0)
|
||||||
|
{
|
||||||
|
// Either empty src, or an error occurred
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate dst buffer
|
||||||
|
*dst = (char*)malloc(sizeof(char) * (*dstlen));
|
||||||
|
|
||||||
|
// Loop variables
|
||||||
|
size_t qlen;
|
||||||
|
char* pdst = *dst;
|
||||||
|
const char* psrc = src;
|
||||||
|
|
||||||
|
// Decode each quantum
|
||||||
|
for (size_t q = 0; q < qmax; q++)
|
||||||
|
{
|
||||||
|
// Are we on the last quantum?
|
||||||
|
if (q == qmax - 1)
|
||||||
|
qlen = lastlen;
|
||||||
|
else
|
||||||
|
qlen = 8;
|
||||||
|
|
||||||
|
// dst 0 1 2 3 4
|
||||||
|
// [11111 111][11 11111 1][1111 1111][1 11111 11][111 11111]
|
||||||
|
// src 0 1 2 3 4 5 6 7
|
||||||
|
|
||||||
|
switch (qlen)
|
||||||
|
{
|
||||||
|
// 8 = 5 bytes in quantum
|
||||||
|
case 8:
|
||||||
|
pdst[4] = b32_decode_char(psrc[7]);
|
||||||
|
pdst[4] |= b32_decode_char(psrc[6]) << 5;
|
||||||
|
// 7 = 4 bytes in quantum
|
||||||
|
case 7:
|
||||||
|
pdst[3] = b32_decode_char(psrc[6]) >> 3;
|
||||||
|
pdst[3] |= (b32_decode_char(psrc[5]) & 0x1F) << 2;
|
||||||
|
pdst[3] |= b32_decode_char(psrc[4]) << 7;
|
||||||
|
// 5 = 3 bytes in quantum
|
||||||
|
case 5:
|
||||||
|
pdst[2] = b32_decode_char(psrc[4]) >> 1;
|
||||||
|
pdst[2] |= b32_decode_char(psrc[3]) << 4;
|
||||||
|
// 4 = 2 bytes in quantum
|
||||||
|
case 4:
|
||||||
|
pdst[1] = b32_decode_char(psrc[3]) >> 4;
|
||||||
|
pdst[1] |= (b32_decode_char(psrc[2]) & 0x1F) << 1;
|
||||||
|
pdst[1] |= b32_decode_char(psrc[1]) << 6;
|
||||||
|
// 2 = 1 byte in quantum
|
||||||
|
case 2:
|
||||||
|
pdst[0] = b32_decode_char(psrc[1]) >> 2;
|
||||||
|
pdst[0] |= b32_decode_char(psrc[0]) << 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break; // TODO error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move quantum pointers forward
|
||||||
|
psrc += 8;
|
||||||
|
pdst += 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char b32_decode_char(char c)
|
||||||
|
{
|
||||||
|
if (c >= 'A' && c <= 'Z')
|
||||||
|
return c - 'A';
|
||||||
|
else if (c >= '2' && c <= '7')
|
||||||
|
return c - '2' + 26;
|
||||||
|
// ... handle lowercase here???
|
||||||
|
else if (c >= 'a' && c <= 'z')
|
||||||
|
return c - 'a';
|
||||||
|
else
|
||||||
|
return 0xFF; // ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************Code Taken from elsewhere********************************/
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
|
|
||||||
|
char key[50];
|
||||||
|
char* k;
|
||||||
|
char* decodeKey;
|
||||||
|
size_t sz_dKey;
|
||||||
|
uint32_t result;
|
||||||
|
|
||||||
|
if (argc <= 1) {
|
||||||
|
printf("Please provide your secret key!!!!!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int sz_key = strlen(argv[1]);
|
||||||
|
|
||||||
|
if (sz_key > 50) {
|
||||||
|
printf("base-32 secret key cannot be more than 50 characters.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//validate the key...
|
||||||
|
for (int i = 0; i < sz_key; i++) {
|
||||||
|
|
||||||
|
if ((argv[1][i] < 'A' && argv[1][i] > 'Z') ||
|
||||||
|
(argv[1][i] < '2' && argv[1][i] > '9') ||
|
||||||
|
(argv[1][i] == '=')) {
|
||||||
|
|
||||||
|
printf("Invalid base-32 encoded key.\nPlease enter correct base-32 encoded key.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
strncpy(key, argv[1], sz_key);
|
||||||
|
|
||||||
|
|
||||||
|
k = key;
|
||||||
|
|
||||||
|
|
||||||
|
b32_decode(&decodeKey, &sz_dKey, k, (size_t)sz_key);
|
||||||
|
|
||||||
|
time_t t = floor((time(NULL) - T0) / VALIDITY);
|
||||||
|
|
||||||
|
result = TOTP((uint8_t*)decodeKey, sz_dKey, (uint64_t)t, DIGITS);
|
||||||
|
|
||||||
|
printf("The resulting OTP value is : %06u\n", result);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
39
cmake/AddGitSubmodule.cmake
Normal file
39
cmake/AddGitSubmodule.cmake
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
function(add_git_submodule relative_dir lib link)
|
||||||
|
find_package(Git REQUIRED)
|
||||||
|
|
||||||
|
set(FULL_DIR ${CMAKE_SOURCE_DIR}/${relative_dir})
|
||||||
|
|
||||||
|
#For intializing git if not already initialized.
|
||||||
|
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||||
|
# If .git directory does not exist, execute git init
|
||||||
|
execute_process(
|
||||||
|
COMMAND git init
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
)
|
||||||
|
|
||||||
|
if(result)
|
||||||
|
message(FATAL_ERROR "Failed to initialize git repository.")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#For adding the external deps if not added yet
|
||||||
|
if (NOT EXISTS ${FULL_DIR}/${lib})
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE}
|
||||||
|
submodule add -- ${link}
|
||||||
|
WORKING_DIRECTORY ${FULL_DIR}
|
||||||
|
)
|
||||||
|
elseif (NOT EXISTS ${FULL_DIR}/CMakeLists.txt)
|
||||||
|
execute_process(COMMAND ${GIT_EXECUTABLE}
|
||||||
|
submodule update --init -- ${relative_dir}
|
||||||
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (EXISTS ${FULL_DIR}/CMakeLists.txt)
|
||||||
|
message("Submodule is CMake Project: ${FULL_DIR}/CMakeLists.txt")
|
||||||
|
add_subdirectory(${FULL_DIR})
|
||||||
|
else()
|
||||||
|
message("Submodule is NO CMake Project: ${FULL_DIR}")
|
||||||
|
endif()
|
||||||
|
endfunction(add_git_submodule)
|
||||||
40
include/rfc4226.h
Normal file
40
include/rfc4226.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef RFC4226_H
|
||||||
|
#define RFC4226_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interface API for this library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint32_t HOTP(uint8_t* key, size_t kl, uint64_t interval, int digits);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Step 1 -> Calling hmac function from openssl
|
||||||
|
* library. It is used to create a 160-bit
|
||||||
|
* integer value which is processed further.
|
||||||
|
* It take a string key as an argument and
|
||||||
|
* a seed value for calculation.
|
||||||
|
* ->unsigned char* key -> key string
|
||||||
|
* ->uint64_t interval -> seed value
|
||||||
|
* |
|
||||||
|
* |
|
||||||
|
* -------> This seed value can be integer counter or
|
||||||
|
* timer value as an argument.
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint8_t* hmac(unsigned char* key, int kl, uint64_t interval);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Step 2 -> This function will truncate some bits to produce
|
||||||
|
* a binary sequence of 32-bit. The 160-bit binary
|
||||||
|
* sequence should in big-endian binary format for
|
||||||
|
* processing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint32_t DT(uint8_t* rawData);
|
||||||
|
#endif
|
||||||
16
include/rfc6238.h
Normal file
16
include/rfc6238.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef RFC6238_H
|
||||||
|
#define RFC6238_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "rfc4226.h"
|
||||||
|
|
||||||
|
#define TS 30 /* time step in seconds, default value */
|
||||||
|
|
||||||
|
uint32_t TOTP(uint8_t* key, size_t kl, uint64_t time, int digits);
|
||||||
|
time_t get_time(time_t T0);
|
||||||
|
#endif
|
||||||
11
src/CMakeLists.txt
Normal file
11
src/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
add_library(${OTP_LIBRARY} STATIC
|
||||||
|
"rfc4226.c"
|
||||||
|
"rfc6238.c")
|
||||||
|
|
||||||
|
target_include_directories(${OTP_LIBRARY} PUBLIC
|
||||||
|
${HEADER_DIR}
|
||||||
|
${OPENSSL_HEADER})
|
||||||
|
|
||||||
|
target_link_libraries(${OTP_LIBRARY} PUBLIC
|
||||||
|
${OPENSSL_LIB}
|
||||||
|
m)
|
||||||
91
src/rfc4226.c
Normal file
91
src/rfc4226.c
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <openssl/hmac.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include "rfc4226.h"
|
||||||
|
|
||||||
|
uint8_t*
|
||||||
|
hmac(unsigned char* key, int kl, uint64_t interval) {
|
||||||
|
|
||||||
|
return (uint8_t*)HMAC(EVP_sha1(), key, kl,
|
||||||
|
(const unsigned char*)&interval, sizeof(interval), NULL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
DT(uint8_t* rawData) {
|
||||||
|
|
||||||
|
uint64_t offset;
|
||||||
|
uint32_t bin_code;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Truncate to 32-bit binary sequence.
|
||||||
|
*/
|
||||||
|
offset = rawData[19] & 0xf;
|
||||||
|
|
||||||
|
bin_code = (rawData[offset] & 0x7f) << 24
|
||||||
|
| (rawData[offset + 1] & 0xff) << 16
|
||||||
|
| (rawData[offset + 2] & 0xff) << 8
|
||||||
|
| (rawData[offset + 3] & 0xff);
|
||||||
|
|
||||||
|
|
||||||
|
return bin_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
mod_hotp(uint32_t bin_code, int digits) {
|
||||||
|
|
||||||
|
int power = pow(10, digits);
|
||||||
|
|
||||||
|
uint32_t otp = bin_code % power;
|
||||||
|
|
||||||
|
return otp;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
machine_endianness_type() {
|
||||||
|
|
||||||
|
unsigned short int a = 1;
|
||||||
|
char ist_byte = *((char*)&a);
|
||||||
|
if (ist_byte == 0)
|
||||||
|
return 0;
|
||||||
|
else if (ist_byte == 1)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
HOTP(uint8_t* key, size_t kl, uint64_t interval, int digits) {
|
||||||
|
|
||||||
|
uint8_t* rawData;
|
||||||
|
uint32_t result;
|
||||||
|
uint32_t endianness;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Converting the interval from little endian
|
||||||
|
* to big endian, if required
|
||||||
|
*/
|
||||||
|
if (machine_endianness_type()) {
|
||||||
|
|
||||||
|
interval = ((interval & 0x00000000ffffffff) << 32) | ((interval & 0xffffffff00000000) >> 32);
|
||||||
|
interval = ((interval & 0x0000ffff0000ffff) << 16) | ((interval & 0xffff0000ffff0000) >> 16);
|
||||||
|
interval = ((interval & 0x00ff00ff00ff00ff) << 8) | ((interval & 0xff00ff00ff00ff00) >> 8);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Step - 1, get the hashed integer value.
|
||||||
|
rawData = (uint8_t*)hmac(key, kl, interval);
|
||||||
|
|
||||||
|
//Step - 2, get dynamically truncated code.
|
||||||
|
uint32_t truncData = DT(rawData);
|
||||||
|
|
||||||
|
//Step - 3 calculate the final result by modding it.
|
||||||
|
result = mod_hotp(truncData, digits);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
17
src/rfc6238.c
Normal file
17
src/rfc6238.c
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#include "rfc6238.h"
|
||||||
|
|
||||||
|
|
||||||
|
time_t
|
||||||
|
get_time(time_t t0)
|
||||||
|
{
|
||||||
|
return floor((time(NULL) - t0) / TS);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
TOTP(uint8_t* key, size_t kl, uint64_t time, int digits)
|
||||||
|
{
|
||||||
|
uint32_t totp;
|
||||||
|
|
||||||
|
totp = HOTP(key, kl, time, digits);
|
||||||
|
return totp;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user