This commit is contained in:
RogueMaster
2022-10-07 03:12:19 -04:00
parent 599fe8c703
commit 6208620636
35 changed files with 2514 additions and 104 deletions

View File

@@ -7,7 +7,8 @@ App(
requires=[
"gui",
"cli",
"dialogs"
"dialogs",
"storage"
],
provides=["totp_start"],
stack_size=2 * 1024,

View File

@@ -1,12 +1,53 @@
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include "../../types/common.h"
#include "../../types/token_info.h"
#include "migrations/config_migration_v1_to_v2.h"
#define CONFIG_FILE_DIRECTORY_PATH "/ext/apps/Misc"
#define CONFIG_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf"
#define CONFIG_FILE_HEADER "Flipper TOTP plugin config file"
#define CONFIG_FILE_VERSION 1
#define CONFIG_FILE_BACKUP_PATH CONFIG_FILE_PATH ".backup"
uint8_t token_info_get_digits_as_int(TokenInfo* token_info) {
switch (token_info->digits) {
case TOTP_6_DIGITS: return 6;
case TOTP_8_DIGITS: return 8;
}
return 6;
}
void token_info_set_digits_from_int(TokenInfo* token_info, uint8_t digits) {
switch (digits) {
case 6:
token_info->digits = TOTP_6_DIGITS;
break;
case 8:
token_info->digits = TOTP_8_DIGITS;
break;
}
}
char* token_info_get_algo_as_cstr(TokenInfo* token_info) {
switch (token_info->algo) {
case SHA1: return TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME;
case SHA256: return TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME;
case SHA512: return TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME;
}
return NULL;
}
void token_info_set_algo_from_str(TokenInfo* token_info, FuriString* str) {
if (string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME) == 0) {
token_info->algo = SHA1;
} else if (string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME)) {
token_info->algo = SHA256;
} else if (string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME)) {
token_info->algo = SHA512;
}
}
Storage* totp_open_storage() {
return furi_record_open(RECORD_STORAGE);
@@ -42,9 +83,42 @@ FlipperFormat* totp_open_config_file(Storage* storage) {
return NULL;
}
flipper_format_write_header_cstr(fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_VERSION);
flipper_format_write_header_cstr(fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_ACTUAL_VERSION);
float tmp_tz = 0;
flipper_format_write_comment_cstr(fff_data_file, " ");
flipper_format_write_comment_cstr(fff_data_file, "Timezone offset in hours. Important note: do not put '+' sign for positive values");
flipper_format_write_float(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &tmp_tz, 1);
FuriString* temp_str;
temp_str = furi_string_alloc();
flipper_format_write_comment_cstr(fff_data_file, " ");
flipper_format_write_comment_cstr(fff_data_file, "=== TOKEN SAMPLE BEGIN ===");
flipper_format_write_comment_cstr(fff_data_file, " ");
flipper_format_write_comment_cstr(fff_data_file, "# Token name which will be visible in the UI.");
string_printf(temp_str, "%s: Sample token name", TOTP_CONFIG_KEY_TOKEN_NAME);
flipper_format_write_comment(fff_data_file, temp_str);
flipper_format_write_comment_cstr(fff_data_file, " ");
flipper_format_write_comment_cstr(fff_data_file, "# Plain token secret without spaces, dashes and etc, just pure alpha-numeric characters. Important note: plain token will be encrypted and replaced by TOTP app");
string_printf(temp_str, "%s: plaintokensecret", TOTP_CONFIG_KEY_TOKEN_SECRET);
flipper_format_write_comment(fff_data_file, temp_str);
flipper_format_write_comment_cstr(fff_data_file, " ");
string_printf(temp_str, " # Token hashing algorithm to use during code generation. Supported options are %s, %s and %s. If you are not use which one to use - use %s", TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME, TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME, TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME);
flipper_format_write_comment(fff_data_file, temp_str);
string_printf(temp_str, "%s: %s", TOTP_CONFIG_KEY_TOKEN_ALGO, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME);
flipper_format_write_comment(fff_data_file, temp_str);
flipper_format_write_comment_cstr(fff_data_file, " ");
flipper_format_write_comment_cstr(fff_data_file, "# How many digits there should be in generated code. Available options are 6 and 8. Majority websites requires 6 digits code, however some rare websites wants to get 8 digits code. If you are not sure which one to use - use 6");
string_printf(temp_str, "%s: 6", TOTP_CONFIG_KEY_TOKEN_DIGITS);
flipper_format_write_comment(fff_data_file, temp_str);
flipper_format_write_comment_cstr(fff_data_file, " ");
flipper_format_write_comment_cstr(fff_data_file, "=== TOKEN SAMPLE END ===");
flipper_format_write_comment_cstr(fff_data_file, " ");
furi_string_free(temp_str);
if(!flipper_format_rewind(fff_data_file)) {
totp_close_config_file(fff_data_file);
FURI_LOG_E(LOGGING_TAG, "Rewind error");
@@ -55,20 +129,27 @@ FlipperFormat* totp_open_config_file(Storage* storage) {
return fff_data_file;
}
void totp_config_file_save_new_token(FlipperFormat* file, TokenInfo* token_info) {
flipper_format_write_string_cstr(file, TOTP_CONFIG_KEY_TOKEN_NAME, token_info->name);
flipper_format_write_hex(file, TOTP_CONFIG_KEY_TOKEN_SECRET, token_info->token, token_info->token_length);
flipper_format_write_string_cstr(file, TOTP_CONFIG_KEY_TOKEN_ALGO, token_info_get_algo_as_cstr(token_info));
uint32_t digits_count_as_uint32 = token_info_get_digits_as_int(token_info);
flipper_format_write_uint32(file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &digits_count_as_uint32, 1);
}
void totp_full_save_config_file(PluginState* const plugin_state) {
Storage* storage = totp_open_storage();
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
flipper_format_file_open_always(fff_data_file, CONFIG_FILE_PATH);
flipper_format_write_header_cstr(fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_VERSION);
flipper_format_write_header_cstr(fff_data_file, CONFIG_FILE_HEADER, CONFIG_FILE_ACTUAL_VERSION);
flipper_format_write_hex(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, &plugin_state->base_iv[0], TOTP_IV_SIZE);
flipper_format_write_hex(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, plugin_state->crypto_verify_data, plugin_state->crypto_verify_data_length);
flipper_format_write_float(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1);
ListNode* node = plugin_state->tokens_list;
while (node != NULL) {
TokenInfo* token_info = node->data;
flipper_format_write_string_cstr(fff_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, token_info->name);
flipper_format_write_hex(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, token_info->token, token_info->token_length);
totp_config_file_save_new_token(fff_data_file, token_info);
node = node->next;
}
@@ -83,14 +164,45 @@ void totp_config_file_load_base(PluginState* const plugin_state) {
plugin_state->timezone_offset = 0;
FuriString* temp_str;
uint32_t temp_data32;
temp_str = furi_string_alloc();
if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
uint32_t file_version;
if(!flipper_format_read_header(fff_data_file, temp_str, &file_version)) {
FURI_LOG_E(LOGGING_TAG, "Missing or incorrect header");
furi_string_free(temp_str);
return;
}
if (file_version < CONFIG_FILE_ACTUAL_VERSION) {
FURI_LOG_I(LOGGING_TAG, "Obsolete config file version detected. Current version: %d; Actual version: %d", file_version, CONFIG_FILE_ACTUAL_VERSION);
totp_close_config_file(fff_data_file);
if (storage_common_stat(storage, CONFIG_FILE_BACKUP_PATH, NULL) == FSE_OK) {
storage_simply_remove(storage, CONFIG_FILE_BACKUP_PATH);
}
if (storage_common_copy(storage, CONFIG_FILE_PATH, CONFIG_FILE_BACKUP_PATH) == FSE_OK) {
FURI_LOG_I(LOGGING_TAG, "Took config file backup to %s", CONFIG_FILE_BACKUP_PATH);
fff_data_file = totp_open_config_file(storage);
FlipperFormat* fff_backup_data_file = flipper_format_file_alloc(storage);
flipper_format_file_open_existing(fff_backup_data_file, CONFIG_FILE_BACKUP_PATH);
if (file_version == 1) {
if (totp_config_migrate_v1_to_v2(fff_data_file, fff_backup_data_file)) {
FURI_LOG_I(LOGGING_TAG, "Applied migration from v1 to v2");
} else {
FURI_LOG_W(LOGGING_TAG, "An error occurred during migration from v1 to v2");
}
}
flipper_format_file_close(fff_backup_data_file);
flipper_format_free(fff_backup_data_file);
flipper_format_rewind(fff_data_file);
} else {
FURI_LOG_E(LOGGING_TAG, "An error occurred during taking backup of %s into %s before migration", CONFIG_FILE_PATH, CONFIG_FILE_BACKUP_PATH);
}
}
if (!flipper_format_read_hex(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, &plugin_state->base_iv[0], TOTP_IV_SIZE)) {
FURI_LOG_D(LOGGING_TAG, "Missing base IV");
}
@@ -130,17 +242,19 @@ void totp_config_file_load_tokens(PluginState* const plugin_state) {
if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
FURI_LOG_E(LOGGING_TAG, "Missing or incorrect header");
furi_string_free(temp_str);
return;
}
uint8_t index = 0;
bool has_any_plain_secret = false;
while (true) {
if (!flipper_format_read_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) {
break;
}
TokenInfo* tokenInfo = malloc(sizeof(TokenInfo));
TokenInfo* tokenInfo = token_info_alloc();
const char* temp_cstr = furi_string_get_cstr(temp_str);
tokenInfo->name = (char *)malloc(strlen(temp_cstr) + 1);
@@ -148,11 +262,13 @@ void totp_config_file_load_tokens(PluginState* const plugin_state) {
uint32_t secret_bytes_count;
if (!flipper_format_get_value_count(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, &secret_bytes_count)) {
token_info_free(tokenInfo);
continue;
}
if (secret_bytes_count == 1) { // Plain secret key
if (!flipper_format_read_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str)) {
token_info_free(tokenInfo);
continue;
}
@@ -164,10 +280,25 @@ void totp_config_file_load_tokens(PluginState* const plugin_state) {
tokenInfo->token_length = secret_bytes_count;
tokenInfo->token = malloc(tokenInfo->token_length);
if (!flipper_format_read_hex(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, tokenInfo->token, tokenInfo->token_length)) {
token_info_free(tokenInfo);
continue;
}
}
if (!flipper_format_read_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, temp_str)) {
token_info_free(tokenInfo);
continue;
}
token_info_set_algo_from_str(tokenInfo, temp_str);
if (!flipper_format_read_uint32(fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &temp_data32, 1)) {
token_info_free(tokenInfo);
continue;
}
token_info_set_digits_from_int(tokenInfo, temp_data32);
FURI_LOG_D(LOGGING_TAG, "Found token \"%s\"", tokenInfo->name);
if (plugin_state->tokens_list == NULL) {

View File

@@ -4,12 +4,8 @@
#include <flipper_format/flipper_format.h>
#include <furi.h>
#include "../../types/plugin_state.h"
#define TOTP_CONFIG_KEY_TIMEZONE "Timezone"
#define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"
#define TOTP_CONFIG_KEY_TOKEN_SECRET "TokenSecret"
#define TOTP_CONFIG_KEY_CRYPTO_VERIFY "Crypto"
#define TOTP_CONFIG_KEY_BASE_IV "BaseIV"
#include "../../types/token_info.h"
#include "constants.h"
Storage* totp_open_storage();
void totp_close_storage();
@@ -18,5 +14,6 @@ void totp_close_config_file(FlipperFormat* file);
void totp_full_save_config_file(PluginState* const plugin_state);
void totp_config_file_load_base(PluginState* const plugin_state);
void totp_config_file_load_tokens(PluginState* const plugin_state);
void totp_config_file_save_new_token(FlipperFormat* file, TokenInfo* token_info);
#endif

View File

@@ -0,0 +1,19 @@
#ifndef _TOTP_CONFIG_CONSTANTS_FILE_H_
#define _TOTP_CONFIG_CONSTANTS_FILE_H_
#define CONFIG_FILE_HEADER "Flipper TOTP plugin config file"
#define CONFIG_FILE_ACTUAL_VERSION 2
#define TOTP_CONFIG_KEY_TIMEZONE "Timezone"
#define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"
#define TOTP_CONFIG_KEY_TOKEN_SECRET "TokenSecret"
#define TOTP_CONFIG_KEY_TOKEN_ALGO "TokenAlgo"
#define TOTP_CONFIG_KEY_TOKEN_DIGITS "TokenDigits"
#define TOTP_CONFIG_KEY_CRYPTO_VERIFY "Crypto"
#define TOTP_CONFIG_KEY_BASE_IV "BaseIV"
#define TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME "sha1"
#define TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME "sha256"
#define TOTP_CONFIG_TOKEN_ALGO_SHA512_NAME "sha512"
#endif

View File

@@ -0,0 +1,42 @@
#include "config_migration_v1_to_v2.h"
#include <flipper_format/flipper_format.h>
#include "../constants.h"
#define NEW_VERSION 2
bool totp_config_migrate_v1_to_v2(FlipperFormat* fff_data_file, FlipperFormat* fff_backup_data_file) {
flipper_format_write_header_cstr(fff_data_file, CONFIG_FILE_HEADER, NEW_VERSION);
FuriString* temp_str;
temp_str = furi_string_alloc();
if (flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_BASE_IV, temp_str);
}
if (flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, temp_str);
}
if (flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TIMEZONE, temp_str)) {
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, temp_str);
}
while (true) {
if (!flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) {
break;
}
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str);
flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str);
flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_TOKEN_SECRET, temp_str);
flipper_format_write_string_cstr(fff_data_file, TOTP_CONFIG_KEY_TOKEN_ALGO, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME);
uint32_t default_digits = 6;
flipper_format_write_uint32(fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &default_digits, 1);
}
furi_string_free(temp_str);
return true;
}

