core: add support of TOTP generation/validation (Time-based One-Time Password)

v2.8-utf8proc
Sébastien Helleu 2018-10-27 11:03:03 +02:00
parent 172736989a
commit d0ea801724
13 changed files with 749 additions and 0 deletions

View File

@ -18,6 +18,10 @@ https://weechat.org/files/releasenotes/ReleaseNotes-devel.html[release notes]
[[v2.4]]
== Version 2.4 (under dev)
New features::
* api: add support of Time-based One-Time Password (TOTP), add infos "totp_generate" and "totp_validate"
Bug fixes::
* buflist: fix warning displayed when script buffers.pl is loaded (issue #1274)

View File

@ -389,6 +389,7 @@ WeeChat "core" is located in following directories:
|          test-hook.cpp | Tests: hooks.
|          test-infolist.cpp | Tests: infolists.
|          test-list.cpp | Tests: lists.
|          test-secure.cpp | Tests: secured data.
|          test-string.cpp | Tests: strings.
|          test-url.cpp | Tests: URLs.
|          test-utf8.cpp | Tests: UTF-8.

View File

@ -391,6 +391,7 @@ Le cœur de WeeChat est situé dans les répertoires suivants :
|          test-hook.cpp | Tests : hooks.
|          test-infolist.cpp | Tests : infolists.
|          test-list.cpp | Tests : listes.
|          test-secure.cpp | Tests : données sécurisées.
|          test-string.cpp | Tests : chaînes.
|          test-url.cpp | Tests : URLs.
|          test-utf8.cpp | Tests : UTF-8.

View File

@ -399,6 +399,8 @@ WeeChat "core" は以下のディレクトリに配置されています:
|          test-hook.cpp | Tests: hooks.
|          test-infolist.cpp | テスト: インフォリスト
|          test-list.cpp | テスト: リスト
// TRANSLATION MISSING
|          test-secure.cpp | Tests: secured data.
|          test-string.cpp | テスト: 文字列
|          test-url.cpp | テスト: URL
|          test-utf8.cpp | テスト: UTF-8

View File

@ -25,6 +25,9 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <math.h>
#include <gcrypt.h>
#include "weechat.h"
@ -494,6 +497,195 @@ secure_decrypt_data_not_decrypted (const char *passphrase)
return num_ok;
}
/*
* Generates a Time-based One-Time Password (TOTP), as described
* in the RFC 6238.
*
* Returns:
* 1: OK
* 0: error
*/
int
secure_totp_generate_internal (const char *secret, int length_secret,
uint64_t moving_factor, int digits,
char *result)
{
gcry_md_hd_t hd_md;
uint64_t moving_factor_swapped;
unsigned char *ptr_hash;
char hash[20];
int offset, length;
unsigned long bin_code;
if (gcry_md_open (&hd_md, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC) != 0)
return 0;
if (gcry_md_setkey (hd_md, secret, length_secret) != 0)
{
gcry_md_close (hd_md);
return 0;
}
moving_factor_swapped = (moving_factor >> 56)
| ((moving_factor << 40) & 0x00FF000000000000)
| ((moving_factor << 24) & 0x0000FF0000000000)
| ((moving_factor << 8) & 0x000000FF00000000)
| ((moving_factor >> 8) & 0x00000000FF000000)
| ((moving_factor >> 24) & 0x0000000000FF0000)
| ((moving_factor >> 40) & 0x000000000000FF00)
| (moving_factor << 56);
gcry_md_write (hd_md,
&moving_factor_swapped, sizeof (moving_factor_swapped));
ptr_hash = gcry_md_read (hd_md, GCRY_MD_SHA1);
if (!ptr_hash)
{
gcry_md_close (hd_md);
return 0;
}
memcpy (hash, ptr_hash, sizeof (hash));
gcry_md_close (hd_md);
offset = hash[19] & 0xf;
bin_code = (hash[offset] & 0x7f) << 24
| (hash[offset+1] & 0xff) << 16
| (hash[offset+2] & 0xff) << 8
| (hash[offset+3] & 0xff);
bin_code %= (unsigned long)(pow (10, digits));
length = snprintf (result, digits + 1, "%.*lu", digits, bin_code);
if (length != digits)
return 0;
return 1;
}
/*
* Generates a Time-based One-Time Password (TOTP), as described
* in the RFC 6238.
*
* Returns the password as string, NULL if error.
*
* Note: result must be freed after use.
*/
char *
secure_totp_generate (const char *secret_base32, time_t totp_time, int digits)
{
char *result, *secret;
int length_secret, rc;
uint64_t moving_factor;
secret = NULL;
result = NULL;
if (!secret_base32 || !secret_base32[0]
|| (digits < SECURE_TOTP_MIN_DIGITS)
|| (digits > SECURE_TOTP_MAX_DIGITS))
{
goto error;
}
secret = malloc ((strlen (secret_base32) * 4) + 16 + 1);
if (!secret)
goto error;
length_secret = string_decode_base32 (secret_base32, secret);
if (length_secret < 0)
goto error;
result = malloc (digits + 1);
if (!result)
goto error;
if (totp_time == 0)
totp_time = time (NULL);
moving_factor = totp_time / 30;
rc = secure_totp_generate_internal (secret, length_secret,
moving_factor, digits, result);
if (!rc)
goto error;
free (secret);
return result;
error:
if (secret)
free (secret);
if (result)
free (result);
return NULL;
}
/*
* Validates a Time-based One-Time Password (TOTP).
*
* Returns:
* 1: OTP is OK
* 0: OTP is invalid
*/
int
secure_totp_validate (const char *secret_base32, time_t totp_time, int window,
const char *otp)
{
char *secret, str_otp[16];
int length_secret, digits, rc, otp_ok;
uint64_t i, moving_factor;
secret = NULL;
if (!secret_base32 || !secret_base32[0] || (window < 0) || !otp || !otp[0])
goto error;
digits = strlen (otp);
if ((digits < SECURE_TOTP_MIN_DIGITS) || (digits > SECURE_TOTP_MAX_DIGITS))
goto error;
secret = malloc (strlen (secret_base32) + 1);
if (!secret)
goto error;
length_secret = string_decode_base32 (secret_base32, secret);
if (length_secret < 0)
goto error;
if (totp_time == 0)
totp_time = time (NULL);
moving_factor = totp_time / 30;
otp_ok = 0;
for (i = moving_factor - window; i <= moving_factor + window; i++)
{
rc = secure_totp_generate_internal (secret, length_secret,
i, digits, str_otp);
if (rc && (strcmp (str_otp, otp) == 0))
{
otp_ok = 1;
break;
}
}
free (secret);
return otp_ok;
error:
if (secret)
free (secret);
return 0;
}
/*
* Initializes secured data.
*

View File

@ -24,6 +24,8 @@
#define SECURE_SALT_DEFAULT "WeeChat!"
#define SECURE_DATA_PASSPHRASE_FLAG "__passphrase__"
#define SECURE_SALT_SIZE 8
#define SECURE_TOTP_MIN_DIGITS 4
#define SECURE_TOTP_MAX_DIGITS 10
enum t_secure_config_hash_algo
{
@ -59,6 +61,10 @@ extern int secure_decrypt_data (const char *buffer, int length_buffer,
const char *passphrase, char **decrypted,
int *length_decrypted);
extern int secure_decrypt_data_not_decrypted (const char *passphrase);
extern char *secure_totp_generate (const char *secret, time_t totp_time,
int digits);
extern int secure_totp_validate (const char *secret, time_t totp_time,
int window, const char *otp);
extern int secure_init ();
extern void secure_end ();

View File

@ -2775,6 +2775,163 @@ string_decode_base16 (const char *from, char *to)
return to_length;
}
/*
* Encodes a string in base32.
*
* Argument "length" is number of bytes in "from" to convert (commonly
* strlen(from)).
*
* This function is inspired by:
* https://github.com/google/google-authenticator-libpam/blob/master/src/base32.c
*
* Original copyright:
*
* Copyright 2010 Google Inc.
* Author: Markus Gutschke
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Returns length of string in "*to" (it does not count final \0).
*/
int
string_encode_base32 (const char *from, int length, char *to)
{
unsigned char base32_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
int count, value, next, bits_left, pad, index;
int length_padding[8] = { 0, 0, 6, 0, 4, 3, 0, 2 };
if (!from || !to)
return -1;
count = 0;
if (length > 0)
{
value = from[0];
next = 1;
bits_left = 8;
while ((bits_left > 0) || (next < length))
{
if (bits_left < 5)
{
if (next < length)
{
value <<= 8;
value |= from[next++] & 0xFF;
bits_left += 8;
}
else
{
pad = 5 - bits_left;
value <<= pad;
bits_left += pad;
}
}
index = 0x1F & (value >> (bits_left - 5));
bits_left -= 5;
to[count++] = base32_table[index];
}
}
pad = length_padding[count % 8];
while (pad > 0)
{
to[count++] = '=';
pad--;
}
to[count] = '\0';
return count;
}
/*
* Decodes a base32 string.
*
* This function is inspired by:
* https://github.com/google/google-authenticator-libpam/blob/master/src/base32.c
*
* Original copyright:
*
* Copyright 2010 Google Inc.
* Author: Markus Gutschke
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
* Returns length of string in "*to" (it does not count final \0).
*/
int
string_decode_base32 (const char *from, char *to)
{
const char *ptr_from;
int value, bits_left, count;
unsigned char c;
if (!from || !to)
return -1;
ptr_from = from;
value = 0;
bits_left = 0;
count = 0;
while (ptr_from[0])
{
c = (unsigned char)ptr_from[0];
value <<= 5;
if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')))
{
c = (c & 0x1F) - 1;
}
else if ((c >= '2') && (c <= '7'))
{
c -= '2' - 26;
}
else if (c == '=')
{
/* padding */
break;
}
else
{
/* invalid base32 char */
return -1;
}
value |= c;
bits_left += 5;
if (bits_left >= 8)
{
to[count++] = value >> (bits_left - 8);
bits_left -= 8;
}
ptr_from++;
}
to[count] = '\0';
return count;
}
/*
* Converts 3 bytes of 8 bits in 4 bytes of 6 bits.
*/

