2017-04-05 20:56:22 +00:00
|
|
|
//==============================================================================
|
|
|
|
// This file is part of Master Password.
|
|
|
|
// Copyright (c) 2011-2017, Maarten Billemont.
|
2014-12-20 19:30:34 +00:00
|
|
|
//
|
2017-04-05 20:56:22 +00:00
|
|
|
// Master Password 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 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
2014-12-20 19:30:34 +00:00
|
|
|
//
|
2017-04-05 20:56:22 +00:00
|
|
|
// Master Password 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.
|
2014-12-20 19:30:34 +00:00
|
|
|
//
|
2017-04-05 20:56:22 +00:00
|
|
|
// You can find a copy of the GNU General Public License in the
|
|
|
|
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
|
|
|
//==============================================================================
|
2014-12-20 19:30:34 +00:00
|
|
|
|
|
|
|
#include <string.h>
|
2017-07-23 04:48:38 +00:00
|
|
|
#include <ctype.h>
|
2017-08-10 16:30:42 +00:00
|
|
|
#include <errno.h>
|
2014-12-20 19:30:34 +00:00
|
|
|
|
2017-08-27 15:17:45 +00:00
|
|
|
#if MPW_CPERCIVA
|
2014-12-20 19:30:34 +00:00
|
|
|
#include <scrypt/crypto_scrypt.h>
|
2017-04-08 18:25:54 +00:00
|
|
|
#include <scrypt/sha256.h>
|
2017-08-27 15:17:45 +00:00
|
|
|
#elif MPW_SODIUM
|
2017-04-10 15:43:55 +00:00
|
|
|
#include "sodium.h"
|
2017-04-08 18:25:54 +00:00
|
|
|
#endif
|
2017-09-24 00:14:53 +00:00
|
|
|
#define AES_ECB 0
|
|
|
|
#define AES_CBC 1
|
|
|
|
#include "aes.h"
|
2017-04-08 18:25:54 +00:00
|
|
|
|
2014-12-20 19:30:34 +00:00
|
|
|
#include "mpw-util.h"
|
2017-07-28 13:50:26 +00:00
|
|
|
|
2017-08-13 01:57:47 +00:00
|
|
|
#ifdef inf_level
|
2017-07-16 01:13:49 +00:00
|
|
|
int mpw_verbosity = inf_level;
|
2017-08-13 01:57:47 +00:00
|
|
|
#endif
|
2014-12-20 19:30:34 +00:00
|
|
|
|
2017-08-27 11:46:34 +00:00
|
|
|
void mpw_uint16(const uint16_t number, uint8_t buf[2]) {
|
|
|
|
|
|
|
|
buf[0] = (uint8_t)((number >> 8L) & UINT8_MAX);
|
|
|
|
buf[1] = (uint8_t)((number >> 0L) & UINT8_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mpw_uint32(const uint32_t number, uint8_t buf[4]) {
|
|
|
|
|
|
|
|
buf[0] = (uint8_t)((number >> 24) & UINT8_MAX);
|
|
|
|
buf[1] = (uint8_t)((number >> 16) & UINT8_MAX);
|
|
|
|
buf[2] = (uint8_t)((number >> 8L) & UINT8_MAX);
|
|
|
|
buf[3] = (uint8_t)((number >> 0L) & UINT8_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mpw_uint64(const uint64_t number, uint8_t buf[8]) {
|
|
|
|
|
|
|
|
buf[0] = (uint8_t)((number >> 56) & UINT8_MAX);
|
|
|
|
buf[1] = (uint8_t)((number >> 48) & UINT8_MAX);
|
|
|
|
buf[2] = (uint8_t)((number >> 40) & UINT8_MAX);
|
|
|
|
buf[3] = (uint8_t)((number >> 32) & UINT8_MAX);
|
|
|
|
buf[4] = (uint8_t)((number >> 24) & UINT8_MAX);
|
|
|
|
buf[5] = (uint8_t)((number >> 16) & UINT8_MAX);
|
|
|
|
buf[6] = (uint8_t)((number >> 8L) & UINT8_MAX);
|
|
|
|
buf[7] = (uint8_t)((number >> 0L) & UINT8_MAX);
|
|
|
|
}
|
|
|
|
|
2017-08-23 04:01:23 +00:00
|
|
|
bool mpw_push_buf(uint8_t **buffer, size_t *bufferSize, const void *pushBuffer, const size_t pushSize) {
|
2014-12-20 19:30:34 +00:00
|
|
|
|
2017-08-03 03:13:51 +00:00
|
|
|
if (!buffer || !bufferSize || !pushBuffer || !pushSize)
|
2017-08-02 18:26:41 +00:00
|
|
|
return false;
|
2017-08-11 01:29:59 +00:00
|
|
|
if (*bufferSize == (size_t)ERR)
|
2014-12-21 17:37:21 +00:00
|
|
|
// The buffer was marked as broken, it is missing a previous push. Abort to avoid corrupt content.
|
2017-07-16 01:13:49 +00:00
|
|
|
return false;
|
2014-12-20 19:30:34 +00:00
|
|
|
|
2017-08-05 23:04:42 +00:00
|
|
|
if (!mpw_realloc( buffer, bufferSize, pushSize )) {
|
2014-12-21 17:37:21 +00:00
|
|
|
// realloc failed, we can't push. Mark the buffer as broken.
|
2017-08-23 04:01:23 +00:00
|
|
|
mpw_free( buffer, *bufferSize );
|
2017-08-04 13:36:03 +00:00
|
|
|
*bufferSize = (size_t)ERR;
|
2017-07-16 01:13:49 +00:00
|
|
|
return false;
|
2014-12-20 19:30:34 +00:00
|
|
|
}
|
|
|
|
|
2017-08-05 23:04:42 +00:00
|
|
|
uint8_t *bufferOffset = *buffer + *bufferSize - pushSize;
|
|
|
|
memcpy( bufferOffset, pushBuffer, pushSize );
|
2017-07-16 01:13:49 +00:00
|
|
|
return true;
|
2014-12-20 19:30:34 +00:00
|
|
|
}
|
|
|
|
|
2017-08-23 04:01:23 +00:00
|
|
|
bool mpw_push_string(uint8_t **buffer, size_t *bufferSize, const char *pushString) {
|
2014-12-20 19:30:34 +00:00
|
|
|
|
2017-08-02 18:26:41 +00:00
|
|
|
return pushString && mpw_push_buf( buffer, bufferSize, pushString, strlen( pushString ) );
|
2014-12-20 19:30:34 +00:00
|
|
|
}
|
|
|
|
|
2017-08-23 04:01:23 +00:00
|
|
|
bool mpw_string_push(char **string, const char *pushString) {
|
2017-08-03 05:07:19 +00:00
|
|
|
|
2017-08-27 12:53:58 +00:00
|
|
|
if (!string || !pushString)
|
|
|
|
return false;
|
2017-08-05 21:33:45 +00:00
|
|
|
if (!*string)
|
|
|
|
*string = calloc( 1, sizeof( char ) );
|
|
|
|
|
2017-08-03 05:07:19 +00:00
|
|
|
size_t stringLength = strlen( *string );
|
|
|
|
return pushString && mpw_push_buf( (uint8_t **const)string, &stringLength, pushString, strlen( pushString ) + 1 );
|
|
|
|
}
|
|
|
|
|
2017-08-23 04:01:23 +00:00
|
|
|
bool mpw_string_pushf(char **string, const char *pushFormat, ...) {
|
2017-08-03 05:07:19 +00:00
|
|
|
|
|
|
|
va_list args;
|
|
|
|
va_start( args, pushFormat );
|
2017-08-27 12:53:58 +00:00
|
|
|
bool success = mpw_string_push( string, mpw_vstr( pushFormat, args ) );
|
2017-08-03 05:07:19 +00:00
|
|
|
va_end( args );
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2017-08-23 04:01:23 +00:00
|
|
|
bool mpw_push_int(uint8_t **buffer, size_t *bufferSize, const uint32_t pushInt) {
|
2014-12-20 19:30:34 +00:00
|
|
|
|
2017-08-27 11:46:34 +00:00
|
|
|
uint8_t pushBuf[4 /* 32 / 8 */];
|
|
|
|
mpw_uint32( pushInt, pushBuf );
|
|
|
|
return mpw_push_buf( buffer, bufferSize, &pushBuf, sizeof( pushBuf ) );
|
2014-12-20 19:30:34 +00:00
|
|
|
}
|
|
|
|
|
2017-08-23 04:01:23 +00:00
|
|
|
bool __mpw_realloc(const void **buffer, size_t *bufferSize, const size_t deltaSize) {
|
2017-08-05 23:04:42 +00:00
|
|
|
|
|
|
|
if (!buffer)
|
|
|
|
return false;
|
|
|
|
|
2017-08-23 04:01:23 +00:00
|
|
|
void *newBuffer = realloc( (void *)*buffer, (bufferSize? *bufferSize: 0) + deltaSize );
|
2017-08-05 23:04:42 +00:00
|
|
|
if (!newBuffer)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
*buffer = newBuffer;
|
|
|
|
if (bufferSize)
|
|
|
|
*bufferSize += deltaSize;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-09-25 06:53:34 +00:00
|
|
|
void mpw_zero(void *buffer, size_t bufferSize) {
|
|
|
|
|
|
|
|
uint8_t *b = buffer;
|
|
|
|
for (; bufferSize > 0; --bufferSize)
|
2017-09-25 22:34:12 +00:00
|
|
|
*b++ = 0;
|
2017-09-25 06:53:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool __mpw_free(void **buffer, const size_t bufferSize) {
|
2014-12-20 19:30:34 +00:00
|
|
|
|
2017-08-23 04:01:23 +00:00
|
|
|
if (!buffer || !*buffer)
|
2017-07-16 01:13:49 +00:00
|
|
|
return false;
|
|
|
|
|
2017-09-25 06:53:34 +00:00
|
|
|
mpw_zero( *buffer, bufferSize );
|
|
|
|
free( *buffer );
|
2017-08-23 04:01:23 +00:00
|
|
|
*buffer = NULL;
|
|
|
|
|
2017-07-16 01:13:49 +00:00
|
|
|
return true;
|
2014-12-20 19:30:34 +00:00
|
|
|
}
|
|
|
|
|
2017-09-25 06:53:34 +00:00
|
|
|
bool __mpw_free_string(char **string) {
|
2017-08-23 04:01:23 +00:00
|
|
|
|
2017-09-25 06:53:34 +00:00
|
|
|
return *string && __mpw_free( (void **)string, strlen( *string ) );
|
2017-08-23 04:01:23 +00:00
|
|
|
}
|
|
|
|
|
2017-09-25 06:53:34 +00:00
|
|
|
bool __mpw_free_strings(char **strings, ...) {
|
2014-12-22 04:45:19 +00:00
|
|
|
|
2017-08-22 22:38:36 +00:00
|
|
|
bool success = true;
|
|
|
|
|
|
|
|
va_list args;
|
|
|
|
va_start( args, strings );
|
2017-08-23 04:53:14 +00:00
|
|
|
success &= mpw_free_string( strings );
|
2017-09-25 06:53:34 +00:00
|
|
|
for (char **string; (string = va_arg( args, char ** ));)
|
2017-08-23 04:01:23 +00:00
|
|
|
success &= mpw_free_string( string );
|
2017-08-22 22:38:36 +00:00
|
|
|
va_end( args );
|
|
|
|
|
|
|
|
return success;
|
2014-12-22 04:45:19 +00:00
|
|
|
}
|
|
|
|
|
2017-08-10 16:30:42 +00:00
|
|
|
uint8_t const *mpw_kdf_scrypt(const size_t keySize, const char *secret, const uint8_t *salt, const size_t saltSize,
|
2014-12-20 19:30:34 +00:00
|
|
|
uint64_t N, uint32_t r, uint32_t p) {
|
|
|
|
|
2016-07-06 05:16:10 +00:00
|
|
|
if (!secret || !salt)
|
|
|
|
return NULL;
|
|
|
|
|
2014-12-20 19:30:34 +00:00
|
|
|
uint8_t *key = malloc( keySize );
|
|
|
|
if (!key)
|
|
|
|
return NULL;
|
|
|
|
|
2017-08-27 15:17:45 +00:00
|
|
|
#if MPW_CPERCIVA
|
2014-12-20 19:30:34 +00:00
|
|
|
if (crypto_scrypt( (const uint8_t *)secret, strlen( secret ), salt, saltSize, N, r, p, key, keySize ) < 0) {
|
2017-08-23 04:01:23 +00:00
|
|
|
mpw_free( &key, keySize );
|
2014-12-20 19:30:34 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2017-08-27 15:17:45 +00:00
|
|
|
#elif MPW_SODIUM
|
2017-07-28 13:50:26 +00:00
|
|
|
if (crypto_pwhash_scryptsalsa208sha256_ll( (const uint8_t *)secret, strlen( secret ), salt, saltSize, N, r, p, key, keySize ) != 0) {
|
2017-08-23 04:01:23 +00:00
|
|
|
mpw_free( &key, keySize );
|
2017-04-08 18:25:54 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2017-08-05 21:33:45 +00:00
|
|
|
#else
|
|
|
|
#error No crypto support for mpw_scrypt.
|
2017-04-08 18:25:54 +00:00
|
|
|
#endif
|
2014-12-20 19:30:34 +00:00
|
|
|
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
2017-08-10 16:30:42 +00:00
|
|
|
uint8_t const *mpw_kdf_blake2b(const size_t subkeySize, const uint8_t *key, const size_t keySize,
|
|
|
|
const uint8_t *context, const size_t contextSize, const uint64_t id, const char *personal) {
|
|
|
|
|
|
|
|
if (!key || !keySize || !subkeySize) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *subkey = malloc( subkeySize );
|
|
|
|
if (!subkey)
|
|
|
|
return NULL;
|
|
|
|
|
2017-08-27 15:17:45 +00:00
|
|
|
#if MPW_SODIUM
|
2017-08-10 16:45:25 +00:00
|
|
|
if (keySize < crypto_generichash_blake2b_KEYBYTES_MIN || keySize > crypto_generichash_blake2b_KEYBYTES_MAX ||
|
|
|
|
subkeySize < crypto_generichash_blake2b_KEYBYTES_MIN || subkeySize > crypto_generichash_blake2b_KEYBYTES_MAX ||
|
|
|
|
(personal && strlen( personal ) > crypto_generichash_blake2b_PERSONALBYTES)) {
|
2017-08-10 16:30:42 +00:00
|
|
|
errno = EINVAL;
|
|
|
|
free( subkey );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t saltBuf[crypto_generichash_blake2b_SALTBYTES];
|
2017-09-25 06:53:34 +00:00
|
|
|
mpw_zero( saltBuf, sizeof saltBuf );
|
2017-08-27 11:46:34 +00:00
|
|
|
if (id)
|
|
|
|
mpw_uint64( id, saltBuf );
|
2017-08-10 16:30:42 +00:00
|
|
|
|
|
|
|
uint8_t personalBuf[crypto_generichash_blake2b_PERSONALBYTES];
|
2017-09-25 06:53:34 +00:00
|
|
|
mpw_zero( personalBuf, sizeof personalBuf );
|
2017-08-10 16:30:42 +00:00
|
|
|
if (personal && strlen( personal ))
|
|
|
|
memcpy( personalBuf, personal, strlen( personal ) );
|
|
|
|
|
|
|
|
if (crypto_generichash_blake2b_salt_personal( subkey, subkeySize, context, contextSize, key, keySize, saltBuf, personalBuf ) != 0) {
|
2017-08-23 04:01:23 +00:00
|
|
|
mpw_free( &subkey, subkeySize );
|
2017-08-10 16:30:42 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#else
|
2017-08-10 16:48:04 +00:00
|
|
|
#error No crypto support for mpw_kdf_blake2b.
|
2017-08-10 16:30:42 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return subkey;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t const *mpw_hash_hmac_sha256(const uint8_t *key, const size_t keySize, const uint8_t *message, const size_t messageSize) {
|
2017-08-05 21:33:45 +00:00
|
|
|
|
|
|
|
if (!key || !keySize || !message || !messageSize)
|
|
|
|
return NULL;
|
2014-12-20 19:30:34 +00:00
|
|
|
|
2017-08-27 15:17:45 +00:00
|
|
|
#if MPW_CPERCIVA
|
2017-08-05 21:33:45 +00:00
|
|
|
uint8_t *const mac = malloc( 32 );
|
|
|
|
if (!mac)
|
2014-12-20 19:30:34 +00:00
|
|
|
return NULL;
|
|
|
|
|
2017-08-05 21:33:45 +00:00
|
|
|
HMAC_SHA256_Buf( key, keySize, message, messageSize, mac );
|
2017-08-27 15:17:45 +00:00
|
|
|
#elif MPW_SODIUM
|
2017-08-05 21:33:45 +00:00
|
|
|
uint8_t *const mac = malloc( crypto_auth_hmacsha256_BYTES );
|
|
|
|
if (!mac)
|
2017-04-08 18:25:54 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
crypto_auth_hmacsha256_state state;
|
|
|
|
if (crypto_auth_hmacsha256_init( &state, key, keySize ) != 0 ||
|
2017-08-05 21:33:45 +00:00
|
|
|
crypto_auth_hmacsha256_update( &state, message, messageSize ) != 0 ||
|
|
|
|
crypto_auth_hmacsha256_final( &state, mac ) != 0) {
|
2017-08-23 04:01:23 +00:00
|
|
|
mpw_free( &mac, crypto_auth_hmacsha256_BYTES );
|
2017-04-08 18:25:54 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2017-08-05 21:33:45 +00:00
|
|
|
#else
|
|
|
|
#error No crypto support for mpw_hmac_sha256.
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return mac;
|
|
|
|
}
|
2017-04-08 18:25:54 +00:00
|
|
|
|
2017-09-25 22:34:12 +00:00
|
|
|
// We do our best to not fail on odd buf's, eg. non-padded cipher texts.
|
2017-09-24 17:06:19 +00:00
|
|
|
static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t keySize, const uint8_t *buf, size_t *bufSize) {
|
2017-08-05 21:33:45 +00:00
|
|
|
|
2017-09-25 22:34:12 +00:00
|
|
|
if (!key || keySize < 16 || !*bufSize)
|
2017-08-05 21:33:45 +00:00
|
|
|
return NULL;
|
|
|
|
|
2017-09-24 17:06:19 +00:00
|
|
|
// IV = zero
|
2017-09-24 00:14:53 +00:00
|
|
|
uint8_t iv[16];
|
2017-09-25 06:53:34 +00:00
|
|
|
mpw_zero( iv, sizeof iv );
|
2017-09-24 00:14:53 +00:00
|
|
|
|
2017-09-24 17:06:19 +00:00
|
|
|
// Add PKCS#7 padding
|
2017-09-25 22:34:12 +00:00
|
|
|
uint32_t aesSize = ((uint32_t)*bufSize + 15 / 16) * 16; // round up to block size.
|
|
|
|
if (encrypt && !(*bufSize % 16)) // add pad block if plain text fits block size.
|
|
|
|
encrypt += 16;
|
2017-09-24 17:06:19 +00:00
|
|
|
uint8_t aesBuf[aesSize];
|
|
|
|
memcpy( aesBuf, buf, *bufSize );
|
|
|
|
memset( aesBuf + *bufSize, aesSize - *bufSize, aesSize - *bufSize );
|
|
|
|
uint8_t *resultBuf = malloc( aesSize );
|
|
|
|
|
|
|
|
if (encrypt)
|
|
|
|
AES_CBC_encrypt_buffer( resultBuf, aesBuf, aesSize, key, iv );
|
|
|
|
else
|
|
|
|
AES_CBC_decrypt_buffer( resultBuf, aesBuf, aesSize, key, iv );
|
2017-09-25 06:53:34 +00:00
|
|
|
mpw_zero( aesBuf, aesSize );
|
|
|
|
mpw_zero( iv, 16 );
|
2017-09-24 17:06:19 +00:00
|
|
|
|
|
|
|
// Truncate PKCS#7 padding
|
|
|
|
if (encrypt)
|
|
|
|
*bufSize = aesSize;
|
2017-09-25 22:34:12 +00:00
|
|
|
else if (*bufSize % 16 == 0 && resultBuf[aesSize - 1] < 16)
|
2017-09-24 17:06:19 +00:00
|
|
|
*bufSize -= resultBuf[aesSize - 1];
|
2017-09-24 00:14:53 +00:00
|
|
|
|
|
|
|
return resultBuf;
|
2017-08-05 21:33:45 +00:00
|
|
|
}
|
|
|
|
|
2017-09-24 17:06:19 +00:00
|
|
|
uint8_t const *mpw_aes_encrypt(const uint8_t *key, const size_t keySize, const uint8_t *plainBuf, size_t *bufSize) {
|
2017-08-05 21:33:45 +00:00
|
|
|
|
|
|
|
return mpw_aes( true, key, keySize, plainBuf, bufSize );
|
|
|
|
}
|
|
|
|
|
2017-09-24 17:06:19 +00:00
|
|
|
uint8_t const *mpw_aes_decrypt(const uint8_t *key, const size_t keySize, const uint8_t *cipherBuf, size_t *bufSize) {
|
2017-04-08 18:25:54 +00:00
|
|
|
|
2017-08-05 21:33:45 +00:00
|
|
|
return mpw_aes( false, key, keySize, cipherBuf, bufSize );
|
2014-12-20 19:30:34 +00:00
|
|
|
}
|
|
|
|
|
2017-08-30 13:40:37 +00:00
|
|
|
#if UNUSED
|
|
|
|
const char *mpw_hotp(const uint8_t *key, size_t keySize, uint64_t movingFactor, uint8_t digits, uint8_t truncationOffset) {
|
|
|
|
|
|
|
|
// Hash the moving factor with the key.
|
|
|
|
uint8_t counter[8];
|
|
|
|
mpw_uint64( movingFactor, counter );
|
|
|
|
uint8_t hash[20];
|
|
|
|
hmac_sha1( key, keySize, counter, sizeof( counter ), hash );
|
|
|
|
|
|
|
|
// Determine the offset to select OTP bytes from.
|
|
|
|
int offset;
|
|
|
|
if ((truncationOffset >= 0) && (truncationOffset < (sizeof( hash ) - 4)))
|
|
|
|
offset = truncationOffset;
|
|
|
|
else
|
|
|
|
offset = hash[sizeof( hash ) - 1] & 0xf;
|
|
|
|
|
|
|
|
// Select four bytes from the truncation offset.
|
|
|
|
uint32_t otp = 0U
|
|
|
|
| ((hash[offset + 0] & 0x7f) << 24)
|
|
|
|
| ((hash[offset + 1] & 0xff) << 16)
|
|
|
|
| ((hash[offset + 2] & 0xff) << 8)
|
|
|
|
| ((hash[offset + 3] & 0xff) << 0);
|
|
|
|
|
|
|
|
// Render the OTP as `digits` decimal digits.
|
|
|
|
otp %= (int)pow(10, digits);
|
2017-09-25 14:51:14 +00:00
|
|
|
return mpw_strdup( mpw_str( "%0*d", digits, otp ) );
|
2017-08-30 13:40:37 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-08-01 12:31:39 +00:00
|
|
|
MPKeyID mpw_id_buf(const void *buf, size_t length) {
|
|
|
|
|
|
|
|
if (!buf)
|
|
|
|
return "<unset>";
|
2014-12-20 19:30:34 +00:00
|
|
|
|
2017-08-27 15:17:45 +00:00
|
|
|
#if MPW_CPERCIVA
|
2014-12-20 19:30:34 +00:00
|
|
|
uint8_t hash[32];
|
|
|
|
SHA256_Buf( buf, length, hash );
|
2017-08-27 15:17:45 +00:00
|
|
|
#elif MPW_SODIUM
|
2017-04-08 18:25:54 +00:00
|
|
|
uint8_t hash[crypto_hash_sha256_BYTES];
|
|
|
|
crypto_hash_sha256( hash, buf, length );
|
2017-08-05 21:33:45 +00:00
|
|
|
#else
|
|
|
|
#error No crypto support for mpw_id_buf.
|
2017-04-08 18:25:54 +00:00
|
|
|
#endif
|
2017-07-23 04:48:38 +00:00
|
|
|
|
|
|
|
return mpw_hex( hash, sizeof( hash ) / sizeof( uint8_t ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool mpw_id_buf_equals(const char *id1, const char *id2) {
|
|
|
|
|
|
|
|
size_t size = strlen( id1 );
|
|
|
|
if (size != strlen( id2 ))
|
|
|
|
return false;
|
|
|
|
|
2017-07-28 13:50:26 +00:00
|
|
|
for (size_t c = 0; c < size; ++c)
|
|
|
|
if (tolower( id1[c] ) != tolower( id2[c] ))
|
2017-07-23 04:48:38 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
2014-12-20 19:30:34 +00:00
|
|
|
}
|
|
|
|
|
2017-08-03 05:07:19 +00:00
|
|
|
const char *mpw_str(const char *format, ...) {
|
|
|
|
|
|
|
|
va_list args;
|
|
|
|
va_start( args, format );
|
2017-08-27 12:53:58 +00:00
|
|
|
const char *str_str = mpw_vstr( format, args );
|
2017-08-03 05:07:19 +00:00
|
|
|
va_end( args );
|
|
|
|
|
|
|
|
return str_str;
|
|
|
|
}
|
|
|
|
|
2017-08-27 12:53:58 +00:00
|
|
|
const char *mpw_vstr(const char *format, va_list args) {
|
|
|
|
|
|
|
|
// TODO: We should find a way to get rid of this shared storage medium.
|
2017-08-27 13:25:53 +00:00
|
|
|
// TODO: Not thread-safe
|
2017-08-27 12:53:58 +00:00
|
|
|
static char *str_str;
|
2017-08-27 13:25:53 +00:00
|
|
|
static size_t str_str_max;
|
2017-08-29 16:06:40 +00:00
|
|
|
if (!str_str && !(str_str = calloc( str_str_max = 1, sizeof( char ) )))
|
2017-08-27 13:25:53 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
do {
|
2017-08-29 16:06:40 +00:00
|
|
|
va_list args_attempt;
|
|
|
|
va_copy( args_attempt, args );
|
|
|
|
size_t len = (size_t)vsnprintf( str_str, str_str_max, format, args_attempt );
|
|
|
|
va_end( args_attempt );
|
|
|
|
|
2017-08-29 03:48:24 +00:00
|
|
|
if ((int)len < 0)
|
|
|
|
return NULL;
|
2017-08-27 13:25:53 +00:00
|
|
|
if (len < str_str_max)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!mpw_realloc( &str_str, &str_str_max, len - str_str_max + 1 ))
|
|
|
|
return NULL;
|
|
|
|
} while (true);
|
|
|
|
|
|
|
|
return str_str;
|
2017-08-27 12:53:58 +00:00
|
|
|
}
|
2014-12-20 19:30:34 +00:00
|
|
|
|
2015-03-05 22:28:04 +00:00
|
|
|
const char *mpw_hex(const void *buf, size_t length) {
|
2015-02-27 13:49:04 +00:00
|
|
|
|
2017-08-27 12:53:58 +00:00
|
|
|
// TODO: We should find a way to get rid of this shared storage medium.
|
2017-08-27 13:25:53 +00:00
|
|
|
// TODO: Not thread-safe
|
2017-08-27 12:53:58 +00:00
|
|
|
static char **mpw_hex_buf;
|
|
|
|
static unsigned int mpw_hex_buf_i;
|
|
|
|
|
2017-08-03 05:07:19 +00:00
|
|
|
if (!mpw_hex_buf)
|
|
|
|
mpw_hex_buf = calloc( 10, sizeof( char * ) );
|
2015-03-11 21:30:34 +00:00
|
|
|
mpw_hex_buf_i = (mpw_hex_buf_i + 1) % 10;
|
|
|
|
|
2017-08-05 23:04:42 +00:00
|
|
|
if (mpw_realloc( &mpw_hex_buf[mpw_hex_buf_i], NULL, length * 2 + 1 ))
|
2017-08-06 22:56:37 +00:00
|
|
|
for (size_t kH = 0; kH < length; kH++)
|
|
|
|
sprintf( &(mpw_hex_buf[mpw_hex_buf_i][kH * 2]), "%02X", ((const uint8_t *)buf)[kH] );
|
2014-12-20 19:30:34 +00:00
|
|
|
|
2015-03-11 21:30:34 +00:00
|
|
|
return mpw_hex_buf[mpw_hex_buf_i];
|
2015-02-27 13:49:04 +00:00
|
|
|
}
|
2015-03-05 22:28:04 +00:00
|
|
|
|
2015-02-27 13:49:04 +00:00
|
|
|
const char *mpw_hex_l(uint32_t number) {
|
2015-03-05 22:28:04 +00:00
|
|
|
|
2017-08-27 11:46:34 +00:00
|
|
|
uint8_t buf[4 /* 32 / 8 */];
|
|
|
|
buf[0] = (uint8_t)((number >> 24) & UINT8_MAX);
|
|
|
|
buf[1] = (uint8_t)((number >> 16) & UINT8_MAX);
|
|
|
|
buf[2] = (uint8_t)((number >> 8L) & UINT8_MAX);
|
|
|
|
buf[3] = (uint8_t)((number >> 0L) & UINT8_MAX);
|
|
|
|
return mpw_hex( &buf, sizeof( buf ) );
|
2014-12-20 19:30:34 +00:00
|
|
|
}
|
|
|
|
|
2015-02-18 22:32:33 +00:00
|
|
|
/**
|
|
|
|
* @return the amount of bytes used by UTF-8 to encode a single character that starts with the given byte.
|
|
|
|
*/
|
2016-11-03 14:04:18 +00:00
|
|
|
static int mpw_utf8_sizeof(unsigned char utf8Byte) {
|
2015-02-18 22:32:33 +00:00
|
|
|
|
|
|
|
if (!utf8Byte)
|
|
|
|
return 0;
|
|
|
|
if ((utf8Byte & 0x80) == 0)
|
|
|
|
return 1;
|
|
|
|
if ((utf8Byte & 0xC0) != 0xC0)
|
|
|
|
return 0;
|
|
|
|
if ((utf8Byte & 0xE0) == 0xC0)
|
|
|
|
return 2;
|
|
|
|
if ((utf8Byte & 0xF0) == 0xE0)
|
|
|
|
return 3;
|
|
|
|
if ((utf8Byte & 0xF8) == 0xF0)
|
|
|
|
return 4;
|
2015-01-15 22:43:41 +00:00
|
|
|
|
2015-02-18 22:32:33 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-03 14:04:18 +00:00
|
|
|
const size_t mpw_utf8_strlen(const char *utf8String) {
|
2015-02-18 22:32:33 +00:00
|
|
|
|
|
|
|
size_t charlen = 0;
|
|
|
|
char *remainingString = (char *)utf8String;
|
2016-11-03 14:04:18 +00:00
|
|
|
for (int charByteSize; (charByteSize = mpw_utf8_sizeof( (unsigned char)*remainingString )); remainingString += charByteSize)
|
2015-02-18 22:32:33 +00:00
|
|
|
++charlen;
|
|
|
|
|
2015-03-05 22:28:04 +00:00
|
|
|
return charlen;
|
2015-01-15 22:43:41 +00:00
|
|
|
}
|
2017-09-25 14:33:31 +00:00
|
|
|
|
2017-09-25 14:51:14 +00:00
|
|
|
char *mpw_strdup(const char *src) {
|
2017-09-25 22:34:12 +00:00
|
|
|
|
|
|
|
if (!src)
|
|
|
|
return NULL;
|
|
|
|
|
2017-09-25 14:51:14 +00:00
|
|
|
size_t len = strlen( src );
|
|
|
|
char *dst = malloc( len + 1 );
|
|
|
|
memcpy( dst, src, len );
|
|
|
|
dst[len] = '\0';
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2017-09-25 14:33:31 +00:00
|
|
|
char *mpw_strndup(const char *src, size_t max) {
|
2017-09-25 22:34:12 +00:00
|
|
|
|
|
|
|
if (!src)
|
|
|
|
return NULL;
|
|
|
|
|
2017-09-25 14:33:31 +00:00
|
|
|
size_t len = 0;
|
|
|
|
for (; len < max && src[len] != '\0'; ++len);
|
|
|
|
|
|
|
|
char *dst = malloc( len + 1 );
|
|
|
|
memcpy( dst, src, len );
|
|
|
|
dst[len] = '\0';
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
}
|