View File

@@ -0,0 +1,8 @@
#ifndef _TOTP_CONFIG_FILE_MIGRATE_V1_TO_V2_H_
#define _TOTP_CONFIG_FILE_MIGRATE_V1_TO_V2_H_
#include <flipper_format/flipper_format.h>
bool totp_config_migrate_v1_to_v2(FlipperFormat* fff_data_file, FlipperFormat* fff_backup_data_file);
#endif

View File

@@ -0,0 +1,14 @@
#include "byteswap.h"
uint32_t swap_uint32( uint32_t val )
{
val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF );
return (val << 16) | (val >> 16);
}
uint64_t swap_uint64( uint64_t val )
{
val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL );
val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL );
return (val << 32) | (val >> 32);
}

View File

@@ -0,0 +1,9 @@
#ifndef BYTESWAP_H
#define BYTESWAP_H
#include <stdint.h>
uint32_t swap_uint32( uint32_t val );
uint64_t swap_uint64( uint64_t val );
#endif

View File

@@ -0,0 +1,71 @@
#include <string.h>
#include "sha256.h"
#include "memxor.h"
#define IPAD 0x36
#define OPAD 0x5c
/* Concatenate two preprocessor tokens. */
#define _GLHMAC_CONCAT_(prefix, suffix) prefix##suffix
#define _GLHMAC_CONCAT(prefix, suffix) _GLHMAC_CONCAT_ (prefix, suffix)
#if GL_HMAC_NAME == 5
# define HMAC_ALG md5
#else
# define HMAC_ALG _GLHMAC_CONCAT (sha, GL_HMAC_NAME)
#endif
#define GL_HMAC_CTX _GLHMAC_CONCAT (HMAC_ALG, _ctx)
#define GL_HMAC_FN _GLHMAC_CONCAT (hmac_, HMAC_ALG)
#define GL_HMAC_FN_INIT _GLHMAC_CONCAT (HMAC_ALG, _init_ctx)
#define GL_HMAC_FN_BLOC _GLHMAC_CONCAT (HMAC_ALG, _process_block)
#define GL_HMAC_FN_PROC _GLHMAC_CONCAT (HMAC_ALG, _process_bytes)
#define GL_HMAC_FN_FINI _GLHMAC_CONCAT (HMAC_ALG, _finish_ctx)
static void
hmac_hash (const void *key, size_t keylen,
const void *in, size_t inlen,
int pad, void *resbuf)
{
struct GL_HMAC_CTX hmac_ctx;
char block[GL_HMAC_BLOCKSIZE];
memset (block, pad, sizeof block);
memxor (block, key, keylen);
GL_HMAC_FN_INIT (&hmac_ctx);
GL_HMAC_FN_BLOC (block, sizeof block, &hmac_ctx);
GL_HMAC_FN_PROC (in, inlen, &hmac_ctx);
GL_HMAC_FN_FINI (&hmac_ctx, resbuf);
}
int
GL_HMAC_FN (const void *key, size_t keylen,
const void *in, size_t inlen, void *resbuf)
{
char optkeybuf[GL_HMAC_HASHSIZE];
char innerhash[GL_HMAC_HASHSIZE];
/* Ensure key size is <= block size. */
if (keylen > GL_HMAC_BLOCKSIZE)
{
struct GL_HMAC_CTX keyhash;
GL_HMAC_FN_INIT (&keyhash);
GL_HMAC_FN_PROC (key, keylen, &keyhash);
GL_HMAC_FN_FINI (&keyhash, optkeybuf);
key = optkeybuf;
/* zero padding of the key to the block size
is implicit in the memxor. */
keylen = sizeof optkeybuf;
}
/* Compute INNERHASH from KEY and IN. */
hmac_hash (key, keylen, in, inlen, IPAD, innerhash);
/* Compute result from KEY and INNERHASH. */
hmac_hash (key, keylen, innerhash, sizeof innerhash, OPAD, resbuf);
return 0;
}

View File

@@ -0,0 +1,24 @@
/* hmac-sha1.c -- hashed message authentication codes
Copyright (C) 2018-2022 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include "hmac-sha1.h"
#include "sha1.h"
#define GL_HMAC_NAME 1
#define GL_HMAC_BLOCKSIZE 64
#define GL_HMAC_HASHSIZE 20
#include "hmac-common.h"

View File

@@ -0,0 +1,14 @@
#ifndef HMAC_SHA1_H
#define HMAC_SHA1_H
#include <stddef.h>
#define HMAC_SHA1_RESULT_SIZE 20
/* Compute Hashed Message Authentication Code with SHA-1, over BUFFER
data of BUFLEN bytes using the KEY of KEYLEN bytes, writing the
output to pre-allocated 20 byte minimum RESBUF buffer. Return 0 on
success. */
int hmac_sha1 (const void *key, size_t keylen, const void *in, size_t inlen, void *restrict resbuf);
#endif /* HMAC_SHA1_H */

View File

@@ -0,0 +1,23 @@
/* hmac-sha256.c -- hashed message authentication codes
Copyright (C) 2018-2022 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include "hmac-sha256.h"
#define GL_HMAC_NAME 256
#define GL_HMAC_BLOCKSIZE 64
#define GL_HMAC_HASHSIZE 32
#include "hmac-common.h"

View File

@@ -0,0 +1,14 @@
#ifndef HMAC_SHA256_H
#define HMAC_SHA256_H
#include <stddef.h>
#define HMAC_SHA256_RESULT_SIZE 32
/* Compute Hashed Message Authentication Code with SHA-256, over BUFFER
data of BUFLEN bytes using the KEY of KEYLEN bytes, writing the
output to pre-allocated 32 byte minimum RESBUF buffer. Return 0 on
success. */
int hmac_sha256 (const void *key, size_t keylen, const void *in, size_t inlen, void *restrict resbuf);
#endif /* HMAC_SHA256_H */

View File

@@ -0,0 +1,24 @@
/* hmac-sha512.c -- hashed message authentication codes
Copyright (C) 2018-2022 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include "hmac-sha512.h"
#include "sha512.h"
#define GL_HMAC_NAME 512
#define GL_HMAC_BLOCKSIZE 128
#define GL_HMAC_HASHSIZE 64
#include "hmac-common.h"

View File

@@ -0,0 +1,14 @@
#ifndef HMAC_SHA512_H
#define HMAC_SHA512_H
#include <stddef.h>
#define HMAC_SHA512_RESULT_SIZE 64
/* Compute Hashed Message Authentication Code with SHA-512, over BUFFER
data of BUFLEN bytes using the KEY of KEYLEN bytes, writing the
output to pre-allocated 64 byte minimum RESBUF buffer. Return 0 on
success. */
int hmac_sha512 (const void *key, size_t keylen, const void *in, size_t inlen, void *restrict resbuf);
#endif /* HMAC_SHA512_H */

View File

@@ -0,0 +1,34 @@
/* memxor.c -- perform binary exclusive OR operation of two memory blocks.
Copyright (C) 2005, 2006 Free Software Foundation, Inc.
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)
any later version.
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, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Simon Josefsson. The interface was inspired by memxor
in Niels Möller's Nettle. */
/* #include <config.h> */
#include "memxor.h"
void* memxor (void */*restrict*/ dest, const void */*restrict*/ src, size_t n)
{
char const *s = (char const*)src;
char *d = (char*)dest;
for (; n > 0; n--)
*d++ ^= *s++;
return dest;
}

View File

@@ -0,0 +1,31 @@
/* memxor.h -- perform binary exclusive OR operation on memory blocks.
Copyright (C) 2005 Free Software Foundation, Inc.
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)
any later version.
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, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Written by Simon Josefsson. The interface was inspired by memxor
in Niels Möller's Nettle. */
#ifndef MEMXOR_H
# define MEMXOR_H
#include <stddef.h>
/* Compute binary exclusive OR of memory areas DEST and SRC, putting
the result in DEST, of length N bytes. Returns a pointer to
DEST. */
void *memxor (void */*restrict*/ dest, const void */*restrict*/ src, size_t n);
#endif /* MEMXOR_H */

View File

