diff options
Diffstat (limited to 'src/lib/utils')
47 files changed, 4596 insertions, 0 deletions
diff --git a/src/lib/utils/asm_x86_32/asm_x86_32.h b/src/lib/utils/asm_x86_32/asm_x86_32.h new file mode 100644 index 000000000..d5482c419 --- /dev/null +++ b/src/lib/utils/asm_x86_32/asm_x86_32.h @@ -0,0 +1,128 @@ +/* +* Assembly Macros for 32-bit x86 +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ASM_MACROS_X86_32_H__ +#define BOTAN_ASM_MACROS_X86_32_H__ + +/* +* General/Global Macros +*/ +#define ALIGN .p2align 4,,15 + +#define START_LISTING(FILENAME) \ + .file #FILENAME; \ + .text; \ + ALIGN; + +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif + +/* +* Function Definitions +*/ +#define START_FUNCTION(func_name) \ + ALIGN; \ + .global func_name; \ + .type func_name,@function; \ +func_name: + +#define END_FUNCTION(func_name) \ + ret + +/* +* Loop Control +*/ +#define START_LOOP(LABEL) \ + ALIGN; \ + LABEL##_LOOP: + +#define LOOP_UNTIL_EQ(REG, NUM, LABEL) \ + cmpl IMM(NUM), REG; \ + jne LABEL##_LOOP + +#define LOOP_UNTIL_LT(REG, NUM, LABEL) \ + cmpl IMM(NUM), REG; \ + jge LABEL##_LOOP + +/* + Conditional Jumps +*/ +#define JUMP_IF_ZERO(REG, LABEL) \ + cmpl IMM(0), REG; \ + jz LABEL + +#define JUMP_IF_LT(REG, NUM, LABEL) \ + cmpl IMM(NUM), REG; \ + jl LABEL + +/* +* Register Names +*/ +#define EAX %eax +#define EBX %ebx +#define ECX %ecx +#define EDX %edx +#define EBP %ebp +#define EDI %edi +#define ESI %esi +#define ESP %esp + +/* +* Memory Access Operations +*/ +#define ARRAY1(REG, NUM) (NUM)(REG) +#define ARRAY4(REG, NUM) 4*(NUM)(REG) +#define ARRAY4_INDIRECT(BASE, OFFSET, NUM) 4*(NUM)(BASE,OFFSET,4) +#define ARG(NUM) 4*(PUSHED) + ARRAY4(ESP, NUM) + +#define ASSIGN(TO, FROM) movl FROM, TO +#define ASSIGN_BYTE(TO, FROM) movzbl FROM, TO + +#define PUSH(REG) pushl REG +#define POP(REG) popl REG + +#define SPILL_REGS() \ + PUSH(EBP) ; \ + PUSH(EDI) ; \ + PUSH(ESI) ; \ + PUSH(EBX) + +#define RESTORE_REGS() \ + POP(EBX) ; \ + POP(ESI) ; \ + POP(EDI) ; \ + POP(EBP) + +/* +* ALU Operations +*/ +#define IMM(VAL) $VAL + +#define ADD(TO, FROM) addl FROM, TO +#define ADD_IMM(TO, NUM) ADD(TO, IMM(NUM)) +#define ADD_W_CARRY(TO1, TO2, FROM) addl FROM, TO1; adcl IMM(0), TO2; +#define SUB_IMM(TO, NUM) subl IMM(NUM), TO +#define ADD2_IMM(TO, FROM, NUM) leal NUM(FROM), TO +#define ADD3_IMM(TO, FROM, NUM) leal NUM(TO,FROM,1), TO +#define MUL(REG) mull REG + +#define SHL_IMM(REG, SHIFT) shll IMM(SHIFT), REG +#define SHR_IMM(REG, SHIFT) shrl IMM(SHIFT), REG +#define SHL2_3(TO, FROM) leal 0(,FROM,8), TO + +#define XOR(TO, FROM) xorl FROM, TO +#define AND(TO, FROM) andl FROM, TO +#define OR(TO, FROM) orl FROM, TO +#define NOT(REG) notl REG +#define ZEROIZE(REG) XOR(REG, REG) + +#define ROTL_IMM(REG, NUM) roll IMM(NUM), REG +#define ROTR_IMM(REG, NUM) rorl IMM(NUM), REG +#define BSWAP(REG) bswapl REG + +#endif diff --git a/src/lib/utils/asm_x86_32/info.txt b/src/lib/utils/asm_x86_32/info.txt new file mode 100644 index 000000000..d29b25fa3 --- /dev/null +++ b/src/lib/utils/asm_x86_32/info.txt @@ -0,0 +1,29 @@ +load_on dep + +<header:internal> +asm_x86_32.h +</header:internal> + +<arch> +x86_32 +</arch> + +# ELF systems +<os> +linux +freebsd +dragonfly +netbsd +openbsd +solaris +</os> + +<cc> +gcc +clang +icc +</cc> + +<requires> +asm_engine +</requires> diff --git a/src/lib/utils/asm_x86_64/asm_x86_64.h b/src/lib/utils/asm_x86_64/asm_x86_64.h new file mode 100644 index 000000000..7abc1f392 --- /dev/null +++ b/src/lib/utils/asm_x86_64/asm_x86_64.h @@ -0,0 +1,127 @@ +/* +* Assembly Macros for 64-bit x86 +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ASM_MACROS_X86_64_H__ +#define BOTAN_ASM_MACROS_X86_64_H__ + +/* +* General/Global Macros +*/ +#define ALIGN .p2align 4,,15 + +#define START_LISTING(FILENAME) \ + .file #FILENAME; \ + .text; \ + ALIGN; + +#if defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif + +/* +* Function Definitions +*/ +#define START_FUNCTION(func_name) \ + ALIGN; \ + .global func_name; \ + .type func_name,@function; \ +func_name: + +#define END_FUNCTION(func_name) \ + ret + +/* +* Conditional Jumps +*/ +#define JUMP_IF_ZERO(REG, LABEL) \ + cmp IMM(0), REG; \ + jz LABEL + +#define JUMP_IF_LT(REG, NUM, LABEL) \ + cmp IMM(NUM), REG; \ + jl LABEL + +/* +* Register Names +*/ +#define R0 %rax +#define R1 %rbx +#define R2 %rcx +#define R2_32 %ecx +#define R3 %rdx +#define R3_32 %edx +#define R4 %rsp +#define R5 %rbp +#define R6 %rsi +#define R6_32 %esi +#define R7 %rdi +#define R8 %r8 +#define R9 %r9 +#define R9_32 %r9d +#define R10 %r10 +#define R11 %r11 +#define R12 %r12 +#define R13 %r13 +#define R14 %r14 +#define R15 %r15 +#define R16 %r16 + +#define ARG_1 R7 +#define ARG_2 R6 +#define ARG_2_32 R6_32 +#define ARG_3 R3 +#define ARG_3_32 R3_32 +#define ARG_4 R2 +#define ARG_4_32 R2_32 +#define ARG_5 R8 +#define ARG_6 R9 +#define ARG_6_32 R9_32 + +#define TEMP_1 R10 +#define TEMP_2 R11 +#define TEMP_3 ARG_6 +#define TEMP_4 ARG_5 +#define TEMP_5 ARG_4 +#define TEMP_5_32 ARG_4_32 +#define TEMP_6 ARG_3 +#define TEMP_7 ARG_2 +#define TEMP_8 ARG_1 +#define TEMP_9 R0 + +/* +* Memory Access Operations +*/ +#define ARRAY8(REG, NUM) 8*(NUM)(REG) +#define ARRAY4(REG, NUM) 4*(NUM)(REG) + +#define ASSIGN(TO, FROM) mov FROM, TO + +/* +* ALU Operations +*/ +#define IMM(VAL) $VAL + +#define ADD(TO, FROM) add FROM, TO +#define ADD_LAST_CARRY(REG) adc IMM(0), REG +#define ADD_IMM(TO, NUM) ADD(TO, IMM(NUM)) +#define ADD_W_CARRY(TO1, TO2, FROM) add FROM, TO1; adc IMM(0), TO2; +#define SUB_IMM(TO, NUM) sub IMM(NUM), TO +#define MUL(REG) mul REG + +#define XOR(TO, FROM) xor FROM, TO +#define AND(TO, FROM) and FROM, TO +#define OR(TO, FROM) or FROM, TO +#define NOT(REG) not REG +#define ZEROIZE(REG) XOR(REG, REG) + +#define RETURN_VALUE_IS(V) ASSIGN(%rax, V) + +#define ROTL_IMM(REG, NUM) rol IMM(NUM), REG +#define ROTR_IMM(REG, NUM) ror IMM(NUM), REG +#define ADD3_IMM(TO, FROM, NUM) lea NUM(TO,FROM,1), TO + +#endif diff --git a/src/lib/utils/asm_x86_64/info.txt b/src/lib/utils/asm_x86_64/info.txt new file mode 100644 index 000000000..3173f3b14 --- /dev/null +++ b/src/lib/utils/asm_x86_64/info.txt @@ -0,0 +1,27 @@ +load_on dep + +<header:internal> +asm_x86_64.h +</header:internal> + +<arch> +x86_64 +</arch> + +<cc> +clang +gcc +icc +</cc> + +# ELF systems +<os> +linux +netbsd +openbsd +solaris +</os> + +<requires> +asm_engine +</requires> diff --git a/src/lib/utils/assert.cpp b/src/lib/utils/assert.cpp new file mode 100644 index 000000000..b6d4f4240 --- /dev/null +++ b/src/lib/utils/assert.cpp @@ -0,0 +1,36 @@ +/* +* Runtime assertion checking +* (C) 2010,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/exceptn.h> +#include <sstream> + +namespace Botan { + +void assertion_failure(const char* expr_str, + const char* assertion_made, + const char* func, + const char* file, + int line) + { + std::ostringstream format; + + format << "False assertion "; + + if(assertion_made && assertion_made[0] != 0) + format << "'" << assertion_made << "' (expression " << expr_str << ") "; + else + format << expr_str << " "; + + if(func) + format << "in " << func << " "; + + format << "@" << file << ":" << line; + + throw std::runtime_error(format.str()); + } + +} diff --git a/src/lib/utils/assert.h b/src/lib/utils/assert.h new file mode 100644 index 000000000..f62fae63e --- /dev/null +++ b/src/lib/utils/assert.h @@ -0,0 +1,83 @@ +/* +* Runtime assertion checking +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ASSERTION_CHECKING_H__ +#define BOTAN_ASSERTION_CHECKING_H__ + +#include <botan/build.h> + +namespace Botan { + +/** +* Called when an assertion fails +*/ +void BOTAN_DLL assertion_failure(const char* expr_str, + const char* assertion_made, + const char* func, + const char* file, + int line); + +/** +* Make an assertion +*/ +#define BOTAN_ASSERT(expr, assertion_made) \ + do { \ + if(!(expr)) \ + Botan::assertion_failure(#expr, \ + assertion_made, \ + __func__, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Assert that value1 == value2 +*/ +#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made) \ + do { \ + if((expr1) != (expr2)) \ + Botan::assertion_failure(#expr1 " == " #expr2, \ + assertion_made, \ + __func__, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Assert that expr1 (if true) implies expr2 is also true +*/ +#define BOTAN_ASSERT_IMPLICATION(expr1, expr2, msg) \ + do { \ + if((expr1) && !(expr2)) \ + Botan::assertion_failure(#expr1 " implies " #expr2, \ + msg, \ + __func__, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Assert that a pointer is not null +*/ +#define BOTAN_ASSERT_NONNULL(ptr) \ + do { \ + if(static_cast<bool>(ptr) == false) \ + Botan::assertion_failure(#ptr " is not null", \ + "", \ + __func__, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Mark variable as unused +*/ +#define BOTAN_UNUSED(v) static_cast<void>(v) + +} + +#endif diff --git a/src/lib/utils/bit_ops.h b/src/lib/utils/bit_ops.h new file mode 100644 index 000000000..0072fde71 --- /dev/null +++ b/src/lib/utils/bit_ops.h @@ -0,0 +1,103 @@ +/* +* Bit/Word Operations +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BIT_OPS_H__ +#define BOTAN_BIT_OPS_H__ + +#include <botan/types.h> + +namespace Botan { + +/** +* Power of 2 test. T should be an unsigned integer type +* @param arg an integer value +* @return true iff arg is 2^n for some n > 0 +*/ +template<typename T> +inline bool is_power_of_2(T arg) + { + return ((arg != 0 && arg != 1) && ((arg & (arg-1)) == 0)); + } + +/** +* Return the index of the highest set bit +* T is an unsigned integer type +* @param n an integer value +* @return index of the highest set bit in n +*/ +template<typename T> +inline size_t high_bit(T n) + { + for(size_t i = 8*sizeof(T); i > 0; --i) + if((n >> (i - 1)) & 0x01) + return i; + return 0; + } + +/** +* Return the index of the lowest set bit +* T is an unsigned integer type +* @param n an integer value +* @return index of the lowest set bit in n +*/ +template<typename T> +inline size_t low_bit(T n) + { + for(size_t i = 0; i != 8*sizeof(T); ++i) + if((n >> i) & 0x01) + return (i + 1); + return 0; + } + +/** +* Return the number of significant bytes in n +* @param n an integer value +* @return number of significant bytes in n +*/ +template<typename T> +inline size_t significant_bytes(T n) + { + for(size_t i = 0; i != sizeof(T); ++i) + if(get_byte(i, n)) + return sizeof(T)-i; + return 0; + } + +/** +* Compute Hamming weights +* @param n an integer value +* @return number of bits in n set to 1 +*/ +template<typename T> +inline size_t hamming_weight(T n) + { + const byte NIBBLE_WEIGHTS[] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; + + size_t weight = 0; + for(size_t i = 0; i != 2*sizeof(T); ++i) + weight += NIBBLE_WEIGHTS[(n >> (4*i)) & 0x0F]; + return weight; + } + +/** +* Count the trailing zero bits in n +* @param n an integer value +* @return maximum x st 2^x divides n +*/ +template<typename T> +inline size_t ctz(T n) + { + for(size_t i = 0; i != 8*sizeof(T); ++i) + if((n >> i) & 0x01) + return i; + return 8*sizeof(T); + } + +} + +#endif diff --git a/src/lib/utils/boost/info.txt b/src/lib/utils/boost/info.txt new file mode 100644 index 000000000..e87fd5b88 --- /dev/null +++ b/src/lib/utils/boost/info.txt @@ -0,0 +1,7 @@ +define BOOST_FILESYSTEM 20131228 +define BOOST_ASIO 20131228 + +<libs> +all -> boost_system,boost_filesystem +</libs> + diff --git a/src/lib/utils/bswap.h b/src/lib/utils/bswap.h new file mode 100644 index 000000000..9d2c9bc28 --- /dev/null +++ b/src/lib/utils/bswap.h @@ -0,0 +1,142 @@ +/* +* Byte Swapping Operations +* (C) 1999-2011 Jack Lloyd +* (C) 2007 Yves Jerschow +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BYTE_SWAP_H__ +#define BOTAN_BYTE_SWAP_H__ + +#include <botan/types.h> +#include <botan/rotate.h> + +#if defined(BOTAN_TARGET_CPU_HAS_SSE2) && !defined(BOTAN_NO_SSE_INTRINSICS) + #include <emmintrin.h> +#endif + +namespace Botan { + +/** +* Swap a 16 bit integer +*/ +inline u16bit reverse_bytes(u16bit val) + { + return rotate_left(val, 8); + } + +/** +* Swap a 32 bit integer +*/ +inline u32bit reverse_bytes(u32bit val) + { +#if BOTAN_GCC_VERSION >= 430 && !defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + /* + GCC intrinsic added in 4.3, works for a number of CPUs + + However avoid under ARM, as it branches to a function in libgcc + instead of generating inline asm, so slower even than the generic + rotate version below. + */ + return __builtin_bswap32(val); + +#elif BOTAN_USE_GCC_INLINE_ASM && defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + + // GCC-style inline assembly for x86 or x86-64 + asm("bswapl %0" : "=r" (val) : "0" (val)); + return val; + +#elif BOTAN_USE_GCC_INLINE_ASM && defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + + asm ("eor r3, %1, %1, ror #16\n\t" + "bic r3, r3, #0x00FF0000\n\t" + "mov %0, %1, ror #8\n\t" + "eor %0, %0, r3, lsr #8" + : "=r" (val) + : "0" (val) + : "r3", "cc"); + + return val; + +#elif defined(_MSC_VER) && defined(BOTAN_TARGET_ARCH_IS_X86_32) + + // Visual C++ inline asm for 32-bit x86, by Yves Jerschow + __asm mov eax, val; + __asm bswap eax; + +#else + + // Generic implementation + return (rotate_right(val, 8) & 0xFF00FF00) | + (rotate_left (val, 8) & 0x00FF00FF); + +#endif + } + +/** +* Swap a 64 bit integer +*/ +inline u64bit reverse_bytes(u64bit val) + { +#if BOTAN_GCC_VERSION >= 430 + + // GCC intrinsic added in 4.3, works for a number of CPUs + return __builtin_bswap64(val); + +#elif BOTAN_USE_GCC_INLINE_ASM && defined(BOTAN_TARGET_ARCH_IS_X86_64) + // GCC-style inline assembly for x86-64 + asm("bswapq %0" : "=r" (val) : "0" (val)); + return val; + +#else + /* Generic implementation. Defined in terms of 32-bit bswap so any + * optimizations in that version can help here (particularly + * useful for 32-bit x86). + */ + + u32bit hi = static_cast<u32bit>(val >> 32); + u32bit lo = static_cast<u32bit>(val); + + hi = reverse_bytes(hi); + lo = reverse_bytes(lo); + + return (static_cast<u64bit>(lo) << 32) | hi; +#endif + } + +/** +* Swap 4 Ts in an array +*/ +template<typename T> +inline void bswap_4(T x[4]) + { + x[0] = reverse_bytes(x[0]); + x[1] = reverse_bytes(x[1]); + x[2] = reverse_bytes(x[2]); + x[3] = reverse_bytes(x[3]); + } + +#if defined(BOTAN_TARGET_CPU_HAS_SSE2) && !defined(BOTAN_NO_SSE_INTRINSICS) + +/** +* Swap 4 u32bits in an array using SSE2 shuffle instructions +*/ +template<> +inline void bswap_4(u32bit x[4]) + { + __m128i T = _mm_loadu_si128(reinterpret_cast<const __m128i*>(x)); + + T = _mm_shufflehi_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); + T = _mm_shufflelo_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); + + T = _mm_or_si128(_mm_srli_epi16(T, 8), _mm_slli_epi16(T, 8)); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(x), T); + } + +#endif + +} + +#endif diff --git a/src/lib/utils/calendar.cpp b/src/lib/utils/calendar.cpp new file mode 100644 index 000000000..14f0113f2 --- /dev/null +++ b/src/lib/utils/calendar.cpp @@ -0,0 +1,52 @@ +/* +* Calendar Functions +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/calendar.h> +#include <botan/exceptn.h> +#include <ctime> + +namespace Botan { + +namespace { + +std::tm do_gmtime(std::time_t time_val) + { + std::tm tm; + +#if defined(BOTAN_TARGET_OS_HAS_GMTIME_S) + gmtime_s(&tm, &time_val); // Windows +#elif defined(BOTAN_TARGET_OS_HAS_GMTIME_R) + gmtime_r(&time_val, &tm); // Unix/SUSv2 +#else + std::tm* tm_p = std::gmtime(&time_val); + if (tm_p == 0) + throw Encoding_Error("time_t_to_tm could not convert"); + tm = *tm_p; +#endif + + return tm; + } + +} + +/* +* Convert a time_point to a calendar_point +*/ +calendar_point calendar_value( + const std::chrono::system_clock::time_point& time_point) + { + std::tm tm = do_gmtime(std::chrono::system_clock::to_time_t(time_point)); + + return calendar_point(tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday, + tm.tm_hour, + tm.tm_min, + tm.tm_sec); + } + +} diff --git a/src/lib/utils/calendar.h b/src/lib/utils/calendar.h new file mode 100644 index 000000000..d617cc9a0 --- /dev/null +++ b/src/lib/utils/calendar.h @@ -0,0 +1,63 @@ +/* +* Calendar Functions +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CALENDAR_H__ +#define BOTAN_CALENDAR_H__ + +#include <botan/types.h> +#include <chrono> + +namespace Botan { + +/** +* Struct representing a particular date and time +*/ +struct BOTAN_DLL calendar_point + { + /** The year */ + u32bit year; + + /** The month, 1 through 12 for Jan to Dec */ + byte month; + + /** The day of the month, 1 through 31 (or 28 or 30 based on month */ + byte day; + + /** Hour in 24-hour form, 0 to 23 */ + byte hour; + + /** Minutes in the hour, 0 to 60 */ + byte minutes; + + /** Seconds in the minute, 0 to 60, but might be slightly + larger to deal with leap seconds on some systems + */ + byte seconds; + + /** + * Initialize a calendar_point + * @param y the year + * @param mon the month + * @param d the day + * @param h the hour + * @param min the minute + * @param sec the second + */ + calendar_point(u32bit y, byte mon, byte d, byte h, byte min, byte sec) : + year(y), month(mon), day(d), hour(h), minutes(min), seconds(sec) {} + }; + +/* +* @param time_point a time point from the system clock +* @return calendar_point object representing this time point +*/ +BOTAN_DLL calendar_point calendar_value( + const std::chrono::system_clock::time_point& time_point); + +} + +#endif diff --git a/src/lib/utils/charset.cpp b/src/lib/utils/charset.cpp new file mode 100644 index 000000000..7ee637f80 --- /dev/null +++ b/src/lib/utils/charset.cpp @@ -0,0 +1,201 @@ +/* +* Character Set Handling +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/charset.h> +#include <botan/parsing.h> +#include <botan/exceptn.h> +#include <cctype> + +namespace Botan { + +namespace Charset { + +namespace { + +/* +* Convert from UCS-2 to ISO 8859-1 +*/ +std::string ucs2_to_latin1(const std::string& ucs2) + { + if(ucs2.size() % 2 == 1) + throw Decoding_Error("UCS-2 string has an odd number of bytes"); + + std::string latin1; + + for(size_t i = 0; i != ucs2.size(); i += 2) + { + const byte c1 = ucs2[i]; + const byte c2 = ucs2[i+1]; + + if(c1 != 0) + throw Decoding_Error("UCS-2 has non-Latin1 characters"); + + latin1 += static_cast<char>(c2); + } + + return latin1; + } + +/* +* Convert from UTF-8 to ISO 8859-1 +*/ +std::string utf8_to_latin1(const std::string& utf8) + { + std::string iso8859; + + size_t position = 0; + while(position != utf8.size()) + { + const byte c1 = static_cast<byte>(utf8[position++]); + + if(c1 <= 0x7F) + iso8859 += static_cast<char>(c1); + else if(c1 >= 0xC0 && c1 <= 0xC7) + { + if(position == utf8.size()) + throw Decoding_Error("UTF-8: sequence truncated"); + + const byte c2 = static_cast<byte>(utf8[position++]); + const byte iso_char = ((c1 & 0x07) << 6) | (c2 & 0x3F); + + if(iso_char <= 0x7F) + throw Decoding_Error("UTF-8: sequence longer than needed"); + + iso8859 += static_cast<char>(iso_char); + } + else + throw Decoding_Error("UTF-8: Unicode chars not in Latin1 used"); + } + + return iso8859; + } + +/* +* Convert from ISO 8859-1 to UTF-8 +*/ +std::string latin1_to_utf8(const std::string& iso8859) + { + std::string utf8; + for(size_t i = 0; i != iso8859.size(); ++i) + { + const byte c = static_cast<byte>(iso8859[i]); + + if(c <= 0x7F) + utf8 += static_cast<char>(c); + else + { + utf8 += static_cast<char>((0xC0 | (c >> 6))); + utf8 += static_cast<char>((0x80 | (c & 0x3F))); + } + } + return utf8; + } + +} + +/* +* Perform character set transcoding +*/ +std::string transcode(const std::string& str, + Character_Set to, Character_Set from) + { + if(to == LOCAL_CHARSET) + to = LATIN1_CHARSET; + if(from == LOCAL_CHARSET) + from = LATIN1_CHARSET; + + if(to == from) + return str; + + if(from == LATIN1_CHARSET && to == UTF8_CHARSET) + return latin1_to_utf8(str); + if(from == UTF8_CHARSET && to == LATIN1_CHARSET) + return utf8_to_latin1(str); + if(from == UCS2_CHARSET && to == LATIN1_CHARSET) + return ucs2_to_latin1(str); + + throw Invalid_Argument("Unknown transcoding operation from " + + std::to_string(from) + " to " + std::to_string(to)); + } + +/* +* Check if a character represents a digit +*/ +bool is_digit(char c) + { + if(c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || + c == '5' || c == '6' || c == '7' || c == '8' || c == '9') + return true; + return false; + } + +/* +* Check if a character represents whitespace +*/ +bool is_space(char c) + { + if(c == ' ' || c == '\t' || c == '\n' || c == '\r') + return true; + return false; + } + +/* +* Convert a character to a digit +*/ +byte char2digit(char c) + { + switch(c) + { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + } + + throw Invalid_Argument("char2digit: Input is not a digit character"); + } + +/* +* Convert a digit to a character +*/ +char digit2char(byte b) + { + switch(b) + { + case 0: return '0'; + case 1: return '1'; + case 2: return '2'; + case 3: return '3'; + case 4: return '4'; + case 5: return '5'; + case 6: return '6'; + case 7: return '7'; + case 8: return '8'; + case 9: return '9'; + } + + throw Invalid_Argument("digit2char: Input is not a digit"); + } + +/* +* Case-insensitive character comparison +*/ +bool caseless_cmp(char a, char b) + { + return (std::tolower(static_cast<unsigned char>(a)) == + std::tolower(static_cast<unsigned char>(b))); + } + +} + +} diff --git a/src/lib/utils/charset.h b/src/lib/utils/charset.h new file mode 100644 index 000000000..afb11733b --- /dev/null +++ b/src/lib/utils/charset.h @@ -0,0 +1,46 @@ +/* +* Character Set Handling +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CHARSET_H__ +#define BOTAN_CHARSET_H__ + +#include <botan/types.h> +#include <string> + +namespace Botan { + +/** +* The different charsets (nominally) supported by Botan. +*/ +enum Character_Set { + LOCAL_CHARSET, + UCS2_CHARSET, + UTF8_CHARSET, + LATIN1_CHARSET +}; + +namespace Charset { + +/* +* Character Set Handling +*/ +std::string BOTAN_DLL transcode(const std::string& str, + Character_Set to, + Character_Set from); + +bool BOTAN_DLL is_digit(char c); +bool BOTAN_DLL is_space(char c); +bool BOTAN_DLL caseless_cmp(char x, char y); + +byte BOTAN_DLL char2digit(char c); +char BOTAN_DLL digit2char(byte b); + +} + +} + +#endif diff --git a/src/lib/utils/cpuid.cpp b/src/lib/utils/cpuid.cpp new file mode 100644 index 000000000..6da5673c1 --- /dev/null +++ b/src/lib/utils/cpuid.cpp @@ -0,0 +1,236 @@ +/* +* Runtime CPU detection +* (C) 2009-2010,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/cpuid.h> +#include <botan/types.h> +#include <botan/get_byte.h> +#include <botan/mem_ops.h> +#include <ostream> + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + +#if defined(BOTAN_TARGET_OS_IS_DARWIN) + #include <sys/sysctl.h> +#endif + +#if defined(BOTAN_TARGET_OS_IS_OPENBSD) + #include <sys/param.h> + #include <sys/sysctl.h> + #include <machine/cpu.h> +#endif + +#endif + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + +#if defined(BOTAN_BUILD_COMPILER_IS_MSVC) + +#include <intrin.h> + +#define X86_CPUID(type, out) do { __cpuid((int*)out, type); } while(0) +#define X86_CPUID_SUBLEVEL(type, level, out) do { __cpuidex((int*)out, type, level); } while(0) + +#elif defined(BOTAN_BUILD_COMPILER_IS_INTEL) + +#include <ia32intrin.h> + +#define X86_CPUID(type, out) do { __cpuid(out, type); } while(0) +#define X86_CPUID_SUBLEVEL(type, level, out) do { __cpuidex((int*)out, type, level); } while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && BOTAN_USE_GCC_INLINE_ASM + +#define X86_CPUID(type, out) \ + asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \ + : "0" (type)) + +#define X86_CPUID_SUBLEVEL(type, level, out) \ + asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \ + : "0" (type), "2" (level)) + +#elif defined(BOTAN_BUILD_COMPILER_IS_GCC) + +#include <cpuid.h> + +#define X86_CPUID(type, out) do { __get_cpuid(type, out, out+1, out+2, out+3); } while(0) + +#define X86_CPUID_SUBLEVEL(type, level, out) \ + do { __cpuid_count(type, level, out[0], out[1], out[2], out[3]); } while(0) + +#else + +#warning "No way of calling cpuid for this compiler" + +#define X86_CPUID(type, out) do { clear_mem(out, 4); } while(0) +#define X86_CPUID_SUBLEVEL(type, level, out) do { clear_mem(out, 4); } while(0) + +#endif + +#endif + +namespace Botan { + +u64bit CPUID::m_x86_processor_flags[2] = { 0, 0 }; +size_t CPUID::m_cache_line_size = 0; +bool CPUID::m_altivec_capable = false; + +namespace { + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + +bool altivec_check_sysctl() + { +#if defined(BOTAN_TARGET_OS_IS_DARWIN) || defined(BOTAN_TARGET_OS_IS_OPENBSD) + +#if defined(BOTAN_TARGET_OS_IS_OPENBSD) + int sels[2] = { CTL_MACHDEP, CPU_ALTIVEC }; +#else + // From Apple's docs + int sels[2] = { CTL_HW, HW_VECTORUNIT }; +#endif + int vector_type = 0; + size_t length = sizeof(vector_type); + int error = sysctl(sels, 2, &vector_type, &length, NULL, 0); + + if(error == 0 && vector_type > 0) + return true; +#endif + + return false; + } + +bool altivec_check_pvr_emul() + { + bool altivec_capable = false; + +#if defined(BOTAN_TARGET_OS_IS_LINUX) || defined(BOTAN_TARGET_OS_IS_NETBSD) + + /* + On PowerPC, MSR 287 is PVR, the Processor Version Number + Normally it is only accessible to ring 0, but Linux and NetBSD + (others, too, maybe?) will trap and emulate it for us. + + PVR identifiers for various AltiVec enabled CPUs. Taken from + PearPC and Linux sources, mostly. + */ + + const u16bit PVR_G4_7400 = 0x000C; + const u16bit PVR_G5_970 = 0x0039; + const u16bit PVR_G5_970FX = 0x003C; + const u16bit PVR_G5_970MP = 0x0044; + const u16bit PVR_G5_970GX = 0x0045; + const u16bit PVR_POWER6 = 0x003E; + const u16bit PVR_POWER7 = 0x003F; + const u16bit PVR_CELL_PPU = 0x0070; + + // Motorola produced G4s with PVR 0x800[0123C] (at least) + const u16bit PVR_G4_74xx_24 = 0x800; + + u32bit pvr = 0; + + asm volatile("mfspr %0, 287" : "=r" (pvr)); + + // Top 16 bit suffice to identify model + pvr >>= 16; + + altivec_capable |= (pvr == PVR_G4_7400); + altivec_capable |= ((pvr >> 4) == PVR_G4_74xx_24); + altivec_capable |= (pvr == PVR_G5_970); + altivec_capable |= (pvr == PVR_G5_970FX); + altivec_capable |= (pvr == PVR_G5_970MP); + altivec_capable |= (pvr == PVR_G5_970GX); + altivec_capable |= (pvr == PVR_POWER6); + altivec_capable |= (pvr == PVR_POWER7); + altivec_capable |= (pvr == PVR_CELL_PPU); +#endif + + return altivec_capable; + } + +#endif + +} + +void CPUID::print(std::ostream& o) + { + o << "CPUID flags: "; + +#define CPUID_PRINT(flag) do { if(has_##flag()) o << #flag << " "; } while(0) + CPUID_PRINT(sse2); + CPUID_PRINT(ssse3); + CPUID_PRINT(sse41); + CPUID_PRINT(sse42); + CPUID_PRINT(avx2); + CPUID_PRINT(avx512f); + CPUID_PRINT(altivec); + + CPUID_PRINT(rdtsc); + CPUID_PRINT(bmi2); + CPUID_PRINT(clmul); + CPUID_PRINT(aes_ni); + CPUID_PRINT(rdrand); + CPUID_PRINT(rdseed); + CPUID_PRINT(intel_sha); + CPUID_PRINT(adx); +#undef CPUID_PRINT + o << "\n"; + } + +void CPUID::initialize() + { +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + if(altivec_check_sysctl() || altivec_check_pvr_emul()) + altivec_capable = true; +#endif + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + const u32bit INTEL_CPUID[3] = { 0x756E6547, 0x6C65746E, 0x49656E69 }; + const u32bit AMD_CPUID[3] = { 0x68747541, 0x444D4163, 0x69746E65 }; + + u32bit cpuid[4] = { 0 }; + X86_CPUID(0, cpuid); + + const u32bit max_supported_sublevel = cpuid[0]; + + if(max_supported_sublevel == 0) + return; + + const bool is_intel = same_mem(cpuid + 1, INTEL_CPUID, 3); + const bool is_amd = same_mem(cpuid + 1, AMD_CPUID, 3); + + X86_CPUID(1, cpuid); + + m_x86_processor_flags[0] = (static_cast<u64bit>(cpuid[2]) << 32) | cpuid[3]; + + if(is_intel) + m_cache_line_size = 8 * get_byte(2, cpuid[1]); + + if(max_supported_sublevel >= 7) + { + clear_mem(cpuid, 4); + X86_CPUID_SUBLEVEL(7, 0, cpuid); + m_x86_processor_flags[1] = (static_cast<u64bit>(cpuid[2]) << 32) | cpuid[1]; + } + + if(is_amd) + { + X86_CPUID(0x80000005, cpuid); + m_cache_line_size = get_byte(3, cpuid[2]); + } + +#endif + +#if defined(BOTAN_TARGET_ARCH_IS_X86_64) + /* + * If we don't have access to CPUID, we can still safely assume that + * any x86-64 processor has SSE2 and RDTSC + */ + if(m_x86_processor_flags[0] == 0) + m_x86_processor_flags[0] = (1 << CPUID_SSE2_BIT) | (1 << CPUID_RDTSC_BIT); +#endif + } + +} diff --git a/src/lib/utils/cpuid.h b/src/lib/utils/cpuid.h new file mode 100644 index 000000000..1c4c1df0b --- /dev/null +++ b/src/lib/utils/cpuid.h @@ -0,0 +1,153 @@ +/* +* Runtime CPU detection +* (C) 2009-2010,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CPUID_H__ +#define BOTAN_CPUID_H__ + +#include <botan/types.h> +#include <iosfwd> + +namespace Botan { + +/** +* A class handling runtime CPU feature detection +*/ +class BOTAN_DLL CPUID + { + public: + /** + * Probe the CPU and see what extensions are supported + */ + static void initialize(); + + /** + * Return a best guess of the cache line size + */ + static size_t cache_line_size() { return m_cache_line_size; } + + /** + * Check if the processor supports RDTSC + */ + static bool has_rdtsc() + { return x86_processor_flags_has(CPUID_RDTSC_BIT); } + + /** + * Check if the processor supports SSE2 + */ + static bool has_sse2() + { return x86_processor_flags_has(CPUID_SSE2_BIT); } + + /** + * Check if the processor supports SSSE3 + */ + static bool has_ssse3() + { return x86_processor_flags_has(CPUID_SSSE3_BIT); } + + /** + * Check if the processor supports SSE4.1 + */ + static bool has_sse41() + { return x86_processor_flags_has(CPUID_SSE41_BIT); } + + /** + * Check if the processor supports SSE4.2 + */ + static bool has_sse42() + { return x86_processor_flags_has(CPUID_SSE42_BIT); } + + /** + * Check if the processor supports AVX2 + */ + static bool has_avx2() + { return x86_processor_flags_has(CPUID_AVX2_BIT); } + + /** + * Check if the processor supports AVX-512F + */ + static bool has_avx512f() + { return x86_processor_flags_has(CPUID_AVX512F_BIT); } + + /** + * Check if the processor supports BMI2 + */ + static bool has_bmi2() + { return x86_processor_flags_has(CPUID_BMI2_BIT); } + + /** + * Check if the processor supports AES-NI + */ + static bool has_aes_ni() + { return x86_processor_flags_has(CPUID_AESNI_BIT); } + + /** + * Check if the processor supports CLMUL + */ + static bool has_clmul() + { return x86_processor_flags_has(CPUID_CLMUL_BIT); } + + /** + * Check if the processor supports Intel SHA extension + */ + static bool has_intel_sha() + { return x86_processor_flags_has(CPUID_SHA_BIT); } + + /** + * Check if the processor supports ADX extension + */ + static bool has_adx() + { return x86_processor_flags_has(CPUID_ADX_BIT); } + + /** + * Check if the processor supports RDRAND + */ + static bool has_rdrand() + { return x86_processor_flags_has(CPUID_RDRAND_BIT); } + + /** + * Check if the processor supports RDSEED + */ + static bool has_rdseed() + { return x86_processor_flags_has(CPUID_RDSEED_BIT); } + + /** + * Check if the processor supports AltiVec/VMX + */ + static bool has_altivec() { return m_altivec_capable; } + + static void print(std::ostream& o); + private: + enum CPUID_bits { + CPUID_RDTSC_BIT = 4, + CPUID_SSE2_BIT = 26, + CPUID_CLMUL_BIT = 33, + CPUID_SSSE3_BIT = 41, + CPUID_SSE41_BIT = 51, + CPUID_SSE42_BIT = 52, + CPUID_AESNI_BIT = 57, + CPUID_RDRAND_BIT = 62, + + CPUID_AVX2_BIT = 64+5, + CPUID_BMI2_BIT = 64+8, + CPUID_AVX512F_BIT = 64+16, + CPUID_RDSEED_BIT = 64+18, + CPUID_ADX_BIT = 64+19, + CPUID_SHA_BIT = 64+29, + }; + + static bool x86_processor_flags_has(u64bit bit) + { + return ((m_x86_processor_flags[bit/64] >> (bit % 64)) & 1); + } + + static u64bit m_x86_processor_flags[2]; + static size_t m_cache_line_size; + static bool m_altivec_capable; + }; + +} + +#endif diff --git a/src/lib/utils/datastor/datastor.cpp b/src/lib/utils/datastor/datastor.cpp new file mode 100644 index 000000000..7563e9309 --- /dev/null +++ b/src/lib/utils/datastor/datastor.cpp @@ -0,0 +1,165 @@ +/* +* Data Store +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/datastor.h> +#include <botan/exceptn.h> +#include <botan/parsing.h> +#include <botan/hex.h> +#include <botan/internal/stl_util.h> + +namespace Botan { + +/* +* Data_Store Equality Comparison +*/ +bool Data_Store::operator==(const Data_Store& other) const + { + return (contents == other.contents); + } + +/* +* Check if this key has at least one value +*/ +bool Data_Store::has_value(const std::string& key) const + { + return (contents.lower_bound(key) != contents.end()); + } + +/* +* Search based on an arbitrary predicate +*/ +std::multimap<std::string, std::string> Data_Store::search_for( + std::function<bool (std::string, std::string)> predicate) const + { + std::multimap<std::string, std::string> out; + + for(auto i = contents.begin(); i != contents.end(); ++i) + if(predicate(i->first, i->second)) + out.insert(std::make_pair(i->first, i->second)); + + return out; + } + +/* +* Search based on key equality +*/ +std::vector<std::string> Data_Store::get(const std::string& looking_for) const + { + std::vector<std::string> out; + auto range = contents.equal_range(looking_for); + for(auto i = range.first; i != range.second; ++i) + out.push_back(i->second); + return out; + } + +/* +* Get a single atom +*/ +std::string Data_Store::get1(const std::string& key) const + { + std::vector<std::string> vals = get(key); + + if(vals.empty()) + throw Invalid_State("Data_Store::get1: No values set for " + key); + if(vals.size() > 1) + throw Invalid_State("Data_Store::get1: More than one value for " + key); + + return vals[0]; + } + +std::string Data_Store::get1(const std::string& key, + const std::string& default_value) const + { + std::vector<std::string> vals = get(key); + + if(vals.size() > 1) + throw Invalid_State("Data_Store::get1: More than one value for " + key); + + if(vals.empty()) + return default_value; + + return vals[0]; + } + +/* +* Get a single std::vector atom +*/ +std::vector<byte> +Data_Store::get1_memvec(const std::string& key) const + { + std::vector<std::string> vals = get(key); + + if(vals.empty()) + return std::vector<byte>(); + + if(vals.size() > 1) + throw Invalid_State("Data_Store::get1_memvec: Multiple values for " + + key); + + return hex_decode(vals[0]); + } + +/* +* Get a single u32bit atom +*/ +u32bit Data_Store::get1_u32bit(const std::string& key, + u32bit default_val) const + { + std::vector<std::string> vals = get(key); + + if(vals.empty()) + return default_val; + else if(vals.size() > 1) + throw Invalid_State("Data_Store::get1_u32bit: Multiple values for " + + key); + + return to_u32bit(vals[0]); + } + +/* +* Insert a single key and value +*/ +void Data_Store::add(const std::string& key, const std::string& val) + { + multimap_insert(contents, key, val); + } + +/* +* Insert a single key and value +*/ +void Data_Store::add(const std::string& key, u32bit val) + { + add(key, std::to_string(val)); + } + +/* +* Insert a single key and value +*/ +void Data_Store::add(const std::string& key, const secure_vector<byte>& val) + { + add(key, hex_encode(&val[0], val.size())); + } + +void Data_Store::add(const std::string& key, const std::vector<byte>& val) + { + add(key, hex_encode(&val[0], val.size())); + } + +/* +* Insert a mapping of key/value pairs +*/ +void Data_Store::add(const std::multimap<std::string, std::string>& in) + { + std::multimap<std::string, std::string>::const_iterator i = in.begin(); + while(i != in.end()) + { + contents.insert(*i); + ++i; + } + } + +} diff --git a/src/lib/utils/datastor/datastor.h b/src/lib/utils/datastor/datastor.h new file mode 100644 index 000000000..1c0504fc9 --- /dev/null +++ b/src/lib/utils/datastor/datastor.h @@ -0,0 +1,57 @@ +/* +* Data Store +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DATA_STORE_H__ +#define BOTAN_DATA_STORE_H__ + +#include <botan/secmem.h> +#include <functional> +#include <utility> +#include <string> +#include <vector> +#include <map> + +namespace Botan { + +/** +* Data Store +*/ +class BOTAN_DLL Data_Store + { + public: + /** + * A search function + */ + bool operator==(const Data_Store&) const; + + std::multimap<std::string, std::string> search_for( + std::function<bool (std::string, std::string)> predicate) const; + + std::vector<std::string> get(const std::string&) const; + + std::string get1(const std::string& key) const; + + std::string get1(const std::string& key, + const std::string& default_value) const; + + std::vector<byte> get1_memvec(const std::string&) const; + u32bit get1_u32bit(const std::string&, u32bit = 0) const; + + bool has_value(const std::string&) const; + + void add(const std::multimap<std::string, std::string>&); + void add(const std::string&, const std::string&); + void add(const std::string&, u32bit); + void add(const std::string&, const secure_vector<byte>&); + void add(const std::string&, const std::vector<byte>&); + private: + std::multimap<std::string, std::string> contents; + }; + +} + +#endif diff --git a/src/lib/utils/datastor/info.txt b/src/lib/utils/datastor/info.txt new file mode 100644 index 000000000..b91fe5082 --- /dev/null +++ b/src/lib/utils/datastor/info.txt @@ -0,0 +1,3 @@ +<requires> +alloc +</requires> diff --git a/src/lib/utils/dyn_load/dyn_load.cpp b/src/lib/utils/dyn_load/dyn_load.cpp new file mode 100644 index 000000000..51afb1afe --- /dev/null +++ b/src/lib/utils/dyn_load/dyn_load.cpp @@ -0,0 +1,79 @@ +/** +* Dynamically Loaded Object +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/dyn_load.h> +#include <botan/build.h> +#include <stdexcept> + +#if defined(BOTAN_TARGET_OS_HAS_DLOPEN) + #include <dlfcn.h> +#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY) + #include <windows.h> +#endif + +namespace Botan { + +namespace { + +void raise_runtime_loader_exception(const std::string& lib_name, + const char* msg) + { + throw std::runtime_error("Failed to load " + lib_name + ": " + + (msg ? msg : "Unknown error")); + } + +} + +Dynamically_Loaded_Library::Dynamically_Loaded_Library( + const std::string& library) : + lib_name(library), lib(nullptr) + { +#if defined(BOTAN_TARGET_OS_HAS_DLOPEN) + lib = ::dlopen(lib_name.c_str(), RTLD_LAZY); + + if(!lib) + raise_runtime_loader_exception(lib_name, dlerror()); + +#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY) + lib = ::LoadLibraryA(lib_name.c_str()); + + if(!lib) + raise_runtime_loader_exception(lib_name, "LoadLibrary failed"); +#endif + + if(!lib) + raise_runtime_loader_exception(lib_name, "Dynamic load not supported"); + } + +Dynamically_Loaded_Library::~Dynamically_Loaded_Library() + { +#if defined(BOTAN_TARGET_OS_HAS_DLOPEN) + ::dlclose(lib); +#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY) + ::FreeLibrary((HMODULE)lib); +#endif + } + +void* Dynamically_Loaded_Library::resolve_symbol(const std::string& symbol) + { + void* addr = nullptr; + +#if defined(BOTAN_TARGET_OS_HAS_DLOPEN) + addr = ::dlsym(lib, symbol.c_str()); +#elif defined(BOTAN_TARGET_OS_HAS_LOADLIBRARY) + addr = reinterpret_cast<void*>(::GetProcAddress((HMODULE)lib, + symbol.c_str())); +#endif + + if(!addr) + throw std::runtime_error("Failed to resolve symbol " + symbol + + " in " + lib_name); + + return addr; + } + +} diff --git a/src/lib/utils/dyn_load/dyn_load.h b/src/lib/utils/dyn_load/dyn_load.h new file mode 100644 index 000000000..9edaed202 --- /dev/null +++ b/src/lib/utils/dyn_load/dyn_load.h @@ -0,0 +1,67 @@ +/* +* Dynamically Loaded Object +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DYNAMIC_LOADER_H__ +#define BOTAN_DYNAMIC_LOADER_H__ + +#include <string> + +namespace Botan { + +/** +* Represents a DLL or shared object +*/ +class Dynamically_Loaded_Library + { + public: + /** + * Load a DLL (or fail with an exception) + * @param lib_name name or path to a library + * + * If you don't use a full path, the search order will be defined + * by whatever the system linker does by default. Always using fully + * qualified pathnames can help prevent code injection attacks (eg + * via manipulation of LD_LIBRARY_PATH on Linux) + */ + Dynamically_Loaded_Library(const std::string& lib_name); + + /** + * Unload the DLL + * @warning Any pointers returned by resolve()/resolve_symbol() + * should not be used after this destructor runs. + */ + ~Dynamically_Loaded_Library(); + + /** + * Load a symbol (or fail with an exception) + * @param symbol names the symbol to load + * @return address of the loaded symbol + */ + void* resolve_symbol(const std::string& symbol); + + /** + * Convenience function for casting symbol to the right type + * @param symbol names the symbol to load + * @return address of the loaded symbol + */ + template<typename T> + T resolve(const std::string& symbol) + { + return reinterpret_cast<T>(resolve_symbol(symbol)); + } + + private: + Dynamically_Loaded_Library(const Dynamically_Loaded_Library&); + Dynamically_Loaded_Library& operator=(const Dynamically_Loaded_Library&); + + std::string lib_name; + void* lib; + }; + +} + +#endif diff --git a/src/lib/utils/dyn_load/info.txt b/src/lib/utils/dyn_load/info.txt new file mode 100644 index 000000000..c8d91dd75 --- /dev/null +++ b/src/lib/utils/dyn_load/info.txt @@ -0,0 +1,24 @@ +define DYNAMIC_LOADER 20131128 + +<os> +freebsd +linux +netbsd +openbsd +qnx +solaris +windows +</os> + +<libs> +linux -> dl +solaris -> dl +</libs> + +<source> +dyn_load.cpp +</source> + +<header:internal> +dyn_load.h +</header:internal> diff --git a/src/lib/utils/exceptn.h b/src/lib/utils/exceptn.h new file mode 100644 index 000000000..c480ffd48 --- /dev/null +++ b/src/lib/utils/exceptn.h @@ -0,0 +1,181 @@ +/* +* Exceptions +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EXCEPTION_H__ +#define BOTAN_EXCEPTION_H__ + +#include <botan/types.h> +#include <botan/parsing.h> +#include <exception> +#include <stdexcept> +#include <string> + +namespace Botan { + +typedef std::runtime_error Exception; +typedef std::invalid_argument Invalid_Argument; + +/** +* Invalid_State Exception +*/ +struct BOTAN_DLL Invalid_State : public Exception + { + Invalid_State(const std::string& err) : + Exception(err) + {} + }; + +/** +* Lookup_Error Exception +*/ +struct BOTAN_DLL Lookup_Error : public Exception + { + Lookup_Error(const std::string& err) : + Exception(err) + {} + }; + +/** +* Internal_Error Exception +*/ +struct BOTAN_DLL Internal_Error : public Exception + { + Internal_Error(const std::string& err) : + Exception("Internal error: " + err) + {} + }; + +/** +* Invalid_Key_Length Exception +*/ +struct BOTAN_DLL Invalid_Key_Length : public Invalid_Argument + { + Invalid_Key_Length(const std::string& name, size_t length) : + Invalid_Argument(name + " cannot accept a key of length " + + std::to_string(length)) + {} + }; + +/** +* Invalid_IV_Length Exception +*/ +struct BOTAN_DLL Invalid_IV_Length : public Invalid_Argument + { + Invalid_IV_Length(const std::string& mode, size_t bad_len) : + Invalid_Argument("IV length " + std::to_string(bad_len) + + " is invalid for " + mode) + {} + }; + +/** +* PRNG_Unseeded Exception +*/ +struct BOTAN_DLL PRNG_Unseeded : public Invalid_State + { + PRNG_Unseeded(const std::string& algo) : + Invalid_State("PRNG not seeded: " + algo) + {} + }; + +/** +* Policy_Violation Exception +*/ +struct BOTAN_DLL Policy_Violation : public Invalid_State + { + Policy_Violation(const std::string& err) : + Invalid_State("Policy violation: " + err) + {} + }; + +/** +* Algorithm_Not_Found Exception +*/ +struct BOTAN_DLL Algorithm_Not_Found : public Lookup_Error + { + Algorithm_Not_Found(const std::string& name) : + Lookup_Error("Could not find any algorithm named \"" + name + "\"") + {} + }; + +/** +* Invalid_Algorithm_Name Exception +*/ +struct BOTAN_DLL Invalid_Algorithm_Name : public Invalid_Argument + { + Invalid_Algorithm_Name(const std::string& name): + Invalid_Argument("Invalid algorithm name: " + name) + {} + }; + +/** +* Encoding_Error Exception +*/ +struct BOTAN_DLL Encoding_Error : public Invalid_Argument + { + Encoding_Error(const std::string& name) : + Invalid_Argument("Encoding error: " + name) {} + }; + +/** +* Decoding_Error Exception +*/ +struct BOTAN_DLL Decoding_Error : public Invalid_Argument + { + Decoding_Error(const std::string& name) : + Invalid_Argument("Decoding error: " + name) {} + }; + +/** +* Integrity_Failure Exception +*/ +struct BOTAN_DLL Integrity_Failure : public Exception + { + Integrity_Failure(const std::string& msg) : + Exception("Integrity failure: " + msg) {} + }; + +/** +* Invalid_OID Exception +*/ +struct BOTAN_DLL Invalid_OID : public Decoding_Error + { + Invalid_OID(const std::string& oid) : + Decoding_Error("Invalid ASN.1 OID: " + oid) {} + }; + +/** +* Stream_IO_Error Exception +*/ +struct BOTAN_DLL Stream_IO_Error : public Exception + { + Stream_IO_Error(const std::string& err) : + Exception("I/O error: " + err) + {} + }; + +/** +* Self Test Failure Exception +*/ +struct BOTAN_DLL Self_Test_Failure : public Internal_Error + { + Self_Test_Failure(const std::string& err) : + Internal_Error("Self test failed: " + err) + {} + }; + +/** +* Memory Allocation Exception +*/ +struct BOTAN_DLL Memory_Exhaustion : public std::bad_alloc + { + const char* what() const noexcept + { return "Ran out of memory, allocation failed"; } + }; + +} + +#endif diff --git a/src/lib/utils/get_byte.h b/src/lib/utils/get_byte.h new file mode 100644 index 000000000..6f8ef2632 --- /dev/null +++ b/src/lib/utils/get_byte.h @@ -0,0 +1,30 @@ +/* +* Read out bytes +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_GET_BYTE_H__ +#define BOTAN_GET_BYTE_H__ + +#include <botan/types.h> + +namespace Botan { + +/** +* Byte extraction +* @param byte_num which byte to extract, 0 == highest byte +* @param input the value to extract from +* @return byte byte_num of input +*/ +template<typename T> inline byte get_byte(size_t byte_num, T input) + { + return static_cast<byte>( + input >> ((sizeof(T)-1-(byte_num&(sizeof(T)-1))) << 3) + ); + } + +} + +#endif diff --git a/src/lib/utils/http_util/http_util.cpp b/src/lib/utils/http_util/http_util.cpp new file mode 100644 index 000000000..a233c1c60 --- /dev/null +++ b/src/lib/utils/http_util/http_util.cpp @@ -0,0 +1,220 @@ +/* +* Sketchy HTTP client +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/http_util.h> +#include <botan/parsing.h> +#include <botan/hex.h> +#include <sstream> + +#if defined(BOTAN_HAS_BOOST_ASIO) +#include <boost/asio.hpp> +#endif + +namespace Botan { + +namespace HTTP { + +#if defined(BOTAN_HAS_BOOST_ASIO) +std::string http_transact_asio(const std::string& hostname, + const std::string& message) + { + using namespace boost::asio::ip; + + boost::asio::ip::tcp::iostream tcp; + + tcp.connect(hostname, "http"); + + if(!tcp) + throw std::runtime_error("HTTP connection to " + hostname + " failed"); + + tcp << message; + tcp.flush(); + + std::ostringstream oss; + oss << tcp.rdbuf(); + + return oss.str(); + } +#endif + +std::string http_transact_fail(const std::string& hostname, + const std::string&) + { + throw std::runtime_error("Cannot connect to " + hostname + + ": network code disabled in build"); + } + +std::string url_encode(const std::string& in) + { + std::ostringstream out; + + for(auto c : in) + { + if(c >= 'A' && c <= 'Z') + out << c; + else if(c >= 'a' && c <= 'z') + out << c; + else if(c >= '0' && c <= '9') + out << c; + else if(c == '-' || c == '_' || c == '.' || c == '~') + out << c; + else + out << '%' << hex_encode(reinterpret_cast<byte*>(&c), 1); + } + + return out.str(); + } + +std::ostream& operator<<(std::ostream& o, const Response& resp) + { + o << "HTTP " << resp.status_code() << " " << resp.status_message() << "\n"; + for(auto h : resp.headers()) + o << "Header '" << h.first << "' = '" << h.second << "'\n"; + o << "Body " << std::to_string(resp.body().size()) << " bytes:\n"; + o.write(reinterpret_cast<const char*>(&resp.body()[0]), resp.body().size()); + return o; + } + +Response http_sync(http_exch_fn http_transact, + const std::string& verb, + const std::string& url, + const std::string& content_type, + const std::vector<byte>& body, + size_t allowable_redirects) + { + const auto protocol_host_sep = url.find("://"); + if(protocol_host_sep == std::string::npos) + throw std::runtime_error("Invalid URL " + url); + const std::string protocol = url.substr(0, protocol_host_sep); + + const auto host_loc_sep = url.find('/', protocol_host_sep + 3); + + std::string hostname, loc; + + if(host_loc_sep == std::string::npos) + { + hostname = url.substr(protocol_host_sep + 3, std::string::npos); + loc = "/"; + } + else + { + hostname = url.substr(protocol_host_sep + 3, host_loc_sep-protocol_host_sep-3); + loc = url.substr(host_loc_sep, std::string::npos); + } + + std::ostringstream outbuf; + + outbuf << verb << " " << loc << " HTTP/1.0\r\n"; + outbuf << "Host: " << hostname << "\r\n"; + + if(verb == "GET") + { + outbuf << "Accept: */*\r\n"; + outbuf << "Cache-Control: no-cache\r\n"; + } + else if(verb == "POST") + outbuf << "Content-Length: " << body.size() << "\r\n"; + + if(content_type != "") + outbuf << "Content-Type: " << content_type << "\r\n"; + outbuf << "Connection: close\r\n\r\n"; + outbuf.write(reinterpret_cast<const char*>(&body[0]), body.size()); + + std::istringstream io(http_transact(hostname, outbuf.str())); + + std::string line1; + std::getline(io, line1); + if(!io || line1.empty()) + throw std::runtime_error("No response"); + + std::stringstream response_stream(line1); + std::string http_version; + unsigned int status_code; + std::string status_message; + + response_stream >> http_version >> status_code; + + std::getline(response_stream, status_message); + + if(!response_stream || http_version.substr(0,5) != "HTTP/") + throw std::runtime_error("Not an HTTP response"); + + std::map<std::string, std::string> headers; + std::string header_line; + while (std::getline(io, header_line) && header_line != "\r") + { + auto sep = header_line.find(": "); + if(sep == std::string::npos || sep > header_line.size() - 2) + throw std::runtime_error("Invalid HTTP header " + header_line); + const std::string key = header_line.substr(0, sep); + + if(sep + 2 < header_line.size() - 1) + { + const std::string val = header_line.substr(sep + 2, (header_line.size() - 1) - (sep + 2)); + headers[key] = val; + } + } + + if(status_code == 301 && headers.count("Location")) + { + if(allowable_redirects == 0) + throw std::runtime_error("HTTP redirection count exceeded"); + return GET_sync(headers["Location"], allowable_redirects - 1); + } + + // Use Content-Length if set + std::vector<byte> resp_body; + std::vector<byte> buf(4096); + while(io.good()) + { + io.read(reinterpret_cast<char*>(&buf[0]), buf.size()); + resp_body.insert(resp_body.end(), &buf[0], &buf[io.gcount()]); + } + + return Response(status_code, status_message, resp_body, headers); + } + +Response http_sync(const std::string& verb, + const std::string& url, + const std::string& content_type, + const std::vector<byte>& body, + size_t allowable_redirects) + { + return http_sync( +#if defined(BOTAN_HAS_BOOST_ASIO) + http_transact_asio, +#else + http_transact_fail, +#endif + verb, + url, + content_type, + body, + allowable_redirects); + } + +Response GET_sync(const std::string& url, size_t allowable_redirects) + { + return http_sync("GET", url, "", std::vector<byte>(), allowable_redirects); + } + +Response POST_sync(const std::string& url, + const std::string& content_type, + const std::vector<byte>& body, + size_t allowable_redirects) + { + return http_sync("POST", url, content_type, body, allowable_redirects); + } + +std::future<Response> GET_async(const std::string& url, size_t allowable_redirects) + { + return std::async(std::launch::async, GET_sync, url, allowable_redirects); + } + +} + +} diff --git a/src/lib/utils/http_util/http_util.h b/src/lib/utils/http_util/http_util.h new file mode 100644 index 000000000..d024add4d --- /dev/null +++ b/src/lib/utils/http_util/http_util.h @@ -0,0 +1,97 @@ +/* +* HTTP utilities +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_UTILS_URLGET_H__ +#define BOTAN_UTILS_URLGET_H__ + +#include <botan/types.h> +#include <future> +#include <vector> +#include <map> +#include <chrono> +#include <string> + +namespace Botan { + +namespace HTTP { + +struct Response + { + public: + Response(unsigned int status_code, const std::string& status_message, + const std::vector<byte>& body, + const std::map<std::string, std::string>& headers) : + m_status_code(status_code), + m_status_message(status_message), + m_body(body), + m_headers(headers) {} + + unsigned int status_code() const { return m_status_code; } + + const std::vector<byte>& body() const { return m_body; } + + const std::map<std::string, std::string>& headers() const { return m_headers; } + + std::string status_message() const { return m_status_message; } + + void throw_unless_ok() + { + if(status_code() != 200) + throw std::runtime_error("HTTP error: " + status_message()); + } + + private: + unsigned int m_status_code; + std::string m_status_message; + std::vector<byte> m_body; + std::map<std::string, std::string> m_headers; + }; + +BOTAN_DLL std::ostream& operator<<(std::ostream& o, const Response& resp); + +typedef std::function<std::string (const std::string&, const std::string&)> http_exch_fn; + +#if defined(BOTAN_HAS_BOOST_ASIO) +std::string BOTAN_DLL http_transact_asio(const std::string& hostname, + const std::string& message); +#endif + +std::string BOTAN_DLL http_transact_fail(const std::string& hostname, + const std::string& message); + + +BOTAN_DLL Response http_sync(http_exch_fn fn, + const std::string& verb, + const std::string& url, + const std::string& content_type, + const std::vector<byte>& body, + size_t allowable_redirects); + +BOTAN_DLL Response http_sync(const std::string& verb, + const std::string& url, + const std::string& content_type, + const std::vector<byte>& body, + size_t allowable_redirects); + +BOTAN_DLL Response GET_sync(const std::string& url, + size_t allowable_redirects = 1); + +BOTAN_DLL Response POST_sync(const std::string& url, + const std::string& content_type, + const std::vector<byte>& body, + size_t allowable_redirects = 1); + +std::future<Response> BOTAN_DLL GET_async(const std::string& url, + size_t allowable_redirects = 1); + +BOTAN_DLL std::string url_encode(const std::string& url); + +} + +} + +#endif diff --git a/src/lib/utils/http_util/info.txt b/src/lib/utils/http_util/info.txt new file mode 100644 index 000000000..a23a43a3d --- /dev/null +++ b/src/lib/utils/http_util/info.txt @@ -0,0 +1 @@ +define HTTP_UTIL 20131128 diff --git a/src/lib/utils/info.txt b/src/lib/utils/info.txt new file mode 100644 index 000000000..0e8edeb00 --- /dev/null +++ b/src/lib/utils/info.txt @@ -0,0 +1,29 @@ +define UTIL_FUNCTIONS 20131128 + +load_on always + +<header:internal> +bit_ops.h +prefetch.h +rounding.h +semaphore.h +stl_util.h +xor_buf.h +</header:internal> + +<header:public> +assert.h +bswap.h +calendar.h +charset.h +cpuid.h +exceptn.h +get_byte.h +loadstor.h +mem_ops.h +mul128.h +parsing.h +rotate.h +types.h +version.h +</header:public> diff --git a/src/lib/utils/loadstor.h b/src/lib/utils/loadstor.h new file mode 100644 index 000000000..29e00592a --- /dev/null +++ b/src/lib/utils/loadstor.h @@ -0,0 +1,627 @@ +/* +* Load/Store Operators +* (C) 1999-2007 Jack Lloyd +* 2007 Yves Jerschow +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_LOAD_STORE_H__ +#define BOTAN_LOAD_STORE_H__ + +#include <botan/types.h> +#include <botan/bswap.h> +#include <botan/get_byte.h> +#include <cstring> + +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + +#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + +#define BOTAN_ENDIAN_N2B(x) (x) +#define BOTAN_ENDIAN_B2N(x) (x) + +#define BOTAN_ENDIAN_N2L(x) reverse_bytes(x) +#define BOTAN_ENDIAN_L2N(x) reverse_bytes(x) + +#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + +#define BOTAN_ENDIAN_N2L(x) (x) +#define BOTAN_ENDIAN_L2N(x) (x) + +#define BOTAN_ENDIAN_N2B(x) reverse_bytes(x) +#define BOTAN_ENDIAN_B2N(x) reverse_bytes(x) + +#endif + +#endif + +namespace Botan { + +/** +* Make a u16bit from two bytes +* @param i0 the first byte +* @param i1 the second byte +* @return i0 || i1 +*/ +inline u16bit make_u16bit(byte i0, byte i1) + { + return ((static_cast<u16bit>(i0) << 8) | i1); + } + +/** +* Make a u32bit from four bytes +* @param i0 the first byte +* @param i1 the second byte +* @param i2 the third byte +* @param i3 the fourth byte +* @return i0 || i1 || i2 || i3 +*/ +inline u32bit make_u32bit(byte i0, byte i1, byte i2, byte i3) + { + return ((static_cast<u32bit>(i0) << 24) | + (static_cast<u32bit>(i1) << 16) | + (static_cast<u32bit>(i2) << 8) | + (static_cast<u32bit>(i3))); + } + +/** +* Make a u32bit from eight bytes +* @param i0 the first byte +* @param i1 the second byte +* @param i2 the third byte +* @param i3 the fourth byte +* @param i4 the fifth byte +* @param i5 the sixth byte +* @param i6 the seventh byte +* @param i7 the eighth byte +* @return i0 || i1 || i2 || i3 || i4 || i5 || i6 || i7 +*/ +inline u64bit make_u64bit(byte i0, byte i1, byte i2, byte i3, + byte i4, byte i5, byte i6, byte i7) + { + return ((static_cast<u64bit>(i0) << 56) | + (static_cast<u64bit>(i1) << 48) | + (static_cast<u64bit>(i2) << 40) | + (static_cast<u64bit>(i3) << 32) | + (static_cast<u64bit>(i4) << 24) | + (static_cast<u64bit>(i5) << 16) | + (static_cast<u64bit>(i6) << 8) | + (static_cast<u64bit>(i7))); + } + +/** +* Load a big-endian word +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th T of in, as a big-endian value +*/ +template<typename T> +inline T load_be(const byte in[], size_t off) + { + in += off * sizeof(T); + T out = 0; + for(size_t i = 0; i != sizeof(T); ++i) + out = (out << 8) | in[i]; + return out; + } + +/** +* Load a little-endian word +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th T of in, as a litte-endian value +*/ +template<typename T> +inline T load_le(const byte in[], size_t off) + { + in += off * sizeof(T); + T out = 0; + for(size_t i = 0; i != sizeof(T); ++i) + out = (out << 8) | in[sizeof(T)-1-i]; + return out; + } + +/** +* Load a big-endian u16bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u16bit of in, as a big-endian value +*/ +template<> +inline u16bit load_be<u16bit>(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2B(*(reinterpret_cast<const u16bit*>(in) + off)); +#else + in += off * sizeof(u16bit); + return make_u16bit(in[0], in[1]); +#endif + } + +/** +* Load a little-endian u16bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u16bit of in, as a little-endian value +*/ +template<> +inline u16bit load_le<u16bit>(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2L(*(reinterpret_cast<const u16bit*>(in) + off)); +#else + in += off * sizeof(u16bit); + return make_u16bit(in[1], in[0]); +#endif + } + +/** +* Load a big-endian u32bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u32bit of in, as a big-endian value +*/ +template<> +inline u32bit load_be<u32bit>(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2B(*(reinterpret_cast<const u32bit*>(in) + off)); +#else + in += off * sizeof(u32bit); + return make_u32bit(in[0], in[1], in[2], in[3]); +#endif + } + +/** +* Load a little-endian u32bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u32bit of in, as a little-endian value +*/ +template<> +inline u32bit load_le<u32bit>(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2L(*(reinterpret_cast<const u32bit*>(in) + off)); +#else + in += off * sizeof(u32bit); + return make_u32bit(in[3], in[2], in[1], in[0]); +#endif + } + +/** +* Load a big-endian u64bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u64bit of in, as a big-endian value +*/ +template<> +inline u64bit load_be<u64bit>(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2B(*(reinterpret_cast<const u64bit*>(in) + off)); +#else + in += off * sizeof(u64bit); + return make_u64bit(in[0], in[1], in[2], in[3], + in[4], in[5], in[6], in[7]); +#endif + } + +/** +* Load a little-endian u64bit +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th u64bit of in, as a little-endian value +*/ +template<> +inline u64bit load_le<u64bit>(const byte in[], size_t off) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + return BOTAN_ENDIAN_N2L(*(reinterpret_cast<const u64bit*>(in) + off)); +#else + in += off * sizeof(u64bit); + return make_u64bit(in[7], in[6], in[5], in[4], + in[3], in[2], in[1], in[0]); +#endif + } + +/** +* Load two little-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +*/ +template<typename T> +inline void load_le(const byte in[], T& x0, T& x1) + { + x0 = load_le<T>(in, 0); + x1 = load_le<T>(in, 1); + } + +/** +* Load four little-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +*/ +template<typename T> +inline void load_le(const byte in[], + T& x0, T& x1, T& x2, T& x3) + { + x0 = load_le<T>(in, 0); + x1 = load_le<T>(in, 1); + x2 = load_le<T>(in, 2); + x3 = load_le<T>(in, 3); + } + +/** +* Load eight little-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +* @param x4 where the fifth word will be written +* @param x5 where the sixth word will be written +* @param x6 where the seventh word will be written +* @param x7 where the eighth word will be written +*/ +template<typename T> +inline void load_le(const byte in[], + T& x0, T& x1, T& x2, T& x3, + T& x4, T& x5, T& x6, T& x7) + { + x0 = load_le<T>(in, 0); + x1 = load_le<T>(in, 1); + x2 = load_le<T>(in, 2); + x3 = load_le<T>(in, 3); + x4 = load_le<T>(in, 4); + x5 = load_le<T>(in, 5); + x6 = load_le<T>(in, 6); + x7 = load_le<T>(in, 7); + } + +/** +* Load a variable number of little-endian words +* @param out the output array of words +* @param in the input array of bytes +* @param count how many words are in in +*/ +template<typename T> +inline void load_le(T out[], + const byte in[], + size_t count) + { +#if defined(BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS) + std::memcpy(out, in, sizeof(T)*count); + +#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + const size_t blocks = count - (count % 4); + const size_t left = count - blocks; + + for(size_t i = 0; i != blocks; i += 4) + bswap_4(out + i); + + for(size_t i = 0; i != left; ++i) + out[blocks+i] = reverse_bytes(out[blocks+i]); +#endif + +#else + for(size_t i = 0; i != count; ++i) + out[i] = load_le<T>(in, i); +#endif + } + +/** +* Load two big-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +*/ +template<typename T> +inline void load_be(const byte in[], T& x0, T& x1) + { + x0 = load_be<T>(in, 0); + x1 = load_be<T>(in, 1); + } + +/** +* Load four big-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +*/ +template<typename T> +inline void load_be(const byte in[], + T& x0, T& x1, T& x2, T& x3) + { + x0 = load_be<T>(in, 0); + x1 = load_be<T>(in, 1); + x2 = load_be<T>(in, 2); + x3 = load_be<T>(in, 3); + } + +/** +* Load eight big-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +* @param x4 where the fifth word will be written +* @param x5 where the sixth word will be written +* @param x6 where the seventh word will be written +* @param x7 where the eighth word will be written +*/ +template<typename T> +inline void load_be(const byte in[], + T& x0, T& x1, T& x2, T& x3, + T& x4, T& x5, T& x6, T& x7) + { + x0 = load_be<T>(in, 0); + x1 = load_be<T>(in, 1); + x2 = load_be<T>(in, 2); + x3 = load_be<T>(in, 3); + x4 = load_be<T>(in, 4); + x5 = load_be<T>(in, 5); + x6 = load_be<T>(in, 6); + x7 = load_be<T>(in, 7); + } + +/** +* Load a variable number of big-endian words +* @param out the output array of words +* @param in the input array of bytes +* @param count how many words are in in +*/ +template<typename T> +inline void load_be(T out[], + const byte in[], + size_t count) + { +#if defined(BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS) + std::memcpy(out, in, sizeof(T)*count); + +#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + const size_t blocks = count - (count % 4); + const size_t left = count - blocks; + + for(size_t i = 0; i != blocks; i += 4) + bswap_4(out + i); + + for(size_t i = 0; i != left; ++i) + out[blocks+i] = reverse_bytes(out[blocks+i]); +#endif + +#else + for(size_t i = 0; i != count; ++i) + out[i] = load_be<T>(in, i); +#endif + } + +/** +* Store a big-endian u16bit +* @param in the input u16bit +* @param out the byte array to write to +*/ +inline void store_be(u16bit in, byte out[2]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast<u16bit*>(out) = BOTAN_ENDIAN_B2N(in); +#else + out[0] = get_byte(0, in); + out[1] = get_byte(1, in); +#endif + } + +/** +* Store a little-endian u16bit +* @param in the input u16bit +* @param out the byte array to write to +*/ +inline void store_le(u16bit in, byte out[2]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast<u16bit*>(out) = BOTAN_ENDIAN_L2N(in); +#else + out[0] = get_byte(1, in); + out[1] = get_byte(0, in); +#endif + } + +/** +* Store a big-endian u32bit +* @param in the input u32bit +* @param out the byte array to write to +*/ +inline void store_be(u32bit in, byte out[4]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast<u32bit*>(out) = BOTAN_ENDIAN_B2N(in); +#else + out[0] = get_byte(0, in); + out[1] = get_byte(1, in); + out[2] = get_byte(2, in); + out[3] = get_byte(3, in); +#endif + } + +/** +* Store a little-endian u32bit +* @param in the input u32bit +* @param out the byte array to write to +*/ +inline void store_le(u32bit in, byte out[4]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast<u32bit*>(out) = BOTAN_ENDIAN_L2N(in); +#else + out[0] = get_byte(3, in); + out[1] = get_byte(2, in); + out[2] = get_byte(1, in); + out[3] = get_byte(0, in); +#endif + } + +/** +* Store a big-endian u64bit +* @param in the input u64bit +* @param out the byte array to write to +*/ +inline void store_be(u64bit in, byte out[8]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast<u64bit*>(out) = BOTAN_ENDIAN_B2N(in); +#else + out[0] = get_byte(0, in); + out[1] = get_byte(1, in); + out[2] = get_byte(2, in); + out[3] = get_byte(3, in); + out[4] = get_byte(4, in); + out[5] = get_byte(5, in); + out[6] = get_byte(6, in); + out[7] = get_byte(7, in); +#endif + } + +/** +* Store a little-endian u64bit +* @param in the input u64bit +* @param out the byte array to write to +*/ +inline void store_le(u64bit in, byte out[8]) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast<u64bit*>(out) = BOTAN_ENDIAN_L2N(in); +#else + out[0] = get_byte(7, in); + out[1] = get_byte(6, in); + out[2] = get_byte(5, in); + out[3] = get_byte(4, in); + out[4] = get_byte(3, in); + out[5] = get_byte(2, in); + out[6] = get_byte(1, in); + out[7] = get_byte(0, in); +#endif + } + +/** +* Store two little-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +*/ +template<typename T> +inline void store_le(byte out[], T x0, T x1) + { + store_le(x0, out + (0 * sizeof(T))); + store_le(x1, out + (1 * sizeof(T))); + } + +/** +* Store two big-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +*/ +template<typename T> +inline void store_be(byte out[], T x0, T x1) + { + store_be(x0, out + (0 * sizeof(T))); + store_be(x1, out + (1 * sizeof(T))); + } + +/** +* Store four little-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +*/ +template<typename T> +inline void store_le(byte out[], T x0, T x1, T x2, T x3) + { + store_le(x0, out + (0 * sizeof(T))); + store_le(x1, out + (1 * sizeof(T))); + store_le(x2, out + (2 * sizeof(T))); + store_le(x3, out + (3 * sizeof(T))); + } + +/** +* Store four big-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +*/ +template<typename T> +inline void store_be(byte out[], T x0, T x1, T x2, T x3) + { + store_be(x0, out + (0 * sizeof(T))); + store_be(x1, out + (1 * sizeof(T))); + store_be(x2, out + (2 * sizeof(T))); + store_be(x3, out + (3 * sizeof(T))); + } + +/** +* Store eight little-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +* @param x4 the fifth word +* @param x5 the sixth word +* @param x6 the seventh word +* @param x7 the eighth word +*/ +template<typename T> +inline void store_le(byte out[], T x0, T x1, T x2, T x3, + T x4, T x5, T x6, T x7) + { + store_le(x0, out + (0 * sizeof(T))); + store_le(x1, out + (1 * sizeof(T))); + store_le(x2, out + (2 * sizeof(T))); + store_le(x3, out + (3 * sizeof(T))); + store_le(x4, out + (4 * sizeof(T))); + store_le(x5, out + (5 * sizeof(T))); + store_le(x6, out + (6 * sizeof(T))); + store_le(x7, out + (7 * sizeof(T))); + } + +/** +* Store eight big-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +* @param x4 the fifth word +* @param x5 the sixth word +* @param x6 the seventh word +* @param x7 the eighth word +*/ +template<typename T> +inline void store_be(byte out[], T x0, T x1, T x2, T x3, + T x4, T x5, T x6, T x7) + { + store_be(x0, out + (0 * sizeof(T))); + store_be(x1, out + (1 * sizeof(T))); + store_be(x2, out + (2 * sizeof(T))); + store_be(x3, out + (3 * sizeof(T))); + store_be(x4, out + (4 * sizeof(T))); + store_be(x5, out + (5 * sizeof(T))); + store_be(x6, out + (6 * sizeof(T))); + store_be(x7, out + (7 * sizeof(T))); + } + +} + +#endif diff --git a/src/lib/utils/mem_ops.h b/src/lib/utils/mem_ops.h new file mode 100644 index 000000000..be617ff19 --- /dev/null +++ b/src/lib/utils/mem_ops.h @@ -0,0 +1,75 @@ +/* +* Memory Operations +* (C) 1999-2009,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MEMORY_OPS_H__ +#define BOTAN_MEMORY_OPS_H__ + +#include <botan/types.h> +#include <cstring> + +namespace Botan { + +/** +* Zeroize memory +* @param ptr a pointer to memory to zero out +* @param n the number of bytes pointed to by ptr +*/ +BOTAN_DLL void zero_mem(void* ptr, size_t n); + +/** +* Zeroize memory +* @param ptr a pointer to an array +* @param n the number of Ts pointed to by ptr +*/ +template<typename T> inline void clear_mem(T* ptr, size_t n) + { + zero_mem(ptr, sizeof(T)*n); + } + +/** +* Copy memory +* @param out the destination array +* @param in the source array +* @param n the number of elements of in/out +*/ +template<typename T> inline void copy_mem(T* out, const T* in, size_t n) + { + std::memmove(out, in, sizeof(T)*n); + } + +/** +* Set memory to a fixed value +* @param ptr a pointer to an array +* @param n the number of Ts pointed to by ptr +* @param val the value to set each byte to +*/ +template<typename T> +inline void set_mem(T* ptr, size_t n, byte val) + { + std::memset(ptr, val, sizeof(T)*n); + } + +/** +* Memory comparison, input insensitive +* @param p1 a pointer to an array +* @param p2 a pointer to another array +* @param n the number of Ts in p1 and p2 +* @return true iff p1[i] == p2[i] forall i in [0...n) +*/ +template<typename T> inline bool same_mem(const T* p1, const T* p2, size_t n) + { + volatile T difference = 0; + + for(size_t i = 0; i != n; ++i) + difference |= (p1[i] ^ p2[i]); + + return difference == 0; + } + +} + +#endif diff --git a/src/lib/utils/mul128.h b/src/lib/utils/mul128.h new file mode 100644 index 000000000..6725021ba --- /dev/null +++ b/src/lib/utils/mul128.h @@ -0,0 +1,121 @@ +/* +* 64x64->128 bit multiply operation +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_UTIL_MUL128_H__ +#define BOTAN_UTIL_MUL128_H__ + +#include <botan/types.h> + +namespace Botan { + +#if defined(__SIZEOF_INT128__) + #define BOTAN_TARGET_HAS_NATIVE_UINT128 + typedef unsigned __int128 uint128_t; + +#elif (BOTAN_GCC_VERSION > 440) && defined(BOTAN_TARGET_CPU_HAS_NATIVE_64BIT) + #define BOTAN_TARGET_HAS_NATIVE_UINT128 + typedef unsigned int uint128_t __attribute__((mode(TI))); +#endif + +} + +#if defined(BOTAN_TARGET_HAS_NATIVE_UINT128) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) \ + do { \ + const uint128_t r = static_cast<uint128_t>(a) * b; \ + *hi = (r >> 64) & 0xFFFFFFFFFFFFFFFF; \ + *lo = (r ) & 0xFFFFFFFFFFFFFFFF; \ + } while(0) + +#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC) && defined(BOTAN_TARGET_CPU_HAS_NATIVE_64BIT) + +#include <intrin.h> +#pragma intrinsic(_umul128) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) \ + do { *lo = _umul128(a, b, hi); } while(0) + +#elif defined(BOTAN_USE_GCC_INLINE_ASM) + +#if defined(BOTAN_TARGET_ARCH_IS_X86_64) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("mulq %3" : "=d" (*hi), "=a" (*lo) : "a" (a), "rm" (b) : "cc"); \ + } while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_ALPHA) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("umulh %1,%2,%0" : "=r" (*hi) : "r" (a), "r" (b)); \ + *lo = a * b; \ +} while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_IA64) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("xmpy.hu %0=%1,%2" : "=f" (*hi) : "f" (a), "f" (b)); \ + *lo = a * b; \ +} while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_PPC64) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("mulhdu %0,%1,%2" : "=r" (*hi) : "r" (a), "r" (b) : "cc"); \ + *lo = a * b; \ +} while(0) + +#endif + +#endif + +namespace Botan { + +/** +* Perform a 64x64->128 bit multiplication +*/ +inline void mul64x64_128(u64bit a, u64bit b, u64bit* lo, u64bit* hi) + { +#if defined(BOTAN_FAST_64X64_MUL) + BOTAN_FAST_64X64_MUL(a, b, lo, hi); +#else + + /* + * Do a 64x64->128 multiply using four 32x32->64 multiplies plus + * some adds and shifts. Last resort for CPUs like UltraSPARC (with + * 64-bit registers/ALU, but no 64x64->128 multiply) or 32-bit CPUs. + */ + const size_t HWORD_BITS = 32; + const u32bit HWORD_MASK = 0xFFFFFFFF; + + const u32bit a_hi = (a >> HWORD_BITS); + const u32bit a_lo = (a & HWORD_MASK); + const u32bit b_hi = (b >> HWORD_BITS); + const u32bit b_lo = (b & HWORD_MASK); + + u64bit x0 = static_cast<u64bit>(a_hi) * b_hi; + u64bit x1 = static_cast<u64bit>(a_lo) * b_hi; + u64bit x2 = static_cast<u64bit>(a_hi) * b_lo; + u64bit x3 = static_cast<u64bit>(a_lo) * b_lo; + + // this cannot overflow as (2^32-1)^2 + 2^32-1 < 2^64-1 + x2 += x3 >> HWORD_BITS; + + // this one can overflow + x2 += x1; + + // propagate the carry if any + x0 += static_cast<u64bit>(static_cast<bool>(x2 < x1)) << HWORD_BITS; + + *hi = x0 + (x2 >> HWORD_BITS); + *lo = ((x2 & HWORD_MASK) << HWORD_BITS) + (x3 & HWORD_MASK); +#endif + } + +} + +#endif diff --git a/src/lib/utils/parsing.cpp b/src/lib/utils/parsing.cpp new file mode 100644 index 000000000..cf47e24f8 --- /dev/null +++ b/src/lib/utils/parsing.cpp @@ -0,0 +1,302 @@ +/* +* Various string utils and parsing functions +* (C) 1999-2007,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/parsing.h> +#include <botan/exceptn.h> +#include <botan/charset.h> +#include <botan/get_byte.h> +#include <set> + +namespace Botan { + +u32bit to_u32bit(const std::string& str) + { + return std::stoul(str, nullptr); + } + +/* +* Convert a string into a time duration +*/ +u32bit timespec_to_u32bit(const std::string& timespec) + { + if(timespec == "") + return 0; + + const char suffix = timespec[timespec.size()-1]; + std::string value = timespec.substr(0, timespec.size()-1); + + u32bit scale = 1; + + if(Charset::is_digit(suffix)) + value += suffix; + else if(suffix == 's') + scale = 1; + else if(suffix == 'm') + scale = 60; + else if(suffix == 'h') + scale = 60 * 60; + else if(suffix == 'd') + scale = 24 * 60 * 60; + else if(suffix == 'y') + scale = 365 * 24 * 60 * 60; + else + throw Decoding_Error("timespec_to_u32bit: Bad input " + timespec); + + return scale * to_u32bit(value); + } + +/* +* Parse a SCAN-style algorithm name +*/ +std::vector<std::string> parse_algorithm_name(const std::string& namex) + { + if(namex.find('(') == std::string::npos && + namex.find(')') == std::string::npos) + return std::vector<std::string>(1, namex); + + std::string name = namex, substring; + std::vector<std::string> elems; + size_t level = 0; + + elems.push_back(name.substr(0, name.find('('))); + name = name.substr(name.find('(')); + + for(auto i = name.begin(); i != name.end(); ++i) + { + char c = *i; + + if(c == '(') + ++level; + if(c == ')') + { + if(level == 1 && i == name.end() - 1) + { + if(elems.size() == 1) + elems.push_back(substring.substr(1)); + else + elems.push_back(substring); + return elems; + } + + if(level == 0 || (level == 1 && i != name.end() - 1)) + throw Invalid_Algorithm_Name(namex); + --level; + } + + if(c == ',' && level == 1) + { + if(elems.size() == 1) + elems.push_back(substring.substr(1)); + else + elems.push_back(substring); + substring.clear(); + } + else + substring += c; + } + + if(substring != "") + throw Invalid_Algorithm_Name(namex); + + return elems; + } + +/* +* Split the string on slashes +*/ +std::vector<std::string> split_on(const std::string& str, char delim) + { + std::vector<std::string> elems; + if(str == "") return elems; + + std::string substr; + for(auto i = str.begin(); i != str.end(); ++i) + { + if(*i == delim) + { + if(substr != "") + elems.push_back(substr); + substr.clear(); + } + else + substr += *i; + } + + if(substr == "") + throw Invalid_Argument("Unable to split string: " + str); + elems.push_back(substr); + + return elems; + } + +/* +* Join a string +*/ +std::string string_join(const std::vector<std::string>& strs, char delim) + { + std::string out = ""; + + for(size_t i = 0; i != strs.size(); ++i) + { + if(i != 0) + out += delim; + out += strs[i]; + } + + return out; + } + +/* +* Parse an ASN.1 OID string +*/ +std::vector<u32bit> parse_asn1_oid(const std::string& oid) + { + std::string substring; + std::vector<u32bit> oid_elems; + + for(auto i = oid.begin(); i != oid.end(); ++i) + { + char c = *i; + + if(c == '.') + { + if(substring == "") + throw Invalid_OID(oid); + oid_elems.push_back(to_u32bit(substring)); + substring.clear(); + } + else + substring += c; + } + + if(substring == "") + throw Invalid_OID(oid); + oid_elems.push_back(to_u32bit(substring)); + + if(oid_elems.size() < 2) + throw Invalid_OID(oid); + + return oid_elems; + } + +/* +* X.500 String Comparison +*/ +bool x500_name_cmp(const std::string& name1, const std::string& name2) + { + auto p1 = name1.begin(); + auto p2 = name2.begin(); + + while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; + while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; + + while(p1 != name1.end() && p2 != name2.end()) + { + if(Charset::is_space(*p1)) + { + if(!Charset::is_space(*p2)) + return false; + + while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; + while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; + + if(p1 == name1.end() && p2 == name2.end()) + return true; + } + + if(!Charset::caseless_cmp(*p1, *p2)) + return false; + ++p1; + ++p2; + } + + while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; + while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; + + if((p1 != name1.end()) || (p2 != name2.end())) + return false; + return true; + } + +/* +* Convert a decimal-dotted string to binary IP +*/ +u32bit string_to_ipv4(const std::string& str) + { + std::vector<std::string> parts = split_on(str, '.'); + + if(parts.size() != 4) + throw Decoding_Error("Invalid IP string " + str); + + u32bit ip = 0; + + for(auto part = parts.begin(); part != parts.end(); ++part) + { + u32bit octet = to_u32bit(*part); + + if(octet > 255) + throw Decoding_Error("Invalid IP string " + str); + + ip = (ip << 8) | (octet & 0xFF); + } + + return ip; + } + +/* +* Convert an IP address to decimal-dotted string +*/ +std::string ipv4_to_string(u32bit ip) + { + std::string str; + + for(size_t i = 0; i != sizeof(ip); ++i) + { + if(i) + str += "."; + str += std::to_string(get_byte(i, ip)); + } + + return str; + } + +std::string erase_chars(const std::string& str, const std::set<char>& chars) + { + std::string out; + + for(auto c: str) + if(chars.count(c) == 0) + out += c; + + return out; + } + +std::string replace_chars(const std::string& str, + const std::set<char>& chars, + char to_char) + { + std::string out = str; + + for(size_t i = 0; i != out.size(); ++i) + if(chars.count(out[i])) + out[i] = to_char; + + return out; + } + +std::string replace_char(const std::string& str, char from_char, char to_char) + { + std::string out = str; + + for(size_t i = 0; i != out.size(); ++i) + if(out[i] == from_char) + out[i] = to_char; + + return out; + } + +} diff --git a/src/lib/utils/parsing.h b/src/lib/utils/parsing.h new file mode 100644 index 000000000..b37e3cb62 --- /dev/null +++ b/src/lib/utils/parsing.h @@ -0,0 +1,133 @@ +/* +* Various string utils and parsing functions +* (C) 1999-2007,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PARSER_H__ +#define BOTAN_PARSER_H__ + +#include <botan/types.h> +#include <string> +#include <vector> +#include <set> + +#include <istream> +#include <functional> +#include <map> + +namespace Botan { + +/** +* Parse a SCAN-style algorithm name +* @param scan_name the name +* @return the name components +*/ +BOTAN_DLL std::vector<std::string> +parse_algorithm_name(const std::string& scan_name); + +/** +* Split a string +* @param str the input string +* @param delim the delimitor +* @return string split by delim +*/ +BOTAN_DLL std::vector<std::string> split_on( + const std::string& str, char delim); + +/** +* Erase characters from a string +*/ +BOTAN_DLL std::string erase_chars(const std::string& str, const std::set<char>& chars); + +/** +* Replace a character in a string +* @param str the input string +* @param from_char the character to replace +* @param to_char the character to replace it with +* @return str with all instances of from_char replaced by to_char +*/ +BOTAN_DLL std::string replace_char(const std::string& str, + char from_char, + char to_char); + +/** +* Replace a character in a string +* @param str the input string +* @param from_chars the characters to replace +* @param to_char the character to replace it with +* @return str with all instances of from_chars replaced by to_char +*/ +BOTAN_DLL std::string replace_chars(const std::string& str, + const std::set<char>& from_chars, + char to_char); + +/** +* Join a string +* @param strs strings to join +* @param delim the delimitor +* @return string joined by delim +*/ +BOTAN_DLL std::string string_join(const std::vector<std::string>& strs, + char delim); + +/** +* Parse an ASN.1 OID +* @param oid the OID in string form +* @return OID components +*/ +BOTAN_DLL std::vector<u32bit> parse_asn1_oid(const std::string& oid); + +/** +* Compare two names using the X.509 comparison algorithm +* @param name1 the first name +* @param name2 the second name +* @return true if name1 is the same as name2 by the X.509 comparison rules +*/ +BOTAN_DLL bool x500_name_cmp(const std::string& name1, + const std::string& name2); + +/** +* Convert a string to a number +* @param str the string to convert +* @return number value of the string +*/ +BOTAN_DLL u32bit to_u32bit(const std::string& str); + +/** +* Convert a time specification to a number +* @param timespec the time specification +* @return number of seconds represented by timespec +*/ +BOTAN_DLL u32bit timespec_to_u32bit(const std::string& timespec); + +/** +* Convert a string representation of an IPv4 address to a number +* @param ip_str the string representation +* @return integer IPv4 address +*/ +BOTAN_DLL u32bit string_to_ipv4(const std::string& ip_str); + +/** +* Convert an IPv4 address to a string +* @param ip_addr the IPv4 address to convert +* @return string representation of the IPv4 address +*/ +BOTAN_DLL std::string ipv4_to_string(u32bit ip_addr); + +void BOTAN_DLL lex_cfg(std::istream& is, + std::function<void (std::string)> cb); + +void BOTAN_DLL lex_cfg_w_headers(std::istream& is, + std::function<void (std::string)> cb, + std::function<void (std::string)> header_cb); + +std::map<std::string, std::map<std::string, std::string>> +BOTAN_DLL +parse_cfg(std::istream& is); + + +} + +#endif diff --git a/src/lib/utils/prefetch.h b/src/lib/utils/prefetch.h new file mode 100644 index 000000000..66024e5ce --- /dev/null +++ b/src/lib/utils/prefetch.h @@ -0,0 +1,39 @@ +/* +* Prefetching Operations +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PREFETCH_H__ +#define BOTAN_PREFETCH_H__ + +#include <botan/cpuid.h> + +namespace Botan { + +template<typename T> +inline void prefetch_readonly(const T* addr, size_t length) + { +#if defined(__GNUG__) + const size_t Ts_per_cache_line = CPUID::cache_line_size() / sizeof(T); + + for(size_t i = 0; i <= length; i += Ts_per_cache_line) + __builtin_prefetch(addr + i, 0); +#endif + } + +template<typename T> +inline void prefetch_readwrite(const T* addr, size_t length) + { +#if defined(__GNUG__) + const size_t Ts_per_cache_line = CPUID::cache_line_size() / sizeof(T); + + for(size_t i = 0; i <= length; i += Ts_per_cache_line) + __builtin_prefetch(addr + i, 1); +#endif + } + +} + +#endif diff --git a/src/lib/utils/read_cfg.cpp b/src/lib/utils/read_cfg.cpp new file mode 100644 index 000000000..ad57a8b3e --- /dev/null +++ b/src/lib/utils/read_cfg.cpp @@ -0,0 +1,115 @@ +/* +* Simple config/test file reader +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/parsing.h> +#include <boost/algorithm/string.hpp> + +namespace Botan { + +void lex_cfg(std::istream& is, + std::function<void (std::string)> cb) + { + while(is.good()) + { + std::string s; + + std::getline(is, s); + + while(is.good() && s.back() == '\\') + { + boost::trim_if(s, boost::is_any_of("\\\n")); + std::string x; + std::getline(is, x); + boost::trim_left(x); + s += x; + } + + auto comment = s.find('#'); + if(comment) + s = s.substr(0, comment); + + if(s.empty()) + continue; + + std::vector<std::string> parts; + boost::split(parts, s, boost::is_any_of(" \t\n"), boost::token_compress_on); + + for(auto p : parts) + { + if(p.empty()) + continue; + + auto eq = p.find("="); + + if(eq == std::string::npos || p.size() < 2) + { + cb(p); + } + else if(eq == 0) + { + cb("="); + cb(p.substr(1, std::string::npos)); + } + else if(eq == p.size() - 1) + { + cb(p.substr(0, p.size() - 1)); + cb("="); + } + else if(eq != std::string::npos) + { + cb(p.substr(0, eq)); + cb("="); + cb(p.substr(eq + 1, std::string::npos)); + } + } + } + } + +void lex_cfg_w_headers(std::istream& is, + std::function<void (std::string)> cb, + std::function<void (std::string)> hdr_cb) + { + auto intercept = [cb,hdr_cb](const std::string& s) + { + if(s[0] == '[' && s[s.length()-1] == ']') + hdr_cb(s.substr(1, s.length()-2)); + else + cb(s); + }; + + lex_cfg(is, intercept); + } + +std::map<std::string, std::map<std::string, std::string>> + parse_cfg(std::istream& is) + { + std::string header = "default"; + std::map<std::string, std::map<std::string, std::string>> vals; + std::string key; + + auto header_cb = [&header](const std::string i) { header = i; }; + auto cb = [&header,&key,&vals](const std::string s) + { + if(s == "=") + { + BOTAN_ASSERT(!key.empty(), "Valid assignment in config"); + } + else if(key.empty()) + key = s; + else + { + vals[header][key] = s; + key = ""; + } + }; + + lex_cfg_w_headers(is, cb, header_cb); + + return vals; + } + +} diff --git a/src/lib/utils/rotate.h b/src/lib/utils/rotate.h new file mode 100644 index 000000000..2593010b4 --- /dev/null +++ b/src/lib/utils/rotate.h @@ -0,0 +1,43 @@ +/* +* Word Rotation Operations +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_WORD_ROTATE_H__ +#define BOTAN_WORD_ROTATE_H__ + +#include <botan/types.h> + +namespace Botan { + +/** +* Bit rotation left +* @param input the input word +* @param rot the number of bits to rotate +* @return input rotated left by rot bits +*/ +template<typename T> inline T rotate_left(T input, size_t rot) + { + if(rot == 0) + return input; + return static_cast<T>((input << rot) | (input >> (8*sizeof(T)-rot)));; + } + +/** +* Bit rotation right +* @param input the input word +* @param rot the number of bits to rotate +* @return input rotated right by rot bits +*/ +template<typename T> inline T rotate_right(T input, size_t rot) + { + if(rot == 0) + return input; + return static_cast<T>((input >> rot) | (input << (8*sizeof(T)-rot))); + } + +} + +#endif diff --git a/src/lib/utils/rounding.h b/src/lib/utils/rounding.h new file mode 100644 index 000000000..4ddd7a432 --- /dev/null +++ b/src/lib/utils/rounding.h @@ -0,0 +1,61 @@ +/* +* Integer Rounding Functions +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ROUNDING_H__ +#define BOTAN_ROUNDING_H__ + +#include <botan/types.h> + +namespace Botan { + +/** +* Round up +* @param n an integer +* @param align_to the alignment boundary +* @return n rounded up to a multiple of align_to +*/ +template<typename T> +inline T round_up(T n, T align_to) + { + if(align_to == 0) + return n; + + if(n % align_to || n == 0) + n += align_to - (n % align_to); + return n; + } + +/** +* Round down +* @param n an integer +* @param align_to the alignment boundary +* @return n rounded down to a multiple of align_to +*/ +template<typename T> +inline T round_down(T n, T align_to) + { + if(align_to == 0) + return n; + + return (n - (n % align_to)); + } + +/** +* Clamp +*/ +inline size_t clamp(size_t n, size_t lower_bound, size_t upper_bound) + { + if(n < lower_bound) + return lower_bound; + if(n > upper_bound) + return upper_bound; + return n; + } + +} + +#endif diff --git a/src/lib/utils/semaphore.cpp b/src/lib/utils/semaphore.cpp new file mode 100644 index 000000000..f4f5b2b53 --- /dev/null +++ b/src/lib/utils/semaphore.cpp @@ -0,0 +1,39 @@ +/* +* Semaphore +* by Pierre Gaston (http://p9as.blogspot.com/2012/06/c11-semaphores.html) +* modified by Joel Low for Botan +* +*/ + +#include <botan/internal/semaphore.h> + +namespace Botan { + +void Semaphore::release(size_t n) + { + for(size_t i = 0; i != n; ++i) + { + std::lock_guard<std::mutex> lock(m_mutex); + + ++m_value; + + if(m_value <= 0) + { + ++m_wakeups; + m_cond.notify_one(); + } + } + } + +void Semaphore::acquire() + { + std::unique_lock<std::mutex> lock(m_mutex); + --m_value; + if(m_value < 0) + { + m_cond.wait(lock, [this] { return m_wakeups > 0; }); + --m_wakeups; + } + } + +} diff --git a/src/lib/utils/semaphore.h b/src/lib/utils/semaphore.h new file mode 100644 index 000000000..c3ce73680 --- /dev/null +++ b/src/lib/utils/semaphore.h @@ -0,0 +1,34 @@ +/* +* Semaphore +* by Pierre Gaston (http://p9as.blogspot.com/2012/06/c11-semaphores.html) +* modified by Joel Low for Botan +* +*/ + +#ifndef BOTAN_SEMAPHORE_H__ +#define BOTAN_SEMAPHORE_H__ + +#include <mutex> +#include <condition_variable> + +namespace Botan { + +class Semaphore + { + public: + Semaphore(int value = 0) : m_value(value), m_wakeups(0) {} + + void acquire(); + + void release(size_t n = 1); + + private: + int m_value; + int m_wakeups; + std::mutex m_mutex; + std::condition_variable m_cond; + }; + +} + +#endif diff --git a/src/lib/utils/sqlite3/info.txt b/src/lib/utils/sqlite3/info.txt new file mode 100644 index 000000000..97d59d697 --- /dev/null +++ b/src/lib/utils/sqlite3/info.txt @@ -0,0 +1,14 @@ + +load_on request + +<libs> +all -> sqlite3 +</libs> + +<header:internal> +sqlite3.h +</header:internal> + +<source> +sqlite3.cpp +</source> diff --git a/src/lib/utils/sqlite3/sqlite3.cpp b/src/lib/utils/sqlite3/sqlite3.cpp new file mode 100644 index 000000000..7f6626759 --- /dev/null +++ b/src/lib/utils/sqlite3/sqlite3.cpp @@ -0,0 +1,137 @@ +/* +* SQLite wrapper +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include <botan/internal/sqlite3.h> +#include <stdexcept> +#include <sqlite3.h> + +namespace Botan { + +sqlite3_database::sqlite3_database(const std::string& db_filename) + { + int rc = ::sqlite3_open(db_filename.c_str(), &m_db); + + if(rc) + { + const std::string err_msg = ::sqlite3_errmsg(m_db); + ::sqlite3_close(m_db); + m_db = nullptr; + throw std::runtime_error("sqlite3_open failed - " + err_msg); + } + } + +sqlite3_database::~sqlite3_database() + { + if(m_db) + ::sqlite3_close(m_db); + m_db = nullptr; + } + +size_t sqlite3_database::row_count(const std::string& table_name) + { + sqlite3_statement stmt(this, "select count(*) from " + table_name); + + if(stmt.step()) + return stmt.get_size_t(0); + else + throw std::runtime_error("Querying size of table " + table_name + " failed"); + } + +void sqlite3_database::create_table(const std::string& table_schema) + { + char* errmsg = nullptr; + int rc = ::sqlite3_exec(m_db, table_schema.c_str(), nullptr, nullptr, &errmsg); + + if(rc != SQLITE_OK) + { + const std::string err_msg = errmsg; + ::sqlite3_free(errmsg); + ::sqlite3_close(m_db); + m_db = nullptr; + throw std::runtime_error("sqlite3_exec for table failed - " + err_msg); + } + } + + +sqlite3_statement::sqlite3_statement(sqlite3_database* db, const std::string& base_sql) + { + int rc = ::sqlite3_prepare_v2(db->m_db, base_sql.c_str(), -1, &m_stmt, nullptr); + + if(rc != SQLITE_OK) + throw std::runtime_error("sqlite3_prepare failed " + base_sql + + ", code " + std::to_string(rc)); + } + +void sqlite3_statement::bind(int column, const std::string& val) + { + int rc = ::sqlite3_bind_text(m_stmt, column, val.c_str(), -1, SQLITE_TRANSIENT); + if(rc != SQLITE_OK) + throw std::runtime_error("sqlite3_bind_text failed, code " + std::to_string(rc)); + } + +void sqlite3_statement::bind(int column, int val) + { + int rc = ::sqlite3_bind_int(m_stmt, column, val); + if(rc != SQLITE_OK) + throw std::runtime_error("sqlite3_bind_int failed, code " + std::to_string(rc)); + } + +void sqlite3_statement::bind(int column, std::chrono::system_clock::time_point time) + { + const int timeval = std::chrono::duration_cast<std::chrono::seconds>(time.time_since_epoch()).count(); + bind(column, timeval); + } + +void sqlite3_statement::bind(int column, const std::vector<byte>& val) + { + int rc = ::sqlite3_bind_blob(m_stmt, column, &val[0], val.size(), SQLITE_TRANSIENT); + if(rc != SQLITE_OK) + throw std::runtime_error("sqlite3_bind_text failed, code " + std::to_string(rc)); + } + +std::pair<const byte*, size_t> sqlite3_statement::get_blob(int column) + { + BOTAN_ASSERT(::sqlite3_column_type(m_stmt, 0) == SQLITE_BLOB, + "Return value is a blob"); + + const void* session_blob = ::sqlite3_column_blob(m_stmt, column); + const int session_blob_size = ::sqlite3_column_bytes(m_stmt, column); + + BOTAN_ASSERT(session_blob_size >= 0, "Blob size is non-negative"); + + return std::make_pair(static_cast<const byte*>(session_blob), + static_cast<size_t>(session_blob_size)); + } + +size_t sqlite3_statement::get_size_t(int column) + { + BOTAN_ASSERT(::sqlite3_column_type(m_stmt, column) == SQLITE_INTEGER, + "Return count is an integer"); + + const int sessions_int = ::sqlite3_column_int(m_stmt, column); + + BOTAN_ASSERT(sessions_int >= 0, "Expected size_t is non-negative"); + + return static_cast<size_t>(sessions_int); + } + +void sqlite3_statement::spin() + { + while(step()) {} + } + +bool sqlite3_statement::step() + { + return (::sqlite3_step(m_stmt) == SQLITE_ROW); + } + +sqlite3_statement::~sqlite3_statement() + { + ::sqlite3_finalize(m_stmt); + } + +} diff --git a/src/lib/utils/sqlite3/sqlite3.h b/src/lib/utils/sqlite3/sqlite3.h new file mode 100644 index 000000000..aef04ab4d --- /dev/null +++ b/src/lib/utils/sqlite3/sqlite3.h @@ -0,0 +1,68 @@ +/* +* SQLite wrapper +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_UTILS_SQLITE_WRAPPER_H__ +#define BOTAN_UTILS_SQLITE_WRAPPER_H__ + +#include <botan/types.h> +#include <string> +#include <chrono> +#include <vector> + +class sqlite3; +class sqlite3_stmt; + +namespace Botan { + +class sqlite3_database + { + public: + sqlite3_database(const std::string& file); + + ~sqlite3_database(); + + size_t row_count(const std::string& table_name); + + void create_table(const std::string& table_schema); + private: + friend class sqlite3_statement; + + sqlite3* m_db; + }; + +class sqlite3_statement + { + public: + sqlite3_statement(sqlite3_database* db, + const std::string& base_sql); + + void bind(int column, const std::string& val); + + void bind(int column, int val); + + void bind(int column, std::chrono::system_clock::time_point time); + + void bind(int column, const std::vector<byte>& val); + + std::pair<const byte*, size_t> get_blob(int column); + + size_t get_size_t(int column); + + void spin(); + + bool step(); + + sqlite3_stmt* stmt() { return m_stmt; } + + ~sqlite3_statement(); + private: + sqlite3_stmt* m_stmt; + }; + +} + +#endif diff --git a/src/lib/utils/stl_util.h b/src/lib/utils/stl_util.h new file mode 100644 index 000000000..0710d61a5 --- /dev/null +++ b/src/lib/utils/stl_util.h @@ -0,0 +1,94 @@ +/* +* STL Utility Functions +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_STL_UTIL_H__ +#define BOTAN_STL_UTIL_H__ + +#include <vector> +#include <string> +#include <map> + +namespace Botan { + +inline std::vector<byte> to_byte_vector(const std::string& s) + { + return std::vector<byte>(reinterpret_cast<const byte*>(&s[0]), + reinterpret_cast<const byte*>(&s[s.size()])); + } + +/* +* Searching through a std::map +* @param mapping the map to search +* @param key is what to look for +* @param null_result is the value to return if key is not in mapping +* @return mapping[key] or null_result +*/ +template<typename K, typename V> +inline V search_map(const std::map<K, V>& mapping, + const K& key, + const V& null_result = V()) + { + auto i = mapping.find(key); + if(i == mapping.end()) + return null_result; + return i->second; + } + +template<typename K, typename V, typename R> +inline R search_map(const std::map<K, V>& mapping, const K& key, + const R& null_result, const R& found_result) + { + auto i = mapping.find(key); + if(i == mapping.end()) + return null_result; + return found_result; + } + +/* +* Insert a key/value pair into a multimap +*/ +template<typename K, typename V> +void multimap_insert(std::multimap<K, V>& multimap, + const K& key, const V& value) + { +#if defined(BOTAN_BUILD_COMPILER_IS_SUN_STUDIO) + // Work around a strange bug in Sun Studio + multimap.insert(std::make_pair<const K, V>(key, value)); +#else + multimap.insert(std::make_pair(key, value)); +#endif + } + +/** +* Existence check for values +*/ +template<typename T> +bool value_exists(const std::vector<T>& vec, + const T& val) + { + for(size_t i = 0; i != vec.size(); ++i) + if(vec[i] == val) + return true; + return false; + } + +template<typename T, typename Pred> +void map_remove_if(Pred pred, T& assoc) + { + auto i = assoc.begin(); + while(i != assoc.end()) + { + if(pred(i->first)) + assoc.erase(i++); + else + i++; + } + } + +} + +#endif diff --git a/src/lib/utils/types.h b/src/lib/utils/types.h new file mode 100644 index 000000000..f4a2eeacd --- /dev/null +++ b/src/lib/utils/types.h @@ -0,0 +1,48 @@ +/* +* Low Level Types +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_TYPES_H__ +#define BOTAN_TYPES_H__ + +#include <botan/build.h> +#include <botan/assert.h> +#include <cstddef> +#include <cstdint> + +/** +* The primary namespace for the botan library +*/ +namespace Botan { + +using std::uint8_t; +using std::uint16_t; +using std::uint32_t; +using std::uint64_t; +using std::size_t; + +typedef uint8_t byte; +typedef uint16_t u16bit; +typedef uint32_t u32bit; +typedef uint64_t u64bit; + +typedef std::int32_t s32bit; + +/** +* A default buffer size; typically a memory page +*/ +static const size_t DEFAULT_BUFFERSIZE = BOTAN_DEFAULT_BUFFER_SIZE; + +} + +namespace Botan_types { + +using Botan::byte; +using Botan::u32bit; + +} + +#endif diff --git a/src/lib/utils/version.cpp b/src/lib/utils/version.cpp new file mode 100644 index 000000000..32679cf63 --- /dev/null +++ b/src/lib/utils/version.cpp @@ -0,0 +1,55 @@ +/* +* Version Information +* (C) 1999-2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/version.h> +#include <botan/parsing.h> + +namespace Botan { + +/* + These are intentionally compiled rather than inlined, so an + application running against a shared library can test the true + version they are running against. +*/ + +/* +* Return the version as a string +*/ +std::string version_string() + { +#define QUOTE(name) #name +#define STR(macro) QUOTE(macro) + + /* + It is intentional that this string is a compile-time constant; + it makes it much easier to find in binaries. + */ + + return "Botan " STR(BOTAN_VERSION_MAJOR) "." + STR(BOTAN_VERSION_MINOR) "." + STR(BOTAN_VERSION_PATCH) " (" + BOTAN_VERSION_RELEASE_TYPE +#if (BOTAN_VERSION_DATESTAMP != 0) + ", dated " STR(BOTAN_VERSION_DATESTAMP) +#endif + ", revision " BOTAN_VERSION_VC_REVISION + ", distribution " BOTAN_DISTRIBUTION_INFO ")"; + +#undef STR +#undef QUOTE + } + +u32bit version_datestamp() { return BOTAN_VERSION_DATESTAMP; } + +/* +* Return parts of the version as integers +*/ +u32bit version_major() { return BOTAN_VERSION_MAJOR; } +u32bit version_minor() { return BOTAN_VERSION_MINOR; } +u32bit version_patch() { return BOTAN_VERSION_PATCH; } + +} diff --git a/src/lib/utils/version.h b/src/lib/utils/version.h new file mode 100644 index 000000000..219c261a5 --- /dev/null +++ b/src/lib/utils/version.h @@ -0,0 +1,72 @@ +/* +* Version Information +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_VERSION_H__ +#define BOTAN_VERSION_H__ + +#include <botan/types.h> +#include <string> + +namespace Botan { + +/* +* Get information describing the version +*/ + +/** +* Get a human-readable string identifying the version of Botan. +* No particular format should be assumed. +* @return version string +*/ +BOTAN_DLL std::string version_string(); + +/** +* Return the date this version of botan was released, in an integer of +* the form YYYYMMDD. For instance a version released on May 21, 2013 +* would return the integer 20130521. If the currently running version +* is not an official release, this function will return 0 instead. +* +* @return release date, or zero if unreleased +*/ +BOTAN_DLL u32bit version_datestamp(); + +/** +* Get the major version number. +* @return major version number +*/ +BOTAN_DLL u32bit version_major(); + +/** +* Get the minor version number. +* @return minor version number +*/ +BOTAN_DLL u32bit version_minor(); + +/** +* Get the patch number. +* @return patch number +*/ +BOTAN_DLL u32bit version_patch(); + +/* +* Macros for compile-time version checks +*/ +#define BOTAN_VERSION_CODE_FOR(a,b,c) ((a << 16) | (b << 8) | (c)) + +/** +* Compare using BOTAN_VERSION_CODE_FOR, as in +* # if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,8,0) +* # error "Botan version too old" +* # endif +*/ +#define BOTAN_VERSION_CODE BOTAN_VERSION_CODE_FOR(BOTAN_VERSION_MAJOR, \ + BOTAN_VERSION_MINOR, \ + BOTAN_VERSION_PATCH) + +} + +#endif diff --git a/src/lib/utils/xor_buf.h b/src/lib/utils/xor_buf.h new file mode 100644 index 000000000..5773a619c --- /dev/null +++ b/src/lib/utils/xor_buf.h @@ -0,0 +1,113 @@ +/* +* XOR operations +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_XOR_BUF_H__ +#define BOTAN_XOR_BUF_H__ + +#include <botan/types.h> +#include <vector> + +namespace Botan { + +/** +* XOR arrays. Postcondition out[i] = in[i] ^ out[i] forall i = 0...length +* @param out the input/output buffer +* @param in the read-only input buffer +* @param length the length of the buffers +*/ +inline void xor_buf(byte out[], const byte in[], size_t length) + { + while(length >= 8) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast<u64bit*>(out) ^= *reinterpret_cast<const u64bit*>(in); +#else + out[0] ^= in[0]; out[1] ^= in[1]; + out[2] ^= in[2]; out[3] ^= in[3]; + out[4] ^= in[4]; out[5] ^= in[5]; + out[6] ^= in[6]; out[7] ^= in[7]; +#endif + + out += 8; in += 8; length -= 8; + } + + for(size_t i = 0; i != length; ++i) + out[i] ^= in[i]; + } + +/** +* XOR arrays. Postcondition out[i] = in[i] ^ in2[i] forall i = 0...length +* @param out the output buffer +* @param in the first input buffer +* @param in2 the second output buffer +* @param length the length of the three buffers +*/ +inline void xor_buf(byte out[], + const byte in[], + const byte in2[], + size_t length) + { + while(length >= 8) + { +#if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK + *reinterpret_cast<u64bit*>(out) = + *reinterpret_cast<const u64bit*>(in) ^ + *reinterpret_cast<const u64bit*>(in2); +#else + out[0] = in[0] ^ in2[0]; out[1] = in[1] ^ in2[1]; + out[2] = in[2] ^ in2[2]; out[3] = in[3] ^ in2[3]; + out[4] = in[4] ^ in2[4]; out[5] = in[5] ^ in2[5]; + out[6] = in[6] ^ in2[6]; out[7] = in[7] ^ in2[7]; +#endif + + in += 8; in2 += 8; out += 8; length -= 8; + } + + for(size_t i = 0; i != length; ++i) + out[i] = in[i] ^ in2[i]; + } + +template<typename Alloc, typename Alloc2> +void xor_buf(std::vector<byte, Alloc>& out, + const std::vector<byte, Alloc2>& in, + size_t n) + { + xor_buf(&out[0], &in[0], n); + } + +template<typename Alloc> +void xor_buf(std::vector<byte, Alloc>& out, + const byte* in, + size_t n) + { + xor_buf(&out[0], in, n); + } + +template<typename Alloc, typename Alloc2> +void xor_buf(std::vector<byte, Alloc>& out, + const byte* in, + const std::vector<byte, Alloc2>& in2, + size_t n) + { + xor_buf(&out[0], &in[0], &in2[0], n); + } + +template<typename T, typename Alloc, typename Alloc2> +std::vector<T, Alloc>& +operator^=(std::vector<T, Alloc>& out, + const std::vector<T, Alloc2>& in) + { + if(out.size() < in.size()) + out.resize(in.size()); + + xor_buf(&out[0], &in[0], in.size()); + return out; + } + +} + +#endif diff --git a/src/lib/utils/zero_mem.cpp b/src/lib/utils/zero_mem.cpp new file mode 100644 index 000000000..e812ced0c --- /dev/null +++ b/src/lib/utils/zero_mem.cpp @@ -0,0 +1,20 @@ +/* +* Zero Memory +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/mem_ops.h> + +namespace Botan { + +void zero_mem(void* ptr, size_t n) + { + volatile byte* p = reinterpret_cast<volatile byte*>(ptr); + + for(size_t i = 0; i != n; ++i) + p[i] = 0; + } + +} |