174 lines
4.7 KiB
C
174 lines
4.7 KiB
C
/****************************************************************************
|
|
* <Novell-copyright>
|
|
* Copyright (c) 2001 Novell, Inc. All Rights Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of version 2 of the GNU General Public License
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* 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, contact Novell, Inc.
|
|
* </Novell-copyright>
|
|
****************************************************************************/
|
|
|
|
#include <argon2.h>
|
|
#include <gcrypt.h>
|
|
#include <liboath/oath.h>
|
|
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <bongoauthsecurity.h>
|
|
|
|
#define TOTP_SECRET_BYTES 20U
|
|
#define CREDENTIAL_BYTES 20U
|
|
#define ARGON_TIME_COST 3U
|
|
#define ARGON_MEMORY_COST 32768U
|
|
#define ARGON_PARALLELISM 1U
|
|
#define ARGON_SALT_BYTES 16U
|
|
#define ARGON_HASH_BYTES 32U
|
|
|
|
static void
|
|
SecureClear(void *buffer, size_t length)
|
|
{
|
|
volatile unsigned char *cursor = buffer;
|
|
|
|
while (length-- > 0)
|
|
*cursor++ = 0;
|
|
}
|
|
|
|
int
|
|
BongoAuthSecurityInit(void)
|
|
{
|
|
if (!gcry_check_version(NULL))
|
|
return -1;
|
|
return oath_init() == OATH_OK ? 0 : -1;
|
|
}
|
|
|
|
void
|
|
BongoAuthSecurityDone(void)
|
|
{
|
|
oath_done();
|
|
}
|
|
|
|
int
|
|
BongoAuthGenerateTotpSecret(char *result, size_t result_size)
|
|
{
|
|
unsigned char random[TOTP_SECRET_BYTES];
|
|
char *encoded = NULL;
|
|
size_t encoded_size = 0;
|
|
int status = -1;
|
|
|
|
if (!result || result_size == 0)
|
|
return -1;
|
|
gcry_randomize(random, sizeof(random), GCRY_STRONG_RANDOM);
|
|
if (oath_base32_encode((const char *)random, sizeof(random), &encoded,
|
|
&encoded_size) == OATH_OK && encoded &&
|
|
encoded_size < result_size) {
|
|
memcpy(result, encoded, encoded_size);
|
|
result[encoded_size] = '\0';
|
|
status = 0;
|
|
}
|
|
if (encoded) {
|
|
SecureClear(encoded, encoded_size);
|
|
free(encoded);
|
|
}
|
|
SecureClear(random, sizeof(random));
|
|
return status;
|
|
}
|
|
|
|
int
|
|
BongoAuthVerifyTotp(const char *secret, const char *otp, time_t now)
|
|
{
|
|
char *decoded = NULL;
|
|
size_t decoded_size = 0;
|
|
int status;
|
|
size_t i;
|
|
|
|
if (!secret || !otp || strlen(otp) != 6)
|
|
return 0;
|
|
for (i = 0; otp[i]; i++)
|
|
if (!isdigit((unsigned char)otp[i]))
|
|
return 0;
|
|
if (oath_base32_decode(secret, strlen(secret), &decoded,
|
|
&decoded_size) != OATH_OK || !decoded)
|
|
return 0;
|
|
status = oath_totp_validate(decoded, decoded_size, now,
|
|
OATH_TOTP_DEFAULT_TIME_STEP_SIZE,
|
|
OATH_TOTP_DEFAULT_START_TIME, 1, otp);
|
|
SecureClear(decoded, decoded_size);
|
|
free(decoded);
|
|
return status >= 0;
|
|
}
|
|
|
|
int
|
|
BongoAuthGenerateCredential(char *result, size_t result_size)
|
|
{
|
|
unsigned char random[CREDENTIAL_BYTES];
|
|
char *encoded = NULL;
|
|
size_t encoded_size = 0;
|
|
size_t i;
|
|
size_t output = 0;
|
|
int status = -1;
|
|
|
|
if (!result || result_size < BONGO_AUTH_CREDENTIAL_SIZE)
|
|
return -1;
|
|
gcry_randomize(random, sizeof(random), GCRY_STRONG_RANDOM);
|
|
if (oath_base32_encode((const char *)random, sizeof(random), &encoded,
|
|
&encoded_size) != OATH_OK || !encoded)
|
|
goto cleanup;
|
|
for (i = 0; i < encoded_size && encoded[i] != '='; i++) {
|
|
if (i > 0 && i % 4 == 0)
|
|
result[output++] = '-';
|
|
result[output++] = (char)tolower((unsigned char)encoded[i]);
|
|
}
|
|
result[output] = '\0';
|
|
status = 0;
|
|
|
|
cleanup:
|
|
if (encoded) {
|
|
SecureClear(encoded, encoded_size);
|
|
free(encoded);
|
|
}
|
|
SecureClear(random, sizeof(random));
|
|
return status;
|
|
}
|
|
|
|
int
|
|
BongoAuthHashCredential(const char *credential, char *result,
|
|
size_t result_size)
|
|
{
|
|
unsigned char salt[ARGON_SALT_BYTES];
|
|
size_t required;
|
|
int status;
|
|
|
|
if (!credential || !credential[0] || !result)
|
|
return -1;
|
|
required = argon2_encodedlen(ARGON_TIME_COST, ARGON_MEMORY_COST,
|
|
ARGON_PARALLELISM, ARGON_SALT_BYTES,
|
|
ARGON_HASH_BYTES, Argon2_id);
|
|
if (result_size < required)
|
|
return -1;
|
|
gcry_randomize(salt, sizeof(salt), GCRY_STRONG_RANDOM);
|
|
status = argon2id_hash_encoded(ARGON_TIME_COST, ARGON_MEMORY_COST,
|
|
ARGON_PARALLELISM, credential,
|
|
strlen(credential), salt, sizeof(salt),
|
|
ARGON_HASH_BYTES, result, result_size);
|
|
SecureClear(salt, sizeof(salt));
|
|
return status == ARGON2_OK ? 0 : -1;
|
|
}
|
|
|
|
int
|
|
BongoAuthVerifyCredential(const char *encoded, const char *credential)
|
|
{
|
|
if (!encoded || !credential)
|
|
return 0;
|
|
return argon2id_verify(encoded, credential, strlen(credential)) == ARGON2_OK;
|
|
}
|