@@ -0,0 +1,358 @@
/* sha1.c - Functions to compute SHA1 message digest of files or
memory blocks according to the NIST specification FIPS-180-1.
Copyright (C) 2000-2001, 2003-2006, 2008-2022 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Scott G. Miller
Credits:
Robert Klep <robert@ilse.nl> -- Expansion function fix
*/
/* Specification. */
#if HAVE_OPENSSL_SHA1
# define GL_OPENSSL_INLINE _GL_EXTERN_INLINE
#endif
#include "sha1.h"
#include <stdint.h>
#include <string.h>
#ifdef WORDS_BIGENDIAN
# define SWAP(n) (n)
#else
#include "byteswap.h"
# define SWAP(n) swap_uint32(n)
#endif
#if ! HAVE_OPENSSL_SHA1
/* This array contains the bytes used to pad the buffer to the next
64-byte boundary. (RFC 1321, 3.1: Step 1) */
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
/* Take a pointer to a 160 bit block of data (five 32 bit ints) and
initialize it to the start constants of the SHA1 algorithm. This
must be called before using hash in the call to sha1_hash. */
void
sha1_init_ctx (struct sha1_ctx *ctx)
{
ctx->A = 0x67452301;
ctx->B = 0xefcdab89;
ctx->C = 0x98badcfe;
ctx->D = 0x10325476;
ctx->E = 0xc3d2e1f0;
ctx->total[0] = ctx->total[1] = 0;
ctx->buflen = 0;
}
/* Copy the 4 byte value from v into the memory location pointed to by *cp,
If your architecture allows unaligned access this is equivalent to
* (uint32_t *) cp = v */
static void
set_uint32 (char *cp, uint32_t v)
{
memcpy (cp, &v, sizeof v);
}
/* Put result from CTX in first 20 bytes following RESBUF. The result
must be in little endian byte order. */
void *
sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf)
{
char *r = resbuf;
set_uint32 (r + 0 * sizeof ctx->A, SWAP (ctx->A));
set_uint32 (r + 1 * sizeof ctx->B, SWAP (ctx->B));
set_uint32 (r + 2 * sizeof ctx->C, SWAP (ctx->C));
set_uint32 (r + 3 * sizeof ctx->D, SWAP (ctx->D));
set_uint32 (r + 4 * sizeof ctx->E, SWAP (ctx->E));
return resbuf;
}
/* Process the remaining bytes in the internal buffer and the usual
prolog according to the standard and write the result to RESBUF. */
void *
sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf)
{
/* Take yet unprocessed bytes into account. */
uint32_t bytes = ctx->buflen;
size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
/* Now count remaining bytes. */
ctx->total[0] += bytes;
if (ctx->total[0] < bytes)
++ctx->total[1];
/* Put the 64-bit file length in *bits* at the end of the buffer. */
ctx->buffer[size - 2] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29));
ctx->buffer[size - 1] = SWAP (ctx->total[0] << 3);
memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
/* Process last bytes. */
sha1_process_block (ctx->buffer, size * 4, ctx);
return sha1_read_ctx (ctx, resbuf);
}
/* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest. */
void *
sha1_buffer (const char *buffer, size_t len, void *resblock)
{
struct sha1_ctx ctx;
/* Initialize the computation context. */
sha1_init_ctx (&ctx);
/* Process whole buffer but last len % 64 bytes. */
sha1_process_bytes (buffer, len, &ctx);
/* Put result in desired memory area. */
return sha1_finish_ctx (&ctx, resblock);
}
void
sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx)
{
/* When we already have some bits in our internal buffer concatenate
both inputs first. */
if (ctx->buflen != 0)
{
size_t left_over = ctx->buflen;
size_t add = 128 - left_over > len ? len : 128 - left_over;
memcpy (&((char *) ctx->buffer)[left_over], buffer, add);
ctx->buflen += add;
if (ctx->buflen > 64)
{
sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
ctx->buflen &= 63;
/* The regions in the following copy operation cannot overlap,
because ctx->buflen < 64 ≤ (left_over + add) & ~63. */
memcpy (ctx->buffer,
&((char *) ctx->buffer)[(left_over + add) & ~63],
ctx->buflen);
}
buffer = (const char *) buffer + add;
len -= add;
}
/* Process available complete blocks. */
if (len >= 64)
{
#if !(_STRING_ARCH_unaligned || _STRING_INLINE_unaligned)
# define UNALIGNED_P(p) ((uintptr_t) (p) % sizeof (uint32_t) != 0)
if (UNALIGNED_P (buffer))
while (len > 64)
{
sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
buffer = (const char *) buffer + 64;
len -= 64;
}
else
#endif
{
sha1_process_block (buffer, len & ~63, ctx);
buffer = (const char *) buffer + (len & ~63);
len &= 63;
}
}
/* Move remaining bytes in internal buffer. */
if (len > 0)
{
size_t left_over = ctx->buflen;
memcpy (&((char *) ctx->buffer)[left_over], buffer, len);
left_over += len;
if (left_over >= 64)
{
sha1_process_block (ctx->buffer, 64, ctx);
left_over -= 64;
/* The regions in the following copy operation cannot overlap,
because left_over ≤ 64. */
memcpy (ctx->buffer, &ctx->buffer[16], left_over);
}
ctx->buflen = left_over;
}
}
/* --- Code below is the primary difference between md5.c and sha1.c --- */
/* SHA1 round constants */
#define K1 0x5a827999
#define K2 0x6ed9eba1
#define K3 0x8f1bbcdc
#define K4 0xca62c1d6
/* Round functions. Note that F2 is the same as F4. */
#define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) )
#define F2(B,C,D) (B ^ C ^ D)
#define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) )
#define F4(B,C,D) (B ^ C ^ D)
/* Process LEN bytes of BUFFER, accumulating context into CTX.
It is assumed that LEN % 64 == 0.
Most of this code comes from GnuPG's cipher/sha1.c. */
void
sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx)
{
const uint32_t *words = buffer;
size_t nwords = len / sizeof (uint32_t);
const uint32_t *endp = words + nwords;
uint32_t x[16];
uint32_t a = ctx->A;
uint32_t b = ctx->B;
uint32_t c = ctx->C;
uint32_t d = ctx->D;
uint32_t e = ctx->E;
uint32_t lolen = len;
/* First increment the byte count. RFC 1321 specifies the possible
length of the file up to 2^64 bits. Here we only compute the
number of bytes. Do a double word increment. */
ctx->total[0] += lolen;
ctx->total[1] += (len >> 31 >> 1) + (ctx->total[0] < lolen);
#define rol(x, n) (((x) << (n)) | ((uint32_t) (x) >> (32 - (n))))
#define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \
^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \
, (x[I&0x0f] = rol(tm, 1)) )
#define R(A,B,C,D,E,F,K,M) do { E += rol( A, 5 ) \
+ F( B, C, D ) \
+ K \
+ M; \
B = rol( B, 30 ); \
} while(0)
while (words < endp)
{
uint32_t tm;
int t;
for (t = 0; t < 16; t++)
{
x[t] = SWAP (*words);
words++;
}
R( a, b, c, d, e, F1, K1, x[ 0] );
R( e, a, b, c, d, F1, K1, x[ 1] );
R( d, e, a, b, c, F1, K1, x[ 2] );
R( c, d, e, a, b, F1, K1, x[ 3] );
R( b, c, d, e, a, F1, K1, x[ 4] );
R( a, b, c, d, e, F1, K1, x[ 5] );
R( e, a, b, c, d, F1, K1, x[ 6] );
R( d, e, a, b, c, F1, K1, x[ 7] );
R( c, d, e, a, b, F1, K1, x[ 8] );
R( b, c, d, e, a, F1, K1, x[ 9] );
R( a, b, c, d, e, F1, K1, x[10] );
R( e, a, b, c, d, F1, K1, x[11] );
R( d, e, a, b, c, F1, K1, x[12] );
R( c, d, e, a, b, F1, K1, x[13] );
R( b, c, d, e, a, F1, K1, x[14] );
R( a, b, c, d, e, F1, K1, x[15] );
R( e, a, b, c, d, F1, K1, M(16) );
R( d, e, a, b, c, F1, K1, M(17) );
R( c, d, e, a, b, F1, K1, M(18) );
R( b, c, d, e, a, F1, K1, M(19) );
R( a, b, c, d, e, F2, K2, M(20) );
R( e, a, b, c, d, F2, K2, M(21) );
R( d, e, a, b, c, F2, K2, M(22) );
R( c, d, e, a, b, F2, K2, M(23) );
R( b, c, d, e, a, F2, K2, M(24) );
R( a, b, c, d, e, F2, K2, M(25) );
R( e, a, b, c, d, F2, K2, M(26) );
R( d, e, a, b, c, F2, K2, M(27) );
R( c, d, e, a, b, F2, K2, M(28) );
R( b, c, d, e, a, F2, K2, M(29) );
R( a, b, c, d, e, F2, K2, M(30) );
R( e, a, b, c, d, F2, K2, M(31) );
R( d, e, a, b, c, F2, K2, M(32) );
R( c, d, e, a, b, F2, K2, M(33) );
R( b, c, d, e, a, F2, K2, M(34) );
R( a, b, c, d, e, F2, K2, M(35) );
R( e, a, b, c, d, F2, K2, M(36) );
R( d, e, a, b, c, F2, K2, M(37) );
R( c, d, e, a, b, F2, K2, M(38) );
R( b, c, d, e, a, F2, K2, M(39) );
R( a, b, c, d, e, F3, K3, M(40) );
R( e, a, b, c, d, F3, K3, M(41) );
R( d, e, a, b, c, F3, K3, M(42) );
R( c, d, e, a, b, F3, K3, M(43) );
R( b, c, d, e, a, F3, K3, M(44) );
R( a, b, c, d, e, F3, K3, M(45) );
R( e, a, b, c, d, F3, K3, M(46) );
R( d, e, a, b, c, F3, K3, M(47) );
R( c, d, e, a, b, F3, K3, M(48) );
R( b, c, d, e, a, F3, K3, M(49) );
R( a, b, c, d, e, F3, K3, M(50) );
R( e, a, b, c, d, F3, K3, M(51) );
R( d, e, a, b, c, F3, K3, M(52) );
R( c, d, e, a, b, F3, K3, M(53) );
R( b, c, d, e, a, F3, K3, M(54) );
R( a, b, c, d, e, F3, K3, M(55) );
R( e, a, b, c, d, F3, K3, M(56) );
R( d, e, a, b, c, F3, K3, M(57) );
R( c, d, e, a, b, F3, K3, M(58) );
R( b, c, d, e, a, F3, K3, M(59) );
R( a, b, c, d, e, F4, K4, M(60) );
R( e, a, b, c, d, F4, K4, M(61) );
R( d, e, a, b, c, F4, K4, M(62) );
R( c, d, e, a, b, F4, K4, M(63) );
R( b, c, d, e, a, F4, K4, M(64) );
R( a, b, c, d, e, F4, K4, M(65) );
R( e, a, b, c, d, F4, K4, M(66) );
R( d, e, a, b, c, F4, K4, M(67) );
R( c, d, e, a, b, F4, K4, M(68) );
R( b, c, d, e, a, F4, K4, M(69) );
R( a, b, c, d, e, F4, K4, M(70) );
R( e, a, b, c, d, F4, K4, M(71) );
R( d, e, a, b, c, F4, K4, M(72) );
R( c, d, e, a, b, F4, K4, M(73) );
R( b, c, d, e, a, F4, K4, M(74) );
R( a, b, c, d, e, F4, K4, M(75) );
R( e, a, b, c, d, F4, K4, M(76) );
R( d, e, a, b, c, F4, K4, M(77) );
R( c, d, e, a, b, F4, K4, M(78) );
R( b, c, d, e, a, F4, K4, M(79) );
a = ctx->A += a;
b = ctx->B += b;
c = ctx->C += c;
d = ctx->D += d;
e = ctx->E += e;
}
}
#endif
/*
* Hey Emacs!
* Local Variables:
* coding: utf-8
* End:
*/

View File

@@ -0,0 +1,115 @@
/* Declarations of functions and data types used for SHA1 sum
library functions.
Copyright (C) 2000-2001, 2003, 2005-2006, 2008-2022 Free Software
Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef SHA1_H
# define SHA1_H 1
# include <stdio.h>
# include <stdint.h>
# if HAVE_OPENSSL_SHA1
# ifndef OPENSSL_API_COMPAT
# define OPENSSL_API_COMPAT 0x10101000L /* FIXME: Use OpenSSL 1.1+ API. */
# endif
# include <openssl/sha.h>
# endif
# ifdef __cplusplus
extern "C" {
# endif
# define SHA1_DIGEST_SIZE 20
# if HAVE_OPENSSL_SHA1
# define GL_OPENSSL_NAME 1
# include "gl_openssl.h"
# else
/* Structure to save state of computation between the single steps. */
struct sha1_ctx
{
uint32_t A;
uint32_t B;
uint32_t C;
uint32_t D;
uint32_t E;
uint32_t total[2];
uint32_t buflen; /* ≥ 0, ≤ 128 */
uint32_t buffer[32]; /* 128 bytes; the first buflen bytes are in use */
};
/* Initialize structure containing state of computation. */
extern void sha1_init_ctx (struct sha1_ctx *ctx);
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is necessary that LEN is a multiple of 64!!! */
extern void sha1_process_block (const void *buffer, size_t len,
struct sha1_ctx *ctx);
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is NOT required that LEN is a multiple of 64. */
extern void sha1_process_bytes (const void *buffer, size_t len,
struct sha1_ctx *ctx);
/* Process the remaining bytes in the buffer and put result from CTX
in first 20 bytes following RESBUF. The result is always in little
endian byte order, so that a byte-wise output yields to the wanted
ASCII representation of the message digest. */
extern void *sha1_finish_ctx (struct sha1_ctx *ctx, void *restrict resbuf);
/* Put result from CTX in first 20 bytes following RESBUF. The result is
always in little endian byte order, so that a byte-wise output yields
to the wanted ASCII representation of the message digest. */
extern void *sha1_read_ctx (const struct sha1_ctx *ctx, void *restrict resbuf);
/* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest. */
extern void *sha1_buffer (const char *buffer, size_t len,
void *restrict resblock);
# endif
/* Compute SHA1 message digest for bytes read from STREAM.
STREAM is an open file stream. Regular files are handled more efficiently.
The contents of STREAM from its current position to its end will be read.
The case that the last operation on STREAM was an 'ungetc' is not supported.
The resulting message digest number will be written into the 20 bytes
beginning at RESBLOCK. */
extern int sha1_stream (FILE *stream, void *resblock);
# ifdef __cplusplus
}
# endif
#endif
/*
* Hey Emacs!
* Local Variables:
* coding: utf-8
* End:
*/

View File