View File

@ -107,6 +107,8 @@ extern int string_fprintf (FILE *file, const char *data, ...);
extern char *string_format_size (unsigned long long size);
extern void string_encode_base16 (const char *from, int length, char *to);
extern int string_decode_base16 (const char *from, char *to);
extern int string_encode_base32 (const char *from, int length, char *to);
extern int string_decode_base32 (const char *from, char *to);
extern void string_encode_base64 (const char *from, int length, char *to);
extern int string_decode_base64 (const char *from, char *to);
extern char *string_hex_dump (const char *data, int data_size,

View File

@ -41,6 +41,7 @@
#include "../core/wee-infolist.h"
#include "../core/wee-input.h"
#include "../core/wee-proxy.h"
#include "../core/wee-secure.h"
#include "../core/wee-string.h"
#include "../core/wee-url.h"
#include "../core/wee-util.h"
@ -897,6 +898,149 @@ plugin_api_info_uptime_cb (const void *pointer, void *data,
return NULL;
}
/*
* Returns WeeChat info "totp_generate": generates a Time-based One-Time
* Password (TOTP).
*
* Arguments: "secret,timestamp,digits" (timestamp and digits are optional).
*/
const char *
plugin_api_info_totp_generate_cb (const void *pointer, void *data,
const char *info_name,
const char *arguments)
{
static char value[32];
char **argv, *ptr_secret, *error, *totp;
int argc, digits, length;
long number;
time_t totp_time;
/* make C compiler happy */
(void) pointer;
(void) data;
(void) info_name;
argv = NULL;
totp = NULL;
if (!arguments || !arguments[0])
goto error;
argv = string_split (arguments, ",", 0, 0, &argc);
if (!argv || (argc < 1))
goto error;
ptr_secret = argv[0];
totp_time = 0;
digits = 6;
if (argc > 1)
{
error = NULL;
number = (int)strtol (argv[1], &error, 10);
if (!error || error[0] || (number < 0))
goto error;
totp_time = (time_t)number;
}
if (argc > 2)
{
error = NULL;
number = (int)strtol (argv[2], &error, 10);
if (!error || error[0] || (number < 0))
goto error;
digits = number;
}
totp = secure_totp_generate (ptr_secret, totp_time, digits);
if (!totp)
goto error;
length = snprintf (value, sizeof (value), "%s", totp);
if (length != digits)
goto error;
string_free_split (argv);
free (totp);
return value;
error:
if (argv)
string_free_split (argv);
if (totp)
free (totp);
return NULL;
}
/*
* Returns WeeChat info "totp_validate": validates a Time-based One-Time
* Password (TOTP).
*
* Arguments: "secret,otp,timestamp,window" (timestamp and window are optional).
*/
const char *
plugin_api_info_totp_validate_cb (const void *pointer, void *data,
const char *info_name,
const char *arguments)
{
static char value[16];
char **argv, *ptr_secret, *ptr_otp, *error;
int argc, window, rc;
long number;
time_t totp_time;
/* make C compiler happy */
(void) pointer;
(void) data;
(void) info_name;
argv = NULL;
if (!arguments || !arguments[0])
goto error;
argv = string_split (arguments, ",", 0, 0, &argc);
if (!argv || (argc < 2))
goto error;
ptr_secret = argv[0];
ptr_otp = argv[1];
totp_time = 0;
window = 0;
if (argc > 2)
{
error = NULL;
number = (int)strtol (argv[2], &error, 10);
if (!error || error[0] || (number < 0))
goto error;
totp_time = (time_t)number;
}
if (argc > 3)
{
error = NULL;
number = (int)strtol (argv[3], &error, 10);
if (!error || error[0] || (number < 0))
goto error;
window = number;
}
rc = secure_totp_validate (ptr_secret, totp_time, window, ptr_otp);
snprintf (value, sizeof (value), "%d", rc);
string_free_split (argv);
return value;
error:
if (argv)
string_free_split (argv);
return NULL;
}
/*
* Returns WeeChat infolist "bar".
*
@ -1983,6 +2127,19 @@ plugin_api_init ()
N_("\"days\" (number of days) or \"seconds\" (number of "
"seconds) (optional)"),
&plugin_api_info_uptime_cb, NULL, NULL);
hook_info (NULL, "totp_generate",
N_("generate a Time-based One-Time Password (TOTP)"),
N_("secret (in base32), timestamp (optional, current time by "
"default), number of digits (optional, between 4 and 10, "
"6 is default and recommended value)"),
&plugin_api_info_totp_generate_cb, NULL, NULL);
hook_info (NULL, "totp_validate",
N_("validate a Time-based One-Time Password (TOTP): 1 if TOTP "
"is correct, otherwise 0"),
N_("secret (in base32), one-time password, "
"timestamp (optional), number of OTP after/before to test "
"(optional, 0 by default)"),
&plugin_api_info_totp_validate_cb, NULL, NULL);
/* WeeChat core infolist hooks */
hook_infolist (NULL, "bar",

View File

@ -32,6 +32,7 @@ set(LIB_WEECHAT_UNIT_TESTS_SRC
unit/core/test-hook.cpp
unit/core/test-infolist.cpp
unit/core/test-list.cpp
unit/core/test-secure.cpp
unit/core/test-string.cpp
unit/core/test-url.cpp
unit/core/test-utf8.cpp

View File

@ -62,6 +62,7 @@ IMPORT_TEST_GROUP(CoreHdata);
IMPORT_TEST_GROUP(CoreHook);
IMPORT_TEST_GROUP(CoreInfolist);
IMPORT_TEST_GROUP(CoreList);
IMPORT_TEST_GROUP(CoreSecure);
IMPORT_TEST_GROUP(CoreString);
IMPORT_TEST_GROUP(CoreUrl);
IMPORT_TEST_GROUP(CoreUtf8);

View File

@ -0,0 +1,137 @@
/*
* test-secure.cpp - test secured data functions
*
* Copyright (C) 2018 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat 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.
*
* WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CppUTest/TestHarness.h"
extern "C"
{
#include "src/core/wee-secure.h"
}
#define TOTP_SECRET "secretpasswordbase32"
#define WEE_CHECK_TOTP_GENERATE(__result, __secret, __time, __digits) \
totp = secure_totp_generate (__secret, __time, __digits); \
if (__result == NULL) \
{ \
POINTERS_EQUAL(NULL, totp); \
} \
else \
{ \
STRCMP_EQUAL(__result, totp); \
free (totp); \
}
#define WEE_CHECK_TOTP_VALIDATE(__result, __secret, __time, __window, \
__otp) \
LONGS_EQUAL(__result, secure_totp_validate (__secret, __time, \
__window, __otp));
TEST_GROUP(CoreSecure)
{
};
/*
* Tests functions:
* secure_totp_generate
*/
TEST(CoreSecure, TotpGenerate)
{
char *totp;
/* invalid secret */
WEE_CHECK_TOTP_GENERATE(NULL, NULL, 0, 6);
WEE_CHECK_TOTP_GENERATE(NULL, "", 0, 6);
WEE_CHECK_TOTP_GENERATE(NULL, "not_in_base32_0189", 0, 6);
/* invalid number of digits (must be between 4 and 10) */
WEE_CHECK_TOTP_GENERATE(NULL, TOTP_SECRET, 0, 3);
WEE_CHECK_TOTP_GENERATE(NULL, TOTP_SECRET, 0, 11);
/* TOTP with 6 digits */
WEE_CHECK_TOTP_GENERATE("065486", TOTP_SECRET, 1540624066, 6);
WEE_CHECK_TOTP_GENERATE("640073", TOTP_SECRET, 1540624085, 6);
WEE_CHECK_TOTP_GENERATE("725645", TOTP_SECRET, 1540624110, 6);
/* TOTP with 7 digits */
WEE_CHECK_TOTP_GENERATE("0065486", TOTP_SECRET, 1540624066, 7);
WEE_CHECK_TOTP_GENERATE("6640073", TOTP_SECRET, 1540624085, 7);
WEE_CHECK_TOTP_GENERATE("4725645", TOTP_SECRET, 1540624110, 7);
/* TOTP with 8 digits */
WEE_CHECK_TOTP_GENERATE("40065486", TOTP_SECRET, 1540624066, 8);
WEE_CHECK_TOTP_GENERATE("16640073", TOTP_SECRET, 1540624085, 8);
WEE_CHECK_TOTP_GENERATE("94725645", TOTP_SECRET, 1540624110, 8);
}
/*
* Tests functions:
* secure_totp_validate
*/
TEST(CoreSecure, TotpValidate)
{
/* invalid secret */
WEE_CHECK_TOTP_VALIDATE(0, NULL, 0, 0, "123456");
WEE_CHECK_TOTP_VALIDATE(0, "", 0, 0, "123456");
WEE_CHECK_TOTP_VALIDATE(0, "not_in_base32_0189", 0, 0, "123456");
/* invalid window (must be ≥ 0) */
WEE_CHECK_TOTP_VALIDATE(0, TOTP_SECRET, 0, -1, "123456");
/* invalid OTP */
WEE_CHECK_TOTP_VALIDATE(0, TOTP_SECRET, 0, 0, NULL);
WEE_CHECK_TOTP_VALIDATE(0, TOTP_SECRET, 0, 0, "");
/* validation error (wrong OTP) */
WEE_CHECK_TOTP_VALIDATE(0, TOTP_SECRET, 1540624110, 0, "065486");
WEE_CHECK_TOTP_VALIDATE(0, TOTP_SECRET, 1540624110, 1, "065486");
/* TOTP with 6 digits */
WEE_CHECK_TOTP_VALIDATE(1, TOTP_SECRET, 1540624066, 0, "065486");
WEE_CHECK_TOTP_VALIDATE(1, TOTP_SECRET, 1540624085, 0, "640073");
WEE_CHECK_TOTP_VALIDATE(1, TOTP_SECRET, 1540624110, 0, "725645");
/* TOTP with 7 digits */
WEE_CHECK_TOTP_VALIDATE(1, TOTP_SECRET, 1540624066, 0, "0065486");
WEE_CHECK_TOTP_VALIDATE(1, TOTP_SECRET, 1540624085, 0, "6640073");
WEE_CHECK_TOTP_VALIDATE(1, TOTP_SECRET, 1540624110, 0, "4725645");
/* TOTP with 7 digits */
WEE_CHECK_TOTP_VALIDATE(1, TOTP_SECRET, 1540624066, 0, "40065486");
WEE_CHECK_TOTP_VALIDATE(1, TOTP_SECRET, 1540624085, 0, "16640073");
WEE_CHECK_TOTP_VALIDATE(1, TOTP_SECRET, 1540624110, 0, "94725645");
/* TOTP with 6 digits, using window */
WEE_CHECK_TOTP_VALIDATE(0, TOTP_SECRET, 1540624110, 0, "065486");
WEE_CHECK_TOTP_VALIDATE(0, TOTP_SECRET, 1540624110, 1, "065486");
WEE_CHECK_TOTP_VALIDATE(1, TOTP_SECRET, 1540624110, 2, "065486");
/* TOTP with 7 digits, using window */
WEE_CHECK_TOTP_VALIDATE(0, TOTP_SECRET, 1540624110, 0, "0065486");
WEE_CHECK_TOTP_VALIDATE(0, TOTP_SECRET, 1540624110, 1, "0065486");
WEE_CHECK_TOTP_VALIDATE(1, TOTP_SECRET, 1540624110, 2, "0065486");
/* TOTP with 8 digits, using window */
WEE_CHECK_TOTP_VALIDATE(0, TOTP_SECRET, 1540624110, 0, "40065486");
WEE_CHECK_TOTP_VALIDATE(0, TOTP_SECRET, 1540624110, 1, "40065486");
WEE_CHECK_TOTP_VALIDATE(1, TOTP_SECRET, 1540624110, 2, "40065486");
}

View File

@ -1335,6 +1335,94 @@ TEST(CoreString, FormatSize)
* Tests functions:
* string_encode_base16
* string_decode_base16
*/
TEST(CoreString, Base16)
{
char str[1024];
/* string_encode_base16 */
string_encode_base16 (NULL, 0, NULL);
string_encode_base16 (NULL, 0, str);
string_encode_base16 ("", 0, NULL);
str[0] = 0xAA;
string_encode_base16 ("", -1, str);
BYTES_EQUAL(0x0, str[0]);
str[0] = 0xAA;
string_encode_base16 ("", 0, str);
BYTES_EQUAL(0x0, str[0]);
string_encode_base16 ("abc", 3, str);
STRCMP_EQUAL("616263", str);
/* string_decode_base16 */
LONGS_EQUAL(0, string_decode_base16 (NULL, NULL));
LONGS_EQUAL(0, string_decode_base16 (NULL, str));
LONGS_EQUAL(0, string_decode_base16 ("", NULL));
LONGS_EQUAL(0, string_decode_base16 ("", str));
LONGS_EQUAL(3, string_decode_base16 ("616263", str));
STRCMP_EQUAL("abc", str);
}
/*
* Tests functions:
* string_encode_base32
* string_decode_base32
*/
TEST(CoreString, Base32)
{
int i, length;
char str[1024];
const char *str_base32[][2] =
{ { "", "" },
{ "A", "IE======" },
{ "B", "II======" },
{ "C", "IM======" },
{ "D", "IQ======" },
{ "abc", "MFRGG===" },
{ "This is a test.", "KRUGS4ZANFZSAYJAORSXG5BO" },
{ "This is a test..", "KRUGS4ZANFZSAYJAORSXG5BOFY======" },
{ "This is a test...", "KRUGS4ZANFZSAYJAORSXG5BOFYXA====" },
{ "This is a test....", "KRUGS4ZANFZSAYJAORSXG5BOFYXC4===" },
{ "This is a long long long sentence here...",
"KRUGS4ZANFZSAYJANRXW4ZZANRXW4ZZANRXW4ZZAONSW45DFNZRWKIDIMVZGKLRO"
"FY======" },
{ NULL, NULL } };
/* string_encode_base32 */
LONGS_EQUAL(-1, string_encode_base32 (NULL, 0, NULL));
LONGS_EQUAL(-1, string_encode_base32 (NULL, 0, str));
LONGS_EQUAL(-1, string_encode_base32 ("", 0, NULL));
str[0] = 0xAA;
LONGS_EQUAL(0, string_encode_base32 ("", -1, str));
BYTES_EQUAL(0x0, str[0]);
str[0] = 0xAA;
LONGS_EQUAL(0, string_encode_base32 ("", 0, str));
BYTES_EQUAL(0x0, str[0]);
for (i = 0; str_base32[i][0]; i++)
{
length = strlen (str_base32[i][1]);
LONGS_EQUAL(length, string_encode_base32 (str_base32[i][0],
strlen (str_base32[i][0]),
str));
STRCMP_EQUAL(str_base32[i][1], str);
}
/* string_decode_base32 */
LONGS_EQUAL(-1, string_decode_base32 (NULL, NULL));
LONGS_EQUAL(-1, string_decode_base32 (NULL, str));
LONGS_EQUAL(-1, string_decode_base32 ("", NULL));
LONGS_EQUAL(0, string_decode_base32 ("", str));
for (i = 0; str_base32[i][0]; i++)
{
length = strlen (str_base32[i][0]);
LONGS_EQUAL(length, string_decode_base32 (str_base32[i][1], str));
STRCMP_EQUAL(str_base32[i][0], str);
}
}
/*
* Tests functions:
* string_encode_base64
* string_decode_base64
*/