diff --git a/LICENSE b/LICENSE
index 1e34fe9..7255953 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2023 Cody Tilkins
+Copyright (c) 2024 Cody Tilkins
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/build.bat b/build.bat
index de607ba..8a01706 100644
--- a/build.bat
+++ b/build.bat
@@ -1,17 +1,17 @@
-@echo off
-
-echo Compiling
-gcc -O2 -Wall -shared -c cotp.c otpuri.c
-
-echo Building DLL
-gcc -O2 -Wall -shared -o libcotp.dll cotp.o otpuri.o -lcrypto
-
-echo Building static library
-ar rcs -o libcotp.a cotp.o otpuri.o
-
-echo Building test C application
-gcc -O2 -Wall -L . -I . -o test_c.exe test/main.c libcotp.a -lcrypto
-
-echo Building test C++ application
-g++ -O2 -Wall -L . -I . -o test_cpp.exe test/main.cpp libcotp.a -lcrypto
-
+@echo off
+
+echo Compiling
+gcc -O2 -Wall -shared -c cotp.c otpuri.c
+
+echo Building DLL
+gcc -O2 -Wall -shared -o libcotp.dll cotp.o otpuri.o -lcrypto
+
+echo Building static library
+ar rcs -o libcotp.a cotp.o otpuri.o
+
+echo Building test C application
+gcc -O2 -Wall -L . -I . -o test_c.exe test/main.c libcotp.a -lcrypto
+
+echo Building test C++ application
+g++ -O2 -Wall -L . -I . -o test_cpp.exe test/main.cpp libcotp.a -lcrypto
+
diff --git a/cotp.c b/cotp.c
index fad72bc..8d3d7d0 100644
--- a/cotp.c
+++ b/cotp.c
@@ -1,470 +1,472 @@
-#include "cotp.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <time.h>
-#include <math.h>
-
-#include <openssl/rand.h>
-
-/*
-	Converts an OTPType enum to string.
-	
-	Returns
-			OTPType as string
-		error, 0
-*/
-const char* OTPType_asString(OTPType type)
-{
-	switch (type)
-	{
-		case OTP: return "OTP";
-		case TOTP: return "TOTP";
-		case HOTP: return "HOTP";
-	}
-	return NULL;
-}
-
-/*
-	Initializes an OTPData structure.
-	
-	OTPData is a non-initialized structure
-	base32_secret is a base32 compliant secret string
-	algo is the hmac algorithm implementation for hash and hmac
-	digits is the amount of output numbers for the OTP
-	
-	Only call otp_free(...) if you malloc/calloc'd the OTPData* structure
-	
-	Returns
-			The same pointer passed through data
-		error, 0
-*/
-OTPData* otp_new(OTPData* data, const char* base32_secret, COTP_ALGO algo, uint32_t digits)
-{
-	data->digits = digits ? digits : 6;
-	data->interval = 0;
-	data->count = 0;
-	
-	data->method = OTP;
-	data->algo = algo;
-	data->time = NULL;
-	
-	data->base32_secret = &base32_secret[0];
-	
-	return data;
-}
-
-/*
-	Initializes an OTPData structure. Extends off of otp_new.
-	
-	OTPData is a non-initialized structure
-	base32_secret is a base32 compliant secret string
-	algo is the hmac algorithm implementation for hash and hmac
-	digits is the amount of output numbers for the OTP
-	interval is the amount of time a code is valid for in seconds
-	
-	Only call otp_free(...) if you malloc/calloc'd the OTPData* structure
-	
-	Returns
-			The same pointer passed through data
-		error, 0
-*/
-OTPData* totp_new(OTPData* data, const char* base32_secret, COTP_ALGO algo, COTP_TIME time, uint32_t digits, uint32_t interval)
-{
-	OTPData* tdata = otp_new(data, base32_secret, algo, digits);
-	tdata->interval = interval;
-	tdata->time = time;
-	tdata->method = TOTP;
-	
-	return data;
-}
-
-/*
-	Initializes an OTPData structure.
-	
-	OTPData is a non-initialized structure
-	base32_secret is a base32 compliant secret string
-	algo is the hmac algorithm implementation for hash and hmac
-	digits is the amount of output numbers for the OTP
-	count is the current counter
-	
-	Only call otp_free(...) if you malloc/calloc'd the OTPData* structure
-	
-	Returns
-			A pointer to a new struct OTPData struct
-		error, 0
-*/
-OTPData* hotp_new(OTPData* data, const char* base32_secret, COTP_ALGO algo, uint32_t digits, uint64_t count)
-{
-	OTPData* hdata = otp_new(data, base32_secret, algo, digits);
-	hdata->method = HOTP;
-	hdata->count = count;
-	
-	return data;
-}
-
-
-/*
-	Semantic convenience method.
-	Equivalent to free(data).
-*/
-void otp_free(OTPData* data)
-{
-	free(data);
-}
-
-/*
-	Un-base32's a base32 string stored inside an OTPData.
-	
-	out_str is the null-terminated output string already allocated
-	
-	Returns
-			1 success
-		error, 0
-*/
-COTPRESULT otp_byte_secret(OTPData* data, char* out_str)
-{
-	if (out_str == NULL || strlen(data->base32_secret) % 8 != 0)
-		return OTP_ERROR;
-	
-	size_t base32_length = strlen(data->base32_secret);
-	size_t num_blocks = base32_length / 8;
-	size_t output_length = num_blocks * 5;
-	
-	if (output_length == 0)
-		return OTP_OK;
-	
-	for (size_t i = 0; i < num_blocks; i++)
-	{
-		unsigned int block_values[8] = { 0 };
-		
-		for (int j = 0; j < 8; j++)
-		{
-			char c = data->base32_secret[i * 8 + j];
-			int found = 0;
-			
-			for (int k = 0; k < 32; k++)
-			{
-				if (c == OTP_DEFAULT_BASE32_CHARS[k])
-				{
-					block_values[j] = k;
-					found = 1;
-					break;
-				}
-			}
-			
-			if (!found)
-			{
-				return OTP_ERROR;
-			}
-		}
-		
-		out_str[i * 5] = (block_values[0] << 3) | (block_values[1] >> 2);
-		out_str[i * 5 + 1] = (block_values[1] << 6) | (block_values[2] << 1) | (block_values[3] >> 4);
-		out_str[i * 5 + 2] = (block_values[3] << 4) | (block_values[4] >> 1);
-		out_str[i * 5 + 3] = (block_values[4] << 7) | (block_values[5] << 2) | (block_values[6] >> 3);
-		out_str[i * 5 + 4] = (block_values[6] << 5) | block_values[7];
-	}
-	
-	return OTP_OK;
-}
-
-/*
-	Converts an integer into an 8 byte array.
-	
-	out_str is the null-terminated output string already allocated
-	
-	Returns
-			1 success
-		error, 0
-*/
-COTPRESULT otp_num_to_bytestring(uint64_t integer, char* out_str)
-{
-	if (out_str == NULL)
-		return OTP_ERROR;
-	
-	size_t i = 7;
-	while  (integer != 0)
-	{
-		out_str[i] = integer & 0xFF;
-		i--;
-		integer >>= 8;
-	}
-	
-	return OTP_OK;
-}
-
-/*
-	Generates a valid secured random base32 string.
-	
-	if len <= 0, len = 16
-	
-	len is the (strlen of out_str) - 1
-	chars is the base32 charset
-	out_str is the null-terminated output string already allocated
-	
-	Returns
-			1 on success
-		error, 0
-
-*/
-COTPRESULT otp_random_base32(size_t len, char* out_str)
-{
-	if (out_str == NULL)
-		return OTP_ERROR;
-	
-	len = len > 0 ? len : 16;
-	
-	unsigned char rand_buffer[len];
-	if (RAND_bytes(rand_buffer, len) != 1)
-		return OTP_ERROR;
-	
-	for (size_t i=0; i<len; i++)
-	{
-		out_str[i] = OTP_DEFAULT_BASE32_CHARS[rand_buffer[i] % 32];
-	}
-	
-	return OTP_OK;
-}
-
-
-/*
-	Compares a key against a generated key for
-	  a single specific timeblock.
-	
-	key is an null-terminated input string, a previous OTP generation, must be data->digits+1 long
-	offset is a timeblock adjustment for the generated compare key
-	for_time is the time the generated key will be created for
-	
-	Returns
-			1 success
-			0 no full comparison made
-		error, 0
-*/
-COTPRESULT totp_compare(OTPData* data, const char* key, int64_t offset, uint64_t for_time)
-{
-	char time_str[data->digits+1];
-	memset(time_str, 0, data->digits+1);
-	
-	if (totp_at(data, for_time, offset, time_str) == 0)
-		return OTP_ERROR;
-	
-	for (size_t i=0; i<data->digits; i++)
-	{
-		if (key[i] != time_str[i])
-			return OTP_ERROR;
-	}
-	
-	return OTP_OK;
-}
-
-/*
-	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
-			1 if otp key was successfully generated
-		error, 0
-*/
-COTPRESULT totp_at(OTPData* data, uint64_t for_time, int64_t offset, char* out_str)
-{
-	return otp_generate(data, totp_timecode(data, for_time) + offset, out_str);
-}
-
-/*
-	Generates a OTP key using the totp algorithm with
-	  the current, unsecure time in seconds.
-	
-	out_str is the null-terminated output string already allocated
-	
-	Returns
-			1 if otp key was successfully generated
-		error, 0
-*/
-COTPRESULT totp_now(OTPData* data, char* out_str)
-{
-	return otp_generate(data, totp_timecode(data, data->time()), out_str);
-}
-
-/*
-	Compares a key against a generated key for multiple
-	  timeblocks before and after a specific time.
-	
-	key is an null-terminated input string, a previous OTP generation, must be data->digits+1 long
-	for_time is the time the generated key will be created for
-	valid_window is the number of timeblocks a OTP should be valid for
-	
-	Returns
-			1 success
-		error, 0
-*/
-COTPRESULT totp_verify(OTPData* data, const char* key, uint64_t for_time, int64_t valid_window)
-{
-	if (key == NULL || valid_window < 0)
-		return OTP_ERROR;
-	
-	if (valid_window > 0)
-	{
-		for (int64_t i=-valid_window; i<valid_window+1; i++)
-		{
-			int cmp = totp_compare(data, key, i, for_time);
-			if (cmp == 1)
-				return cmp;
-		}
-		return OTP_ERROR;
-	}
-	
-	return totp_compare(data, key, 0, for_time);
-}
-
-/*
-	Calculate the time in seconds relative to
-	  for_time an OTP is valid for.
-	
-	for_time is a time in seconds
-	valid_window is the number of timeblocks a OTP should be valid for
-	
-	Returns
-			the expiration time for a code using the current OTPData configuration
-*/
-uint64_t totp_valid_until(OTPData* data, uint64_t for_time, int64_t valid_window)
-{
-	return for_time + (data->interval * valid_window);
-}
-
-/*
-	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(OTPData* data, uint64_t for_time)
-{
-	if (data->interval <= 0)
-		return OTP_ERROR;
-	
-	return for_time/data->interval;
-}
-
-
-/*
-	Compares a key against a generated key for a single counter.
-	
-	key is an null-terminated input string, a previous OTP generation, must be data->digits+1 long
-	offset is a timeblock adjustment for the generated compare key
-	for_time is the time the generated key will be created for
-	
-	Returns
-			1 success
-			0 no full comparison made
-		error, 0
-*/
-int hotp_compare(OTPData* data, const char* key, uint64_t counter)
-{
-	if (key == NULL)
-		return OTP_ERROR;
-	
-	char cnt_str[data->digits+1];
-	memset(cnt_str, 0, data->digits+1);
-	
-	if (hotp_at(data, counter, cnt_str) == 0)
-		return OTP_ERROR;
-	
-	for (size_t i=0; i<data->digits; i++)
-	{
-		if (key[i] != cnt_str[i])
-			return OTP_ERROR;
-	}
-	
-	return OTP_OK;
-}
-
-/*
-	Generates a OTP key using the hotp algorithm.
-	
-	counter is the counter the generated key will be created for
-	out_str is the null-terminated output string already allocated
-	
-	Returns
-			1 if otp key was successfully generated
-		error, 0
-*/
-int hotp_at(OTPData* data, uint64_t counter, char* out_str)
-{
-	return otp_generate(data, counter, out_str);
-}
-
-/*
-	Generates a OTP key using the hotp algorithm and advances the counter.
-	
-	out_str is the null-terminated output string already allocated
-	
-	Returns
-			1 if otp key was successfully generated
-		error, 0
-*/
-int hotp_next(OTPData* data, char* out_str)
-{
-	return otp_generate(data, data->count++, out_str);
-}
-
-/*
-	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
-			1 if otp code was successfully generated
-		error, 0
-*/
-COTPRESULT otp_generate(OTPData* data, uint64_t input, char* out_str)
-{
-	if (out_str == NULL)
-		return OTP_ERROR;
-	
-	char byte_string[8+1];
-	memset(byte_string, 0, 8+1);
-	
-	size_t bs_len = (strlen(data->base32_secret)/8)*5 + 1;
-	char byte_secret[bs_len];
-	memset(byte_secret, 0, bs_len);
-	
-	char hmac[64+1];
-	memset(hmac, 0, 64+1);
-	
-	if (otp_num_to_bytestring(input, byte_string) == 0
-			|| otp_byte_secret(data, byte_secret) == 0)
-		return OTP_ERROR;
-	
-	int hmac_len = (*(data->algo))(byte_secret, byte_string, hmac);
-	if (hmac_len == 0)
-		return OTP_ERROR;
-	
-	uint64_t offset = (hmac[hmac_len - 1] & 0xF);
-	uint64_t code =
-		(((hmac[offset] & 0x7F) << 24)
-		| ((hmac[offset+1] & 0xFF) << 16)
-		| ((hmac[offset+2] & 0xFF) << 8)
-		| ((hmac[offset+3] & 0xFF)));
-	
-	static const uint64_t POWERS[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
-	code %= (uint64_t) POWERS[data->digits];
-	
-	sprintf(out_str, "%0*" PRIu64, data->digits, code);
-	
-	return OTP_OK;
-}
-
+#include "cotp.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+
+#include <openssl/rand.h>
+
+/*
+	Converts an OTPType enum to string.
+	
+	Returns
+			OTPType as string
+		error, 0
+*/
+const char* OTPType_asString(OTPType type)
+{
+	switch (type)
+	{
+		case OTP: return "OTP";
+		case TOTP: return "TOTP";
+		case HOTP: return "HOTP";
+	}
+	return NULL;
+}
+
+/*
+	Initializes an OTPData structure.
+	
+	OTPData is a non-initialized structure
+	base32_secret is a base32 compliant secret string
+	algo is the hmac algorithm implementation for hash and hmac
+	digits is the amount of output numbers for the OTP
+	
+	Only call otp_free(...) if you malloc/calloc'd the OTPData* structure
+	
+	Returns
+			The same pointer passed through data
+		error, 0
+*/
+OTPData* otp_new(OTPData* data, const char* base32_secret, COTP_ALGO algo, uint32_t digits)
+{
+	data->digits = digits ? digits : 6;
+	data->interval = 0;
+	data->count = 0;
+	
+	data->method = OTP;
+	data->algo = algo;
+	data->time = NULL;
+	
+	data->base32_secret = &base32_secret[0];
+	
+	return data;
+}
+
+/*
+	Initializes an OTPData structure. Extends off of otp_new.
+	
+	OTPData is a non-initialized structure
+	base32_secret is a base32 compliant secret string
+	algo is the hmac algorithm implementation for hash and hmac
+	digits is the amount of output numbers for the OTP
+	interval is the amount of time a code is valid for in seconds
+	
+	Only call otp_free(...) if you malloc/calloc'd the OTPData* structure
+	
+	Returns
+			The same pointer passed through data
+		error, 0
+*/
+OTPData* totp_new(OTPData* data, const char* base32_secret, COTP_ALGO algo, COTP_TIME time, uint32_t digits, uint32_t interval)
+{
+	OTPData* tdata = otp_new(data, base32_secret, algo, digits);
+	tdata->interval = interval;
+	tdata->time = time;
+	tdata->method = TOTP;
+	
+	return data;
+}
+
+/*
+	Initializes an OTPData structure.
+	
+	OTPData is a non-initialized structure
+	base32_secret is a base32 compliant secret string
+	algo is the hmac algorithm implementation for hash and hmac
+	digits is the amount of output numbers for the OTP
+	count is the current counter
+	
+	Only call otp_free(...) if you malloc/calloc'd the OTPData* structure
+	
+	Returns
+			A pointer to a new struct OTPData struct
+		error, 0
+*/
+OTPData* hotp_new(OTPData* data, const char* base32_secret, COTP_ALGO algo, uint32_t digits, uint64_t count)
+{
+	OTPData* hdata = otp_new(data, base32_secret, algo, digits);
+	hdata->method = HOTP;
+	hdata->count = count;
+	
+	return data;
+}
+
+
+/*
+	Semantic convenience method.
+	Equivalent to free(data).
+*/
+void otp_free(OTPData* data)
+{
+	free(data);
+}
+
+/*
+	Un-base32's a base32 string stored inside an OTPData.
+	
+	out_str is the null-terminated output string already allocated
+	
+	Returns
+			1 success
+		error, 0
+*/
+COTPRESULT otp_byte_secret(OTPData* data, char* out_str)
+{
+	if (out_str == NULL || strlen(data->base32_secret) % 8 != 0)
+		return OTP_ERROR;
+	
+	size_t base32_length = strlen(data->base32_secret);
+	size_t num_blocks = base32_length / 8;
+	size_t output_length = num_blocks * 5;
+	
+	if (output_length == 0)
+		return OTP_OK;
+	
+	for (size_t i = 0; i < num_blocks; i++)
+	{
+		unsigned int block_values[8] = { 0 };
+		
+		for (int j = 0; j < 8; j++)
+		{
+			char c = data->base32_secret[i * 8 + j];
+			if (c == '=')
+				break;
+				
+			int found = 0;
+			for (int k = 0; k < 32; k++)
+			{
+				if (c == OTP_DEFAULT_BASE32_CHARS[k])
+				{
+					block_values[j] = k;
+					found = 1;
+					break;
+				}
+			}
+			
+			if (!found)
+			{
+				return OTP_ERROR;
+			}
+		}
+		
+		out_str[i * 5] = (block_values[0] << 3) | (block_values[1] >> 2);
+		out_str[i * 5 + 1] = (block_values[1] << 6) | (block_values[2] << 1) | (block_values[3] >> 4);
+		out_str[i * 5 + 2] = (block_values[3] << 4) | (block_values[4] >> 1);
+		out_str[i * 5 + 3] = (block_values[4] << 7) | (block_values[5] << 2) | (block_values[6] >> 3);
+		out_str[i * 5 + 4] = (block_values[6] << 5) | block_values[7];
+	}
+	
+	return OTP_OK;
+}
+
+/*
+	Converts an integer into an 8 byte array.
+	
+	out_str is the null-terminated output string already allocated
+	
+	Returns
+			1 success
+		error, 0
+*/
+COTPRESULT otp_num_to_bytestring(uint64_t integer, char* out_str)
+{
+	if (out_str == NULL)
+		return OTP_ERROR;
+	
+	size_t i = 7;
+	while  (integer != 0)
+	{
+		out_str[i] = integer & 0xFF;
+		i--;
+		integer >>= 8;
+	}
+	
+	return OTP_OK;
+}
+
+/*
+	Generates a valid secured random base32 string.
+	
+	if len <= 0, len = 16
+	
+	len is the (strlen of out_str) - 1
+	chars is the base32 charset
+	out_str is the null-terminated output string already allocated
+	
+	Returns
+			1 on success
+		error, 0
+
+*/
+COTPRESULT otp_random_base32(size_t len, char* out_str)
+{
+	if (out_str == NULL)
+		return OTP_ERROR;
+	
+	len = len > 0 ? len : 16;
+	
+	unsigned char rand_buffer[len];
+	if (RAND_bytes(rand_buffer, len) != 1)
+		return OTP_ERROR;
+	
+	for (size_t i=0; i<len; i++)
+	{
+		out_str[i] = OTP_DEFAULT_BASE32_CHARS[rand_buffer[i] % 32];
+	}
+	
+	return OTP_OK;
+}
+
+
+/*
+	Compares a key against a generated key for
+	  a single specific timeblock.
+	
+	key is an null-terminated input string, a previous OTP generation, must be data->digits+1 long
+	offset is a timeblock adjustment for the generated compare key
+	for_time is the time the generated key will be created for
+	
+	Returns
+			1 success
+			0 no full comparison made
+		error, 0
+*/
+COTPRESULT totp_compare(OTPData* data, const char* key, int64_t offset, uint64_t for_time)
+{
+	char time_str[data->digits+1];
+	memset(time_str, 0, data->digits+1);
+	
+	if (totp_at(data, for_time, offset, time_str) == 0)
+		return OTP_ERROR;
+	
+	for (size_t i=0; i<data->digits; i++)
+	{
+		if (key[i] != time_str[i])
+			return OTP_ERROR;
+	}
+	
+	return OTP_OK;
+}
+
+/*
+	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
+			1 if otp key was successfully generated
+		error, 0
+*/
+COTPRESULT totp_at(OTPData* data, uint64_t for_time, int64_t offset, char* out_str)
+{
+	return otp_generate(data, totp_timecode(data, for_time) + offset, out_str);
+}
+
+/*
+	Generates a OTP key using the totp algorithm with
+	  the current, unsecure time in seconds.
+	
+	out_str is the null-terminated output string already allocated
+	
+	Returns
+			1 if otp key was successfully generated
+		error, 0
+*/
+COTPRESULT totp_now(OTPData* data, char* out_str)
+{
+	return otp_generate(data, totp_timecode(data, data->time()), out_str);
+}
+
+/*
+	Compares a key against a generated key for multiple
+	  timeblocks before and after a specific time.
+	
+	key is an null-terminated input string, a previous OTP generation, must be data->digits+1 long
+	for_time is the time the generated key will be created for
+	valid_window is the number of timeblocks a OTP should be valid for
+	
+	Returns
+			1 success
+		error, 0
+*/
+COTPRESULT totp_verify(OTPData* data, const char* key, uint64_t for_time, int64_t valid_window)
+{
+	if (key == NULL || valid_window < 0)
+		return OTP_ERROR;
+	
+	if (valid_window > 0)
+	{
+		for (int64_t i=-valid_window; i<valid_window+1; i++)
+		{
+			int cmp = totp_compare(data, key, i, for_time);
+			if (cmp == 1)
+				return cmp;
+		}
+		return OTP_ERROR;
+	}
+	
+	return totp_compare(data, key, 0, for_time);
+}
+
+/*
+	Calculate the time in seconds relative to
+	  for_time an OTP is valid for.
+	
+	for_time is a time in seconds
+	valid_window is the number of timeblocks a OTP should be valid for
+	
+	Returns
+			the expiration time for a code using the current OTPData configuration
+*/
+uint64_t totp_valid_until(OTPData* data, uint64_t for_time, int64_t valid_window)
+{
+	return for_time + (data->interval * valid_window);
+}
+
+/*
+	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(OTPData* data, uint64_t for_time)
+{
+	if (data->interval <= 0)
+		return OTP_ERROR;
+	
+	return for_time/data->interval;
+}
+
+
+/*
+	Compares a key against a generated key for a single counter.
+	
+	key is an null-terminated input string, a previous OTP generation, must be data->digits+1 long
+	offset is a timeblock adjustment for the generated compare key
+	for_time is the time the generated key will be created for
+	
+	Returns
+			1 success
+			0 no full comparison made
+		error, 0
+*/
+int hotp_compare(OTPData* data, const char* key, uint64_t counter)
+{
+	if (key == NULL)
+		return OTP_ERROR;
+	
+	char cnt_str[data->digits+1];
+	memset(cnt_str, 0, data->digits+1);
+	
+	if (hotp_at(data, counter, cnt_str) == 0)
+		return OTP_ERROR;
+	
+	for (size_t i=0; i<data->digits; i++)
+	{
+		if (key[i] != cnt_str[i])
+			return OTP_ERROR;
+	}
+	
+	return OTP_OK;
+}
+
+/*
+	Generates a OTP key using the hotp algorithm.
+	
+	counter is the counter the generated key will be created for
+	out_str is the null-terminated output string already allocated
+	
+	Returns
+			1 if otp key was successfully generated
+		error, 0
+*/
+int hotp_at(OTPData* data, uint64_t counter, char* out_str)
+{
+	return otp_generate(data, counter, out_str);
+}
+
+/*
+	Generates a OTP key using the hotp algorithm and advances the counter.
+	
+	out_str is the null-terminated output string already allocated
+	
+	Returns
+			1 if otp key was successfully generated
+		error, 0
+*/
+int hotp_next(OTPData* data, char* out_str)
+{
+	return otp_generate(data, data->count++, out_str);
+}
+
+/*
+	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
+			1 if otp code was successfully generated
+		error, 0
+*/
+COTPRESULT otp_generate(OTPData* data, uint64_t input, char* out_str)
+{
+	if (out_str == NULL)
+		return OTP_ERROR;
+	
+	char byte_string[8+1];
+	memset(byte_string, 0, 8+1);
+	
+	size_t bs_len = (strlen(data->base32_secret)/8)*5;
+	char byte_secret[bs_len + 1];
+	memset(byte_secret, 0, bs_len + 1);
+	
+	char hmac[64+1];
+	memset(hmac, 0, 64+1);
+	
+	if (otp_num_to_bytestring(input, byte_string) == 0
+			|| otp_byte_secret(data, byte_secret) == 0)
+		return OTP_ERROR;
+	
+	int hmac_len = (*(data->algo))(byte_secret, bs_len, byte_string, hmac);
+	if (hmac_len == 0)
+		return OTP_ERROR;
+	
+	uint64_t offset = (hmac[hmac_len - 1] & 0xF);
+	uint64_t code =
+		(((hmac[offset] & 0x7F) << 24)
+		| ((hmac[offset+1] & 0xFF) << 16)
+		| ((hmac[offset+2] & 0xFF) << 8)
+		| ((hmac[offset+3] & 0xFF)));
+	
+	static const uint64_t POWERS[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
+	code %= (uint64_t) POWERS[data->digits];
+	
+	sprintf(out_str, "%0*" PRIu64, data->digits, code);
+	
+	return OTP_OK;
+}
+
diff --git a/cotp.h b/cotp.h
index 4a59e8e..0aca353 100644
--- a/cotp.h
+++ b/cotp.h
@@ -1,116 +1,115 @@
-#pragma once
-
-#include <stdlib.h>
-#include <stdint.h>
-
-
-// OTPRESULT can either be 1 (success) or 0 (error)
-typedef int COTPRESULT;
-
-#define OTP_OK		((COTPRESULT) 1)
-#define OTP_ERROR	((COTPRESULT) 0)
-
-
-/*
-	Default characters used in BASE32 digests.
-	For use with otp_random_base32()
-*/
-static const char OTP_DEFAULT_BASE32_CHARS[32] =
-{
-	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
-	'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
-	'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5',
-	'6', '7'
-};
-
-
-/*
-	Used for differentiation on which
-	  method you are using. Necessary
-	  when you go to generate a URI.
-*/
-typedef enum OTPType
-{
-	OTP, TOTP, HOTP
-} OTPType;
-
-const char* OTPType_asString(OTPType type);
-
-
-/*
-	Must compute HMAC using passed arguments,
-	  output as char array through output.
-	
-	key is base32 secret key.
-	input is input number as string.
-	output is an output char buffer of the resulting HMAC operation.
-	
-	Must return 0 if error, or the length in bytes of the HMAC operation.
-*/
-typedef int (*COTP_ALGO)(const char* key, const char* input, char* output);
-
-/*
-	Must return the current time in seconds.
-*/
-typedef uint64_t (*COTP_TIME)();
-
-
-/*
-	Holds data for use by the cotp module.
-	
-	If you know what you are doing,
-		feel free to initialize this yourself.
-*/
-typedef struct OTPData
-{
-	uint32_t digits;
-	uint32_t interval; // TOTP exclusive
-	uint64_t count;
-	
-	OTPType method;
-	COTP_ALGO algo;
-	COTP_TIME time;
-	
-	const char* base32_secret;
-} OTPData;
-
-
-/*
-	Struct initialization functions
-*/
-OTPData* otp_new(OTPData* data, const char* base32_secret, COTP_ALGO algo, uint32_t digits);
-OTPData* totp_new(OTPData* data, const char* base32_secret, COTP_ALGO algo, COTP_TIME time, uint32_t digits, uint32_t interval);
-OTPData* hotp_new(OTPData* data, const char* base32_secret, COTP_ALGO algo, uint32_t digits, uint64_t count);
-
-/*
-	OTP free function
-*/
-void otp_free(OTPData* data);
-
-/*
-	OTP functions
-*/
-COTPRESULT otp_generate(OTPData* data, uint64_t input, char* out_str);
-COTPRESULT otp_byte_secret(OTPData* data, char* out_str);
-COTPRESULT otp_num_to_bytestring(uint64_t integer, char* out_str);
-COTPRESULT otp_random_base32(size_t len, char* out_str);
-
-
-/*
-	TOTP functions
-*/
-COTPRESULT totp_compare(OTPData* data, const char* key, int64_t offset, uint64_t for_time);
-COTPRESULT totp_at(OTPData* data, uint64_t for_time, int64_t offset, char* out_str);
-COTPRESULT totp_now(OTPData* data, char* out_str);
-COTPRESULT totp_verify(OTPData* data, const char* key, uint64_t for_time, int64_t valid_window);
-uint64_t totp_valid_until(OTPData* data, uint64_t for_time, int64_t valid_window);
-uint64_t totp_timecode(OTPData* data, uint64_t for_time);
-
-
-/*
-	HOTP functions
-*/
-COTPRESULT hotp_compare(OTPData* data, const char* key, uint64_t counter);
-COTPRESULT hotp_at(OTPData* data, uint64_t counter, char* out_str);
-COTPRESULT hotp_next(OTPData* data, char* out_str);
-
+#pragma once
+
+#include <stdlib.h>
+#include <stdint.h>
+
+
+// OTPRESULT can either be 1 (success) or 0 (error)
+typedef int COTPRESULT;
+
+#define OTP_OK		((COTPRESULT) 1)
+#define OTP_ERROR	((COTPRESULT) 0)
+
+
+/*
+	Default characters used in BASE32 digests.
+	For use with otp_random_base32()
+*/
+static const char OTP_DEFAULT_BASE32_CHARS[32] =
+{
+	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+	'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+	'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5',
+	'6', '7'
+};
+
+
+/*
+	Used for differentiation on which
+	  method you are using. Necessary
+	  when you go to generate a URI.
+*/
+typedef enum OTPType
+{
+	OTP, TOTP, HOTP
+} OTPType;
+
+const char* OTPType_asString(OTPType type);
+
+
+/*
+	Must compute HMAC using passed arguments,
+	  output as char array through output.
+	
+	key is base32 secret key.
+	input is input number as string.
+	output is an output char buffer of the resulting HMAC operation.
+	
+	Must return 0 if error, or the length in bytes of the HMAC operation.
+*/
+typedef int (*COTP_ALGO)(const char* key, int key_length, const char* input, char* output);
+
+/*
+	Must return the current time in seconds.
+*/
+typedef uint64_t (*COTP_TIME)();
+
+
+/*
+	Holds data for use by the cotp module.
+	
+	If you know what you are doing,
+		feel free to initialize this yourself.
+*/
+typedef struct OTPData
+{
+	uint32_t digits;
+	uint32_t interval; // TOTP exclusive
+	uint64_t count;
+	
+	OTPType method;
+	COTP_ALGO algo;
+	COTP_TIME time;
+	
+	const char* base32_secret;
+} OTPData;
+
+
+/*
+	Struct initialization functions
+*/
+OTPData* otp_new(OTPData* data, const char* base32_secret, COTP_ALGO algo, uint32_t digits);
+OTPData* totp_new(OTPData* data, const char* base32_secret, COTP_ALGO algo, COTP_TIME time, uint32_t digits, uint32_t interval);
+OTPData* hotp_new(OTPData* data, const char* base32_secret, COTP_ALGO algo, uint32_t digits, uint64_t count);
+
+/*
+	OTP free function
+*/
+void otp_free(OTPData* data);
+
+/*
+	OTP functions
+*/
+COTPRESULT otp_generate(OTPData* data, uint64_t input, char* out_str);
+COTPRESULT otp_byte_secret(OTPData* data, char* out_str);
+COTPRESULT otp_num_to_bytestring(uint64_t integer, char* out_str);
+COTPRESULT otp_random_base32(size_t len, char* out_str);
+
+
+/*
+	TOTP functions
+*/
+COTPRESULT totp_compare(OTPData* data, const char* key, int64_t offset, uint64_t for_time);
+COTPRESULT totp_at(OTPData* data, uint64_t for_time, int64_t offset, char* out_str);
+COTPRESULT totp_now(OTPData* data, char* out_str);
+COTPRESULT totp_verify(OTPData* data, const char* key, uint64_t for_time, int64_t valid_window);
+uint64_t totp_valid_until(OTPData* data, uint64_t for_time, int64_t valid_window);
+uint64_t totp_timecode(OTPData* data, uint64_t for_time);
+
+
+/*
+	HOTP functions
+*/
+COTPRESULT hotp_compare(OTPData* data, const char* key, uint64_t counter);
+COTPRESULT hotp_at(OTPData* data, uint64_t counter, char* out_str);
+COTPRESULT hotp_next(OTPData* data, char* out_str);
diff --git a/cotp.hpp b/cotp.hpp
index 8b895de..7522f07 100644
--- a/cotp.hpp
+++ b/cotp.hpp
@@ -1,191 +1,191 @@
-
-#pragma once
-
-#if defined(__cplusplus)
-
-extern "C"
-{
-	#include "cotp.h"
-	#include "otpuri.h"
-}
-
-#include <cstdint>
-
-namespace COTP
-{
-	
-	class OTP
-	{
-		protected:
-			OTPData* data;
-			
-		public:
-			OTP(OTPData* data, const char* base32_secret, COTP_ALGO algo, uint32_t digits)
-			{
-				this->data = otp_new(data, base32_secret, algo, digits);
-			}
-			
-			~OTP()
-			{
-				data = nullptr;
-			}
-			
-			COTPRESULT generate(int64_t input, char* output)
-			{
-				return otp_generate(data, input, output);
-			}
-			
-			COTPRESULT byte_secret(char* out_str)
-			{
-				return otp_byte_secret(data, out_str);
-			}
-			
-			COTPRESULT num_to_bytestring(uint64_t integer, char* out_str)
-			{
-				return otp_num_to_bytestring(integer, out_str);
-			}
-			
-			size_t uri_strlen(const char* issuer, const char* name, const char* digest)
-			{
-				return otpuri_strlen(data, issuer, name, digest);
-			}
-			
-			COTPRESULT build_uri(const char* issuer, const char* name, const char* digest, char* output)
-			{
-				return otpuri_build_uri(data, issuer, name, digest, output);
-			}
-			
-			OTPData* data_struct()
-			{
-				return data;
-			}
-			
-			static COTPRESULT random_base32(size_t len, char* out_str)
-			{
-				return otp_random_base32(len, out_str);
-			}
-			
-	};
-
-	class TOTP
-	{
-		protected:
-			OTPData* data;
-			
-		public:
-			TOTP(OTPData* data, const char* base32_secret, COTP_ALGO algo, COTP_TIME time, uint32_t digits, uint32_t interval)
-			{
-				this->data = totp_new(data, base32_secret, algo, time, digits, interval);
-			}
-			
-			~TOTP()
-			{
-				data = nullptr;
-			}
-			
-			COTPRESULT at(uint64_t for_time, uint64_t offset, char* out_str)
-			{
-				return totp_at(data, for_time, offset, out_str);
-			}
-			
-			COTPRESULT now(char* out_str)
-			{
-				return totp_now(data, out_str);
-			}
-			
-			COTPRESULT verify(const char* key, uint64_t for_time, int64_t valid_window)
-			{
-				return totp_verify(data, key, for_time, valid_window);
-			}
-			
-			uint64_t valid_until(uint64_t for_time, int64_t valid_window)
-			{
-				return totp_valid_until(data, for_time, valid_window);
-			}
-			
-			uint64_t timecode(uint64_t for_time)
-			{
-				return totp_timecode(data, for_time);
-			}
-			
-			size_t uri_strlen(const char* issuer, const char* name, const char* digest)
-			{
-				return otpuri_strlen(data, issuer, name, digest);
-			}
-			
-			COTPRESULT build_uri(const char* issuer, const char* name, const char* digest, char* output)
-			{
-				return otpuri_build_uri(data, issuer, name, digest, output);
-			}
-			
-			OTPData* data_struct()
-			{
-				return data;
-			}
-			
-			static COTPRESULT random_base32(size_t len, char* out_str)
-			{
-				return otp_random_base32(len, out_str);
-			}
-			
-	};
-
-	class HOTP
-	{
-		protected:
-			OTPData* data;
-			
-		public:
-			HOTP(OTPData* data, const char* base32_secret, COTP_ALGO algo, uint32_t digits, uint64_t count)
-			{
-				this->data = hotp_new(data, base32_secret, algo, digits, count);
-			}
-			
-			~HOTP()
-			{
-				data = nullptr;
-			}
-			
-			COTPRESULT at(uint64_t counter, char* out_str)
-			{
-				return hotp_at(data, counter, out_str);
-			}
-			
-			COTPRESULT next(char* out_str)
-			{
-				return hotp_next(data, out_str);
-			}
-			
-			COTPRESULT compare(const char* key, uint64_t counter)
-			{
-				return hotp_compare(data, key, counter);
-			}
-			
-			size_t uri_strlen(const char* issuer, const char* name, const char* digest)
-			{
-				return otpuri_strlen(data, issuer, name, digest);
-			}
-			
-			COTPRESULT build_uri(const char* issuer, const char* name, const char* digest, char* output)
-			{
-				return otpuri_build_uri(data, issuer, name, digest, output);
-			}
-			
-			OTPData* data_struct()
-			{
-				return data;
-			}
-			
-			static COTPRESULT random_base32(size_t len, char* out_str)
-			{
-				return otp_random_base32(len, out_str);
-			}
-			
-	};
-	
-} // namespace COTP
-
-#else
-#	error "cotp.hpp is a C++ header. __cplusplus not defined."
-#endif
-
+
+#pragma once
+
+#if defined(__cplusplus)
+
+extern "C"
+{
+	#include "cotp.h"
+	#include "otpuri.h"
+}
+
+#include <cstdint>
+
+namespace COTP
+{
+	
+	class OTP
+	{
+		protected:
+			OTPData* data;
+			
+		public:
+			OTP(OTPData* data, const char* base32_secret, COTP_ALGO algo, uint32_t digits)
+			{
+				this->data = otp_new(data, base32_secret, algo, digits);
+			}
+			
+			~OTP()
+			{
+				data = nullptr;
+			}
+			
+			COTPRESULT generate(int64_t input, char* output)
+			{
+				return otp_generate(data, input, output);
+			}
+			
+			COTPRESULT byte_secret(char* out_str)
+			{
+				return otp_byte_secret(data, out_str);
+			}
+			
+			COTPRESULT num_to_bytestring(uint64_t integer, char* out_str)
+			{
+				return otp_num_to_bytestring(integer, out_str);
+			}
+			
+			size_t uri_strlen(const char* issuer, const char* name, const char* digest)
+			{
+				return otpuri_strlen(data, issuer, name, digest);
+			}
+			
+			COTPRESULT build_uri(const char* issuer, const char* name, const char* digest, char* output)
+			{
+				return otpuri_build_uri(data, issuer, name, digest, output);
+			}
+			
+			OTPData* data_struct()
+			{
+				return data;
+			}
+			
+			static COTPRESULT random_base32(size_t len, char* out_str)
+			{
+				return otp_random_base32(len, out_str);
+			}
+			
+	};
+
+	class TOTP
+	{
+		protected:
+			OTPData* data;
+			
+		public:
+			TOTP(OTPData* data, const char* base32_secret, COTP_ALGO algo, COTP_TIME time, uint32_t digits, uint32_t interval)
+			{
+				this->data = totp_new(data, base32_secret, algo, time, digits, interval);
+			}
+			
+			~TOTP()
+			{
+				data = nullptr;
+			}
+			
+			COTPRESULT at(uint64_t for_time, uint64_t offset, char* out_str)
+			{
+				return totp_at(data, for_time, offset, out_str);
+			}
+			
+			COTPRESULT now(char* out_str)
+			{
+				return totp_now(data, out_str);
+			}
+			
+			COTPRESULT verify(const char* key, uint64_t for_time, int64_t valid_window)
+			{
+				return totp_verify(data, key, for_time, valid_window);
+			}
+			
+			uint64_t valid_until(uint64_t for_time, int64_t valid_window)
+			{
+				return totp_valid_until(data, for_time, valid_window);
+			}
+			
+			uint64_t timecode(uint64_t for_time)
+			{
+				return totp_timecode(data, for_time);
+			}
+			
+			size_t uri_strlen(const char* issuer, const char* name, const char* digest)
+			{
+				return otpuri_strlen(data, issuer, name, digest);
+			}
+			
+			COTPRESULT build_uri(const char* issuer, const char* name, const char* digest, char* output)
+			{
+				return otpuri_build_uri(data, issuer, name, digest, output);
+			}
+			
+			OTPData* data_struct()
+			{
+				return data;
+			}
+			
+			static COTPRESULT random_base32(size_t len, char* out_str)
+			{
+				return otp_random_base32(len, out_str);
+			}
+			
+	};
+
+	class HOTP
+	{
+		protected:
+			OTPData* data;
+			
+		public:
+			HOTP(OTPData* data, const char* base32_secret, COTP_ALGO algo, uint32_t digits, uint64_t count)
+			{
+				this->data = hotp_new(data, base32_secret, algo, digits, count);
+			}
+			
+			~HOTP()
+			{
+				data = nullptr;
+			}
+			
+			COTPRESULT at(uint64_t counter, char* out_str)
+			{
+				return hotp_at(data, counter, out_str);
+			}
+			
+			COTPRESULT next(char* out_str)
+			{
+				return hotp_next(data, out_str);
+			}
+			
+			COTPRESULT compare(const char* key, uint64_t counter)
+			{
+				return hotp_compare(data, key, counter);
+			}
+			
+			size_t uri_strlen(const char* issuer, const char* name, const char* digest)
+			{
+				return otpuri_strlen(data, issuer, name, digest);
+			}
+			
+			COTPRESULT build_uri(const char* issuer, const char* name, const char* digest, char* output)
+			{
+				return otpuri_build_uri(data, issuer, name, digest, output);
+			}
+			
+			OTPData* data_struct()
+			{
+				return data;
+			}
+			
+			static COTPRESULT random_base32(size_t len, char* out_str)
+			{
+				return otp_random_base32(len, out_str);
+			}
+			
+	};
+	
+} // namespace COTP
+
+#else
+#	error "cotp.hpp is a C++ header. __cplusplus not defined."
+#endif
+
diff --git a/otpuri.c b/otpuri.c
index 42ec716..713b4a3 100644
--- a/otpuri.c
+++ b/otpuri.c
@@ -1,160 +1,160 @@
-
-#include "otpuri.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-
-
-/*
-	Encodes all given data into url-safe data. Null-terminates
-	  returned string. Caller must free the returned pointer.
-	  Will treat embedded \0's as valid characters.
-	
-	length is the length in bytes of input string data
-	data is the optionally null-terminated string to encode
-	
-	Returns
-			Pointer to malloc'd url-safe data string
-		error, 0
-*/
-COTPRESULT otpuri_encode_url(const char* data, size_t length, char* output)
-{
-	if (data == NULL || output == NULL)
-		return OTP_ERROR;
-	
-	static const char to_test[] = "\"<>#%@{}|\\^~[]` ?&";
-	
-	size_t output_i = 0;
-	for (size_t i=0; i<length; i++)
-	{
-		output[output_i] = data[i];
-		if (data[i] < 0x20 || data[i] >= 0x7F)
-		{
-			output_i += snprintf(output + output_i, 3+1, "%%%.2X", data[i]);
-			output_i--;
-		}
-		else
-		{
-			for (size_t j=0; j<18; j++)
-			{
-				if (to_test[j] == data[i])
-				{
-					output_i += snprintf(output + output_i, 3+1, "%%%.2X", data[i]);
-					output_i--;
-					break;
-				}
-			}
-		}
-		output_i++;
-	}
-	
-	return OTP_OK;
-}
-
-/*
-	Returns the maximum expected length of an array needed to fill a buffer
-	  with an otpuri not including the null-termination.
-	
-	Returns
-			Length in bytes of an array to match an otpuri generation
-*/
-size_t otpuri_strlen(OTPData* data, const char* issuer, const char* name, const char* digest)
-{
-	return strlen(issuer) * 2 * 3
-			+ strlen(name) * 3
-			+ strlen(data->base32_secret) * 3
-			+ strlen(digest) * 3
-			+ 100;
-}
-
-/*
-	Builds a valid, url-safe URI which is used for applications such as QR codes.
-	
-	issuer is the null-terminated string of the company name
-	name is the null-terminated string of the username
-	digest is the null-terminated string of the HMAC encryption algorithm
-	output is the zero'd destination the function writes the URI to
-	
-	Returns
-			1 on success
-		error, 0
-		
-*/
-COTPRESULT otpuri_build_uri(OTPData* data, const char* issuer, const char* name, const char* digest, char* output)
-{
-	if (issuer == NULL || name == NULL || digest == NULL || output == NULL)
-		return OTP_ERROR;
-	
-	strcat(output, "otpuri://");
-	switch(data->method)
-	{
-		case TOTP:
-			strcat(output, "totp");
-			break;
-		case HOTP:
-			strcat(output, "hotp");
-			break;
-		default:
-			strcat(output, "otp");
-			break;
-	}
-	
-	strcat(output, "/");
-	
-	char cissuer[strlen(issuer)*3 + 1];
-	memset(cissuer, 0, strlen(issuer)*3 + 1);
-	otpuri_encode_url(issuer, strlen(issuer), cissuer);
-	strcat(output, cissuer);
-	
-	strcat(output, ":");
-	
-	char cname[strlen(name)*3 + 1];
-	memset(cname, 0, strlen(name)*3 + 1);
-	otpuri_encode_url(name, strlen(name), cname);
-	strcat(output, cname);
-	
-	strcat(output, "?secret=");
-	char csecret[strlen(data->base32_secret)*3 + 1];
-	memset(csecret, 0, strlen(data->base32_secret)*3 + 1);
-	otpuri_encode_url(data->base32_secret, strlen(data->base32_secret), csecret);
-	strcat(output, csecret);
-	
-	strcat(output, "&issuer=");
-	strcat(output, cissuer);
-	
-	strcat(output, "&algorithm=");
-	char cdigest[strlen(digest)*3 + 1];
-	memset(cdigest, 0, strlen(digest)*3 + 1);
-	otpuri_encode_url(digest, strlen(digest), cdigest);
-	strcat(output, cdigest);
-	
-	strcat(output, "&digits=");
-	char cdigits[21];
-	memset(cdigits, 0, 21);
-	snprintf(cdigits, 21, "%" PRIu32, data->digits);
-	strcat(output, cdigits);
-	
-	switch(data->method)
-	{
-		case TOTP:
-			strcat(output, "&period=");
-			char cperiod[21];
-			memset(cperiod, 0, 21);
-			snprintf(cperiod, 21, "%" PRIu32, data->interval);
-			strcat(output, cperiod);
-			break;
-		case HOTP:
-			strcat(output, "&counter=");
-			char ccounter[21];
-			memset(ccounter, 0, 21);
-			snprintf(ccounter, 21, "%" PRIu64, data->count);
-			strcat(output, ccounter);
-			break;
-		default:
-			break;
-	}
-	
-	return OTP_OK;
-}
-
+
+#include "otpuri.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+
+/*
+	Encodes all given data into url-safe data. Null-terminates
+	  returned string. Caller must free the returned pointer.
+	  Will treat embedded \0's as valid characters.
+	
+	length is the length in bytes of input string data
+	data is the optionally null-terminated string to encode
+	
+	Returns
+			Pointer to malloc'd url-safe data string
+		error, 0
+*/
+COTPRESULT otpuri_encode_url(const char* data, size_t length, char* output)
+{
+	if (data == NULL || output == NULL)
+		return OTP_ERROR;
+	
+	static const char to_test[] = "\"<>#%@{}|\\^~[]` ?&";
+	
+	size_t output_i = 0;
+	for (size_t i=0; i<length; i++)
+	{
+		output[output_i] = data[i];
+		if (data[i] < 0x20 || data[i] >= 0x7F)
+		{
+			output_i += snprintf(output + output_i, 3+1, "%%%.2X", data[i]);
+			output_i--;
+		}
+		else
+		{
+			for (size_t j=0; j<18; j++)
+			{
+				if (to_test[j] == data[i])
+				{
+					output_i += snprintf(output + output_i, 3+1, "%%%.2X", data[i]);
+					output_i--;
+					break;
+				}
+			}
+		}
+		output_i++;
+	}
+	
+	return OTP_OK;
+}
+
+/*
+	Returns the maximum expected length of an array needed to fill a buffer
+	  with an otpuri not including the null-termination.
+	
+	Returns
+			Length in bytes of an array to match an otpuri generation
+*/
+size_t otpuri_strlen(OTPData* data, const char* issuer, const char* name, const char* digest)
+{
+	return strlen(issuer) * 2 * 3
+			+ strlen(name) * 3
+			+ strlen(data->base32_secret) * 3
+			+ strlen(digest) * 3
+			+ 100;
+}
+
+/*
+	Builds a valid, url-safe URI which is used for applications such as QR codes.
+	
+	issuer is the null-terminated string of the company name
+	name is the null-terminated string of the username
+	digest is the null-terminated string of the HMAC encryption algorithm
+	output is the zero'd destination the function writes the URI to
+	
+	Returns
+			1 on success
+		error, 0
+		
+*/
+COTPRESULT otpuri_build_uri(OTPData* data, const char* issuer, const char* name, const char* digest, char* output)
+{
+	if (issuer == NULL || name == NULL || digest == NULL || output == NULL)
+		return OTP_ERROR;
+	
+	strcat(output, "otpuri://");
+	switch(data->method)
+	{
+		case TOTP:
+			strcat(output, "totp");
+			break;
+		case HOTP:
+			strcat(output, "hotp");
+			break;
+		default:
+			strcat(output, "otp");
+			break;
+	}
+	
+	strcat(output, "/");
+	
+	char cissuer[strlen(issuer)*3 + 1];
+	memset(cissuer, 0, strlen(issuer)*3 + 1);
+	otpuri_encode_url(issuer, strlen(issuer), cissuer);
+	strcat(output, cissuer);
+	
+	strcat(output, ":");
+	
+	char cname[strlen(name)*3 + 1];
+	memset(cname, 0, strlen(name)*3 + 1);
+	otpuri_encode_url(name, strlen(name), cname);
+	strcat(output, cname);
+	
+	strcat(output, "?secret=");
+	char csecret[strlen(data->base32_secret)*3 + 1];
+	memset(csecret, 0, strlen(data->base32_secret)*3 + 1);
+	otpuri_encode_url(data->base32_secret, strlen(data->base32_secret), csecret);
+	strcat(output, csecret);
+	
+	strcat(output, "&issuer=");
+	strcat(output, cissuer);
+	
+	strcat(output, "&algorithm=");
+	char cdigest[strlen(digest)*3 + 1];
+	memset(cdigest, 0, strlen(digest)*3 + 1);
+	otpuri_encode_url(digest, strlen(digest), cdigest);
+	strcat(output, cdigest);
+	
+	strcat(output, "&digits=");
+	char cdigits[21];
+	memset(cdigits, 0, 21);
+	snprintf(cdigits, 21, "%" PRIu32, data->digits);
+	strcat(output, cdigits);
+	
+	switch(data->method)
+	{
+		case TOTP:
+			strcat(output, "&period=");
+			char cperiod[21];
+			memset(cperiod, 0, 21);
+			snprintf(cperiod, 21, "%" PRIu32, data->interval);
+			strcat(output, cperiod);
+			break;
+		case HOTP:
+			strcat(output, "&counter=");
+			char ccounter[21];
+			memset(ccounter, 0, 21);
+			snprintf(ccounter, 21, "%" PRIu64, data->count);
+			strcat(output, ccounter);
+			break;
+		default:
+			break;
+	}
+	
+	return OTP_OK;
+}
+
diff --git a/otpuri.h b/otpuri.h
index b7ec999..26f174a 100644
--- a/otpuri.h
+++ b/otpuri.h
@@ -1,7 +1,7 @@
-#pragma once
-
-#include "cotp.h"
-
-size_t otpuri_strlen(OTPData* data, const char* issuer, const char* name, const char* digest);
-COTPRESULT otpuri_encode_url(const char* data, size_t length, char* output);
-COTPRESULT otpuri_build_uri(OTPData* data, const char* issuer, const char* name, const char* digest, char* output);
+#pragma once
+
+#include "cotp.h"
+
+size_t otpuri_strlen(OTPData* data, const char* issuer, const char* name, const char* digest);
+COTPRESULT otpuri_encode_url(const char* data, size_t length, char* output);
+COTPRESULT otpuri_build_uri(OTPData* data, const char* issuer, const char* name, const char* digest, char* output);
diff --git a/test/main.c b/test/main.c
index c15517c..6b0bd43 100644
--- a/test/main.c
+++ b/test/main.c
@@ -1,288 +1,359 @@
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#if defined(_WIN32)
-#	include <sysinfoapi.h>
-#elif defined(__linux__)
-#	include <sys/time.h>
-#else
-#	error "OS not supported."
-#endif
-
-#include <openssl/evp.h>
-#include <openssl/hmac.h>
-
-#include "../cotp.h"
-#include "../otpuri.h"
-
-
-static const int32_t SHA1_BYTES   = 160 / 8;	// 20
-static const int32_t SHA256_BYTES = 256 / 8;	// 32
-static const int32_t SHA512_BYTES = 512 / 8;	// 64
-
-
-// byte_secret is unbase32 key
-// byte_string is data to be HMAC'd
-// returns 0 for failure otherwise the length of the string
-int hmac_algo_sha1(const char* byte_secret, const char* byte_string, char* out)
-{
-	// Output len
-	unsigned int len = SHA1_BYTES;
-	
-	unsigned char* result = HMAC(
-		EVP_sha1(),							// algorithm
-		(unsigned char*)byte_secret, 10,	// key
-		(unsigned char*)byte_string, 8,		// data
-		(unsigned char*)out,				// output
-		&len								// output length
-	);
-	
-	// Return the HMAC success
-	return result == 0 ? 0 : len;
-}
-
-int hmac_algo_sha256(const char* byte_secret, const char* byte_string, char* out)
-{
-	// Output len
-	unsigned int len = SHA256_BYTES;
-	
-	unsigned char* result = HMAC(
-		EVP_sha256(),						// algorithm
-		(unsigned char*)byte_secret, 10,	// key
-		(unsigned char*)byte_string, 8,		// data
-		(unsigned char*)out,				// output
-		&len								// output length
-	);
-	
-	// Return the HMAC success
-	return result == 0 ? 0 : len;
-}
-
-int hmac_algo_sha512(const char* byte_secret, const char* byte_string, char* out)
-{
-	// Output len
-	unsigned int len = SHA512_BYTES;
-	
-	unsigned char* result = HMAC(
-		EVP_sha512(),						// algorithm
-		(unsigned char*)byte_secret, 10,	// key
-		(unsigned char*)byte_string, 8,		// data
-		(unsigned char*)out,				// output
-		&len								// output length
-	);
-	
-	// Return the HMAC success
-	return result == 0 ? 0 : len;
-}
-
-uint64_t get_current_time()
-{
-	uint64_t milliseconds = 0;
-	
-#if defined(_WIN32)
-	FILETIME fileTime;
-	GetSystemTimeAsFileTime(&fileTime);
-	
-	ULARGE_INTEGER largeInteger;
-	largeInteger.LowPart = fileTime.dwLowDateTime;
-	largeInteger.HighPart = fileTime.dwHighDateTime;
-	
-	milliseconds = (largeInteger.QuadPart - 116444736000000000ULL) / 10000000ULL;
-#elif defined(__linux__)
-	struct timeval sys_time;
-	gettimeofday(&sys_time, NULL);
-	
-	milliseconds = sys_time.tv_sec;
-#endif
-	
-	return milliseconds;
-}
-
-
-
-int main(int argc, char** argv)
-{
-	////////////////////////////////////////////////////////////////
-	// Initialization Stuff                                       //
-	////////////////////////////////////////////////////////////////
-	
-	const int INTERVAL	= 30;
-	const int DIGITS	= 6;
-	
-	
-	// Base32 secret to utilize
-	const char BASE32_SECRET[] = "JBSWY3DPEHPK3PXP"; // JBSWY3DPEHPK3PXP 3E56263A4A655ED7
-	
-	OTPData odata1;
-	memset(&odata1, 0, sizeof(OTPData));
-	
-	OTPData odata2;
-	memset(&odata2, 0, sizeof(OTPData));
-	
-	// Create OTPData struct, which decides the environment
-	OTPData* tdata = totp_new(
-		&odata1,
-		BASE32_SECRET,
-		hmac_algo_sha1,
-		get_current_time,
-		DIGITS,
-		INTERVAL
-	);
-	
-	OTPData* hdata = hotp_new(
-		&odata2,
-		BASE32_SECRET,
-		hmac_algo_sha1,
-		DIGITS,
-		0
-	);
-	
-	// Dump data members of struct OTPData tdata
-	printf("\\\\ totp tdata \\\\\n");
-	printf("tdata->digits: `%u`\n", tdata->digits);
-	printf("tdata->interval: `%u`\n", tdata->interval);
-	printf("tdata->method: `%u`\n", tdata->method);
-	printf("tdata->algo: `0x%p`\n", tdata->algo);
-	printf("tdata->time: `0x%p`\n", tdata->time);
-	printf("tdata->base32_secret: `%s`\n", tdata->base32_secret);
-	printf("// totp tdata //\n\n");
-	
-	// Dump data members of struct OTPData hdata
-	printf("\\\\ hotp hdata \\\\\n");
-	printf("hdata->digits: `%u`\n", hdata->digits);
-	printf("hdata->method: `%u`\n", hdata->method);
-	printf("hdata->algo: `0x%p`\n", hdata->algo);
-	printf("hdata->base32_secret: `%s`\n", hdata->base32_secret);
-	printf("hdata->count: `%zu`\n", hdata->count);
-	printf("// hotp hdata //\n\n");
-	
-	printf("Current Time: `%zu`\n\n", get_current_time());
-	
-	
-	
-	////////////////////////////////////////////////////////////////
-	// URI Example                                                //
-	////////////////////////////////////////////////////////////////
-	
-	char name1[] = "name1";
-	char name2[] = "name2";
-	char whatever1[] = "account@whatever1.com";
-	char whatever2[] = "account@whatever2.com";
-	
-	size_t totp_uri_max = otpuri_strlen(tdata, name1, whatever1, "SHA1");
-	size_t hotp_uri_max = otpuri_strlen(hdata, name2, whatever2, "SHA1");
-	printf("Maximum buffer size for TOTP: `%zu`\n", totp_uri_max);
-	printf("Maximum buffer size for HOTP: `%zu`\n\n", hotp_uri_max);
-	
-	char totp_uri[totp_uri_max + 1];
-	memset(totp_uri, 0, totp_uri_max + 1);
-	otpuri_build_uri(tdata, name1, whatever1, "SHA1", totp_uri);
-	printf("TOTP URI (%zu bytes): `%s`\n", strlen(totp_uri), totp_uri);
-	
-	size_t counter = 52; // for example
-	hdata->count = counter;
-	
-	char hotp_uri[hotp_uri_max + 1];
-	memset(hotp_uri, 0, hotp_uri_max + 1);
-	otpuri_build_uri(hdata, name2, whatever2, "SHA1", hotp_uri);
-	printf("HOTP URI (%zu bytes): `%s`\n\n", strlen(hotp_uri), hotp_uri);
-	
-	
-	
-	////////////////////////////////////////////////////////////////
-	// BASE32 Stuff                                               //
-	////////////////////////////////////////////////////////////////
-	
-	const int base32_len = 16; // must be % 8 == 0
-	
-	// Generate random base32
-	char base32_new_secret[base32_len + 1];
-	memset(&base32_new_secret, 0, base32_len + 1);
-	
-	otp_random_base32(base32_len, base32_new_secret);
-	printf("Random Generated BASE32 Secret: `%s`\n", base32_new_secret);
-	
-	puts(""); // line break for readability
-	
-	
-	
-	////////////////////////////////////////////////////////////////
-	// TOTP Stuff                                                 //
-	////////////////////////////////////////////////////////////////
-	
-	// Get TOTP for a timeblock
-	//   1. Reserve memory and ensure it's null-terminated
-	//   2. Generate and load totp key into buffer
-	//   3. Check for error
-	
-	// totp_now
-	char tcode[DIGITS+1];
-	memset(tcode, 0, DIGITS+1);
-	
-	int totp_err_1 = totp_now(tdata, tcode);
-	if(totp_err_1 == OTP_ERROR)
-	{
-		fputs("TOTP Error totp_now", stderr);
-		return EXIT_FAILURE;
-	}
-	printf("totp_now() pass=1: `%s` `%d`\n", tcode, totp_err_1);
-	
-	// totp_at
-	char tcode2[DIGITS+1];
-	memset(tcode2, 0, DIGITS+1);
-	
-	int totp_err_2 = totp_at(tdata, 0, 0, tcode2);
-	if(totp_err_2 == OTP_ERROR)
-	{
-		fputs("TOTP Error totp_at", stderr);
-		return EXIT_FAILURE;
-	}
-	printf("totp_at(0, 0) pass=1: `%s` `%d`\n", tcode2, totp_err_2);
-	
-	// Do a verification for a hardcoded code
-	// Won't succeed, this code is for a timeblock far into the past/future
-	int tv1 = totp_verify(tdata, "358892", get_current_time(), 4);
-	printf("TOTP Verification 1 pass=false: `%s`\n", tv1 == 0 ? "false" : "true");
-	
-	// Will succeed, timeblock 0 for JBSWY3DPEHPK3PXP == 282760
-	int tv2 = totp_verify(tdata, "282760", 0, 4);
-	printf("TOTP Verification 2 pass=true: `%s`\n", tv2 == 0 ? "false" : "true");
-	
-	puts(""); // line break for readability
-	
-	
-	
-	////////////////////////////////////////////////////////////////
-	// HOTP Stuff                                                 //
-	////////////////////////////////////////////////////////////////
-	
-	// Get HOTP for token 1
-	//   1. Reserve memory and ensure it's null-terminated
-	//   2. Generate and load hotp key into buffer
-	//   3. Check for error
-	
-	char hcode[DIGITS+1];
-	memset(hcode, 0, DIGITS+1);
-	
-	int hotp_err_1 = hotp_at(hdata, 1, hcode);
-	if(hotp_err_1 == OTP_ERROR)
-	{
-		puts("HOTP Error hotp_at");
-		return EXIT_FAILURE;
-	}
-	printf("hotp_at(1) pass=1: `%s` `%d`\n", hcode, hotp_err_1);
-	
-	// Do a verification for a hardcoded code
-	// Won't succeed, 1 for JBSWY3DPEHPK3PXP == 996554
-	int hv1 = hotp_compare(hdata, "996555", 1);
-	printf("HOTP Verification 1 pass=false: `%s`\n", hv1 == 0 ? "false" : "true");
-	
-	// Will succeed, 1 for JBSWY3DPEHPK3PXP == 996554
-	int hv2 = hotp_compare(hdata, "996554", 1);
-	printf("HOTP Verification 2 pass=true: `%s`\n", hv2 == 0 ? "false" : "true");
-	
-	return EXIT_SUCCESS;
-}
-
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_WIN32)
+#	include <sysinfoapi.h>
+#elif defined(__linux__)
+#	include <sys/time.h>
+#else
+#	error "OS not supported."
+#endif
+
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+#include "../cotp.h"
+#include "../otpuri.h"
+
+
+static const int32_t SHA1_BYTES   = 160 / 8;	// 20
+static const int32_t SHA256_BYTES = 256 / 8;	// 32
+static const int32_t SHA512_BYTES = 512 / 8;	// 64
+
+
+// byte_secret is unbase32 key
+// byte_string is data to be HMAC'd
+// returns 0 for failure otherwise the length of the string
+int hmac_algo_sha1(const char* byte_secret, int key_length, const char* byte_string, char* out)
+{
+	// Output len
+	unsigned int len = SHA1_BYTES;
+	
+	unsigned char* result = HMAC(
+		EVP_sha1(),									// algorithm
+		(unsigned char*)byte_secret, key_length,	// key
+		(unsigned char*)byte_string, 8,				// data
+		(unsigned char*)out,						// output
+		&len										// output length
+	);
+	
+	// Return the HMAC success
+	return result == 0 ? 0 : len;
+}
+
+int hmac_algo_sha256(const char* byte_secret, int key_length, const char* byte_string, char* out)
+{
+	// Output len
+	unsigned int len = SHA256_BYTES;
+	
+	unsigned char* result = HMAC(
+		EVP_sha256(),								// algorithm
+		(unsigned char*)byte_secret, key_length,	// key
+		(unsigned char*)byte_string, 8,				// data
+		(unsigned char*)out,						// output
+		&len										// output length
+	);
+	
+	// Return the HMAC success
+	return result == 0 ? 0 : len;
+}
+
+int hmac_algo_sha512(const char* byte_secret, int key_length, const char* byte_string, char* out)
+{
+	// Output len
+	unsigned int len = SHA512_BYTES;
+	
+	unsigned char* result = HMAC(
+		EVP_sha512(),								// algorithm
+		(unsigned char*)byte_secret, key_length,	// key
+		(unsigned char*)byte_string, 8,				// data
+		(unsigned char*)out,						// output
+		&len										// output length
+	);
+	
+	// Return the HMAC success
+	return result == 0 ? 0 : len;
+}
+
+uint64_t get_current_time()
+{
+	uint64_t milliseconds = 0;
+	
+#if defined(_WIN32)
+	FILETIME fileTime;
+	GetSystemTimeAsFileTime(&fileTime);
+	
+	ULARGE_INTEGER largeInteger;
+	largeInteger.LowPart = fileTime.dwLowDateTime;
+	largeInteger.HighPart = fileTime.dwHighDateTime;
+	
+	milliseconds = (largeInteger.QuadPart - 116444736000000000ULL) / 10000000ULL;
+#elif defined(__linux__)
+	struct timeval sys_time;
+	gettimeofday(&sys_time, NULL);
+	
+	milliseconds = sys_time.tv_sec;
+#endif
+	
+	return milliseconds;
+}
+
+
+
+int main(int argc, char** argv)
+{
+	////////////////////////////////////////////////////////////////
+	// Initialization Stuff                                       //
+	////////////////////////////////////////////////////////////////
+	
+	const int INTERVAL	= 30;
+	const int DIGITS	= 6;
+	
+	
+	// Base32 secret to utilize
+	const char BASE32_SECRET[] = "JBSWY3DPEHPK3PXP"; // JBSWY3DPEHPK3PXP 3E56263A4A655ED7
+	
+	// Base32 secret to utilize with padding
+	const char BASE32_SECRET_PADDING[] = "ORSXG5BRGIZXIZLTOQ2DKNRXHA4XIZLTOQYQ====";
+	
+	OTPData odata1;
+	memset(&odata1, 0, sizeof(OTPData));
+	
+	OTPData odata_padding;
+	memset(&odata_padding, 0, sizeof(OTPData));
+	
+	OTPData odata2;
+	memset(&odata2, 0, sizeof(OTPData));
+	
+	// Create OTPData struct, which decides the environment
+	OTPData* tdata = totp_new(
+		&odata1,
+		BASE32_SECRET,
+		hmac_algo_sha1,
+		get_current_time,
+		DIGITS,
+		INTERVAL
+	);
+	
+	OTPData* tdata_padding = totp_new(
+		&odata_padding,
+		BASE32_SECRET_PADDING,
+		hmac_algo_sha1,
+		get_current_time,
+		DIGITS,
+		INTERVAL
+	);
+	
+	OTPData* hdata = hotp_new(
+		&odata2,
+		BASE32_SECRET,
+		hmac_algo_sha1,
+		DIGITS,
+		0
+	);
+	
+	// Dump data members of struct OTPData tdata
+	printf("\\\\ totp tdata \\\\\n");
+	printf("tdata->digits: `%u`\n", tdata->digits);
+	printf("tdata->interval: `%u`\n", tdata->interval);
+	printf("tdata->method: `%u`\n", tdata->method);
+	printf("tdata->algo: `0x%p`\n", tdata->algo);
+	printf("tdata->time: `0x%p`\n", tdata->time);
+	printf("tdata->base32_secret: `%s`\n", tdata->base32_secret);
+	printf("// totp tdata //\n\n");
+	
+	// Dump data members of struct OTPData tdata_padding
+	printf("\\\\ totp tdata_padding \\\\\n");
+	printf("tdata_padding->digits: `%u`\n", tdata_padding->digits);
+	printf("tdata_padding->interval: `%u`\n", tdata_padding->interval);
+	printf("tdata_padding->method: `%u`\n", tdata_padding->method);
+	printf("tdata_padding->algo: `0x%p`\n", tdata_padding->algo);
+	printf("tdata_padding->time: `0x%p`\n", tdata_padding->time);
+	printf("tdata_padding->base32_secret: `%s`\n", tdata_padding->base32_secret);
+	printf("// totp tdata_padding //\n\n");
+	
+	// Dump data members of struct OTPData hdata
+	printf("\\\\ hotp hdata \\\\\n");
+	printf("hdata->digits: `%u`\n", hdata->digits);
+	printf("hdata->method: `%u`\n", hdata->method);
+	printf("hdata->algo: `0x%p`\n", hdata->algo);
+	printf("hdata->base32_secret: `%s`\n", hdata->base32_secret);
+	printf("hdata->count: `%zu`\n", hdata->count);
+	printf("// hotp hdata //\n\n");
+	
+	printf("Current Time: `%zu`\n\n", get_current_time());
+	
+	
+	
+	////////////////////////////////////////////////////////////////
+	// URI Example                                                //
+	////////////////////////////////////////////////////////////////
+	
+	char name1[] = "name1";
+	char name2[] = "name2";
+	char whatever1[] = "account@whatever1.com";
+	char whatever2[] = "account@whatever2.com";
+	
+	size_t totp_uri_max = otpuri_strlen(tdata, name1, whatever1, "SHA1");
+	size_t hotp_uri_max = otpuri_strlen(hdata, name2, whatever2, "SHA1");
+	printf("Maximum buffer size for TOTP: `%zu`\n", totp_uri_max);
+	printf("Maximum buffer size for HOTP: `%zu`\n\n", hotp_uri_max);
+	
+	char totp_uri[totp_uri_max + 1];
+	memset(totp_uri, 0, totp_uri_max + 1);
+	otpuri_build_uri(tdata, name1, whatever1, "SHA1", totp_uri);
+	printf("TOTP URI (%zu bytes): `%s`\n", strlen(totp_uri), totp_uri);
+	
+	size_t counter = 52; // for example
+	hdata->count = counter;
+	
+	char hotp_uri[hotp_uri_max + 1];
+	memset(hotp_uri, 0, hotp_uri_max + 1);
+	otpuri_build_uri(hdata, name2, whatever2, "SHA1", hotp_uri);
+	printf("HOTP URI (%zu bytes): `%s`\n\n", strlen(hotp_uri), hotp_uri);
+	
+	
+	
+	////////////////////////////////////////////////////////////////
+	// BASE32 Stuff                                               //
+	////////////////////////////////////////////////////////////////
+	
+	const int base32_len = 16; // must be % 8 == 0
+	
+	// Generate random base32
+	char base32_new_secret[base32_len + 1];
+	memset(&base32_new_secret, 0, base32_len + 1);
+	
+	otp_random_base32(base32_len, base32_new_secret);
+	printf("Random Generated BASE32 Secret: `%s`\n", base32_new_secret);
+	
+	puts(""); // line break for readability
+	
+	
+	
+	////////////////////////////////////////////////////////////////
+	// TOTP Stuff                                                 //
+	////////////////////////////////////////////////////////////////
+	
+	// Get TOTP for a timeblock
+	//   1. Reserve memory and ensure it's null-terminated
+	//   2. Generate and load totp key into buffer
+	//   3. Check for error
+	
+	// totp_now
+	char tcode[DIGITS+1];
+	memset(tcode, 0, DIGITS+1);
+	
+	int totp_err_1 = totp_now(tdata, tcode);
+	if(totp_err_1 == OTP_ERROR)
+	{
+		fputs("TOTP Error totp_now", stderr);
+		return EXIT_FAILURE;
+	}
+	printf("totp_now() pass=1: `%s` `%d`\n", tcode, totp_err_1);
+	
+	// totp_at
+	char tcode2[DIGITS+1];
+	memset(tcode2, 0, DIGITS+1);
+	
+	int totp_err_2 = totp_at(tdata, 0, 0, tcode2);
+	if(totp_err_2 == OTP_ERROR)
+	{
+		fputs("TOTP Error totp_at", stderr);
+		return EXIT_FAILURE;
+	}
+	printf("totp_at(0, 0) pass=1: `%s` `%d`\n", tcode2, totp_err_2);
+	
+	// Do a verification for a hardcoded code
+	// Won't succeed, this code is for a timeblock far into the past/future
+	int tv1 = totp_verify(tdata, "358892", get_current_time(), 4);
+	printf("TOTP Verification 1 pass=false: `%s`\n", tv1 == 0 ? "false" : "true");
+	
+	// Will succeed, timeblock 0 for JBSWY3DPEHPK3PXP == 282760
+	int tv2 = totp_verify(tdata, "282760", 0, 4);
+	printf("TOTP Verification 2 pass=true: `%s`\n", tv2 == 0 ? "false" : "true");
+	
+	puts(""); // line break for readability
+	
+	
+	
+	////////////////////////////////////////////////////////////////
+	// TOTP Stuff (Padding)                                       //
+	////////////////////////////////////////////////////////////////
+	
+	// Get TOTP for a timeblock
+	//   1. Reserve memory and ensure it's null-terminated
+	//   2. Generate and load totp key into buffer
+	//   3. Check for error
+	
+	// totp_now
+	char tcode3[DIGITS+1];
+	memset(tcode3, 0, DIGITS+1);
+	
+	int totp_err_3 = totp_now(tdata_padding, tcode3);
+	if(totp_err_3 == OTP_ERROR)
+	{
+		fputs("TOTP Error totp_now (padding)", stderr);
+		return EXIT_FAILURE;
+	}
+	printf("totp_now() (padding) pass=1: `%s` `%d`\n", tcode3, totp_err_3);
+	
+	// totp_at
+	char tcode4[DIGITS+1];
+	memset(tcode4, 0, DIGITS+1);
+	
+	int totp_err_4 = totp_at(tdata_padding, 0, 0, tcode4);
+	if(totp_err_4 == OTP_ERROR)
+	{
+		fputs("TOTP Error totp_at (padding)", stderr);
+		return EXIT_FAILURE;
+	}
+	printf("totp_at(0, 0) (padding) pass=1: `%s` `%d`\n", tcode4, totp_err_4);
+	
+	// Do a verification for a hardcoded code
+	// Won't succeed, this code is for a timeblock far into the past/future
+	int tv3 = totp_verify(tdata_padding, "122924", get_current_time(), 4);
+	printf("TOTP Verification 1 (padding) pass=false: `%s`\n", tv3 == 0 ? "false" : "true");
+	
+	// Will succeed, timeblock 0 for 'ORSXG5BRGIZXIZLTOQ2DKNRXHA4XIZLTOQYQ====' == 570783
+	int tv4 = totp_verify(tdata_padding, "570783", 0, 4);
+	printf("TOTP Verification 2 (padding) pass=true: `%s`\n", tv4 == 0 ? "false" : "true");
+	
+	puts(""); // line break for readability
+	
+	
+	
+	////////////////////////////////////////////////////////////////
+	// HOTP Stuff                                                 //
+	////////////////////////////////////////////////////////////////
+	
+	// Get HOTP for token 1
+	//   1. Reserve memory and ensure it's null-terminated
+	//   2. Generate and load hotp key into buffer
+	//   3. Check for error
+	
+	char hcode[DIGITS+1];
+	memset(hcode, 0, DIGITS+1);
+	
+	int hotp_err_1 = hotp_at(hdata, 1, hcode);
+	if(hotp_err_1 == OTP_ERROR)
+	{
+		puts("HOTP Error hotp_at");
+		return EXIT_FAILURE;
+	}
+	printf("hotp_at(1) pass=1: `%s` `%d`\n", hcode, hotp_err_1);
+	
+	// Do a verification for a hardcoded code
+	// Won't succeed, 1 for JBSWY3DPEHPK3PXP == 996554
+	int hv1 = hotp_compare(hdata, "996555", 1);
+	printf("HOTP Verification 1 pass=false: `%s`\n", hv1 == 0 ? "false" : "true");
+	
+	// Will succeed, 1 for JBSWY3DPEHPK3PXP == 996554
+	int hv2 = hotp_compare(hdata, "996554", 1);
+	printf("HOTP Verification 2 pass=true: `%s`\n", hv2 == 0 ? "false" : "true");
+	
+	return EXIT_SUCCESS;
+}
+
diff --git a/test/main.cpp b/test/main.cpp
index 66b4ff7..3c7d785 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -1,279 +1,353 @@
-
-#include <cstdlib>
-#include <iostream>
-#include <cstring>
-#include <chrono>
-
-#include "../cotp.hpp"
-
-extern "C"
-{
-	#include <openssl/evp.h>
-	#include <openssl/hmac.h>
-}
-
-
-using namespace std;
-using namespace COTP;
-
-
-static const int32_t SHA1_BYTES   = 160 / 8;	// 20
-static const int32_t SHA256_BYTES = 256 / 8;	// 32
-static const int32_t SHA512_BYTES = 512 / 8;	// 64
-
-
-// byte_secret is unbase32 key
-// byte_string is data to be HMAC'd
-// returns 0 for failure otherwise the length of the string
-int hmac_algo_sha1(const char* byte_secret, const char* byte_string, char* out)
-{
-	// Output len
-	unsigned int len = SHA1_BYTES;
-	
-	unsigned char* result = HMAC(
-		EVP_sha1(),							// algorithm
-		(unsigned char*)byte_secret, 10,	// key
-		(unsigned char*)byte_string, 8,		// data
-		(unsigned char*)out,				// output
-		&len								// output length
-	);
-	
-	// Return the HMAC success
-	return result == 0 ? 0 : len;
-}
-
-
-int hmac_algo_sha256(const char* byte_secret, const char* byte_string, char* out)
-{
-	// Output len
-	unsigned int len = SHA256_BYTES;
-	
-	unsigned char* result = HMAC(
-		EVP_sha256(),						// algorithm
-		(unsigned char*)byte_secret, 10,	// key
-		(unsigned char*)byte_string, 8,		// data
-		(unsigned char*)out,				// output
-		&len								// output length
-	);
-	
-	// Return the HMAC success
-	return result == 0 ? 0 : len;
-}
-
-int hmac_algo_sha512(const char* byte_secret, const char* byte_string, char* out)
-{
-	// Output len
-	unsigned int len = SHA512_BYTES;
-	
-	unsigned char* result = HMAC(
-		EVP_sha512(),						// algorithm
-		(unsigned char*)byte_secret, 10,	// key
-		(unsigned char*)byte_string, 8,		// data
-		(unsigned char*)out,				// output
-		&len								// output length
-	);
-	
-	// Return the HMAC success
-	return result == 0 ? 0 : len;
-}
-
-// TODO: use a secure random generator
-uint64_t get_current_time()
-{
-	using namespace std::chrono;
-	
-	auto now = system_clock::now();
-	auto dur = now.time_since_epoch();
-	
-	return duration_cast<chrono::seconds>(dur).count();
-}
-
-
-
-int main(int argc, char** argv)
-{
-	////////////////////////////////////////////////////////////////
-	// Initialization Stuff                                       //
-	////////////////////////////////////////////////////////////////
-	
-	const int INTERVAL	= 30;
-	const int DIGITS	= 6;
-	
-	
-	// Base32 secret to utilize
-	const char BASE32_SECRET[] = "JBSWY3DPEHPK3PXP";
-	
-	OTPData odata1;
-	memset(&odata1, 0, sizeof(OTPData));
-	
-	OTPData odata2;
-	memset(&odata2, 0, sizeof(OTPData));
-	
-	// Create OTPData struct, which decides the environment
-	class TOTP tdata
-	{
-		&odata1,
-		BASE32_SECRET,
-		hmac_algo_sha1,
-		get_current_time,
-		DIGITS,
-		INTERVAL
-	};
-		
-	class HOTP hdata
-	{
-		&odata2,
-		BASE32_SECRET,
-		hmac_algo_sha1,
-		DIGITS,
-		0
-	};
-	
-	// Dump data members of struct OTPData tdata
-	OTPData* tdata_s = tdata.data_struct();
-	cout << "\\\\ totp tdata \\\\"		<< endl;
-	cout << "tdata->digits: `"			<< tdata_s->digits			<< "`" << endl;
-	cout << "tdata->interval: `"		<< tdata_s->interval		<< "`" << endl;
-	cout << "tdata->method: `"			<< tdata_s->method			<< "`" << endl;
-	cout << "tdata->algo: `"			<< reinterpret_cast<void*>(tdata_s->algo) << "`" << endl;
-	cout << "tdata->time: `"			<< reinterpret_cast<void*>(tdata_s->time) << "`" << endl;
-	cout << "tdata->base32_secret: `"	<< tdata_s->base32_secret	<< "`" << endl;
-	cout << "// totp tdata //"			<< endl						<< endl;
-	
-	// Dump data members of struct OTPData hdata
-	OTPData* hdata_s = hdata.data_struct();
-	cout << "\\\\ hotp hdata \\\\"		<< endl;
-	cout << "hdata->digits: `"			<< hdata_s->digits			<< "`" << endl;
-	cout << "hdata->method: `"			<< hdata_s->method			<< "`" << endl;
-	cout << "hdata->algo: `"			<< reinterpret_cast<void*>(hdata_s->algo) << "`" << endl;
-	cout << "hdata->base32_secret: `"	<< hdata_s->base32_secret	<< "`" << endl;
-	cout << "hdata->count: `"			<< hdata_s->count			<< "`" << endl;
-	cout << "// hotp hdata //"			<< endl						<< endl;
-	
-	cout << "Current Time: `" << get_current_time() << "`" << endl << endl;
-	
-	
-	
-	////////////////////////////////////////////////////////////////
-	// URI Example                                                //
-	////////////////////////////////////////////////////////////////
-	
-	char name1[] = "name1";
-	char name2[] = "name2";
-	char whatever1[] = "account@whatever1.com";
-	char whatever2[] = "account@whatever2.com";
-	
-	size_t totp_uri_max = tdata.uri_strlen(name1, whatever1, "SHA1");
-	size_t hotp_uri_max = hdata.uri_strlen(name2, whatever2, "SHA1");
-	cout << "Maximum buffer size for TOTP: `" << totp_uri_max << "`" << endl;
-	cout << "Maximum buffer size for HOTP: `" << hotp_uri_max << "`" << endl << endl;
-	
-	char totp_uri[totp_uri_max + 1];
-	memset(totp_uri, 0, totp_uri_max + 1);
-	tdata.build_uri(name1, whatever1, "SHA1", totp_uri);
-	cout << "TOTP URI: `" << totp_uri << "`" << endl;
-	
-	size_t counter = 52; // for example
-	hdata_s->count = counter;
-	
-	char hotp_uri[hotp_uri_max + 1];
-	memset(hotp_uri, 0, hotp_uri_max + 1);
-	hdata.build_uri(name2, whatever2, "SHA1", hotp_uri);
-	cout << "HOTP URI: `" << hotp_uri << "`" << endl << endl;
-	
-	
-	
-	////////////////////////////////////////////////////////////////
-	// BASE32 Stuff                                               //
-	////////////////////////////////////////////////////////////////
-	
-	const int base32_len = 16; // must be % 8 == 0
-	
-	// Generate random base32
-	char base32_new_secret[base32_len + 1];
-	memset(&base32_new_secret, 0, base32_len + 1);
-	
-	OTP::random_base32(base32_len, base32_new_secret);
-	cout << "Random Generated BASE32 Secret: `" << base32_new_secret << "`" << endl;
-	
-	cout << endl; // line break for readability
-	
-	
-	
-	////////////////////////////////////////////////////////////////
-	// TOTP Stuff                                                 //
-	////////////////////////////////////////////////////////////////
-	
-	// Get TOTP for a timeblock
-	//   1. Reserve memory and ensure it's null-terminated
-	//   2. Generate and load totp key into buffer
-	//   3. Check for error
-	
-	// totp_now
-	char tcode[DIGITS+1];
-	memset(tcode, 0, DIGITS+1);
-	
-	int totp_err_1 = tdata.now(tcode);
-	if(totp_err_1 == OTP_ERROR)
-	{
-		cout << "TOTP Error totp_now" << endl;
-		return EXIT_FAILURE;
-	}
-	cout << "totp_now() pass=1: `" << tcode << "` `" << totp_err_1 << "`" << endl;
-	
-	// totp_at
-	char tcode2[DIGITS+1];
-	memset(tcode2, 0, DIGITS+1);
-	
-	int totp_err_2 = tdata.at(0, 0, tcode2);
-	if(totp_err_2 == 0)
-	{
-		cout << "TOTP Error totp_at" << endl;
-		return EXIT_FAILURE;
-	}
-	cout << "totp_at(0, 0) pass=1: `" << tcode2 << "` `" << totp_err_2 << "`" << endl;
-	
-	// Do a verification for a hardcoded code
-	// Won't succeed, this code is for a timeblock far into the past/future
-	int tv1 = tdata.verify("358892", get_current_time(), 4);
-	cout << "TOTP Verification 1 pass=false: `" << (tv1 == 0 ? "false" : "true") << "`" << endl;
-	
-	// Will succeed, timeblock 0 for JBSWY3DPEHPK3PXP == 282760
-	int tv2 = tdata.verify("282760", 0, 4);
-	cout << "TOTP Verification 2 pass=true: `" << (tv2 == 0 ? "false" : "true") << "`" << endl;
-	
-	cout << endl; // line break for readability
-	
-	
-	
-	////////////////////////////////////////////////////////////////
-	// HOTP Stuff                                                 //
-	////////////////////////////////////////////////////////////////
-	
-	// Get HOTP for token 1
-	//   1. Reserve memory and ensure it's null-terminated
-	//   2. Generate and load hotp key into buffer
-	//   3. Check for error
-	
-	char hcode[DIGITS+1];
-	memset(hcode, 0, DIGITS+1);
-	
-	int hotp_err_1 = hdata.at(1, hcode);
-	if(hotp_err_1 == 0) {
-		cout << "HOTP Error hotp_at" << endl;
-		return EXIT_FAILURE;
-	}
-	cout << "hotp_at(1) pass=1: `" << hcode << "`" << " `" << hotp_err_1 << "`" << endl;
-	
-	// Do a verification for a hardcoded code
-	// Won't succeed, 1 for JBSWY3DPEHPK3PXP == 996554
-	int hv1 = hdata.compare("996555", 1);
-	cout << "HOTP Verification 1 pass=false: `" << (hv1 == 0 ? "false" : "true") << "`" << endl;
-	
-	// Will succeed, 1 for JBSWY3DPEHPK3PXP == 996554
-	int hv2 = hdata.compare("996554", 1);
-	cout << "HOTP Verification 2 pass=true: `" << (hv2 == 0 ? "false" : "true") << "`" << endl;
-	
-	return EXIT_SUCCESS;
-}
-
+
+#include <cstdlib>
+#include <iostream>
+#include <cstring>
+#include <chrono>
+
+#include "../cotp.hpp"
+
+extern "C"
+{
+	#include <openssl/evp.h>
+	#include <openssl/hmac.h>
+}
+
+
+using namespace std;
+using namespace COTP;
+
+
+static const int32_t SHA1_BYTES   = 160 / 8;	// 20
+static const int32_t SHA256_BYTES = 256 / 8;	// 32
+static const int32_t SHA512_BYTES = 512 / 8;	// 64
+
+
+// byte_secret is unbase32 key
+// byte_string is data to be HMAC'd
+// returns 0 for failure otherwise the length of the string
+int hmac_algo_sha1(const char* byte_secret, int key_length, const char* byte_string, char* out)
+{
+	// Output len
+	unsigned int len = SHA1_BYTES;
+	
+	unsigned char* result = HMAC(
+		EVP_sha1(),							// algorithm
+		(unsigned char*)byte_secret, key_length,	// key
+		(unsigned char*)byte_string, 8,		// data
+		(unsigned char*)out,				// output
+		&len								// output length
+	);
+	
+	// Return the HMAC success
+	return result == 0 ? 0 : len;
+}
+
+
+int hmac_algo_sha256(const char* byte_secret, int key_length, const char* byte_string, char* out)
+{
+	// Output len
+	unsigned int len = SHA256_BYTES;
+	
+	unsigned char* result = HMAC(
+		EVP_sha256(),						// algorithm
+		(unsigned char*)byte_secret, key_length,	// key
+		(unsigned char*)byte_string, 8,		// data
+		(unsigned char*)out,				// output
+		&len								// output length
+	);
+	
+	// Return the HMAC success
+	return result == 0 ? 0 : len;
+}
+
+int hmac_algo_sha512(const char* byte_secret, int key_length, const char* byte_string, char* out)
+{
+	// Output len
+	unsigned int len = SHA512_BYTES;
+	
+	unsigned char* result = HMAC(
+		EVP_sha512(),						// algorithm
+		(unsigned char*)byte_secret, key_length,	// key
+		(unsigned char*)byte_string, 8,		// data
+		(unsigned char*)out,				// output
+		&len								// output length
+	);
+	
+	// Return the HMAC success
+	return result == 0 ? 0 : len;
+}
+
+// TODO: use a secure random generator
+uint64_t get_current_time()
+{
+	using namespace std::chrono;
+	
+	auto now = system_clock::now();
+	auto dur = now.time_since_epoch();
+	
+	return duration_cast<chrono::seconds>(dur).count();
+}
+
+
+
+int main(int argc, char** argv)
+{
+	////////////////////////////////////////////////////////////////
+	// Initialization Stuff                                       //
+	////////////////////////////////////////////////////////////////
+	
+	const int INTERVAL	= 30;
+	const int DIGITS	= 6;
+	
+	
+	// Base32 secret to utilize
+	const char BASE32_SECRET[] = "JBSWY3DPEHPK3PXP";
+	
+	// Base32 secret to utilize with padding
+	const char BASE32_SECRET_PADDING[] = "ORSXG5BRGIZXIZLTOQ2DKNRXHA4XIZLTOQYQ====";
+	
+	OTPData odata1;
+	memset(&odata1, 0, sizeof(OTPData));
+	
+	OTPData odata_padding;
+	memset(&odata_padding, 0, sizeof(OTPData));
+	
+	OTPData odata2;
+	memset(&odata2, 0, sizeof(OTPData));
+	
+	// Create OTPData struct, which decides the environment
+	class TOTP tdata
+	{
+		&odata1,
+		BASE32_SECRET,
+		hmac_algo_sha1,
+		get_current_time,
+		DIGITS,
+		INTERVAL
+	};
+	
+	class TOTP tdata_padding
+	{
+		&odata_padding,
+		BASE32_SECRET_PADDING,
+		hmac_algo_sha1,
+		get_current_time,
+		DIGITS,
+		INTERVAL
+	};
+	
+	class HOTP hdata
+	{
+		&odata2,
+		BASE32_SECRET,
+		hmac_algo_sha1,
+		DIGITS,
+		0
+	};
+	
+	// Dump data members of struct OTPData tdata
+	OTPData* tdata_s = tdata.data_struct();
+	cout << "\\\\ totp tdata \\\\"		<< endl;
+	cout << "tdata->digits: `"			<< tdata_s->digits			<< "`" << endl;
+	cout << "tdata->interval: `"		<< tdata_s->interval		<< "`" << endl;
+	cout << "tdata->method: `"			<< tdata_s->method			<< "`" << endl;
+	cout << "tdata->algo: `"			<< reinterpret_cast<void*>(tdata_s->algo) << "`" << endl;
+	cout << "tdata->time: `"			<< reinterpret_cast<void*>(tdata_s->time) << "`" << endl;
+	cout << "tdata->base32_secret: `"	<< tdata_s->base32_secret	<< "`" << endl;
+	cout << "// totp tdata //"			<< endl						<< endl;
+	
+	// Dump data members of struct OTPData tdata_padding
+	OTPData* tdata_padding_s = tdata.data_struct();
+	cout << "\\\\ totp tdata_padding \\\\"		<< endl;
+	cout << "tdata_padding->digits: `"			<< tdata_padding_s->digits			<< "`" << endl;
+	cout << "tdata_padding->interval: `"		<< tdata_padding_s->interval		<< "`" << endl;
+	cout << "tdata_padding->method: `"			<< tdata_padding_s->method			<< "`" << endl;
+	cout << "tdata_padding->algo: `"			<< reinterpret_cast<void*>(tdata_padding_s->algo) << "`" << endl;
+	cout << "tdata_padding->time: `"			<< reinterpret_cast<void*>(tdata_padding_s->time) << "`" << endl;
+	cout << "tdata_padding->base32_secret: `"	<< tdata_padding_s->base32_secret	<< "`" << endl;
+	cout << "// totp tdata_padding //"			<< endl								<< endl;
+	
+	
+	// Dump data members of struct OTPData hdata
+	OTPData* hdata_s = hdata.data_struct();
+	cout << "\\\\ hotp hdata \\\\"		<< endl;
+	cout << "hdata->digits: `"			<< hdata_s->digits			<< "`" << endl;
+	cout << "hdata->method: `"			<< hdata_s->method			<< "`" << endl;
+	cout << "hdata->algo: `"			<< reinterpret_cast<void*>(hdata_s->algo) << "`" << endl;
+	cout << "hdata->base32_secret: `"	<< hdata_s->base32_secret	<< "`" << endl;
+	cout << "hdata->count: `"			<< hdata_s->count			<< "`" << endl;
+	cout << "// hotp hdata //"			<< endl						<< endl;
+	
+	cout << "Current Time: `" << get_current_time() << "`" << endl << endl;
+	
+	
+	
+	////////////////////////////////////////////////////////////////
+	// URI Example                                                //
+	////////////////////////////////////////////////////////////////
+	
+	char name1[] = "name1";
+	char name2[] = "name2";
+	char whatever1[] = "account@whatever1.com";
+	char whatever2[] = "account@whatever2.com";
+	
+	size_t totp_uri_max = tdata.uri_strlen(name1, whatever1, "SHA1");
+	size_t hotp_uri_max = hdata.uri_strlen(name2, whatever2, "SHA1");
+	cout << "Maximum buffer size for TOTP: `" << totp_uri_max << "`" << endl;
+	cout << "Maximum buffer size for HOTP: `" << hotp_uri_max << "`" << endl << endl;
+	
+	char totp_uri[totp_uri_max + 1];
+	memset(totp_uri, 0, totp_uri_max + 1);
+	tdata.build_uri(name1, whatever1, "SHA1", totp_uri);
+	cout << "TOTP URI: `" << totp_uri << "`" << endl;
+	
+	size_t counter = 52; // for example
+	hdata_s->count = counter;
+	
+	char hotp_uri[hotp_uri_max + 1];
+	memset(hotp_uri, 0, hotp_uri_max + 1);
+	hdata.build_uri(name2, whatever2, "SHA1", hotp_uri);
+	cout << "HOTP URI: `" << hotp_uri << "`" << endl << endl;
+	
+	
+	
+	////////////////////////////////////////////////////////////////
+	// BASE32 Stuff                                               //
+	////////////////////////////////////////////////////////////////
+	
+	const int base32_len = 16; // must be % 8 == 0
+	
+	// Generate random base32
+	char base32_new_secret[base32_len + 1];
+	memset(&base32_new_secret, 0, base32_len + 1);
+	
+	OTP::random_base32(base32_len, base32_new_secret);
+	cout << "Random Generated BASE32 Secret: `" << base32_new_secret << "`" << endl;
+	
+	cout << endl; // line break for readability
+	
+	
+	
+	////////////////////////////////////////////////////////////////
+	// TOTP Stuff                                                 //
+	////////////////////////////////////////////////////////////////
+	
+	// Get TOTP for a timeblock
+	//   1. Reserve memory and ensure it's null-terminated
+	//   2. Generate and load totp key into buffer
+	//   3. Check for error
+	
+	// totp_now
+	char tcode[DIGITS+1];
+	memset(tcode, 0, DIGITS+1);
+	
+	int totp_err_1 = tdata.now(tcode);
+	if(totp_err_1 == OTP_ERROR)
+	{
+		cout << "TOTP Error totp_now (padding)" << endl;
+		return EXIT_FAILURE;
+	}
+	cout << "totp_now() (padding) pass=1: `" << tcode << "` `" << totp_err_1 << "`" << endl;
+	
+	// totp_at
+	char tcode2[DIGITS+1];
+	memset(tcode2, 0, DIGITS+1);
+	
+	int totp_err_2 = tdata.at(0, 0, tcode2);
+	if(totp_err_2 == 0)
+	{
+		cout << "TOTP Error totp_at (padding)" << endl;
+		return EXIT_FAILURE;
+	}
+	cout << "totp_at(0, 0) (padding) pass=1: `" << tcode2 << "` `" << totp_err_2 << "`" << endl;
+	
+	// Do a verification for a hardcoded code
+	// Won't succeed, this code is for a timeblock far into the past/future
+	int tv1 = tdata.verify("358892", get_current_time(), 4);
+	cout << "TOTP Verification 1 (padding) pass=false: `" << (tv1 == 0 ? "false" : "true") << "`" << endl;
+	
+	// Will succeed, timeblock 0 for JBSWY3DPEHPK3PXP == 282760
+	int tv2 = tdata.verify("282760", 0, 4);
+	cout << "TOTP Verification 2 (padding) pass=true: `" << (tv2 == 0 ? "false" : "true") << "`" << endl;
+	
+	cout << endl; // line break for readability
+	
+	
+	
+	////////////////////////////////////////////////////////////////
+	// TOTP Stuff (Padding)                                       //
+	////////////////////////////////////////////////////////////////
+	
+	// Get TOTP for a timeblock
+	//   1. Reserve memory and ensure it's null-terminated
+	//   2. Generate and load totp key into buffer
+	//   3. Check for error
+	
+	// totp_now
+	char tcode3[DIGITS+1];
+	memset(tcode3, 0, DIGITS+1);
+	
+	int totp_err_3 = tdata_padding.now(tcode3);
+	if(totp_err_3 == OTP_ERROR)
+	{
+		cout << "TOTP Error totp_now" << endl;
+		return EXIT_FAILURE;
+	}
+	cout << "totp_now() pass=1: `" << tcode3 << "` `" << totp_err_3 << "`" << endl;
+	
+	// totp_at
+	char tcode4[DIGITS+1];
+	memset(tcode4, 0, DIGITS+1);
+	
+	int totp_err_4 = tdata_padding.at(0, 0, tcode4);
+	if(totp_err_4 == 0)
+	{
+		cout << "TOTP Error totp_at" << endl;
+		return EXIT_FAILURE;
+	}
+	cout << "totp_at(0, 0) pass=1: `" << tcode4 << "` `" << totp_err_4 << "`" << endl;
+	
+	// Do a verification for a hardcoded code
+	// Won't succeed, this code is for a timeblock far into the past/future
+	int tv3 = tdata_padding.verify("358892", get_current_time(), 4);
+	cout << "TOTP Verification 1 pass=false: `" << (tv3 == 0 ? "false" : "true") << "`" << endl;
+	
+	// Will succeed, timeblock 0 for 'ORSXG5BRGIZXIZLTOQ2DKNRXHA4XIZLTOQYQ====' == 570783
+	int tv4 = tdata_padding.verify("570783", 0, 4);
+	cout << "TOTP Verification 2 pass=true: `" << (tv4 == 0 ? "false" : "true") << "`" << endl;
+	
+	cout << endl; // line break for readability
+	
+	
+	
+	////////////////////////////////////////////////////////////////
+	// HOTP Stuff                                                 //
+	////////////////////////////////////////////////////////////////
+	
+	// Get HOTP for token 1
+	//   1. Reserve memory and ensure it's null-terminated
+	//   2. Generate and load hotp key into buffer
+	//   3. Check for error
+	
+	char hcode[DIGITS+1];
+	memset(hcode, 0, DIGITS+1);
+	
+	int hotp_err_1 = hdata.at(1, hcode);
+	if(hotp_err_1 == 0) {
+		cout << "HOTP Error hotp_at" << endl;
+		return EXIT_FAILURE;
+	}
+	cout << "hotp_at(1) pass=1: `" << hcode << "`" << " `" << hotp_err_1 << "`" << endl;
+	
+	// Do a verification for a hardcoded code
+	// Won't succeed, 1 for JBSWY3DPEHPK3PXP == 996554
+	int hv1 = hdata.compare("996555", 1);
+	cout << "HOTP Verification 1 pass=false: `" << (hv1 == 0 ? "false" : "true") << "`" << endl;
+	
+	// Will succeed, 1 for JBSWY3DPEHPK3PXP == 996554
+	int hv2 = hdata.compare("996554", 1);
+	cout << "HOTP Verification 2 pass=true: `" << (hv2 == 0 ? "false" : "true") << "`" << endl;
+	
+	return EXIT_SUCCESS;
+}
+