@@ -0,0 +1,430 @@
/* sha256.c - Functions to compute SHA256 and SHA224 message digest of files or
memory blocks according to the NIST specification FIPS-180-2.
Copyright (C) 2005-2006, 2008-2022 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by David Madore, considerably copypasting from
Scott G. Miller's sha1.c
*/
/* Specification. */
#if HAVE_OPENSSL_SHA256
# define GL_OPENSSL_INLINE _GL_EXTERN_INLINE
#endif
#include "sha256.h"
#include <stdint.h>
#include <string.h>
#ifdef WORDS_BIGENDIAN
# define SWAP(n) (n)
#else
#include "byteswap.h"
# define SWAP(n) swap_uint32 (n)
#endif
#if ! HAVE_OPENSSL_SHA256
/* This array contains the bytes used to pad the buffer to the next
64-byte boundary. */
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
/*
Takes a pointer to a 256 bit block of data (eight 32 bit ints) and
initializes it to the start constants of the SHA256 algorithm. This
must be called before using hash in the call to sha256_hash
*/
void
sha256_init_ctx (struct sha256_ctx *ctx)
{
ctx->state[0] = 0x6a09e667UL;
ctx->state[1] = 0xbb67ae85UL;
ctx->state[2] = 0x3c6ef372UL;
ctx->state[3] = 0xa54ff53aUL;
ctx->state[4] = 0x510e527fUL;
ctx->state[5] = 0x9b05688cUL;
ctx->state[6] = 0x1f83d9abUL;
ctx->state[7] = 0x5be0cd19UL;
ctx->total[0] = ctx->total[1] = 0;
ctx->buflen = 0;
}
void
sha224_init_ctx (struct sha256_ctx *ctx)
{
ctx->state[0] = 0xc1059ed8UL;
ctx->state[1] = 0x367cd507UL;
ctx->state[2] = 0x3070dd17UL;
ctx->state[3] = 0xf70e5939UL;
ctx->state[4] = 0xffc00b31UL;
ctx->state[5] = 0x68581511UL;
ctx->state[6] = 0x64f98fa7UL;
ctx->state[7] = 0xbefa4fa4UL;
ctx->total[0] = ctx->total[1] = 0;
ctx->buflen = 0;
}
/* Copy the value from v into the memory location pointed to by *CP,
If your architecture allows unaligned access, this is equivalent to
* (__typeof__ (v) *) cp = v */
static void
set_uint32 (char *cp, uint32_t v)
{
memcpy (cp, &v, sizeof v);
}
/* Put result from CTX in first 32 bytes following RESBUF.
The result must be in little endian byte order. */
void *
sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf)
{
int i;
char *r = resbuf;
for (i = 0; i < 8; i++)
set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i]));
return resbuf;
}
void *
sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf)
{
int i;
char *r = resbuf;
for (i = 0; i < 7; i++)
set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i]));
return resbuf;
}
/* Process the remaining bytes in the internal buffer and the usual
prolog according to the standard and write the result to RESBUF. */
static void
sha256_conclude_ctx (struct sha256_ctx *ctx)
{
/* Take yet unprocessed bytes into account. */
size_t bytes = ctx->buflen;
size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
/* Now count remaining bytes. */
ctx->total[0] += bytes;
if (ctx->total[0] < bytes)
++ctx->total[1];
/* Put the 64-bit file length in *bits* at the end of the buffer.
Use set_uint32 rather than a simple assignment, to avoid risk of
unaligned access. */
set_uint32 ((char *) &ctx->buffer[size - 2],
SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)));
set_uint32 ((char *) &ctx->buffer[size - 1],
SWAP (ctx->total[0] << 3));
memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
/* Process last bytes. */
sha256_process_block (ctx->buffer, size * 4, ctx);
}
void *
sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf)
{
sha256_conclude_ctx (ctx);
return sha256_read_ctx (ctx, resbuf);
}
void *
sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf)
{
sha256_conclude_ctx (ctx);
return sha224_read_ctx (ctx, resbuf);
}
/* Compute SHA256 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest. */
void *
sha256_buffer (const char *buffer, size_t len, void *resblock)
{
struct sha256_ctx ctx;
/* Initialize the computation context. */
sha256_init_ctx (&ctx);
/* Process whole buffer but last len % 64 bytes. */
sha256_process_bytes (buffer, len, &ctx);
/* Put result in desired memory area. */
return sha256_finish_ctx (&ctx, resblock);
}
void *
sha224_buffer (const char *buffer, size_t len, void *resblock)
{
struct sha256_ctx ctx;
/* Initialize the computation context. */
sha224_init_ctx (&ctx);
/* Process whole buffer but last len % 64 bytes. */
sha256_process_bytes (buffer, len, &ctx);
/* Put result in desired memory area. */
return sha224_finish_ctx (&ctx, resblock);
}
void
sha256_process_bytes (const void *buffer, size_t len, struct sha256_ctx *ctx)
{
/* When we already have some bits in our internal buffer concatenate
both inputs first. */
if (ctx->buflen != 0)
{
size_t left_over = ctx->buflen;
size_t add = 128 - left_over > len ? len : 128 - left_over;
memcpy (&((char *) ctx->buffer)[left_over], buffer, add);
ctx->buflen += add;
if (ctx->buflen > 64)
{
sha256_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
ctx->buflen &= 63;
/* The regions in the following copy operation cannot overlap,
because ctx->buflen < 64 ≤ (left_over + add) & ~63. */
memcpy (ctx->buffer,
&((char *) ctx->buffer)[(left_over + add) & ~63],
ctx->buflen);
}
buffer = (const char *) buffer + add;
len -= add;
}
/* Process available complete blocks. */
if (len >= 64)
{
#if !(_STRING_ARCH_unaligned || _STRING_INLINE_unaligned)
# define UNALIGNED_P(p) ((uintptr_t) (p) % sizeof (uint32_t) != 0)
if (UNALIGNED_P (buffer))
while (len > 64)
{
sha256_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
buffer = (const char *) buffer + 64;
len -= 64;
}
else
#endif
{
sha256_process_block (buffer, len & ~63, ctx);
buffer = (const char *) buffer + (len & ~63);
len &= 63;
}
}
/* Move remaining bytes in internal buffer. */
if (len > 0)
{
size_t left_over = ctx->buflen;
memcpy (&((char *) ctx->buffer)[left_over], buffer, len);
left_over += len;
if (left_over >= 64)
{
sha256_process_block (ctx->buffer, 64, ctx);
left_over -= 64;
/* The regions in the following copy operation cannot overlap,
because left_over ≤ 64. */
memcpy (ctx->buffer, &ctx->buffer[16], left_over);
}
ctx->buflen = left_over;
}
}
/* --- Code below is the primary difference between sha1.c and sha256.c --- */
/* SHA256 round constants */
#define K(I) sha256_round_constants[I]
static const uint32_t sha256_round_constants[64] = {
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL,
};
/* Round functions. */
#define F2(A,B,C) ( ( A & B ) | ( C & ( A | B ) ) )
#define F1(E,F,G) ( G ^ ( E & ( F ^ G ) ) )
/* Process LEN bytes of BUFFER, accumulating context into CTX.
It is assumed that LEN % 64 == 0.
Most of this code comes from GnuPG's cipher/sha1.c. */
void
sha256_process_block (const void *buffer, size_t len, struct sha256_ctx *ctx)
{
const uint32_t *words = buffer;
size_t nwords = len / sizeof (uint32_t);
const uint32_t *endp = words + nwords;
uint32_t x[16];
uint32_t a = ctx->state[0];
uint32_t b = ctx->state[1];
uint32_t c = ctx->state[2];
uint32_t d = ctx->state[3];
uint32_t e = ctx->state[4];
uint32_t f = ctx->state[5];
uint32_t g = ctx->state[6];
uint32_t h = ctx->state[7];
uint32_t lolen = len;
/* First increment the byte count. FIPS PUB 180-2 specifies the possible
length of the file up to 2^64 bits. Here we only compute the
number of bytes. Do a double word increment. */
ctx->total[0] += lolen;
ctx->total[1] += (len >> 31 >> 1) + (ctx->total[0] < lolen);
#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
#define S0(x) (rol(x,25)^rol(x,14)^(x>>3))
#define S1(x) (rol(x,15)^rol(x,13)^(x>>10))
#define SS0(x) (rol(x,30)^rol(x,19)^rol(x,10))
#define SS1(x) (rol(x,26)^rol(x,21)^rol(x,7))
#define M(I) ( tm = S1(x[(I-2)&0x0f]) + x[(I-7)&0x0f] \
+ S0(x[(I-15)&0x0f]) + x[I&0x0f] \
, x[I&0x0f] = tm )
#define R(A,B,C,D,E,F,G,H,K,M) do { t0 = SS0(A) + F2(A,B,C); \
t1 = H + SS1(E) \
+ F1(E,F,G) \
+ K \
+ M; \
D += t1; H = t0 + t1; \
} while(0)
while (words < endp)
{
uint32_t tm;
uint32_t t0, t1;
int t;
/* FIXME: see sha1.c for a better implementation. */
for (t = 0; t < 16; t++)
{
x[t] = SWAP (*words);
words++;
}
R( a, b, c, d, e, f, g, h, K( 0), x[ 0] );
R( h, a, b, c, d, e, f, g, K( 1), x[ 1] );
R( g, h, a, b, c, d, e, f, K( 2), x[ 2] );
R( f, g, h, a, b, c, d, e, K( 3), x[ 3] );
R( e, f, g, h, a, b, c, d, K( 4), x[ 4] );
R( d, e, f, g, h, a, b, c, K( 5), x[ 5] );
R( c, d, e, f, g, h, a, b, K( 6), x[ 6] );
R( b, c, d, e, f, g, h, a, K( 7), x[ 7] );
R( a, b, c, d, e, f, g, h, K( 8), x[ 8] );
R( h, a, b, c, d, e, f, g, K( 9), x[ 9] );
R( g, h, a, b, c, d, e, f, K(10), x[10] );
R( f, g, h, a, b, c, d, e, K(11), x[11] );
R( e, f, g, h, a, b, c, d, K(12), x[12] );
R( d, e, f, g, h, a, b, c, K(13), x[13] );
R( c, d, e, f, g, h, a, b, K(14), x[14] );
R( b, c, d, e, f, g, h, a, K(15), x[15] );
R( a, b, c, d, e, f, g, h, K(16), M(16) );
R( h, a, b, c, d, e, f, g, K(17), M(17) );
R( g, h, a, b, c, d, e, f, K(18), M(18) );
R( f, g, h, a, b, c, d, e, K(19), M(19) );
R( e, f, g, h, a, b, c, d, K(20), M(20) );
R( d, e, f, g, h, a, b, c, K(21), M(21) );
R( c, d, e, f, g, h, a, b, K(22), M(22) );
R( b, c, d, e, f, g, h, a, K(23), M(23) );
R( a, b, c, d, e, f, g, h, K(24), M(24) );
R( h, a, b, c, d, e, f, g, K(25), M(25) );
R( g, h, a, b, c, d, e, f, K(26), M(26) );
R( f, g, h, a, b, c, d, e, K(27), M(27) );
R( e, f, g, h, a, b, c, d, K(28), M(28) );
R( d, e, f, g, h, a, b, c, K(29), M(29) );
R( c, d, e, f, g, h, a, b, K(30), M(30) );
R( b, c, d, e, f, g, h, a, K(31), M(31) );
R( a, b, c, d, e, f, g, h, K(32), M(32) );
R( h, a, b, c, d, e, f, g, K(33), M(33) );
R( g, h, a, b, c, d, e, f, K(34), M(34) );
R( f, g, h, a, b, c, d, e, K(35), M(35) );
R( e, f, g, h, a, b, c, d, K(36), M(36) );
R( d, e, f, g, h, a, b, c, K(37), M(37) );
R( c, d, e, f, g, h, a, b, K(38), M(38) );
R( b, c, d, e, f, g, h, a, K(39), M(39) );
R( a, b, c, d, e, f, g, h, K(40), M(40) );
R( h, a, b, c, d, e, f, g, K(41), M(41) );
R( g, h, a, b, c, d, e, f, K(42), M(42) );
R( f, g, h, a, b, c, d, e, K(43), M(43) );
R( e, f, g, h, a, b, c, d, K(44), M(44) );
R( d, e, f, g, h, a, b, c, K(45), M(45) );
R( c, d, e, f, g, h, a, b, K(46), M(46) );
R( b, c, d, e, f, g, h, a, K(47), M(47) );
R( a, b, c, d, e, f, g, h, K(48), M(48) );
R( h, a, b, c, d, e, f, g, K(49), M(49) );
R( g, h, a, b, c, d, e, f, K(50), M(50) );
R( f, g, h, a, b, c, d, e, K(51), M(51) );
R( e, f, g, h, a, b, c, d, K(52), M(52) );
R( d, e, f, g, h, a, b, c, K(53), M(53) );
R( c, d, e, f, g, h, a, b, K(54), M(54) );
R( b, c, d, e, f, g, h, a, K(55), M(55) );
R( a, b, c, d, e, f, g, h, K(56), M(56) );
R( h, a, b, c, d, e, f, g, K(57), M(57) );
R( g, h, a, b, c, d, e, f, K(58), M(58) );
R( f, g, h, a, b, c, d, e, K(59), M(59) );
R( e, f, g, h, a, b, c, d, K(60), M(60) );
R( d, e, f, g, h, a, b, c, K(61), M(61) );
R( c, d, e, f, g, h, a, b, K(62), M(62) );
R( b, c, d, e, f, g, h, a, K(63), M(63) );
a = ctx->state[0] += a;
b = ctx->state[1] += b;
c = ctx->state[2] += c;
d = ctx->state[3] += d;
e = ctx->state[4] += e;
f = ctx->state[5] += f;
g = ctx->state[6] += g;
h = ctx->state[7] += h;
}
}
#endif
/*
* Hey Emacs!
* Local Variables:
* coding: utf-8
* End:
*/

View File

@@ -0,0 +1,121 @@
/* Declarations of functions and data types used for SHA256 and SHA224 sum
library functions.
Copyright (C) 2005-2006, 2008-2022 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef SHA256_H
# define SHA256_H 1
# include <stdio.h>
# include <stdint.h>
# if HAVE_OPENSSL_SHA256
# ifndef OPENSSL_API_COMPAT
# define OPENSSL_API_COMPAT 0x10101000L /* FIXME: Use OpenSSL 1.1+ API. */
# endif
# include <openssl/sha.h>
# endif
# ifdef __cplusplus
extern "C" {
# endif
enum { SHA224_DIGEST_SIZE = 224 / 8 };
enum { SHA256_DIGEST_SIZE = 256 / 8 };
# if HAVE_OPENSSL_SHA256
# define GL_OPENSSL_NAME 224
# include "gl_openssl.h"
# define GL_OPENSSL_NAME 256
# include "gl_openssl.h"
# else
/* Structure to save state of computation between the single steps. */
struct sha256_ctx
{
uint32_t state[8];
uint32_t total[2];
size_t buflen; /* ≥ 0, ≤ 128 */
uint32_t buffer[32]; /* 128 bytes; the first buflen bytes are in use */
};
/* Initialize structure containing state of computation. */
extern void sha256_init_ctx (struct sha256_ctx *ctx);
extern void sha224_init_ctx (struct sha256_ctx *ctx);
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is necessary that LEN is a multiple of 64!!! */
extern void sha256_process_block (const void *buffer, size_t len,
struct sha256_ctx *ctx);
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is NOT required that LEN is a multiple of 64. */
extern void sha256_process_bytes (const void *buffer, size_t len,
struct sha256_ctx *ctx);
/* Process the remaining bytes in the buffer and put result from CTX
in first 32 (28) bytes following RESBUF. The result is always in little
endian byte order, so that a byte-wise output yields to the wanted
ASCII representation of the message digest. */
extern void *sha256_finish_ctx (struct sha256_ctx *ctx, void *restrict resbuf);
extern void *sha224_finish_ctx (struct sha256_ctx *ctx, void *restrict resbuf);
/* Put result from CTX in first 32 (28) bytes following RESBUF. The result is
always in little endian byte order, so that a byte-wise output yields
to the wanted ASCII representation of the message digest. */
extern void *sha256_read_ctx (const struct sha256_ctx *ctx,
void *restrict resbuf);
extern void *sha224_read_ctx (const struct sha256_ctx *ctx,
void *restrict resbuf);
/* Compute SHA256 (SHA224) message digest for LEN bytes beginning at BUFFER.
The result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest. */
extern void *sha256_buffer (const char *buffer, size_t len,
void *restrict resblock);
extern void *sha224_buffer (const char *buffer, size_t len,
void *restrict resblock);
# endif
/* Compute SHA256 (SHA224) message digest for bytes read from STREAM.
STREAM is an open file stream. Regular files are handled more efficiently.
The contents of STREAM from its current position to its end will be read.
The case that the last operation on STREAM was an 'ungetc' is not supported.
The resulting message digest number will be written into the 32 (28) bytes
beginning at RESBLOCK. */
extern int sha256_stream (FILE *stream, void *resblock);
extern int sha224_stream (FILE *stream, void *resblock);
# ifdef __cplusplus
}
# endif
#endif
/*
* Hey Emacs!
* Local Variables:
* coding: utf-8
* End:
*/

