You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
654 lines
18 KiB
654 lines
18 KiB
////////////////////////////////////////////////////////////////////////////////// |
|
// Name: actUtility.h |
|
// Product: cv act library |
|
// Purpose: useful global functions |
|
// |
|
// Copyright: (c) 2000-2001 cv cryptovision GmbH |
|
// all rights reserved |
|
// Licence: The conditions for the use of this software are regulated |
|
// in the cv act library licence agreement. |
|
////////////////////////////////////////////////////////////////////////////////// |
|
|
|
#ifndef ACT_Utility_h |
|
#define ACT_Utility_h |
|
|
|
#include "actBlob.h" |
|
#include "actBasics.h" |
|
#include "actException.h" |
|
|
|
#include <string> |
|
#include <algorithm> |
|
#include <cctype> |
|
#include <cwctype> |
|
#include <stdio.h> |
|
#include <ctype.h> |
|
|
|
#if defined(__GNUC__) && (__GNUC__ < 4) |
|
namespace act { typedef std::basic_string<wchar_t> wstring; } |
|
#else |
|
namespace act { using std::wstring; } |
|
#endif |
|
|
|
namespace act |
|
{ |
|
class IParam; |
|
|
|
// |
|
// Const Values |
|
// |
|
|
|
extern const size_t sizeof_uuid; |
|
|
|
// |
|
// Prototypes |
|
// |
|
|
|
const char* get_string_param(paramid_t id, IParam* owner); |
|
|
|
// Converts an unsigned hexadecimal number (independent of prefix "0x") |
|
// into a Blob and backwards. |
|
// - for blob2hex: the user has to allocate hexnumber |
|
Blob& hex2blob(const char* hexnumber, Blob& b); |
|
inline Blob& hex2blob(const std::string& hexnumber, Blob& b) |
|
{ |
|
return hex2blob(hexnumber.c_str(), b); |
|
} |
|
inline Blob hex2blob(const char* hexnumber) |
|
{ |
|
Blob b; |
|
return move(hex2blob(hexnumber, b)); |
|
} |
|
|
|
void blob2hex(const Blob& b, char* hexnumber); |
|
std::string blob2hex(const Blob& b); |
|
|
|
// file i/o for act::Blob |
|
bool file2blob(const char* filename, Blob &blob); |
|
bool blob2file(const char* filename, const act::Blob &blob); |
|
|
|
// Create an ISO 9834-8 / RFC 4122 version 4 (pseudo random) UUID. |
|
// Output string format is "xxxxxxxx-xxxx-4xxx-vxxx-xxxxxxxxxxxx", where |
|
// x is random hex char 0 <= x <= f and v an element of { 8, 9, a, b}. |
|
void createPseudoRandomUUID(Blob& uuid, bool network_byte_order = true); |
|
std::string createPseudoRandomUUID(); |
|
std::string uuid2string(const Blob& uuid, bool is_network_byte_order = true); |
|
void swapTimeFields(Blob& uuid); |
|
|
|
std::string serno2string(const act::Blob& serno); |
|
std::string id2string(const act::Blob& id, bool is_network_byte_order = true); |
|
|
|
// CBCMAC with ISO padding |
|
void iCBCMAC(const char* cipher, const Blob& iv, const Blob& mac_key, |
|
const Blob& mac_data, Blob& mac); |
|
|
|
void SetDESKeyParity(Blob &key); |
|
bool CheckDESKeyParity(const Blob &key); |
|
|
|
void get_string_seq(const std::string& s, const std::string start, const std::string end, |
|
std::string& result, bool case_sens); |
|
|
|
bool wstr2utf8(const wchar_t* str, std::string& utf8); |
|
bool utf82wstr(const char* utf8, act::wstring& wstr); |
|
|
|
void ASN1ToSequenceOf(Blob& asn1_data); |
|
Blob GetASN1SequenceOf(const Blob& asn1_data); |
|
Blob GetASN1EncodedLength(size_t length); |
|
|
|
size_t SkipTagLength(byte tag, const byte* tlv_data, size_t tlv_data_len); |
|
size_t SkipTLVElement(byte tag, const byte* tlv_data, size_t tlv_data_len, bool skip_value = true); |
|
int FindTlvTemplate(Blob& contentb, const Blob& inb, int intag, int counts); |
|
|
|
// |
|
// Implementation |
|
// |
|
|
|
// |
|
// -------------------------------------------------------------------- |
|
template<typename ConverterT, typename RegistryT, typename TypeT> |
|
const Blob SafeGetName(TypeT* instance) |
|
{ |
|
Blob name; |
|
if(instance != 0) |
|
{ |
|
const char* cname = RegistryT::GetName(instance->GetCreatePointer()); |
|
if(cname != 0) ConverterT(cname).swap(name); |
|
} |
|
return move(name); |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
template<typename TypeT> |
|
struct is_whitespace : is_whitespace<typename TypeT::value_type> |
|
{ |
|
typedef typename TypeT::value_type argument_type; |
|
using is_whitespace<typename TypeT::value_type>::operator(); |
|
}; |
|
|
|
template<> |
|
struct is_whitespace<char> |
|
{ |
|
typedef char argument_type; |
|
bool operator()(unsigned char value) const { return std::isspace(value) != 0; } |
|
}; |
|
|
|
template<> |
|
struct is_whitespace<wchar_t> |
|
{ |
|
typedef wchar_t argument_type; |
|
bool operator()(wchar_t value) const { return std::iswspace(value) != 0; } |
|
}; |
|
|
|
// --------------------------------------------------------------------------- |
|
template<typename PredicateT, typename TypeT> |
|
inline TypeT& erase_right(const PredicateT& predicate, TypeT& value) |
|
{ |
|
value.erase(std::find_if(value.rbegin(), value.rend(), predicate).base(), value.end()); |
|
return value; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
template<typename TypeT> |
|
inline void fill(TypeT* begin, size_t length, byte value) |
|
{ |
|
ACT_ASSERT(begin != 0); |
|
std::fill(reinterpret_cast<act::byte*>(begin), |
|
reinterpret_cast<act::byte*>(begin) + length, value); |
|
} |
|
|
|
// |
|
// scoped_delete<PointerT> |
|
// --------------------------------------------------------------------------- |
|
template<typename PointerT> |
|
struct scoped_delete<PointerT, void, 1> |
|
{ |
|
PointerT _ptr; |
|
|
|
explicit scoped_delete(PointerT ptr) : _ptr(ptr) { } |
|
~scoped_delete() { delete _ptr; } |
|
|
|
PointerT operator->() const |
|
{ |
|
if(_ptr == 0) throw NullPointerException(); |
|
return _ptr; |
|
} |
|
}; |
|
|
|
// --------------------------------------------------------------------------- |
|
template<typename PointerT> |
|
scoped_delete<PointerT, void, 1> checked_delete(PointerT& ptr_ref) |
|
{ |
|
PointerT ptr = ptr_ref; ptr_ref = 0; |
|
return scoped_delete<PointerT, void, 1>(ptr); |
|
} |
|
|
|
// |
|
// scoped_delete<AutoPtrT> |
|
// --------------------------------------------------------------------------- |
|
template |
|
< |
|
template<class> class AutoPtrT, |
|
class TypeT |
|
> |
|
struct scoped_delete<AutoPtrT<TypeT>, void, 1> |
|
{ |
|
AutoPtrT<TypeT> _ptr; |
|
|
|
explicit scoped_delete(AutoPtrT<TypeT>& ptr) : _ptr(ptr) { } |
|
~scoped_delete() { AutoPtrT<TypeT>(_ptr); } |
|
|
|
TypeT* operator->() const |
|
{ |
|
TypeT* ptr = _ptr.get(); |
|
if(ptr == 0) throw NullPointerException(); |
|
return ptr; |
|
} |
|
}; |
|
|
|
// --------------------------------------------------------------------------- |
|
template |
|
< |
|
template<class> class AutoPtrT, |
|
class TypeT |
|
> |
|
scoped_delete<AutoPtrT<TypeT>, void, 1> checked_delete(AutoPtrT<TypeT>& ptr_ref) |
|
{ |
|
return scoped_delete<AutoPtrT<TypeT>, void, 1>(ptr_ref); |
|
} |
|
|
|
|
|
// |
|
// scoped_delete<ArrayT<TypeT*> > |
|
// --------------------------------------------------------------------------- |
|
template |
|
< |
|
template<class, class> class ArrayT, |
|
class TypeT, class AllocatorT, |
|
typename DestructF |
|
> |
|
struct scoped_delete<ArrayT<TypeT, AllocatorT>, DestructF, 3> |
|
{ |
|
typedef ArrayT<TypeT, AllocatorT> container_type; |
|
typedef DestructF destruct_func; |
|
|
|
explicit scoped_delete(container_type& _container, const destruct_func& _destruct) |
|
: destruct(_destruct) |
|
{ container.swap(_container); } |
|
|
|
~scoped_delete() |
|
{ release(container, destruct); } |
|
|
|
static void release(container_type& container, const destruct_func& destruct) |
|
{ |
|
if(container.empty() == true) return; |
|
|
|
container_type failed; |
|
typedef typename container_type::const_iterator const_iterator; |
|
for(const_iterator i(container.begin()), end(container.end()); i != end; ++i) |
|
try { destruct(*i); } |
|
catch(Exception&) { failed.push_back(*i); } |
|
|
|
container.swap(failed); |
|
} |
|
|
|
destruct_func destruct; |
|
container_type container; |
|
}; |
|
|
|
// |
|
// checked_delete(array_of_ptr_to_type, std::mem_fun(&type::destruct)); |
|
// --------------------------------------------------------------------------- |
|
template |
|
< |
|
template<class, class> class ArrayT, |
|
class TypeT, class AllocatorT, |
|
typename DestructF |
|
> |
|
scoped_delete<ArrayT<TypeT, AllocatorT>, DestructF, 3> |
|
checked_delete(ArrayT<TypeT, AllocatorT>& container, const DestructF& destruct) |
|
{ |
|
return scoped_delete<ArrayT<TypeT, AllocatorT>, DestructF, 3>(container, destruct); |
|
} |
|
|
|
// |
|
// scoped_delete<MapT<TypeT*> > |
|
// --------------------------------------------------------------------------- |
|
template |
|
< |
|
template<class, class, class, class> class MapT, |
|
class KeyT, class TypeT, class PredT, class AllocatorT, |
|
typename DestructF |
|
> |
|
struct scoped_delete<MapT<KeyT, TypeT, PredT, AllocatorT>, DestructF, 4> |
|
{ |
|
typedef MapT<KeyT, TypeT, PredT, AllocatorT> container_type; |
|
typedef DestructF destruct_func; |
|
|
|
explicit scoped_delete(container_type& _container, const destruct_func& _destruct) |
|
: destruct(_destruct) |
|
{ container.swap(_container); } |
|
|
|
~scoped_delete() |
|
{ release(container, destruct); } |
|
|
|
static void release(container_type& container, const destruct_func& destruct) |
|
{ |
|
if(container.empty() == true) return; |
|
|
|
container_type failed; |
|
typedef typename container_type::const_iterator const_iterator; |
|
for(const_iterator i(container.begin()), end(container.end()); i != end; ++i) |
|
try { destruct(i->second); } |
|
catch(Exception&) { failed.insert(*i); } |
|
|
|
container.swap(failed); |
|
} |
|
|
|
destruct_func destruct; |
|
container_type container; |
|
}; |
|
|
|
// |
|
// checked_delete_map(map_of_ptr_to_type, std::mem_fun(&type::destruct)); |
|
// --------------------------------------------------------------------------- |
|
template |
|
< |
|
template<class, class, class, class> class MapT, |
|
class KeyT, class TypeT, class PredT, class AllocatorT, |
|
typename DestructF |
|
> |
|
scoped_delete<MapT<KeyT, TypeT, PredT, AllocatorT>, DestructF, 4> |
|
checked_delete_map(MapT<KeyT, TypeT, PredT, AllocatorT>& map_ref, const DestructF& destruct) |
|
{ |
|
return scoped_delete<MapT<KeyT, TypeT, PredT, AllocatorT>, DestructF, 4>(map_ref, destruct); |
|
} |
|
|
|
// |
|
// scoped_delete<> |
|
// --------------------------------------------------------------------------- |
|
template<typename TypeT, typename DestructF> |
|
struct scoped_delete<TypeT, DestructF, 0> |
|
{ |
|
scoped_delete(const DestructF& _destruct) |
|
: destruct(_destruct) |
|
{ } |
|
|
|
~scoped_delete() |
|
{ if(value.empty() == false) checked_delete(value, destruct); } |
|
|
|
DestructF destruct; |
|
TypeT value; |
|
}; |
|
|
|
// |
|
// checked_static_cast<> |
|
// --------------------------------------------------------------------------- |
|
template<class U, class V> |
|
inline U checked_static_cast(V p) |
|
{ |
|
ACT_ASSERT(p != 0); |
|
ACT_ASSERT(dynamic_cast<U>(p) != 0); |
|
return static_cast<U>(p); |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
template<typename TypeT> |
|
inline TypeT& byref(const TypeT& e) |
|
{ |
|
return const_cast<TypeT&>(e); |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline int max_int() |
|
{ |
|
return int((unsigned(1) << (8 * sizeof(int) - 1)) - 1); |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline void OS2IP(Blob& number) |
|
{ |
|
// octet string to integer presentation |
|
if((number.at(0) & byte(0x80)) != 0) |
|
number.insert(number.begin(), 0); |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline void I2OSP(Blob& number) |
|
{ |
|
// integer to octet string presentation |
|
if(number.at(0) == byte(0)) |
|
number.erase(number.begin()); |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline void byte2long(const byte *in, size_t input_len, uint32 *out) |
|
{ |
|
size_t i, output_len = input_len / 4; |
|
for(i = 0; i < output_len; i++) |
|
out[i]= in[i*4] | (in[i*4+1] << 8) | (in[i*4+2] << 16) | (in[i*4+3] << 24); |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline void long2byte(const uint32 *in, size_t input_len, byte *out) |
|
{ |
|
size_t i, output_len = input_len * 4; |
|
for(i = 0; i < output_len; i++) |
|
out[i] = byte(in[i/4] >> (8*(i%4))); |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline void sweep(void* Mem,size_t l) |
|
{ |
|
std::fill_n(reinterpret_cast<byte*>(Mem), l, byte(0)); |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
template<class TypeT> |
|
inline const TypeT Min(const TypeT& a, const TypeT& b) |
|
{ |
|
return (a < b) ? a : b; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
template<class TypeT> |
|
inline const TypeT& Max(const TypeT& a, const TypeT& b) |
|
{ |
|
return (a<b)? b : a; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
template<class T1, class T2, class T3> |
|
inline void xor_n(T1 a, T2 len, T3 b) |
|
{ |
|
for(T2 i = 0; i < len; i++) b[i] ^= a[i]; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
template<class T1, class T3> inline void Xor (T1 a, T1 a_end, T3 b) |
|
{ |
|
while(a < a_end) |
|
*b++ ^= *a++; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline const char* blob2char(Blob& b) |
|
{ |
|
b.push_back(byte(0)); |
|
return reinterpret_cast<const char*>(&b[0]); |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline std::string blob2string(const Blob& value) |
|
{ |
|
return value.empty() == false ? |
|
std::string(reinterpret_cast<const std::string::value_type*>(&value.at(0)), |
|
reinterpret_cast<const std::string::value_type*>(&value[0] + value.size())) : |
|
std::string(); |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline std::string byte2hex(const byte i) |
|
{ |
|
char tmp[3]; |
|
sprintf(tmp, "%02x", i); |
|
return tmp; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline bool isHex(const byte c) |
|
{ |
|
if((c < byte('0') || c > byte('9')) |
|
&& (c < byte('a') || c > byte('f')) |
|
&& (c < byte('A') || c > byte('F'))) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline bool isHex(const Blob& b) |
|
{ |
|
size_t i, b_len = b.size(); |
|
|
|
for(i = 0; i < b_len; ++i) |
|
if(!isHex(b[i])) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline bool isAlphanumeric(const byte c) |
|
{ |
|
if((c < byte('0') || c > byte('9')) |
|
&& (c < byte('a') || c > byte('z')) |
|
&& (c < byte('A') || c > byte('Z'))) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline bool isAlphanumeric(const Blob& b) |
|
{ |
|
size_t i, b_len = b.size(); |
|
|
|
for(i = 0; i < b_len; ++i) |
|
if(!isAlphanumeric(b[i])) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline bool isPrintable(const Blob& b) |
|
{ |
|
size_t i, b_len = b.size(); |
|
|
|
for(i = 0; i < b_len; ++i) |
|
if(isprint(int(b[i])) == 0) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline bool isUUIDFormat(const Blob& b) |
|
{ |
|
size_t b_len = b.size(); |
|
|
|
if(b_len != sizeof_uuid) |
|
return false; |
|
|
|
// check if the Blob contains only hexadecimal characters, |
|
// separated by '-' (UUID string representation) |
|
for(size_t i = 0; i < b_len; ++i) |
|
if(!isHex(b[i]) && (b[i] != byte('-'))) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline std::string short2hex(const unsigned short i) |
|
{ |
|
char tmp[5]; |
|
sprintf(tmp,"%04x",i); |
|
return tmp; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline std::string long2hex(const unsigned long i) |
|
{ |
|
char tmp[9]; |
|
sprintf(tmp,"%08lx",i); |
|
return tmp; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline unsigned long blob2long(const Blob& b) |
|
{ |
|
if(b.size() == 0) |
|
throw LogicalException("bad size","blob2long"); |
|
|
|
Blob tmp(b); |
|
while(tmp[0] == 0 && tmp.size() > sizeof(long)) |
|
tmp.erase(tmp.begin()); |
|
|
|
if(tmp.size() > sizeof(long)) |
|
throw LogicalException("bad size", "blob2long"); |
|
|
|
unsigned long n = tmp[0]; |
|
for(unsigned int i = 1; i < tmp.size(); ++i) |
|
{ |
|
n <<= 8; |
|
n |= tmp[i]; |
|
} |
|
return n; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline Blob& long2blob(unsigned long n, Blob& value) |
|
{ |
|
value.resize(sizeof(long)); |
|
for(size_t i = sizeof(long) - 1, j = 0; j < sizeof(long); --i, ++j) |
|
value[j] = byte((n >> (8 * i)) & 0xff); |
|
return value; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline Blob long2blob(unsigned long n) |
|
{ |
|
Blob value; |
|
return move(long2blob(n, value)); |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline Blob size2blob(size_t size) |
|
{ |
|
Blob tmp; |
|
tmp.reserve(8); |
|
|
|
if(size == 0) |
|
{ |
|
tmp.resize(1); |
|
return move(tmp); |
|
} |
|
size_t remaining = size; |
|
while(remaining > 0) |
|
{ |
|
tmp.insert(tmp.begin(), byte(remaining & 0xFF)); |
|
remaining >>= 8; |
|
} |
|
return move(tmp); |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline unsigned short blob2short(const Blob& b) |
|
{ |
|
if(b.size() != sizeof(short)) |
|
throw LogicalException("bad size", "blob2short"); |
|
|
|
unsigned short n = b[1]; |
|
n += (b[0] << 8); |
|
return n; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
// Input: a (big endian byte arrays) |
|
// Output: ++a (increment with carry) |
|
inline byte memincr(byte* a, int len) |
|
{ |
|
int i = len-1; |
|
byte carry; |
|
do { |
|
carry = ++a[i] == 0 ? 1 : 0; |
|
} while( --i >= 0 && carry != 0); |
|
return carry; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
// Input: a, b (big endian byte arrays) |
|
// Output: a += b (add with carry) |
|
inline byte memadd(byte* a, const byte* b, int len, byte carry = 0) |
|
{ |
|
int i = len - 1; |
|
unsigned long tmp; |
|
for(; i >= 0; --i) |
|
{ |
|
tmp = a[i] + b[i] + carry; |
|
a[i] = byte(tmp & 0xff); |
|
carry = byte(tmp >> 8); |
|
} |
|
return carry; |
|
} |
|
|
|
// --------------------------------------------------------------------------- |
|
inline void convert_to_upper(std::string& s) |
|
{ |
|
for(std::string::iterator it = s.begin(); it != s.end() ; ++it) |
|
*it = toupper(*it); |
|
} |
|
|
|
} //namespace act |
|
|
|
#endif // ACT_Utility_h
|
|
|