View File

@@ -0,0 +1,475 @@
/* sha512.c - Functions to compute SHA512 and SHA384 message digest of files or
memory blocks according to the NIST specification FIPS-180-2.
Copyright (C) 2005-2006, 2008-2022 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by David Madore, considerably copypasting from
Scott G. Miller's sha1.c
*/
/* Specification. */
#if HAVE_OPENSSL_SHA512
# define GL_OPENSSL_INLINE _GL_EXTERN_INLINE
#endif
#include "sha512.h"
#include <stdint.h>
#include <string.h>
#ifdef WORDS_BIGENDIAN
# define SWAP(n) (n)
#else
#include "byteswap.h"
# define SWAP(n) swap_uint64 (n)
#endif
#if ! HAVE_OPENSSL_SHA512
/* This array contains the bytes used to pad the buffer to the next
128-byte boundary. */
static const unsigned char fillbuf[128] = { 0x80, 0 /* , 0, 0, ... */ };
/*
Takes a pointer to a 512 bit block of data (eight 64 bit ints) and
initializes it to the start constants of the SHA512 algorithm. This
must be called before using hash in the call to sha512_hash
*/
void
sha512_init_ctx (struct sha512_ctx *ctx)
{
ctx->state[0] = u64hilo (0x6a09e667, 0xf3bcc908);
ctx->state[1] = u64hilo (0xbb67ae85, 0x84caa73b);
ctx->state[2] = u64hilo (0x3c6ef372, 0xfe94f82b);
ctx->state[3] = u64hilo (0xa54ff53a, 0x5f1d36f1);
ctx->state[4] = u64hilo (0x510e527f, 0xade682d1);
ctx->state[5] = u64hilo (0x9b05688c, 0x2b3e6c1f);
ctx->state[6] = u64hilo (0x1f83d9ab, 0xfb41bd6b);
ctx->state[7] = u64hilo (0x5be0cd19, 0x137e2179);
ctx->total[0] = ctx->total[1] = u64lo (0);
ctx->buflen = 0;
}
void
sha384_init_ctx (struct sha512_ctx *ctx)
{
ctx->state[0] = u64hilo (0xcbbb9d5d, 0xc1059ed8);
ctx->state[1] = u64hilo (0x629a292a, 0x367cd507);
ctx->state[2] = u64hilo (0x9159015a, 0x3070dd17);
ctx->state[3] = u64hilo (0x152fecd8, 0xf70e5939);
ctx->state[4] = u64hilo (0x67332667, 0xffc00b31);
ctx->state[5] = u64hilo (0x8eb44a87, 0x68581511);
ctx->state[6] = u64hilo (0xdb0c2e0d, 0x64f98fa7);
ctx->state[7] = u64hilo (0x47b5481d, 0xbefa4fa4);
ctx->total[0] = ctx->total[1] = u64lo (0);
ctx->buflen = 0;
}
/* Copy the value from V into the memory location pointed to by *CP,
If your architecture allows unaligned access, this is equivalent to
* (__typeof__ (v) *) cp = v */
static void
set_uint64 (char *cp, u64 v)
{
memcpy (cp, &v, sizeof v);
}
/* Put result from CTX in first 64 bytes following RESBUF.
The result must be in little endian byte order. */
void *
sha512_read_ctx (const struct sha512_ctx *ctx, void *resbuf)
{
int i;
char *r = resbuf;
for (i = 0; i < 8; i++)
set_uint64 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i]));
return resbuf;
}
void *
sha384_read_ctx (const struct sha512_ctx *ctx, void *resbuf)
{
int i;
char *r = resbuf;
for (i = 0; i < 6; i++)
set_uint64 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i]));
return resbuf;
}
/* Process the remaining bytes in the internal buffer and the usual
prolog according to the standard and write the result to RESBUF. */
static void
sha512_conclude_ctx (struct sha512_ctx *ctx)
{
/* Take yet unprocessed bytes into account. */
size_t bytes = ctx->buflen;
size_t size = (bytes < 112) ? 128 / 8 : 128 * 2 / 8;
/* Now count remaining bytes. */
ctx->total[0] = u64plus (ctx->total[0], u64lo (bytes));
if (u64lt (ctx->total[0], u64lo (bytes)))
ctx->total[1] = u64plus (ctx->total[1], u64lo (1));
/* Put the 128-bit file length in *bits* at the end of the buffer.
Use set_uint64 rather than a simple assignment, to avoid risk of
unaligned access. */
set_uint64 ((char *) &ctx->buffer[size - 2],
SWAP (u64or (u64shl (ctx->total[1], 3),
u64shr (ctx->total[0], 61))));
set_uint64 ((char *) &ctx->buffer[size - 1],
SWAP (u64shl (ctx->total[0], 3)));
memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 8 - bytes);
/* Process last bytes. */
sha512_process_block (ctx->buffer, size * 8, ctx);
}
void *
sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf)
{
sha512_conclude_ctx (ctx);
return sha512_read_ctx (ctx, resbuf);
}
void *
sha384_finish_ctx (struct sha512_ctx *ctx, void *resbuf)
{
sha512_conclude_ctx (ctx);
return sha384_read_ctx (ctx, resbuf);
}
/* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The
result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest. */
void *
sha512_buffer (const char *buffer, size_t len, void *resblock)
{
struct sha512_ctx ctx;
/* Initialize the computation context. */
sha512_init_ctx (&ctx);
/* Process whole buffer but last len % 128 bytes. */
sha512_process_bytes (buffer, len, &ctx);
/* Put result in desired memory area. */
return sha512_finish_ctx (&ctx, resblock);
}
void *
sha384_buffer (const char *buffer, size_t len, void *resblock)
{
struct sha512_ctx ctx;
/* Initialize the computation context. */
sha384_init_ctx (&ctx);
/* Process whole buffer but last len % 128 bytes. */
sha512_process_bytes (buffer, len, &ctx);
/* Put result in desired memory area. */
return sha384_finish_ctx (&ctx, resblock);
}
void
sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx)
{
/* When we already have some bits in our internal buffer concatenate
both inputs first. */
if (ctx->buflen != 0)
{
size_t left_over = ctx->buflen;
size_t add = 256 - left_over > len ? len : 256 - left_over;
memcpy (&((char *) ctx->buffer)[left_over], buffer, add);
ctx->buflen += add;
if (ctx->buflen > 128)
{
sha512_process_block (ctx->buffer, ctx->buflen & ~127, ctx);
ctx->buflen &= 127;
/* The regions in the following copy operation cannot overlap,
because ctx->buflen < 128 ≤ (left_over + add) & ~127. */
memcpy (ctx->buffer,
&((char *) ctx->buffer)[(left_over + add) & ~127],
ctx->buflen);
}
buffer = (const char *) buffer + add;
len -= add;
}
/* Process available complete blocks. */
if (len >= 128)
{
#if !(_STRING_ARCH_unaligned || _STRING_INLINE_unaligned)
# define UNALIGNED_P(p) ((uintptr_t) (p) % sizeof (u64) != 0)
if (UNALIGNED_P (buffer))
while (len > 128)
{
sha512_process_block (memcpy (ctx->buffer, buffer, 128), 128, ctx);
buffer = (const char *) buffer + 128;
len -= 128;
}
else
#endif
{
sha512_process_block (buffer, len & ~127, ctx);
buffer = (const char *) buffer + (len & ~127);
len &= 127;
}
}
/* Move remaining bytes in internal buffer. */
if (len > 0)
{
size_t left_over = ctx->buflen;
memcpy (&((char *) ctx->buffer)[left_over], buffer, len);
left_over += len;
if (left_over >= 128)
{
sha512_process_block (ctx->buffer, 128, ctx);
left_over -= 128;
/* The regions in the following copy operation cannot overlap,
because left_over ≤ 128. */
memcpy (ctx->buffer, &ctx->buffer[16], left_over);
}
ctx->buflen = left_over;
}
}
/* --- Code below is the primary difference between sha1.c and sha512.c --- */
/* SHA512 round constants */
#define K(I) sha512_round_constants[I]
static u64 const sha512_round_constants[80] = {
u64init (0x428a2f98, 0xd728ae22), u64init (0x71374491, 0x23ef65cd),
u64init (0xb5c0fbcf, 0xec4d3b2f), u64init (0xe9b5dba5, 0x8189dbbc),
u64init (0x3956c25b, 0xf348b538), u64init (0x59f111f1, 0xb605d019),
u64init (0x923f82a4, 0xaf194f9b), u64init (0xab1c5ed5, 0xda6d8118),
u64init (0xd807aa98, 0xa3030242), u64init (0x12835b01, 0x45706fbe),
u64init (0x243185be, 0x4ee4b28c), u64init (0x550c7dc3, 0xd5ffb4e2),
u64init (0x72be5d74, 0xf27b896f), u64init (0x80deb1fe, 0x3b1696b1),
u64init (0x9bdc06a7, 0x25c71235), u64init (0xc19bf174, 0xcf692694),
u64init (0xe49b69c1, 0x9ef14ad2), u64init (0xefbe4786, 0x384f25e3),
u64init (0x0fc19dc6, 0x8b8cd5b5), u64init (0x240ca1cc, 0x77ac9c65),
u64init (0x2de92c6f, 0x592b0275), u64init (0x4a7484aa, 0x6ea6e483),
u64init (0x5cb0a9dc, 0xbd41fbd4), u64init (0x76f988da, 0x831153b5),
u64init (0x983e5152, 0xee66dfab), u64init (0xa831c66d, 0x2db43210),
u64init (0xb00327c8, 0x98fb213f), u64init (0xbf597fc7, 0xbeef0ee4),
u64init (0xc6e00bf3, 0x3da88fc2), u64init (0xd5a79147, 0x930aa725),
u64init (0x06ca6351, 0xe003826f), u64init (0x14292967, 0x0a0e6e70),
u64init (0x27b70a85, 0x46d22ffc), u64init (0x2e1b2138, 0x5c26c926),
u64init (0x4d2c6dfc, 0x5ac42aed), u64init (0x53380d13, 0x9d95b3df),
u64init (0x650a7354, 0x8baf63de), u64init (0x766a0abb, 0x3c77b2a8),
u64init (0x81c2c92e, 0x47edaee6), u64init (0x92722c85, 0x1482353b),
u64init (0xa2bfe8a1, 0x4cf10364), u64init (0xa81a664b, 0xbc423001),
u64init (0xc24b8b70, 0xd0f89791), u64init (0xc76c51a3, 0x0654be30),
u64init (0xd192e819, 0xd6ef5218), u64init (0xd6990624, 0x5565a910),
u64init (0xf40e3585, 0x5771202a), u64init (0x106aa070, 0x32bbd1b8),
u64init (0x19a4c116, 0xb8d2d0c8), u64init (0x1e376c08, 0x5141ab53),
u64init (0x2748774c, 0xdf8eeb99), u64init (0x34b0bcb5, 0xe19b48a8),
u64init (0x391c0cb3, 0xc5c95a63), u64init (0x4ed8aa4a, 0xe3418acb),
u64init (0x5b9cca4f, 0x7763e373), u64init (0x682e6ff3, 0xd6b2b8a3),
u64init (0x748f82ee, 0x5defb2fc), u64init (0x78a5636f, 0x43172f60),
u64init (0x84c87814, 0xa1f0ab72), u64init (0x8cc70208, 0x1a6439ec),
u64init (0x90befffa, 0x23631e28), u64init (0xa4506ceb, 0xde82bde9),
u64init (0xbef9a3f7, 0xb2c67915), u64init (0xc67178f2, 0xe372532b),
u64init (0xca273ece, 0xea26619c), u64init (0xd186b8c7, 0x21c0c207),
u64init (0xeada7dd6, 0xcde0eb1e), u64init (0xf57d4f7f, 0xee6ed178),
u64init (0x06f067aa, 0x72176fba), u64init (0x0a637dc5, 0xa2c898a6),
u64init (0x113f9804, 0xbef90dae), u64init (0x1b710b35, 0x131c471b),
u64init (0x28db77f5, 0x23047d84), u64init (0x32caab7b, 0x40c72493),
u64init (0x3c9ebe0a, 0x15c9bebc), u64init (0x431d67c4, 0x9c100d4c),
u64init (0x4cc5d4be, 0xcb3e42b6), u64init (0x597f299c, 0xfc657e2a),
u64init (0x5fcb6fab, 0x3ad6faec), u64init (0x6c44198c, 0x4a475817),
};
/* Round functions. */
#define F2(A, B, C) u64or (u64and (A, B), u64and (C, u64or (A, B)))
#define F1(E, F, G) u64xor (G, u64and (E, u64xor (F, G)))
/* Process LEN bytes of BUFFER, accumulating context into CTX.
It is assumed that LEN % 128 == 0.
Most of this code comes from GnuPG's cipher/sha1.c. */
void
sha512_process_block (const void *buffer, size_t len, struct sha512_ctx *ctx)
{
u64 const *words = buffer;
u64 const *endp = words + len / sizeof (u64);
u64 x[16];
u64 a = ctx->state[0];
u64 b = ctx->state[1];
u64 c = ctx->state[2];
u64 d = ctx->state[3];
u64 e = ctx->state[4];
u64 f = ctx->state[5];
u64 g = ctx->state[6];
u64 h = ctx->state[7];
u64 lolen = u64size (len);
/* First increment the byte count. FIPS PUB 180-2 specifies the possible
length of the file up to 2^128 bits. Here we only compute the
number of bytes. Do a double word increment. */
ctx->total[0] = u64plus (ctx->total[0], lolen);
ctx->total[1] = u64plus (ctx->total[1],
u64plus (u64size (len >> 31 >> 31 >> 2),
u64lo (u64lt (ctx->total[0], lolen))));
#define S0(x) u64xor (u64rol(x, 63), u64xor (u64rol (x, 56), u64shr (x, 7)))
#define S1(x) u64xor (u64rol (x, 45), u64xor (u64rol (x, 3), u64shr (x, 6)))
#define SS0(x) u64xor (u64rol (x, 36), u64xor (u64rol (x, 30), u64rol (x, 25)))
#define SS1(x) u64xor (u64rol(x, 50), u64xor (u64rol (x, 46), u64rol (x, 23)))
#define M(I) (x[(I) & 15] \
= u64plus (x[(I) & 15], \
u64plus (S1 (x[((I) - 2) & 15]), \
u64plus (x[((I) - 7) & 15], \
S0 (x[((I) - 15) & 15])))))
#define R(A, B, C, D, E, F, G, H, K, M) \
do \
{ \
u64 t0 = u64plus (SS0 (A), F2 (A, B, C)); \
u64 t1 = \
u64plus (H, u64plus (SS1 (E), \
u64plus (F1 (E, F, G), u64plus (K, M)))); \
D = u64plus (D, t1); \
H = u64plus (t0, t1); \
} \
while (0)
while (words < endp)
{
int t;
/* FIXME: see sha1.c for a better implementation. */
for (t = 0; t < 16; t++)
{
x[t] = SWAP (*words);
words++;
}
R( a, b, c, d, e, f, g, h, K( 0), x[ 0] );
R( h, a, b, c, d, e, f, g, K( 1), x[ 1] );
R( g, h, a, b, c, d, e, f, K( 2), x[ 2] );
R( f, g, h, a, b, c, d, e, K( 3), x[ 3] );
R( e, f, g, h, a, b, c, d, K( 4), x[ 4] );
R( d, e, f, g, h, a, b, c, K( 5), x[ 5] );
R( c, d, e, f, g, h, a, b, K( 6), x[ 6] );
R( b, c, d, e, f, g, h, a, K( 7), x[ 7] );
R( a, b, c, d, e, f, g, h, K( 8), x[ 8] );
R( h, a, b, c, d, e, f, g, K( 9), x[ 9] );
R( g, h, a, b, c, d, e, f, K(10), x[10] );
R( f, g, h, a, b, c, d, e, K(11), x[11] );
R( e, f, g, h, a, b, c, d, K(12), x[12] );
R( d, e, f, g, h, a, b, c, K(13), x[13] );
R( c, d, e, f, g, h, a, b, K(14), x[14] );
R( b, c, d, e, f, g, h, a, K(15), x[15] );
R( a, b, c, d, e, f, g, h, K(16), M(16) );
R( h, a, b, c, d, e, f, g, K(17), M(17) );
R( g, h, a, b, c, d, e, f, K(18), M(18) );
R( f, g, h, a, b, c, d, e, K(19), M(19) );
R( e, f, g, h, a, b, c, d, K(20), M(20) );
R( d, e, f, g, h, a, b, c, K(21), M(21) );
R( c, d, e, f, g, h, a, b, K(22), M(22) );
R( b, c, d, e, f, g, h, a, K(23), M(23) );
R( a, b, c, d, e, f, g, h, K(24), M(24) );
R( h, a, b, c, d, e, f, g, K(25), M(25) );
R( g, h, a, b, c, d, e, f, K(26), M(26) );
R( f, g, h, a, b, c, d, e, K(27), M(27) );
R( e, f, g, h, a, b, c, d, K(28), M(28) );
R( d, e, f, g, h, a, b, c, K(29), M(29) );
R( c, d, e, f, g, h, a, b, K(30), M(30) );
R( b, c, d, e, f, g, h, a, K(31), M(31) );
R( a, b, c, d, e, f, g, h, K(32), M(32) );
R( h, a, b, c, d, e, f, g, K(33), M(33) );
R( g, h, a, b, c, d, e, f, K(34), M(34) );
R( f, g, h, a, b, c, d, e, K(35), M(35) );
R( e, f, g, h, a, b, c, d, K(36), M(36) );
R( d, e, f, g, h, a, b, c, K(37), M(37) );
R( c, d, e, f, g, h, a, b, K(38), M(38) );
R( b, c, d, e, f, g, h, a, K(39), M(39) );
R( a, b, c, d, e, f, g, h, K(40), M(40) );
R( h, a, b, c, d, e, f, g, K(41), M(41) );
R( g, h, a, b, c, d, e, f, K(42), M(42) );
R( f, g, h, a, b, c, d, e, K(43), M(43) );
R( e, f, g, h, a, b, c, d, K(44), M(44) );
R( d, e, f, g, h, a, b, c, K(45), M(45) );
R( c, d, e, f, g, h, a, b, K(46), M(46) );
R( b, c, d, e, f, g, h, a, K(47), M(47) );
R( a, b, c, d, e, f, g, h, K(48), M(48) );
R( h, a, b, c, d, e, f, g, K(49), M(49) );
R( g, h, a, b, c, d, e, f, K(50), M(50) );
R( f, g, h, a, b, c, d, e, K(51), M(51) );
R( e, f, g, h, a, b, c, d, K(52), M(52) );
R( d, e, f, g, h, a, b, c, K(53), M(53) );
R( c, d, e, f, g, h, a, b, K(54), M(54) );
R( b, c, d, e, f, g, h, a, K(55), M(55) );
R( a, b, c, d, e, f, g, h, K(56), M(56) );
R( h, a, b, c, d, e, f, g, K(57), M(57) );
R( g, h, a, b, c, d, e, f, K(58), M(58) );
R( f, g, h, a, b, c, d, e, K(59), M(59) );
R( e, f, g, h, a, b, c, d, K(60), M(60) );
R( d, e, f, g, h, a, b, c, K(61), M(61) );
R( c, d, e, f, g, h, a, b, K(62), M(62) );
R( b, c, d, e, f, g, h, a, K(63), M(63) );
R( a, b, c, d, e, f, g, h, K(64), M(64) );
R( h, a, b, c, d, e, f, g, K(65), M(65) );
R( g, h, a, b, c, d, e, f, K(66), M(66) );
R( f, g, h, a, b, c, d, e, K(67), M(67) );
R( e, f, g, h, a, b, c, d, K(68), M(68) );
R( d, e, f, g, h, a, b, c, K(69), M(69) );
R( c, d, e, f, g, h, a, b, K(70), M(70) );
R( b, c, d, e, f, g, h, a, K(71), M(71) );
R( a, b, c, d, e, f, g, h, K(72), M(72) );
R( h, a, b, c, d, e, f, g, K(73), M(73) );
R( g, h, a, b, c, d, e, f, K(74), M(74) );
R( f, g, h, a, b, c, d, e, K(75), M(75) );
R( e, f, g, h, a, b, c, d, K(76), M(76) );
R( d, e, f, g, h, a, b, c, K(77), M(77) );
R( c, d, e, f, g, h, a, b, K(78), M(78) );
R( b, c, d, e, f, g, h, a, K(79), M(79) );
a = ctx->state[0] = u64plus (ctx->state[0], a);
b = ctx->state[1] = u64plus (ctx->state[1], b);
c = ctx->state[2] = u64plus (ctx->state[2], c);
d = ctx->state[3] = u64plus (ctx->state[3], d);
e = ctx->state[4] = u64plus (ctx->state[4], e);
f = ctx->state[5] = u64plus (ctx->state[5], f);
g = ctx->state[6] = u64plus (ctx->state[6], g);
h = ctx->state[7] = u64plus (ctx->state[7], h);
}
}
#endif
/*
* Hey Emacs!
* Local Variables:
* coding: utf-8
* End:
*/

View File

@@ -0,0 +1,124 @@
/* Declarations of functions and data types used for SHA512 and SHA384 sum
library functions.
Copyright (C) 2005-2006, 2008-2022 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef SHA512_H
# define SHA512_H 1
# include <stdio.h>
# include "u64.h"
# if HAVE_OPENSSL_SHA512
# ifndef OPENSSL_API_COMPAT
# define OPENSSL_API_COMPAT 0x10101000L /* FIXME: Use OpenSSL 1.1+ API. */
# endif
# include <openssl/sha.h>
# endif
# ifdef __cplusplus
extern "C" {
# endif
enum { SHA384_DIGEST_SIZE = 384 / 8 };
enum { SHA512_DIGEST_SIZE = 512 / 8 };
# if HAVE_OPENSSL_SHA512
# define GL_OPENSSL_NAME 384
# include "gl_openssl.h"
# define GL_OPENSSL_NAME 512
# include "gl_openssl.h"
# else
/* Structure to save state of computation between the single steps. */
struct sha512_ctx
{
u64 state[8];
u64 total[2];
size_t buflen; /* ≥ 0, ≤ 256 */
u64 buffer[32]; /* 256 bytes; the first buflen bytes are in use */
};
/* Initialize structure containing state of computation. */
extern void sha512_init_ctx (struct sha512_ctx *ctx);
extern void sha384_init_ctx (struct sha512_ctx *ctx);
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is necessary that LEN is a multiple of 128!!! */
extern void sha512_process_block (const void *buffer, size_t len,
struct sha512_ctx *ctx);
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is NOT required that LEN is a multiple of 128. */
extern void sha512_process_bytes (const void *buffer, size_t len,
struct sha512_ctx *ctx);
/* Process the remaining bytes in the buffer and put result from CTX
in first 64 (48) bytes following RESBUF. The result is always in little
endian byte order, so that a byte-wise output yields to the wanted
ASCII representation of the message digest. */
extern void *sha512_finish_ctx (struct sha512_ctx *ctx, void *restrict resbuf);
extern void *sha384_finish_ctx (struct sha512_ctx *ctx, void *restrict resbuf);
/* Put result from CTX in first 64 (48) bytes following RESBUF. The result is
always in little endian byte order, so that a byte-wise output yields
to the wanted ASCII representation of the message digest.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32 bits value. */
extern void *sha512_read_ctx (const struct sha512_ctx *ctx,
void *restrict resbuf);
extern void *sha384_read_ctx (const struct sha512_ctx *ctx,
void *restrict resbuf);
/* Compute SHA512 (SHA384) message digest for LEN bytes beginning at BUFFER.
The result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest. */
extern void *sha512_buffer (const char *buffer, size_t len,
void *restrict resblock);
extern void *sha384_buffer (const char *buffer, size_t len,
void *restrict resblock);
# endif
/* Compute SHA512 (SHA384) message digest for bytes read from STREAM.
STREAM is an open file stream. Regular files are handled more efficiently.
The contents of STREAM from its current position to its end will be read.
The case that the last operation on STREAM was an 'ungetc' is not supported.
The resulting message digest number will be written into the 64 (48) bytes
beginning at RESBLOCK. */
extern int sha512_stream (FILE *stream, void *resblock);
extern int sha384_stream (FILE *stream, void *resblock);
# ifdef __cplusplus
}
# endif
#endif
/*
* Hey Emacs!
* Local Variables:
* coding: utf-8
* End:
*/

View File

@@ -0,0 +1,20 @@
/* uint64_t-like operations that work even on hosts lacking uint64_t
Copyright (C) 2012-2022 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#define _GL_U64_INLINE _GL_EXTERN_INLINE
#include "u64.h"
typedef int dummy;

View File

@@ -0,0 +1,42 @@
/* uint64_t-like operations that work even on hosts lacking uint64_t
Copyright (C) 2006, 2009-2022 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Paul Eggert. */
#include <stdint.h>
#ifndef _GL_U64_INLINE
# define _GL_U64_INLINE _GL_INLINE
#endif
/* Return X rotated left by N bits, where 0 < N < 64. */
#define u64rol(x, n) u64or (u64shl (x, n), u64shr (x, 64 - n))
/* Native implementations are trivial. See below for comments on what
these operations do. */
typedef uint64_t u64;
# define u64hilo(hi, lo) ((u64) (((u64) (hi) << 32) + (lo)))
# define u64init(hi, lo) u64hilo (hi, lo)
# define u64lo(x) ((u64) (x))
# define u64size(x) u64lo (x)
# define u64lt(x, y) ((x) < (y))
# define u64and(x, y) ((x) & (y))
# define u64or(x, y) ((x) | (y))
# define u64xor(x, y) ((x) ^ (y))
# define u64plus(x, y) ((x) + (y))
# define u64shl(x, n) ((x) << (n))
# define u64shr(x, n) ((x) >> (n))

View File

@@ -0,0 +1,16 @@
#include "timezone_utils.h"
int32_t timezone_offset_from_hours(float hours) {
return hours * 3600.0f;
}
uint64_t timezone_offset_apply(uint64_t time, int32_t offset) {
uint64_t for_time_adjusted;
if (offset > 0) {
for_time_adjusted = time - offset;
} else {
for_time_adjusted = time + (-offset);
}
return for_time_adjusted;
}

View File

@@ -0,0 +1,9 @@
#ifndef _TIMEZONE_UTILS_H_
#define _TIMEZONE_UTILS_H_
#include <inttypes.h>
int32_t timezone_offset_from_hours(float hours);
uint64_t timezone_offset_apply(uint64_t time, int32_t offset);
#endif

View File

@@ -1,71 +1,123 @@
#include "totp.h"
#include "sha1.h"
int _timeZoneOffset;
uint32_t _timeStep;
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include "../hmac/hmac-sha1.h"
#include "../hmac/hmac-sha256.h"
#include "../hmac/hmac-sha512.h"
#include "../timezone_utils/timezone_utils.h"
// Init the library with the private key, its length and the timeStep duration
void totp_setup(uint32_t timeStep) {
_timeStep = timeStep;
#define UINT64_GET_BYTE(integer, index) ((integer >> (8 * index)) & 0xFF)
/*
Generates the timeblock for a time in seconds.
Timeblocks are the amount of intervals in a given time. For example,
if 1,000,000 seconds has passed for 30 second intervals, you would get
33,333 timeblocks (intervals), where timeblock++ is effectively +30 seconds.
for_time is a time in seconds to get the current timeblocks
Returns
timeblock given for_time, using data->interval
error, 0
*/
uint64_t totp_timecode(uint8_t interval, uint64_t for_time)
{
return for_time/interval;
}
void totp_set_timezone(float timezone){
_timeZoneOffset = (int)(timezone * 3600.0f);
/*
Converts an integer into an 8 byte array.
out_bytes is the null-terminated output string already allocated
*/
void otp_num_to_bytes(uint64_t integer, uint8_t* out_bytes)
{
out_bytes[7] = UINT64_GET_BYTE(integer, 0);
out_bytes[6] = UINT64_GET_BYTE(integer, 1);
out_bytes[5] = UINT64_GET_BYTE(integer, 2);
out_bytes[4] = UINT64_GET_BYTE(integer, 3);
out_bytes[3] = UINT64_GET_BYTE(integer, 4);
out_bytes[2] = UINT64_GET_BYTE(integer, 5);
out_bytes[1] = UINT64_GET_BYTE(integer, 6);
out_bytes[0] = UINT64_GET_BYTE(integer, 7);
}
// Generate a code, using the number of steps provided
uint32_t totp_get_code_from_steps(uint8_t* hmacKey, uint8_t keyLength, uint32_t steps) {
// STEP 0, map the number of steps in a 8-bytes array (counter value)
uint8_t _byteArray[8];
_byteArray[0] = 0x00;
_byteArray[1] = 0x00;
_byteArray[2] = 0x00;
_byteArray[3] = 0x00;
_byteArray[4] = (uint8_t)((steps >> 24) & 0xFF);
_byteArray[5] = (uint8_t)((steps >> 16) & 0xFF);
_byteArray[6] = (uint8_t)((steps >> 8) & 0XFF);
_byteArray[7] = (uint8_t)((steps & 0XFF));
/*
Generates an OTP (One Time Password).
input is a number used to generate the OTP
out_str is the null-terminated output string already allocated
Returns
OTP code if otp code was successfully generated
0 otherwise
*/
uint32_t otp_generate(TOTP_ALGO algo, uint8_t digits, const uint8_t* plain_secret, uint8_t plain_secret_length, uint64_t input)
{
uint8_t* bytes = malloc(8);
memset(bytes, 0, 8);
uint8_t* hmac = malloc(64);
memset(hmac, 0, 64);
// STEP 1, get the HMAC-SHA1 hash from counter and key
sha1_init_hmac(hmacKey, keyLength);
sha1_write_array(_byteArray, 8);
uint8_t* _hash = sha1_result_hmac();
// STEP 2, apply dynamic truncation to obtain a 4-bytes string
uint32_t _truncatedHash = 0;
uint8_t _offset = _hash[20 - 1] & 0xF;
uint8_t j;
for (j = 0; j < 4; ++j) {
_truncatedHash <<= 8;
_truncatedHash |= _hash[_offset + j];
otp_num_to_bytes(input, bytes);
int hmac_len = (*(algo))(plain_secret, plain_secret_length, bytes, 8, hmac);
if (hmac_len == 0) {
free(hmac);
free(bytes);
return OTP_ERROR;
}
uint64_t offset = (hmac[hmac_len-1] & 0xF);
uint64_t i_code =
((hmac[offset] & 0x7F) << 24 |
(hmac[offset + 1] & 0xFF) << 16 |
(hmac[offset + 2] & 0xFF) << 8 |
(hmac[offset + 3] & 0xFF));
i_code %= (uint64_t) pow(10, digits);
// STEP 3, compute the OTP value
_truncatedHash &= 0x7FFFFFFF; //Disabled
_truncatedHash %= 1000000;
return _truncatedHash;
free(hmac);
free(bytes);
return i_code;
}
uint32_t time_struct_to_timestamp(struct tm time){
//time.tm_mon -= 1;
//time.tm_year -= 1900;
return mktime(&(time)) - 2208988800;
/*
Generates a OTP key using the totp algorithm.
for_time is the time the generated key will be created for
offset is a timeblock adjustment for the generated key
out_str is the null-terminated output string already allocated
Returns
TOTP code if otp code was successfully generated
0 otherwise
*/
uint32_t totp_at(TOTP_ALGO algo, uint8_t digits, const uint8_t* plain_secret, uint8_t plain_secret_length, uint64_t for_time, float timezone, uint8_t interval)
{
uint64_t for_time_adjusted = timezone_offset_apply(for_time, timezone_offset_from_hours(timezone));
return otp_generate(algo, digits, plain_secret, plain_secret_length, totp_timecode(interval, for_time_adjusted));
}
// Generate a code, using the timestamp provided
uint32_t totp_get_code_from_timestamp(uint8_t* hmacKey, uint8_t keyLength, uint32_t timeStamp) {
uint32_t steps;
if (_timeZoneOffset >= 0) {
steps = (timeStamp - _timeZoneOffset) / _timeStep;
} else {
steps = (timeStamp + (-_timeZoneOffset)) / _timeStep;
}
return totp_get_code_from_steps(hmacKey, keyLength, steps);
static int totp_algo_sha1(const uint8_t* key, uint8_t key_length, const uint8_t* input, uint8_t input_length, uint8_t* output) {
hmac_sha1(key, key_length, input, input_length, output);
return HMAC_SHA1_RESULT_SIZE;
}
// Generate a code, using the timestamp provided
uint32_t totp_get_code_from_time_struct(uint8_t* hmacKey, uint8_t keyLength, struct tm time) {
return totp_get_code_from_timestamp(hmacKey, keyLength, time_struct_to_timestamp(time));
static int totp_algo_sha256(const uint8_t* key, uint8_t key_length, const uint8_t* input, uint8_t input_length, uint8_t* output) {
hmac_sha256(key, key_length, input, input_length, output);
return HMAC_SHA256_RESULT_SIZE;
}
static int totp_algo_sha512(const uint8_t* key, uint8_t key_length, const uint8_t* input, uint8_t input_length, uint8_t* output) {
hmac_sha512(key, key_length, input, input_length, output);
return HMAC_SHA512_RESULT_SIZE;
}
const TOTP_ALGO TOTP_ALGO_SHA1 = (TOTP_ALGO)(&totp_algo_sha1);
const TOTP_ALGO TOTP_ALGO_SHA256 = (TOTP_ALGO)(&totp_algo_sha256);
const TOTP_ALGO TOTP_ALGO_SHA512 = (TOTP_ALGO)(&totp_algo_sha512);

View File

@@ -1,11 +1,44 @@
#ifndef _token_h
#define _token_h
#ifndef _TOTP_H_
#define _TOTP_H_
#include <inttypes.h>
#include <sys/time.h>
#include <stdlib.h>
#include <stdint.h>
#define OTP_ERROR (0)
/*
Must compute HMAC using passed arguments,
output as char array through output.
key is secret key.
input is input number.
output is an output buffer of the resulting HMAC operation.
Must return 0 if error, or the length in bytes of the HMAC operation.
*/
typedef int (*TOTP_ALGO)(const uint8_t* key, uint8_t key_length, const uint8_t* input, uint8_t input_length, uint8_t* output);
/*
Computes HMAC using SHA1
*/
extern const TOTP_ALGO TOTP_ALGO_SHA1;
/*
Computes HMAC using SHA256
*/
extern const TOTP_ALGO TOTP_ALGO_SHA256;
/*
Computes HMAC using SHA512
*/
extern const TOTP_ALGO TOTP_ALGO_SHA512;
/*
Computes TOTP token
Returns:
TOTP token on success
0 otherwise
*/
uint32_t totp_at(TOTP_ALGO algo, uint8_t digits, const uint8_t* plain_secret, uint8_t plain_secret_length, uint64_t for_time, float timezone, uint8_t interval);
void totp_setup(uint32_t timeStep);
void totp_set_timezone(float timezone);
uint32_t totp_get_code_from_timestamp(uint8_t* hmacKey, uint8_t keyLength, uint32_t timeStamp);
uint32_t totp_get_code_from_time_struct(uint8_t* hmacKey, uint8_t keyLength, struct tm time);
#endif

View File

@@ -1,10 +1,15 @@
#include "ui_controls.h"
#include "constants.h"
#include "icons.h"
#define TEXT_BOX_HEIGHT 13
#define TEXT_BOX_MARGIN 4
void ui_control_text_box_render(Canvas* const canvas, int8_t y, char* text, bool is_selected) {
if (y < -TEXT_BOX_HEIGHT) {
return;
}
void ui_control_text_box_render(Canvas* const canvas, uint8_t y, char* text, bool is_selected) {
const uint8_t TEXT_BOX_MARGIN = 4;
if (is_selected) {
canvas_draw_rframe(canvas, TEXT_BOX_MARGIN, TEXT_BOX_MARGIN + y, SCREEN_WIDTH - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN, TEXT_BOX_HEIGHT, 0);
canvas_draw_rframe(canvas, TEXT_BOX_MARGIN - 1, TEXT_BOX_MARGIN + y - 1, SCREEN_WIDTH - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN + 2, TEXT_BOX_HEIGHT + 2, 1);
@@ -15,7 +20,28 @@ void ui_control_text_box_render(Canvas* const canvas, uint8_t y, char* text, boo
canvas_draw_str_aligned(canvas, TEXT_BOX_MARGIN + 2, TEXT_BOX_MARGIN + 3 + y, AlignLeft, AlignTop, text);
}
void ui_control_button_render(Canvas* const canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height, char* text, bool is_selected) {
void ui_control_select_render(Canvas* const canvas, int8_t y, char* text, bool is_selected) {
if (y < -TEXT_BOX_HEIGHT) {
return;
}
if (is_selected) {
canvas_draw_rframe(canvas, TEXT_BOX_MARGIN, TEXT_BOX_MARGIN + y, SCREEN_WIDTH - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN, TEXT_BOX_HEIGHT, 0);
canvas_draw_rframe(canvas, TEXT_BOX_MARGIN - 1, TEXT_BOX_MARGIN + y - 1, SCREEN_WIDTH - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN + 2, TEXT_BOX_HEIGHT + 2, 1);
} else {
canvas_draw_rframe(canvas, TEXT_BOX_MARGIN, TEXT_BOX_MARGIN + y, SCREEN_WIDTH - TEXT_BOX_MARGIN - TEXT_BOX_MARGIN, TEXT_BOX_HEIGHT, 1);
}
canvas_draw_str_aligned(canvas, SCREEN_WIDTH_CENTER, TEXT_BOX_MARGIN + 3 + y, AlignCenter, AlignTop, text);
canvas_draw_xbm(canvas, TEXT_BOX_MARGIN + 2, TEXT_BOX_MARGIN + 2 + y, ICON_ARROW_LEFT_8x9_WIDTH, ICON_ARROW_LEFT_8x9_HEIGHT, &ICON_ARROW_LEFT_8x9[0]);
canvas_draw_xbm(canvas, SCREEN_WIDTH - TEXT_BOX_MARGIN - 10, TEXT_BOX_MARGIN + 2 + y, ICON_ARROW_RIGHT_8x9_WIDTH, ICON_ARROW_RIGHT_8x9_HEIGHT, &ICON_ARROW_RIGHT_8x9[0]);
}
void ui_control_button_render(Canvas* const canvas, uint8_t x, int8_t y, uint8_t width, uint8_t height, char* text, bool is_selected) {
if (y < -height) {
return;
}
if (is_selected) {
canvas_draw_rbox(canvas, x, y, width, height, 1);
canvas_set_color(canvas, ColorWhite);

View File

@@ -4,7 +4,8 @@
#include <inttypes.h>
#include <gui/gui.h>
void ui_control_text_box_render(Canvas* const canvas, uint8_t y, char* text, bool is_selected);
void ui_control_button_render(Canvas* const canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height, char* text, bool is_selected);
void ui_control_text_box_render(Canvas* const canvas, int8_t y, char* text, bool is_selected);
void ui_control_button_render(Canvas* const canvas, uint8_t x, int8_t y, uint8_t width, uint8_t height, char* text, bool is_selected);
void ui_control_select_render(Canvas* const canvas, int8_t y, char* text, bool is_selected);
#endif

View File

@@ -10,9 +10,16 @@
#include "../../lib/ui/ui_controls.h"
#include "../generate_token/totp_scene_generate_token.h"
#define TOKEN_ALGO_LIST_LENGTH 3
char* TOKEN_ALGO_LIST[] = { "SHA1", "SHA256", "SHA512" };
#define TOKEN_DIGITS_LIST_LENGTH 2
char* TOKEN_DIGITS_LIST[] = { "6 digits", "8 digits" };
typedef enum {
TokenNameTextBox,
TokenSecretTextBox,
TokenAlgoSelect,
TokenLengthSelect,
ConfirmButton,
} Control;
@@ -28,6 +35,9 @@ typedef struct {
InputTextSceneState* input_state;
uint32_t input_started_at;
int current_token_index;
int32_t screen_y_offset;
TokenHashAlgo algo;
TokenDigitsCount digits_count;
} SceneState;
void totp_scene_add_new_token_init(PluginState* plugin_state) {
@@ -70,6 +80,8 @@ void totp_scene_add_new_token_activate(PluginState* plugin_state, const TokenAdd
scene_state->token_secret_input_context->callback_data = scene_state;
scene_state->token_secret_input_context->callback = on_token_secret_user_comitted;
scene_state->screen_y_offset = 0;
scene_state->input_state = NULL;
if (context == NULL) {
@@ -86,13 +98,26 @@ void totp_scene_add_new_token_render(Canvas* const canvas, PluginState* plugin_s
return;
}
ui_control_text_box_render(canvas, 10 - scene_state->screen_y_offset, scene_state->token_name, scene_state->selected_control == TokenNameTextBox);
ui_control_text_box_render(canvas, 27 - scene_state->screen_y_offset, scene_state->token_secret, scene_state->selected_control == TokenSecretTextBox);
ui_control_select_render(canvas, 44 - scene_state->screen_y_offset, TOKEN_ALGO_LIST[scene_state->algo], scene_state->selected_control == TokenAlgoSelect);
ui_control_select_render(canvas, 63 - scene_state->screen_y_offset, TOKEN_DIGITS_LIST[scene_state->digits_count], scene_state->selected_control == TokenLengthSelect);
ui_control_button_render(canvas, SCREEN_WIDTH_CENTER - 24, 85 - scene_state->screen_y_offset, 48, 13, "Confirm", scene_state->selected_control == ConfirmButton);
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 0, 0, SCREEN_WIDTH, 10);
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, "Add new token");
canvas_set_font(canvas, FontSecondary);
ui_control_text_box_render(canvas, 10, scene_state->token_name, scene_state->selected_control == TokenNameTextBox);
ui_control_text_box_render(canvas, 27, scene_state->token_secret, scene_state->selected_control == TokenSecretTextBox);
ui_control_button_render(canvas, SCREEN_WIDTH_CENTER - 24, 48, 48, 13, "Confirm", scene_state->selected_control == ConfirmButton);
}
void update_screen_y_offset(SceneState* scene_state) {
if (scene_state->selected_control > TokenAlgoSelect) {
scene_state->screen_y_offset = 35;
} else {
scene_state->screen_y_offset = 0;
}
}
bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState* plugin_state) {
@@ -109,16 +134,46 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState
case InputKeyUp:
if (scene_state->selected_control > TokenNameTextBox) {
scene_state->selected_control--;
update_screen_y_offset(scene_state);
}
break;
case InputKeyDown:
if (scene_state->selected_control < ConfirmButton) {
scene_state->selected_control++;
update_screen_y_offset(scene_state);
}
break;
case InputKeyRight:
if (scene_state->selected_control == TokenAlgoSelect) {
if (scene_state->algo < SHA512) {
scene_state->algo++;
} else {
scene_state->algo = SHA1;
}
}
else if (scene_state->selected_control == TokenLengthSelect) {
if (scene_state->digits_count < TOTP_8_DIGITS) {
scene_state->digits_count++;
} else {
scene_state->digits_count = TOTP_6_DIGITS;
}
}
break;
case InputKeyLeft:
if (scene_state->selected_control == TokenAlgoSelect) {
if (scene_state->algo > SHA1) {
scene_state->algo--;
} else {
scene_state->algo = SHA512;
}
}
else if (scene_state->selected_control == TokenLengthSelect) {
if (scene_state->digits_count > TOTP_6_DIGITS) {
scene_state->digits_count--;
} else {
scene_state->digits_count = TOTP_8_DIGITS;
}
}
break;
case InputKeyOk:
switch (scene_state->selected_control) {
@@ -136,12 +191,19 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState
scene_state->input_state = totp_input_text_activate(scene_state->token_secret_input_context);
scene_state->input_started_at = furi_get_tick();
break;
case TokenAlgoSelect:
break;
case TokenLengthSelect:
break;
case ConfirmButton: {
TokenInfo* tokenInfo = malloc(sizeof(TokenInfo));
TokenInfo* tokenInfo = token_info_alloc();
tokenInfo->name = malloc(scene_state->token_name_length + 1);
strcpy(tokenInfo->name, scene_state->token_name);
token_info_set_secret(tokenInfo, scene_state->token_secret, scene_state->token_secret_length, &plugin_state->iv[0]);
tokenInfo->algo = scene_state->algo;
tokenInfo->digits = scene_state->digits_count;
if (plugin_state->tokens_list == NULL) {
plugin_state->tokens_list = list_init_head(tokenInfo);
@@ -154,8 +216,7 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState
FlipperFormat* cfg_file = totp_open_config_file(cfg_storage);
flipper_format_seek_to_end(cfg_file);
flipper_format_write_string_cstr(cfg_file, TOTP_CONFIG_KEY_TOKEN_NAME, tokenInfo->name);
flipper_format_write_hex(cfg_file, TOTP_CONFIG_KEY_TOKEN_SECRET, tokenInfo->token, tokenInfo->token_length);
totp_config_file_save_new_token(cfg_file, tokenInfo);
totp_close_config_file(cfg_file);
totp_close_storage();

View File

@@ -12,10 +12,11 @@
#include "../token_menu/totp_scene_token_menu.h"
#define TOKEN_LIFETIME 30
#define DIGIT_TO_CHAR(digit) ((digit) + '0')
typedef struct {
uint8_t current_token_index;
char last_code[7];
char last_code[9];
char* last_code_name;
bool need_token_update;
uint32_t last_token_gen_time;
@@ -32,9 +33,19 @@ static const NotificationSequence sequence_short_vibro_and_sound = {
NULL,
};
static void i_token_to_str(uint32_t i_token_code, char* str) {
str[6] = '\0';
if (i_token_code == 0 || i_token_code > 999999) {
static void i_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount len) {
if (len == TOTP_8_DIGITS) {
str[8] = '\0';
} else if (len == TOTP_6_DIGITS) {
str[6] = '\0';
}
if (i_token_code == 0) {
if (len > TOTP_6_DIGITS) {
str[7] = '-';
str[6] = '-';
}
str[5] = '-';
str[4] = '-';
str[3] = '-';
@@ -42,20 +53,37 @@ static void i_token_to_str(uint32_t i_token_code, char* str) {
str[1] = '-';
str[0] = '-';
} else {
str[5] = i_token_code % 10 + 0x30;
str[4] = (i_token_code = i_token_code / 10) % 10 + 0x30;
str[3] = (i_token_code = i_token_code / 10) % 10 + 0x30;
str[2] = (i_token_code = i_token_code / 10) % 10 + 0x30;
str[1] = (i_token_code = i_token_code / 10) % 10 + 0x30;
str[0] = (i_token_code = i_token_code / 10) % 10 + 0x30;
if (len == TOTP_8_DIGITS) {
str[7] = DIGIT_TO_CHAR(i_token_code % 10);
str[6] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
str[5] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
} else if (len == TOTP_6_DIGITS) {
str[5] = DIGIT_TO_CHAR(i_token_code % 10);
}
str[4] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
str[3] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
str[2] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
str[1] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
str[0] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
}
}
TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) {
switch (algo) {
case SHA1: return TOTP_ALGO_SHA1;
case SHA256: return TOTP_ALGO_SHA256;
case SHA512: return TOTP_ALGO_SHA512;
}
return NULL;
}
void update_totp_params(PluginState* const plugin_state) {
SceneState* scene_state = (SceneState *)plugin_state->current_scene_state;
if (scene_state->current_token_index < plugin_state->tokens_count) {
TokenInfo* tokenInfo = (TokenInfo*)(list_element_at(plugin_state->tokens_list, scene_state->current_token_index)->data);
TokenInfo* tokenInfo = (TokenInfo *)(list_element_at(plugin_state->tokens_list, scene_state->current_token_index)->data);
scene_state->need_token_update = true;
scene_state->last_code_name = tokenInfo->name;
@@ -64,7 +92,6 @@ void update_totp_params(PluginState* const plugin_state) {
void totp_scene_generate_token_init(PluginState* plugin_state) {
UNUSED(plugin_state);
totp_setup(TOKEN_LIFETIME);
}
void totp_scene_generate_token_activate(PluginState* plugin_state, const GenerateTokenSceneContext* context) {
@@ -79,7 +106,6 @@ void totp_scene_generate_token_activate(PluginState* plugin_state, const Generat
}
scene_state->need_token_update = true;
plugin_state->current_scene_state = scene_state;
totp_set_timezone(plugin_state->timezone_offset);
FURI_LOG_D(LOGGING_TAG, "Timezone set to: %f", (double)plugin_state->timezone_offset);
update_totp_params(plugin_state);
}
@@ -113,7 +139,7 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
furi_hal_crypto_decrypt(tokenInfo->token, key, tokenInfo->token_length);
furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
i_token_to_str(totp_get_code_from_timestamp(key, tokenInfo->token_length, curr_ts), scene_state->last_code);
i_token_to_str(totp_at(get_totp_algo_impl(tokenInfo->algo), token_info_get_digits_count(tokenInfo), key, tokenInfo->token_length, curr_ts, plugin_state->timezone_offset, TOKEN_LIFETIME), scene_state->last_code, tokenInfo->digits);
memset(key, 0, tokenInfo->token_length);
free(key);

View File

@@ -5,6 +5,13 @@
#include "common.h"
#include "../lib/base32/base32.h"
TokenInfo* token_info_alloc() {
TokenInfo* tokenInfo = malloc(sizeof(TokenInfo));
tokenInfo->algo = SHA1;
tokenInfo->digits = TOTP_6_DIGITS;
return tokenInfo;
}
void token_info_free(TokenInfo* token_info) {
if (token_info == NULL) return;
free(token_info->name);
@@ -36,3 +43,12 @@ void token_info_set_secret(TokenInfo* token_info, const char* base32_token_secre
memset(plain_secret, 0, token_info->token_length);
free(plain_secret);
}
uint8_t token_info_get_digits_count(TokenInfo* token_info) {
switch (token_info->digits) {
case TOTP_6_DIGITS: return 6;
case TOTP_8_DIGITS: return 8;
}
return 6;
}

View File

@@ -3,13 +3,28 @@
#include <inttypes.h>
typedef enum {
SHA1,
SHA256,
SHA512
} TokenHashAlgo;
typedef enum {
TOTP_6_DIGITS,
TOTP_8_DIGITS
} TokenDigitsCount;
typedef struct {
uint8_t* token;
uint8_t token_length;
char* name;
TokenHashAlgo algo;
TokenDigitsCount digits;
} TokenInfo;
TokenInfo* token_info_alloc();
void token_info_free(TokenInfo* token_info);
void token_info_set_secret(TokenInfo* token_info, const char* base32_token_secret, uint8_t token_secret_length, uint8_t* iv);
uint8_t token_info_get_digits_count(TokenInfo* token_info);
#endif