From 061d2cf31700181de1e7a447686dc967a2288475 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 18 Sep 2015 18:52:34 +0800 Subject: [PATCH] cipher for sha1/sha256/sha224/sha512/sha384 md5 hmac aes 3des pbkdf2 rsa digest. --- Makefile.comm | 15 + base/base64.cpp | 252 ++ base/base64.h | 17 + base/stringutils.cpp | 337 +++ base/stringutils.h | 166 ++ cipher/Makefile | 26 + cipher/aes.c | 1246 ++++++++++ cipher/aes.h | 13 + cipher/digest.c | 108 + cipher/digest.h | 43 + cipher/hmac.c | 219 ++ cipher/hmac.h | 29 + cipher/md5.c | 373 +++ cipher/md5.h | 83 + cipher/md5key.cpp | 472 ++++ cipher/md5key.h | 34 + cipher/pbkdf2_hmac.c | 325 +++ cipher/pbkdf2_hmac.h | 21 + cipher/rc4.c | 42 + cipher/rc4.h | 11 + cipher/rsa/Makefile | 19 + cipher/rsa/Makefile.aix | 19 + cipher/rsa/Makefile.hp | 19 + cipher/rsa/Makefile.linux | 19 + cipher/rsa/asn1.c | 212 ++ cipher/rsa/asn1.h | 72 + cipher/rsa/base64.c | 154 ++ cipher/rsa/base64.h | 31 + cipher/rsa/bignum.c | 230 ++ cipher/rsa/bignum.h | 38 + cipher/rsa/build_config.h | 105 + cipher/rsa/common.c | 333 +++ cipher/rsa/common.h | 489 ++++ cipher/rsa/includes.h | 59 + cipher/rsa/libtommath.c | 3381 +++++++++++++++++++++++++++ cipher/rsa/os.h | 512 ++++ cipher/rsa/os_unix.c | 439 ++++ cipher/rsa/rsa.c | 374 +++ cipher/rsa/rsa.h | 29 + cipher/rsa/test_rsa.c | 139 ++ cipher/rsa/trace.c | 329 +++ cipher/rsa/trace.h | 74 + cipher/rsa/user_rsa.c | 94 + cipher/rsa/user_rsa.h | 19 + cipher/rsa/wpa_debug.c | 397 ++++ cipher/rsa/wpa_debug.h | 256 ++ cipher/rsa/wpabuf.c | 304 +++ cipher/rsa/wpabuf.h | 162 ++ cipher/sha.c | 222 ++ cipher/sha.h | 21 + cipher/sha1.c | 296 +++ cipher/sha1.h | 28 + cipher/sha224.c | 38 + cipher/sha224.h | 15 + cipher/sha256.c | 243 ++ cipher/sha256.h | 22 + cipher/sha384.c | 41 + cipher/sha384.h | 14 + cipher/sha512.c | 364 +++ cipher/sha512.h | 23 + cipher/ssh.h | 57 + cipher/tdes.c | 1246 ++++++++++ cipher/tdes.h | 18 + cipher/unittest/Makefile | 39 + cipher/unittest/cipher_unittest.cpp | 380 +++ cipher/unittest/ut/test_harness.cpp | 95 + cipher/unittest/ut/test_harness.h | 152 ++ 67 files changed, 15454 insertions(+) create mode 100644 Makefile.comm create mode 100644 base/base64.cpp create mode 100644 base/base64.h create mode 100644 base/stringutils.cpp create mode 100644 base/stringutils.h create mode 100644 cipher/Makefile create mode 100644 cipher/aes.c create mode 100644 cipher/aes.h create mode 100644 cipher/digest.c create mode 100644 cipher/digest.h create mode 100644 cipher/hmac.c create mode 100644 cipher/hmac.h create mode 100644 cipher/md5.c create mode 100644 cipher/md5.h create mode 100644 cipher/md5key.cpp create mode 100644 cipher/md5key.h create mode 100644 cipher/pbkdf2_hmac.c create mode 100644 cipher/pbkdf2_hmac.h create mode 100644 cipher/rc4.c create mode 100644 cipher/rc4.h create mode 100644 cipher/rsa/Makefile create mode 100644 cipher/rsa/Makefile.aix create mode 100644 cipher/rsa/Makefile.hp create mode 100644 cipher/rsa/Makefile.linux create mode 100644 cipher/rsa/asn1.c create mode 100644 cipher/rsa/asn1.h create mode 100644 cipher/rsa/base64.c create mode 100644 cipher/rsa/base64.h create mode 100644 cipher/rsa/bignum.c create mode 100644 cipher/rsa/bignum.h create mode 100644 cipher/rsa/build_config.h create mode 100644 cipher/rsa/common.c create mode 100644 cipher/rsa/common.h create mode 100644 cipher/rsa/includes.h create mode 100644 cipher/rsa/libtommath.c create mode 100644 cipher/rsa/os.h create mode 100644 cipher/rsa/os_unix.c create mode 100644 cipher/rsa/rsa.c create mode 100644 cipher/rsa/rsa.h create mode 100644 cipher/rsa/test_rsa.c create mode 100644 cipher/rsa/trace.c create mode 100644 cipher/rsa/trace.h create mode 100644 cipher/rsa/user_rsa.c create mode 100644 cipher/rsa/user_rsa.h create mode 100644 cipher/rsa/wpa_debug.c create mode 100644 cipher/rsa/wpa_debug.h create mode 100644 cipher/rsa/wpabuf.c create mode 100644 cipher/rsa/wpabuf.h create mode 100644 cipher/sha.c create mode 100644 cipher/sha.h create mode 100644 cipher/sha1.c create mode 100644 cipher/sha1.h create mode 100644 cipher/sha224.c create mode 100644 cipher/sha224.h create mode 100644 cipher/sha256.c create mode 100644 cipher/sha256.h create mode 100644 cipher/sha384.c create mode 100644 cipher/sha384.h create mode 100644 cipher/sha512.c create mode 100644 cipher/sha512.h create mode 100644 cipher/ssh.h create mode 100644 cipher/tdes.c create mode 100644 cipher/tdes.h create mode 100644 cipher/unittest/Makefile create mode 100644 cipher/unittest/cipher_unittest.cpp create mode 100644 cipher/unittest/ut/test_harness.cpp create mode 100644 cipher/unittest/ut/test_harness.h diff --git a/Makefile.comm b/Makefile.comm new file mode 100644 index 0000000..a1acdda --- /dev/null +++ b/Makefile.comm @@ -0,0 +1,15 @@ +#CFLAGS = -DDEBUG_LOG -D_DEBUG +#CFLAGS = -DDEBUG_LOG +CFLAGS = -DLINUX + +CC=gcc -std=c++11 -g -O3 $(CFLAGS) +CC=gcc -std=c++11 -g $(CFLAGS) +CCC=gcc -std=c++11 -g $(CFLAGS) +SHARED_FLAG = -fPIC -shared + +%.o : %.cpp + $(CC) $(INC) -c $< -o $@ +%.o : %.c + $(CC) $(INC) -c $< -o $@ +%.o : %.cc + $(CC) $(INC) -c $< -o $@ diff --git a/base/base64.cpp b/base/base64.cpp new file mode 100644 index 0000000..be46cc4 --- /dev/null +++ b/base/base64.cpp @@ -0,0 +1,252 @@ +/* +** Copyright (C) 2014 Wang Yaofu +** All rights reserved. +** +**Author:Wang Yaofu voipman@qq.com +**Description: The source file of base64. +*/ + +#include +#include +#include +#include "base64.h" +namespace { + +static const unsigned char EncodeTable[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const unsigned char* DecodeTable = NULL; + +void FillDecodeTable() { + // double buffer is used here for thread safe. + static unsigned char DecodeTableBuff[256]; + unsigned char buff[256]; + if (DecodeTable != NULL) { + return; + } + ::memset(buff, 0x80, sizeof(buff)); + + for (size_t k = 0; k < sizeof(EncodeTable); ++k) { + buff[(size_t)EncodeTable[k]] = k; + } + // to mark those valid characters in encoded string, but not in these + // 64 bases list. + buff[(size_t)'\r'] = buff[(size_t)'\n'] = 0x4F; + buff[(size_t)'='] = 0x40; + + ::memcpy(DecodeTableBuff, buff, sizeof(DecodeTableBuff)); + DecodeTable = DecodeTableBuff; +} + +// Get the next 4 characters from input string, '\r\n' will be trimmed off. +// The input string starts from 'p', and ends before 'q'. 'buff' is for +// storing the return characters. +// The return value, -1: error, there aren't 4 characters available, or get +// invalid character. 0-4 mean the number of valid characters, '=' is excluded. +int GetNext4EncodedCharacters(const unsigned char*& p, + const unsigned char* q, + unsigned char* buff) { + int k = 0; + unsigned char c = 0; + while (k < 4 && p < q) { + c = DecodeTable[*p]; + if ((c & 0xC0) == 0) { // normal valid characters + *buff++ = c; + ++p; + ++k; + } else if (c & 0x80) { // not ('\r' or '\n' or '=') + return -1; + } else if (*p == '=') { + break; + } else { // ('\r' or '\n') + ++p; + } + } + // success. this should be most of the cases, return as soon as possible + if (k == 4) { + return 4; + } + // get a '=' + if (p < q && *p == '=') { + ++p; + // there should be 4 characters in the last encode group + int tail = 4 - k - 1; + // there should not be more than 2 '=' in the end + if (tail > 1) { + return -1; + } + while (tail > 0 && p < q && ((DecodeTable[*p] & 0x40) == 0x40)) { + if (*p == '=') { + --tail; + } + ++p; + } + // any character not ('\r' or '\n' or '=') appears after '=' + if (tail != 0) { + return -1; + } + // only ('\r' || '\n') is allowed at the end + while (p < q) { + if ((DecodeTable[*p] & 0x4F) == 0x4F) { + ++p; + } else { + return -1; + } + } + + return k; + } + // for ('\r' or '\n') at very end + while (p < q && (DecodeTable[*p] & 0x4F) == 0x4F) { + ++p; + } + if (k == 0 && p == q) { + return 0; + } + + return -1; +} + +size_t ExpectedEncodeLength(size_t len) +{ + size_t encodedLen = ((len * 4 / 3 + 3) / 4) * 4; + return encodedLen; +} + +size_t ExpectedDecodeLength(size_t len) +{ + return (size_t)((len + 3) / 4 * 3); +} + +} // anonymous namespace + +bool Base64Encode(const std::string& input, std::string* output) +{ + assert(output); + output->resize(ExpectedEncodeLength(input.size())); + + char* buff = const_cast(output->data()); + size_t len = output->size(); + + if (!Base64Encode(input, buff, &len)) { + output->clear(); + return false; + } + output->resize(len); + return true; +} + +bool Base64Encode(const std::string& input, char* output, size_t* len) +{ + assert(output); + + char* buff = output; + if (__builtin_expect(*len < ExpectedEncodeLength(input.size()), 0)) { + return false; + } + + unsigned char *p = (unsigned char*)input.data(); + unsigned char *q = p + input.size(); + unsigned char c1, c2, c3; + + // process 3 char every loop + for (; p + 3 <= q; p += 3) { + c1 = *p; + c2 = *(p + 1); + c3 = *(p + 2); + + *buff++ = EncodeTable[c1 >> 2]; + *buff++ = EncodeTable[((c1 << 4) | (c2 >> 4)) & 0x3f]; + *buff++ = EncodeTable[((c2 << 2) | (c3 >> 6)) & 0x3f]; + *buff++ = EncodeTable[c3 & 0x3f]; + } + + // the reminders + if (q - p == 1) { + c1 = *p; + *buff++ = EncodeTable[(c1 & 0xfc) >> 2]; + *buff++ = EncodeTable[(c1 & 0x03) << 4]; + *buff++ = '='; + *buff++ = '='; + } else if (q - p == 2) { + c1 = *p; + c2 = *(p + 1); + *buff++ = EncodeTable[(c1 & 0xfc) >> 2]; + *buff++ = EncodeTable[((c1 & 0x03) << 4) | ((c2 & 0xf0) >> 4)]; + *buff++ = EncodeTable[((c2 & 0x0f) << 2)]; + *buff++ = '='; + } + + *len = buff - output; + return true; +} + +bool Base64Decode(const std::string& input, std::string* output) +{ + assert(output); + output->resize(ExpectedDecodeLength(input.size())); + + char* buff = const_cast(output->data()); + size_t len = output->size(); + + if (!Base64Decode(input, buff, &len)) { + output->clear(); + return false; + } + output->resize(len); + return true; +} + +bool Base64Decode(const std::string& input, char* output, size_t* len) +{ + assert(output && len); + + char* buff = output; + if (__builtin_expect(*len < ExpectedDecodeLength(input.size()), 0)) { + return false; + } + if (__builtin_expect(!DecodeTable, 0)) { + FillDecodeTable(); + } + if (input.empty()) { + *len = buff - output; + return true; + } + + const unsigned char* p = (unsigned char*)input.data(); + const unsigned char* q = (unsigned char*)input.data() + input.size(); + + // handle 4 bytes in every loop + while (true) { + char ch = 0; + unsigned char encoded[4]; + int len = GetNext4EncodedCharacters(p, q, encoded); + if (__builtin_expect(len == 4, 1)) { + ch = encoded[0] << 2; // all 6 bits + ch |= encoded[1] >> 4; // 2 high bits + *buff++ = ch; + ch = encoded[1] << 4; // 4 low bits + ch |= encoded[2] >> 2; // 4 high bits + *buff++ = ch; + ch = encoded[2] << 6; // 2 low bits + ch |= encoded[3]; + *buff++ = ch; + } else if (len >= 2) { + ch = encoded[0] << 2; // all 6 bits + ch |= encoded[1] >> 4; // 2 high bits + *buff++ = ch; + if (len == 3) { + ch = encoded[1] << 4; // 4 low bits + ch |= encoded[2] >> 2; // 4 high bits + *buff++ = ch; + } + } else if (len == 0) { + break; + } else { + return false; + } + } + + *len = buff - output; + return true; +} + diff --git a/base/base64.h b/base/base64.h new file mode 100644 index 0000000..6a02897 --- /dev/null +++ b/base/base64.h @@ -0,0 +1,17 @@ +/* +** Copyright (C) 2014 Wang Yaofu +** All rights reserved. +** +**Author:Wang Yaofu voipman@qq.com +**Description: The header file of base64. +*/ +#ifndef _BASE64UTILS_H_ +#define _BASE64UTILS_H_ +#include +bool Base64Encode(const std::string& input, std::string* output); +bool Base64Encode(const std::string& input, char* output, size_t* len); + +bool Base64Decode(const std::string& input, std::string* output); +bool Base64Decode(const std::string& input, char* output, size_t* len); + +#endif // #define _BASE64UTILS_H_ diff --git a/base/stringutils.cpp b/base/stringutils.cpp new file mode 100644 index 0000000..3074cec --- /dev/null +++ b/base/stringutils.cpp @@ -0,0 +1,337 @@ +/* +** Copyright (C) 2014 Wang Yaofu +** All rights reserved. +** +**Author:Wang Yaofu voipman@qq.com +**Description: The source file of class CStringUitls. +*/ +#include +#include +#include +#include +#include +#include +#include "stringutils.h" +namespace common { + const char kWhitespaceASCII[] = + { + 0x09, // to + 0x0A, + 0x0B, + 0x0C, + 0x0D, + 0x20, // Space + 0 + }; + + template + void TrimStringT(const STR& input, + const typename STR::value_type trim_chars[], + TrimOption option, + STR* output) { + // Find the edges of leading/trailing whitespace as desired. + const typename STR::size_type last_char = input.length() - 1; + const typename STR::size_type first_good_char = (option & kTrimLeading) ? + input.find_first_not_of(trim_chars) : 0; + const typename STR::size_type last_good_char = (option & kTrimTrailing) ? + input.find_last_not_of(trim_chars) : last_char; + + // When the string was all whitespace, report that we stripped off + // whitespace from whichever position the caller was interested in. + // For empty input, we stripped no whitespace, but we still need to + // clear |output|. + if (input.empty() || + (first_good_char == STR::npos) || (last_good_char == STR::npos)) { + output->clear(); + return; + } + + // Trim the whitespace. + *output = + input.substr(first_good_char, last_good_char - first_good_char + 1); + } + + void StrUtils::TrimWhitespace(const std::string& input, + TrimOption option, + std::string* output) { + TrimStringT(input, kWhitespaceASCII, option, output); + } + + void StrUtils::ReplaceString(const std::string& input, + const std::string& old_val, + const std::string& new_val, + std::string* output) { + if (old_val.empty()) { + return; + } + + std::ostringstream ss; + std::string::size_type pos = 0; + std::string::size_type pos_prev = 0; + + while (pos != std::string::npos) { + pos_prev = pos; + if ((pos = input.find(old_val, pos)) != std::string::npos) { + if (pos > pos_prev) { + ss << input.substr(pos_prev, pos - pos_prev); + } + ss << new_val; + pos += old_val.length(); + } else { + if (pos_prev + 1 <= input.length()) { + ss << input.substr(pos_prev); + } + break; + } + } + + *output = ss.str(); + } + + std::string StrUtils::ToLowerCase(const std::string& input) { + if (input.empty()) { + return std::string(); + } + std::string output(input); + std::string::pointer begin = &output[0]; + std::string::pointer end = begin + output.size(); + for (; begin < end; ++begin) { + *begin = tolower(*begin); + } + return output; + } + + std::string StrUtils::ToUpperCase(const std::string& input) { + if (input.empty()) { + return std::string(); + } + std::string output(input); + std::string::pointer begin = &output[0]; + std::string::pointer end = begin + output.size(); + for (; begin < end; ++begin) { + *begin = toupper(*begin); + } + return output; + } + + template + void SplitStringT(const STR& str, + const STR& s, + std::vector* r) { + r->clear(); + typename STR::size_type begin_index = 0; + while (true) { + const typename STR::size_type end_index = str.find(s, begin_index); + if (end_index == STR::npos) { + const STR term = str.substr(begin_index); + r->push_back(term); + return; + } + const STR term = str.substr(begin_index, end_index - begin_index); + r->push_back(term); + begin_index = end_index + s.size(); + } + } + + void StrUtils::SplitString(const std::string& str, + const std::string& s, + std::vector* r) { + SplitStringT(str, s, r); + } + bool StrUtils::Split(const std::string& s, + char sep, + std::string& first, + std::string& second) { + std::string::size_type sep_pos = s.find(sep); + first = s.substr(0, sep_pos); + if (sep_pos!=std::string::npos) + second = s.substr(sep_pos+1); + return true; + } + int StrUtils::stoi(const std::string &str) { + return ::atoi(str.c_str()); + } + long StrUtils::stol(const std::string &str, const int base) { + char *ep; + return ::strtol(str.c_str(), &ep, base); + } + long long StrUtils::stoll(const std::string &str, const int base) { + char *ep; + return ::strtoll(str.c_str(), &ep, base); + } + unsigned long StrUtils::stoul(const std::string &str, const int base) { + char *ep; + return ::strtoul(str.c_str(), &ep, base); + } + unsigned long long StrUtils::stoull(const std::string &str, const int base) { + char *ep; + return ::strtoull(str.c_str(), &ep, base); + } + float StrUtils::stof(const std::string& str) { + char *ep; + return ::strtof(str.data(), &ep); + } + double StrUtils::stod(const std::string& str) { + char *ep; + return ::strtold(str.data(), &ep); + } + long double StrUtils::stold(const std::string& str) { + char *ep; + return ::strtod(str.data(), &ep); + } + std::string StrUtils::JoinStr(std::vector& parts, + const std::string& delimiter) { + if (parts.empty()) { + return ""; + } + std::stringstream ss; + for (size_t i = 0; i < parts.size() - 1; ++i) { + ss << parts[i]; + ss << delimiter; + } + ss << parts[parts.size() - 1]; //no delimiter at last + return ss.str(); + } + + std::string StrUtils::JoinStr(std::vector& parts, char delimiter) { + std::string tmp; + tmp.assign(1, delimiter); + return JoinStr(parts, tmp); + } + + std::string StrUtils::Hex(const char* cpSrcStr, int len, bool isUpper) { + if (cpSrcStr == NULL) { + return ""; + } + std::string ret(len * 2, 0x00); + const char* hex = isUpper ? "0123456789ABCDEF" : "0123456789abcdef"; + for (size_t i = 0; i < len; ++i) { + unsigned char v = static_cast(cpSrcStr[i]); + ret[2*i] = hex[(v >> 4) & 0x0f]; + ret[2*i+1] = hex[ v & 0x0f]; + } + return ret; + } + + std::string StrUtils::Hex(const std::string& srcStr, bool isUpper) { + return Hex(srcStr.c_str(), srcStr.size(), isUpper); + } + std::string StrUtils::Hex(const char ch, bool isUpper) { + return Hex(&ch, 1, isUpper); + } + namespace { + char asc_bcd(const char *what) { + unsigned char digit; + unsigned char m; + + digit = (what[0] >= 'a' ? ((what[0]) - 'a') + 10 : (what[0] - '0')); + digit *= 16; + digit += (what[1] >= 'a' ? ((what[1]) - 'a') + 10 : (what[1] - '0')); + return(digit); + } + } + + std::string StrUtils::fromHex(const char* from, size_t len) { + std::string ret(len / 2, 0x00); + for (size_t ii = 0; ii < len / 2; ii++) + ret[ii] = asc_bcd(from + ii * 2); + return ret; + } + + std::string StrUtils::fromHex(const std::string& from) { + return fromHex(from.c_str(), from.length()); + } + + int StrUtils::fromHex(const char* from, char* to) { + int len = strlen(from)/2; + for (size_t ii = 0; ii < len; ii++) + to[ii] = asc_bcd(from + ii * 2); + return len; + } + + int StrUtils::HexStr2Int(const char* aStr, int len) { + int i, res = 0; + + for(i = 0; i < len; i++) { + res *= 16; + if ((aStr[i] >= '0') && (aStr[i] <= '9')) { + res += aStr[i] - '0'; + } else if ((aStr[i] >= 'a') && (aStr[i] <= 'f')) { + res += aStr[i] - 'a' + 10; + } else if ((aStr[i] >= 'A') && (aStr[i] <= 'F')) { + res += aStr[i] - 'A' + 10; + } else { + return 0; + } + } + return res; + } + int StrUtils::HexStr2Int(const std::string& srcStr) { + return HexStr2Int(srcStr.c_str(), srcStr.length()); + } + int StrUtils::Int2HexInt(int src) { + std::string hexStr; + Format(hexStr, "%d", src); + return HexStr2Int(hexStr.c_str(), hexStr.length()); + } + bool StrUtils::IsNumber(char ch) { + return (ch >= '0' && ch <= '9'); + } + + bool StrUtils::IsLetter(char ch) { + return ((ch >= 'a' && ch <= 'z') || ((ch >= 'A') && (ch <= 'Z'))); + } + + bool StrUtils::IsUnderLine(char ch) { + return (ch == '_'); + } + + bool StrUtils::Format(std::string &outStr, const char *format, ...) { + char* mem; + va_list ap; + va_start(ap, format); + if (vasprintf(&mem, format, ap) < 0) { + va_end(ap); + return false; + } + outStr = mem; + va_end(ap); + free(mem); + return true; + } + + unsigned int StrUtils::ELFhash(const char* aStr, unsigned int aHashMod) { + unsigned int h = 0; + + while (*aStr) { + h = (h << 4) + *aStr++; + unsigned int g = h & 0xF0000000; + if (g) h ^= g >> 24; + h &= ~g; + } + + return h % aHashMod; + } + + unsigned int StrUtils::HfIp(const char* aStr, unsigned int aHashMod) { + unsigned int n = 0; + unsigned char* b = (unsigned char*)&n; + + for (unsigned int i = 0; aStr[i] != 0x00; i++) + b[i%4] ^= aStr[i]; + + return n % aHashMod; + } + + unsigned int StrUtils::hf(const char* aStr, unsigned int aHashMod) { + int result = 0; + const char* ptr = aStr; + int c; + + for (int i = 1; (c = *ptr++); i++) + result += c * 3 * i; + if (result < 0) result = -result; + return result % aHashMod; + } + +}// namespace common diff --git a/base/stringutils.h b/base/stringutils.h new file mode 100644 index 0000000..7166a9e --- /dev/null +++ b/base/stringutils.h @@ -0,0 +1,166 @@ +/* +** Copyright (C) 2014 Wang Yaofu +** All rights reserved. +** +**Author:Wang Yaofu voipman@qq.com +**Description: The header file of class CStringUitls. +*/ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +namespace common { + enum TrimOption { + kTrimNone = 0, + kTrimLeading = 1 << 0, + kTrimTrailing = 1 << 1, + kTrimAll = kTrimLeading | kTrimTrailing, + }; + class StrUtils { + public: + static void TrimWhitespace(const std::string& input, + TrimOption option, std::string* output); + + static void ReplaceString(const std::string& input, + const std::string& old_val, + const std::string& new_val, + std::string* output); + + static std::string ReplaceString(const std::string& input, + const std::string& old_val, + const std::string& new_val) { + std::string output; + ReplaceString(input, old_val, new_val, &output); + return output; + } + + static void Trim(std::string& aStr, const std::string& aSep, + TrimOption aOption = kTrimTrailing) { + size_t pos = 0; + if (aOption & kTrimLeading) { + pos = aStr.find(aSep); + if (pos != aStr.npos) { + aStr.erase(0, pos + 1); + } + } + if (aOption & kTrimTrailing) { + pos = aStr.rfind(aSep); + if (pos != aStr.npos) { + aStr.erase(pos); + } + } + } + + // ABC => abc + static std::string ToLowerCase(const std::string& input); + // str => STR + static std::string ToUpperCase(const std::string& input); + // 11&22&33 +& =>11 22 33 + & + static void SplitString(const std::string& str, + const std::string& s, + std::vector* r); + // string to split string + static bool Split(const std::string& s, + char sep, + std::string& first, + std::string& second); + // any to string. + template + static std::string to_string(const INT_TYPE& aValue) { + std::stringstream ss; + ss << aValue; + return ss.str(); + } + + template + static std::string to_string(const typename std::pair& v) { + std::ostringstream o; + o << to_string(v.first) << ": " << to_string(v.second); + return o.str(); + } + + template + static std::string to_string(const T& beg, const T& end) { + std::ostringstream o; + for (T it = beg; it != end; ++it) { + if (it != beg) + o << ", "; + o << to_string(*it); + } + return o.str(); + } + + template + static std::string to_string(const std::vector& t) { + std::ostringstream o; + o << "[" << to_string(t.begin(), t.end()) << "]"; + return o.str(); + } + + template + static std::string to_string(const std::list& t) { + std::ostringstream o; + o << "[" << to_string(t.begin(), t.end()) << "]"; + return o.str(); + } + + template + static std::string to_string(const std::map& m) { + std::ostringstream o; + o << "{" << to_string(m.begin(), m.end()) << "}"; + return o.str(); + } + + template + static std::string to_string(const std::set& s) { + std::ostringstream o; + o << "{" << to_string(s.begin(), s.end()) << "}"; + return o.str(); + } + + template + static Type stringToNum(const std::string& str) { + std::istringstream iss(str); + Type num; + iss >> num; + return num; + } + static int stoi(const std::string &str); + static long stol(const std::string &str, const int base = 10); + static long long stoll(const std::string &str, const int base = 10); + static unsigned long stoul(const std::string &str, const int base = 10); + static unsigned long long stoull(const std::string &str, const int base = 10); + static float stof(const std::string& str); + static double stod(const std::string& str); + static long double stold(const std::string& str); + + // 11 22 33 + & => 11&22&33 + static std::string JoinStr(std::vector& parts, char delimiter); + // 11 22 33 + %% => 11%%22%%33 + static std::string JoinStr(std::vector& parts, const std::string& delimiter); + + // 19AaZz\n => 31 39 41 61 5a 7a 0a + static std::string Hex(const char* cpSrcStr, int len, bool isUpper = false); + static std::string Hex(const std::string& srcStr, bool isUpper = false); + static std::string Hex(const char ch, bool isUpper = false); + static std::string fromHex(const char* from, size_t len); + static int fromHex(const char* from, char* to); + static std::string fromHex(const std::string& from); + static int HexStr2Int(const char* aStr, int len); + static int HexStr2Int(const std::string& srcStr); + static int Int2HexInt(int src); + static bool IsNumber(char ch); + static bool IsLetter(char ch); + static bool IsUnderLine(char ch); + static bool Format(std::string &outStr, const char *format, ...); + static unsigned int HfIp(const char* aStr, unsigned int aHashMod); + static unsigned int hf(const char* aStr, unsigned int aHashMod); + // System - v hash method, it is nice. + static unsigned int ELFhash(const char* aStr, unsigned int aHashMod = 0x7FFFFFFF); + }; +} // namespace common diff --git a/cipher/Makefile b/cipher/Makefile new file mode 100644 index 0000000..5cc9045 --- /dev/null +++ b/cipher/Makefile @@ -0,0 +1,26 @@ +include ../Makefile.comm + +INC += -I../ +INC += -I./ + +SOURCES = $(foreach d,.,$(wildcard $(d)/*.c)) +OBJS = $(patsubst %.c, %.o, $(SOURCES)) +OBJS += md5key.o + +CC += $(SHARED_FLAG) +all : libcipher.a +libcipher.a : $(OBJS) + ar -rus $@ $^ + echo $(OBJS) + echo $(SOURCES) + @echo "" + @echo "+--------------------------------------------+" + @echo "| Finish compilation |" + @echo "+--------------------------------------------+" + @echo "| Thanks using libcipher.a |" + @echo "| copyright(c)Wang Yaofu voipman@qq.com |" + @echo "+--------------------------------------------+" + +clean: + rm -rf *.o *.a + diff --git a/cipher/aes.c b/cipher/aes.c new file mode 100644 index 0000000..36d6bab --- /dev/null +++ b/cipher/aes.c @@ -0,0 +1,1246 @@ +/* + * aes.c - implementation of AES / Rijndael + * + * AES is a flexible algorithm as regards endianness: it has no + * inherent preference as to which way round you should form words + * from the input byte stream. It talks endlessly of four-byte + * _vectors_, but never of 32-bit _words_ - there's no 32-bit + * addition at all, which would force an endianness by means of + * which way the carries went. So it would be possible to write a + * working AES that read words big-endian, and another working one + * that read them little-endian, just by computing a different set + * of tables - with no speed drop. + * + * It's therefore tempting to do just that, and remove the overhead + * of GET_32BIT_MSB_FIRST() et al, allowing every system to use its + * own endianness-native code; but I decided not to, partly for + * ease of testing, and mostly because I like the flexibility that + * allows you to encrypt a non-word-aligned block of memory (which + * many systems would stop being able to do if I went the + * endianness-dependent route). + * + * This implementation reads and stores words big-endian, but + * that's a minor implementation detail. By flipping the endianness + * of everything in the E0..E3, D0..D3 tables, and substituting + * GET_32BIT_LSB_FIRST for GET_32BIT_MSB_FIRST, I could create an + * implementation that worked internally little-endian and gave the + * same answers at the same speed. + */ + +#include +#include + +#include "ssh.h" +#define MAX_NR 14 /* max no of rounds */ +#define MAX_NK 8 /* max no of words in input key */ +#define MAX_NB 8 /* max no of words in cipher blk */ + +#define mulby2(x) ( ((x&0x7F) << 1) ^ (x & 0x80 ? 0x1B : 0) ) +#define PUT_32BIT_MSB_FIRST(cp, value) ( \ + (cp)[0] = (unsigned char)((value) >> 24), \ + (cp)[1] = (unsigned char)((value) >> 16), \ + (cp)[2] = (unsigned char)((value) >> 8), \ + (cp)[3] = (unsigned char)(value) ) + +#define GET_32BIT_LSB_FIRST(cp) \ + (((unsigned long)(unsigned char)(cp)[0]) | \ + ((unsigned long)(unsigned char)(cp)[1] << 8) | \ + ((unsigned long)(unsigned char)(cp)[2] << 16) | \ + ((unsigned long)(unsigned char)(cp)[3] << 24)) + +#define GET_32BIT_MSB_FIRST(cp) \ + (((unsigned long)(unsigned char)(cp)[0] << 24) | \ + ((unsigned long)(unsigned char)(cp)[1] << 16) | \ + ((unsigned long)(unsigned char)(cp)[2] << 8) | \ + ((unsigned long)(unsigned char)(cp)[3])) +typedef unsigned int uint32; +typedef uint32 word32; +typedef struct AESContext AESContext; + +struct AESContext { + word32 keysched[(MAX_NR + 1) * MAX_NB]; + word32 invkeysched[(MAX_NR + 1) * MAX_NB]; + void (*encrypt) (AESContext * ctx, word32 * block); + void (*decrypt) (AESContext * ctx, word32 * block); + word32 iv[MAX_NB]; + int Nb, Nr; +}; + +static const unsigned char Sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +static const unsigned char Sboxinv[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, + 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, + 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, + 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, + 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, + 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, + 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, + 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, + 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, + 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, + 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, + 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, + 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, + 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, + 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +}; + +static const word32 E0[256] = { + 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, + 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, + 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, + 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, + 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, + 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, + 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, + 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, + 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, + 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, + 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, + 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, + 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, + 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, + 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, + 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, + 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, + 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, + 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, + 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, + 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, + 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, + 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, + 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, + 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, + 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, + 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, + 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, + 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, + 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, + 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, + 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, + 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, + 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, + 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, + 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, + 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, + 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, + 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, + 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, + 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, + 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, + 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, + 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, + 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, + 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, + 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, + 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, + 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, + 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, + 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, + 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, + 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, + 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, + 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, + 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, + 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, + 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, + 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, + 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, + 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, + 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, + 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, + 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a, +}; +static const word32 E1[256] = { + 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, + 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, + 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, + 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, + 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, + 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, + 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, + 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, + 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, + 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, + 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, + 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, + 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, + 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, + 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, + 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, + 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, + 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, + 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, + 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, + 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, + 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, + 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, + 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, + 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, + 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, + 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, + 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, + 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, + 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, + 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, + 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, + 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, + 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, + 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, + 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, + 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, + 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, + 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, + 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, + 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, + 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, + 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, + 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, + 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, + 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, + 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, + 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, + 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, + 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, + 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, + 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, + 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, + 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, + 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, + 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, + 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, + 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, + 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, + 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, + 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, + 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, + 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, + 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616, +}; +static const word32 E2[256] = { + 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, + 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, + 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, + 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, + 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, + 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, + 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, + 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, + 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, + 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, + 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, + 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, + 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, + 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, + 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, + 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, + 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, + 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, + 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, + 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, + 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, + 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, + 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, + 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, + 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, + 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, + 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, + 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, + 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, + 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, + 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, + 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, + 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, + 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, + 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, + 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, + 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, + 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, + 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, + 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, + 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, + 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, + 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, + 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, + 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, + 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, + 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, + 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, + 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, + 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, + 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, + 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, + 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, + 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, + 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, + 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, + 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, + 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, + 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, + 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, + 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, + 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, + 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, + 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16, +}; +static const word32 E3[256] = { + 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, + 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, + 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, + 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, + 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, + 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, + 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, + 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, + 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, + 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, + 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, + 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, + 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, + 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, + 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, + 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, + 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, + 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, + 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, + 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, + 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, + 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, + 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, + 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, + 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, + 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, + 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, + 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, + 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, + 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, + 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, + 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, + 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, + 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, + 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, + 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, + 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, + 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, + 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, + 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, + 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, + 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, + 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, + 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, + 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, + 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, + 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, + 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, + 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, + 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, + 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, + 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, + 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, + 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, + 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, + 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, + 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, + 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, + 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, + 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, + 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, + 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, + 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, + 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c, +}; +static const word32 D0[256] = { + 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, + 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, + 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, + 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, + 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, + 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, + 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, + 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, + 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, + 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, + 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, + 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, + 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, + 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, + 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, + 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, + 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, + 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, + 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, + 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, + 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, + 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, + 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, + 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, + 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, + 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, + 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, + 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, + 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, + 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, + 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, + 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, + 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, + 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, + 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, + 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, + 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, + 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, + 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, + 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, + 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, + 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, + 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, + 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, + 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, + 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, + 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, + 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, + 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, + 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, + 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, + 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, + 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, + 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, + 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, + 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, + 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, + 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, + 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, + 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, + 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, + 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, + 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, + 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742, +}; +static const word32 D1[256] = { + 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, + 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, + 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, + 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, + 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, + 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, + 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, + 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, + 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, + 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, + 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, + 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, + 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, + 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, + 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, + 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, + 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, + 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, + 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, + 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, + 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, + 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, + 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, + 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, + 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, + 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, + 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, + 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, + 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, + 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, + 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, + 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, + 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, + 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, + 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, + 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, + 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, + 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, + 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, + 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, + 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, + 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, + 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, + 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, + 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, + 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, + 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, + 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, + 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, + 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, + 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, + 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, + 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, + 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, + 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, + 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, + 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, + 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, + 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, + 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, + 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, + 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, + 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, + 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857, +}; +static const word32 D2[256] = { + 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, + 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, + 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, + 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, + 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, + 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, + 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, + 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, + 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, + 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, + 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, + 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, + 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, + 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, + 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, + 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, + 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, + 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, + 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, + 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, + 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, + 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, + 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, + 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, + 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, + 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, + 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, + 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, + 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, + 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, + 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, + 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, + 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, + 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, + 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, + 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, + 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, + 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, + 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, + 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, + 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, + 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, + 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, + 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, + 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, + 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, + 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, + 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, + 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, + 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, + 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, + 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, + 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, + 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, + 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, + 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, + 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, + 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, + 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, + 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, + 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, + 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, + 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, + 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8, +}; +static const word32 D3[256] = { + 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, + 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, + 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, + 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, + 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, + 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, + 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, + 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, + 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, + 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, + 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, + 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, + 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, + 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, + 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, + 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, + 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, + 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, + 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, + 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, + 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, + 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, + 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, + 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, + 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, + 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, + 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, + 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, + 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, + 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, + 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, + 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, + 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, + 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, + 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, + 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, + 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, + 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, + 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, + 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, + 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, + 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, + 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, + 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, + 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, + 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, + 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, + 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, + 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, + 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, + 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, + 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, + 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, + 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, + 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, + 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, + 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, + 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, + 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, + 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, + 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, + 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, + 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, + 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0, +}; + +/* + * Common macros in both the encryption and decryption routines. + */ +#define ADD_ROUND_KEY_4 (block[0]^=*keysched++, block[1]^=*keysched++, \ + block[2]^=*keysched++, block[3]^=*keysched++) +#define ADD_ROUND_KEY_6 (block[0]^=*keysched++, block[1]^=*keysched++, \ + block[2]^=*keysched++, block[3]^=*keysched++, \ + block[4]^=*keysched++, block[5]^=*keysched++) +#define ADD_ROUND_KEY_8 (block[0]^=*keysched++, block[1]^=*keysched++, \ + block[2]^=*keysched++, block[3]^=*keysched++, \ + block[4]^=*keysched++, block[5]^=*keysched++, \ + block[6]^=*keysched++, block[7]^=*keysched++) +#define MOVEWORD(i) ( block[i] = newstate[i] ) + +/* + * Macros for the encryption routine. There are three encryption + * cores, for Nb=4,6,8. + */ +#define MAKEWORD(i) ( newstate[i] = (E0[(block[i] >> 24) & 0xFF] ^ \ + E1[(block[(i+C1)%Nb] >> 16) & 0xFF] ^ \ + E2[(block[(i+C2)%Nb] >> 8) & 0xFF] ^ \ + E3[block[(i+C3)%Nb] & 0xFF]) ) +#define LASTWORD(i) ( newstate[i] = (Sbox[(block[i] >> 24) & 0xFF] << 24) | \ + (Sbox[(block[(i+C1)%Nb] >> 16) & 0xFF] << 16) | \ + (Sbox[(block[(i+C2)%Nb] >> 8) & 0xFF] << 8) | \ + (Sbox[(block[(i+C3)%Nb] ) & 0xFF] ) ) + +/* + * Core encrypt routines, expecting word32 inputs read big-endian + * from the byte-oriented input stream. + */ +static void aes_encrypt_nb_4(AESContext * ctx, word32 * block) +{ + int i; + static const int C1 = 1, C2 = 2, C3 = 3, Nb = 4; + word32 *keysched = ctx->keysched; + word32 newstate[4]; + for (i = 0; i < ctx->Nr - 1; i++) { + ADD_ROUND_KEY_4; + MAKEWORD(0); + MAKEWORD(1); + MAKEWORD(2); + MAKEWORD(3); + MOVEWORD(0); + MOVEWORD(1); + MOVEWORD(2); + MOVEWORD(3); + } + ADD_ROUND_KEY_4; + LASTWORD(0); + LASTWORD(1); + LASTWORD(2); + LASTWORD(3); + MOVEWORD(0); + MOVEWORD(1); + MOVEWORD(2); + MOVEWORD(3); + ADD_ROUND_KEY_4; +} +static void aes_encrypt_nb_6(AESContext * ctx, word32 * block) +{ + int i; + static const int C1 = 1, C2 = 2, C3 = 3, Nb = 6; + word32 *keysched = ctx->keysched; + word32 newstate[6]; + for (i = 0; i < ctx->Nr - 1; i++) { + ADD_ROUND_KEY_6; + MAKEWORD(0); + MAKEWORD(1); + MAKEWORD(2); + MAKEWORD(3); + MAKEWORD(4); + MAKEWORD(5); + MOVEWORD(0); + MOVEWORD(1); + MOVEWORD(2); + MOVEWORD(3); + MOVEWORD(4); + MOVEWORD(5); + } + ADD_ROUND_KEY_6; + LASTWORD(0); + LASTWORD(1); + LASTWORD(2); + LASTWORD(3); + LASTWORD(4); + LASTWORD(5); + MOVEWORD(0); + MOVEWORD(1); + MOVEWORD(2); + MOVEWORD(3); + MOVEWORD(4); + MOVEWORD(5); + ADD_ROUND_KEY_6; +} +static void aes_encrypt_nb_8(AESContext * ctx, word32 * block) +{ + int i; + static const int C1 = 1, C2 = 3, C3 = 4, Nb = 8; + word32 *keysched = ctx->keysched; + word32 newstate[8]; + for (i = 0; i < ctx->Nr - 1; i++) { + ADD_ROUND_KEY_8; + MAKEWORD(0); + MAKEWORD(1); + MAKEWORD(2); + MAKEWORD(3); + MAKEWORD(4); + MAKEWORD(5); + MAKEWORD(6); + MAKEWORD(7); + MOVEWORD(0); + MOVEWORD(1); + MOVEWORD(2); + MOVEWORD(3); + MOVEWORD(4); + MOVEWORD(5); + MOVEWORD(6); + MOVEWORD(7); + } + ADD_ROUND_KEY_8; + LASTWORD(0); + LASTWORD(1); + LASTWORD(2); + LASTWORD(3); + LASTWORD(4); + LASTWORD(5); + LASTWORD(6); + LASTWORD(7); + MOVEWORD(0); + MOVEWORD(1); + MOVEWORD(2); + MOVEWORD(3); + MOVEWORD(4); + MOVEWORD(5); + MOVEWORD(6); + MOVEWORD(7); + ADD_ROUND_KEY_8; +} + +#undef MAKEWORD +#undef LASTWORD + +/* + * Macros for the decryption routine. There are three decryption + * cores, for Nb=4,6,8. + */ +#define MAKEWORD(i) ( newstate[i] = (D0[(block[i] >> 24) & 0xFF] ^ \ + D1[(block[(i+C1)%Nb] >> 16) & 0xFF] ^ \ + D2[(block[(i+C2)%Nb] >> 8) & 0xFF] ^ \ + D3[block[(i+C3)%Nb] & 0xFF]) ) +#define LASTWORD(i) (newstate[i] = (Sboxinv[(block[i] >> 24) & 0xFF] << 24) | \ + (Sboxinv[(block[(i+C1)%Nb] >> 16) & 0xFF] << 16) | \ + (Sboxinv[(block[(i+C2)%Nb] >> 8) & 0xFF] << 8) | \ + (Sboxinv[(block[(i+C3)%Nb] ) & 0xFF] ) ) + +/* + * Core decrypt routines, expecting word32 inputs read big-endian + * from the byte-oriented input stream. + */ +static void aes_decrypt_nb_4(AESContext * ctx, word32 * block) +{ + int i; + static const int C1 = 4 - 1, C2 = 4 - 2, C3 = 4 - 3, Nb = 4; + word32 *keysched = ctx->invkeysched; + word32 newstate[4]; + for (i = 0; i < ctx->Nr - 1; i++) { + ADD_ROUND_KEY_4; + MAKEWORD(0); + MAKEWORD(1); + MAKEWORD(2); + MAKEWORD(3); + MOVEWORD(0); + MOVEWORD(1); + MOVEWORD(2); + MOVEWORD(3); + } + ADD_ROUND_KEY_4; + LASTWORD(0); + LASTWORD(1); + LASTWORD(2); + LASTWORD(3); + MOVEWORD(0); + MOVEWORD(1); + MOVEWORD(2); + MOVEWORD(3); + ADD_ROUND_KEY_4; +} +static void aes_decrypt_nb_6(AESContext * ctx, word32 * block) +{ + int i; + static const int C1 = 6 - 1, C2 = 6 - 2, C3 = 6 - 3, Nb = 6; + word32 *keysched = ctx->invkeysched; + word32 newstate[6]; + for (i = 0; i < ctx->Nr - 1; i++) { + ADD_ROUND_KEY_6; + MAKEWORD(0); + MAKEWORD(1); + MAKEWORD(2); + MAKEWORD(3); + MAKEWORD(4); + MAKEWORD(5); + MOVEWORD(0); + MOVEWORD(1); + MOVEWORD(2); + MOVEWORD(3); + MOVEWORD(4); + MOVEWORD(5); + } + ADD_ROUND_KEY_6; + LASTWORD(0); + LASTWORD(1); + LASTWORD(2); + LASTWORD(3); + LASTWORD(4); + LASTWORD(5); + MOVEWORD(0); + MOVEWORD(1); + MOVEWORD(2); + MOVEWORD(3); + MOVEWORD(4); + MOVEWORD(5); + ADD_ROUND_KEY_6; +} +static void aes_decrypt_nb_8(AESContext * ctx, word32 * block) +{ + int i; + static const int C1 = 8 - 1, C2 = 8 - 3, C3 = 8 - 4, Nb = 8; + word32 *keysched = ctx->invkeysched; + word32 newstate[8]; + for (i = 0; i < ctx->Nr - 1; i++) { + ADD_ROUND_KEY_8; + MAKEWORD(0); + MAKEWORD(1); + MAKEWORD(2); + MAKEWORD(3); + MAKEWORD(4); + MAKEWORD(5); + MAKEWORD(6); + MAKEWORD(7); + MOVEWORD(0); + MOVEWORD(1); + MOVEWORD(2); + MOVEWORD(3); + MOVEWORD(4); + MOVEWORD(5); + MOVEWORD(6); + MOVEWORD(7); + } + ADD_ROUND_KEY_8; + LASTWORD(0); + LASTWORD(1); + LASTWORD(2); + LASTWORD(3); + LASTWORD(4); + LASTWORD(5); + LASTWORD(6); + LASTWORD(7); + MOVEWORD(0); + MOVEWORD(1); + MOVEWORD(2); + MOVEWORD(3); + MOVEWORD(4); + MOVEWORD(5); + MOVEWORD(6); + MOVEWORD(7); + ADD_ROUND_KEY_8; +} + +#undef MAKEWORD +#undef LASTWORD + + +/* + * Set up an AESContext. `keylen' and `blocklen' are measured in + * bytes; each can be either 16 (128-bit), 24 (192-bit), or 32 + * (256-bit). + */ +static void aes_setup(AESContext * ctx, int blocklen, + unsigned char *key, int keylen) +{ + int i, j, Nk, rconst; + + assert(blocklen == 16 || blocklen == 24 || blocklen == 32); + assert(keylen == 16 || keylen == 24 || keylen == 32); + + /* + * Basic parameters. Words per block, words in key, rounds. + */ + Nk = keylen / 4; + ctx->Nb = blocklen / 4; + ctx->Nr = 6 + (ctx->Nb > Nk ? ctx->Nb : Nk); + + /* + * Assign core-function pointers. + */ + if (ctx->Nb == 8) + ctx->encrypt = aes_encrypt_nb_8, ctx->decrypt = aes_decrypt_nb_8; + else if (ctx->Nb == 6) + ctx->encrypt = aes_encrypt_nb_6, ctx->decrypt = aes_decrypt_nb_6; + else if (ctx->Nb == 4) + ctx->encrypt = aes_encrypt_nb_4, ctx->decrypt = aes_decrypt_nb_4; + + /* + * Now do the key setup itself. + */ + rconst = 1; + for (i = 0; i < (ctx->Nr + 1) * ctx->Nb; i++) { + if (i < Nk) + ctx->keysched[i] = GET_32BIT_MSB_FIRST(key + 4 * i); + else { + word32 temp = ctx->keysched[i - 1]; + if (i % Nk == 0) { + int a, b, c, d; + a = (temp >> 16) & 0xFF; + b = (temp >> 8) & 0xFF; + c = (temp >> 0) & 0xFF; + d = (temp >> 24) & 0xFF; + temp = Sbox[a] ^ rconst; + temp = (temp << 8) | Sbox[b]; + temp = (temp << 8) | Sbox[c]; + temp = (temp << 8) | Sbox[d]; + rconst = mulby2(rconst); + } else if (i % Nk == 4 && Nk > 6) { + int a, b, c, d; + a = (temp >> 24) & 0xFF; + b = (temp >> 16) & 0xFF; + c = (temp >> 8) & 0xFF; + d = (temp >> 0) & 0xFF; + temp = Sbox[a]; + temp = (temp << 8) | Sbox[b]; + temp = (temp << 8) | Sbox[c]; + temp = (temp << 8) | Sbox[d]; + } + ctx->keysched[i] = ctx->keysched[i - Nk] ^ temp; + } + } + + /* + * Now prepare the modified keys for the inverse cipher. + */ + for (i = 0; i <= ctx->Nr; i++) { + for (j = 0; j < ctx->Nb; j++) { + word32 temp; + temp = ctx->keysched[(ctx->Nr - i) * ctx->Nb + j]; + if (i != 0 && i != ctx->Nr) { + /* + * Perform the InvMixColumn operation on i. The D + * tables give the result of InvMixColumn applied + * to Sboxinv on individual bytes, so we should + * compose Sbox with the D tables for this. + */ + int a, b, c, d; + a = (temp >> 24) & 0xFF; + b = (temp >> 16) & 0xFF; + c = (temp >> 8) & 0xFF; + d = (temp >> 0) & 0xFF; + temp = D0[Sbox[a]]; + temp ^= D1[Sbox[b]]; + temp ^= D2[Sbox[c]]; + temp ^= D3[Sbox[d]]; + } + ctx->invkeysched[i * ctx->Nb + j] = temp; + } + } +} + +static void aes_encrypt(AESContext * ctx, word32 * block) +{ + ctx->encrypt(ctx, block); +} + +static void aes_decrypt(AESContext * ctx, word32 * block) +{ + ctx->decrypt(ctx, block); +} + +static void aes_encrypt_cbc(unsigned char *blk, int len, AESContext * ctx) +{ + word32 iv[4]; + int i; + + assert((len & 15) == 0); + + memcpy(iv, ctx->iv, sizeof(iv)); + + while (len > 0) { + for (i = 0; i < 4; i++) + iv[i] ^= GET_32BIT_MSB_FIRST(blk + 4 * i); + aes_encrypt(ctx, iv); + for (i = 0; i < 4; i++) + PUT_32BIT_MSB_FIRST(blk + 4 * i, iv[i]); + blk += 16; + len -= 16; + } + + memcpy(ctx->iv, iv, sizeof(iv)); +} + +static void aes_decrypt_cbc(unsigned char *blk, int len, AESContext * ctx) +{ + word32 iv[4], x[4], ct[4]; + int i; + + assert((len & 15) == 0); + + memcpy(iv, ctx->iv, sizeof(iv)); + + while (len > 0) { + for (i = 0; i < 4; i++) + x[i] = ct[i] = GET_32BIT_MSB_FIRST(blk + 4 * i); + aes_decrypt(ctx, x); + for (i = 0; i < 4; i++) { + PUT_32BIT_MSB_FIRST(blk + 4 * i, iv[i] ^ x[i]); + iv[i] = ct[i]; + } + blk += 16; + len -= 16; + } + + memcpy(ctx->iv, iv, sizeof(iv)); +} + +static void aes_sdctr(unsigned char *blk, int len, AESContext *ctx) +{ + word32 iv[4], b[4], tmp; + int i; + + assert((len & 15) == 0); + + memcpy(iv, ctx->iv, sizeof(iv)); + + while (len > 0) { + memcpy(b, iv, sizeof(b)); + aes_encrypt(ctx, b); + for (i = 0; i < 4; i++) { + tmp = GET_32BIT_MSB_FIRST(blk + 4 * i); + PUT_32BIT_MSB_FIRST(blk + 4 * i, tmp ^ b[i]); + } + for (i = 3; i >= 0; i--) + if ((iv[i] = (iv[i] + 1) & 0xffffffff) != 0) + break; + blk += 16; + len -= 16; + } + + memcpy(ctx->iv, iv, sizeof(iv)); +} + +void *aes_make_context(void) +{ + return (AESContext *)malloc(sizeof(AESContext)); +} + +void aes_free_context(void *handle) +{ + free(handle); +} + +void aes128_key(void *handle, unsigned char *key) +{ + AESContext *ctx = (AESContext *)handle; + aes_setup(ctx, 16, key, 16); +} + +void aes192_key(void *handle, unsigned char *key) +{ + AESContext *ctx = (AESContext *)handle; + aes_setup(ctx, 16, key, 24); +} + +void aes256_key(void *handle, unsigned char *key) +{ + AESContext *ctx = (AESContext *)handle; + aes_setup(ctx, 16, key, 32); +} + +void aes_iv(void *handle, unsigned char *iv) +{ + AESContext *ctx = (AESContext *)handle; + int i; + for (i = 0; i < 4; i++) + ctx->iv[i] = GET_32BIT_MSB_FIRST(iv + 4 * i); +} + +void aes_ssh2_encrypt_blk(void *handle, unsigned char *blk, int len) +{ + AESContext *ctx = (AESContext *)handle; + aes_encrypt_cbc(blk, len, ctx); +} + +void aes_ssh2_decrypt_blk(void *handle, unsigned char *blk, int len) +{ + AESContext *ctx = (AESContext *)handle; + aes_decrypt_cbc(blk, len, ctx); +} + +static void aes_ssh2_sdctr(void *handle, unsigned char *blk, int len) +{ + AESContext *ctx = (AESContext *)handle; + aes_sdctr(blk, len, ctx); +} + +void aes256_encrypt_pubkey(unsigned char *key, unsigned char *blk, int len) +{ + AESContext ctx; + aes_setup(&ctx, 16, key, 32); + memset(ctx.iv, 0, sizeof(ctx.iv)); + aes_encrypt_cbc(blk, len, &ctx); + memset(&ctx, 0, sizeof(ctx)); +} + +void aes256_decrypt_pubkey(unsigned char *key, unsigned char *blk, int len) +{ + AESContext ctx; + aes_setup(&ctx, 16, key, 32); + memset(ctx.iv, 0, sizeof(ctx.iv)); + aes_decrypt_cbc(blk, len, &ctx); + memset(&ctx, 0, sizeof(ctx)); +} + +static const struct ssh2_cipher ssh_aes128_ctr = { + aes_make_context, aes_free_context, aes_iv, aes128_key, + aes_ssh2_sdctr, aes_ssh2_sdctr, + "aes128-ctr", + 16, 128, 0, "AES-128 SDCTR" +}; + +static const struct ssh2_cipher ssh_aes192_ctr = { + aes_make_context, aes_free_context, aes_iv, aes192_key, + aes_ssh2_sdctr, aes_ssh2_sdctr, + "aes192-ctr", + 16, 192, 0, "AES-192 SDCTR" +}; + +static const struct ssh2_cipher ssh_aes256_ctr = { + aes_make_context, aes_free_context, aes_iv, aes256_key, + aes_ssh2_sdctr, aes_ssh2_sdctr, + "aes256-ctr", + 16, 256, 0, "AES-256 SDCTR" +}; + +static const struct ssh2_cipher ssh_aes128 = { + aes_make_context, aes_free_context, aes_iv, aes128_key, + aes_ssh2_encrypt_blk, aes_ssh2_decrypt_blk, + "aes128-cbc", + 16, 128, SSH_CIPHER_IS_CBC, "AES-128 CBC" +}; + +static const struct ssh2_cipher ssh_aes192 = { + aes_make_context, aes_free_context, aes_iv, aes192_key, + aes_ssh2_encrypt_blk, aes_ssh2_decrypt_blk, + "aes192-cbc", + 16, 192, SSH_CIPHER_IS_CBC, "AES-192 CBC" +}; + +static const struct ssh2_cipher ssh_aes256 = { + aes_make_context, aes_free_context, aes_iv, aes256_key, + aes_ssh2_encrypt_blk, aes_ssh2_decrypt_blk, + "aes256-cbc", + 16, 256, SSH_CIPHER_IS_CBC, "AES-256 CBC" +}; + +static const struct ssh2_cipher ssh_rijndael_lysator = { + aes_make_context, aes_free_context, aes_iv, aes256_key, + aes_ssh2_encrypt_blk, aes_ssh2_decrypt_blk, + "rijndael-cbc@lysator.liu.se", + 16, 256, SSH_CIPHER_IS_CBC, "AES-256 CBC" +}; + +static const struct ssh2_cipher *const aes_list[] = { + &ssh_aes256_ctr, + &ssh_aes256, + &ssh_rijndael_lysator, + &ssh_aes192_ctr, + &ssh_aes192, + &ssh_aes128_ctr, + &ssh_aes128, +}; diff --git a/cipher/aes.h b/cipher/aes.h new file mode 100644 index 0000000..eed6b01 --- /dev/null +++ b/cipher/aes.h @@ -0,0 +1,13 @@ +#ifndef _CIPHER_AES_H +#define _CIPHER_AES_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void aes256_encrypt_pubkey(unsigned char *key, unsigned char *blk, int len); +void aes256_decrypt_pubkey(unsigned char *key, unsigned char *blk, int len); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _CIPHER_AES_H */ diff --git a/cipher/digest.c b/cipher/digest.c new file mode 100644 index 0000000..56b12a5 --- /dev/null +++ b/cipher/digest.c @@ -0,0 +1,108 @@ +#include +#include "md5.h" +#include "digest.h" + +void CvtHex( + IN HASH Bin, + OUT HASHHEX Hex + ) +{ + unsigned short i; + unsigned char j; + + for (i = 0; i < HASHLEN; i++) { + j = (Bin[i] >> 4) & 0xf; + if (j <= 9) + Hex[i*2] = (j + '0'); + else + Hex[i*2] = (j + 'a' - 10); + j = Bin[i] & 0xf; + if (j <= 9) + Hex[i*2+1] = (j + '0'); + else + Hex[i*2+1] = (j + 'a' - 10); + }; + Hex[HASHHEXLEN] = '\0'; +}; + +/* calculate H(A1) as per spec */ +void DigestCalcHA1( + IN unsigned char * pszAlg, + IN unsigned char * pszUserName, + IN unsigned char * pszRealm, + IN unsigned char * pszPassword, + IN unsigned char * pszNonce, + IN unsigned char * pszCNonce, + OUT HASHHEX SessionKey + ) +{ + MD5_CTX Md5Ctx; + HASH HA1; + + MD5Init(&Md5Ctx); + MD5Update(&Md5Ctx, pszUserName, strlen(pszUserName)); + MD5Update(&Md5Ctx, ":", 1); + MD5Update(&Md5Ctx, pszRealm, strlen(pszRealm)); + MD5Update(&Md5Ctx, ":", 1); + MD5Update(&Md5Ctx, pszPassword, strlen(pszPassword)); + MD5Final(HA1, &Md5Ctx); + if (memcmp(pszAlg, "md5-sess", 8) == 0) { + MD5Init(&Md5Ctx); + MD5Update(&Md5Ctx, HA1, HASHLEN); + MD5Update(&Md5Ctx, ":", 1); + MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce)); + MD5Update(&Md5Ctx, ":", 1); + MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce)); + MD5Final(HA1, &Md5Ctx); + }; + CvtHex(HA1, SessionKey); +}; + +/* calculate request-digest/response-digest as per HTTP Digest spec */ +void DigestCalcResponse( + IN HASHHEX HA1, /* H(A1) */ + IN unsigned char * pszNonce, /* nonce from server */ + IN unsigned char * pszNonceCount, /* 8 hex digits */ + IN unsigned char * pszCNonce, /* client nonce */ + IN unsigned char * pszQop, /* qop-value: "", "auth", "auth-int" */ + IN unsigned char * pszMethod, /* method from the request */ + IN unsigned char * pszDigestUri, /* requested URL */ + IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */ + OUT HASHHEX Response /* request-digest or response-digest */ + ) +{ + MD5_CTX Md5Ctx; + HASH HA2; + HASH RespHash; + HASHHEX HA2Hex; + + // calculate H(A2) + MD5Init(&Md5Ctx); + MD5Update(&Md5Ctx, pszMethod, strlen(pszMethod)); + MD5Update(&Md5Ctx, ":", 1); + MD5Update(&Md5Ctx, pszDigestUri, strlen(pszDigestUri)); + if (memcmp(pszQop, "auth-int", 8) == 0) { + MD5Update(&Md5Ctx, ":", 1); + MD5Update(&Md5Ctx, HEntity, HASHHEXLEN); + }; + MD5Final(HA2, &Md5Ctx); + CvtHex(HA2, HA2Hex); + + // calculate response + MD5Init(&Md5Ctx); + MD5Update(&Md5Ctx, HA1, HASHHEXLEN); + MD5Update(&Md5Ctx, ":", 1); + MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce)); + MD5Update(&Md5Ctx, ":", 1); + if (*pszQop) { + MD5Update(&Md5Ctx, pszNonceCount, strlen(pszNonceCount)); + MD5Update(&Md5Ctx, ":", 1); + MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce)); + MD5Update(&Md5Ctx, ":", 1); + MD5Update(&Md5Ctx, pszQop, strlen(pszQop)); + MD5Update(&Md5Ctx, ":", 1); + }; + MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN); + MD5Final(RespHash, &Md5Ctx); + CvtHex(RespHash, Response); +}; \ No newline at end of file diff --git a/cipher/digest.h b/cipher/digest.h new file mode 100644 index 0000000..220c9fa --- /dev/null +++ b/cipher/digest.h @@ -0,0 +1,43 @@ +#ifndef _CIPHER_DIGEST_H_ +#define _CIPHER_DIGEST_H_ + +/* from rfc2617 */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define HASHLEN 16 +typedef unsigned char HASH[HASHLEN]; +#define HASHHEXLEN 32 +typedef unsigned char HASHHEX[HASHHEXLEN+1]; +#define IN +#define OUT + +/* calculate H(A1) as per HTTP Digest spec */ +void DigestCalcHA1( + IN unsigned char * pszAlg, + IN unsigned char * pszUserName, + IN unsigned char * pszRealm, + IN unsigned char * pszPassword, + IN unsigned char * pszNonce, + IN unsigned char * pszCNonce, + OUT HASHHEX SessionKey + ); + +/* calculate request-digest/response-digest as per HTTP Digest spec */ +void DigestCalcResponse( + IN HASHHEX HA1, /* H(A1) */ + IN unsigned char * pszNonce, /* nonce from server */ + IN unsigned char * pszNonceCount, /* 8 hex digits */ + IN unsigned char * pszCNonce, /* client nonce */ + IN unsigned char * pszQop, /* qop-value: "", "auth", "auth-int" */ + IN unsigned char * pszMethod, /* method from the request */ + IN unsigned char * pszDigestUri, /* requested URL */ + IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */ + OUT HASHHEX Response /* request-digest or response-digest */ + ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _CIPHER_DIGEST_H_ */ \ No newline at end of file diff --git a/cipher/hmac.c b/cipher/hmac.c new file mode 100644 index 0000000..81e7be5 --- /dev/null +++ b/cipher/hmac.c @@ -0,0 +1,219 @@ +#include +#include "hmac.h" +#include "md5.h" +#include "sha.h" +#include "sha224.h" +#include "sha256.h" +#include "sha384.h" +#include "sha512.h" + +/* +unsigned char* text; pointer to data stream +int text_len; length of data stream +unsigned char* key; pointer to authentication key +int key_len; length of authentication key +unsigned char* digest; caller digest to be filled in +*/ +#define KEY_IOPAD_SIZE 64 +void hmac_md5(unsigned char *key, int key_len, + unsigned char *text, int text_len, unsigned char *hmac) +{ + MD5_CTX context; + unsigned char k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */ + int i; + + /* + * the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + /* start out by storing key in pads */ + memset( k_ipad, 0, sizeof(k_ipad)); + memset( k_opad, 0, sizeof(k_opad)); + memcpy( k_ipad, key, key_len); + memcpy( k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < KEY_IOPAD_SIZE; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + // perform inner MD5 + MD5Init(&context); /* init context for 1st pass */ + MD5Update(&context, k_ipad, KEY_IOPAD_SIZE); /* start with inner pad */ + MD5Update(&context, (unsigned char*)text, text_len); /* then text of datagram */ + MD5Final(hmac, &context); /* finish up 1st pass */ + + // perform outer MD5 + MD5Init(&context); /* init context for 2nd pass */ + MD5Update(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */ + MD5Update(&context, hmac, MD5_DIGEST_SIZE); /* then results of 1st hash */ + MD5Final(hmac, &context); /* finish up 2nd pass */ +} + +void hmac_sha1(unsigned char *key, int key_len, + unsigned char *text, int text_len, unsigned char *hmac) { + SHA_State context; + unsigned char k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */ + int i; + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < KEY_IOPAD_SIZE; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + // perform inner SHA + SHA_Init(&context); /* init context for 1st pass */ + SHA_Bytes(&context, k_ipad, KEY_IOPAD_SIZE); /* start with inner pad */ + SHA_Bytes(&context, text, text_len); /* then text of datagram */ + SHA_Final(&context, hmac); /* finish up 1st pass */ + + // perform outer SHA + SHA_Init(&context); /* init context for 2nd pass */ + SHA_Bytes(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */ + SHA_Bytes(&context, hmac, SHA1_DIGEST_SIZE); /* then results of 1st hash */ + SHA_Final(&context, hmac); /* finish up 2nd pass */ +} + +void hmac_sha224(unsigned char *key, int key_len, + unsigned char *text, int text_len, unsigned char *hmac) { + SHA256_State context; + unsigned char k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */ + int i; + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < KEY_IOPAD_SIZE; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + // perform inner SHA224 + SHA224_Init(&context); /* init context for 1st pass */ + SHA224_Bytes(&context, k_ipad, KEY_IOPAD_SIZE); /* start with inner pad */ + SHA224_Bytes(&context, (unsigned char*)text, text_len); /* then text of datagram */ + SHA224_Final(&context, hmac); /* finish up 1st pass */ + + // perform outer SHA224 + SHA224_Init(&context); /* init context for 2nd pass */ + SHA224_Bytes(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */ + SHA224_Bytes(&context, hmac, SHA224_DIGEST_SIZE); /* then results of 1st hash */ + SHA224_Final(&context, hmac); /* finish up 2nd pass */ +} +void hmac_sha256(unsigned char *key, int key_len, + unsigned char *text, int text_len, unsigned char *hmac) { + SHA256_State context; + unsigned char k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */ + int i; + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < KEY_IOPAD_SIZE; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + // perform inner SHA256 + SHA256_Init(&context); /* init context for 1st pass */ + SHA256_Bytes(&context, k_ipad, KEY_IOPAD_SIZE); /* start with inner pad */ + SHA256_Bytes(&context, text, text_len); /* then text of datagram */ + SHA256_Final(&context, hmac); /* finish up 1st pass */ + + // perform outer SHA256 + SHA256_Init(&context); /* init context for 2nd pass */ + SHA256_Bytes(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */ + SHA256_Bytes(&context, hmac, SHA256_DIGEST_SIZE); /* then results of 1st hash */ + SHA256_Final(&context, hmac); /* finish up 2nd pass */ +} +void hmac_sha384(unsigned char *key, int key_len, + unsigned char *text, int text_len, unsigned char *hmac) { + SHA512_State context; + unsigned char k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */ + int i; + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < KEY_IOPAD_SIZE; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + // perform inner SHA384 + SHA384_Init(&context); /* init context for 1st pass */ + SHA384_Bytes(&context, k_ipad, KEY_IOPAD_SIZE); /* start with inner pad */ + SHA384_Bytes(&context, text, text_len); /* then text of datagram */ + SHA384_Final(&context, hmac); /* finish up 1st pass */ + + // perform outer SHA384 + SHA384_Init(&context); /* init context for 2nd pass */ + SHA384_Bytes(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */ + SHA384_Bytes(&context, hmac, SHA384_DIGEST_SIZE); /* then results of 1st hash */ + SHA384_Final(&context, hmac); /* finish up 2nd pass */ +} +void hmac_sha512(unsigned char *key, int key_len, + unsigned char *text, int text_len, unsigned char *hmac) { + SHA512_State context; + unsigned char k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */ + int i; + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < KEY_IOPAD_SIZE; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + // perform inner SHA512 + SHA512_Init(&context); /* init context for 1st pass */ + SHA512_Bytes(&context, k_ipad, KEY_IOPAD_SIZE); /* start with inner pad */ + SHA512_Bytes(&context, text, text_len); /* then text of datagram */ + SHA512_Final(&context, hmac); /* fnish up 1st pass */ + + // perform outer SHA512 + SHA512_Init(&context); /* init context for 2nd pass */ + SHA512_Bytes(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */ + SHA512_Bytes(&context, hmac, SHA512_DIGEST_SIZE); /* then results of 1st hash */ + SHA512_Final(&context, hmac); /* finish up 2nd pass */ +} + diff --git a/cipher/hmac.h b/cipher/hmac.h new file mode 100644 index 0000000..46a821e --- /dev/null +++ b/cipher/hmac.h @@ -0,0 +1,29 @@ +#ifndef _CIPHER_HMAC_ALL_H +#define _CIPHER_HMAC_ALL_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define SHA1_DIGEST_SIZE 20 +#define SHA224_DIGEST_SIZE 28 +#define SHA256_DIGEST_SIZE 32 +#define SHA384_DIGEST_SIZE 48 +#define SHA512_DIGEST_SIZE 64 +#define MD5_DIGEST_SIZE 16 + void hmac_md5(unsigned char *key, int key_len, + unsigned char *text, int text_len, unsigned char *hmac); + void hmac_sha1(unsigned char *key, int key_len, + unsigned char *text, int text_len, unsigned char *hmac); + void hmac_sha224(unsigned char *key, int key_len, + unsigned char *text, int text_len, unsigned char *hmac); + void hmac_sha256(unsigned char *key, int key_len, + unsigned char *text, int text_len, unsigned char *hmac); + void hmac_sha384(unsigned char *key, int key_len, + unsigned char *text, int text_len, unsigned char *hmac); + void hmac_sha512(unsigned char *key, int key_len, + unsigned char *text, int text_len, unsigned char *hmac); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _CIPHER_HMAC_ALL_H */ diff --git a/cipher/md5.c b/cipher/md5.c new file mode 100644 index 0000000..b62a7f2 --- /dev/null +++ b/cipher/md5.c @@ -0,0 +1,373 @@ +/* taken from RFC-1321/Appendix A.3 */ + +/* +* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm +*/ + +/* +* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights +* reserved. +* +* License to copy and use this software is granted provided that it is +* identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" +* in all material mentioning or referencing this software or this function. +* +* License is also granted to make and use derivative works provided that such +* works are identified as "derived from the RSA Data Security, Inc. MD5 +* Message-Digest Algorithm" in all material mentioning or referencing the +* derived work. +* +* RSA Data Security, Inc. makes no representations concerning either the +* merchantability of this software or the suitability of this software for +* any particular purpose. It is provided "as is" without express or implied +* warranty of any kind. +* +* These notices must be retained in any copies of any part of this +* documentation and/or software. +*/ + +#include "md5.h" +/* +* Constants for MD5Transform routine. +*/ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform PROTO_LIST((UINT4[4], unsigned char[64])); +static void Encode PROTO_LIST +((unsigned char *, UINT4 *, unsigned int)); +static void Decode PROTO_LIST +((UINT4 *, unsigned char *, unsigned int)); +static void MD5_memcpy PROTO_LIST((POINTER, POINTER, unsigned int)); +static void MD5_memset PROTO_LIST((POINTER, int, unsigned int)); + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* +* F, G, H and I are basic MD5 functions. +*/ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* +* ROTATE_LEFT rotates x left n bits. +*/ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* +* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is +* separate from addition to prevent recomputation. +*/ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* +* MD5 initialization. Begins an MD5 operation, writing a new context. +*/ +void +MD5Init(//context) + MD5_CTX *context)/* context */ +{ + context->count[0] = context->count[1] = 0; + /* + * Load magic initialization constants. + */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* +* MD5 block update operation. Continues an MD5 message-digest operation, +* processing another message block, and updating the context. +*/ +void +MD5Update(//context, input, inputLen) + MD5_CTX *context,/* context */ + unsigned char *input, /* input block */ + unsigned int inputLen) /* length of input block */ +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int) ((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4) inputLen << 3)) + < ((UINT4) inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4) inputLen >> 29); + + partLen = 64 - index; + + /* + * Transform as many times as possible. + */ + if (inputLen >= partLen) { + MD5_memcpy + ((POINTER) & context->buffer[index], (POINTER) input, partLen); + MD5Transform(context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform(context->state, &input[i]); + + index = 0; + } else + i = 0; + + /* Buffer remaining input */ + MD5_memcpy + ((POINTER) & context->buffer[index], (POINTER) & input[i], + inputLen - i); +} + +/* +* MD5 finalization. Ends an MD5 message-digest operation, writing the the +* message digest and zeroizing the context. +*/ +void +MD5Final(//digest, context) + unsigned char digest[16], /* message digest */ + MD5_CTX *context)/* context */ +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode(bits, context->count, 8); + + /* + * Pad out to 56 mod 64. + */ + index = (unsigned int) ((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update(context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update(context, bits, 8); + /* Store state in digest */ + Encode(digest, context->state, 16); + + /* + * Zeroize sensitive information. + */ + MD5_memset((POINTER) context, 0, sizeof(*context)); +} + +/* +* MD5 basic transformation. Transforms state based on block. +*/ +static void +MD5Transform(//state, block) + UINT4 state[4], + unsigned char block[64]) +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], + x[16]; + + Decode(x, block, 64); + + /* Round 1 */ + FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ + FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ + FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ + FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ + FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ + FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ + FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ + FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ + FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ + FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ + FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ + GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ + GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ + GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ + GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ + GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ + GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ + GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ + GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ + GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ + GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ + HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ + HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ + HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ + HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ + HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ + HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ + HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ + HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ + HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ + II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ + II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ + II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ + II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ + II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ + II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ + II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ + II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ + II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* + * Zeroize sensitive information. + */ + MD5_memset((POINTER) x, 0, sizeof(x)); +} + +/* +* Encodes input (UINT4) into output (unsigned char). Assumes len is a +* multiple of 4. +*/ +static void +Encode(//output, input, len) + unsigned char *output, + UINT4 *input, + unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char) (input[i] & 0xff); + output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff); + output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff); + output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff); + } +} + +/* +* Decodes input (unsigned char) into output (UINT4). Assumes len is a +* multiple of 4. +*/ +static void +Decode(//output, input, len) + UINT4 *output, + unsigned char *input, + unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) | + (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24); +} + +/* +* Note: Replace "for loop" with standard memcpy if possible. +*/ + +static void +MD5_memcpy(//output, input, len) + POINTER output, + POINTER input, + unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) + output[i] = input[i]; +} + +/* +* Note: Replace "for loop" with standard memset if possible. +*/ +static void +MD5_memset(//output, value, len) + POINTER output, + int value, + unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) + ((char *) output)[i] = (char) value; +} + +void MD5Calc(const unsigned char *input, unsigned int inlen, unsigned char *output) +{ + MD5_CTX context; + MD5Init(&context); + // Md5 Key + static char initStr[32+1] = + {0x21, 0x45, 0x34, 0x12, 0x20, 0x85, 0x21, 0x89, + 0x10, 0x20, 0x34, 0x23, 0x34, 0xa1, 0x1f, 0x13, + 0x1d, 0x2d, 0x4c, 0x33, 0x39, 0xb2, 0x2c, 0x34, + 0xd4, 0xb4, 0x4f, 0xff, 0x9b, 0x45, 0x3a, 0xf5, 0x00}; + //MD5Update(&context, (unsigned char *)initStr, 32); + MD5Update(&context, (unsigned char *)input, inlen); + MD5Final(output, &context); +} \ No newline at end of file diff --git a/cipher/md5.h b/cipher/md5.h new file mode 100644 index 0000000..407219c --- /dev/null +++ b/cipher/md5.h @@ -0,0 +1,83 @@ +/* taken from RFC-1321/Appendices A.1/A.2 */ + +/* PROTOTYPES should be set to one if and only if the compiler supports +function argument prototyping. +The following makes PROTOTYPES default to 0 if it has not already +been defined with C compiler flags. +*/ +#ifndef _SYS_MD5_H_ +#define _SYS_MD5_H_ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + typedef unsigned int UINT4; + typedef unsigned char UCHAR; + +#ifndef PROTOTYPES +#define PROTOTYPES 1 /* jeikul modified this from 0 to 1 */ +#endif + + /* POINTER defines a generic pointer type */ + typedef unsigned char *POINTER; + + /* UINT2 defines a two byte word */ + typedef unsigned short int UINT2; + + /* UINT4 defines a four byte word */ + /* typedef unsigned long int UINT4; */ + + /* PROTO_LIST is defined depending on how PROTOTYPES is defined above. + If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it + returns an empty list. + */ +#if PROTOTYPES +#define PROTO_LIST(list) list +#else +#define PROTO_LIST(list) () +#endif + + /* MD5.H - header file for MD5C.C + */ + + /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + */ + + /* MD5 context. */ + typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ + } MD5_CTX; + + void MD5Init PROTO_LIST ((MD5_CTX *)); + void MD5Update PROTO_LIST + ((MD5_CTX *, unsigned char *, unsigned int)); + void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); + // The function to calculate the message digest string + // of a given string based on the MD5 algrithm. + void MD5Calc(const unsigned char *input, unsigned int inlen, unsigned char *output); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _SYS_MD5_H_ */ diff --git a/cipher/md5key.cpp b/cipher/md5key.cpp new file mode 100644 index 0000000..b48ece2 --- /dev/null +++ b/cipher/md5key.cpp @@ -0,0 +1,472 @@ +#define _MD5KEY_CPP + +#ifndef _REENTRANT +#define _REENTRANT /* basic 3-lines for threads */ +#endif + +#include +#include +#include +#include +#include + +#ifdef LINUX +#include +#endif + +#include "md5.h" +#include "md5key.h" + +int CalcPasswordLen(int inlen) +{ + return ((inlen+15)/16)*16; +} + +int MakePassword(char *output, char *input, int inlen, unsigned char *key, unsigned char *vector) +{ + unsigned int keylen = strlen((char *) key); + unsigned char buf[128]; + if (keylen > sizeof(buf)-16) + keylen = sizeof(buf)-16; + + memset(buf, 0, sizeof(buf)); + strncpy((char *) buf, (char *) key, sizeof(buf)-16); + memcpy(buf+keylen, vector, 16); + + int outlen = ((inlen+15)/16)*16; + memset(output, 0, outlen); + + outlen = 0; + int i=0; + unsigned char b[17], p[17]; + unsigned char *c; + while (inlen > 0) { + MD5Calc(buf, keylen + 16, b); + memset(p, 0, sizeof(p)); + int len = (inlen<16) ? inlen : 16; + inlen -= len; + memcpy(p, input+i, len); //input segment of 16 chars + c = (unsigned char *) (output+i); //output buffer + + for (int j=0; j<16; j++) + buf[keylen+j] = c[j] = p[j] ^ b[j]; + + outlen += 16; + i += len; + } + + return outlen; +} + +/************************************************** +Function: + unlock the password by MD5 key +***************************************************/ +int GetPassword(char *output, char *input, int inlen, unsigned char *key, unsigned char *vector) +{ + unsigned int keylen = strlen((char *) key); + unsigned char buf[128]; + if (keylen > sizeof(buf)-16) + keylen = sizeof(buf)-16; + + memset(buf, 0, sizeof(buf)); + strncpy((char *) buf, (char *) key, sizeof(buf)-16); + memcpy(buf+keylen, vector, 16); + + int outlen = ((inlen+15)/16)*16; + memset(output, 0, outlen); + + int i=0; + unsigned char b[17], c[17]; + unsigned char *p; + outlen = 0; + while (inlen>0) { + MD5Calc(buf, keylen + 16, b); + memset(c, 0, sizeof(c)); + int len = (inlen < 16) ? inlen : 16; + inlen -= len; + memcpy(c, input+i, len); //input segment of 16 chars + + p = (unsigned char *) (output+i); //output buffer + for (int j=0; j<16; j++) { + p[j] = c[j] ^ b[j]; + buf[keylen+j] = c[j]; + } + + outlen += 16; + i += len; + } + + return outlen; +} + +time_t GetExpireSec(char *expire) +{ + int year; + int month; + int day; + + if (sscanf(expire, "%d/%d/%d", &year, &month, &day) != 3) { + return -1; + } + + struct tm time_str; + time_str.tm_year = year - 1900; + time_str.tm_mon = month - 1; + time_str.tm_mday = day; + time_str.tm_hour = 0; + time_str.tm_min = 0; + time_str.tm_sec = 1; + time_str.tm_isdst = -1; + + time_t expiresec = mktime(&time_str); + return expiresec; +} + +unsigned long GetExpireDays(char *expire) +{ + int year; + int month; + int day; + + if (sscanf(expire, "%d/%d/%d", &year, &month, &day) != 3) { + //printf("error format of expire %s\n", expire); + return 0; + } + + //printf("year=%04d, month=%02d, day=%02d\n", year, month, day); + time_t nowsec; + time(&nowsec); + + struct tm time_str; + localtime_r(&nowsec, &time_str); + time_str.tm_hour = 0; + time_str.tm_min = 0; + time_str.tm_sec = 1; + time_str.tm_isdst = -1; + + nowsec = mktime(&time_str); + time_str.tm_year = year - 1900; + time_str.tm_mon = month - 1; + time_str.tm_mday = day; + time_str.tm_hour = 0; + time_str.tm_min = 0; + time_str.tm_sec = 1; + time_str.tm_isdst = -1; + + time_t expiresec = mktime(&time_str); + return ((expiresec >= nowsec) ? expiresec - nowsec : 0) / (60*60*24); +} + +long ToUINT4(int c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + return -1; +} + +int GenLicenseKey(char *buf, + char *product, + char *version, + char *client, + unsigned long users, + char *expire, + char *hostid ) +{ + if (buf == NULL || product == NULL || version == NULL || client == NULL || expire == NULL || hostid == NULL) + return -1; + + struct timespec t; + clock_gettime(CLOCK_REALTIME, &t); + unsigned int rs = t.tv_nsec; + + time_t nowsec = t.tv_sec; + + struct tm now_str; + localtime_r(&nowsec, &now_str); + now_str.tm_hour = 0; + now_str.tm_min = 0; + now_str.tm_sec = 1; + now_str.tm_isdst= -1; + + nowsec = mktime(&now_str); + + unsigned char vector[17]; + memset(vector, 0, sizeof(vector)); + + int i; + for (i = 0; i< 16; i++) + vector[i] = (unsigned char) rand_r(&rs); + + if (strlen(hostid) != 8) + return -1; + + long id = 0; + for (i=0; i<8; i++) { + id = id*16 + ToUINT4((unsigned char) hostid[i]); + } + + unsigned char key[10]; + sprintf((char *) key, "%08lx", id); + + char sbuf[1024]; + memset(sbuf, 0, sizeof(sbuf)); + + int len = 0; + memcpy(sbuf+len, vector, 16); + len += 16; + + int l = strlen(product); + sbuf[len] = l; + memcpy(sbuf+len+1, product, l); + len += l+1; + + l = strlen(version); + sbuf[len] = l; + memcpy(sbuf+len+1, version, l); + len += l+1; + + l = strlen(client); + sbuf[len] = l; + memcpy(sbuf+len+1, client, l); + len += l+1; + + unsigned long v = users; + unsigned char v1 = (v >> 24) & 0xff; + unsigned char v2 = (v >> 16) & 0xff; + unsigned char v3 = (v >> 8) & 0xff; + unsigned char v4 = v & 0xff; + + sbuf[len] = v1; + sbuf[len+1] = v2; + sbuf[len+2] = v3; + sbuf[len+3] = v4; + len += 4; + + long expireSec; + if (strcasecmp(expire, "Never") != 0) { + expireSec = GetExpireSec(expire); + } + else { + expireSec = -1; + } + + v = expireSec; + v1 = (v >> 24) & 0xff; + v2 = (v >> 16) & 0xff; + v3 = (v >> 8) & 0xff; + v4 = v & 0xff; + + sbuf[len] = v1; + sbuf[len+1] = v2; + sbuf[len+2] = v3; + sbuf[len+3] = v4; + len += 4; + + v = id; + v1 = (v >> 24) & 0xff; + v2 = (v >> 16) & 0xff; + v3 = (v >> 8) & 0xff; + v4 = v & 0xff; + + sbuf[len] = v1; + sbuf[len+1] = v2; + sbuf[len+2] = v3; + sbuf[len+3] = v4; + len += 4; + + v = id; + v1 = (v >> 24) & 0xff; + v2 = (v >> 16) & 0xff; + v3 = (v >> 8) & 0xff; + v4 = v & 0xff; + + buf[0] = v1; + buf[1] = v2; + buf[2] = v3; + buf[3] = v4; + + memcpy(buf+4, vector, 16); + return MakePassword(buf+20, sbuf, len, key, vector) + 20; +} + +LicenseKeyRet CheckLicenseKey(char *key, int keylen, + char *product, + char *version, + char *client, + char *hostid, + unsigned long *users, + long *expire) +{ + if (keylen < 20) { + printf("CheckLicenseKey() keylen=%d, < 20\n", keylen); + return kLicenseKeyError; + } + + if (((keylen-20)%16) != 0) { + printf("CheckLicenseKey() keylen=%d error\n", keylen); + return kLicenseKeyError; + } + + int i; + long _id=0; + for (i=0; i<4; i++) + _id = _id*256 + (unsigned char) key[i]; + + char _hostid[9]; + sprintf(_hostid, "%08lx", _id); + + bool hostidOK=false; + if (strcmp(_hostid, hostid) == 0) { + hostidOK = true; + } + else { + printf("_hostid=%s, hostid=%s\n", _hostid, hostid); + hostidOK = false; + } + + unsigned char md5key[64]; + memset(md5key, 0, sizeof(md5key)); + memcpy(md5key, _hostid, 8); + + unsigned char vector[17]; + memset(vector, 0, sizeof(vector)); + memcpy(vector, key+4, 16); + + char sbuf[1024]; + memset(sbuf, 0, sizeof(sbuf)); + GetPassword(sbuf, key+20, keylen-20, md5key, vector); + + if (memcmp(vector, sbuf, 16) != 0) { + if (hostidOK) { + printf("CheckLicenseKey() vector error\n"); + return kLicenseKeyError; + } + else + return kLicenseHostIDError; + } + + int len = 16; + int l = (unsigned char) sbuf[len++]; + + char _product[64]; + memset(_product, 0, sizeof(_product)); + memcpy(_product, sbuf+len, l); + len += l; + + l = (unsigned char) sbuf[len++]; + + char _version[10]; + memset(_version, 0, sizeof(_version)); + memcpy(_version, sbuf+len, l); + len += l; + + l = (unsigned char) sbuf[len++]; + + char _client[256]; + memset(_client, 0, sizeof(_client)); + memcpy(_client, sbuf+len, l); + len += l; + + unsigned long _users = 0; + for (i=0; i<4; i++) + _users = _users*256 + (unsigned char) sbuf[len++]; + + unsigned long _expireSec = 0; + for (i=0; i<4; i++) + _expireSec = _expireSec*256 + (unsigned char) sbuf[len++]; + + long _id1=0; + for (i=0; i<4; i++) + _id1 = _id1*256 + (unsigned char) sbuf[len++]; + + //printf("keylen=%d, len=%d\n", keylen, len); + //struct tm expire_str; + //localtime_r((time_t *)&_expireSec, &expire_str); + + *users = _users; + *expire = _expireSec; + + if (_id != _id1) { + printf("_id=%08x, _id1=%08x\n", _id, _id1); + hostidOK = false; + } + + if (strcmp(_product, product) != 0) + return kLicenseNotThisProduct; + + if (strcmp(_version, version) != 0) + return kLicenseVersionError; + + if (strcmp(_client, client) != 0) + return kLicenseClientError; + + time_t nowsec; + time(&nowsec); + + if ((unsigned long) nowsec >= (unsigned long) _expireSec) { + printf("now=%d, expire=%u\n", nowsec, _expireSec); + return kLicenseExpireDayTimeout; + } + + if (hostidOK == false) { + printf("_id=%08x, _id1=%08x, hostid=%s\n", _id, _id1, hostid); + return kLicenseHostIDError; + } + + return kLicenseOK; +} + +#ifdef LINUX +/*Simulate the POSIX.4 time function in Linux,but the precision is microsecond*/ +int clock_gettime (int clock_id, struct timespec *ts) +{ + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + TIMEVAL_TO_TIMESPEC(&tv, ts); + return 0; +} +#endif + +/* +void main(int argc, char *argv[]) +{ + int i, outlen; + char *key = "88----89"; + char vector[16] = {0x34, 0x5b, 0x0a, 0x9f, 0x1d, 0xfa, 0x27, 0xec, 0x48, 0x35, 0x17, 0xb5, 0x36, 0xd2, 0x6e, 0x4a}; + char secret[16] = {0xb7, 0x52, 0x90, 0x5b, 0xbf, 0xb7, 0x97, 0x6f, 0x19, 0xda, 0xf6, 0xac, 0x1e, 0x9e, 0x9d, 0xe7}; + char output[200], recalc[200]; + + if (argc != 2) + return -1; + + printf("key=%s\n", key); + printf("input=%s\n", argv[1]); + + outlen = MakePassword(output, argv[1], strlen(argv[1]), key, vector); + + printf("Secret string: "); + for (i=0; i +#include +#include +#include "pbkdf2_hmac.h" +#include "sha.h" +#define KEY_IOPAD_SIZE 64 +#define PUT_32BIT_MSB_FIRST(cp, value) ( \ + (cp)[0] = (unsigned char)((value) >> 24), \ + (cp)[1] = (unsigned char)((value) >> 16), \ + (cp)[2] = (unsigned char)((value) >> 8), \ + (cp)[3] = (unsigned char)(value)) + +typedef struct { + SHA_State ctx; + + unsigned char ipad[KEY_IOPAD_SIZE]; /*!< HMAC: inner padding */ + unsigned char opad[KEY_IOPAD_SIZE]; /*!< HMAC: outer padding */ +} sha1_context; + +void sha1_hmac_starts(sha1_context * ctx, const unsigned char *key, int keylen) +{ + int i; + unsigned char sum[20]; + + if (keylen > 64) { + SHA_Simple(key, keylen, sum); + keylen = 20; + key = sum; + } + + memset(ctx->ipad, 0x36, KEY_IOPAD_SIZE); + memset(ctx->opad, 0x5C, KEY_IOPAD_SIZE); + + for (i = 0; i < keylen; i++) { + ctx->ipad[i] = (unsigned char)(ctx->ipad[i] ^ key[i]); + ctx->opad[i] = (unsigned char)(ctx->opad[i] ^ key[i]); + } + + SHA_Init(&ctx->ctx); + SHA_Bytes(&ctx->ctx, ctx->ipad, KEY_IOPAD_SIZE); + +} + +/* +* SHA-1 HMAC process buffer +*/ +void sha1_hmac_update(sha1_context * ctx, const unsigned char *input, int ilen) +{ + SHA_Bytes(&ctx->ctx, input, ilen); +} + +/* +* SHA-1 HMAC final digest +*/ +void sha1_hmac_finish(sha1_context * ctx, unsigned char output[20]) +{ + unsigned char tmpbuf[20]; + + SHA_Final(&ctx->ctx, tmpbuf); + SHA_Init(&ctx->ctx); + SHA_Bytes(&ctx->ctx, ctx->opad, 64); + SHA_Bytes(&ctx->ctx, tmpbuf, 20); + SHA_Final(&ctx->ctx, output); + +} +#ifndef min +#define min( a, b ) ( ((a) < (b)) ? (a) : (b) ) +#endif + +void PKCS5_PBKDF2_HMAC(const unsigned char *password, size_t plen, + const unsigned char *salt, size_t slen, + const unsigned long iteration_count, const unsigned long key_length, + unsigned char *output) +{ + sha1_context ctx; + SHA_Init(&ctx.ctx); + + // Size of the generated digest + unsigned char md_size = 20; + unsigned char md1[20]; + unsigned char work[20]; + + unsigned long counter = 1; + unsigned long generated_key_length = 0; + while (generated_key_length < key_length) { + // U1 ends up in md1 and work + unsigned char c[4]; + PUT_32BIT_MSB_FIRST(c, counter); + sha1_hmac_starts(&ctx, password, plen); + sha1_hmac_update(&ctx, salt, slen); + sha1_hmac_update(&ctx, c, 4); + sha1_hmac_finish(&ctx, md1); + memcpy(work, md1, md_size); + + unsigned long ic = 1; + for (ic = 1; ic < iteration_count; ic++) { + // U2 ends up in md1 + sha1_hmac_starts(&ctx, password, plen); + sha1_hmac_update(&ctx, md1, md_size); + sha1_hmac_finish(&ctx, md1); + // U1 xor U2 + unsigned long i = 0; + for (i = 0; i < md_size; i++) { + work[i] ^= md1[i]; + } + // and so on until iteration_count + } + + // Copy the generated bytes to the key + unsigned long bytes_to_write = + min((key_length - generated_key_length), md_size); + memcpy(output + generated_key_length, work, bytes_to_write); + generated_key_length += bytes_to_write; + ++counter; + } +} + +#include "sha256.h" + +// for SHA256 HMAC +typedef struct { + SHA256_State ctx; + + unsigned char ipad[KEY_IOPAD_SIZE]; /*!< HMAC: inner padding */ + unsigned char opad[KEY_IOPAD_SIZE]; /*!< HMAC: outer padding */ +} sha2_context; +#define SHA256_DIGEST_SIZE 32 +void sha2_hmac_starts(sha2_context * ctx, const unsigned char *key, int keylen) +{ + int i; + unsigned char sum[SHA256_DIGEST_SIZE]; + + if (keylen > 64) { + SHA256_Simple(key, keylen, sum); + keylen = SHA256_DIGEST_SIZE; + key = sum; + } + + memset(ctx->ipad, 0x36, KEY_IOPAD_SIZE); + memset(ctx->opad, 0x5C, KEY_IOPAD_SIZE); + + for (i = 0; i < keylen; i++) { + ctx->ipad[i] = (unsigned char)(ctx->ipad[i] ^ key[i]); + ctx->opad[i] = (unsigned char)(ctx->opad[i] ^ key[i]); + } + + SHA256_Init(&ctx->ctx); + SHA256_Bytes(&ctx->ctx, ctx->ipad, KEY_IOPAD_SIZE); + +} + +/* +* SHA-2 HMAC process buffer +*/ +void sha2_hmac_update(sha2_context * ctx, const unsigned char *input, int ilen) +{ + SHA256_Bytes(&ctx->ctx, input, ilen); +} + +/* +* SHA-2 HMAC final digest +*/ +void sha2_hmac_finish(sha2_context * ctx, unsigned char output[20]) +{ + unsigned char tmpbuf[SHA256_DIGEST_SIZE]; + + SHA256_Final(&ctx->ctx, tmpbuf); + SHA256_Init(&ctx->ctx); + SHA256_Bytes(&ctx->ctx, ctx->opad, 64); + SHA256_Bytes(&ctx->ctx, tmpbuf, SHA256_DIGEST_SIZE); + SHA256_Final(&ctx->ctx, output); + +} + +void PKCS5_PBKDF2_HMAC2(const unsigned char *password, size_t plen, + const unsigned char *salt, size_t slen, + const unsigned long iteration_count, const unsigned long key_length, + unsigned char *output) +{ + sha2_context ctx; + SHA256_Init(&ctx.ctx); + + // Size of the generated digest + unsigned char md_size = SHA256_DIGEST_SIZE; + unsigned char md1[SHA256_DIGEST_SIZE]; + unsigned char work[SHA256_DIGEST_SIZE]; + + unsigned long counter = 1; + unsigned long generated_key_length = 0; + while (generated_key_length < key_length) { + // U1 ends up in md1 and work + unsigned char c[4]; + PUT_32BIT_MSB_FIRST(c, counter); + sha2_hmac_starts(&ctx, password, plen); + sha2_hmac_update(&ctx, salt, slen); + sha2_hmac_update(&ctx, c, 4); + sha2_hmac_finish(&ctx, md1); + memcpy(work, md1, md_size); + + unsigned long ic = 1; + for (ic = 1; ic < iteration_count; ic++) { + // U2 ends up in md1 + sha2_hmac_starts(&ctx, password, plen); + sha2_hmac_update(&ctx, md1, md_size); + sha2_hmac_finish(&ctx, md1); + // U1 xor U2 + unsigned long i = 0; + for (i = 0; i < md_size; i++) { + work[i] ^= md1[i]; + } + // and so on until iteration_count + } + + // Copy the generated bytes to the key + unsigned long bytes_to_write = + min((key_length - generated_key_length), md_size); + memcpy(output + generated_key_length, work, bytes_to_write); + generated_key_length += bytes_to_write; + ++counter; + } +} + +#include "sha512.h" +// for SHA512 HMAC +typedef struct { + SHA512_State ctx; + + unsigned char ipad[KEY_IOPAD_SIZE]; /*!< HMAC: inner padding */ + unsigned char opad[KEY_IOPAD_SIZE]; /*!< HMAC: outer padding */ +} sha5_context; +#define SHA512_DIGEST_SIZE 64 +void sha5_hmac_starts(sha5_context * ctx, const unsigned char *key, int keylen) +{ + int i; + unsigned char sum[SHA512_DIGEST_SIZE]; + + if (keylen > 64) { + SHA512_Simple(key, keylen, sum); + keylen = SHA512_DIGEST_SIZE; + key = sum; + } + + memset(ctx->ipad, 0x36, KEY_IOPAD_SIZE); + memset(ctx->opad, 0x5C, KEY_IOPAD_SIZE); + + for (i = 0; i < keylen; i++) { + ctx->ipad[i] = (unsigned char)(ctx->ipad[i] ^ key[i]); + ctx->opad[i] = (unsigned char)(ctx->opad[i] ^ key[i]); + } + + SHA512_Init(&ctx->ctx); + SHA512_Bytes(&ctx->ctx, ctx->ipad, KEY_IOPAD_SIZE); + +} + +/* +* SHA-2 HMAC process buffer +*/ +void sha5_hmac_update(sha5_context * ctx, const unsigned char *input, int ilen) +{ + SHA512_Bytes(&ctx->ctx, input, ilen); +} + +/* +* SHA-2 HMAC final digest +*/ +void sha5_hmac_finish(sha5_context * ctx, unsigned char output[20]) +{ + unsigned char tmpbuf[SHA512_DIGEST_SIZE]; + + SHA512_Final(&ctx->ctx, tmpbuf); + SHA512_Init(&ctx->ctx); + SHA512_Bytes(&ctx->ctx, ctx->opad, 64); + SHA512_Bytes(&ctx->ctx, tmpbuf, SHA512_DIGEST_SIZE); + SHA512_Final(&ctx->ctx, output); + +} + +void PKCS5_PBKDF2_HMAC5(const unsigned char *password, size_t plen, + const unsigned char *salt, size_t slen, + const unsigned long iteration_count, const unsigned long key_length, + unsigned char *output) +{ + sha5_context ctx; + SHA512_Init(&ctx.ctx); + + // Size of the generated digest + unsigned char md_size = SHA512_DIGEST_SIZE; + unsigned char md1[SHA512_DIGEST_SIZE]; + unsigned char work[SHA512_DIGEST_SIZE]; + + unsigned long counter = 1; + unsigned long generated_key_length = 0; + while (generated_key_length < key_length) { + // U1 ends up in md1 and work + unsigned char c[4]; + PUT_32BIT_MSB_FIRST(c, counter); + sha5_hmac_starts(&ctx, password, plen); + sha5_hmac_update(&ctx, salt, slen); + sha5_hmac_update(&ctx, c, 4); + sha5_hmac_finish(&ctx, md1); + memcpy(work, md1, md_size); + + unsigned long ic = 1; + for (ic = 1; ic < iteration_count; ic++) { + // U2 ends up in md1 + sha5_hmac_starts(&ctx, password, plen); + sha5_hmac_update(&ctx, md1, md_size); + sha5_hmac_finish(&ctx, md1); + // U1 xor U2 + unsigned long i = 0; + for (i = 0; i < md_size; i++) { + work[i] ^= md1[i]; + } + // and so on until iteration_count + } + + // Copy the generated bytes to the key + unsigned long bytes_to_write = + min((key_length - generated_key_length), md_size); + memcpy(output + generated_key_length, work, bytes_to_write); + generated_key_length += bytes_to_write; + ++counter; + } +} \ No newline at end of file diff --git a/cipher/pbkdf2_hmac.h b/cipher/pbkdf2_hmac.h new file mode 100644 index 0000000..8c5a769 --- /dev/null +++ b/cipher/pbkdf2_hmac.h @@ -0,0 +1,21 @@ +#ifndef _CIPHER_PKCS5_PBKDF2_HMAC_H +#define _CIPHER_PKCS5_PBKDF2_HMAC_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + void PKCS5_PBKDF2_HMAC(const unsigned char *password, size_t plen, + const unsigned char *salt, size_t slen, + const unsigned long iteration_count, const unsigned long key_length, + unsigned char *output); + void PKCS5_PBKDF2_HMAC2(const unsigned char *password, size_t plen, + const unsigned char *salt, size_t slen, + const unsigned long iteration_count, const unsigned long key_length, + unsigned char *output); + void PKCS5_PBKDF2_HMAC5(const unsigned char *password, size_t plen, + const unsigned char *salt, size_t slen, + const unsigned long iteration_count, const unsigned long key_length, + unsigned char *output); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif // _CIPHER_PKCS5_PBKDF2_HMAC_H \ No newline at end of file diff --git a/cipher/rc4.c b/cipher/rc4.c new file mode 100644 index 0000000..f9c6ccb --- /dev/null +++ b/cipher/rc4.c @@ -0,0 +1,42 @@ +#include "rc4.h" + +#define RC4_SIZE 256 +void rc4_setup(unsigned char *s, + unsigned char *key, unsigned int Len) { + int i = 0, j = 0; + char k[RC4_SIZE] = { 0 }; + unsigned char tmp = 0; + for (i = 0; i < RC4_SIZE; i++) { + s[i] = i; + k[i] = key[i%Len]; + } + for (i = 0; i < RC4_SIZE; i++) { + j = (j + s[i] + k[i]) % RC4_SIZE; + tmp = s[i]; + s[i] = s[j]; + s[j] = tmp; + } +} + +void rc4_crypt(unsigned char *s, + unsigned char *data, unsigned int Len) { + int i = 0, j = 0, t = 0; + unsigned int k = 0; + unsigned char tmp; + for (k = 0; k < Len; k++) { + i = (i + 1) % RC4_SIZE; + j = (j + s[i]) % RC4_SIZE; + tmp = s[i]; + s[i] = s[j]; + s[j] = tmp; + t = (s[i] + s[j]) % RC4_SIZE; + data[k] ^= s[t]; + } +} + +void RC4_Sample(unsigned char *key, int key_len, + unsigned char *data, int data_len) { + char sbox[RC4_SIZE] = { 0 }; + rc4_setup(sbox, key, key_len); + rc4_crypt(sbox, data, data_len); +} \ No newline at end of file diff --git a/cipher/rc4.h b/cipher/rc4.h new file mode 100644 index 0000000..d3224d2 --- /dev/null +++ b/cipher/rc4.h @@ -0,0 +1,11 @@ +#ifndef _CIPHER_RC4_H +#define _CIPHER_RC4_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +void RC4_Sample(unsigned char *key, int key_len, + unsigned char *data, int data_len); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif // _CIPHER_RC4_H \ No newline at end of file diff --git a/cipher/rsa/Makefile b/cipher/rsa/Makefile new file mode 100644 index 0000000..e35a066 --- /dev/null +++ b/cipher/rsa/Makefile @@ -0,0 +1,19 @@ +OBJ=asn1.o os_unix.o common.o wpabuf.o wpa_debug.o rsa.o bignum.o base64.o + +all:test_rsa libuser_rsa.a + +test_rsa: $(OBJ) test_rsa.o + gcc -o $@ $^ + +libuser_rsa.a: $(OBJ) user_rsa.o + ar rus $@ $^ + +%.o:%.c + gcc -DCONFIG_USE_INTTYPES_H -DCONFIG_INTERNAL_LIBTOMMATH -g -c $< + +key: + openssl genrsa -out privkey 464 + openssl rsa -in privkey -pubout -out pubkey + +clean: + rm -rf *.o test_rsa libuser_rsa.a diff --git a/cipher/rsa/Makefile.aix b/cipher/rsa/Makefile.aix new file mode 100644 index 0000000..4d6c1ed --- /dev/null +++ b/cipher/rsa/Makefile.aix @@ -0,0 +1,19 @@ +OBJ=asn1.o os_unix.o common.o wpabuf.o wpa_debug.o rsa.o bignum.o base64.o + +all:test_rsa libuser_rsa.a + +test_rsa: $(OBJ) test_rsa.o + xlc -o $@ $^ + +libuser_rsa.a: $(OBJ) user_rsa.o + ar rus $@ $^ + +%.o:%.c + xlc -D__AIX__ -DCONFIG_INTERNAL_LIBTOMMATH -g -c $< + +key: + openssl genrsa -out privkey 464 + openssl rsa -in privkey -pubout -out pubkey + +clean: + rm -rf *.o test_rsa libuser_rsa.a diff --git a/cipher/rsa/Makefile.hp b/cipher/rsa/Makefile.hp new file mode 100644 index 0000000..48d5550 --- /dev/null +++ b/cipher/rsa/Makefile.hp @@ -0,0 +1,19 @@ +OBJ=asn1.o os_unix.o common.o wpabuf.o wpa_debug.o rsa.o bignum.o base64.o + +all:test_rsa libuser_rsa.a + +test_rsa: $(OBJ) test_rsa.o + cc -o $@ $^ + +libuser_rsa.a: $(OBJ) user_rsa.o + ar rus $@ $^ + +%.o:%.c + cc -DHPUX -DCONFIG_NO_INLINE -DCONFIG_INTERNAL_LIBTOMMATH -g -c $< + +key: + openssl genrsa -out privkey 464 + openssl rsa -in privkey -pubout -out pubkey + +clean: + rm -rf *.o test_rsa libuser_rsa.a diff --git a/cipher/rsa/Makefile.linux b/cipher/rsa/Makefile.linux new file mode 100644 index 0000000..95924ef --- /dev/null +++ b/cipher/rsa/Makefile.linux @@ -0,0 +1,19 @@ +OBJ=asn1.o os_unix.o common.o wpabuf.o wpa_debug.o rsa.o bignum.o base64.o + +all:test_rsa libuser_rsa.a + +test_rsa: $(OBJ) test_rsa.o + gcc -o $@ $^ + +libuser_rsa.a: $(OBJ) user_rsa.o + ar rus $@ $^ + +%.o:%.c + gcc -fPIC -DCONFIG_INTERNAL_LIBTOMMATH -g -c $< + +key: + openssl genrsa -out privkey 464 + openssl rsa -in privkey -pubout -out pubkey + +clean: + rm -rf *.o test_rsa libuser_rsa.a diff --git a/cipher/rsa/asn1.c b/cipher/rsa/asn1.c new file mode 100644 index 0000000..3391245 --- /dev/null +++ b/cipher/rsa/asn1.c @@ -0,0 +1,212 @@ +/* + * ASN.1 DER parsing + * Copyright (c) 2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "asn1.h" + +int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr) +{ + const u8 *pos, *end; + u8 tmp; + + os_memset(hdr, 0, sizeof(*hdr)); + pos = buf; + end = buf + len; + + hdr->identifier = *pos++; + hdr->class = hdr->identifier >> 6; + hdr->constructed = !!(hdr->identifier & (1 << 5)); + + if ((hdr->identifier & 0x1f) == 0x1f) { + hdr->tag = 0; + do { + if (pos >= end) { + wpa_printf(MSG_DEBUG, "ASN.1: Identifier " + "underflow"); + return -1; + } + tmp = *pos++; + wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: " + "0x%02x", tmp); + hdr->tag = (hdr->tag << 7) | (tmp & 0x7f); + } while (tmp & 0x80); + } else + hdr->tag = hdr->identifier & 0x1f; + + tmp = *pos++; + if (tmp & 0x80) { + if (tmp == 0xff) { + wpa_printf(MSG_DEBUG, "ASN.1: Reserved length " + "value 0xff used"); + return -1; + } + tmp &= 0x7f; /* number of subsequent octets */ + hdr->length = 0; + if (tmp > 4) { + wpa_printf(MSG_DEBUG, "ASN.1: Too long length field"); + return -1; + } + while (tmp--) { + if (pos >= end) { + wpa_printf(MSG_DEBUG, "ASN.1: Length " + "underflow"); + return -1; + } + hdr->length = (hdr->length << 8) | *pos++; + } + } else { + /* Short form - length 0..127 in one octet */ + hdr->length = tmp; + } + + if (end < pos || hdr->length > (unsigned int) (end - pos)) { + wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow"); + return -1; + } + + hdr->payload = pos; + return 0; +} + + +int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid) +{ + const u8 *pos, *end; + unsigned long val; + u8 tmp; + + os_memset(oid, 0, sizeof(*oid)); + + pos = buf; + end = buf + len; + + while (pos < end) { + val = 0; + + do { + if (pos >= end) + return -1; + tmp = *pos++; + val = (val << 7) | (tmp & 0x7f); + } while (tmp & 0x80); + + if (oid->len >= ASN1_MAX_OID_LEN) { + wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value"); + return -1; + } + if (oid->len == 0) { + /* + * The first octet encodes the first two object + * identifier components in (X*40) + Y formula. + * X = 0..2. + */ + oid->oid[0] = val / 40; + if (oid->oid[0] > 2) + oid->oid[0] = 2; + oid->oid[1] = val - oid->oid[0] * 40; + oid->len = 2; + } else + oid->oid[oid->len++] = val; + } + + return 0; +} + + +int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, + const u8 **next) +{ + struct asn1_hdr hdr; + + if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0) + return -1; + + if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) { + wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d " + "tag 0x%x", hdr.class, hdr.tag); + return -1; + } + + *next = hdr.payload + hdr.length; + + return asn1_parse_oid(hdr.payload, hdr.length, oid); +} + + +void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len) +{ + char *pos = buf; + size_t i; + int ret; + + if (len == 0) + return; + + buf[0] = '\0'; + + for (i = 0; i < oid->len; i++) { + ret = os_snprintf(pos, buf + len - pos, + "%s%lu", + i == 0 ? "" : ".", oid->oid[i]); + if (ret < 0 || ret >= buf + len - pos) + break; + pos += ret; + } + buf[len - 1] = '\0'; +} + + +static u8 rotate_bits(u8 octet) +{ + int i; + u8 res; + + res = 0; + for (i = 0; i < 8; i++) { + res <<= 1; + if (octet & 1) + res |= 1; + octet >>= 1; + } + + return res; +} + + +unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len) +{ + unsigned long val = 0; + const u8 *pos = buf; + + /* BER requires that unused bits are zero, so we can ignore the number + * of unused bits */ + pos++; + + if (len >= 2) + val |= rotate_bits(*pos++); + if (len >= 3) + val |= ((unsigned long) rotate_bits(*pos++)) << 8; + if (len >= 4) + val |= ((unsigned long) rotate_bits(*pos++)) << 16; + if (len >= 5) + val |= ((unsigned long) rotate_bits(*pos++)) << 24; + if (len >= 6) + wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored " + "(BIT STRING length %lu)", + __func__, (unsigned long) len); + + return val; +} diff --git a/cipher/rsa/asn1.h b/cipher/rsa/asn1.h new file mode 100644 index 0000000..2ff571e --- /dev/null +++ b/cipher/rsa/asn1.h @@ -0,0 +1,72 @@ +/* + * ASN.1 DER parsing + * Copyright (c) 2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef ASN1_H +#define ASN1_H + +#define ASN1_TAG_EOC 0x00 /* not used with DER */ +#define ASN1_TAG_BOOLEAN 0x01 +#define ASN1_TAG_INTEGER 0x02 +#define ASN1_TAG_BITSTRING 0x03 +#define ASN1_TAG_OCTETSTRING 0x04 +#define ASN1_TAG_NULL 0x05 +#define ASN1_TAG_OID 0x06 +#define ASN1_TAG_OBJECT_DESCRIPTOR 0x07 /* not yet parsed */ +#define ASN1_TAG_EXTERNAL 0x08 /* not yet parsed */ +#define ASN1_TAG_REAL 0x09 /* not yet parsed */ +#define ASN1_TAG_ENUMERATED 0x0A /* not yet parsed */ +#define ASN1_TAG_UTF8STRING 0x0C /* not yet parsed */ +#define ANS1_TAG_RELATIVE_OID 0x0D +#define ASN1_TAG_SEQUENCE 0x10 /* shall be constructed */ +#define ASN1_TAG_SET 0x11 +#define ASN1_TAG_NUMERICSTRING 0x12 /* not yet parsed */ +#define ASN1_TAG_PRINTABLESTRING 0x13 +#define ASN1_TAG_TG1STRING 0x14 /* not yet parsed */ +#define ASN1_TAG_VIDEOTEXSTRING 0x15 /* not yet parsed */ +#define ASN1_TAG_IA5STRING 0x16 +#define ASN1_TAG_UTCTIME 0x17 +#define ASN1_TAG_GENERALIZEDTIME 0x18 /* not yet parsed */ +#define ASN1_TAG_GRAPHICSTRING 0x19 /* not yet parsed */ +#define ASN1_TAG_VISIBLESTRING 0x1A +#define ASN1_TAG_GENERALSTRING 0x1B /* not yet parsed */ +#define ASN1_TAG_UNIVERSALSTRING 0x1C /* not yet parsed */ +#define ASN1_TAG_BMPSTRING 0x1D /* not yet parsed */ + +#define ASN1_CLASS_UNIVERSAL 0 +#define ASN1_CLASS_APPLICATION 1 +#define ASN1_CLASS_CONTEXT_SPECIFIC 2 +#define ASN1_CLASS_PRIVATE 3 + + +struct asn1_hdr { + const u8 *payload; + u8 identifier, class, constructed; + unsigned int tag, length; +}; + +#define ASN1_MAX_OID_LEN 20 +struct asn1_oid { + unsigned long oid[ASN1_MAX_OID_LEN]; + size_t len; +}; + + +int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr); +int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid); +int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, + const u8 **next); +void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len); +unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len); + +#endif /* ASN1_H */ diff --git a/cipher/rsa/base64.c b/cipher/rsa/base64.c new file mode 100644 index 0000000..155bfce --- /dev/null +++ b/cipher/rsa/base64.c @@ -0,0 +1,154 @@ +/* + * Base64 encoding/decoding (RFC1341) + * Copyright (c) 2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "os.h" +#include "base64.h" + +static const unsigned char base64_table[65] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/** + * base64_encode - Base64 encode + * @src: Data to be encoded + * @len: Length of the data to be encoded + * @out_len: Pointer to output length variable, or %NULL if not used + * Returns: Allocated buffer of out_len bytes of encoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. Returned buffer is + * nul terminated to make it easier to use as a C string. The nul terminator is + * not included in out_len. + */ +unsigned char * base64_encode(const unsigned char *src, size_t len, + size_t *out_len) +{ + unsigned char *out, *pos; + const unsigned char *end, *in; + size_t olen; + int line_len; + + olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ + olen += olen / 72; /* line feeds */ + olen++; /* nul termination */ + if (olen < len) + return NULL; /* integer overflow */ + out = os_malloc(olen); + if (out == NULL) + return NULL; + + end = src + len; + in = src; + pos = out; + line_len = 0; + while (end - in >= 3) { + *pos++ = base64_table[in[0] >> 2]; + *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; + *pos++ = base64_table[in[2] & 0x3f]; + in += 3; + line_len += 4; + if (line_len >= 72) { + *pos++ = '\n'; + line_len = 0; + } + } + + if (end - in) { + *pos++ = base64_table[in[0] >> 2]; + if (end - in == 1) { + *pos++ = base64_table[(in[0] & 0x03) << 4]; + *pos++ = '='; + } else { + *pos++ = base64_table[((in[0] & 0x03) << 4) | + (in[1] >> 4)]; + *pos++ = base64_table[(in[1] & 0x0f) << 2]; + } + *pos++ = '='; + line_len += 4; + } + + if (line_len) + *pos++ = '\n'; + + *pos = '\0'; + if (out_len) + *out_len = pos - out; + return out; +} + + +/** + * base64_decode - Base64 decode + * @src: Data to be decoded + * @len: Length of the data to be decoded + * @out_len: Pointer to output length variable + * Returns: Allocated buffer of out_len bytes of decoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. + */ +unsigned char * base64_decode(const unsigned char *src, size_t len, + size_t *out_len) +{ + unsigned char dtable[256], *out, *pos, in[4], block[4], tmp; + size_t i, count, olen; + + os_memset(dtable, 0x80, 256); + for (i = 0; i < sizeof(base64_table) - 1; i++) + dtable[base64_table[i]] = (unsigned char) i; + dtable['='] = 0; + + count = 0; + for (i = 0; i < len; i++) { + if (dtable[src[i]] != 0x80) + count++; + } + + if (count == 0 || count % 4) + return NULL; + + olen = count / 4 * 3; + pos = out = os_malloc(olen); + if (out == NULL) + return NULL; + + count = 0; + for (i = 0; i < len; i++) { + tmp = dtable[src[i]]; + if (tmp == 0x80) + continue; + + in[count] = src[i]; + block[count] = tmp; + count++; + if (count == 4) { + *pos++ = (block[0] << 2) | (block[1] >> 4); + *pos++ = (block[1] << 4) | (block[2] >> 2); + *pos++ = (block[2] << 6) | block[3]; + count = 0; + } + } + + if (pos > out) { + if (in[2] == '=') + pos -= 2; + else if (in[3] == '=') + pos--; + } + + *out_len = pos - out; + return out; +} diff --git a/cipher/rsa/base64.h b/cipher/rsa/base64.h new file mode 100644 index 0000000..6b766c9 --- /dev/null +++ b/cipher/rsa/base64.h @@ -0,0 +1,31 @@ +/* + * Base64 encoding/decoding (RFC1341) + * Copyright (c) 2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef BASE64_H +#define BASE64_h + +#ifdef __cplusplus +extern "C"{ +#endif + +unsigned char * base64_encode(const unsigned char *src, size_t len, + size_t *out_len); +unsigned char * base64_decode(const unsigned char *src, size_t len, + size_t *out_len); + +#ifdef __cplusplus +} +#endif + +#endif /* BASE64_H */ diff --git a/cipher/rsa/bignum.c b/cipher/rsa/bignum.c new file mode 100644 index 0000000..5c0fc62 --- /dev/null +++ b/cipher/rsa/bignum.c @@ -0,0 +1,230 @@ +/* + * Big number math + * Copyright (c) 2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "bignum.h" + +#ifdef CONFIG_INTERNAL_LIBTOMMATH +#include "libtommath.c" +#else /* CONFIG_INTERNAL_LIBTOMMATH */ +#include +#endif /* CONFIG_INTERNAL_LIBTOMMATH */ + + +/* + * The current version is just a wrapper for LibTomMath library, so + * struct bignum is just typecast to mp_int. + */ + +/** + * bignum_init - Allocate memory for bignum + * Returns: Pointer to allocated bignum or %NULL on failure + */ +struct bignum * bignum_init(void) +{ + struct bignum *n = os_zalloc(sizeof(mp_int)); + if (n == NULL) + return NULL; + if (mp_init((mp_int *) n) != MP_OKAY) { + os_free(n); + n = NULL; + } + return n; +} + + +/** + * bignum_deinit - Free bignum + * @n: Bignum from bignum_init() + */ +void bignum_deinit(struct bignum *n) +{ + if (n) { + mp_clear((mp_int *) n); + os_free(n); + } +} + + +/** + * bignum_get_unsigned_bin - Get length of bignum as an unsigned binary buffer + * @n: Bignum from bignum_init() + * Returns: Length of n if written to a binary buffer + */ +size_t bignum_get_unsigned_bin_len(struct bignum *n) +{ + return mp_unsigned_bin_size((mp_int *) n); +} + + +/** + * bignum_get_unsigned_bin - Set binary buffer to unsigned bignum + * @n: Bignum from bignum_init() + * @buf: Buffer for the binary number + * @len: Length of the buffer, can be %NULL if buffer is known to be long + * enough. Set to used buffer length on success if not %NULL. + * Returns: 0 on success, -1 on failure + */ +int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len) +{ + size_t need = mp_unsigned_bin_size((mp_int *) n); + if (len && need > *len) { + *len = need; + return -1; + } + if (mp_to_unsigned_bin((mp_int *) n, buf) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + if (len) + *len = need; + return 0; +} + + +/** + * bignum_set_unsigned_bin - Set bignum based on unsigned binary buffer + * @n: Bignum from bignum_init(); to be set to the given value + * @buf: Buffer with unsigned binary value + * @len: Length of buf in octets + * Returns: 0 on success, -1 on failure + */ +int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len) +{ + if (mp_read_unsigned_bin((mp_int *) n, (u8 *) buf, len) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_cmp - Signed comparison + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * Returns: 0 on success, -1 on failure + */ +int bignum_cmp(const struct bignum *a, const struct bignum *b) +{ + return mp_cmp((mp_int *) a, (mp_int *) b); +} + + +/** + * bignum_cmd_d - Compare bignum to standard integer + * @a: Bignum from bignum_init() + * @b: Small integer + * Returns: 0 on success, -1 on failure + */ +int bignum_cmp_d(const struct bignum *a, unsigned long b) +{ + return mp_cmp_d((mp_int *) a, b); +} + + +/** + * bignum_add - c = a + b + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); used to store the result of a + b + * Returns: 0 on success, -1 on failure + */ +int bignum_add(const struct bignum *a, const struct bignum *b, + struct bignum *c) +{ + if (mp_add((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_sub - c = a - b + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); used to store the result of a - b + * Returns: 0 on success, -1 on failure + */ +int bignum_sub(const struct bignum *a, const struct bignum *b, + struct bignum *c) +{ + if (mp_sub((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_mul - c = a * b + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); used to store the result of a * b + * Returns: 0 on success, -1 on failure + */ +int bignum_mul(const struct bignum *a, const struct bignum *b, + struct bignum *c) +{ + if (mp_mul((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_mulmod - d = a * b (mod c) + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); modulus + * @d: Bignum from bignum_init(); used to store the result of a * b (mod c) + * Returns: 0 on success, -1 on failure + */ +int bignum_mulmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d) +{ + if (mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d) + != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_exptmod - Modular exponentiation: d = a^b (mod c) + * @a: Bignum from bignum_init(); base + * @b: Bignum from bignum_init(); exponent + * @c: Bignum from bignum_init(); modulus + * @d: Bignum from bignum_init(); used to store the result of a^b (mod c) + * Returns: 0 on success, -1 on failure + */ +int bignum_exptmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d) +{ + if (mp_exptmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d) + != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} diff --git a/cipher/rsa/bignum.h b/cipher/rsa/bignum.h new file mode 100644 index 0000000..f25e267 --- /dev/null +++ b/cipher/rsa/bignum.h @@ -0,0 +1,38 @@ +/* + * Big number math + * Copyright (c) 2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef BIGNUM_H +#define BIGNUM_H + +struct bignum; + +struct bignum * bignum_init(void); +void bignum_deinit(struct bignum *n); +size_t bignum_get_unsigned_bin_len(struct bignum *n); +int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len); +int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len); +int bignum_cmp(const struct bignum *a, const struct bignum *b); +int bignum_cmp_d(const struct bignum *a, unsigned long b); +int bignum_add(const struct bignum *a, const struct bignum *b, + struct bignum *c); +int bignum_sub(const struct bignum *a, const struct bignum *b, + struct bignum *c); +int bignum_mul(const struct bignum *a, const struct bignum *b, + struct bignum *c); +int bignum_mulmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d); +int bignum_exptmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d); + +#endif /* BIGNUM_H */ diff --git a/cipher/rsa/build_config.h b/cipher/rsa/build_config.h new file mode 100644 index 0000000..3666778 --- /dev/null +++ b/cipher/rsa/build_config.h @@ -0,0 +1,105 @@ +/* + * wpa_supplicant/hostapd - Build time configuration defines + * Copyright (c) 2005-2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * This header file can be used to define configuration defines that were + * originally defined in Makefile. This is mainly meant for IDE use or for + * systems that do not have suitable 'make' tool. In these cases, it may be + * easier to have a single place for defining all the needed C pre-processor + * defines. + */ + +#ifndef BUILD_CONFIG_H +#define BUILD_CONFIG_H + +/* Insert configuration defines, e.g., #define EAP_MD5, here, if needed. */ + +#ifdef CONFIG_WIN32_DEFAULTS +#define CONFIG_NATIVE_WINDOWS +#define CONFIG_ANSI_C_EXTRA +#define CONFIG_WINPCAP +#define IEEE8021X_EAPOL +#define PKCS12_FUNCS +#define PCSC_FUNCS +#define CONFIG_CTRL_IFACE +#define CONFIG_CTRL_IFACE_NAMED_PIPE +#define CONFIG_DRIVER_NDIS +#define CONFIG_NDIS_EVENTS_INTEGRATED +#define CONFIG_DEBUG_FILE +#define EAP_MD5 +#define EAP_TLS +#define EAP_MSCHAPv2 +#define EAP_PEAP +#define EAP_TTLS +#define EAP_GTC +#define EAP_OTP +#define EAP_LEAP +#define EAP_TNC +#define _CRT_SECURE_NO_DEPRECATE + +#ifdef USE_INTERNAL_CRYPTO +#define CONFIG_TLS_INTERNAL_CLIENT +#define CONFIG_INTERNAL_LIBTOMMATH +#define CONFIG_CRYPTO_INTERNAL +#endif /* USE_INTERNAL_CRYPTO */ +#endif /* CONFIG_WIN32_DEFAULTS */ + +#ifdef __SYMBIAN32__ +#define OS_NO_C_LIB_DEFINES +#define CONFIG_ANSI_C_EXTRA +#define CONFIG_NO_WPA_MSG +#define CONFIG_NO_HOSTAPD_LOGGER +#define CONFIG_NO_STDOUT_DEBUG +#define CONFIG_BACKEND_FILE +#define CONFIG_INTERNAL_LIBTOMMATH +#define CONFIG_CRYPTO_INTERNAL +#define IEEE8021X_EAPOL +#define PKCS12_FUNCS +#define EAP_MD5 +#define EAP_TLS +#define EAP_MSCHAPv2 +#define EAP_PEAP +#define EAP_TTLS +#define EAP_GTC +#define EAP_OTP +#define EAP_LEAP +#define EAP_FAST +#endif /* __SYMBIAN32__ */ + +#ifdef CONFIG_XCODE_DEFAULTS +#define CONFIG_DRIVER_OSX +#define CONFIG_BACKEND_FILE +#define IEEE8021X_EAPOL +#define PKCS12_FUNCS +#define CONFIG_CTRL_IFACE +#define CONFIG_CTRL_IFACE_UNIX +#define CONFIG_DEBUG_FILE +#define EAP_MD5 +#define EAP_TLS +#define EAP_MSCHAPv2 +#define EAP_PEAP +#define EAP_TTLS +#define EAP_GTC +#define EAP_OTP +#define EAP_LEAP +#define EAP_TNC +#define CONFIG_WPS +#define EAP_WSC + +#ifdef USE_INTERNAL_CRYPTO +#define CONFIG_TLS_INTERNAL_CLIENT +#define CONFIG_INTERNAL_LIBTOMMATH +#define CONFIG_CRYPTO_INTERNAL +#endif /* USE_INTERNAL_CRYPTO */ +#endif /* CONFIG_XCODE_DEFAULTS */ + +#endif /* BUILD_CONFIG_H */ diff --git a/cipher/rsa/common.c b/cipher/rsa/common.c new file mode 100644 index 0000000..9a46ebe --- /dev/null +++ b/cipher/rsa/common.c @@ -0,0 +1,333 @@ +/* + * wpa_supplicant/hostapd / common helper functions, etc. + * Copyright (c) 2002-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" + + +static int hex2num(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + + +static int hex2byte(const char *hex) +{ + int a, b; + a = hex2num(*hex++); + if (a < 0) + return -1; + b = hex2num(*hex++); + if (b < 0) + return -1; + return (a << 4) | b; +} + + +/** + * hwaddr_aton - Convert ASCII string to MAC address + * @txt: MAC address as a string (e.g., "00:11:22:33:44:55") + * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) + * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) + */ +int hwaddr_aton(const char *txt, u8 *addr) +{ + int i; + + for (i = 0; i < 6; i++) { + int a, b; + + a = hex2num(*txt++); + if (a < 0) + return -1; + b = hex2num(*txt++); + if (b < 0) + return -1; + *addr++ = (a << 4) | b; + if (i < 5 && *txt++ != ':') + return -1; + } + + return 0; +} + + +/** + * hexstr2bin - Convert ASCII hex string into binary data + * @hex: ASCII hex string (e.g., "01ab") + * @buf: Buffer for the binary data + * @len: Length of the text to convert in bytes (of buf); hex will be double + * this size + * Returns: 0 on success, -1 on failure (invalid hex string) + */ +int hexstr2bin(const char *hex, u8 *buf, size_t len) +{ + size_t i; + int a; + const char *ipos = hex; + u8 *opos = buf; + + for (i = 0; i < len; i++) { + a = hex2byte(ipos); + if (a < 0) + return -1; + *opos++ = a; + ipos += 2; + } + return 0; +} + + +/** + * inc_byte_array - Increment arbitrary length byte array by one + * @counter: Pointer to byte array + * @len: Length of the counter in bytes + * + * This function increments the last byte of the counter by one and continues + * rolling over to more significant bytes if the byte was incremented from + * 0xff to 0x00. + */ +void inc_byte_array(u8 *counter, size_t len) +{ + int pos = len - 1; + while (pos >= 0) { + counter[pos]++; + if (counter[pos] != 0) + break; + pos--; + } +} + + +void wpa_get_ntp_timestamp(u8 *buf) +{ + struct os_time now; + u32 sec, usec; + be32 tmp; + + /* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */ + os_get_time(&now); + sec = now.sec + 2208988800U; /* Epoch to 1900 */ + /* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */ + usec = now.usec; + usec = 4295 * usec - (usec >> 5) - (usec >> 9); + tmp = host_to_be32(sec); + os_memcpy(buf, (u8 *) &tmp, 4); + tmp = host_to_be32(usec); + os_memcpy(buf + 4, (u8 *) &tmp, 4); +} + + +static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, + size_t len, int uppercase) +{ + size_t i; + char *pos = buf, *end = buf + buf_size; + int ret; + if (buf_size == 0) + return 0; + for (i = 0; i < len; i++) { + ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x", + data[i]); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return pos - buf; + } + pos += ret; + } + end[-1] = '\0'; + return pos - buf; +} + +/** + * wpa_snprintf_hex - Print data as a hex string into a buffer + * @buf: Memory area to use as the output buffer + * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1) + * @data: Data to be printed + * @len: Length of data in bytes + * Returns: Number of bytes written + */ +int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len) +{ + return _wpa_snprintf_hex(buf, buf_size, data, len, 0); +} + + +/** + * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf + * @buf: Memory area to use as the output buffer + * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1) + * @data: Data to be printed + * @len: Length of data in bytes + * Returns: Number of bytes written + */ +int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, + size_t len) +{ + return _wpa_snprintf_hex(buf, buf_size, data, len, 1); +} + + +#ifdef CONFIG_ANSI_C_EXTRA + +#ifdef _WIN32_WCE +void perror(const char *s) +{ + wpa_printf(MSG_ERROR, "%s: GetLastError: %d", + s, (int) GetLastError()); +} +#endif /* _WIN32_WCE */ + + +int optind = 1; +int optopt; +char *optarg; + +int getopt(int argc, char *const argv[], const char *optstring) +{ + static int optchr = 1; + char *cp; + + if (optchr == 1) { + if (optind >= argc) { + /* all arguments processed */ + return EOF; + } + + if (argv[optind][0] != '-' || argv[optind][1] == '\0') { + /* no option characters */ + return EOF; + } + } + + if (os_strcmp(argv[optind], "--") == 0) { + /* no more options */ + optind++; + return EOF; + } + + optopt = argv[optind][optchr]; + cp = os_strchr(optstring, optopt); + if (cp == NULL || optopt == ':') { + if (argv[optind][++optchr] == '\0') { + optchr = 1; + optind++; + } + return '?'; + } + + if (cp[1] == ':') { + /* Argument required */ + optchr = 1; + if (argv[optind][optchr + 1]) { + /* No space between option and argument */ + optarg = &argv[optind++][optchr + 1]; + } else if (++optind >= argc) { + /* option requires an argument */ + return '?'; + } else { + /* Argument in the next argv */ + optarg = argv[optind++]; + } + } else { + /* No argument */ + if (argv[optind][++optchr] == '\0') { + optchr = 1; + optind++; + } + optarg = NULL; + } + return *cp; +} +#endif /* CONFIG_ANSI_C_EXTRA */ + + +#ifdef CONFIG_NATIVE_WINDOWS +/** + * wpa_unicode2ascii_inplace - Convert unicode string into ASCII + * @str: Pointer to string to convert + * + * This function converts a unicode string to ASCII using the same + * buffer for output. If UNICODE is not set, the buffer is not + * modified. + */ +void wpa_unicode2ascii_inplace(TCHAR *str) +{ +#ifdef UNICODE + char *dst = (char *) str; + while (*str) + *dst++ = (char) *str++; + *dst = '\0'; +#endif /* UNICODE */ +} + + +TCHAR * wpa_strdup_tchar(const char *str) +{ +#ifdef UNICODE + TCHAR *buf; + buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR)); + if (buf == NULL) + return NULL; + wsprintf(buf, L"%S", str); + return buf; +#else /* UNICODE */ + return os_strdup(str); +#endif /* UNICODE */ +} +#endif /* CONFIG_NATIVE_WINDOWS */ + + +/** + * wpa_ssid_txt - Convert SSID to a printable string + * @ssid: SSID (32-octet string) + * @ssid_len: Length of ssid in octets + * Returns: Pointer to a printable string + * + * This function can be used to convert SSIDs into printable form. In most + * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard + * does not limit the used character set, so anything could be used in an SSID. + * + * This function uses a static buffer, so only one call can be used at the + * time, i.e., this is not re-entrant and the returned buffer must be used + * before calling this again. + */ +const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len) +{ + static char ssid_txt[33]; + char *pos; + + if (ssid_len > 32) + ssid_len = 32; + os_memcpy(ssid_txt, ssid, ssid_len); + ssid_txt[ssid_len] = '\0'; + for (pos = ssid_txt; *pos != '\0'; pos++) { + if ((u8) *pos < 32 || (u8) *pos >= 127) + *pos = '_'; + } + return ssid_txt; +} + + +void * __hide_aliasing_typecast(void *foo) +{ + return foo; +} diff --git a/cipher/rsa/common.h b/cipher/rsa/common.h new file mode 100644 index 0000000..9949f0d --- /dev/null +++ b/cipher/rsa/common.h @@ -0,0 +1,489 @@ +/* + * wpa_supplicant/hostapd / common helper functions, etc. + * Copyright (c) 2002-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef COMMON_H +#define COMMON_H + +#include "os.h" + +#ifdef __linux__ +#include +#include +#endif /* __linux__ */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ + defined(__OpenBSD__) +#include +#include +#define __BYTE_ORDER _BYTE_ORDER +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN +#ifdef __OpenBSD__ +#define bswap_16 swap16 +#define bswap_32 swap32 +#define bswap_64 swap64 +#else /* __OpenBSD__ */ +#define bswap_16 bswap16 +#define bswap_32 bswap32 +#define bswap_64 bswap64 +#endif /* __OpenBSD__ */ +#endif /* defined(__FreeBSD__) || defined(__NetBSD__) || + * defined(__DragonFly__) || defined(__OpenBSD__) */ + +#ifdef __APPLE__ +#include +#include +#define __BYTE_ORDER _BYTE_ORDER +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN +static inline unsigned short bswap_16(unsigned short v) +{ + return ((v & 0xff) << 8) | (v >> 8); +} + +static inline unsigned int bswap_32(unsigned int v) +{ + return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | + ((v & 0xff0000) >> 8) | (v >> 24); +} +#endif /* __APPLE__ */ + +#ifdef CONFIG_TI_COMPILER +#define __BIG_ENDIAN 4321 +#define __LITTLE_ENDIAN 1234 +#ifdef __big_endian__ +#define __BYTE_ORDER __BIG_ENDIAN +#else +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif +#endif /* CONFIG_TI_COMPILER */ + +#ifdef __SYMBIAN32__ +#define __BIG_ENDIAN 4321 +#define __LITTLE_ENDIAN 1234 +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif /* __SYMBIAN32__ */ + +#ifdef __AIX__ +#define __BYTE_ORDER __BIG_ENDIAN +#endif + +#ifdef HPUX +#define __BYTE_ORDER __BIG_ENDIAN +static unsigned int bswap_32(unsigned int v) +{ + return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | + ((v & 0xff0000) >> 8) | (v >> 24); +} +#endif + +#ifdef CONFIG_NATIVE_WINDOWS +#include + +typedef int socklen_t; + +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 /* not supported */ +#endif + +#endif /* CONFIG_NATIVE_WINDOWS */ + +#ifdef _MSC_VER +#define inline __inline + +#undef vsnprintf +#define vsnprintf _vsnprintf +#undef close +#define close closesocket +#endif /* _MSC_VER */ + + +/* Define platform specific integer types */ + +#ifdef _MSC_VER +typedef UINT64 u64; +typedef UINT32 u32; +typedef UINT16 u16; +typedef UINT8 u8; +typedef INT64 s64; +typedef INT32 s32; +typedef INT16 s16; +typedef INT8 s8; +#define WPA_TYPES_DEFINED +#endif /* _MSC_VER */ + +#ifdef __vxworks +typedef unsigned long long u64; +typedef UINT32 u32; +typedef UINT16 u16; +typedef UINT8 u8; +typedef long long s64; +typedef INT32 s32; +typedef INT16 s16; +typedef INT8 s8; +#define WPA_TYPES_DEFINED +#endif /* __vxworks */ + +#ifdef CONFIG_TI_COMPILER +#ifdef _LLONG_AVAILABLE +typedef unsigned long long u64; +#else +/* + * TODO: 64-bit variable not available. Using long as a workaround to test the + * build, but this will likely not work for all operations. + */ +typedef unsigned long u64; +#endif +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; +#define WPA_TYPES_DEFINED +#endif /* CONFIG_TI_COMPILER */ + +#ifdef __SYMBIAN32__ +#define __REMOVE_PLATSEC_DIAGNOSTICS__ +#include +typedef TUint64 u64; +typedef TUint32 u32; +typedef TUint16 u16; +typedef TUint8 u8; +#define WPA_TYPES_DEFINED +#endif /* __SYMBIAN32__ */ + +#ifndef WPA_TYPES_DEFINED +#ifdef CONFIG_USE_INTTYPES_H +#include +#else +#include +#endif +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; +typedef int64_t s64; +typedef int32_t s32; +typedef int16_t s16; +typedef int8_t s8; +#define WPA_TYPES_DEFINED +#endif /* !WPA_TYPES_DEFINED */ + + +/* Define platform specific byte swapping macros */ + +#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) + +static inline unsigned short wpa_swap_16(unsigned short v) +{ + return ((v & 0xff) << 8) | (v >> 8); +} + +static inline unsigned int wpa_swap_32(unsigned int v) +{ + return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | + ((v & 0xff0000) >> 8) | (v >> 24); +} + +#define le_to_host16(n) (n) +#define host_to_le16(n) (n) +#define be_to_host16(n) wpa_swap_16(n) +#define host_to_be16(n) wpa_swap_16(n) +#define le_to_host32(n) (n) +#define be_to_host32(n) wpa_swap_32(n) +#define host_to_be32(n) wpa_swap_32(n) + +#define WPA_BYTE_SWAP_DEFINED + +#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */ + + +#ifndef WPA_BYTE_SWAP_DEFINED + +#ifndef __BYTE_ORDER +#ifndef __LITTLE_ENDIAN +#ifndef __BIG_ENDIAN +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#if defined(sparc) +#define __BYTE_ORDER __BIG_ENDIAN +#endif +#endif /* __BIG_ENDIAN */ +#endif /* __LITTLE_ENDIAN */ +#endif /* __BYTE_ORDER */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define le_to_host16(n) ((__force u16) (le16) (n)) +#define host_to_le16(n) ((__force le16) (u16) (n)) +#define be_to_host16(n) bswap_16((__force u16) (be16) (n)) +#define host_to_be16(n) ((__force be16) bswap_16((n))) +#define le_to_host32(n) ((__force u32) (le32) (n)) +#define host_to_le32(n) ((__force le32) (u32) (n)) +#define be_to_host32(n) bswap_32((__force u32) (be32) (n)) +#define host_to_be32(n) ((__force be32) bswap_32((n))) +#define le_to_host64(n) ((__force u64) (le64) (n)) +#define host_to_le64(n) ((__force le64) (u64) (n)) +#define be_to_host64(n) bswap_64((__force u64) (be64) (n)) +#define host_to_be64(n) ((__force be64) bswap_64((n))) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define le_to_host16(n) bswap_16(n) +#define host_to_le16(n) bswap_16(n) +#define be_to_host16(n) (n) +#define host_to_be16(n) (n) +#define le_to_host32(n) bswap_32(n) +#define be_to_host32(n) (n) +#define host_to_be32(n) (n) +#define le_to_host64(n) bswap_64(n) +#define host_to_le64(n) bswap_64(n) +#define be_to_host64(n) (n) +#define host_to_be64(n) (n) +#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN +#endif +#else +#error Could not determine CPU byte order +#endif + +#define WPA_BYTE_SWAP_DEFINED +#endif /* !WPA_BYTE_SWAP_DEFINED */ + + +/* Macros for handling unaligned memory accesses */ + +#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) +#define WPA_PUT_BE16(a, val) \ + do { \ + (a)[0] = ((u16) (val)) >> 8; \ + (a)[1] = ((u16) (val)) & 0xff; \ + } while (0) + +#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) +#define WPA_PUT_LE16(a, val) \ + do { \ + (a)[1] = ((u16) (val)) >> 8; \ + (a)[0] = ((u16) (val)) & 0xff; \ + } while (0) + +#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ + ((u32) (a)[2])) +#define WPA_PUT_BE24(a, val) \ + do { \ + (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[2] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ + (((u32) (a)[2]) << 8) | ((u32) (a)[3])) +#define WPA_PUT_BE32(a, val) \ + do { \ + (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[3] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \ + (((u32) (a)[1]) << 8) | ((u32) (a)[0])) +#define WPA_PUT_LE32(a, val) \ + do { \ + (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[0] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \ + (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \ + (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \ + (((u64) (a)[6]) << 8) | ((u64) (a)[7])) +#define WPA_PUT_BE64(a, val) \ + do { \ + (a)[0] = (u8) (((u64) (val)) >> 56); \ + (a)[1] = (u8) (((u64) (val)) >> 48); \ + (a)[2] = (u8) (((u64) (val)) >> 40); \ + (a)[3] = (u8) (((u64) (val)) >> 32); \ + (a)[4] = (u8) (((u64) (val)) >> 24); \ + (a)[5] = (u8) (((u64) (val)) >> 16); \ + (a)[6] = (u8) (((u64) (val)) >> 8); \ + (a)[7] = (u8) (((u64) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \ + (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \ + (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \ + (((u64) (a)[1]) << 8) | ((u64) (a)[0])) + + +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif +#ifndef ETH_P_ALL +#define ETH_P_ALL 0x0003 +#endif +#ifndef ETH_P_PAE +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#endif /* ETH_P_PAE */ +#ifndef ETH_P_EAPOL +#define ETH_P_EAPOL ETH_P_PAE +#endif /* ETH_P_EAPOL */ +#ifndef ETH_P_RSN_PREAUTH +#define ETH_P_RSN_PREAUTH 0x88c7 +#endif /* ETH_P_RSN_PREAUTH */ +#ifndef ETH_P_RRB +#define ETH_P_RRB 0x890D +#endif /* ETH_P_RRB */ + + +#ifdef __GNUC__ +#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b)))) +#define STRUCT_PACKED __attribute__ ((packed)) +#else +#define PRINTF_FORMAT(a,b) +#define STRUCT_PACKED +#endif + + +#ifdef CONFIG_ANSI_C_EXTRA + +#if !defined(_MSC_VER) || _MSC_VER < 1400 +/* snprintf - used in number of places; sprintf() is _not_ a good replacement + * due to possible buffer overflow; see, e.g., + * http://www.ijs.si/software/snprintf/ for portable implementation of + * snprintf. */ +int snprintf(char *str, size_t size, const char *format, ...); + +/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */ +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */ + +/* getopt - only used in main.c */ +int getopt(int argc, char *const argv[], const char *optstring); +extern char *optarg; +extern int optind; + +#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF +#ifndef __socklen_t_defined +typedef int socklen_t; +#endif +#endif + +/* inline - define as __inline or just define it to be empty, if needed */ +#ifdef CONFIG_NO_INLINE +#define inline +#else +#define inline __inline +#endif + +#ifndef __func__ +#define __func__ "__func__ not defined" +#endif + +#ifndef bswap_16 +#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff)) +#endif + +#ifndef bswap_32 +#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \ + (((u32) (a) << 8) & 0xff0000) | \ + (((u32) (a) >> 8) & 0xff00) | \ + (((u32) (a) >> 24) & 0xff)) +#endif + +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 +#endif + +#ifdef _WIN32_WCE +void perror(const char *s); +#endif /* _WIN32_WCE */ + +#endif /* CONFIG_ANSI_C_EXTRA */ + +#ifndef MAC2STR +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" +#endif + +#ifndef BIT +#define BIT(x) (1 << (x)) +#endif + +/* + * Definitions for sparse validation + * (http://kernel.org/pub/linux/kernel/people/josh/sparse/) + */ +#ifdef __CHECKER__ +#define __force __attribute__((force)) +#define __bitwise __attribute__((bitwise)) +#else +#define __force +#define __bitwise +#endif + +typedef u16 __bitwise be16; +typedef u16 __bitwise le16; +typedef u32 __bitwise be32; +typedef u32 __bitwise le32; +typedef u64 __bitwise be64; +typedef u64 __bitwise le64; + +#ifndef __must_check +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define __must_check __attribute__((__warn_unused_result__)) +#else +#define __must_check +#endif /* __GNUC__ */ +#endif /* __must_check */ + +int hwaddr_aton(const char *txt, u8 *addr); +int hexstr2bin(const char *hex, u8 *buf, size_t len); +void inc_byte_array(u8 *counter, size_t len); +void wpa_get_ntp_timestamp(u8 *buf); +int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); +int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, + size_t len); + +#ifdef CONFIG_NATIVE_WINDOWS +void wpa_unicode2ascii_inplace(TCHAR *str); +TCHAR * wpa_strdup_tchar(const char *str); +#else /* CONFIG_NATIVE_WINDOWS */ +#define wpa_unicode2ascii_inplace(s) do { } while (0) +#define wpa_strdup_tchar(s) strdup((s)) +#endif /* CONFIG_NATIVE_WINDOWS */ + +const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); + +static inline int is_zero_ether_addr(const u8 *a) +{ + return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]); +} + +#include "wpa_debug.h" + + +/* + * gcc 4.4 ends up generating strict-aliasing warnings about some very common + * networking socket uses that do not really result in a real problem and + * cannot be easily avoided with union-based type-punning due to struct + * definitions including another struct in system header files. To avoid having + * to fully disable strict-aliasing warnings, provide a mechanism to hide the + * typecast from aliasing for now. A cleaner solution will hopefully be found + * in the future to handle these cases. + */ +void * __hide_aliasing_typecast(void *foo); +#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a)) + +#endif /* COMMON_H */ diff --git a/cipher/rsa/includes.h b/cipher/rsa/includes.h new file mode 100644 index 0000000..63b5c23 --- /dev/null +++ b/cipher/rsa/includes.h @@ -0,0 +1,59 @@ +/* + * wpa_supplicant/hostapd - Default include files + * Copyright (c) 2005-2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * This header file is included into all C files so that commonly used header + * files can be selected with OS specific ifdef blocks in one place instead of + * having to have OS/C library specific selection in many files. + */ + +#ifndef INCLUDES_H +#define INCLUDES_H + +/* Include possible build time configuration before including anything else */ +#include "build_config.h" + +#include +#include +#include +#include +#ifndef _WIN32_WCE +#ifndef CONFIG_TI_COMPILER +#include +#include +#endif /* CONFIG_TI_COMPILER */ +#include +#endif /* _WIN32_WCE */ +#include +#include + +#ifndef CONFIG_TI_COMPILER +#ifndef _MSC_VER +#include +#endif /* _MSC_VER */ +#endif /* CONFIG_TI_COMPILER */ + +#ifndef CONFIG_NATIVE_WINDOWS +#ifndef CONFIG_TI_COMPILER +#include +#include +#include +#ifndef __vxworks +#ifndef __SYMBIAN32__ +#include +#endif /* __SYMBIAN32__ */ +#include +#endif /* __vxworks */ +#endif /* CONFIG_TI_COMPILER */ +#endif /* CONFIG_NATIVE_WINDOWS */ + +#endif /* INCLUDES_H */ diff --git a/cipher/rsa/libtommath.c b/cipher/rsa/libtommath.c new file mode 100644 index 0000000..1374264 --- /dev/null +++ b/cipher/rsa/libtommath.c @@ -0,0 +1,3381 @@ +/* + * Minimal code for RSA support from LibTomMath 0.41 + * http://libtom.org/ + * http://libtom.org/files/ltm-0.41.tar.bz2 + * This library was released in public domain by Tom St Denis. + * + * The combination in this file may not use all of the optimized algorithms + * from LibTomMath and may be considerable slower than the LibTomMath with its + * default settings. The main purpose of having this version here is to make it + * easier to build bignum.c wrapper without having to install and build an + * external library. + * + * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this + * libtommath.c file instead of using the external LibTomMath library. + */ + +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +#define BN_MP_INVMOD_C +#define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would + * require BN_MP_EXPTMOD_FAST_C instead */ +#define BN_S_MP_MUL_DIGS_C +#define BN_MP_INVMOD_SLOW_C +#define BN_S_MP_SQR_C +#define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this + * would require other than mp_reduce */ + +#ifdef LTM_FAST + +/* Use faster div at the cost of about 1 kB */ +#define BN_MP_MUL_D_C + +/* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */ +#define BN_MP_EXPTMOD_FAST_C +#define BN_MP_MONTGOMERY_SETUP_C +#define BN_FAST_MP_MONTGOMERY_REDUCE_C +#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C +#define BN_MP_MUL_2_C + +/* Include faster sqr at the cost of about 0.5 kB in code */ +#define BN_FAST_S_MP_SQR_C + +#else /* LTM_FAST */ + +#define BN_MP_DIV_SMALL +#define BN_MP_INIT_MULTI_C +#define BN_MP_CLEAR_MULTI_C +#define BN_MP_ABS_C +#endif /* LTM_FAST */ + +/* Current uses do not require support for negative exponent in exptmod, so we + * can save about 1.5 kB in leaving out invmod. */ +#define LTM_NO_NEG_EXP + +/* from tommath.h */ + +#ifndef MIN + #define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + +#ifndef MAX + #define MAX(x,y) ((x)>(y)?(x):(y)) +#endif + +#define OPT_CAST(x) + +typedef unsigned long mp_digit; +typedef u64 mp_word; + +#define DIGIT_BIT 28 +#define MP_28BIT + + +#define XMALLOC os_malloc +#define XFREE os_free +#define XREALLOC os_realloc + + +#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1)) + +#define MP_LT -1 /* less than */ +#define MP_EQ 0 /* equal to */ +#define MP_GT 1 /* greater than */ + +#define MP_ZPOS 0 /* positive integer */ +#define MP_NEG 1 /* negative */ + +#define MP_OKAY 0 /* ok result */ +#define MP_MEM -2 /* out of mem */ +#define MP_VAL -3 /* invalid input */ + +#define MP_YES 1 /* yes response */ +#define MP_NO 0 /* no response */ + +typedef int mp_err; + +/* define this to use lower memory usage routines (exptmods mostly) */ +#define MP_LOW_MEM + +/* default precision */ +#ifndef MP_PREC + #ifndef MP_LOW_MEM + #define MP_PREC 32 /* default digits of precision */ + #else + #define MP_PREC 8 /* default digits of precision */ + #endif +#endif + +/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */ +#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1)) + +/* the infamous mp_int structure */ +typedef struct { + int used, alloc, sign; + mp_digit *dp; +} mp_int; + + +/* ---> Basic Manipulations <--- */ +#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO) +#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO) +#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO) + + +/* prototypes for copied functions */ +#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) +static int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode); +static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); +static int s_mp_sqr(mp_int * a, mp_int * b); +static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs); + +static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); + +#ifdef BN_MP_INIT_MULTI_C +static int mp_init_multi(mp_int *mp, ...); +#endif +#ifdef BN_MP_CLEAR_MULTI_C +static void mp_clear_multi(mp_int *mp, ...); +#endif +static int mp_lshd(mp_int * a, int b); +static void mp_set(mp_int * a, mp_digit b); +static void mp_clamp(mp_int * a); +static void mp_exch(mp_int * a, mp_int * b); +static void mp_rshd(mp_int * a, int b); +static void mp_zero(mp_int * a); +static int mp_mod_2d(mp_int * a, int b, mp_int * c); +static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d); +static int mp_init_copy(mp_int * a, mp_int * b); +static int mp_mul_2d(mp_int * a, int b, mp_int * c); +#ifndef LTM_NO_NEG_EXP +static int mp_div_2(mp_int * a, mp_int * b); +static int mp_invmod(mp_int * a, mp_int * b, mp_int * c); +static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c); +#endif /* LTM_NO_NEG_EXP */ +static int mp_copy(mp_int * a, mp_int * b); +static int mp_count_bits(mp_int * a); +static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d); +static int mp_mod(mp_int * a, mp_int * b, mp_int * c); +static int mp_grow(mp_int * a, int size); +static int mp_cmp_mag(mp_int * a, mp_int * b); +#ifdef BN_MP_ABS_C +static int mp_abs(mp_int * a, mp_int * b); +#endif +static int mp_sqr(mp_int * a, mp_int * b); +static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d); +static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d); +static int mp_2expt(mp_int * a, int b); +static int mp_reduce_setup(mp_int * a, mp_int * b); +static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu); +static int mp_init_size(mp_int * a, int size); +#ifdef BN_MP_EXPTMOD_FAST_C +static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode); +#endif /* BN_MP_EXPTMOD_FAST_C */ +#ifdef BN_FAST_S_MP_SQR_C +static int fast_s_mp_sqr (mp_int * a, mp_int * b); +#endif /* BN_FAST_S_MP_SQR_C */ +#ifdef BN_MP_MUL_D_C +static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c); +#endif /* BN_MP_MUL_D_C */ + + + +/* functions from bn_.c */ + + +/* reverse an array, used for radix code */ +static void bn_reverse (unsigned char *s, int len) +{ + int ix, iy; + unsigned char t; + + ix = 0; + iy = len - 1; + while (ix < iy) { + t = s[ix]; + s[ix] = s[iy]; + s[iy] = t; + ++ix; + --iy; + } +} + + +/* low level addition, based on HAC pp.594, Algorithm 14.7 */ +static int s_mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int *x; + int olduse, res, min, max; + + /* find sizes, we let |a| <= |b| which means we have to sort + * them. "x" will point to the input with the most digits + */ + if (a->used > b->used) { + min = b->used; + max = a->used; + x = a; + } else { + min = a->used; + max = b->used; + x = b; + } + + /* init result */ + if (c->alloc < max + 1) { + if ((res = mp_grow (c, max + 1)) != MP_OKAY) { + return res; + } + } + + /* get old used digit count and set new one */ + olduse = c->used; + c->used = max + 1; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + + /* first input */ + tmpa = a->dp; + + /* second input */ + tmpb = b->dp; + + /* destination */ + tmpc = c->dp; + + /* zero the carry */ + u = 0; + for (i = 0; i < min; i++) { + /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ + *tmpc = *tmpa++ + *tmpb++ + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, that is in A+B + * if A or B has more digits add those in + */ + if (min != max) { + for (; i < max; i++) { + /* T[i] = X[i] + U */ + *tmpc = x->dp[i] + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + } + + /* add carry */ + *tmpc++ = u; + + /* clear digits above oldused */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + + +/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ +static int s_mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int olduse, res, min, max; + + /* find sizes */ + min = b->used; + max = a->used; + + /* init result */ + if (c->alloc < max) { + if ((res = mp_grow (c, max)) != MP_OKAY) { + return res; + } + } + olduse = c->used; + c->used = max; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + tmpa = a->dp; + tmpb = b->dp; + tmpc = c->dp; + + /* set carry to zero */ + u = 0; + for (i = 0; i < min; i++) { + /* T[i] = A[i] - B[i] - U */ + *tmpc = *tmpa++ - *tmpb++ - u; + + /* U = carry bit of T[i] + * Note this saves performing an AND operation since + * if a carry does occur it will propagate all the way to the + * MSB. As a result a single shift is enough to get the carry + */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, e.g. if A has more digits than B */ + for (; i < max; i++) { + /* T[i] = A[i] - U */ + *tmpc = *tmpa++ - u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* clear digits above used (since we may not have grown result above) */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + + +/* init a new mp_int */ +static int mp_init (mp_int * a) +{ + int i; + + /* allocate memory required and clear it */ + a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the digits to zero */ + for (i = 0; i < MP_PREC; i++) { + a->dp[i] = 0; + } + + /* set the used to zero, allocated digits to the default precision + * and sign to positive */ + a->used = 0; + a->alloc = MP_PREC; + a->sign = MP_ZPOS; + + return MP_OKAY; +} + + +/* clear one (frees) */ +static void mp_clear (mp_int * a) +{ + int i; + + /* only do anything if a hasn't been freed previously */ + if (a->dp != NULL) { + /* first zero the digits */ + for (i = 0; i < a->used; i++) { + a->dp[i] = 0; + } + + /* free ram */ + XFREE(a->dp); + + /* reset members to make debugging easier */ + a->dp = NULL; + a->alloc = a->used = 0; + a->sign = MP_ZPOS; + } +} + + +/* high level addition (handles signs) */ +static int mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + /* get sign of both inputs */ + sa = a->sign; + sb = b->sign; + + /* handle two cases, not four */ + if (sa == sb) { + /* both positive or both negative */ + /* add their magnitudes, copy the sign */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* one positive, the other negative */ + /* subtract the one with the greater magnitude from */ + /* the one of the lesser magnitude. The result gets */ + /* the sign of the one with the greater magnitude. */ + if (mp_cmp_mag (a, b) == MP_LT) { + c->sign = sb; + res = s_mp_sub (b, a, c); + } else { + c->sign = sa; + res = s_mp_sub (a, b, c); + } + } + return res; +} + + +/* high level subtraction (handles signs) */ +static int mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + sa = a->sign; + sb = b->sign; + + if (sa != sb) { + /* subtract a negative from a positive, OR */ + /* subtract a positive from a negative. */ + /* In either case, ADD their magnitudes, */ + /* and use the sign of the first number. */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* subtract a positive from a positive, OR */ + /* subtract a negative from a negative. */ + /* First, take the difference between their */ + /* magnitudes, then... */ + if (mp_cmp_mag (a, b) != MP_LT) { + /* Copy the sign from the first */ + c->sign = sa; + /* The first has a larger or equal magnitude */ + res = s_mp_sub (a, b, c); + } else { + /* The result has the *opposite* sign from */ + /* the first number. */ + c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; + /* The second has a larger magnitude */ + res = s_mp_sub (b, a, c); + } + } + return res; +} + + +/* high level multiplication (handles sign) */ +static int mp_mul (mp_int * a, mp_int * b, mp_int * c) +{ + int res, neg; + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + + /* use Toom-Cook? */ +#ifdef BN_MP_TOOM_MUL_C + if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) { + res = mp_toom_mul(a, b, c); + } else +#endif +#ifdef BN_MP_KARATSUBA_MUL_C + /* use Karatsuba? */ + if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) { + res = mp_karatsuba_mul (a, b, c); + } else +#endif + { + /* can we use the fast multiplier? + * + * The fast multiplier can be used if the output will + * have less than MP_WARRAY digits and the number of + * digits won't affect carry propagation + */ +#ifdef BN_FAST_S_MP_MUL_DIGS_C + int digs = a->used + b->used + 1; + + if ((digs < MP_WARRAY) && + MIN(a->used, b->used) <= + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + res = fast_s_mp_mul_digs (a, b, c, digs); + } else +#endif +#ifdef BN_S_MP_MUL_DIGS_C + res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */ +#else +#error mp_mul could fail + res = MP_VAL; +#endif + + } + c->sign = (c->used > 0) ? neg : MP_ZPOS; + return res; +} + + +/* d = a * b (mod c) */ +static int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_mul (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + + +/* c = a mod b, 0 <= c < b */ +static int mp_mod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int t; + int res; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + if (t.sign != b->sign) { + res = mp_add (b, &t, c); + } else { + res = MP_OKAY; + mp_exch (&t, c); + } + + mp_clear (&t); + return res; +} + + +/* this is a shell function that calls either the normal or Montgomery + * exptmod functions. Originally the call to the montgomery code was + * embedded in the normal function but that wasted alot of stack space + * for nothing (since 99% of the time the Montgomery code would be called) + */ +static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +{ + int dr; + + /* modulus P must be positive */ + if (P->sign == MP_NEG) { + return MP_VAL; + } + + /* if exponent X is negative we have to recurse */ + if (X->sign == MP_NEG) { +#ifdef LTM_NO_NEG_EXP + return MP_VAL; +#else /* LTM_NO_NEG_EXP */ +#ifdef BN_MP_INVMOD_C + mp_int tmpG, tmpX; + int err; + + /* first compute 1/G mod P */ + if ((err = mp_init(&tmpG)) != MP_OKAY) { + return err; + } + if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + + /* now get |X| */ + if ((err = mp_init(&tmpX)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + /* and now compute (1/G)**|X| instead of G**X [X < 0] */ + err = mp_exptmod(&tmpG, &tmpX, P, Y); + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; +#else +#error mp_exptmod would always fail + /* no invmod */ + return MP_VAL; +#endif +#endif /* LTM_NO_NEG_EXP */ + } + +/* modified diminished radix reduction */ +#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C) + if (mp_reduce_is_2k_l(P) == MP_YES) { + return s_mp_exptmod(G, X, P, Y, 1); + } +#endif + +#ifdef BN_MP_DR_IS_MODULUS_C + /* is it a DR modulus? */ + dr = mp_dr_is_modulus(P); +#else + /* default to no */ + dr = 0; +#endif + +#ifdef BN_MP_REDUCE_IS_2K_C + /* if not, is it a unrestricted DR modulus? */ + if (dr == 0) { + dr = mp_reduce_is_2k(P) << 1; + } +#endif + + /* if the modulus is odd or dr != 0 use the montgomery method */ +#ifdef BN_MP_EXPTMOD_FAST_C + if (mp_isodd (P) == 1 || dr != 0) { + return mp_exptmod_fast (G, X, P, Y, dr); + } else { +#endif +#ifdef BN_S_MP_EXPTMOD_C + /* otherwise use the generic Barrett reduction technique */ + return s_mp_exptmod (G, X, P, Y, 0); +#else +#error mp_exptmod could fail + /* no exptmod for evens */ + return MP_VAL; +#endif +#ifdef BN_MP_EXPTMOD_FAST_C + } +#endif +} + + +/* compare two ints (signed)*/ +static int mp_cmp (mp_int * a, mp_int * b) +{ + /* compare based on sign */ + if (a->sign != b->sign) { + if (a->sign == MP_NEG) { + return MP_LT; + } else { + return MP_GT; + } + } + + /* compare digits */ + if (a->sign == MP_NEG) { + /* if negative compare opposite direction */ + return mp_cmp_mag(b, a); + } else { + return mp_cmp_mag(a, b); + } +} + + +/* compare a digit */ +static int mp_cmp_d(mp_int * a, mp_digit b) +{ + /* compare based on sign */ + if (a->sign == MP_NEG) { + return MP_LT; + } + + /* compare based on magnitude */ + if (a->used > 1) { + return MP_GT; + } + + /* compare the only digit of a to b */ + if (a->dp[0] > b) { + return MP_GT; + } else if (a->dp[0] < b) { + return MP_LT; + } else { + return MP_EQ; + } +} + + +#ifndef LTM_NO_NEG_EXP +/* hac 14.61, pp608 */ +static int mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + +#ifdef BN_FAST_MP_INVMOD_C + /* if the modulus is odd we can use a faster routine instead */ + if (mp_isodd (b) == 1) { + return fast_mp_invmod (a, b, c); + } +#endif + +#ifdef BN_MP_INVMOD_SLOW_C + return mp_invmod_slow(a, b, c); +#endif + +#ifndef BN_FAST_MP_INVMOD_C +#ifndef BN_MP_INVMOD_SLOW_C +#error mp_invmod would always fail +#endif +#endif + return MP_VAL; +} +#endif /* LTM_NO_NEG_EXP */ + + +/* get the size for an unsigned equivalent */ +static int mp_unsigned_bin_size (mp_int * a) +{ + int size = mp_count_bits (a); + return (size / 8 + ((size & 7) != 0 ? 1 : 0)); +} + + +#ifndef LTM_NO_NEG_EXP +/* hac 14.61, pp608 */ +static int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, A, B, C, D; + int res; + + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + + /* init temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, + &A, &B, &C, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x = a, y = b */ + if ((res = mp_mod(a, b, &x)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (b, &y)) != MP_OKAY) { + goto LBL_ERR; + } + + /* 2. [modified] if x,y are both even then return an error! */ + if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { + res = MP_VAL; + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto LBL_ERR; + } + mp_set (&A, 1); + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto LBL_ERR; + } + /* 4.2 if A or B is odd then */ + if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) { + /* A = (A+y)/2, B = (B-x)/2 */ + if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* A = A/2, B = B/2 */ + if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto LBL_ERR; + } + /* 5.2 if C or D is odd then */ + if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) { + /* C = (C+y)/2, D = (D-x)/2 */ + if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* C = C/2, D = D/2 */ + if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, A = A - C, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } else { + /* v - v - u, C = C - A, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) + goto top; + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto LBL_ERR; + } + + /* if its too low */ + while (mp_cmp_d(&C, 0) == MP_LT) { + if ((res = mp_add(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* too big */ + while (mp_cmp_mag(&C, b) != MP_LT) { + if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* C is now the inverse */ + mp_exch (&C, c); + res = MP_OKAY; +LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); + return res; +} +#endif /* LTM_NO_NEG_EXP */ + + +/* compare maginitude of two ints (unsigned) */ +static int mp_cmp_mag (mp_int * a, mp_int * b) +{ + int n; + mp_digit *tmpa, *tmpb; + + /* compare based on # of non-zero digits */ + if (a->used > b->used) { + return MP_GT; + } + + if (a->used < b->used) { + return MP_LT; + } + + /* alias for a */ + tmpa = a->dp + (a->used - 1); + + /* alias for b */ + tmpb = b->dp + (a->used - 1); + + /* compare based on digits */ + for (n = 0; n < a->used; ++n, --tmpa, --tmpb) { + if (*tmpa > *tmpb) { + return MP_GT; + } + + if (*tmpa < *tmpb) { + return MP_LT; + } + } + return MP_EQ; +} + + +/* reads a unsigned char array, assumes the msb is stored first [big endian] */ +static int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c) +{ + int res; + + /* make sure there are at least two digits */ + if (a->alloc < 2) { + if ((res = mp_grow(a, 2)) != MP_OKAY) { + return res; + } + } + + /* zero the int */ + mp_zero (a); + + /* read the bytes in */ + while (c-- > 0) { + if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { + return res; + } + +#ifndef MP_8BIT + a->dp[0] |= *b++; + a->used += 1; +#else + a->dp[0] = (*b & MP_MASK); + a->dp[1] |= ((*b++ >> 7U) & 1); + a->used += 2; +#endif + } + mp_clamp (a); + return MP_OKAY; +} + + +/* store in unsigned [big endian] format */ +static int mp_to_unsigned_bin (mp_int * a, unsigned char *b) +{ + int x, res; + mp_int t; + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + x = 0; + while (mp_iszero (&t) == 0) { +#ifndef MP_8BIT + b[x++] = (unsigned char) (t.dp[0] & 255); +#else + b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7)); +#endif + if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + bn_reverse (b, x); + mp_clear (&t); + return MP_OKAY; +} + + +/* shift right by a certain bit count (store quotient in c, optional remainder in d) */ +static int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) +{ + mp_digit D, r, rr; + int x, res; + mp_int t; + + + /* if the shift count is <= 0 then we do no work */ + if (b <= 0) { + res = mp_copy (a, c); + if (d != NULL) { + mp_zero (d); + } + return res; + } + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + /* get the remainder */ + if (d != NULL) { + if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + mp_rshd (c, b / DIGIT_BIT); + } + + /* shift any bit count < DIGIT_BIT */ + D = (mp_digit) (b % DIGIT_BIT); + if (D != 0) { + register mp_digit *tmpc, mask, shift; + + /* mask */ + mask = (((mp_digit)1) << D) - 1; + + /* shift for lsb */ + shift = DIGIT_BIT - D; + + /* alias */ + tmpc = c->dp + (c->used - 1); + + /* carry */ + r = 0; + for (x = c->used - 1; x >= 0; x--) { + /* get the lower bits of this word in a temp */ + rr = *tmpc & mask; + + /* shift the current word and mix in the carry bits from the previous word */ + *tmpc = (*tmpc >> D) | (r << shift); + --tmpc; + + /* set the carry to the carry bits of the current word found above */ + r = rr; + } + } + mp_clamp (c); + if (d != NULL) { + mp_exch (&t, d); + } + mp_clear (&t); + return MP_OKAY; +} + + +static int mp_init_copy (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_init (a)) != MP_OKAY) { + return res; + } + return mp_copy (b, a); +} + + +/* set to zero */ +static void mp_zero (mp_int * a) +{ + int n; + mp_digit *tmp; + + a->sign = MP_ZPOS; + a->used = 0; + + tmp = a->dp; + for (n = 0; n < a->alloc; n++) { + *tmp++ = 0; + } +} + + +/* copy, b = a */ +static int mp_copy (mp_int * a, mp_int * b) +{ + int res, n; + + /* if dst == src do nothing */ + if (a == b) { + return MP_OKAY; + } + + /* grow dest */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + /* zero b and copy the parameters over */ + { + register mp_digit *tmpa, *tmpb; + + /* pointer aliases */ + + /* source */ + tmpa = a->dp; + + /* destination */ + tmpb = b->dp; + + /* copy all the digits */ + for (n = 0; n < a->used; n++) { + *tmpb++ = *tmpa++; + } + + /* clear high digits */ + for (; n < b->used; n++) { + *tmpb++ = 0; + } + } + + /* copy used count and sign */ + b->used = a->used; + b->sign = a->sign; + return MP_OKAY; +} + + +/* shift right a certain amount of digits */ +static void mp_rshd (mp_int * a, int b) +{ + int x; + + /* if b <= 0 then ignore it */ + if (b <= 0) { + return; + } + + /* if b > used then simply zero it and return */ + if (a->used <= b) { + mp_zero (a); + return; + } + + { + register mp_digit *bottom, *top; + + /* shift the digits down */ + + /* bottom */ + bottom = a->dp; + + /* top [offset into digits] */ + top = a->dp + b; + + /* this is implemented as a sliding window where + * the window is b-digits long and digits from + * the top of the window are copied to the bottom + * + * e.g. + + b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> + /\ | ----> + \-------------------/ ----> + */ + for (x = 0; x < (a->used - b); x++) { + *bottom++ = *top++; + } + + /* zero the top digits */ + for (; x < a->used; x++) { + *bottom++ = 0; + } + } + + /* remove excess digits */ + a->used -= b; +} + + +/* swap the elements of two integers, for cases where you can't simply swap the + * mp_int pointers around + */ +static void mp_exch (mp_int * a, mp_int * b) +{ + mp_int t; + + t = *a; + *a = *b; + *b = t; +} + + +/* trim unused digits + * + * This is used to ensure that leading zero digits are + * trimed and the leading "used" digit will be non-zero + * Typically very fast. Also fixes the sign if there + * are no more leading digits + */ +static void mp_clamp (mp_int * a) +{ + /* decrease used while the most significant digit is + * zero. + */ + while (a->used > 0 && a->dp[a->used - 1] == 0) { + --(a->used); + } + + /* reset the sign flag if used == 0 */ + if (a->used == 0) { + a->sign = MP_ZPOS; + } +} + + +/* grow as required */ +static int mp_grow (mp_int * a, int size) +{ + int i; + mp_digit *tmp; + + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + /* ensure there are always at least MP_PREC digits extra on top */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* reallocate the array a->dp + * + * We store the return in a temporary variable + * in case the operation failed we don't want + * to overwrite the dp member of a. + */ + tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size); + if (tmp == NULL) { + /* reallocation failed but "a" is still valid [can be freed] */ + return MP_MEM; + } + + /* reallocation succeeded so set a->dp */ + a->dp = tmp; + + /* zero excess digits */ + i = a->alloc; + a->alloc = size; + for (; i < a->alloc; i++) { + a->dp[i] = 0; + } + } + return MP_OKAY; +} + + +#ifdef BN_MP_ABS_C +/* b = |a| + * + * Simple function copies the input and fixes the sign to positive + */ +static int mp_abs (mp_int * a, mp_int * b) +{ + int res; + + /* copy a to b */ + if (a != b) { + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + } + + /* force the sign of b to positive */ + b->sign = MP_ZPOS; + + return MP_OKAY; +} +#endif + + +/* set to a digit */ +static void mp_set (mp_int * a, mp_digit b) +{ + mp_zero (a); + a->dp[0] = b & MP_MASK; + a->used = (a->dp[0] != 0) ? 1 : 0; +} + + +#ifndef LTM_NO_NEG_EXP +/* b = a/2 */ +static int mp_div_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* copy */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* source alias */ + tmpa = a->dp + b->used - 1; + + /* dest alias */ + tmpb = b->dp + b->used - 1; + + /* carry */ + r = 0; + for (x = b->used - 1; x >= 0; x--) { + /* get the carry for the next iteration */ + rr = *tmpa & 1; + + /* shift the current digit, add in carry and store */ + *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); + + /* forward carry to next iteration */ + r = rr; + } + + /* zero excess digits */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + mp_clamp (b); + return MP_OKAY; +} +#endif /* LTM_NO_NEG_EXP */ + + +/* shift left by a certain bit count */ +static int mp_mul_2d (mp_int * a, int b, mp_int * c) +{ + mp_digit d; + int res; + + /* copy */ + if (a != c) { + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + } + + if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) { + if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { + return res; + } + } + + /* shift any bit count < DIGIT_BIT */ + d = (mp_digit) (b % DIGIT_BIT); + if (d != 0) { + register mp_digit *tmpc, shift, mask, r, rr; + register int x; + + /* bitmask for carries */ + mask = (((mp_digit)1) << d) - 1; + + /* shift for msbs */ + shift = DIGIT_BIT - d; + + /* alias */ + tmpc = c->dp; + + /* carry */ + r = 0; + for (x = 0; x < c->used; x++) { + /* get the higher bits of the current word */ + rr = (*tmpc >> shift) & mask; + + /* shift the current word and OR in the carry */ + *tmpc = ((*tmpc << d) | r) & MP_MASK; + ++tmpc; + + /* set the carry to the carry bits of the current word */ + r = rr; + } + + /* set final carry */ + if (r != 0) { + c->dp[(c->used)++] = r; + } + } + mp_clamp (c); + return MP_OKAY; +} + + +#ifdef BN_MP_INIT_MULTI_C +static int mp_init_multi(mp_int *mp, ...) +{ + mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ + int n = 0; /* Number of ok inits */ + mp_int* cur_arg = mp; + va_list args; + + va_start(args, mp); /* init args to next argument from caller */ + while (cur_arg != NULL) { + if (mp_init(cur_arg) != MP_OKAY) { + /* Oops - error! Back-track and mp_clear what we already + succeeded in init-ing, then return error. + */ + va_list clean_args; + + /* end the current list */ + va_end(args); + + /* now start cleaning up */ + cur_arg = mp; + va_start(clean_args, mp); + while (n--) { + mp_clear(cur_arg); + cur_arg = va_arg(clean_args, mp_int*); + } + va_end(clean_args); + res = MP_MEM; + break; + } + n++; + cur_arg = va_arg(args, mp_int*); + } + va_end(args); + return res; /* Assumed ok, if error flagged above. */ +} +#endif + + +#ifdef BN_MP_CLEAR_MULTI_C +static void mp_clear_multi(mp_int *mp, ...) +{ + mp_int* next_mp = mp; + va_list args; + va_start(args, mp); + while (next_mp != NULL) { + mp_clear(next_mp); + next_mp = va_arg(args, mp_int*); + } + va_end(args); +} +#endif + + +/* shift left a certain amount of digits */ +static int mp_lshd (mp_int * a, int b) +{ + int x, res; + + /* if its less than zero return */ + if (b <= 0) { + return MP_OKAY; + } + + /* grow to fit the new digits */ + if (a->alloc < a->used + b) { + if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { + return res; + } + } + + { + register mp_digit *top, *bottom; + + /* increment the used by the shift amount then copy upwards */ + a->used += b; + + /* top */ + top = a->dp + a->used - 1; + + /* base */ + bottom = a->dp + a->used - 1 - b; + + /* much like mp_rshd this is implemented using a sliding window + * except the window goes the otherway around. Copying from + * the bottom to the top. see bn_mp_rshd.c for more info. + */ + for (x = a->used - 1; x >= b; x--) { + *top-- = *bottom--; + } + + /* zero the lower digits */ + top = a->dp; + for (x = 0; x < b; x++) { + *top++ = 0; + } + } + return MP_OKAY; +} + + +/* returns the number of bits in an int */ +static int mp_count_bits (mp_int * a) +{ + int r; + mp_digit q; + + /* shortcut */ + if (a->used == 0) { + return 0; + } + + /* get number of digits and add that */ + r = (a->used - 1) * DIGIT_BIT; + + /* take the last digit and count the bits in it */ + q = a->dp[a->used - 1]; + while (q > ((mp_digit) 0)) { + ++r; + q >>= ((mp_digit) 1); + } + return r; +} + + +/* calc a value mod 2**b */ +static int mp_mod_2d (mp_int * a, int b, mp_int * c) +{ + int x, res; + + /* if b is <= 0 then zero the int */ + if (b <= 0) { + mp_zero (c); + return MP_OKAY; + } + + /* if the modulus is larger than the value than return */ + if (b >= (int) (a->used * DIGIT_BIT)) { + res = mp_copy (a, c); + return res; + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + + /* zero digits above the last digit of the modulus */ + for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { + c->dp[x] = 0; + } + /* clear the digit that is not completely outside/inside the modulus */ + c->dp[b / DIGIT_BIT] &= + (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); + mp_clamp (c); + return MP_OKAY; +} + + +#ifdef BN_MP_DIV_SMALL + +/* slower bit-bang division... also smaller */ +static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int ta, tb, tq, q; + int res, n, n2; + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + /* init our temps */ + if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) { + return res; + } + + + mp_set(&tq, 1); + n = mp_count_bits(a) - mp_count_bits(b); + if (((res = mp_abs(a, &ta)) != MP_OKAY) || + ((res = mp_abs(b, &tb)) != MP_OKAY) || + ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) || + ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) { + goto LBL_ERR; + } + + while (n-- >= 0) { + if (mp_cmp(&tb, &ta) != MP_GT) { + if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) || + ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) { + goto LBL_ERR; + } + } + if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) || + ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) { + goto LBL_ERR; + } + } + + /* now q == quotient and ta == remainder */ + n = a->sign; + n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG); + if (c != NULL) { + mp_exch(c, &q); + c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2; + } + if (d != NULL) { + mp_exch(d, &ta); + d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n; + } +LBL_ERR: + mp_clear_multi(&ta, &tb, &tq, &q, NULL); + return res; +} + +#else + +/* integer signed division. + * c*b + d == a [e.g. a/b, c=quotient, d=remainder] + * HAC pp.598 Algorithm 14.20 + * + * Note that the description in HAC is horribly + * incomplete. For example, it doesn't consider + * the case where digits are removed from 'x' in + * the inner loop. It also doesn't consider the + * case that y has fewer than three digits, etc.. + * + * The overall algorithm is as described as + * 14.20 from HAC but fixed to treat these cases. +*/ +static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int q, x, y, t1, t2; + int res, n, t, i, norm, neg; + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { + return res; + } + q.used = a->used + 2; + + if ((res = mp_init (&t1)) != MP_OKAY) { + goto LBL_Q; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto LBL_T1; + } + + if ((res = mp_init_copy (&x, a)) != MP_OKAY) { + goto LBL_T2; + } + + if ((res = mp_init_copy (&y, b)) != MP_OKAY) { + goto LBL_X; + } + + /* fix the sign */ + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + x.sign = y.sign = MP_ZPOS; + + /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ + norm = mp_count_bits(&y) % DIGIT_BIT; + if (norm < (int)(DIGIT_BIT-1)) { + norm = (DIGIT_BIT-1) - norm; + if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) { + goto LBL_Y; + } + } else { + norm = 0; + } + + /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ + n = x.used - 1; + t = y.used - 1; + + /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ + if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */ + goto LBL_Y; + } + + while (mp_cmp (&x, &y) != MP_LT) { + ++(q.dp[n - t]); + if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) { + goto LBL_Y; + } + } + + /* reset y by shifting it back down */ + mp_rshd (&y, n - t); + + /* step 3. for i from n down to (t + 1) */ + for (i = n; i >= (t + 1); i--) { + if (i > x.used) { + continue; + } + + /* step 3.1 if xi == yt then set q{i-t-1} to b-1, + * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ + if (x.dp[i] == y.dp[t]) { + q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); + } else { + mp_word tmp; + tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); + tmp |= ((mp_word) x.dp[i - 1]); + tmp /= ((mp_word) y.dp[t]); + if (tmp > (mp_word) MP_MASK) + tmp = MP_MASK; + q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); + } + + /* while (q{i-t-1} * (yt * b + y{t-1})) > + xi * b**2 + xi-1 * b + xi-2 + + do q{i-t-1} -= 1; + */ + q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; + do { + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; + + /* find left hand */ + mp_zero (&t1); + t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; + t1.dp[1] = y.dp[t]; + t1.used = 2; + if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto LBL_Y; + } + + /* find right hand */ + t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; + t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; + t2.dp[2] = x.dp[i]; + t2.used = 3; + } while (mp_cmp_mag(&t1, &t2) == MP_GT); + + /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ + if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto LBL_Y; + } + + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto LBL_Y; + } + + if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) { + goto LBL_Y; + } + + /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ + if (x.sign == MP_NEG) { + if ((res = mp_copy (&y, &t1)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { + goto LBL_Y; + } + + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; + } + } + + /* now q is the quotient and x is the remainder + * [which we have to normalize] + */ + + /* get sign before writing to c */ + x.sign = x.used == 0 ? MP_ZPOS : a->sign; + + if (c != NULL) { + mp_clamp (&q); + mp_exch (&q, c); + c->sign = neg; + } + + if (d != NULL) { + mp_div_2d (&x, norm, &x, NULL); + mp_exch (&x, d); + } + + res = MP_OKAY; + +LBL_Y:mp_clear (&y); +LBL_X:mp_clear (&x); +LBL_T2:mp_clear (&t2); +LBL_T1:mp_clear (&t1); +LBL_Q:mp_clear (&q); + return res; +} + +#endif + + +#ifdef MP_LOW_MEM + #define TAB_SIZE 32 +#else + #define TAB_SIZE 256 +#endif + +static int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res, mu; + mp_digit buf; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + int (*redux)(mp_int*,mp_int*,mp_int*); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* create mu, used for Barrett reduction */ + if ((err = mp_init (&mu)) != MP_OKAY) { + goto LBL_M; + } + + if (redmode == 0) { + if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { + goto LBL_MU; + } + redux = mp_reduce; + } else { + if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + redux = mp_reduce_2k_l; + } + + /* create M table + * + * The M table contains powers of the base, + * e.g. M[x] = G**x mod P + * + * The first half of the table is not + * computed though accept for M[0] and M[1] + */ + if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { + goto LBL_MU; + } + + /* compute the value at M[1<<(winsize-1)] by squaring + * M[1] (winsize-1) times + */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + for (x = 0; x < (winsize - 1); x++) { + /* square it */ + if ((err = mp_sqr (&M[1 << (winsize - 1)], + &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + /* reduce modulo P */ + if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* create upper table, that is M[x] = M[x-1] * M[1] (mod P) + * for x = (2**(winsize - 1) + 1) to (2**winsize - 1) + */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto LBL_MU; + } + if ((err = redux (&M[x], P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto LBL_MU; + } + mp_set (&res, 1); + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits */ + if (digidx == -1) { + break; + } + /* read next digit and reset the bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int) DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + } + } + } + + mp_exch (&res, Y); + err = MP_OKAY; +LBL_RES:mp_clear (&res); +LBL_MU:mp_clear (&mu); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + + +/* computes b = a*a */ +static int mp_sqr (mp_int * a, mp_int * b) +{ + int res; + +#ifdef BN_MP_TOOM_SQR_C + /* use Toom-Cook? */ + if (a->used >= TOOM_SQR_CUTOFF) { + res = mp_toom_sqr(a, b); + /* Karatsuba? */ + } else +#endif +#ifdef BN_MP_KARATSUBA_SQR_C +if (a->used >= KARATSUBA_SQR_CUTOFF) { + res = mp_karatsuba_sqr (a, b); + } else +#endif + { +#ifdef BN_FAST_S_MP_SQR_C + /* can we use the fast comba multiplier? */ + if ((a->used * 2 + 1) < MP_WARRAY && + a->used < + (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { + res = fast_s_mp_sqr (a, b); + } else +#endif +#ifdef BN_S_MP_SQR_C + res = s_mp_sqr (a, b); +#else +#error mp_sqr could fail + res = MP_VAL; +#endif + } + b->sign = MP_ZPOS; + return res; +} + + +/* reduces a modulo n where n is of the form 2**p - d + This differs from reduce_2k since "d" can be larger + than a single digit. +*/ +static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + /* q = q * d */ + if ((res = mp_mul(&q, d, &q)) != MP_OKAY) { + goto ERR; + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + + +/* determines the setup value */ +static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d) +{ + int res; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) { + goto ERR; + } + + if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear(&tmp); + return res; +} + + +/* computes a = 2**b + * + * Simple algorithm which zeroes the int, grows it then just sets one bit + * as required. + */ +static int mp_2expt (mp_int * a, int b) +{ + int res; + + /* zero a as per default */ + mp_zero (a); + + /* grow a to accomodate the single bit */ + if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + + /* set the used count of where the bit will go */ + a->used = b / DIGIT_BIT + 1; + + /* put the single bit in its place */ + a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT); + + return MP_OKAY; +} + + +/* pre-calculate the value required for Barrett reduction + * For a given modulus "b" it calulates the value required in "a" + */ +static int mp_reduce_setup (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { + return res; + } + return mp_div (a, b, a, NULL); +} + + +/* reduces x mod m, assumes 0 < x < m**2, mu is + * precomputed via mp_reduce_setup. + * From HAC pp.604 Algorithm 14.42 + */ +static int mp_reduce (mp_int * x, mp_int * m, mp_int * mu) +{ + mp_int q; + int res, um = m->used; + + /* q = x */ + if ((res = mp_init_copy (&q, x)) != MP_OKAY) { + return res; + } + + /* q1 = x / b**(k-1) */ + mp_rshd (&q, um - 1); + + /* according to HAC this optimization is ok */ + if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) { + if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { + goto CLEANUP; + } + } else { +#ifdef BN_S_MP_MUL_HIGH_DIGS_C + if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } +#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C) + if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } +#else + { +#error mp_reduce would always fail + res = MP_VAL; + goto CLEANUP; + } +#endif + } + + /* q3 = q2 / b**(k+1) */ + mp_rshd (&q, um + 1); + + /* x = x mod b**(k+1), quick (no division) */ + if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { + goto CLEANUP; + } + + /* q = q * m mod b**(k+1), quick (no division) */ + if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + + /* x = x - q */ + if ((res = mp_sub (x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + + /* If x < 0, add b**(k+1) to it */ + if (mp_cmp_d (x, 0) == MP_LT) { + mp_set (&q, 1); + if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + if ((res = mp_add (x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + } + + /* Back off if it's too big */ + while (mp_cmp (x, m) != MP_LT) { + if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { + goto CLEANUP; + } + } + +CLEANUP: + mp_clear (&q); + + return res; +} + + +/* multiplies |a| * |b| and only computes upto digs digits of result + * HAC pp. 595, Algorithm 14.12 Modified so you can control how + * many digits of output are created. + */ +static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (((digs) < MP_WARRAY) && + MIN (a->used, b->used) < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, digs)) != MP_OKAY) { + return res; + } + t.used = digs; + + /* compute the digits of the product directly */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { + /* set the carry to zero */ + u = 0; + + /* limit ourselves to making digs digits of output */ + pb = MIN (b->used, digs - ix); + + /* setup some aliases */ + /* copy of the digit from a used within the nested loop */ + tmpx = a->dp[ix]; + + /* an alias for the destination shifted ix places */ + tmpt = t.dp + ix; + + /* an alias for the digits of b */ + tmpy = b->dp; + + /* compute the columns of the output and propagate the carry */ + for (iy = 0; iy < pb; iy++) { + /* compute the column as a mp_word */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* the new column is the lower part of the result */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry word from the result */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + /* set carry if it is placed below digs */ + if (ix + iy < digs) { + *tmpt = u; + } + } + + mp_clamp (&t); + mp_exch (&t, c); + + mp_clear (&t); + return MP_OKAY; +} + + +/* Fast (comba) multiplier + * + * This is the fast column-array [comba] multiplier. It is + * designed to compute the columns of the product first + * then handle the carries afterwards. This has the effect + * of making the nested loops that compute the columns very + * simple and schedulable on super-scalar processors. + * + * This has been modified to produce a variable number of + * digits of output so if say only a half-product is required + * you don't have to compute the upper half (a feature + * required for fast Barrett reduction). + * + * Based on Algorithm 14.12 on pp.595 of HAC. + * + */ +static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY]; + register mp_word _W; + + /* grow the destination as required */ + if (c->alloc < digs) { + if ((res = mp_grow (c, digs)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + pa = MIN(digs, a->used + b->used); + + /* clear the carry */ + _W = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty; + int iy; + mp_digit *tmpx, *tmpy; + + /* get offsets into the two bignums */ + ty = MIN(b->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = b->dp + ty; + + /* this is the number of times the loop will iterrate, essentially + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(a->used-tx, ty+1); + + /* execute loop */ + for (iz = 0; iz < iy; ++iz) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + + } + + /* store term */ + W[ix] = ((mp_digit)_W) & MP_MASK; + + /* make next carry */ + _W = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + register mp_digit *tmpc; + tmpc = c->dp; + for (ix = 0; ix < pa+1; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + mp_clamp (c); + return MP_OKAY; +} + + +/* init an mp_init for a given size */ +static int mp_init_size (mp_int * a, int size) +{ + int x; + + /* pad size so there are always extra digits */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* alloc mem */ + a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the members */ + a->used = 0; + a->alloc = size; + a->sign = MP_ZPOS; + + /* zero the digits */ + for (x = 0; x < size; x++) { + a->dp[x] = 0; + } + + return MP_OKAY; +} + + +/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ +static int s_mp_sqr (mp_int * a, mp_int * b) +{ + mp_int t; + int res, ix, iy, pa; + mp_word r; + mp_digit u, tmpx, *tmpt; + + pa = a->used; + if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) { + return res; + } + + /* default used is maximum possible size */ + t.used = 2*pa + 1; + + for (ix = 0; ix < pa; ix++) { + /* first calculate the digit at 2*ix */ + /* calculate double precision result */ + r = ((mp_word) t.dp[2*ix]) + + ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]); + + /* store lower part in result */ + t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + + /* left hand side of A[ix] * A[iy] */ + tmpx = a->dp[ix]; + + /* alias for where to store the results */ + tmpt = t.dp + (2*ix + 1); + + for (iy = ix + 1; iy < pa; iy++) { + /* first calculate the product */ + r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]); + + /* now calculate the double precision result, note we use + * addition instead of *2 since it's easier to optimize + */ + r = ((mp_word) *tmpt) + r + r + ((mp_word) u); + + /* store lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + /* propagate upwards */ + while (u != ((mp_digit) 0)) { + r = ((mp_word) *tmpt) + ((mp_word) u); + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + } + + mp_clamp (&t); + mp_exch (&t, b); + mp_clear (&t); + return MP_OKAY; +} + + +/* multiplies |a| * |b| and does not compute the lower digs digits + * [meant to get the higher part of the product] + */ +static int s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ +#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C + if (((a->used + b->used + 1) < MP_WARRAY) + && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_high_digs (a, b, c, digs); + } +#endif + + if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { + return res; + } + t.used = a->used + b->used + 1; + + pa = a->used; + pb = b->used; + for (ix = 0; ix < pa; ix++) { + /* clear the carry */ + u = 0; + + /* left hand side of A[ix] * B[iy] */ + tmpx = a->dp[ix]; + + /* alias to the address of where the digits will be stored */ + tmpt = &(t.dp[digs]); + + /* alias for where to read the right hand side from */ + tmpy = b->dp + (digs - ix); + + for (iy = digs - ix; iy < pb; iy++) { + /* calculate the double precision result */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* get the lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* carry the carry */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + *tmpt = u; + } + mp_clamp (&t); + mp_exch (&t, c); + mp_clear (&t); + return MP_OKAY; +} + + +#ifdef BN_MP_MONTGOMERY_SETUP_C +/* setups the montgomery reduction stuff */ +static int +mp_montgomery_setup (mp_int * n, mp_digit * rho) +{ + mp_digit x, b; + +/* fast inversion mod 2**k + * + * Based on the fact that + * + * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) + * => 2*X*A - X*X*A*A = 1 + * => 2*(1) - (1) = 1 + */ + b = n->dp[0]; + + if ((b & 1) == 0) { + return MP_VAL; + } + + x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */ + x *= 2 - b * x; /* here x*a==1 mod 2**8 */ +#if !defined(MP_8BIT) + x *= 2 - b * x; /* here x*a==1 mod 2**16 */ +#endif +#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) + x *= 2 - b * x; /* here x*a==1 mod 2**32 */ +#endif +#ifdef MP_64BIT + x *= 2 - b * x; /* here x*a==1 mod 2**64 */ +#endif + + /* rho = -1/m mod b */ + *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK; + + return MP_OKAY; +} +#endif + + +#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C +/* computes xR**-1 == x (mod N) via Montgomery Reduction + * + * This is an optimized implementation of montgomery_reduce + * which uses the comba method to quickly calculate the columns of the + * reduction. + * + * Based on Algorithm 14.32 on pp.601 of HAC. +*/ +int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, olduse; + mp_word W[MP_WARRAY]; + + /* get old used count */ + olduse = x->used; + + /* grow a as required */ + if (x->alloc < n->used + 1) { + if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) { + return res; + } + } + + /* first we have to get the digits of the input into + * an array of double precision words W[...] + */ + { + register mp_word *_W; + register mp_digit *tmpx; + + /* alias for the W[] array */ + _W = W; + + /* alias for the digits of x*/ + tmpx = x->dp; + + /* copy the digits of a into W[0..a->used-1] */ + for (ix = 0; ix < x->used; ix++) { + *_W++ = *tmpx++; + } + + /* zero the high words of W[a->used..m->used*2] */ + for (; ix < n->used * 2 + 1; ix++) { + *_W++ = 0; + } + } + + /* now we proceed to zero successive digits + * from the least significant upwards + */ + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * m' mod b + * + * We avoid a double precision multiplication (which isn't required) + * by casting the value down to a mp_digit. Note this requires + * that W[ix-1] have the carry cleared (see after the inner loop) + */ + register mp_digit mu; + mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK); + + /* a = a + mu * m * b**i + * + * This is computed in place and on the fly. The multiplication + * by b**i is handled by offseting which columns the results + * are added to. + * + * Note the comba method normally doesn't handle carries in the + * inner loop In this case we fix the carry from the previous + * column since the Montgomery reduction requires digits of the + * result (so far) [see above] to work. This is + * handled by fixing up one carry after the inner loop. The + * carry fixups are done in order so after these loops the + * first m->used words of W[] have the carries fixed + */ + { + register int iy; + register mp_digit *tmpn; + register mp_word *_W; + + /* alias for the digits of the modulus */ + tmpn = n->dp; + + /* Alias for the columns set by an offset of ix */ + _W = W + ix; + + /* inner loop */ + for (iy = 0; iy < n->used; iy++) { + *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++); + } + } + + /* now fix carry for next digit, W[ix+1] */ + W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); + } + + /* now we have to propagate the carries and + * shift the words downward [all those least + * significant digits we zeroed]. + */ + { + register mp_digit *tmpx; + register mp_word *_W, *_W1; + + /* nox fix rest of carries */ + + /* alias for current word */ + _W1 = W + ix; + + /* alias for next word, where the carry goes */ + _W = W + ++ix; + + for (; ix <= n->used * 2 + 1; ix++) { + *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); + } + + /* copy out, A = A/b**n + * + * The result is A/b**n but instead of converting from an + * array of mp_word to mp_digit than calling mp_rshd + * we just copy them in the right order + */ + + /* alias for destination word */ + tmpx = x->dp; + + /* alias for shifted double precision result */ + _W = W + n->used; + + for (ix = 0; ix < n->used + 1; ix++) { + *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK)); + } + + /* zero oldused digits, if the input a was larger than + * m->used+1 we'll have to clear the digits + */ + for (; ix < olduse; ix++) { + *tmpx++ = 0; + } + } + + /* set the max used and clamp */ + x->used = n->used + 1; + mp_clamp (x); + + /* if A >= m then A = A - m */ + if (mp_cmp_mag (x, n) != MP_LT) { + return s_mp_sub (x, n, x); + } + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_MUL_2_C +/* b = a*2 */ +static int mp_mul_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* grow to accomodate result */ + if (b->alloc < a->used + 1) { + if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* alias for source */ + tmpa = a->dp; + + /* alias for dest */ + tmpb = b->dp; + + /* carry */ + r = 0; + for (x = 0; x < a->used; x++) { + + /* get what will be the *next* carry bit from the + * MSB of the current digit + */ + rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1)); + + /* now shift up this digit, add in the carry [from the previous] */ + *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; + + /* copy the carry that would be from the source + * digit into the next iteration + */ + r = rr; + } + + /* new leading digit? */ + if (r != 0) { + /* add a MSB which is always 1 at this point */ + *tmpb = 1; + ++(b->used); + } + + /* now zero any excess digits on the destination + * that we didn't write to + */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C +/* + * shifts with subtractions when the result is greater than b. + * + * The method is slightly modified to shift B unconditionally upto just under + * the leading bit of b. This saves alot of multiple precision shifting. + */ +static int mp_montgomery_calc_normalization (mp_int * a, mp_int * b) +{ + int x, bits, res; + + /* how many bits of last digit does b use */ + bits = mp_count_bits (b) % DIGIT_BIT; + + if (b->used > 1) { + if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { + return res; + } + } else { + mp_set(a, 1); + bits = 1; + } + + + /* now compute C = A * B mod b */ + for (x = bits - 1; x < (int)DIGIT_BIT; x++) { + if ((res = mp_mul_2 (a, a)) != MP_OKAY) { + return res; + } + if (mp_cmp_mag (a, b) != MP_LT) { + if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { + return res; + } + } + } + + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_EXPTMOD_FAST_C +/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85 + * + * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. + * The value of k changes based on the size of the exponent. + * + * Uses Montgomery or Diminished Radix reduction [whichever appropriate] + */ + +static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res; + mp_digit buf, mp; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* use a pointer to the reduction algorithm. This allows us to use + * one of many reduction algorithms without modding the guts of + * the code with if statements everywhere. + */ + int (*redux)(mp_int*,mp_int*,mp_digit); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* determine and setup reduction code */ + if (redmode == 0) { +#ifdef BN_MP_MONTGOMERY_SETUP_C + /* now setup montgomery */ + if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { + goto LBL_M; + } +#else + err = MP_VAL; + goto LBL_M; +#endif + + /* automatically pick the comba one if available (saves quite a few calls/ifs) */ +#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C + if (((P->used * 2 + 1) < MP_WARRAY) && + P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + redux = fast_mp_montgomery_reduce; + } else +#endif + { +#ifdef BN_MP_MONTGOMERY_REDUCE_C + /* use slower baseline Montgomery method */ + redux = mp_montgomery_reduce; +#else + err = MP_VAL; + goto LBL_M; +#endif + } + } else if (redmode == 1) { +#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C) + /* setup DR reduction for moduli of the form B**k - b */ + mp_dr_setup(P, &mp); + redux = mp_dr_reduce; +#else + err = MP_VAL; + goto LBL_M; +#endif + } else { +#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C) + /* setup DR reduction for moduli of the form 2**k - b */ + if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) { + goto LBL_M; + } + redux = mp_reduce_2k; +#else + err = MP_VAL; + goto LBL_M; +#endif + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto LBL_M; + } + + /* create M table + * + + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ + + if (redmode == 0) { +#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C + /* now we need R mod m */ + if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { + goto LBL_RES; + } +#else + err = MP_VAL; + goto LBL_RES; +#endif + + /* now set M[1] to G * R mod m */ + if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { + goto LBL_RES; + } + } else { + mp_set(&res, 1); + if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { + goto LBL_RES; + } + } + + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&M[x], P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits so break */ + if (digidx == -1) { + break; + } + /* read next digit and reset bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int)DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + + /* get next bit of the window */ + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + } + } + + if (redmode == 0) { + /* fixup result if Montgomery reduction is used + * recall that any value in a Montgomery system is + * actually multiplied by R mod n. So we have + * to reduce one more time to cancel out the factor + * of R. + */ + if ((err = redux(&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* swap res with Y */ + mp_exch (&res, Y); + err = MP_OKAY; +LBL_RES:mp_clear (&res); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} +#endif + + +#ifdef BN_FAST_S_MP_SQR_C +/* the jist of squaring... + * you do like mult except the offset of the tmpx [one that + * starts closer to zero] can't equal the offset of tmpy. + * So basically you set up iy like before then you min it with + * (ty-tx) so that it never happens. You double all those + * you add in the inner loop + +After that loop you do the squares and add them in. +*/ + +static int fast_s_mp_sqr (mp_int * a, mp_int * b) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY], *tmpx; + mp_word W1; + + /* grow the destination as required */ + pa = a->used + a->used; + if (b->alloc < pa) { + if ((res = mp_grow (b, pa)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + W1 = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty, iy; + mp_word _W; + mp_digit *tmpy; + + /* clear counter */ + _W = 0; + + /* get offsets into the two bignums */ + ty = MIN(a->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = a->dp + ty; + + /* this is the number of times the loop will iterrate, essentially + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(a->used-tx, ty+1); + + /* now for squaring tx can never equal ty + * we halve the distance since they approach at a rate of 2x + * and we have to round because odd cases need to be executed + */ + iy = MIN(iy, (ty-tx+1)>>1); + + /* execute loop */ + for (iz = 0; iz < iy; iz++) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + } + + /* double the inner product and add carry */ + _W = _W + _W + W1; + + /* even columns have the square term in them */ + if ((ix&1) == 0) { + _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]); + } + + /* store it */ + W[ix] = (mp_digit)(_W & MP_MASK); + + /* make next carry */ + W1 = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = b->used; + b->used = a->used+a->used; + + { + mp_digit *tmpb; + tmpb = b->dp; + for (ix = 0; ix < pa; ix++) { + *tmpb++ = W[ix] & MP_MASK; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpb++ = 0; + } + } + mp_clamp (b); + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_MUL_D_C +/* multiply by a digit */ +static int +mp_mul_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_digit u, *tmpa, *tmpc; + mp_word r; + int ix, res, olduse; + + /* make sure c is big enough to hold a*b */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* get the original destinations used count */ + olduse = c->used; + + /* set the sign */ + c->sign = a->sign; + + /* alias for a->dp [source] */ + tmpa = a->dp; + + /* alias for c->dp [dest] */ + tmpc = c->dp; + + /* zero carry */ + u = 0; + + /* compute columns */ + for (ix = 0; ix < a->used; ix++) { + /* compute product and carry sum for this term */ + r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b); + + /* mask off higher bits to get a single digit */ + *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* send carry into next iteration */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + + /* store final carry [if any] and increment ix offset */ + *tmpc++ = u; + ++ix; + + /* now zero digits above the top */ + while (ix++ < olduse) { + *tmpc++ = 0; + } + + /* set used count */ + c->used = a->used + 1; + mp_clamp(c); + + return MP_OKAY; +} +#endif diff --git a/cipher/rsa/os.h b/cipher/rsa/os.h new file mode 100644 index 0000000..641a3ed --- /dev/null +++ b/cipher/rsa/os.h @@ -0,0 +1,512 @@ +/* + * OS specific functions + * Copyright (c) 2005-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef OS_H +#define OS_H + +#if defined(HPUX) +#define inline +#endif + +typedef long os_time_t; + +/** + * os_sleep - Sleep (sec, usec) + * @sec: Number of seconds to sleep + * @usec: Number of microseconds to sleep + */ +void os_sleep(os_time_t sec, os_time_t usec); + +struct os_time { + os_time_t sec; + os_time_t usec; +}; + +/** + * os_get_time - Get current time (sec, usec) + * @t: Pointer to buffer for the time + * Returns: 0 on success, -1 on failure + */ +int os_get_time(struct os_time *t); + + +/* Helper macros for handling struct os_time */ + +#define os_time_before(a, b) \ + ((a)->sec < (b)->sec || \ + ((a)->sec == (b)->sec && (a)->usec < (b)->usec)) + +#define os_time_sub(a, b, res) do { \ + (res)->sec = (a)->sec - (b)->sec; \ + (res)->usec = (a)->usec - (b)->usec; \ + if ((res)->usec < 0) { \ + (res)->sec--; \ + (res)->usec += 1000000; \ + } \ +} while (0) + +/** + * os_mktime - Convert broken-down time into seconds since 1970-01-01 + * @year: Four digit year + * @month: Month (1 .. 12) + * @day: Day of month (1 .. 31) + * @hour: Hour (0 .. 23) + * @min: Minute (0 .. 59) + * @sec: Second (0 .. 60) + * @t: Buffer for returning calendar time representation (seconds since + * 1970-01-01 00:00:00) + * Returns: 0 on success, -1 on failure + * + * Note: The result is in seconds from Epoch, i.e., in UTC, not in local time + * which is used by POSIX mktime(). + */ +int os_mktime(int year, int month, int day, int hour, int min, int sec, + os_time_t *t); + + +/** + * os_daemonize - Run in the background (detach from the controlling terminal) + * @pid_file: File name to write the process ID to or %NULL to skip this + * Returns: 0 on success, -1 on failure + */ +int os_daemonize(const char *pid_file); + +/** + * os_daemonize_terminate - Stop running in the background (remove pid file) + * @pid_file: File name to write the process ID to or %NULL to skip this + */ +void os_daemonize_terminate(const char *pid_file); + +/** + * os_get_random - Get cryptographically strong pseudo random data + * @buf: Buffer for pseudo random data + * @len: Length of the buffer + * Returns: 0 on success, -1 on failure + */ +int os_get_random(unsigned char *buf, size_t len); + +/** + * os_random - Get pseudo random value (not necessarily very strong) + * Returns: Pseudo random value + */ +unsigned long os_random(void); + +/** + * os_rel2abs_path - Get an absolute path for a file + * @rel_path: Relative path to a file + * Returns: Absolute path for the file or %NULL on failure + * + * This function tries to convert a relative path of a file to an absolute path + * in order for the file to be found even if current working directory has + * changed. The returned value is allocated and caller is responsible for + * freeing it. It is acceptable to just return the same path in an allocated + * buffer, e.g., return strdup(rel_path). This function is only used to find + * configuration files when os_daemonize() may have changed the current working + * directory and relative path would be pointing to a different location. + */ +char * os_rel2abs_path(const char *rel_path); + +/** + * os_program_init - Program initialization (called at start) + * Returns: 0 on success, -1 on failure + * + * This function is called when a programs starts. If there are any OS specific + * processing that is needed, it can be placed here. It is also acceptable to + * just return 0 if not special processing is needed. + */ +int os_program_init(void); + +/** + * os_program_deinit - Program deinitialization (called just before exit) + * + * This function is called just before a program exists. If there are any OS + * specific processing, e.g., freeing resourced allocated in os_program_init(), + * it should be done here. It is also acceptable for this function to do + * nothing. + */ +void os_program_deinit(void); + +/** + * os_setenv - Set environment variable + * @name: Name of the variable + * @value: Value to set to the variable + * @overwrite: Whether existing variable should be overwritten + * Returns: 0 on success, -1 on error + * + * This function is only used for wpa_cli action scripts. OS wrapper does not + * need to implement this if such functionality is not needed. + */ +int os_setenv(const char *name, const char *value, int overwrite); + +/** + * os_unsetenv - Delete environent variable + * @name: Name of the variable + * Returns: 0 on success, -1 on error + * + * This function is only used for wpa_cli action scripts. OS wrapper does not + * need to implement this if such functionality is not needed. + */ +int os_unsetenv(const char *name); + +/** + * os_readfile - Read a file to an allocated memory buffer + * @name: Name of the file to read + * @len: For returning the length of the allocated buffer + * Returns: Pointer to the allocated buffer or %NULL on failure + * + * This function allocates memory and reads the given file to this buffer. Both + * binary and text files can be read with this function. The caller is + * responsible for freeing the returned buffer with os_free(). + */ +char * os_readfile(const char *name, size_t *len); + +/** + * os_zalloc - Allocate and zero memory + * @size: Number of bytes to allocate + * Returns: Pointer to allocated and zeroed memory or %NULL on failure + * + * Caller is responsible for freeing the returned buffer with os_free(). + */ +void * os_zalloc(size_t size); + + +/* + * The following functions are wrapper for standard ANSI C or POSIX functions. + * By default, they are just defined to use the standard function name and no + * os_*.c implementation is needed for them. This avoids extra function calls + * by allowing the C pre-processor take care of the function name mapping. + * + * If the target system uses a C library that does not provide these functions, + * build_config.h can be used to define the wrappers to use a different + * function name. This can be done on function-by-function basis since the + * defines here are only used if build_config.h does not define the os_* name. + * If needed, os_*.c file can be used to implement the functions that are not + * included in the C library on the target system. Alternatively, + * OS_NO_C_LIB_DEFINES can be defined to skip all defines here in which case + * these functions need to be implemented in os_*.c file for the target system. + */ + +#ifdef OS_NO_C_LIB_DEFINES + +/** + * os_malloc - Allocate dynamic memory + * @size: Size of the buffer to allocate + * Returns: Allocated buffer or %NULL on failure + * + * Caller is responsible for freeing the returned buffer with os_free(). + */ +void * os_malloc(size_t size); + +/** + * os_realloc - Re-allocate dynamic memory + * @ptr: Old buffer from os_malloc() or os_realloc() + * @size: Size of the new buffer + * Returns: Allocated buffer or %NULL on failure + * + * Caller is responsible for freeing the returned buffer with os_free(). + * If re-allocation fails, %NULL is returned and the original buffer (ptr) is + * not freed and caller is still responsible for freeing it. + */ +void * os_realloc(void *ptr, size_t size); + +/** + * os_free - Free dynamic memory + * @ptr: Old buffer from os_malloc() or os_realloc(); can be %NULL + */ +void os_free(void *ptr); + +/** + * os_memcpy - Copy memory area + * @dest: Destination + * @src: Source + * @n: Number of bytes to copy + * Returns: dest + * + * The memory areas src and dst must not overlap. os_memmove() can be used with + * overlapping memory. + */ +void * os_memcpy(void *dest, const void *src, size_t n); + +/** + * os_memmove - Copy memory area + * @dest: Destination + * @src: Source + * @n: Number of bytes to copy + * Returns: dest + * + * The memory areas src and dst may overlap. + */ +void * os_memmove(void *dest, const void *src, size_t n); + +/** + * os_memset - Fill memory with a constant byte + * @s: Memory area to be filled + * @c: Constant byte + * @n: Number of bytes started from s to fill with c + * Returns: s + */ +void * os_memset(void *s, int c, size_t n); + +/** + * os_memcmp - Compare memory areas + * @s1: First buffer + * @s2: Second buffer + * @n: Maximum numbers of octets to compare + * Returns: An integer less than, equal to, or greater than zero if s1 is + * found to be less than, to match, or be greater than s2. Only first n + * characters will be compared. + */ +int os_memcmp(const void *s1, const void *s2, size_t n); + +/** + * os_strdup - Duplicate a string + * @s: Source string + * Returns: Allocated buffer with the string copied into it or %NULL on failure + * + * Caller is responsible for freeing the returned buffer with os_free(). + */ +char * os_strdup(const char *s); + +/** + * os_strlen - Calculate the length of a string + * @s: '\0' terminated string + * Returns: Number of characters in s (not counting the '\0' terminator) + */ +size_t os_strlen(const char *s); + +/** + * os_strcasecmp - Compare two strings ignoring case + * @s1: First string + * @s2: Second string + * Returns: An integer less than, equal to, or greater than zero if s1 is + * found to be less than, to match, or be greatred than s2 + */ +int os_strcasecmp(const char *s1, const char *s2); + +/** + * os_strncasecmp - Compare two strings ignoring case + * @s1: First string + * @s2: Second string + * @n: Maximum numbers of characters to compare + * Returns: An integer less than, equal to, or greater than zero if s1 is + * found to be less than, to match, or be greater than s2. Only first n + * characters will be compared. + */ +int os_strncasecmp(const char *s1, const char *s2, size_t n); + +/** + * os_strchr - Locate the first occurrence of a character in string + * @s: String + * @c: Character to search for + * Returns: Pointer to the matched character or %NULL if not found + */ +char * os_strchr(const char *s, int c); + +/** + * os_strrchr - Locate the last occurrence of a character in string + * @s: String + * @c: Character to search for + * Returns: Pointer to the matched character or %NULL if not found + */ +char * os_strrchr(const char *s, int c); + +/** + * os_strcmp - Compare two strings + * @s1: First string + * @s2: Second string + * Returns: An integer less than, equal to, or greater than zero if s1 is + * found to be less than, to match, or be greatred than s2 + */ +int os_strcmp(const char *s1, const char *s2); + +/** + * os_strncmp - Compare two strings + * @s1: First string + * @s2: Second string + * @n: Maximum numbers of characters to compare + * Returns: An integer less than, equal to, or greater than zero if s1 is + * found to be less than, to match, or be greater than s2. Only first n + * characters will be compared. + */ +int os_strncmp(const char *s1, const char *s2, size_t n); + +/** + * os_strncpy - Copy a string + * @dest: Destination + * @src: Source + * @n: Maximum number of characters to copy + * Returns: dest + */ +char * os_strncpy(char *dest, const char *src, size_t n); + +/** + * os_strstr - Locate a substring + * @haystack: String (haystack) to search from + * @needle: Needle to search from haystack + * Returns: Pointer to the beginning of the substring or %NULL if not found + */ +char * os_strstr(const char *haystack, const char *needle); + +/** + * os_snprintf - Print to a memory buffer + * @str: Memory buffer to print into + * @size: Maximum length of the str buffer + * @format: printf format + * Returns: Number of characters printed (not including trailing '\0'). + * + * If the output buffer is truncated, number of characters which would have + * been written is returned. Since some C libraries return -1 in such a case, + * the caller must be prepared on that value, too, to indicate truncation. + * + * Note: Some C library implementations of snprintf() may not guarantee null + * termination in case the output is truncated. The OS wrapper function of + * os_snprintf() should provide this guarantee, i.e., to null terminate the + * output buffer if a C library version of the function is used and if that + * function does not guarantee null termination. + * + * If the target system does not include snprintf(), see, e.g., + * http://www.ijs.si/software/snprintf/ for an example of a portable + * implementation of snprintf. + */ +int os_snprintf(char *str, size_t size, const char *format, ...); + +#else /* OS_NO_C_LIB_DEFINES */ + +#ifdef WPA_TRACE +void * os_malloc(size_t size); +void * os_realloc(void *ptr, size_t size); +void os_free(void *ptr); +char * os_strdup(const char *s); +#else /* WPA_TRACE */ +#ifndef os_malloc +#define os_malloc(s) malloc((s)) +#endif +#ifndef os_realloc +#define os_realloc(p, s) realloc((p), (s)) +#endif +#ifndef os_free +#define os_free(p) free((p)) +#endif +#ifndef os_strdup +#ifdef _MSC_VER +#define os_strdup(s) _strdup(s) +#else +#define os_strdup(s) strdup(s) +#endif +#endif +#endif /* WPA_TRACE */ + +#ifndef os_memcpy +#define os_memcpy(d, s, n) memcpy((d), (s), (n)) +#endif +#ifndef os_memmove +#define os_memmove(d, s, n) memmove((d), (s), (n)) +#endif +#ifndef os_memset +#define os_memset(s, c, n) memset(s, c, n) +#endif +#ifndef os_memcmp +#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n)) +#endif + +#ifndef os_strlen +#define os_strlen(s) strlen(s) +#endif +#ifndef os_strcasecmp +#ifdef _MSC_VER +#define os_strcasecmp(s1, s2) _stricmp((s1), (s2)) +#else +#define os_strcasecmp(s1, s2) strcasecmp((s1), (s2)) +#endif +#endif +#ifndef os_strncasecmp +#ifdef _MSC_VER +#define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n)) +#else +#define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n)) +#endif +#endif +#ifndef os_strchr +#define os_strchr(s, c) strchr((s), (c)) +#endif +#ifndef os_strcmp +#define os_strcmp(s1, s2) strcmp((s1), (s2)) +#endif +#ifndef os_strncmp +#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n)) +#endif +#ifndef os_strncpy +#define os_strncpy(d, s, n) strncpy((d), (s), (n)) +#endif +#ifndef os_strrchr +#define os_strrchr(s, c) strrchr((s), (c)) +#endif +#ifndef os_strstr +#define os_strstr(h, n) strstr((h), (n)) +#endif + +#ifndef os_snprintf +#ifdef _MSC_VER +#define os_snprintf _snprintf +#else +#define os_snprintf snprintf +#endif +#endif + +#endif /* OS_NO_C_LIB_DEFINES */ + + +/** + * os_strlcpy - Copy a string with size bound and NUL-termination + * @dest: Destination + * @src: Source + * @siz: Size of the target buffer + * Returns: Total length of the target string (length of src) (not including + * NUL-termination) + * + * This function matches in behavior with the strlcpy(3) function in OpenBSD. + */ +size_t os_strlcpy(char *dest, const char *src, size_t siz); + + +#ifdef OS_REJECT_C_LIB_FUNCTIONS +#define malloc OS_DO_NOT_USE_malloc +#define realloc OS_DO_NOT_USE_realloc +#define free OS_DO_NOT_USE_free +#define memcpy OS_DO_NOT_USE_memcpy +#define memmove OS_DO_NOT_USE_memmove +#define memset OS_DO_NOT_USE_memset +#define memcmp OS_DO_NOT_USE_memcmp +#undef strdup +#define strdup OS_DO_NOT_USE_strdup +#define strlen OS_DO_NOT_USE_strlen +#define strcasecmp OS_DO_NOT_USE_strcasecmp +#define strncasecmp OS_DO_NOT_USE_strncasecmp +#undef strchr +#define strchr OS_DO_NOT_USE_strchr +#undef strcmp +#define strcmp OS_DO_NOT_USE_strcmp +#undef strncmp +#define strncmp OS_DO_NOT_USE_strncmp +#undef strncpy +#define strncpy OS_DO_NOT_USE_strncpy +#define strrchr OS_DO_NOT_USE_strrchr +#define strstr OS_DO_NOT_USE_strstr +#undef snprintf +#define snprintf OS_DO_NOT_USE_snprintf + +#define strcpy OS_DO_NOT_USE_strcpy +#endif /* OS_REJECT_C_LIB_FUNCTIONS */ + +#endif /* OS_H */ diff --git a/cipher/rsa/os_unix.c b/cipher/rsa/os_unix.c new file mode 100644 index 0000000..c16eeff --- /dev/null +++ b/cipher/rsa/os_unix.c @@ -0,0 +1,439 @@ +/* + * OS specific functions for UNIX/POSIX systems + * Copyright (c) 2005-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "os.h" + +#ifdef WPA_TRACE + +#include "common.h" +#include "list.h" +#include "wpa_debug.h" +#include "trace.h" + +static struct dl_list alloc_list; + +#define ALLOC_MAGIC 0xa84ef1b2 +#define FREED_MAGIC 0x67fd487a + +struct os_alloc_trace { + unsigned int magic; + struct dl_list list; + size_t len; + WPA_TRACE_INFO +}; + +#endif /* WPA_TRACE */ + + +void os_sleep(os_time_t sec, os_time_t usec) +{ + if (sec) + sleep(sec); + if (usec) + usleep(usec); +} + + +int os_get_time(struct os_time *t) +{ + int res; + struct timeval tv; + res = gettimeofday(&tv, NULL); + t->sec = tv.tv_sec; + t->usec = tv.tv_usec; + return res; +} + + +int os_mktime(int year, int month, int day, int hour, int min, int sec, + os_time_t *t) +{ + struct tm tm, *tm1; + time_t t_local, t1, t2; + os_time_t tz_offset; + + if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || + hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || + sec > 60) + return -1; + + memset(&tm, 0, sizeof(tm)); + tm.tm_year = year - 1900; + tm.tm_mon = month - 1; + tm.tm_mday = day; + tm.tm_hour = hour; + tm.tm_min = min; + tm.tm_sec = sec; + + t_local = mktime(&tm); + + /* figure out offset to UTC */ + tm1 = localtime(&t_local); + if (tm1) { + t1 = mktime(tm1); + tm1 = gmtime(&t_local); + if (tm1) { + t2 = mktime(tm1); + tz_offset = t2 - t1; + } else + tz_offset = 0; + } else + tz_offset = 0; + + *t = (os_time_t) t_local - tz_offset; + return 0; +} + + +#ifdef __APPLE__ +#include +static int os_daemon(int nochdir, int noclose) +{ + int devnull; + + if (chdir("/") < 0) + return -1; + + devnull = open("/dev/null", O_RDWR); + if (devnull < 0) + return -1; + + if (dup2(devnull, STDIN_FILENO) < 0) { + close(devnull); + return -1; + } + + if (dup2(devnull, STDOUT_FILENO) < 0) { + close(devnull); + return -1; + } + + if (dup2(devnull, STDERR_FILENO) < 0) { + close(devnull); + return -1; + } + + return 0; +} +#else /* __APPLE__ */ +#define os_daemon daemon +#endif /* __APPLE__ */ + + +int os_daemonize(const char *pid_file) +{ +#ifdef __uClinux__ + return -1; +#else /* __uClinux__ */ +/* if (os_daemon(0, 0)) { + perror("daemon"); + return -1; + } + + if (pid_file) { + FILE *f = fopen(pid_file, "w"); + if (f) { + fprintf(f, "%u\n", getpid()); + fclose(f); + } + } +*/ + return -0; +#endif /* __uClinux__ */ +} + + +void os_daemonize_terminate(const char *pid_file) +{ + if (pid_file) + unlink(pid_file); +} + + +int os_get_random(unsigned char *buf, size_t len) +{ + FILE *f; + size_t rc; + + f = fopen("/dev/urandom", "rb"); + if (f == NULL) { + printf("Could not open /dev/urandom.\n"); + return -1; + } + + rc = fread(buf, 1, len, f); + fclose(f); + + return rc != len ? -1 : 0; +} + + +unsigned long os_random(void) +{ + return random(); +} + + +char * os_rel2abs_path(const char *rel_path) +{ + char *buf = NULL, *cwd, *ret; + size_t len = 128, cwd_len, rel_len, ret_len; + int last_errno; + + if (rel_path[0] == '/') + return os_strdup(rel_path); + + for (;;) { + buf = os_malloc(len); + if (buf == NULL) + return NULL; + cwd = getcwd(buf, len); + if (cwd == NULL) { + last_errno = errno; + os_free(buf); + if (last_errno != ERANGE) + return NULL; + len *= 2; + if (len > 2000) + return NULL; + } else { + buf[len - 1] = '\0'; + break; + } + } + + cwd_len = os_strlen(cwd); + rel_len = os_strlen(rel_path); + ret_len = cwd_len + 1 + rel_len + 1; + ret = os_malloc(ret_len); + if (ret) { + os_memcpy(ret, cwd, cwd_len); + ret[cwd_len] = '/'; + os_memcpy(ret + cwd_len + 1, rel_path, rel_len); + ret[ret_len - 1] = '\0'; + } + os_free(buf); + return ret; +} + + +int os_program_init(void) +{ +#ifdef WPA_TRACE + dl_list_init(&alloc_list); +#endif /* WPA_TRACE */ + return 0; +} + + +void os_program_deinit(void) +{ +#ifdef WPA_TRACE + struct os_alloc_trace *a; + unsigned long total = 0; + dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) { + total += a->len; + if (a->magic != ALLOC_MAGIC) { + wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x " + "len %lu", + a, a->magic, (unsigned long) a->len); + continue; + } + wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu", + a, (unsigned long) a->len); + wpa_trace_dump("memleak", a); + } + if (total) + wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes", + (unsigned long) total); +#endif /* WPA_TRACE */ +} + + +int os_setenv(const char *name, const char *value, int overwrite) +{ + //return setenv(name, value, overwrite); + return -1; +} + + +int os_unsetenv(const char *name) +{ +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \ + defined(__OpenBSD__) + unsetenv(name); + return 0; +#else + //return unsetenv(name); + return -1; +#endif +} + + +char * os_readfile(const char *name, size_t *len) +{ + FILE *f; + char *buf; + + f = fopen(name, "rb"); + if (f == NULL) + return NULL; + + fseek(f, 0, SEEK_END); + *len = ftell(f); + fseek(f, 0, SEEK_SET); + + buf = os_malloc(*len); + if (buf == NULL) { + fclose(f); + return NULL; + } + + if (fread(buf, 1, *len, f) != *len) { + fclose(f); + os_free(buf); + return NULL; + } + + fclose(f); + + return buf; +} + + +#ifndef WPA_TRACE +void * os_zalloc(size_t size) +{ + return calloc(1, size); +} +#endif /* WPA_TRACE */ + + +size_t os_strlcpy(char *dest, const char *src, size_t siz) +{ + const char *s = src; + size_t left = siz; + + if (left) { + /* Copy string up to the maximum size of the dest buffer */ + while (--left != 0) { + if ((*dest++ = *s++) == '\0') + break; + } + } + + if (left == 0) { + /* Not enough room for the string; force NUL-termination */ + if (siz != 0) + *dest = '\0'; + while (*s++) + ; /* determine total src string length */ + } + + return s - src - 1; +} + + +#ifdef WPA_TRACE + +void * os_malloc(size_t size) +{ + struct os_alloc_trace *a; + a = malloc(sizeof(*a) + size); + if (a == NULL) + return NULL; + a->magic = ALLOC_MAGIC; + dl_list_add(&alloc_list, &a->list); + a->len = size; + wpa_trace_record(a); + return a + 1; +} + + +void * os_realloc(void *ptr, size_t size) +{ + struct os_alloc_trace *a; + size_t copy_len; + void *n; + + if (ptr == NULL) + return os_malloc(size); + + a = ptr - sizeof(*a); + if (a->magic != ALLOC_MAGIC) { + wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s", + a, a->magic, + a->magic == FREED_MAGIC ? " (already freed)" : ""); + wpa_trace_show("Invalid os_realloc() call"); + abort(); + } + n = os_malloc(size); + if (n == NULL) + return NULL; + copy_len = a->len; + if (copy_len > size) + copy_len = size; + os_memcpy(n, a + 1, copy_len); + os_free(ptr); + return n; +} + + +void os_free(void *ptr) +{ + struct os_alloc_trace *a; + + if (ptr == NULL) + return; + a = ptr - sizeof(*a); + if (a->magic != ALLOC_MAGIC) { + wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s", + a, a->magic, + a->magic == FREED_MAGIC ? " (already freed)" : ""); + wpa_trace_show("Invalid os_free() call"); + abort(); + } + dl_list_del(&a->list); + a->magic = FREED_MAGIC; + + wpa_trace_check_ref(ptr); + free(a); +} + + +void * os_zalloc(size_t size) +{ + void *ptr = os_malloc(size); + if (ptr) + os_memset(ptr, 0, size); + return ptr; +} + + +char * os_strdup(const char *s) +{ + size_t len; + char *d; + len = os_strlen(s); + d = os_malloc(len + 1); + if (d == NULL) + return NULL; + os_memcpy(d, s, len); + d[len] = '\0'; + return d; +} + +#endif /* WPA_TRACE */ diff --git a/cipher/rsa/rsa.c b/cipher/rsa/rsa.c new file mode 100644 index 0000000..6ab0786 --- /dev/null +++ b/cipher/rsa/rsa.c @@ -0,0 +1,374 @@ +/* + * RSA + * Copyright (c) 2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "asn1.h" +#include "bignum.h" +#include "rsa.h" + + +struct crypto_rsa_key { + int private_key; /* whether private key is set */ + struct bignum *n; /* modulus (p * q) */ + struct bignum *e; /* public exponent */ + /* The following parameters are available only if private_key is set */ + struct bignum *d; /* private exponent */ + struct bignum *p; /* prime p (factor of n) */ + struct bignum *q; /* prime q (factor of n) */ + struct bignum *dmp1; /* d mod (p - 1); CRT exponent */ + struct bignum *dmq1; /* d mod (q - 1); CRT exponent */ + struct bignum *iqmp; /* 1 / q mod p; CRT coefficient */ +}; + + +static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end, + struct bignum *num) +{ + struct asn1_hdr hdr; + + if (pos == NULL) + return NULL; + + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { + wpa_printf(MSG_DEBUG, "RSA: Expected INTEGER - found class %d " + "tag 0x%x", hdr.class, hdr.tag); + return NULL; + } + + if (bignum_set_unsigned_bin(num, hdr.payload, hdr.length) < 0) { + wpa_printf(MSG_DEBUG, "RSA: Failed to parse INTEGER"); + return NULL; + } + + return hdr.payload + hdr.length; +} + + +/** + * crypto_rsa_import_public_key - Import an RSA public key + * @buf: Key buffer (DER encoded RSA public key) + * @len: Key buffer length in bytes + * Returns: Pointer to the public key or %NULL on failure + */ +struct crypto_rsa_key * +crypto_rsa_import_public_key(const u8 *buf, size_t len) +{ + struct crypto_rsa_key *key; + struct asn1_hdr hdr; + const u8 *pos, *end; + + key = os_zalloc(sizeof(*key)); + if (key == NULL) + return NULL; + + key->n = bignum_init(); + key->e = bignum_init(); + if (key->n == NULL || key->e == NULL) { + crypto_rsa_free(key); + return NULL; + } + + /* + * PKCS #1, 7.1: + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ + + if (asn1_get_next(buf, len, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE " + "(public key) - found class %d tag 0x%x", + hdr.class, hdr.tag); + goto error; + } + pos = hdr.payload; + end = pos + hdr.length; + +/***/ + //printf("len=%d\n", hdr.length); + + asn1_get_next(pos, end-pos, &hdr); + //printf("tag 0x%x, len=%d\n", hdr.tag, hdr.length); + pos = hdr.payload + hdr.length; + + asn1_get_next(pos, end-pos, &hdr); + //printf("tag 0x%x, len=%d\n", hdr.tag, hdr.length); + pos = hdr.payload + 1; //why 00 ahead? + + asn1_get_next(pos, end-pos, &hdr); + //printf("tag 0x%x, len=%d\n", hdr.tag, hdr.length); + pos = hdr.payload; +/***/ + + pos = crypto_rsa_parse_integer(pos, end, key->n); + pos = crypto_rsa_parse_integer(pos, end, key->e); + + if (pos == NULL) + goto error; + + if (pos != end) { + wpa_hexdump(MSG_DEBUG, + "RSA: Extra data in public key SEQUENCE", + pos, end - pos); + goto error; + } + + return key; + +error: + crypto_rsa_free(key); + return NULL; +} + + +/** + * crypto_rsa_import_private_key - Import an RSA private key + * @buf: Key buffer (DER encoded RSA private key) + * @len: Key buffer length in bytes + * Returns: Pointer to the private key or %NULL on failure + */ +struct crypto_rsa_key * +crypto_rsa_import_private_key(const u8 *buf, size_t len) +{ + struct crypto_rsa_key *key; + struct bignum *zero; + struct asn1_hdr hdr; + const u8 *pos, *end; + + key = os_zalloc(sizeof(*key)); + if (key == NULL) + return NULL; + + key->private_key = 1; + + key->n = bignum_init(); + key->e = bignum_init(); + key->d = bignum_init(); + key->p = bignum_init(); + key->q = bignum_init(); + key->dmp1 = bignum_init(); + key->dmq1 = bignum_init(); + key->iqmp = bignum_init(); + + if (key->n == NULL || key->e == NULL || key->d == NULL || + key->p == NULL || key->q == NULL || key->dmp1 == NULL || + key->dmq1 == NULL || key->iqmp == NULL) { + crypto_rsa_free(key); + return NULL; + } + + /* + * PKCS #1, 7.2: + * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER -- (inverse of q) mod p + * } + * + * Version ::= INTEGER -- shall be 0 for this version of the standard + */ + if (asn1_get_next(buf, len, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE " + "(public key) - found class %d tag 0x%x", + hdr.class, hdr.tag); + goto error; + } + pos = hdr.payload; + end = pos + hdr.length; + + zero = bignum_init(); + if (zero == NULL) + goto error; + pos = crypto_rsa_parse_integer(pos, end, zero); + if (pos == NULL || bignum_cmp_d(zero, 0) != 0) { + wpa_printf(MSG_DEBUG, "RSA: Expected zero INTEGER in the " + "beginning of private key; not found"); + bignum_deinit(zero); + goto error; + } + bignum_deinit(zero); + + pos = crypto_rsa_parse_integer(pos, end, key->n); + pos = crypto_rsa_parse_integer(pos, end, key->e); + pos = crypto_rsa_parse_integer(pos, end, key->d); + pos = crypto_rsa_parse_integer(pos, end, key->p); + pos = crypto_rsa_parse_integer(pos, end, key->q); + pos = crypto_rsa_parse_integer(pos, end, key->dmp1); + pos = crypto_rsa_parse_integer(pos, end, key->dmq1); + pos = crypto_rsa_parse_integer(pos, end, key->iqmp); + + if (pos == NULL) + goto error; + + if (pos != end) { + wpa_hexdump(MSG_DEBUG, + "RSA: Extra data in public key SEQUENCE", + pos, end - pos); + goto error; + } + + return key; + +error: + crypto_rsa_free(key); + return NULL; +} + + +/** + * crypto_rsa_get_modulus_len - Get the modulus length of the RSA key + * @key: RSA key + * Returns: Modulus length of the key + */ +size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key) +{ + return bignum_get_unsigned_bin_len(key->n); +} + + +/** + * crypto_rsa_exptmod - RSA modular exponentiation + * @in: Input data + * @inlen: Input data length + * @out: Buffer for output data + * @outlen: Maximum size of the output buffer and used size on success + * @key: RSA key + * @use_private: 1 = Use RSA private key, 0 = Use RSA public key + * Returns: 0 on success, -1 on failure + */ +int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen, + struct crypto_rsa_key *key, int use_private) +{ + struct bignum *tmp, *a = NULL, *b = NULL; + int ret = -1; + size_t modlen; + + if (use_private && !key->private_key) + return -1; + + tmp = bignum_init(); + if (tmp == NULL) + return -1; + + if (bignum_set_unsigned_bin(tmp, in, inlen) < 0) + goto error; + if (bignum_cmp(key->n, tmp) < 0) { + /* Too large input value for the RSA key modulus */ + goto error; + } + + if (use_private) { + /* + * Decrypt (or sign) using Chinese remainer theorem to speed + * up calculation. This is equivalent to tmp = tmp^d mod n + * (which would require more CPU to calculate directly). + * + * dmp1 = (1/e) mod (p-1) + * dmq1 = (1/e) mod (q-1) + * iqmp = (1/q) mod p, where p > q + * m1 = c^dmp1 mod p + * m2 = c^dmq1 mod q + * h = q^-1 (m1 - m2) mod p + * m = m2 + hq + */ + a = bignum_init(); + b = bignum_init(); + if (a == NULL || b == NULL) + goto error; + + /* a = tmp^dmp1 mod p */ + if (bignum_exptmod(tmp, key->dmp1, key->p, a) < 0) + goto error; + + /* b = tmp^dmq1 mod q */ + if (bignum_exptmod(tmp, key->dmq1, key->q, b) < 0) + goto error; + + /* tmp = (a - b) * (1/q mod p) (mod p) */ + if (bignum_sub(a, b, tmp) < 0 || + bignum_mulmod(tmp, key->iqmp, key->p, tmp) < 0) + goto error; + + /* tmp = b + q * tmp */ + if (bignum_mul(tmp, key->q, tmp) < 0 || + bignum_add(tmp, b, tmp) < 0) + goto error; + } else { + /* Encrypt (or verify signature) */ + /* tmp = tmp^e mod N */ + if (bignum_exptmod(tmp, key->e, key->n, tmp) < 0) + goto error; + } + + modlen = crypto_rsa_get_modulus_len(key); + if (modlen > *outlen) { + *outlen = modlen; + goto error; + } + + if (bignum_get_unsigned_bin_len(tmp) > modlen) + goto error; /* should never happen */ + + *outlen = modlen; + os_memset(out, 0, modlen); + if (bignum_get_unsigned_bin( + tmp, out + + (modlen - bignum_get_unsigned_bin_len(tmp)), NULL) < 0) + goto error; + + ret = 0; + +error: + bignum_deinit(tmp); + bignum_deinit(a); + bignum_deinit(b); + return ret; +} + + +/** + * crypto_rsa_free - Free RSA key + * @key: RSA key to be freed + * + * This function frees an RSA key imported with either + * crypto_rsa_import_public_key() or crypto_rsa_import_private_key(). + */ +void crypto_rsa_free(struct crypto_rsa_key *key) +{ + if (key) { + bignum_deinit(key->n); + bignum_deinit(key->e); + bignum_deinit(key->d); + bignum_deinit(key->p); + bignum_deinit(key->q); + bignum_deinit(key->dmp1); + bignum_deinit(key->dmq1); + bignum_deinit(key->iqmp); + os_free(key); + } +} diff --git a/cipher/rsa/rsa.h b/cipher/rsa/rsa.h new file mode 100644 index 0000000..ac50dfd --- /dev/null +++ b/cipher/rsa/rsa.h @@ -0,0 +1,29 @@ +/* + * RSA + * Copyright (c) 2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef RSA_H +#define RSA_H + +struct crypto_rsa_key; + +struct crypto_rsa_key * +crypto_rsa_import_public_key(const u8 *buf, size_t len); +struct crypto_rsa_key * +crypto_rsa_import_private_key(const u8 *buf, size_t len); +size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key); +int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen, + struct crypto_rsa_key *key, int use_private); +void crypto_rsa_free(struct crypto_rsa_key *key); + +#endif /* RSA_H */ diff --git a/cipher/rsa/test_rsa.c b/cipher/rsa/test_rsa.c new file mode 100644 index 0000000..644b750 --- /dev/null +++ b/cipher/rsa/test_rsa.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include "common.h" +#include "base64.h" +#include "rsa.h" + +static const u8 * search_tag(const char *tag, const u8 *buf, size_t len) +{ + size_t i, plen; + + plen = os_strlen(tag); + if (len < plen) + return NULL; + + for (i = 0; i < len - plen; i++) { + if (os_memcmp(buf + i, tag, plen) == 0) + return buf + i; + } + + return NULL; +} + +u8* get_key(const char *file, const char *start_tag, const char *end_tag, size_t *outlen) +{ + size_t len; + u8 *buf = os_readfile(file, &len); + if (!buf) + return NULL; + + const u8 *pos; + const u8 *end; + u8* der; + + pos = search_tag(start_tag, buf, len); + if (!pos) + goto err; + + pos += strlen(start_tag); + end = search_tag(end_tag, pos, buf + len - pos); + if (!end) + goto err; + + der = base64_decode(pos, end-pos, outlen); + + //prt(der, *outlen); + + + free(buf); + return der; + +err: + if (buf) + free(buf); + return NULL; +} + + +static void prt(void *p, int len) +{ + int i; + char *d = (char *)p; + for (i = 0; i < len; ++i) { + printf("%02x ", (unsigned char)d[i]); + if (i != 0 && (i+1)%20 == 0) + printf("\n"); + } + printf("\n"); +} + + +int main(int argc, char *argv[]) +{ + extern int wpa_debug_level; + wpa_debug_level = MSG_MSGDUMP; + struct crypto_rsa_key *key = NULL; + u8* buf = NULL;; + size_t l = 0; + + if (argc > 1) { + buf = get_key("./pubkey", "-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----", &l); + if (!buf) + return 0; + + key = crypto_rsa_import_public_key(buf, l); + if (!key) { + printf("private error\n"); + goto err; + } + + char src[1024]; + memset(src, 0, sizeof(src)); + strcpy(src, argv[1]); + int mod_len = crypto_rsa_get_modulus_len(key); + printf("modulus len=%d\n", mod_len); + + char encrypt_buf[1024]; + memset(encrypt_buf, 0, sizeof(encrypt_buf)); + size_t buf_len = sizeof(encrypt_buf); + if (0 == crypto_rsa_exptmod(src, mod_len, encrypt_buf, &buf_len, key, 0)) { + printf("result len=%d\n", buf_len); + prt(encrypt_buf, buf_len); + + FILE *fp=fopen("out.bin", "w"); + if (fp) { + fwrite(encrypt_buf, 1, buf_len, fp); + } + fclose(fp); + } + } else { + buf = get_key("./privkey", "-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----", &l); + if (!buf) + return 0; + + key = crypto_rsa_import_private_key(buf, l); + if (!key) { + printf("public error\n"); + goto err; + } + + size_t f_len; + char *p = os_readfile("out.bin", &f_len); + if (p) { + char decrypt_buf[1024]; + memset(decrypt_buf, 0, sizeof(decrypt_buf)); + size_t buf_len = sizeof(decrypt_buf); + + if (0 == crypto_rsa_exptmod(p, f_len, decrypt_buf, &buf_len, key, 1)) { + printf("outlen = %d\n", buf_len); + prt(decrypt_buf, buf_len); + } + free(p); + } + } + +err: + free(buf); + crypto_rsa_free(key); +} diff --git a/cipher/rsa/trace.c b/cipher/rsa/trace.c new file mode 100644 index 0000000..bb3eb24 --- /dev/null +++ b/cipher/rsa/trace.c @@ -0,0 +1,329 @@ +/* + * Backtrace debugging + * Copyright (c) 2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "trace.h" + +#ifdef WPA_TRACE + +static struct dl_list active_references = +{ &active_references, &active_references }; + +#ifdef WPA_TRACE_BFD +#include +#ifdef __linux__ +#include +#else /* __linux__ */ +#include +#endif /* __linux__ */ + +static char *prg_fname = NULL; +static bfd *cached_abfd = NULL; +static asymbol **syms = NULL; + +static void get_prg_fname(void) +{ + char exe[50], fname[512]; + int len; + os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid()); + len = readlink(exe, fname, sizeof(fname) - 1); + if (len < 0 || len >= (int) sizeof(fname)) { + perror("readlink"); + return; + } + fname[len] = '\0'; + prg_fname = strdup(fname); +} + + +static bfd * open_bfd(const char *fname) +{ + bfd *abfd; + char **matching; + + abfd = bfd_openr(prg_fname, NULL); + if (abfd == NULL) { + wpa_printf(MSG_INFO, "bfd_openr failed"); + return NULL; + } + + if (bfd_check_format(abfd, bfd_archive)) { + wpa_printf(MSG_INFO, "bfd_check_format failed"); + bfd_close(abfd); + return NULL; + } + + if (!bfd_check_format_matches(abfd, bfd_object, &matching)) { + wpa_printf(MSG_INFO, "bfd_check_format_matches failed"); + free(matching); + bfd_close(abfd); + return NULL; + } + + return abfd; +} + + +static void read_syms(bfd *abfd) +{ + long storage, symcount; + bfd_boolean dynamic = FALSE; + + if (syms) + return; + + if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) { + wpa_printf(MSG_INFO, "No symbols"); + return; + } + + storage = bfd_get_symtab_upper_bound(abfd); + if (storage == 0) { + storage = bfd_get_dynamic_symtab_upper_bound(abfd); + dynamic = TRUE; + } + if (storage < 0) { + wpa_printf(MSG_INFO, "Unknown symtab upper bound"); + return; + } + + syms = malloc(storage); + if (syms == NULL) { + wpa_printf(MSG_INFO, "Failed to allocate memory for symtab " + "(%ld bytes)", storage); + return; + } + if (dynamic) + symcount = bfd_canonicalize_dynamic_symtab(abfd, syms); + else + symcount = bfd_canonicalize_symtab(abfd, syms); + if (symcount < 0) { + wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab", + dynamic ? "dynamic " : ""); + free(syms); + syms = NULL; + return; + } +} + + +struct bfd_data { + bfd_vma pc; + bfd_boolean found; + const char *filename; + const char *function; + unsigned int line; +}; + + +static void find_addr_sect(bfd *abfd, asection *section, void *obj) +{ + struct bfd_data *data = obj; + bfd_vma vma; + bfd_size_type size; + + if (data->found) + return; + + if (!(bfd_get_section_vma(abfd, section))) + return; + + vma = bfd_get_section_vma(abfd, section); + if (data->pc < vma) + return; + + size = bfd_get_section_size(section); + if (data->pc >= vma + size) + return; + + data->found = bfd_find_nearest_line(abfd, section, syms, + data->pc - vma, + &data->filename, + &data->function, + &data->line); +} + + +static void wpa_trace_bfd_addr(void *pc) +{ + bfd *abfd = cached_abfd; + struct bfd_data data; + const char *name; + char *aname = NULL; + const char *filename; + + if (abfd == NULL) + return; + + data.pc = (bfd_vma) pc; + data.found = FALSE; + bfd_map_over_sections(abfd, find_addr_sect, &data); + + if (!data.found) + return; + + do { + if (data.function) + aname = bfd_demangle(abfd, data.function, + DMGL_ANSI | DMGL_PARAMS); + name = aname ? aname : data.function; + filename = data.filename; + if (filename) { + char *end = os_strrchr(filename, '/'); + int i = 0; + while (*filename && *filename == prg_fname[i] && + filename <= end) { + filename++; + i++; + } + } + wpa_printf(MSG_INFO, " %s() %s:%u", + name, filename, data.line); + free(aname); + + data.found = bfd_find_inliner_info(abfd, &data.filename, + &data.function, &data.line); + } while (data.found); +} + + +static const char * wpa_trace_bfd_addr2func(void *pc) +{ + bfd *abfd = cached_abfd; + struct bfd_data data; + + if (abfd == NULL) + return NULL; + + data.pc = (bfd_vma) pc; + data.found = FALSE; + bfd_map_over_sections(abfd, find_addr_sect, &data); + + if (!data.found) + return NULL; + + return data.function; +} + + +static void wpa_trace_bfd_init(void) +{ + if (!prg_fname) { + get_prg_fname(); + if (!prg_fname) + return; + } + + if (!cached_abfd) { + cached_abfd = open_bfd(prg_fname); + if (!cached_abfd) { + wpa_printf(MSG_INFO, "Failed to open bfd"); + return; + } + } + + read_syms(cached_abfd); + if (!syms) { + wpa_printf(MSG_INFO, "Failed to read symbols"); + return; + } +} + + +void wpa_trace_dump_funcname(const char *title, void *pc) +{ + wpa_printf(MSG_INFO, "WPA_TRACE: %s: %p", title, pc); + wpa_trace_bfd_init(); + wpa_trace_bfd_addr(pc); +} + +#else /* WPA_TRACE_BFD */ + +#define wpa_trace_bfd_init() do { } while (0) +#define wpa_trace_bfd_addr(pc) do { } while (0) +#define wpa_trace_bfd_addr2func(pc) NULL + +#endif /* WPA_TRACE_BFD */ + +void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num) +{ + char **sym; + int i; + enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state; + + wpa_trace_bfd_init(); + wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title); + sym = backtrace_symbols(btrace, btrace_num); + state = TRACE_HEAD; + for (i = 0; i < btrace_num; i++) { + const char *func = wpa_trace_bfd_addr2func(btrace[i]); + if (state == TRACE_HEAD && func && + (os_strcmp(func, "wpa_trace_add_ref_func") == 0 || + os_strcmp(func, "wpa_trace_check_ref") == 0 || + os_strcmp(func, "wpa_trace_show") == 0)) + continue; + if (state == TRACE_TAIL && sym && sym[i] && + os_strstr(sym[i], "__libc_start_main")) + break; + if (state == TRACE_HEAD) + state = TRACE_RELEVANT; + if (sym) + wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]); + else + wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]); + wpa_trace_bfd_addr(btrace[i]); + if (state == TRACE_RELEVANT && func && + os_strcmp(func, "main") == 0) + state = TRACE_TAIL; + } + free(sym); + wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title); +} + + +void wpa_trace_show(const char *title) +{ + struct info { + WPA_TRACE_INFO + } info; + wpa_trace_record(&info); + wpa_trace_dump(title, &info); +} + + +void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr) +{ + if (addr == NULL) + return; + ref->addr = addr; + wpa_trace_record(ref); + dl_list_add(&active_references, &ref->list); +} + + +void wpa_trace_check_ref(const void *addr) +{ + struct wpa_trace_ref *ref; + dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) { + if (addr != ref->addr) + continue; + wpa_trace_show("Freeing referenced memory"); + wpa_trace_dump("Reference registration", ref); + abort(); + } +} + +#endif /* WPA_TRACE */ diff --git a/cipher/rsa/trace.h b/cipher/rsa/trace.h new file mode 100644 index 0000000..22d3de0 --- /dev/null +++ b/cipher/rsa/trace.h @@ -0,0 +1,74 @@ +/* + * Backtrace debugging + * Copyright (c) 2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef TRACE_H +#define TRACE_H + +#define WPA_TRACE_LEN 16 + +#ifdef WPA_TRACE +#include + +#include "list.h" + +#define WPA_TRACE_INFO void *btrace[WPA_TRACE_LEN]; int btrace_num; + +struct wpa_trace_ref { + struct dl_list list; + const void *addr; + WPA_TRACE_INFO +}; +#define WPA_TRACE_REF(name) struct wpa_trace_ref wpa_trace_ref_##name + +#define wpa_trace_dump(title, ptr) \ + wpa_trace_dump_func((title), (ptr)->btrace, (ptr)->btrace_num) +void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num); +#define wpa_trace_record(ptr) \ + (ptr)->btrace_num = backtrace((ptr)->btrace, WPA_TRACE_LEN) +void wpa_trace_show(const char *title); +#define wpa_trace_add_ref(ptr, name, addr) \ + wpa_trace_add_ref_func(&(ptr)->wpa_trace_ref_##name, (addr)) +void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr); +#define wpa_trace_remove_ref(ptr, name, addr) \ + do { \ + if ((addr)) \ + dl_list_del(&(ptr)->wpa_trace_ref_##name.list); \ + } while (0) +void wpa_trace_check_ref(const void *addr); + +#else /* WPA_TRACE */ + +#define WPA_TRACE_INFO +#define WPA_TRACE_REF(n) +#define wpa_trace_dump(title, ptr) do { } while (0) +#define wpa_trace_record(ptr) do { } while (0) +#define wpa_trace_show(title) do { } while (0) +#define wpa_trace_add_ref(ptr, name, addr) do { } while (0) +#define wpa_trace_remove_ref(ptr, name, addr) do { } while (0) +#define wpa_trace_check_ref(addr) do { } while (0) + +#endif /* WPA_TRACE */ + + +#ifdef WPA_TRACE_BFD + +void wpa_trace_dump_funcname(const char *title, void *pc); + +#else /* WPA_TRACE_BFD */ + +#define wpa_trace_dump_funcname(title, pc) do { } while (0) + +#endif /* WPA_TRACE_BFD */ + +#endif /* TRACE_H */ diff --git a/cipher/rsa/user_rsa.c b/cipher/rsa/user_rsa.c new file mode 100644 index 0000000..a3b6304 --- /dev/null +++ b/cipher/rsa/user_rsa.c @@ -0,0 +1,94 @@ +#include +#include +#include "common.h" +#include "base64.h" +#include "rsa.h" +#include "user_rsa.h" + + +static const u8 * search_tag(const char *tag, const u8 *buf, size_t len) +{ + size_t i, plen; + + plen = os_strlen(tag); + if (len < plen) + return NULL; + + for (i = 0; i < len - plen; i++) { + if (os_memcmp(buf + i, tag, plen) == 0) + return buf + i; + } + + return NULL; +} + +static u8* get_key(const char *file, const char *start_tag, const char *end_tag, size_t *outlen) +{ + size_t len; + u8 *buf = os_readfile(file, &len); + if (!buf) + return NULL; + + const u8 *pos; + const u8 *end; + u8* der; + + pos = search_tag(start_tag, buf, len); + if (!pos) + goto err; + + pos += strlen(start_tag); + end = search_tag(end_tag, pos, buf + len - pos); + if (!end) + goto err; + + der = base64_decode(pos, end-pos, outlen); + + free(buf); + return der; + +err: + if (buf) + free(buf); + return NULL; +} + +void *RSA_Private_Init(const char *cert) +{ + size_t l = 0; + u8* buf = get_key(cert, "-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----", &l); + if (!buf) { + fprintf(stderr, "get cert '%s' error\n", cert); + return NULL; + } + + void *key = (void *)crypto_rsa_import_private_key(buf, l); + if (!key) { + fprintf(stderr, "import private key error\n"); + return NULL; + } + + os_free(buf); + return key; +} + +int RSA_Private_Run(void *key, const void *src, size_t src_len, void *out, size_t *out_len) +{ + struct crypto_rsa_key *rsa_key = (struct crypto_rsa_key*)key; + size_t mod_len = crypto_rsa_get_modulus_len(rsa_key); + if (mod_len < src_len) + return -1; + + char *p = os_zalloc(mod_len); + if (!p) + return -2; + memcpy(p, src, src_len); + int ret = crypto_rsa_exptmod(p, mod_len, out, out_len, rsa_key, 1); + os_free(p); + return ret; +} + +void RSA_Free(void *key) +{ + crypto_rsa_free((struct crypto_rsa_key*)key); +} diff --git a/cipher/rsa/user_rsa.h b/cipher/rsa/user_rsa.h new file mode 100644 index 0000000..abfa3d8 --- /dev/null +++ b/cipher/rsa/user_rsa.h @@ -0,0 +1,19 @@ +#ifndef _USER_RSA_H +#define _USER_RSA_H + +#ifdef __cplusplus +extern "C"{ +#endif + + void *RSA_Private_Init(const char *cert); + + int RSA_Private_Run(void *key, const void *src, size_t src_len, void *out, size_t *out_len); + + void RSA_Free(void *key); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/cipher/rsa/wpa_debug.c b/cipher/rsa/wpa_debug.c new file mode 100644 index 0000000..3c9d9a1 --- /dev/null +++ b/cipher/rsa/wpa_debug.c @@ -0,0 +1,397 @@ +/* + * wpa_supplicant/hostapd / Debug prints + * Copyright (c) 2002-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" + +#ifdef CONFIG_DEBUG_SYSLOG +#include + +static int wpa_debug_syslog = 0; +#endif /* CONFIG_DEBUG_SYSLOG */ + + +#ifdef CONFIG_DEBUG_FILE +static FILE *out_file = NULL; +#endif /* CONFIG_DEBUG_FILE */ +int wpa_debug_level = MSG_INFO; +int wpa_debug_show_keys = 0; +int wpa_debug_timestamp = 0; + + +#ifndef CONFIG_NO_STDOUT_DEBUG + +void wpa_debug_print_timestamp(void) +{ + struct os_time tv; + + if (!wpa_debug_timestamp) + return; + + os_get_time(&tv); +#ifdef CONFIG_DEBUG_FILE + if (out_file) { + fprintf(out_file, "%ld.%06u: ", (long) tv.sec, + (unsigned int) tv.usec); + } else +#endif /* CONFIG_DEBUG_FILE */ + printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec); +} + + +#ifdef CONFIG_DEBUG_SYSLOG +void wpa_debug_open_syslog(void) +{ + openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_DAEMON); + wpa_debug_syslog++; +} + + +void wpa_debug_close_syslog(void) +{ + if (wpa_debug_syslog) + closelog(); +} + + +static int syslog_priority(int level) +{ + switch (level) { + case MSG_MSGDUMP: + case MSG_DEBUG: + return LOG_DEBUG; + case MSG_INFO: + return LOG_NOTICE; + case MSG_WARNING: + return LOG_WARNING; + case MSG_ERROR: + return LOG_ERR; + } + return LOG_INFO; +} +#endif /* CONFIG_DEBUG_SYSLOG */ + + +/** + * wpa_printf - conditional printf + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. + * + * Note: New line '\n' is added to the end of the text when printing to stdout. + */ +void wpa_printf(int level, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (level >= wpa_debug_level) { +#ifdef CONFIG_DEBUG_SYSLOG + if (wpa_debug_syslog) { + vsyslog(syslog_priority(level), fmt, ap); + } else { +#endif /* CONFIG_DEBUG_SYSLOG */ + wpa_debug_print_timestamp(); +#ifdef CONFIG_DEBUG_FILE + if (out_file) { + vfprintf(out_file, fmt, ap); + fprintf(out_file, "\n"); + } else { +#endif /* CONFIG_DEBUG_FILE */ + vprintf(fmt, ap); + printf("\n"); +#ifdef CONFIG_DEBUG_FILE + } +#endif /* CONFIG_DEBUG_FILE */ +#ifdef CONFIG_DEBUG_SYSLOG + } +#endif /* CONFIG_DEBUG_SYSLOG */ + } + va_end(ap); +} + + +static void _wpa_hexdump(int level, const char *title, const u8 *buf, + size_t len, int show) +{ + size_t i; + if (level < wpa_debug_level) + return; + wpa_debug_print_timestamp(); +#ifdef CONFIG_DEBUG_FILE + if (out_file) { + fprintf(out_file, "%s - hexdump(len=%lu):", + title, (unsigned long) len); + if (buf == NULL) { + fprintf(out_file, " [NULL]"); + } else if (show) { + for (i = 0; i < len; i++) + fprintf(out_file, " %02x", buf[i]); + } else { + fprintf(out_file, " [REMOVED]"); + } + fprintf(out_file, "\n"); + } else { +#endif /* CONFIG_DEBUG_FILE */ + printf("%s - hexdump(len=%lu):", title, (unsigned long) len); + if (buf == NULL) { + printf(" [NULL]"); + } else if (show) { + for (i = 0; i < len; i++) + printf(" %02x", buf[i]); + } else { + printf(" [REMOVED]"); + } + printf("\n"); +#ifdef CONFIG_DEBUG_FILE + } +#endif /* CONFIG_DEBUG_FILE */ +} + +void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len) +{ + _wpa_hexdump(level, title, buf, len, 1); +} + + +void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len) +{ + _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys); +} + + +static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf, + size_t len, int show) +{ + size_t i, llen; + const u8 *pos = buf; + const size_t line_len = 16; + + if (level < wpa_debug_level) + return; + wpa_debug_print_timestamp(); +#ifdef CONFIG_DEBUG_FILE + if (out_file) { + if (!show) { + fprintf(out_file, + "%s - hexdump_ascii(len=%lu): [REMOVED]\n", + title, (unsigned long) len); + return; + } + if (buf == NULL) { + fprintf(out_file, + "%s - hexdump_ascii(len=%lu): [NULL]\n", + title, (unsigned long) len); + return; + } + fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n", + title, (unsigned long) len); + while (len) { + llen = len > line_len ? line_len : len; + fprintf(out_file, " "); + for (i = 0; i < llen; i++) + fprintf(out_file, " %02x", pos[i]); + for (i = llen; i < line_len; i++) + fprintf(out_file, " "); + fprintf(out_file, " "); + for (i = 0; i < llen; i++) { + if (isprint(pos[i])) + fprintf(out_file, "%c", pos[i]); + else + fprintf(out_file, "_"); + } + for (i = llen; i < line_len; i++) + fprintf(out_file, " "); + fprintf(out_file, "\n"); + pos += llen; + len -= llen; + } + } else { +#endif /* CONFIG_DEBUG_FILE */ + if (!show) { + printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n", + title, (unsigned long) len); + return; + } + if (buf == NULL) { + printf("%s - hexdump_ascii(len=%lu): [NULL]\n", + title, (unsigned long) len); + return; + } + printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len); + while (len) { + llen = len > line_len ? line_len : len; + printf(" "); + for (i = 0; i < llen; i++) + printf(" %02x", pos[i]); + for (i = llen; i < line_len; i++) + printf(" "); + printf(" "); + for (i = 0; i < llen; i++) { + if (isprint(pos[i])) + printf("%c", pos[i]); + else + printf("_"); + } + for (i = llen; i < line_len; i++) + printf(" "); + printf("\n"); + pos += llen; + len -= llen; + } +#ifdef CONFIG_DEBUG_FILE + } +#endif /* CONFIG_DEBUG_FILE */ +} + + +void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len) +{ + _wpa_hexdump_ascii(level, title, buf, len, 1); +} + + +void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, + size_t len) +{ + _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys); +} + + +int wpa_debug_open_file(const char *path) +{ +#ifdef CONFIG_DEBUG_FILE + if (!path) + return 0; + out_file = fopen(path, "a"); + if (out_file == NULL) { + wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open " + "output file, using standard output"); + return -1; + } +#ifndef _WIN32 + setvbuf(out_file, NULL, _IOLBF, 0); +#endif /* _WIN32 */ +#endif /* CONFIG_DEBUG_FILE */ + return 0; +} + + +void wpa_debug_close_file(void) +{ +#ifdef CONFIG_DEBUG_FILE + if (!out_file) + return; + fclose(out_file); + out_file = NULL; +#endif /* CONFIG_DEBUG_FILE */ +} + +#endif /* CONFIG_NO_STDOUT_DEBUG */ + + +#ifndef CONFIG_NO_WPA_MSG +static wpa_msg_cb_func wpa_msg_cb = NULL; + +void wpa_msg_register_cb(wpa_msg_cb_func func) +{ + wpa_msg_cb = func; +} + + +void wpa_msg(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + const int buflen = 2048; + int len; + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message " + "buffer"); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_printf(level, "%s", buf); + if (wpa_msg_cb) + wpa_msg_cb(ctx, level, buf, len); + os_free(buf); +} + + +void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + const int buflen = 2048; + int len; + + if (!wpa_msg_cb) + return; + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate " + "message buffer"); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_msg_cb(ctx, level, buf, len); + os_free(buf); +} +#endif /* CONFIG_NO_WPA_MSG */ + + +#ifndef CONFIG_NO_HOSTAPD_LOGGER +static hostapd_logger_cb_func hostapd_logger_cb = NULL; + +void hostapd_logger_register_cb(hostapd_logger_cb_func func) +{ + hostapd_logger_cb = func; +} + + +void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, + const char *fmt, ...) +{ + va_list ap; + char *buf; + const int buflen = 2048; + int len; + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate " + "message buffer"); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + if (hostapd_logger_cb) + hostapd_logger_cb(ctx, addr, module, level, buf, len); + else + wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf); + os_free(buf); +} +#endif /* CONFIG_NO_HOSTAPD_LOGGER */ diff --git a/cipher/rsa/wpa_debug.h b/cipher/rsa/wpa_debug.h new file mode 100644 index 0000000..6e5e79e --- /dev/null +++ b/cipher/rsa/wpa_debug.h @@ -0,0 +1,256 @@ +/* + * wpa_supplicant/hostapd / Debug prints + * Copyright (c) 2002-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPA_DEBUG_H +#define WPA_DEBUG_H + +#include "wpabuf.h" + +/* Debugging function - conditional printf and hex dump. Driver wrappers can + * use these for debugging purposes. */ + +enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR }; + +#ifdef CONFIG_NO_STDOUT_DEBUG + +#define wpa_debug_print_timestamp() do { } while (0) +#define wpa_printf(args...) do { } while (0) +#define wpa_hexdump(l,t,b,le) do { } while (0) +#define wpa_hexdump_buf(l,t,b) do { } while (0) +#define wpa_hexdump_key(l,t,b,le) do { } while (0) +#define wpa_hexdump_buf_key(l,t,b) do { } while (0) +#define wpa_hexdump_ascii(l,t,b,le) do { } while (0) +#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0) +#define wpa_debug_open_file(p) do { } while (0) +#define wpa_debug_close_file() do { } while (0) + +#else /* CONFIG_NO_STDOUT_DEBUG */ + +int wpa_debug_open_file(const char *path); +void wpa_debug_close_file(void); + +/** + * wpa_debug_printf_timestamp - Print timestamp for debug output + * + * This function prints a timestamp in seconds_from_1970.microsoconds + * format if debug output has been configured to include timestamps in debug + * messages. + */ +void wpa_debug_print_timestamp(void); + +/** + * wpa_printf - conditional printf + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. + * + * Note: New line '\n' is added to the end of the text when printing to stdout. + */ +void wpa_printf(int level, const char *fmt, ...) +PRINTF_FORMAT(2, 3); + +/** + * wpa_hexdump - conditional hex dump + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump. + */ +void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len); + +static inline void wpa_hexdump_buf(int level, const char *title, + const struct wpabuf *buf) +{ + wpa_hexdump(level, title, wpabuf_head(buf), wpabuf_len(buf)); +} + +/** + * wpa_hexdump_key - conditional hex dump, hide keys + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump. This works + * like wpa_hexdump(), but by default, does not include secret keys (passwords, + * etc.) in debug output. + */ +void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len); + +static inline void wpa_hexdump_buf_key(int level, const char *title, + const struct wpabuf *buf) +{ + wpa_hexdump_key(level, title, wpabuf_head(buf), wpabuf_len(buf)); +} + +/** + * wpa_hexdump_ascii - conditional hex dump + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump with both + * the hex numbers and ASCII characters (for printable range) are shown. 16 + * bytes per line will be shown. + */ +void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, + size_t len); + +/** + * wpa_hexdump_ascii_key - conditional hex dump, hide keys + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump with both + * the hex numbers and ASCII characters (for printable range) are shown. 16 + * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by + * default, does not include secret keys (passwords, etc.) in debug output. + */ +void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, + size_t len); + +#endif /* CONFIG_NO_STDOUT_DEBUG */ + + +#ifdef CONFIG_NO_WPA_MSG +#define wpa_msg(args...) do { } while (0) +#define wpa_msg_ctrl(args...) do { } while (0) +#define wpa_msg_register_cb(f) do { } while (0) +#else /* CONFIG_NO_WPA_MSG */ +/** + * wpa_msg - Conditional printf for default target and ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. This function is like wpa_printf(), but it also sends the + * same message to all attached ctrl_iface monitors. + * + * Note: New line '\n' is added to the end of the text when printing to stdout. + */ +void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg(), but it sends the output only to the + * attached ctrl_iface monitors. In other words, it can be used for frequent + * events that do not need to be sent to syslog. + */ +void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) +PRINTF_FORMAT(3, 4); + +typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt, + size_t len); + +/** + * wpa_msg_register_cb - Register callback function for wpa_msg() messages + * @func: Callback function (%NULL to unregister) + */ +void wpa_msg_register_cb(wpa_msg_cb_func func); +#endif /* CONFIG_NO_WPA_MSG */ + + +#ifdef CONFIG_NO_HOSTAPD_LOGGER +#define hostapd_logger(args...) do { } while (0) +#define hostapd_logger_register_cb(f) do { } while (0) +#else /* CONFIG_NO_HOSTAPD_LOGGER */ +void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, + const char *fmt, ...) PRINTF_FORMAT(5, 6); + +typedef void (*hostapd_logger_cb_func)(void *ctx, const u8 *addr, + unsigned int module, int level, + const char *txt, size_t len); + +/** + * hostapd_logger_register_cb - Register callback function for hostapd_logger() + * @func: Callback function (%NULL to unregister) + */ +void hostapd_logger_register_cb(hostapd_logger_cb_func func); +#endif /* CONFIG_NO_HOSTAPD_LOGGER */ + +#define HOSTAPD_MODULE_IEEE80211 0x00000001 +#define HOSTAPD_MODULE_IEEE8021X 0x00000002 +#define HOSTAPD_MODULE_RADIUS 0x00000004 +#define HOSTAPD_MODULE_WPA 0x00000008 +#define HOSTAPD_MODULE_DRIVER 0x00000010 +#define HOSTAPD_MODULE_IAPP 0x00000020 +#define HOSTAPD_MODULE_MLME 0x00000040 + +enum hostapd_logger_level { + HOSTAPD_LEVEL_DEBUG_VERBOSE = 0, + HOSTAPD_LEVEL_DEBUG = 1, + HOSTAPD_LEVEL_INFO = 2, + HOSTAPD_LEVEL_NOTICE = 3, + HOSTAPD_LEVEL_WARNING = 4 +}; + + +#ifdef CONFIG_DEBUG_SYSLOG + +void wpa_debug_open_syslog(void); +void wpa_debug_close_syslog(void); + +#else /* CONFIG_DEBUG_SYSLOG */ + +static inline void wpa_debug_open_syslog(void) +{ +} + +static inline void wpa_debug_close_syslog(void) +{ +} + +#endif /* CONFIG_DEBUG_SYSLOG */ + + +#ifdef EAPOL_TEST +#define WPA_ASSERT(a) \ + do { \ + if (!(a)) { \ + printf("WPA_ASSERT FAILED '" #a "' " \ + "%s %s:%d\n", \ + __FUNCTION__, __FILE__, __LINE__); \ + exit(1); \ + } \ + } while (0) +#else +#define WPA_ASSERT(a) do { } while (0) +#endif + +#endif /* WPA_DEBUG_H */ diff --git a/cipher/rsa/wpabuf.c b/cipher/rsa/wpabuf.c new file mode 100644 index 0000000..eda779e --- /dev/null +++ b/cipher/rsa/wpabuf.c @@ -0,0 +1,304 @@ +/* + * Dynamic data buffer + * Copyright (c) 2007-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "trace.h" +#include "wpabuf.h" + +#ifdef WPA_TRACE +#define WPABUF_MAGIC 0x51a974e3 + +struct wpabuf_trace { + unsigned int magic; +}; + +static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf) +{ + return (struct wpabuf_trace *) + ((const u8 *) buf - sizeof(struct wpabuf_trace)); +} +#endif /* WPA_TRACE */ + + +static void wpabuf_overflow(const struct wpabuf *buf, size_t len) +{ +#ifdef WPA_TRACE + struct wpabuf_trace *trace = wpabuf_get_trace(buf); + if (trace->magic != WPABUF_MAGIC) { + wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", + trace->magic); + } +#endif /* WPA_TRACE */ + wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu", + buf, (unsigned long) buf->size, (unsigned long) buf->used, + (unsigned long) len); + wpa_trace_show("wpabuf overflow"); + abort(); +} + + +int wpabuf_resize(struct wpabuf **_buf, size_t add_len) +{ + struct wpabuf *buf = *_buf; +#ifdef WPA_TRACE + struct wpabuf_trace *trace; +#endif /* WPA_TRACE */ + + if (buf == NULL) { + *_buf = wpabuf_alloc(add_len); + return *_buf == NULL ? -1 : 0; + } + +#ifdef WPA_TRACE + trace = wpabuf_get_trace(buf); + if (trace->magic != WPABUF_MAGIC) { + wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", + trace->magic); + wpa_trace_show("wpabuf_resize invalid magic"); + abort(); + } +#endif /* WPA_TRACE */ + + if (buf->used + add_len > buf->size) { + unsigned char *nbuf; + if (buf->ext_data) { + nbuf = os_realloc(buf->ext_data, buf->used + add_len); + if (nbuf == NULL) + return -1; + os_memset(nbuf + buf->used, 0, add_len); + buf->ext_data = nbuf; + } else { +#ifdef WPA_TRACE + nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) + + sizeof(struct wpabuf) + + buf->used + add_len); + if (nbuf == NULL) + return -1; + trace = (struct wpabuf_trace *) nbuf; + buf = (struct wpabuf *) (trace + 1); + os_memset(nbuf + sizeof(struct wpabuf_trace) + + sizeof(struct wpabuf) + buf->used, 0, + add_len); +#else /* WPA_TRACE */ + nbuf = os_realloc(buf, sizeof(struct wpabuf) + + buf->used + add_len); + if (nbuf == NULL) + return -1; + buf = (struct wpabuf *) nbuf; + os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0, + add_len); +#endif /* WPA_TRACE */ + *_buf = buf; + } + buf->size = buf->used + add_len; + } + + return 0; +} + + +/** + * wpabuf_alloc - Allocate a wpabuf of the given size + * @len: Length for the allocated buffer + * Returns: Buffer to the allocated wpabuf or %NULL on failure + */ +struct wpabuf * wpabuf_alloc(size_t len) +{ +#ifdef WPA_TRACE + struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + + sizeof(struct wpabuf) + len); + struct wpabuf *buf; + if (trace == NULL) + return NULL; + trace->magic = WPABUF_MAGIC; + buf = (struct wpabuf *) (trace + 1); +#else /* WPA_TRACE */ + struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf) + len); + if (buf == NULL) + return NULL; +#endif /* WPA_TRACE */ + + buf->size = len; + return buf; +} + + +struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len) +{ +#ifdef WPA_TRACE + struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + + sizeof(struct wpabuf)); + struct wpabuf *buf; + if (trace == NULL) + return NULL; + trace->magic = WPABUF_MAGIC; + buf = (struct wpabuf *) (trace + 1); +#else /* WPA_TRACE */ + struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf)); + if (buf == NULL) + return NULL; +#endif /* WPA_TRACE */ + + buf->size = len; + buf->used = len; + buf->ext_data = data; + + return buf; +} + + +struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len) +{ + struct wpabuf *buf = wpabuf_alloc(len); + if (buf) + wpabuf_put_data(buf, data, len); + return buf; +} + + +struct wpabuf * wpabuf_dup(const struct wpabuf *src) +{ + struct wpabuf *buf = wpabuf_alloc(wpabuf_len(src)); + if (buf) + wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src)); + return buf; +} + + +/** + * wpabuf_free - Free a wpabuf + * @buf: wpabuf buffer + */ +void wpabuf_free(struct wpabuf *buf) +{ +#ifdef WPA_TRACE + struct wpabuf_trace *trace; + if (buf == NULL) + return; + trace = wpabuf_get_trace(buf); + if (trace->magic != WPABUF_MAGIC) { + wpa_printf(MSG_ERROR, "wpabuf_free: invalid magic %x", + trace->magic); + wpa_trace_show("wpabuf_free magic mismatch"); + abort(); + } + os_free(buf->ext_data); + os_free(trace); +#else /* WPA_TRACE */ + if (buf == NULL) + return; + os_free(buf->ext_data); + os_free(buf); +#endif /* WPA_TRACE */ +} + + +void * wpabuf_put(struct wpabuf *buf, size_t len) +{ + void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); + buf->used += len; + if (buf->used > buf->size) { + wpabuf_overflow(buf, len); + } + return tmp; +} + + +/** + * wpabuf_concat - Concatenate two buffers into a newly allocated one + * @a: First buffer + * @b: Second buffer + * Returns: wpabuf with concatenated a + b data or %NULL on failure + * + * Both buffers a and b will be freed regardless of the return value. Input + * buffers can be %NULL which is interpreted as an empty buffer. + */ +struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b) +{ + struct wpabuf *n = NULL; + size_t len = 0; + + if (b == NULL) + return a; + + if (a) + len += wpabuf_len(a); + if (b) + len += wpabuf_len(b); + + n = wpabuf_alloc(len); + if (n) { + if (a) + wpabuf_put_buf(n, a); + if (b) + wpabuf_put_buf(n, b); + } + + wpabuf_free(a); + wpabuf_free(b); + + return n; +} + + +/** + * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length + * @buf: Buffer to be padded + * @len: Length for the padded buffer + * Returns: wpabuf padded to len octets or %NULL on failure + * + * If buf is longer than len octets or of same size, it will be returned as-is. + * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed + * by the source data. The source buffer will be freed on error, i.e., caller + * will only be responsible on freeing the returned buffer. If buf is %NULL, + * %NULL will be returned. + */ +struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len) +{ + struct wpabuf *ret; + size_t blen; + + if (buf == NULL) + return NULL; + + blen = wpabuf_len(buf); + if (blen >= len) + return buf; + + ret = wpabuf_alloc(len); + if (ret) { + os_memset(wpabuf_put(ret, len - blen), 0, len - blen); + wpabuf_put_buf(ret, buf); + } + wpabuf_free(buf); + + return ret; +} + + +void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) +{ + va_list ap; + void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); + int res; + + va_start(ap, fmt); + res = vsnprintf(tmp, buf->size - buf->used, fmt, ap); + va_end(ap); + if (res < 0 || (size_t) res >= buf->size - buf->used) + wpabuf_overflow(buf, res); + buf->used += res; +} diff --git a/cipher/rsa/wpabuf.h b/cipher/rsa/wpabuf.h new file mode 100644 index 0000000..a150455 --- /dev/null +++ b/cipher/rsa/wpabuf.h @@ -0,0 +1,162 @@ +/* + * Dynamic data buffer + * Copyright (c) 2007-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPABUF_H +#define WPABUF_H + +/* + * Internal data structure for wpabuf. Please do not touch this directly from + * elsewhere. This is only defined in header file to allow inline functions + * from this file to access data. + */ +struct wpabuf { + size_t size; /* total size of the allocated buffer */ + size_t used; /* length of data in the buffer */ + u8 *ext_data; /* pointer to external data; NULL if data follows + * struct wpabuf */ + /* optionally followed by the allocated buffer */ +}; + + +int wpabuf_resize(struct wpabuf **buf, size_t add_len); +struct wpabuf * wpabuf_alloc(size_t len); +struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len); +struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len); +struct wpabuf * wpabuf_dup(const struct wpabuf *src); +void wpabuf_free(struct wpabuf *buf); +void * wpabuf_put(struct wpabuf *buf, size_t len); +struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b); +struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len); +void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3); + + +/** + * wpabuf_size - Get the currently allocated size of a wpabuf buffer + * @buf: wpabuf buffer + * Returns: Currently allocated size of the buffer + */ +static inline size_t wpabuf_size(const struct wpabuf *buf) +{ + return buf->size; +} + +/** + * wpabuf_len - Get the current length of a wpabuf buffer data + * @buf: wpabuf buffer + * Returns: Currently used length of the buffer + */ +static inline size_t wpabuf_len(const struct wpabuf *buf) +{ + return buf->used; +} + +/** + * wpabuf_tailroom - Get size of available tail room in the end of the buffer + * @buf: wpabuf buffer + * Returns: Tail room (in bytes) of available space in the end of the buffer + */ +static inline size_t wpabuf_tailroom(const struct wpabuf *buf) +{ + return buf->size - buf->used; +} + +/** + * wpabuf_head - Get pointer to the head of the buffer data + * @buf: wpabuf buffer + * Returns: Pointer to the head of the buffer data + */ +static inline const void * wpabuf_head(const struct wpabuf *buf) +{ + if (buf->ext_data) + return buf->ext_data; + return buf + 1; +} + +static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf) +{ + return wpabuf_head(buf); +} + +/** + * wpabuf_mhead - Get modifiable pointer to the head of the buffer data + * @buf: wpabuf buffer + * Returns: Pointer to the head of the buffer data + */ +static inline void * wpabuf_mhead(struct wpabuf *buf) +{ + if (buf->ext_data) + return buf->ext_data; + return buf + 1; +} + +static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf) +{ + return wpabuf_mhead(buf); +} + +static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data) +{ + u8 *pos = wpabuf_put(buf, 1); + *pos = data; +} + +static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data) +{ + u8 *pos = wpabuf_put(buf, 2); + WPA_PUT_LE16(pos, data); +} + +static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data) +{ + u8 *pos = wpabuf_put(buf, 2); + WPA_PUT_BE16(pos, data); +} + +static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data) +{ + u8 *pos = wpabuf_put(buf, 3); + WPA_PUT_BE24(pos, data); +} + +static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data) +{ + u8 *pos = wpabuf_put(buf, 4); + WPA_PUT_BE32(pos, data); +} + +static inline void wpabuf_put_data(struct wpabuf *buf, const void *data, + size_t len) +{ + if (data) + os_memcpy(wpabuf_put(buf, len), data, len); +} + +static inline void wpabuf_put_buf(struct wpabuf *dst, + const struct wpabuf *src) +{ + wpabuf_put_data(dst, wpabuf_head(src), wpabuf_len(src)); +} + +static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len) +{ + buf->ext_data = (u8 *) data; + buf->size = buf->used = len; +} + +static inline void wpabuf_put_str(struct wpabuf *dst, const char *str) +{ + wpabuf_put_data(dst, str, os_strlen(str)); +} + +#endif /* WPABUF_H */ diff --git a/cipher/sha.c b/cipher/sha.c new file mode 100644 index 0000000..47886bb --- /dev/null +++ b/cipher/sha.c @@ -0,0 +1,222 @@ +/* + * SHA1 hash algorithm. Used in SSH-2 as a MAC, and the transform is + * also used as a `stirring' function for the PuTTY random number + * pool. Implemented directly from the specification by Simon + * Tatham. + */ +#include +#include "sha.h" + +/* ---------------------------------------------------------------------- + * Core SHA algorithm: processes 16-word blocks into a message digest. + */ + +#define rol(x,y) ( ((x) << (y)) | (((uint32)x) >> (32-y)) ) +#define PUT_32BIT_MSB_FIRST(cp, value) ( \ + (cp)[0] = (unsigned char)((value) >> 24), \ + (cp)[1] = (unsigned char)((value) >> 16), \ + (cp)[2] = (unsigned char)((value) >> 8), \ + (cp)[3] = (unsigned char)(value) ) + +static void SHA_Core_Init(uint32 h[5]) +{ + h[0] = 0x67452301; + h[1] = 0xefcdab89; + h[2] = 0x98badcfe; + h[3] = 0x10325476; + h[4] = 0xc3d2e1f0; +} + +void SHATransform(word32 * digest, word32 * block) +{ + word32 w[80]; + word32 a, b, c, d, e; + int t; + +#ifdef RANDOM_DIAGNOSTICS + { + extern int random_diagnostics; + if (random_diagnostics) { + int i; + printf("SHATransform:"); + for (i = 0; i < 5; i++) + printf(" %08x", digest[i]); + printf(" +"); + for (i = 0; i < 16; i++) + printf(" %08x", block[i]); + } + } +#endif + + for (t = 0; t < 16; t++) + w[t] = block[t]; + + for (t = 16; t < 80; t++) { + word32 tmp = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]; + w[t] = rol(tmp, 1); + } + + a = digest[0]; + b = digest[1]; + c = digest[2]; + d = digest[3]; + e = digest[4]; + + for (t = 0; t < 20; t++) { + word32 tmp = + rol(a, 5) + ((b & c) | (d & ~b)) + e + w[t] + 0x5a827999; + e = d; + d = c; + c = rol(b, 30); + b = a; + a = tmp; + } + for (t = 20; t < 40; t++) { + word32 tmp = rol(a, 5) + (b ^ c ^ d) + e + w[t] + 0x6ed9eba1; + e = d; + d = c; + c = rol(b, 30); + b = a; + a = tmp; + } + for (t = 40; t < 60; t++) { + word32 tmp = rol(a, + 5) + ((b & c) | (b & d) | (c & d)) + e + w[t] + + 0x8f1bbcdc; + e = d; + d = c; + c = rol(b, 30); + b = a; + a = tmp; + } + for (t = 60; t < 80; t++) { + word32 tmp = rol(a, 5) + (b ^ c ^ d) + e + w[t] + 0xca62c1d6; + e = d; + d = c; + c = rol(b, 30); + b = a; + a = tmp; + } + + digest[0] += a; + digest[1] += b; + digest[2] += c; + digest[3] += d; + digest[4] += e; + +#ifdef RANDOM_DIAGNOSTICS + { + extern int random_diagnostics; + if (random_diagnostics) { + int i; + printf(" ="); + for (i = 0; i < 5; i++) + printf(" %08x", digest[i]); + printf("\n"); + } + } +#endif +} + +/* ---------------------------------------------------------------------- + * Outer SHA algorithm: take an arbitrary length byte string, + * convert it into 16-word blocks with the prescribed padding at + * the end, and pass those blocks to the core SHA algorithm. + */ + +void SHA_Init(SHA_State * s) +{ + SHA_Core_Init(s->h); + s->blkused = 0; + s->lenhi = s->lenlo = 0; +} + +void SHA_Bytes(SHA_State * s, const void *p, int len) +{ + const unsigned char *q = (const unsigned char *) p; + uint32 wordblock[16]; + uint32 lenw = len; + int i; + + /* + * Update the length field. + */ + s->lenlo += lenw; + s->lenhi += (s->lenlo < lenw); + + if (s->blkused && s->blkused + len < 64) { + /* + * Trivial case: just add to the block. + */ + memcpy(s->block + s->blkused, q, len); + s->blkused += len; + } else { + /* + * We must complete and process at least one block. + */ + while (s->blkused + len >= 64) { + memcpy(s->block + s->blkused, q, 64 - s->blkused); + q += 64 - s->blkused; + len -= 64 - s->blkused; + /* Now process the block. Gather bytes big-endian into words */ + for (i = 0; i < 16; i++) { + wordblock[i] = + (((uint32) s->block[i * 4 + 0]) << 24) | + (((uint32) s->block[i * 4 + 1]) << 16) | + (((uint32) s->block[i * 4 + 2]) << 8) | + (((uint32) s->block[i * 4 + 3]) << 0); + } + SHATransform(s->h, wordblock); + s->blkused = 0; + } + memcpy(s->block, q, len); + s->blkused = len; + } +} + +void SHA_Final(SHA_State * s, unsigned char *output) +{ + int i; + int pad; + unsigned char c[64]; + uint32 lenhi, lenlo; + + if (s->blkused >= 56) + pad = 56 + 64 - s->blkused; + else + pad = 56 - s->blkused; + + lenhi = (s->lenhi << 3) | (s->lenlo >> (32 - 3)); + lenlo = (s->lenlo << 3); + + memset(c, 0, pad); + c[0] = 0x80; + SHA_Bytes(s, &c, pad); + + c[0] = (lenhi >> 24) & 0xFF; + c[1] = (lenhi >> 16) & 0xFF; + c[2] = (lenhi >> 8) & 0xFF; + c[3] = (lenhi >> 0) & 0xFF; + c[4] = (lenlo >> 24) & 0xFF; + c[5] = (lenlo >> 16) & 0xFF; + c[6] = (lenlo >> 8) & 0xFF; + c[7] = (lenlo >> 0) & 0xFF; + + SHA_Bytes(s, &c, 8); + + for (i = 0; i < 5; i++) { + output[i * 4] = (s->h[i] >> 24) & 0xFF; + output[i * 4 + 1] = (s->h[i] >> 16) & 0xFF; + output[i * 4 + 2] = (s->h[i] >> 8) & 0xFF; + output[i * 4 + 3] = (s->h[i]) & 0xFF; + } +} + +void SHA_Simple(const void *p, int len, unsigned char *output) +{ + SHA_State s; + + SHA_Init(&s); + SHA_Bytes(&s, p, len); + SHA_Final(&s, output); +} diff --git a/cipher/sha.h b/cipher/sha.h new file mode 100644 index 0000000..e8a5e2e --- /dev/null +++ b/cipher/sha.h @@ -0,0 +1,21 @@ +#ifndef _CIPHER_SHASHA_H +#define _CIPHER_SHASHA_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + typedef unsigned int uint32; + typedef uint32 word32; + typedef struct { + uint32 h[5]; + unsigned char block[64]; + int blkused; + uint32 lenhi, lenlo; + } SHA_State; + void SHA_Init(SHA_State * s); + void SHA_Bytes(SHA_State * s, const void *p, int len); + void SHA_Final(SHA_State * s, unsigned char *output); + void SHA_Simple(const void *p, int len, unsigned char *output); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _CIPHER_SHASHA_H */ diff --git a/cipher/sha1.c b/cipher/sha1.c new file mode 100644 index 0000000..0fa2fa6 --- /dev/null +++ b/cipher/sha1.c @@ -0,0 +1,296 @@ + +/* from valgrind tests */ + +/* ================ sha1.c ================ */ +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ +/* #define SHA1HANDSOFF * Copies data before messing with it. */ + +#define SHA1HANDSOFF + +#include +#include +#include /* for u_int*_t */ +#if defined(__sun) +#include "solarisfixes.h" +#endif +#include "sha1.h" +#ifndef BYTE_ORDER +#if (BSD >= 199103) +# include +#else +#if defined(linux) || defined(__linux__) +# include +#else +#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */ +#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ +#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp)*/ + +#if defined(__i386__) || defined(__x86_64__) || defined(__amd64__) || \ + defined(vax) || defined(ns32000) || defined(sun386) || \ + defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \ + defined(__alpha__) || defined(__alpha) +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ + defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ + defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ + defined(apollo) || defined(__convex__) || defined(_CRAY) || \ + defined(__hppa) || defined(__hp9000) || \ + defined(__hp9000s300) || defined(__hp9000s700) || \ + defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc) +#define BYTE_ORDER BIG_ENDIAN +#endif +#endif /* linux */ +#endif /* BSD */ +#endif /* BYTE_ORDER */ + +/* Sometimes after including an OS-specific header that defines the + * endianess we end with __BYTE_ORDER but not with BYTE_ORDER that is what + * the Redis code uses. In this case let's define everything without the + * underscores. */ +#ifndef BYTE_ORDER +#ifdef __BYTE_ORDER +#if defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN) +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN __LITTLE_ENDIAN +#endif +#ifndef BIG_ENDIAN +#define BIG_ENDIAN __BIG_ENDIAN +#endif +#if (__BYTE_ORDER == __LITTLE_ENDIAN) +#define BYTE_ORDER LITTLE_ENDIAN +#else +#define BYTE_ORDER BIG_ENDIAN +#endif +#endif +#endif +#endif + +#if !defined(BYTE_ORDER) || \ + (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN) + /* you must determine what the correct bit order is for + * your compiler - the next line is an intentional error + * which will force your compiles to bomb until you fix + * the above macros. + */ +#error "Undefined or invalid BYTE_ORDER" +#endif + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#if BYTE_ORDER == LITTLE_ENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#elif BYTE_ORDER == BIG_ENDIAN +#define blk0(i) block->l[i] +#else +#error "Endianness not defined!" +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]) +{ + unsigned int a, b, c, d, e; + typedef union { + unsigned char c[64]; + unsigned int l[16]; + } CHAR64LONG16; +#ifdef SHA1HANDSOFF + CHAR64LONG16 block[1]; /* use array to appear as a pointer */ + memcpy(block, buffer, 64); +#else + /* The following had better never be used because it causes the + * pointer-to-const buffer to be cast into a pointer to non-const. + * And the result is written through. I threw a "const" in, hoping + * this will cause a diagnostic. + */ + CHAR64LONG16* block = (const CHAR64LONG16*)buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +#ifdef SHA1HANDSOFF + memset(block, '\0', sizeof(block)); +#endif +} + + +/* SHA1Init - Initialize new context */ + +void SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void SHA1Update(SHA1_CTX* context, const unsigned char* data, unsigned int len) +{ + unsigned int i, j; + + j = context->count[0]; + if ((context->count[0] += len << 3) < j) + context->count[1]++; + context->count[1] += (len>>29); + j = (j >> 3) & 63; + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for (; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +void SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ + unsigned i; + unsigned char finalcount[8]; + unsigned char c; + +#if 0 /* untested "improvement" by DHR */ + /* Convert context->count to a sequence of bytes + * in finalcount. Second element first, but + * big-endian order within element. + * But we do it all backwards. + */ + unsigned char *fcp = &finalcount[8]; + + for (i = 0; i < 2; i++) + { + unsigned int t = context->count[i]; + int j; + + for (j = 0; j < 4; t >>= 8, j++) + *--fcp = (unsigned char) t; + } +#else + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8)) & 255); /* Endian independent */ + } +#endif + c = 0200; + SHA1Update(context, &c, 1); + while ((context->count[0] & 504) != 448) { + c = 0000; + SHA1Update(context, &c, 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i>>2] >> ((3-(i & 3)) * 8)) & 255); + } + /* Wipe variables */ + memset(context, '\0', sizeof(*context)); + memset(&finalcount, '\0', sizeof(finalcount)); +} + +void SHA1Calc(const unsigned char *input, unsigned int inlen, unsigned char *output) { + SHA1_CTX ctx; + SHA1Init(&ctx); + SHA1Update(&ctx, input, inlen); + SHA1Final(output, &ctx); +} +/* ================ end of sha1.cpp ================ */ + +#if 0 +#define BUFSIZE 4096 + +int +main(int argc, char **argv) +{ + SHA1_CTX ctx; + unsigned char hash[20], buf[BUFSIZE]; + int i; + + for(i=0;i +100% Public Domain +*/ +#ifndef _SYS_SHA1_H_ +#define _SYS_SHA1_H_ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + typedef struct { + unsigned int state[5]; + unsigned int count[2]; + unsigned char buffer[64]; + } SHA1_CTX; + + void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]); + void SHA1Init(SHA1_CTX* context); + void SHA1Update(SHA1_CTX* context, const unsigned char* data, unsigned int len); + void SHA1Final(unsigned char digest[20], SHA1_CTX* context); + // The function to calculate the message digest string + // of a given string based on the SHA1 algrithm. + void SHA1Calc(const unsigned char *input, unsigned int inlen, unsigned char *output); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _SYS_SHA1_H_ */ diff --git a/cipher/sha224.c b/cipher/sha224.c new file mode 100644 index 0000000..a5fcc83 --- /dev/null +++ b/cipher/sha224.c @@ -0,0 +1,38 @@ +#include +#include "sha224.h" + +void SHA224_Core_Init(SHA256_State *s) { + s->h[0] = 0xc1059ed8ul; + s->h[1] = 0x367cd507ul; + s->h[2] = 0x3070dd17ul; + s->h[3] = 0xf70e5939ul; + s->h[4] = 0xffc00b31ul; + s->h[5] = 0x68581511ul; + s->h[6] = 0x64f98fa7ul; + s->h[7] = 0xbefa4fa4ul; +} + +#define SHA224_DIGEST_SIZE 28 + +void SHA224_Init(SHA256_State *s) { + SHA224_Core_Init(s); + s->blkused = 0; + s->lenhi = s->lenlo = 0; +} + +void SHA224_Bytes(SHA256_State *s, const void *p, int len) { + SHA256_Bytes(s, p, len); +} + +void SHA224_Final(SHA256_State *s, unsigned char *digest) { + SHA256_Final(s, digest); + digest[SHA224_DIGEST_SIZE] = 0x00; +} + +void SHA224_Simple(const void *p, int len, unsigned char *output) { + SHA256_State s; + + SHA224_Init(&s); + SHA224_Bytes(&s, p, len); + SHA224_Final(&s, output); +} diff --git a/cipher/sha224.h b/cipher/sha224.h new file mode 100644 index 0000000..8faf02d --- /dev/null +++ b/cipher/sha224.h @@ -0,0 +1,15 @@ +#ifndef _CIPHER_SHA224_H +#define _CIPHER_SHA224_H +#include "sha256.h" +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + void SHA224_Init(SHA256_State * s); + void SHA224_Bytes(SHA256_State * s, const void *p, int len); + void SHA224_Final(SHA256_State * s, unsigned char *output); + void SHA224_Simple(const void *p, int len, unsigned char *output); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _CIPHER_SHA224_H */ diff --git a/cipher/sha256.c b/cipher/sha256.c new file mode 100644 index 0000000..4e118d6 --- /dev/null +++ b/cipher/sha256.c @@ -0,0 +1,243 @@ +/* + * SHA-256 algorithm as described at + * + * http://csrc.nist.gov/cryptval/shs.html + */ +#include +#include "sha256.h" +//#define TEST +/* ---------------------------------------------------------------------- + * Core SHA256 algorithm: processes 16-word blocks into a message digest. + */ + +#define ror(x,y) ( ((x) << (32-y)) | (((uint32)(x)) >> (y)) ) +#define shr(x,y) ( (((uint32)(x)) >> (y)) ) +#define Ch(x,y,z) ( ((x) & (y)) ^ (~(x) & (z)) ) +#define Maj(x,y,z) ( ((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)) ) +#define bigsigma0(x) ( ror((x),2) ^ ror((x),13) ^ ror((x),22) ) +#define bigsigma1(x) ( ror((x),6) ^ ror((x),11) ^ ror((x),25) ) +#define smallsigma0(x) ( ror((x),7) ^ ror((x),18) ^ shr((x),3) ) +#define smallsigma1(x) ( ror((x),17) ^ ror((x),19) ^ shr((x),10) ) + +#define PUT_32BIT_MSB_FIRST(cp, value) ( \ + (cp)[0] = (unsigned char)((value) >> 24), \ + (cp)[1] = (unsigned char)((value) >> 16), \ + (cp)[2] = (unsigned char)((value) >> 8), \ + (cp)[3] = (unsigned char)(value) ) + +void SHA256_Core_Init(SHA256_State *s) { + s->h[0] = 0x6a09e667; + s->h[1] = 0xbb67ae85; + s->h[2] = 0x3c6ef372; + s->h[3] = 0xa54ff53a; + s->h[4] = 0x510e527f; + s->h[5] = 0x9b05688c; + s->h[6] = 0x1f83d9ab; + s->h[7] = 0x5be0cd19; +} + +void SHA256_Block(SHA256_State *s, uint32 *block) { + uint32 w[80]; + uint32 a,b,c,d,e,f,g,h; + static const int k[] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, + }; + + int t; + + for (t = 0; t < 16; t++) + w[t] = block[t]; + + for (t = 16; t < 64; t++) + w[t] = smallsigma1(w[t-2]) + w[t-7] + smallsigma0(w[t-15]) + w[t-16]; + + a = s->h[0]; b = s->h[1]; c = s->h[2]; d = s->h[3]; + e = s->h[4]; f = s->h[5]; g = s->h[6]; h = s->h[7]; + + for (t = 0; t < 64; t+=8) { + uint32 t1, t2; + +#define ROUND(j,a,b,c,d,e,f,g,h) \ + t1 = h + bigsigma1(e) + Ch(e,f,g) + k[j] + w[j]; \ + t2 = bigsigma0(a) + Maj(a,b,c); \ + d = d + t1; h = t1 + t2; + + ROUND(t+0, a,b,c,d,e,f,g,h); + ROUND(t+1, h,a,b,c,d,e,f,g); + ROUND(t+2, g,h,a,b,c,d,e,f); + ROUND(t+3, f,g,h,a,b,c,d,e); + ROUND(t+4, e,f,g,h,a,b,c,d); + ROUND(t+5, d,e,f,g,h,a,b,c); + ROUND(t+6, c,d,e,f,g,h,a,b); + ROUND(t+7, b,c,d,e,f,g,h,a); + } + + s->h[0] += a; s->h[1] += b; s->h[2] += c; s->h[3] += d; + s->h[4] += e; s->h[5] += f; s->h[6] += g; s->h[7] += h; +} + +/* ---------------------------------------------------------------------- + * Outer SHA256 algorithm: take an arbitrary length byte string, + * convert it into 16-word blocks with the prescribed padding at + * the end, and pass those blocks to the core SHA256 algorithm. + */ + +#define BLKSIZE 64 + +void SHA256_Init(SHA256_State *s) { + SHA256_Core_Init(s); + s->blkused = 0; + s->lenhi = s->lenlo = 0; +} + +void SHA256_Bytes(SHA256_State *s, const void *p, int len) { + unsigned char *q = (unsigned char *)p; + uint32 wordblock[16]; + uint32 lenw = len; + int i; + + /* + * Update the length field. + */ + s->lenlo += lenw; + s->lenhi += (s->lenlo < lenw); + + if (s->blkused && s->blkused+len < BLKSIZE) { + /* + * Trivial case: just add to the block. + */ + memcpy(s->block + s->blkused, q, len); + s->blkused += len; + } else { + /* + * We must complete and process at least one block. + */ + while (s->blkused + len >= BLKSIZE) { + memcpy(s->block + s->blkused, q, BLKSIZE - s->blkused); + q += BLKSIZE - s->blkused; + len -= BLKSIZE - s->blkused; + /* Now process the block. Gather bytes big-endian into words */ + for (i = 0; i < 16; i++) { + wordblock[i] = + ( ((uint32)s->block[i*4+0]) << 24 ) | + ( ((uint32)s->block[i*4+1]) << 16 ) | + ( ((uint32)s->block[i*4+2]) << 8 ) | + ( ((uint32)s->block[i*4+3]) << 0 ); + } + SHA256_Block(s, wordblock); + s->blkused = 0; + } + memcpy(s->block, q, len); + s->blkused = len; + } +} + +void SHA256_Final(SHA256_State *s, unsigned char *digest) { + int i; + int pad; + unsigned char c[64]; + uint32 lenhi, lenlo; + + if (s->blkused >= 56) + pad = 56 + 64 - s->blkused; + else + pad = 56 - s->blkused; + + lenhi = (s->lenhi << 3) | (s->lenlo >> (32-3)); + lenlo = (s->lenlo << 3); + + memset(c, 0, pad); + c[0] = 0x80; + SHA256_Bytes(s, &c, pad); + + c[0] = (lenhi >> 24) & 0xFF; + c[1] = (lenhi >> 16) & 0xFF; + c[2] = (lenhi >> 8) & 0xFF; + c[3] = (lenhi >> 0) & 0xFF; + c[4] = (lenlo >> 24) & 0xFF; + c[5] = (lenlo >> 16) & 0xFF; + c[6] = (lenlo >> 8) & 0xFF; + c[7] = (lenlo >> 0) & 0xFF; + + SHA256_Bytes(s, &c, 8); + + for (i = 0; i < 8; i++) { + digest[i*4+0] = (s->h[i] >> 24) & 0xFF; + digest[i*4+1] = (s->h[i] >> 16) & 0xFF; + digest[i*4+2] = (s->h[i] >> 8) & 0xFF; + digest[i*4+3] = (s->h[i] >> 0) & 0xFF; + } +} + +void SHA256_Simple(const void *p, int len, unsigned char *output) { + SHA256_State s; + + SHA256_Init(&s); + SHA256_Bytes(&s, p, len); + SHA256_Final(&s, output); +} + +#ifdef TEST + +#include +#include +#include + +int main(void) { + unsigned char digest[32]; + int i, j, errors; + + struct { + const char *teststring; + unsigned char digest[32]; + } tests[] = { + { "abc", { + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, + 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, + 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad, + } }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", { + 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, + 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, + 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1, + } }, + }; + + errors = 0; + + for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) { + SHA256_Simple(tests[i].teststring, + strlen(tests[i].teststring), digest); + for (j = 0; j < 32; j++) { + if (digest[j] != tests[i].digest[j]) { + fprintf(stderr, + "\"%s\" digest byte %d should be 0x%02x, is 0x%02x\n", + tests[i].teststring, j, tests[i].digest[j], digest[j]); + errors++; + } + } + } + + printf("%d errors\n", errors); + + return 0; +} + +#endif diff --git a/cipher/sha256.h b/cipher/sha256.h new file mode 100644 index 0000000..042e9c2 --- /dev/null +++ b/cipher/sha256.h @@ -0,0 +1,22 @@ +#ifndef _CIPHER_SHA256_H +#define _CIPHER_SHA256_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + typedef unsigned int uint32; + typedef struct { + uint32 h[8]; + unsigned char block[64]; + int blkused; + uint32 lenhi, lenlo; + } SHA256_State; + void SHA256_Init(SHA256_State * s); + void SHA256_Bytes(SHA256_State * s, const void *p, int len); + void SHA256_Final(SHA256_State * s, unsigned char *output); + void SHA256_Simple(const void *p, int len, unsigned char *output); + void sha256_do_hmac(unsigned char* key, int keylen, + unsigned char *blk, int len, unsigned char *hmac); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _CIPHER_SHA256_H */ diff --git a/cipher/sha384.c b/cipher/sha384.c new file mode 100644 index 0000000..304522e --- /dev/null +++ b/cipher/sha384.c @@ -0,0 +1,41 @@ +#include "sha384.h" + +#define INIT(h,l) { h, l } + +static void SHA384_Core_Init(SHA512_State *s) { + static const uint64 iv[] = { + INIT(0xcbbb9d5d, 0xc1059ed8), INIT(0x629a292a, 0x367cd507), + INIT(0x9159015a, 0x3070dd17), INIT(0x152fecd8, 0xf70e5939), + INIT(0x67332667, 0xffc00b31), INIT(0x8eb44a87, 0x68581511), + INIT(0xdb0c2e0d, 0x64f98fa7), INIT(0x47b5481d, 0xbefa4fa4), + }; + int i; + for (i = 0; i < 8; i++) + s->h[i] = iv[i]; +} + +void SHA384_Init(SHA512_State *s) { + int i; + SHA384_Core_Init(s); + s->blkused = 0; + for (i = 0; i < 4; i++) + s->len[i] = 0; +} + +void SHA384_Bytes(SHA512_State *s, const void *p, int len) { + SHA512_Bytes(s, p, len); +} + +#define SHA384_DIGEST_SIZE 48 +void SHA384_Final(SHA512_State *s, unsigned char *digest) { + SHA512_Final(s, digest); + digest[SHA384_DIGEST_SIZE] = 0x00; +} + +void SHA384_Simple(const void *p, int len, unsigned char *output) { + SHA512_State s; + + SHA384_Init(&s); + SHA384_Bytes(&s, p, len); + SHA384_Final(&s, output); +} diff --git a/cipher/sha384.h b/cipher/sha384.h new file mode 100644 index 0000000..e37f25e --- /dev/null +++ b/cipher/sha384.h @@ -0,0 +1,14 @@ +#ifndef _CIPHER_SHA384_H +#define _CIPHER_SHA384_H +#include "sha512.h" +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + void SHA384_Init(SHA512_State * s); + void SHA384_Bytes(SHA512_State * s, const void *p, int len); + void SHA384_Final(SHA512_State * s, unsigned char *output); + void SHA384_Simple(const void *p, int len, unsigned char *output); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _CIPHER_SHA384_H */ diff --git a/cipher/sha512.c b/cipher/sha512.c new file mode 100644 index 0000000..0075313 --- /dev/null +++ b/cipher/sha512.c @@ -0,0 +1,364 @@ +/* + * SHA-512 algorithm as described at + * + * http://csrc.nist.gov/cryptval/shs.html + */ +#include +#include "sha512.h" +//#define TEST +#define BLKSIZE 128 + +/* + * Arithmetic implementations. Note that AND, XOR and NOT can + * overlap destination with one source, but the others can't. + */ +#define add(r,x,y) ( r.lo = y.lo + x.lo, \ + r.hi = y.hi + x.hi + ((uint32)r.lo < (uint32)y.lo) ) +#define rorB(r,x,y) ( r.lo = ((uint32)x.hi >> ((y)-32)) | ((uint32)x.lo << (64-(y))), \ + r.hi = ((uint32)x.lo >> ((y)-32)) | ((uint32)x.hi << (64-(y))) ) +#define rorL(r,x,y) ( r.lo = ((uint32)x.lo >> (y)) | ((uint32)x.hi << (32-(y))), \ + r.hi = ((uint32)x.hi >> (y)) | ((uint32)x.lo << (32-(y))) ) +#define shrB(r,x,y) ( r.lo = (uint32)x.hi >> ((y)-32), r.hi = 0 ) +#define shrL(r,x,y) ( r.lo = ((uint32)x.lo >> (y)) | ((uint32)x.hi << (32-(y))), \ + r.hi = (uint32)x.hi >> (y) ) +#define and(r,x,y) ( r.lo = x.lo & y.lo, r.hi = x.hi & y.hi ) +#define xor(r,x,y) ( r.lo = x.lo ^ y.lo, r.hi = x.hi ^ y.hi ) +#define not(r,x) ( r.lo = ~x.lo, r.hi = ~x.hi ) +#define INIT(h,l) { h, l } +#define BUILD(r,h,l) ( r.hi = h, r.lo = l ) +#define EXTRACT(h,l,r) ( h = r.hi, l = r.lo ) + +/* ---------------------------------------------------------------------- + * Core SHA512 algorithm: processes 16-doubleword blocks into a + * message digest. + */ + +#define Ch(r,t,x,y,z) ( not(t,x), and(r,t,z), and(t,x,y), xor(r,r,t) ) +#define Maj(r,t,x,y,z) ( and(r,x,y), and(t,x,z), xor(r,r,t), \ + and(t,y,z), xor(r,r,t) ) +#define bigsigma0(r,t,x) ( rorL(r,x,28), rorB(t,x,34), xor(r,r,t), \ + rorB(t,x,39), xor(r,r,t) ) +#define bigsigma1(r,t,x) ( rorL(r,x,14), rorL(t,x,18), xor(r,r,t), \ + rorB(t,x,41), xor(r,r,t) ) +#define smallsigma0(r,t,x) ( rorL(r,x,1), rorL(t,x,8), xor(r,r,t), \ + shrL(t,x,7), xor(r,r,t) ) +#define smallsigma1(r,t,x) ( rorL(r,x,19), rorB(t,x,61), xor(r,r,t), \ + shrL(t,x,6), xor(r,r,t) ) + +#define PUT_32BIT_MSB_FIRST(cp, value) ( \ + (cp)[0] = (unsigned char)((value) >> 24), \ + (cp)[1] = (unsigned char)((value) >> 16), \ + (cp)[2] = (unsigned char)((value) >> 8), \ + (cp)[3] = (unsigned char)(value)) + +static void SHA512_Core_Init(SHA512_State *s) { + static const uint64 iv[] = { + INIT(0x6a09e667, 0xf3bcc908), + INIT(0xbb67ae85, 0x84caa73b), + INIT(0x3c6ef372, 0xfe94f82b), + INIT(0xa54ff53a, 0x5f1d36f1), + INIT(0x510e527f, 0xade682d1), + INIT(0x9b05688c, 0x2b3e6c1f), + INIT(0x1f83d9ab, 0xfb41bd6b), + INIT(0x5be0cd19, 0x137e2179), + }; + int i; + for (i = 0; i < 8; i++) + s->h[i] = iv[i]; +} + +static void SHA512_Block(SHA512_State *s, uint64 *block) { + uint64 w[80]; + uint64 a,b,c,d,e,f,g,h; + static const uint64 k[] = { + INIT(0x428a2f98, 0xd728ae22), INIT(0x71374491, 0x23ef65cd), + INIT(0xb5c0fbcf, 0xec4d3b2f), INIT(0xe9b5dba5, 0x8189dbbc), + INIT(0x3956c25b, 0xf348b538), INIT(0x59f111f1, 0xb605d019), + INIT(0x923f82a4, 0xaf194f9b), INIT(0xab1c5ed5, 0xda6d8118), + INIT(0xd807aa98, 0xa3030242), INIT(0x12835b01, 0x45706fbe), + INIT(0x243185be, 0x4ee4b28c), INIT(0x550c7dc3, 0xd5ffb4e2), + INIT(0x72be5d74, 0xf27b896f), INIT(0x80deb1fe, 0x3b1696b1), + INIT(0x9bdc06a7, 0x25c71235), INIT(0xc19bf174, 0xcf692694), + INIT(0xe49b69c1, 0x9ef14ad2), INIT(0xefbe4786, 0x384f25e3), + INIT(0x0fc19dc6, 0x8b8cd5b5), INIT(0x240ca1cc, 0x77ac9c65), + INIT(0x2de92c6f, 0x592b0275), INIT(0x4a7484aa, 0x6ea6e483), + INIT(0x5cb0a9dc, 0xbd41fbd4), INIT(0x76f988da, 0x831153b5), + INIT(0x983e5152, 0xee66dfab), INIT(0xa831c66d, 0x2db43210), + INIT(0xb00327c8, 0x98fb213f), INIT(0xbf597fc7, 0xbeef0ee4), + INIT(0xc6e00bf3, 0x3da88fc2), INIT(0xd5a79147, 0x930aa725), + INIT(0x06ca6351, 0xe003826f), INIT(0x14292967, 0x0a0e6e70), + INIT(0x27b70a85, 0x46d22ffc), INIT(0x2e1b2138, 0x5c26c926), + INIT(0x4d2c6dfc, 0x5ac42aed), INIT(0x53380d13, 0x9d95b3df), + INIT(0x650a7354, 0x8baf63de), INIT(0x766a0abb, 0x3c77b2a8), + INIT(0x81c2c92e, 0x47edaee6), INIT(0x92722c85, 0x1482353b), + INIT(0xa2bfe8a1, 0x4cf10364), INIT(0xa81a664b, 0xbc423001), + INIT(0xc24b8b70, 0xd0f89791), INIT(0xc76c51a3, 0x0654be30), + INIT(0xd192e819, 0xd6ef5218), INIT(0xd6990624, 0x5565a910), + INIT(0xf40e3585, 0x5771202a), INIT(0x106aa070, 0x32bbd1b8), + INIT(0x19a4c116, 0xb8d2d0c8), INIT(0x1e376c08, 0x5141ab53), + INIT(0x2748774c, 0xdf8eeb99), INIT(0x34b0bcb5, 0xe19b48a8), + INIT(0x391c0cb3, 0xc5c95a63), INIT(0x4ed8aa4a, 0xe3418acb), + INIT(0x5b9cca4f, 0x7763e373), INIT(0x682e6ff3, 0xd6b2b8a3), + INIT(0x748f82ee, 0x5defb2fc), INIT(0x78a5636f, 0x43172f60), + INIT(0x84c87814, 0xa1f0ab72), INIT(0x8cc70208, 0x1a6439ec), + INIT(0x90befffa, 0x23631e28), INIT(0xa4506ceb, 0xde82bde9), + INIT(0xbef9a3f7, 0xb2c67915), INIT(0xc67178f2, 0xe372532b), + INIT(0xca273ece, 0xea26619c), INIT(0xd186b8c7, 0x21c0c207), + INIT(0xeada7dd6, 0xcde0eb1e), INIT(0xf57d4f7f, 0xee6ed178), + INIT(0x06f067aa, 0x72176fba), INIT(0x0a637dc5, 0xa2c898a6), + INIT(0x113f9804, 0xbef90dae), INIT(0x1b710b35, 0x131c471b), + INIT(0x28db77f5, 0x23047d84), INIT(0x32caab7b, 0x40c72493), + INIT(0x3c9ebe0a, 0x15c9bebc), INIT(0x431d67c4, 0x9c100d4c), + INIT(0x4cc5d4be, 0xcb3e42b6), INIT(0x597f299c, 0xfc657e2a), + INIT(0x5fcb6fab, 0x3ad6faec), INIT(0x6c44198c, 0x4a475817), + }; + + int t; + + for (t = 0; t < 16; t++) + w[t] = block[t]; + + for (t = 16; t < 80; t++) { + uint64 p, q, r, tmp; + smallsigma1(p, tmp, w[t-2]); + smallsigma0(q, tmp, w[t-15]); + add(r, p, q); + add(p, r, w[t-7]); + add(w[t], p, w[t-16]); + } + + a = s->h[0]; b = s->h[1]; c = s->h[2]; d = s->h[3]; + e = s->h[4]; f = s->h[5]; g = s->h[6]; h = s->h[7]; + + for (t = 0; t < 80; t+=8) { + uint64 tmp, p, q, r; + +#define ROUND(j,a,b,c,d,e,f,g,h) \ + bigsigma1(p, tmp, e); \ + Ch(q, tmp, e, f, g); \ + add(r, p, q); \ + add(p, r, k[j]) ; \ + add(q, p, w[j]); \ + add(r, q, h); \ + bigsigma0(p, tmp, a); \ + Maj(tmp, q, a, b, c); \ + add(q, tmp, p); \ + add(p, r, d); \ + d = p; \ + add(h, q, r); + + ROUND(t+0, a,b,c,d,e,f,g,h); + ROUND(t+1, h,a,b,c,d,e,f,g); + ROUND(t+2, g,h,a,b,c,d,e,f); + ROUND(t+3, f,g,h,a,b,c,d,e); + ROUND(t+4, e,f,g,h,a,b,c,d); + ROUND(t+5, d,e,f,g,h,a,b,c); + ROUND(t+6, c,d,e,f,g,h,a,b); + ROUND(t+7, b,c,d,e,f,g,h,a); + } + + { + uint64 tmp; +#define UPDATE(state, local) ( tmp = state, add(state, tmp, local) ) + UPDATE(s->h[0], a); UPDATE(s->h[1], b); + UPDATE(s->h[2], c); UPDATE(s->h[3], d); + UPDATE(s->h[4], e); UPDATE(s->h[5], f); + UPDATE(s->h[6], g); UPDATE(s->h[7], h); + } +} + +/* ---------------------------------------------------------------------- + * Outer SHA512 algorithm: take an arbitrary length byte string, + * convert it into 16-doubleword blocks with the prescribed padding + * at the end, and pass those blocks to the core SHA512 algorithm. + */ + +void SHA512_Init(SHA512_State *s) { + int i; + SHA512_Core_Init(s); + s->blkused = 0; + for (i = 0; i < 4; i++) + s->len[i] = 0; +} + +void SHA512_Bytes(SHA512_State *s, const void *p, int len) { + unsigned char *q = (unsigned char *)p; + uint64 wordblock[16]; + uint32 lenw = len; + int i; + + /* + * Update the length field. + */ + for (i = 0; i < 4; i++) { + s->len[i] += lenw; + lenw = (s->len[i] < lenw); + } + + if (s->blkused && s->blkused+len < BLKSIZE) { + /* + * Trivial case: just add to the block. + */ + memcpy(s->block + s->blkused, q, len); + s->blkused += len; + } else { + /* + * We must complete and process at least one block. + */ + while (s->blkused + len >= BLKSIZE) { + memcpy(s->block + s->blkused, q, BLKSIZE - s->blkused); + q += BLKSIZE - s->blkused; + len -= BLKSIZE - s->blkused; + /* Now process the block. Gather bytes big-endian into words */ + for (i = 0; i < 16; i++) { + uint32 h, l; + h = ( ((uint32)s->block[i*8+0]) << 24 ) | + ( ((uint32)s->block[i*8+1]) << 16 ) | + ( ((uint32)s->block[i*8+2]) << 8 ) | + ( ((uint32)s->block[i*8+3]) << 0 ); + l = ( ((uint32)s->block[i*8+4]) << 24 ) | + ( ((uint32)s->block[i*8+5]) << 16 ) | + ( ((uint32)s->block[i*8+6]) << 8 ) | + ( ((uint32)s->block[i*8+7]) << 0 ); + BUILD(wordblock[i], h, l); + } + SHA512_Block(s, wordblock); + s->blkused = 0; + } + memcpy(s->block, q, len); + s->blkused = len; + } +} + +void SHA512_Final(SHA512_State *s, unsigned char *digest) { + int i; + int pad; + unsigned char c[BLKSIZE]; + uint32 len[4]; + + if (s->blkused >= BLKSIZE-16) + pad = (BLKSIZE-16) + BLKSIZE - s->blkused; + else + pad = (BLKSIZE-16) - s->blkused; + + for (i = 4; i-- ;) { + uint32 lenhi = s->len[i]; + uint32 lenlo = i > 0 ? s->len[i-1] : 0; + len[i] = (lenhi << 3) | (lenlo >> (32-3)); + } + + memset(c, 0, pad); + c[0] = 0x80; + SHA512_Bytes(s, &c, pad); + + for (i = 0; i < 4; i++) { + c[i*4+0] = (len[3-i] >> 24) & 0xFF; + c[i*4+1] = (len[3-i] >> 16) & 0xFF; + c[i*4+2] = (len[3-i] >> 8) & 0xFF; + c[i*4+3] = (len[3-i] >> 0) & 0xFF; + } + + SHA512_Bytes(s, &c, 16); + + for (i = 0; i < 8; i++) { + uint32 h, l; + EXTRACT(h, l, s->h[i]); + digest[i*8+0] = (h >> 24) & 0xFF; + digest[i*8+1] = (h >> 16) & 0xFF; + digest[i*8+2] = (h >> 8) & 0xFF; + digest[i*8+3] = (h >> 0) & 0xFF; + digest[i*8+4] = (l >> 24) & 0xFF; + digest[i*8+5] = (l >> 16) & 0xFF; + digest[i*8+6] = (l >> 8) & 0xFF; + digest[i*8+7] = (l >> 0) & 0xFF; + } +} + +void SHA512_Simple(const void *p, int len, unsigned char *output) { + SHA512_State s; + + SHA512_Init(&s); + SHA512_Bytes(&s, p, len); + SHA512_Final(&s, output); +} + +#ifdef TEST + +#include +#include +#include + +int main(void) { + unsigned char digest[64]; + int i, j, errors; + + struct { + const char *teststring; + unsigned char digest512[64]; + } tests[] = { + { "abc", { + 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, + 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, + 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, + 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, + 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, + 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, + 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, + 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f, + } }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", { + 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, + 0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f, + 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1, + 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, + 0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, + 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a, + 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54, + 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09, + } }, + { NULL, { + 0xe7, 0x18, 0x48, 0x3d, 0x0c, 0xe7, 0x69, 0x64, + 0x4e, 0x2e, 0x42, 0xc7, 0xbc, 0x15, 0xb4, 0x63, + 0x8e, 0x1f, 0x98, 0xb1, 0x3b, 0x20, 0x44, 0x28, + 0x56, 0x32, 0xa8, 0x03, 0xaf, 0xa9, 0x73, 0xeb, + 0xde, 0x0f, 0xf2, 0x44, 0x87, 0x7e, 0xa6, 0x0a, + 0x4c, 0xb0, 0x43, 0x2c, 0xe5, 0x77, 0xc3, 0x1b, + 0xeb, 0x00, 0x9c, 0x5c, 0x2c, 0x49, 0xaa, 0x2e, + 0x4e, 0xad, 0xb2, 0x17, 0xad, 0x8c, 0xc0, 0x9b, + } }, + }; + + errors = 0; + + for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) { + if (tests[i].teststring) { + SHA512_Simple(tests[i].teststring, + strlen(tests[i].teststring), digest); + } else { + SHA512_State s; + int n; + SHA512_Init(&s); + for (n = 0; n < 1000000 / 40; n++) + SHA512_Bytes(&s, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + 40); + SHA512_Final(&s, digest); + } + for (j = 0; j < 64; j++) { + if (digest[j] != tests[i].digest512[j]) { + fprintf(stderr, + "\"%s\" digest512 byte %d should be 0x%02x, is 0x%02x\n", + tests[i].teststring, j, tests[i].digest512[j], + digest[j]); + errors++; + } + } + + } + + printf("%d errors\n", errors); + + return 0; +} + +#endif diff --git a/cipher/sha512.h b/cipher/sha512.h new file mode 100644 index 0000000..c925191 --- /dev/null +++ b/cipher/sha512.h @@ -0,0 +1,23 @@ +#ifndef _CIPHER_SHA512_H +#define _CIPHER_SHA512_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + typedef struct { + unsigned long hi, lo; + } uint64; + typedef unsigned int uint32; + typedef struct { + uint64 h[8]; + unsigned char block[128]; + int blkused; + uint32 len[4]; + } SHA512_State; + void SHA512_Init(SHA512_State * s); + void SHA512_Bytes(SHA512_State * s, const void *p, int len); + void SHA512_Final(SHA512_State * s, unsigned char *output); + void SHA512_Simple(const void *p, int len, unsigned char *output); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _CIPHER_SHA512_H */ diff --git a/cipher/ssh.h b/cipher/ssh.h new file mode 100644 index 0000000..1dc0d0e --- /dev/null +++ b/cipher/ssh.h @@ -0,0 +1,57 @@ +#ifndef _CIPHER_SSHSSH_H_ +#define _CIPHER_SSHSSH_H_ +#include +#include +#include +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + struct ssh_mac { + void *(*make_context)(void); + void (*free_context)(void *); + void (*setkey) (void *, unsigned char *key); + /* whole-packet operations */ + void (*generate) (void *, unsigned char *blk, int len, unsigned long seq); + int (*verify) (void *, unsigned char *blk, int len, unsigned long seq); + /* partial-packet operations */ + void (*start) (void *); + void (*bytes) (void *, unsigned char *, int); + void (*genresult) (void *, unsigned char *); + int (*verresult) (void *, unsigned char *); + char *name; + int len; + char *text_name; + }; + + struct ssh_hash { + void *(*init)(void); /* also allocates context */ + void (*bytes)(void *, void *, int); + void (*final)(void *, unsigned char *); /* also frees context */ + int hlen; /* output length in bytes */ + char *text_name; + }; + struct ssh2_cipher { + void *(*make_context)(void); + void (*free_context)(void *); + void (*setiv) (void *, unsigned char *key); /* for SSH-2 */ + void (*setkey) (void *, unsigned char *key);/* for SSH-2 */ + void (*encrypt) (void *, unsigned char *blk, int len); + void (*decrypt) (void *, unsigned char *blk, int len); + char *name; + int blksize; + int keylen; + unsigned int flags; + #define SSH_CIPHER_IS_CBC 1 + char *text_name; + }; + extern const struct ssh_mac ssh_hmac_md5; + extern const struct ssh_mac ssh_hmac_sha1; + extern const struct ssh_mac ssh_hmac_sha1_buggy; + extern const struct ssh_mac ssh_hmac_sha1_96; + extern const struct ssh_mac ssh_hmac_sha1_96_buggy; + extern const struct ssh_mac ssh_hmac_sha256; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _CIPHER_SSHSSH_H_ */ diff --git a/cipher/tdes.c b/cipher/tdes.c new file mode 100644 index 0000000..b9c08b2 --- /dev/null +++ b/cipher/tdes.c @@ -0,0 +1,1246 @@ +#include +#include +#include "tdes.h" +#define MAX_CI_LEN 1024 +#ifndef LINUX +struct byte +{ + unsigned bit7:1; + unsigned bit6:1; + unsigned bit5:1; + unsigned bit4:1; + unsigned bit3:1; + unsigned bit2:1; + unsigned bit1:1; + unsigned bit0:1; +}; +#else +struct byte +{ + unsigned bit0:1; + unsigned bit1:1; + unsigned bit2:1; + unsigned bit3:1; + unsigned bit4:1; + unsigned bit5:1; + unsigned bit6:1; + unsigned bit7:1; +}; +#endif +union hbyte +{ + struct byte ibyte; + unsigned char abyte; +}; + +char triple_des_key[16]={0x44,0x2f,0x7c,0xda,0x9c,0xb0,0x98,0xe8, +0x8f,0xc5,0xd4,0xfd,0x32,0x79,0x24,0x12}; + +/*----------------------------------------------------------- +DES Expand procedure +Description: Expand 32 bits to 48 bits +-----------------------------------------------------------*/ +void expand(char in[4], char out[6]) +{ + union hbyte ip1; + union hbyte ipr; + ip1.abyte=0; + ipr.abyte=0; + + ip1.abyte=in[0]; ipr.ibyte.bit7=ip1.ibyte.bit0; /* bit 32 */ + ip1.abyte=in[3]; ipr.ibyte.bit6=ip1.ibyte.bit7; /* bit 1 */ + ip1.abyte=in[3]; ipr.ibyte.bit5=ip1.ibyte.bit6; /* bit 2 */ + ip1.abyte=in[3]; ipr.ibyte.bit4=ip1.ibyte.bit5; /* bit 3 */ + ip1.abyte=in[3]; ipr.ibyte.bit3=ip1.ibyte.bit4; /* bit 4 */ + ip1.abyte=in[3]; ipr.ibyte.bit2=ip1.ibyte.bit3; /* bit 5 */ + ip1.abyte=in[3]; ipr.ibyte.bit1=ip1.ibyte.bit4; /* bit 4 */ + ip1.abyte=in[3]; ipr.ibyte.bit0=ip1.ibyte.bit3; /* bit 5 */ + out[5]=ipr.abyte; + + ip1.abyte=in[3]; ipr.ibyte.bit7=ip1.ibyte.bit2; /* bit 6 */ + ip1.abyte=in[3]; ipr.ibyte.bit6=ip1.ibyte.bit1; /* bit 7 */ + ip1.abyte=in[3]; ipr.ibyte.bit5=ip1.ibyte.bit0; /* bit 8 */ + ip1.abyte=in[2]; ipr.ibyte.bit4=ip1.ibyte.bit7; /* bit 9 */ + ip1.abyte=in[3]; ipr.ibyte.bit3=ip1.ibyte.bit0; /* bit 8 */ + ip1.abyte=in[2]; ipr.ibyte.bit2=ip1.ibyte.bit7; /* bit 9 */ + ip1.abyte=in[2]; ipr.ibyte.bit1=ip1.ibyte.bit6; /* bit 10 */ + ip1.abyte=in[2]; ipr.ibyte.bit0=ip1.ibyte.bit5; /* bit 11 */ + out[4]=ipr.abyte; + + ip1.abyte=in[2]; ipr.ibyte.bit7=ip1.ibyte.bit4; /* bit 12 */ + ip1.abyte=in[2]; ipr.ibyte.bit6=ip1.ibyte.bit3; /* bit 13 */ + ip1.abyte=in[2]; ipr.ibyte.bit5=ip1.ibyte.bit4; /* bit 12 */ + ip1.abyte=in[2]; ipr.ibyte.bit4=ip1.ibyte.bit3; /* bit 13 */ + ip1.abyte=in[2]; ipr.ibyte.bit3=ip1.ibyte.bit2; /* bit 14 */ + ip1.abyte=in[2]; ipr.ibyte.bit2=ip1.ibyte.bit1; /* bit 15 */ + ip1.abyte=in[2]; ipr.ibyte.bit1=ip1.ibyte.bit0; /* bit 16 */ + ip1.abyte=in[1]; ipr.ibyte.bit0=ip1.ibyte.bit7; /* bit 17 */ + out[3]=ipr.abyte; + + ip1.abyte=in[2]; ipr.ibyte.bit7=ip1.ibyte.bit0; /* bit 16 */ + ip1.abyte=in[1]; ipr.ibyte.bit6=ip1.ibyte.bit7; /* bit 17 */ + ip1.abyte=in[1]; ipr.ibyte.bit5=ip1.ibyte.bit6; /* bit 18 */ + ip1.abyte=in[1]; ipr.ibyte.bit4=ip1.ibyte.bit5; /* bit 19 */ + ip1.abyte=in[1]; ipr.ibyte.bit3=ip1.ibyte.bit4; /* bit 20 */ + ip1.abyte=in[1]; ipr.ibyte.bit2=ip1.ibyte.bit3; /* bit 21 */ + ip1.abyte=in[1]; ipr.ibyte.bit1=ip1.ibyte.bit4; /* bit 20 */ + ip1.abyte=in[1]; ipr.ibyte.bit0=ip1.ibyte.bit3; /* bit 21 */ + out[2]=ipr.abyte; + + ip1.abyte=in[1]; ipr.ibyte.bit7=ip1.ibyte.bit2; /* bit 22 */ + ip1.abyte=in[1]; ipr.ibyte.bit6=ip1.ibyte.bit1; /* bit 23 */ + ip1.abyte=in[1]; ipr.ibyte.bit5=ip1.ibyte.bit0; /* bit 24 */ + ip1.abyte=in[0]; ipr.ibyte.bit4=ip1.ibyte.bit7; /* bit 25 */ + ip1.abyte=in[1]; ipr.ibyte.bit3=ip1.ibyte.bit0; /* bit 24 */ + ip1.abyte=in[0]; ipr.ibyte.bit2=ip1.ibyte.bit7; /* bit 25 */ + ip1.abyte=in[0]; ipr.ibyte.bit1=ip1.ibyte.bit6; /* bit 26 */ + ip1.abyte=in[0]; ipr.ibyte.bit0=ip1.ibyte.bit5; /* bit 27 */ + out[1]=ipr.abyte; + + ip1.abyte=in[0]; ipr.ibyte.bit7=ip1.ibyte.bit4; /* bit 28 */ + ip1.abyte=in[0]; ipr.ibyte.bit6=ip1.ibyte.bit3; /* bit 29 */ + ip1.abyte=in[0]; ipr.ibyte.bit5=ip1.ibyte.bit4; /* bit 28 */ + ip1.abyte=in[0]; ipr.ibyte.bit4=ip1.ibyte.bit3; /* bit 29 */ + ip1.abyte=in[0]; ipr.ibyte.bit3=ip1.ibyte.bit2; /* bit 30 */ + ip1.abyte=in[0]; ipr.ibyte.bit2=ip1.ibyte.bit1; /* bit 31 */ + ip1.abyte=in[0]; ipr.ibyte.bit1=ip1.ibyte.bit0; /* bit 32 */ + ip1.abyte=in[3]; ipr.ibyte.bit0=ip1.ibyte.bit7; /* bit 1 */ + out[0]=ipr.abyte; + + return; +} + +/*----------------------------------------------------------- +DES Compress procedure +Description: +-----------------------------------------------------------*/ +static void compress(char in[6],char out[4]) +{ + /* S Box */ + char s[8][4][16]={ + /* S1 */ + 14, 4,13, 1, 2,15,11, 8, 3,10, 6,12, 5, 9, 0, 7, + 0,15, 7, 4,14, 2,13, 1,10, 6,12,11, 9, 5, 3, 8, + 4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3,10, 5, 0, + 15,12, 8, 2, 4, 9, 1, 7, 5,11, 3,14,10, 0, 6,13, + /* S2 */ + 15, 1, 8,14, 6,11, 3, 4, 9, 7, 2,13,12, 0, 5,10, + 3,13, 4, 7,15, 2, 8,14,12, 0, 1,10, 6, 9,11, 5, + 0,14, 7,11,10, 4,13, 1, 5, 8,12, 6, 9, 3, 2,15, + 13,8,10, 1, 3,15, 4, 2,11, 6, 7,12, 0, 5,14, 9, + /* S3 */ + 10, 0, 9,14, 6, 3,15, 5, 1,13,12, 7,11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6,10, 2, 8, 5,14,12,11,15, 1, + 13, 6, 4, 9, 8,15, 3, 0,11, 1, 2,12, 5,10,14, 7, + 1,10,13, 0, 6, 9, 8, 7, 4,15,14, 3,11, 5, 2,12, + /* S4 */ + 7,13,14, 3, 0, 6, 9,10, 1, 2, 8, 5,11,12, 4,15, + 13, 8,11, 5, 6,15, 0, 3, 4, 7, 2,12, 1,10,14, 9, + 10, 6, 9, 0,12,11, 7,13,15, 1, 3,14, 5, 2, 8, 4, + 3,15, 0, 6,10, 1,13, 8, 9, 4, 5,11,12, 7, 2,14, + /* S5 */ + 2,12, 4, 1, 7,10,11, 6, 8, 5, 3,15,13, 0,14, 9, + 14,11, 2,12, 4, 7,13, 1, 5, 0,15,10, 3, 9, 8, 6, + 4, 2, 1,11,10,13, 7, 8,15, 9,12, 5, 6, 3, 0,14, + 11, 8,12, 7, 1,14, 2,13, 6,15, 0, 9,10, 4, 5, 3, + /* S6 */ + 12, 1,10,15, 9, 2, 6, 8, 0,13, 3, 4,14, 7, 5,11, + 10,15, 4, 2, 7,12, 9, 5, 6, 1,13,14, 0,11, 3, 8, + 9,14,15, 5, 2, 8,12, 3, 7, 0, 4,10, 1,13,11, 6, + 4, 3, 2,12, 9, 5,15,10,11,14, 1, 7, 6, 0, 8,13, + /* S7 */ + 4,11, 2,14,15, 0, 8,13, 3,12, 9, 7, 5,10, 6, 1, + 13, 0,11, 7, 4, 9, 1,10,14, 3, 5,12, 2,15, 8, 6, + 1, 4,11,13,12, 3, 7,14,10,15, 6, 8, 0, 5, 9, 2, + 6,11,13, 8, 1, 4,10, 7, 9, 5, 0,15,14, 2, 3,12, + /* S8 */ + 13, 2, 8, 4, 6,15,11, 1,10, 9, 3,14, 5, 0,12, 7, + 1,15,13, 8,10, 3, 7, 4,12, 5, 6,11, 0,14, 9, 2, + 7,11, 4, 1, 9,12,14, 2, 0, 6,10,13,15, 3, 5, 8, + 2, 1,14, 7, 4,10, 8,13,15,12, 9, 0, 3, 5, 6,11 + }; + + union hbyte ip1; + union hbyte ipr; + char tmp[8]; + char c[8]; + int i; + char hang,lie; + ip1.abyte=0; + ipr.abyte=0; + + /* Trans 6 bytes to 8 bytes of 6 bits */ + ip1.abyte=in[5]; ipr.ibyte.bit7=ip1.ibyte.bit7; /* bit 1 */ + ip1.abyte=in[5]; ipr.ibyte.bit6=ip1.ibyte.bit6; /* bit 2 */ + ip1.abyte=in[5]; ipr.ibyte.bit5=ip1.ibyte.bit5; /* bit 3 */ + ip1.abyte=in[5]; ipr.ibyte.bit4=ip1.ibyte.bit4; /* bit 4 */ + ip1.abyte=in[5]; ipr.ibyte.bit3=ip1.ibyte.bit3; /* bit 5 */ + ip1.abyte=in[5]; ipr.ibyte.bit2=ip1.ibyte.bit2; /* bit 6 */ + ipr.ibyte.bit1=0; /* bit */ + ipr.ibyte.bit0=0; /* bit */ + tmp[7]=ipr.abyte; + + ip1.abyte=in[5]; ipr.ibyte.bit7=ip1.ibyte.bit1; /* bit 7 */ + ip1.abyte=in[5]; ipr.ibyte.bit6=ip1.ibyte.bit0; /* bit 8 */ + ip1.abyte=in[4]; ipr.ibyte.bit5=ip1.ibyte.bit7; /* bit 9 */ + ip1.abyte=in[4]; ipr.ibyte.bit4=ip1.ibyte.bit6; /* bit 10 */ + ip1.abyte=in[4]; ipr.ibyte.bit3=ip1.ibyte.bit5; /* bit 11 */ + ip1.abyte=in[4]; ipr.ibyte.bit2=ip1.ibyte.bit4; /* bit 12 */ + ipr.ibyte.bit1=0; /* bit */ + ipr.ibyte.bit0=0; /* bit */ + tmp[6]=ipr.abyte; + + ip1.abyte=in[4]; ipr.ibyte.bit7=ip1.ibyte.bit3; /* bit 13 */ + ip1.abyte=in[4]; ipr.ibyte.bit6=ip1.ibyte.bit2; /* bit 14 */ + ip1.abyte=in[4]; ipr.ibyte.bit5=ip1.ibyte.bit1; /* bit 15 */ + ip1.abyte=in[4]; ipr.ibyte.bit4=ip1.ibyte.bit0; /* bit 16 */ + ip1.abyte=in[3]; ipr.ibyte.bit3=ip1.ibyte.bit7; /* bit 17 */ + ip1.abyte=in[3]; ipr.ibyte.bit2=ip1.ibyte.bit6; /* bit 18 */ + ipr.ibyte.bit1=0; /* bit */ + ipr.ibyte.bit0=0; /* bit */ + tmp[5]=ipr.abyte; + + ip1.abyte=in[3]; ipr.ibyte.bit7=ip1.ibyte.bit5; /* bit 19 */ + ip1.abyte=in[3]; ipr.ibyte.bit6=ip1.ibyte.bit4; /* bit 20 */ + ip1.abyte=in[3]; ipr.ibyte.bit5=ip1.ibyte.bit3; /* bit 21 */ + ip1.abyte=in[3]; ipr.ibyte.bit4=ip1.ibyte.bit2; /* bit 22 */ + ip1.abyte=in[3]; ipr.ibyte.bit3=ip1.ibyte.bit1; /* bit 23 */ + ip1.abyte=in[3]; ipr.ibyte.bit2=ip1.ibyte.bit0; /* bit 24 */ + ipr.ibyte.bit1=0; /* bit */ + ipr.ibyte.bit0=0; /* bit */ + tmp[4]=ipr.abyte; + + ip1.abyte=in[2]; ipr.ibyte.bit7=ip1.ibyte.bit7; /* bit 25 */ + ip1.abyte=in[2]; ipr.ibyte.bit6=ip1.ibyte.bit6; /* bit 26 */ + ip1.abyte=in[2]; ipr.ibyte.bit5=ip1.ibyte.bit5; /* bit 27 */ + ip1.abyte=in[2]; ipr.ibyte.bit4=ip1.ibyte.bit4; /* bit 28 */ + ip1.abyte=in[2]; ipr.ibyte.bit3=ip1.ibyte.bit3; /* bit 29 */ + ip1.abyte=in[2]; ipr.ibyte.bit2=ip1.ibyte.bit2; /* bit 30 */ + ipr.ibyte.bit1=0; /* bit */ + ipr.ibyte.bit0=0; /* bit */ + tmp[3]=ipr.abyte; + + ip1.abyte=in[2]; ipr.ibyte.bit7=ip1.ibyte.bit1; /* bit 31 */ + ip1.abyte=in[2]; ipr.ibyte.bit6=ip1.ibyte.bit0; /* bit 32 */ + ip1.abyte=in[1]; ipr.ibyte.bit5=ip1.ibyte.bit7; /* bit 33 */ + ip1.abyte=in[1]; ipr.ibyte.bit4=ip1.ibyte.bit6; /* bit 34 */ + ip1.abyte=in[1]; ipr.ibyte.bit3=ip1.ibyte.bit5; /* bit 35 */ + ip1.abyte=in[1]; ipr.ibyte.bit2=ip1.ibyte.bit4; /* bit 36 */ + ipr.ibyte.bit1=0; /* bit */ + ipr.ibyte.bit0=0; /* bit */ + tmp[2]=ipr.abyte; + + ip1.abyte=in[1]; ipr.ibyte.bit7=ip1.ibyte.bit3; /* bit 37 */ + ip1.abyte=in[1]; ipr.ibyte.bit6=ip1.ibyte.bit2; /* bit 38 */ + ip1.abyte=in[1]; ipr.ibyte.bit5=ip1.ibyte.bit1; /* bit 39 */ + ip1.abyte=in[1]; ipr.ibyte.bit4=ip1.ibyte.bit0; /* bit 40 */ + ip1.abyte=in[0]; ipr.ibyte.bit3=ip1.ibyte.bit7; /* bit 41 */ + ip1.abyte=in[0]; ipr.ibyte.bit2=ip1.ibyte.bit6; /* bit 42 */ + ipr.ibyte.bit1=0; /* bit */ + ipr.ibyte.bit0=0; /* bit */ + tmp[1]=ipr.abyte; + + ip1.abyte=in[0]; ipr.ibyte.bit7=ip1.ibyte.bit5; /* bit 43 */ + ip1.abyte=in[0]; ipr.ibyte.bit6=ip1.ibyte.bit4; /* bit 44 */ + ip1.abyte=in[0]; ipr.ibyte.bit5=ip1.ibyte.bit3; /* bit 45 */ + ip1.abyte=in[0]; ipr.ibyte.bit4=ip1.ibyte.bit2; /* bit 46 */ + ip1.abyte=in[0]; ipr.ibyte.bit3=ip1.ibyte.bit1; /* bit 47 */ + ip1.abyte=in[0]; ipr.ibyte.bit2=ip1.ibyte.bit0; /* bit 48 */ + ipr.ibyte.bit1=0; /* bit */ + ipr.ibyte.bit0=0; /* bit */ + tmp[0]=ipr.abyte; + + /* Compress 6 bits to 4 bits */ + i=7; + while (i>=0) { + ip1.abyte=tmp[i]; + ipr.ibyte.bit1=ip1.ibyte.bit7; /* Hang Number */ + ipr.ibyte.bit0=ip1.ibyte.bit2; + hang=ipr.abyte & 0x03; + + ipr.ibyte.bit3=ip1.ibyte.bit6; /* Lie Number */ + ipr.ibyte.bit2=ip1.ibyte.bit5; + ipr.ibyte.bit1=ip1.ibyte.bit4; + ipr.ibyte.bit0=ip1.ibyte.bit3; + lie=ipr.abyte & 0x0F; + + c[i]=s[7-i][hang][lie]; + i=i-1; + } + + out[3]=(c[7]<<4)|c[6]; + out[2]=(c[5]<<4)|c[4]; + out[1]=(c[3]<<4)|c[2]; + out[0]=(c[1]<<4)|c[0]; + + return; +} + +/*----------------------------------------------------------- +DES Permutation procedure +Description: +-----------------------------------------------------------*/ +void permutate(char in[4],char out[4]) +{ + union hbyte ip1; + union hbyte ipr; + ip1.abyte=0; + ipr.abyte=0; + + /* Trans Array Out[4] */ + ip1.abyte=in[2]; ipr.ibyte.bit7=ip1.ibyte.bit0; /* bit 16 */ + ip1.abyte=in[3]; ipr.ibyte.bit6=ip1.ibyte.bit1; /* bit 7 */ + ip1.abyte=in[1]; ipr.ibyte.bit5=ip1.ibyte.bit4; /* bit 20 */ + ip1.abyte=in[1]; ipr.ibyte.bit4=ip1.ibyte.bit3; /* bit 21 */ + ip1.abyte=in[0]; ipr.ibyte.bit3=ip1.ibyte.bit3; /* bit 29 */ + ip1.abyte=in[2]; ipr.ibyte.bit2=ip1.ibyte.bit4; /* bit 12 */ + ip1.abyte=in[0]; ipr.ibyte.bit1=ip1.ibyte.bit4; /* bit 28 */ + ip1.abyte=in[1]; ipr.ibyte.bit0=ip1.ibyte.bit7; /* bit 17 */ + out[3]=ipr.abyte; + + ip1.abyte=in[3]; ipr.ibyte.bit7=ip1.ibyte.bit7; /* bit 1 */ + ip1.abyte=in[2]; ipr.ibyte.bit6=ip1.ibyte.bit1; /* bit 15 */ + ip1.abyte=in[1]; ipr.ibyte.bit5=ip1.ibyte.bit1; /* bit 23 */ + ip1.abyte=in[0]; ipr.ibyte.bit4=ip1.ibyte.bit6; /* bit 26 */ + ip1.abyte=in[3]; ipr.ibyte.bit3=ip1.ibyte.bit3; /* bit 5 */ + ip1.abyte=in[1]; ipr.ibyte.bit2=ip1.ibyte.bit6; /* bit 18 */ + ip1.abyte=in[0]; ipr.ibyte.bit1=ip1.ibyte.bit1; /* bit 31 */ + ip1.abyte=in[2]; ipr.ibyte.bit0=ip1.ibyte.bit6; /* bit 10 */ + out[2]=ipr.abyte; + + ip1.abyte=in[3]; ipr.ibyte.bit7=ip1.ibyte.bit6; /* bit 2 */ + ip1.abyte=in[3]; ipr.ibyte.bit6=ip1.ibyte.bit0; /* bit 8 */ + ip1.abyte=in[1]; ipr.ibyte.bit5=ip1.ibyte.bit0; /* bit 24 */ + ip1.abyte=in[2]; ipr.ibyte.bit4=ip1.ibyte.bit2; /* bit 14 */ + ip1.abyte=in[0]; ipr.ibyte.bit3=ip1.ibyte.bit0; /* bit 32 */ + ip1.abyte=in[0]; ipr.ibyte.bit2=ip1.ibyte.bit5; /* bit 27 */ + ip1.abyte=in[3]; ipr.ibyte.bit1=ip1.ibyte.bit5; /* bit 3 */ + ip1.abyte=in[2]; ipr.ibyte.bit0=ip1.ibyte.bit7; /* bit 9 */ + out[1]=ipr.abyte; + + ip1.abyte=in[1]; ipr.ibyte.bit7=ip1.ibyte.bit5; /* bit 19 */ + ip1.abyte=in[2]; ipr.ibyte.bit6=ip1.ibyte.bit3; /* bit 13 */ + ip1.abyte=in[0]; ipr.ibyte.bit5=ip1.ibyte.bit2; /* bit 30 */ + ip1.abyte=in[3]; ipr.ibyte.bit4=ip1.ibyte.bit2; /* bit 6 */ + ip1.abyte=in[1]; ipr.ibyte.bit3=ip1.ibyte.bit2; /* bit 22 */ + ip1.abyte=in[2]; ipr.ibyte.bit2=ip1.ibyte.bit5; /* bit 11 */ + ip1.abyte=in[3]; ipr.ibyte.bit1=ip1.ibyte.bit4; /* bit 4 */ + ip1.abyte=in[0]; ipr.ibyte.bit0=ip1.ibyte.bit7; /* bit 25 */ + out[0]=ipr.abyte; + + return; +} + +/*----------------------------------------------------------- +PC-2 +Description: Sub Procedure of Subkey +-----------------------------------------------------------*/ +void pc2(char keyc[4],char keyd[4],char subkey[6]) +{ + union hbyte ip1; + union hbyte ipr; + ip1.abyte=0; + ipr.abyte=0; + + /* Trans Ci */ + ip1.abyte=keyc[2]; ipr.ibyte.bit7=ip1.ibyte.bit2; /* bit 14 */ + ip1.abyte=keyc[1]; ipr.ibyte.bit6=ip1.ibyte.bit7; /* bit 17 */ + ip1.abyte=keyc[2]; ipr.ibyte.bit5=ip1.ibyte.bit5; /* bit 11 */ + ip1.abyte=keyc[1]; ipr.ibyte.bit4=ip1.ibyte.bit0; /* bit 24 */ + ip1.abyte=keyc[3]; ipr.ibyte.bit3=ip1.ibyte.bit7; /* bit 1 */ + ip1.abyte=keyc[3]; ipr.ibyte.bit2=ip1.ibyte.bit3; /* bit 5 */ + ip1.abyte=keyc[3]; ipr.ibyte.bit1=ip1.ibyte.bit5; /* bit 3 */ + ip1.abyte=keyc[0]; ipr.ibyte.bit0=ip1.ibyte.bit4; /* bit 28 */ + subkey[5]=ipr.abyte; + + ip1.abyte=keyc[2]; ipr.ibyte.bit7=ip1.ibyte.bit1; /* bit 15 */ + ip1.abyte=keyc[3]; ipr.ibyte.bit6=ip1.ibyte.bit2; /* bit 6 */ + ip1.abyte=keyc[1]; ipr.ibyte.bit5=ip1.ibyte.bit3; /* bit 21 */ + ip1.abyte=keyc[2]; ipr.ibyte.bit4=ip1.ibyte.bit6; /* bit 10 */ + ip1.abyte=keyc[1]; ipr.ibyte.bit3=ip1.ibyte.bit1; /* bit 23 */ + ip1.abyte=keyc[1]; ipr.ibyte.bit2=ip1.ibyte.bit5; /* bit 19 */ + ip1.abyte=keyc[2]; ipr.ibyte.bit1=ip1.ibyte.bit4; /* bit 12 */ + ip1.abyte=keyc[3]; ipr.ibyte.bit0=ip1.ibyte.bit4; /* bit 4 */ + subkey[4]=ipr.abyte; + + ip1.abyte=keyc[0]; ipr.ibyte.bit7=ip1.ibyte.bit6; /* bit 26 */ + ip1.abyte=keyc[3]; ipr.ibyte.bit6=ip1.ibyte.bit0; /* bit 8 */ + ip1.abyte=keyc[2]; ipr.ibyte.bit5=ip1.ibyte.bit0; /* bit 16 */ + ip1.abyte=keyc[3]; ipr.ibyte.bit4=ip1.ibyte.bit1; /* bit 7 */ + ip1.abyte=keyc[0]; ipr.ibyte.bit3=ip1.ibyte.bit5; /* bit 27 */ + ip1.abyte=keyc[1]; ipr.ibyte.bit2=ip1.ibyte.bit4; /* bit 20 */ + ip1.abyte=keyc[2]; ipr.ibyte.bit1=ip1.ibyte.bit3; /* bit 13 */ + ip1.abyte=keyc[3]; ipr.ibyte.bit0=ip1.ibyte.bit6; /* bit 2 */ + subkey[3]=ipr.abyte; + + /* Trans Di */ + ip1.abyte=keyd[2]; ipr.ibyte.bit7=ip1.ibyte.bit3; /* bit 41 */ + ip1.abyte=keyd[1]; ipr.ibyte.bit6=ip1.ibyte.bit0; /* bit 52 */ + ip1.abyte=keyd[3]; ipr.ibyte.bit5=ip1.ibyte.bit5; /* bit 31 */ + ip1.abyte=keyd[2]; ipr.ibyte.bit4=ip1.ibyte.bit7; /* bit 37 */ + ip1.abyte=keyd[1]; ipr.ibyte.bit3=ip1.ibyte.bit5; /* bit 47 */ + ip1.abyte=keyd[0]; ipr.ibyte.bit2=ip1.ibyte.bit5; /* bit 55 */ + ip1.abyte=keyd[3]; ipr.ibyte.bit1=ip1.ibyte.bit6; /* bit 30 */ + ip1.abyte=keyd[2]; ipr.ibyte.bit0=ip1.ibyte.bit4; /* bit 40 */ + subkey[2]=ipr.abyte; + + ip1.abyte=keyd[1]; ipr.ibyte.bit7=ip1.ibyte.bit1; /* bit 51 */ + ip1.abyte=keyd[1]; ipr.ibyte.bit6=ip1.ibyte.bit7; /* bit 45 */ + ip1.abyte=keyd[3]; ipr.ibyte.bit5=ip1.ibyte.bit3; /* bit 33 */ + ip1.abyte=keyd[1]; ipr.ibyte.bit4=ip1.ibyte.bit4; /* bit 48 */ + ip1.abyte=keyd[2]; ipr.ibyte.bit3=ip1.ibyte.bit0; /* bit 44 */ + ip1.abyte=keyd[1]; ipr.ibyte.bit2=ip1.ibyte.bit3; /* bit 49 */ + ip1.abyte=keyd[2]; ipr.ibyte.bit1=ip1.ibyte.bit5; /* bit 39 */ + ip1.abyte=keyd[0]; ipr.ibyte.bit0=ip1.ibyte.bit4; /* bit 56 */ + subkey[1]=ipr.abyte; + + ip1.abyte=keyd[3]; ipr.ibyte.bit7=ip1.ibyte.bit2; /* bit 34 */ + ip1.abyte=keyd[0]; ipr.ibyte.bit6=ip1.ibyte.bit7; /* bit 53 */ + ip1.abyte=keyd[1]; ipr.ibyte.bit5=ip1.ibyte.bit6; /* bit 46 */ + ip1.abyte=keyd[2]; ipr.ibyte.bit4=ip1.ibyte.bit2; /* bit 42 */ + ip1.abyte=keyd[1]; ipr.ibyte.bit3=ip1.ibyte.bit2; /* bit 50 */ + ip1.abyte=keyd[3]; ipr.ibyte.bit2=ip1.ibyte.bit0; /* bit 36 */ + ip1.abyte=keyd[3]; ipr.ibyte.bit1=ip1.ibyte.bit7; /* bit 29 */ + ip1.abyte=keyd[3]; ipr.ibyte.bit0=ip1.ibyte.bit4; /* bit 32 */ + subkey[0]=ipr.abyte; + + return; +} + +/*----------------------------------------------------------- +Rotate bits +Description: Sub Procedure of Subkey +-----------------------------------------------------------*/ +void rotatebits(char key[4],char skey[4],char bits) +{ + union hbyte c[4],d[4]; + + c[0].abyte=key[0]; + c[1].abyte=key[1]; + c[2].abyte=key[2]; + c[3].abyte=key[3]; + + /* total 28 bits */ + if (bits==1){ + /* Key[0] */ + d[0].ibyte.bit4=c[3].ibyte.bit7; /* bit 1 */ + + d[0].ibyte.bit5=c[0].ibyte.bit4; /* bit 2 */ + d[0].ibyte.bit6=c[0].ibyte.bit5; /* bit 3 */ + d[0].ibyte.bit7=c[0].ibyte.bit6; /* bit 4 */ + + /* key[1] */ + d[1].ibyte.bit0=c[0].ibyte.bit7; /* bit 5 */ + d[1].ibyte.bit1=c[1].ibyte.bit0; /* bit 6 */ + d[1].ibyte.bit2=c[1].ibyte.bit1; /* bit 7 */ + d[1].ibyte.bit3=c[1].ibyte.bit2; /* bit 8 */ + d[1].ibyte.bit4=c[1].ibyte.bit3; /* bit 9 */ + d[1].ibyte.bit5=c[1].ibyte.bit4; /* bit 10 */ + d[1].ibyte.bit6=c[1].ibyte.bit5; /* bit 11 */ + d[1].ibyte.bit7=c[1].ibyte.bit6; /* bit 12 */ + + /* key[2] */ + d[2].ibyte.bit0=c[1].ibyte.bit7; /* bit 13 */ + d[2].ibyte.bit1=c[2].ibyte.bit0; /* bit 14 */ + d[2].ibyte.bit2=c[2].ibyte.bit1; /* bit 15 */ + d[2].ibyte.bit3=c[2].ibyte.bit2; /* bit 16 */ + d[2].ibyte.bit4=c[2].ibyte.bit3; /* bit 17 */ + d[2].ibyte.bit5=c[2].ibyte.bit4; /* bit 18 */ + d[2].ibyte.bit6=c[2].ibyte.bit5; /* bit 19 */ + d[2].ibyte.bit7=c[2].ibyte.bit6; /* bit 20 */ + + /* key[3] */ + d[3].ibyte.bit0=c[2].ibyte.bit7; /* bit 21 */ + d[3].ibyte.bit1=c[3].ibyte.bit0; /* bit 22 */ + d[3].ibyte.bit2=c[3].ibyte.bit1; /* bit 23 */ + d[3].ibyte.bit3=c[3].ibyte.bit2; /* bit 24 */ + d[3].ibyte.bit4=c[3].ibyte.bit3; /* bit 25 */ + d[3].ibyte.bit5=c[3].ibyte.bit4; /* bit 26 */ + d[3].ibyte.bit6=c[3].ibyte.bit5; /* bit 27 */ + d[3].ibyte.bit7=c[3].ibyte.bit6; /* bit 28 */ + } + else { /* Left rotate 2 bits */ + /* Key[0] */ + d[0].ibyte.bit4=c[3].ibyte.bit6; /* bit 1 */ + d[0].ibyte.bit5=c[3].ibyte.bit7; /* bit 2 */ + + d[0].ibyte.bit6=c[0].ibyte.bit4; /* bit 3 */ + d[0].ibyte.bit7=c[0].ibyte.bit5; /* bit 4 */ + + /* key[1] */ + d[1].ibyte.bit0=c[0].ibyte.bit6; /* bit 5 */ + d[1].ibyte.bit1=c[0].ibyte.bit7; /* bit 6 */ + d[1].ibyte.bit2=c[1].ibyte.bit0; /* bit 7 */ + d[1].ibyte.bit3=c[1].ibyte.bit1; /* bit 8 */ + d[1].ibyte.bit4=c[1].ibyte.bit2; /* bit 9 */ + d[1].ibyte.bit5=c[1].ibyte.bit3; /* bit 10 */ + d[1].ibyte.bit6=c[1].ibyte.bit4; /* bit 11 */ + d[1].ibyte.bit7=c[1].ibyte.bit5; /* bit 12 */ + + /* key[2] */ + d[2].ibyte.bit0=c[1].ibyte.bit6; /* bit 13 */ + d[2].ibyte.bit1=c[1].ibyte.bit7; /* bit 14 */ + d[2].ibyte.bit2=c[2].ibyte.bit0; /* bit 15 */ + d[2].ibyte.bit3=c[2].ibyte.bit1; /* bit 16 */ + d[2].ibyte.bit4=c[2].ibyte.bit2; /* bit 17 */ + d[2].ibyte.bit5=c[2].ibyte.bit3; /* bit 18 */ + d[2].ibyte.bit6=c[2].ibyte.bit4; /* bit 19 */ + d[2].ibyte.bit7=c[2].ibyte.bit5; /* bit 20 */ + + /* key[3] */ + d[3].ibyte.bit0=c[2].ibyte.bit6; /* bit 21 */ + d[3].ibyte.bit1=c[2].ibyte.bit7; /* bit 22 */ + d[3].ibyte.bit2=c[3].ibyte.bit0; /* bit 23 */ + d[3].ibyte.bit3=c[3].ibyte.bit1; /* bit 24 */ + d[3].ibyte.bit4=c[3].ibyte.bit2; /* bit 25 */ + d[3].ibyte.bit5=c[3].ibyte.bit3; /* bit 26 */ + d[3].ibyte.bit6=c[3].ibyte.bit4; /* bit 27 */ + d[3].ibyte.bit7=c[3].ibyte.bit5; /* bit 28 */ + } + + skey[0]=d[0].abyte; + skey[1]=d[1].abyte; + skey[2]=d[2].abyte; + skey[3]=d[3].abyte; + return; +} + +/*----------------------------------------------------------- +DES Gernerate Sub Key procedure +Description: +-----------------------------------------------------------*/ +void Gsubkey(char key[8],char subkey[16][6]) +{ + int i; + char cup[4], dup[4]; + char ci[4], di[4]; + char lsi[16]; + union hbyte ip1; + union hbyte ipr; + ip1.abyte=0; + ipr.abyte=0; + + /* Initial LSi */ + lsi[0]=lsi[1]=lsi[8]=lsi[15]=1; + lsi[2]=lsi[3]=lsi[4]=lsi[5]=lsi[6]=lsi[7]=2; + lsi[9]=lsi[10]=lsi[11]=lsi[12]=lsi[13]=lsi[14]=2; + + + /* Getout 1 bit of 1 byte: all 56 bytes */ + /* Through PC-1, Get C0, 28 bits */ + ip1.abyte=key[0]; ipr.ibyte.bit7=ip1.ibyte.bit7; /* 57 bit */ + ip1.abyte=key[1]; ipr.ibyte.bit6=ip1.ibyte.bit7; /* 49 bit */ + ip1.abyte=key[2]; ipr.ibyte.bit5=ip1.ibyte.bit7; /* 41 bit */ + ip1.abyte=key[3]; ipr.ibyte.bit4=ip1.ibyte.bit7; /* 33 bit */ + ip1.abyte=key[4]; ipr.ibyte.bit3=ip1.ibyte.bit7; /* 25 bit */ + ip1.abyte=key[5]; ipr.ibyte.bit2=ip1.ibyte.bit7; /* 17 bit */ + ip1.abyte=key[6]; ipr.ibyte.bit1=ip1.ibyte.bit7; /* 9 bit */ + ip1.abyte=key[7]; ipr.ibyte.bit0=ip1.ibyte.bit7; /* 1 bit */ + ci[3]=ipr.abyte; + + ip1.abyte=key[0]; ipr.ibyte.bit7=ip1.ibyte.bit6; /* 58 bit */ + ip1.abyte=key[1]; ipr.ibyte.bit6=ip1.ibyte.bit6; /* 50 bit */ + ip1.abyte=key[2]; ipr.ibyte.bit5=ip1.ibyte.bit6; /* 42 bit */ + ip1.abyte=key[3]; ipr.ibyte.bit4=ip1.ibyte.bit6; /* 34 bit */ + ip1.abyte=key[4]; ipr.ibyte.bit3=ip1.ibyte.bit6; /* 26 bit */ + ip1.abyte=key[5]; ipr.ibyte.bit2=ip1.ibyte.bit6; /* 18 bit */ + ip1.abyte=key[6]; ipr.ibyte.bit1=ip1.ibyte.bit6; /* 10 bit */ + ip1.abyte=key[7]; ipr.ibyte.bit0=ip1.ibyte.bit6; /* 2 bit */ + ci[2]=ipr.abyte; + + ip1.abyte=key[0]; ipr.ibyte.bit7=ip1.ibyte.bit5; /* 59 bit */ + ip1.abyte=key[1]; ipr.ibyte.bit6=ip1.ibyte.bit5; /* 51 bit */ + ip1.abyte=key[2]; ipr.ibyte.bit5=ip1.ibyte.bit5; /* 43 bit */ + ip1.abyte=key[3]; ipr.ibyte.bit4=ip1.ibyte.bit5; /* 35 bit */ + ip1.abyte=key[4]; ipr.ibyte.bit3=ip1.ibyte.bit5; /* 27 bit */ + ip1.abyte=key[5]; ipr.ibyte.bit2=ip1.ibyte.bit5; /* 19 bit */ + ip1.abyte=key[6]; ipr.ibyte.bit1=ip1.ibyte.bit5; /* 11 bit */ + ip1.abyte=key[7]; ipr.ibyte.bit0=ip1.ibyte.bit5; /* 3 bit */ + ci[1]=ipr.abyte; + + ip1.abyte=key[0]; ipr.ibyte.bit7=ip1.ibyte.bit4; /* 60 bit */ + ip1.abyte=key[1]; ipr.ibyte.bit6=ip1.ibyte.bit4; /* 52 bit */ + ip1.abyte=key[2]; ipr.ibyte.bit5=ip1.ibyte.bit4; /* 44 bit */ + ip1.abyte=key[3]; ipr.ibyte.bit4=ip1.ibyte.bit4; /* 36 bit */ + ci[0]=ipr.abyte; + + /* Through PC-1, Get D0, 28 bits */ + ip1.abyte=key[0]; ipr.ibyte.bit7=ip1.ibyte.bit1; /* 63 bit */ + ip1.abyte=key[1]; ipr.ibyte.bit6=ip1.ibyte.bit1; /* 55 bit */ + ip1.abyte=key[2]; ipr.ibyte.bit5=ip1.ibyte.bit1; /* 47 bit */ + ip1.abyte=key[3]; ipr.ibyte.bit4=ip1.ibyte.bit1; /* 39 bit */ + ip1.abyte=key[4]; ipr.ibyte.bit3=ip1.ibyte.bit1; /* 31 bit */ + ip1.abyte=key[5]; ipr.ibyte.bit2=ip1.ibyte.bit1; /* 23 bit */ + ip1.abyte=key[6]; ipr.ibyte.bit1=ip1.ibyte.bit1; /* 15 bit */ + ip1.abyte=key[7]; ipr.ibyte.bit0=ip1.ibyte.bit1; /* 7 bit */ + di[3]=ipr.abyte; + + ip1.abyte=key[0]; ipr.ibyte.bit7=ip1.ibyte.bit2; /* 62 bit */ + ip1.abyte=key[1]; ipr.ibyte.bit6=ip1.ibyte.bit2; /* 54 bit */ + ip1.abyte=key[2]; ipr.ibyte.bit5=ip1.ibyte.bit2; /* 46 bit */ + ip1.abyte=key[3]; ipr.ibyte.bit4=ip1.ibyte.bit2; /* 38 bit */ + ip1.abyte=key[4]; ipr.ibyte.bit3=ip1.ibyte.bit2; /* 30 bit */ + ip1.abyte=key[5]; ipr.ibyte.bit2=ip1.ibyte.bit2; /* 22 bit */ + ip1.abyte=key[6]; ipr.ibyte.bit1=ip1.ibyte.bit2; /* 14 bit */ + ip1.abyte=key[7]; ipr.ibyte.bit0=ip1.ibyte.bit2; /* 6 bit */ + di[2]=ipr.abyte; + + ip1.abyte=key[0]; ipr.ibyte.bit7=ip1.ibyte.bit3; /* 61 bit */ + ip1.abyte=key[1]; ipr.ibyte.bit6=ip1.ibyte.bit3; /* 53 bit */ + ip1.abyte=key[2]; ipr.ibyte.bit5=ip1.ibyte.bit3; /* 45 bit */ + ip1.abyte=key[3]; ipr.ibyte.bit4=ip1.ibyte.bit3; /* 37 bit */ + ip1.abyte=key[4]; ipr.ibyte.bit3=ip1.ibyte.bit3; /* 29 bit */ + ip1.abyte=key[5]; ipr.ibyte.bit2=ip1.ibyte.bit3; /* 21 bit */ + ip1.abyte=key[6]; ipr.ibyte.bit1=ip1.ibyte.bit3; /* 13 bit */ + ip1.abyte=key[7]; ipr.ibyte.bit0=ip1.ibyte.bit3; /* 5 bit */ + di[1]=ipr.abyte; + + ip1.abyte=key[4]; ipr.ibyte.bit7=ip1.ibyte.bit4; /* 28 bit */ + ip1.abyte=key[5]; ipr.ibyte.bit6=ip1.ibyte.bit4; /* 20 bit */ + ip1.abyte=key[6]; ipr.ibyte.bit5=ip1.ibyte.bit4; /* 12 bit */ + ip1.abyte=key[7]; ipr.ibyte.bit4=ip1.ibyte.bit4; /* 4 bit */ + di[0]=ipr.abyte; + + + for(i=0;i<16;i=i+1) { + cup[3]=ci[3]; cup[2]=ci[2]; cup[1]=ci[1]; cup[0]=ci[0]; + dup[3]=di[3]; dup[2]=di[2]; dup[1]=di[1]; dup[0]=di[0]; + /* Generate 16 Subkey */ + rotatebits(cup,ci,lsi[i]); + rotatebits(dup,di,lsi[i]); + pc2(ci,di,subkey[i]); + } + + return; +} + +/*----------------------------------------------------------- +DES Main procedure +Description: +-----------------------------------------------------------*/ +void des(char m[8],char key[8]) +{ + char ip[8]; + char lin[4]; + char rin[4]; + char lup[4]; + char rup[4]; + char tmp[6]; + char tmp4[4]; + char subkey[16][6]; + char i,j; + union hbyte ip1; + union hbyte ipr; + ip1.abyte=0; + ipr.abyte=0; + + /* Subkey Generate */ + Gsubkey(key,subkey); + + /* IP trans */ + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit6; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit6; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit6; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit6; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit6; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit6; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit6; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit6; + ip[7]=ipr.abyte; /* byte7: 8 bits */ + + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit4; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit4; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit4; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit4; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit4; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit4; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit4; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit4; + ip[6]=ipr.abyte; /* byte6: 8 bits */ + + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit2; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit2; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit2; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit2; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit2; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit2; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit2; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit2; + ip[5]=ipr.abyte; /* byte5: 8 bits */ + + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit0; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit0; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit0; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit0; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit0; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit0; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit0; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit0; + ip[4]=ipr.abyte; /* byte4: 8 bits */ + + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit7; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit7; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit7; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit7; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit7; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit7; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit7; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit7; + ip[3]=ipr.abyte; /* byte3: 8 bits */ + + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit5; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit5; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit5; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit5; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit5; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit5; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit5; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit5; + ip[2]=ipr.abyte; /* byte2: 8 bits */ + + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit3; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit3; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit3; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit3; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit3; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit3; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit3; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit3; + ip[1]=ipr.abyte; /* byte1: 8 bits */ + + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit1; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit1; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit1; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit1; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit1; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit1; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit1; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit1; + ip[0]=ipr.abyte; /* byte0: 8 bits */ + + /* Generate L0, R0 */ + lin[3]=ip[7];lin[2]=ip[6];lin[1]=ip[5];lin[0]=ip[4]; /* L0 */ + rin[3]=ip[3];rin[2]=ip[2];rin[1]=ip[1];rin[0]=ip[0]; /* R0 */ + + /* Generate Ri, Li (16 Times) */ + for(j=0;j<16;j=j+1){ + + for(i=0;i<4;i=i+1){ lup[i]=lin[i]; } + for(i=0;i<4;i=i+1){ rup[i]=rin[i]; } + /* Expand Operation */ + expand(rup,tmp); + /* 48 bits MOD 2 */ + for(i=0;i<6;i=i+1){ tmp[i]=tmp[i]^subkey[j][i]; } + /* Compress Operation */ + compress(tmp,rin); + /* Permutation */ + permutate(rin,tmp4); + /* 32 bits MOD 2 */ + for(i=0;i<4;i=i+1){ rin[i]=lup[i]^tmp4[i]; } /* Ri */ + for(i=0;i<4;i=i+1){ lin[i]=rup[i]; } /* Li */ + + } + /* Generate R16, L16 */ + for(i=0;i<4;i=i+1){ tmp4[i]= rin[i]; } + for(i=0;i<4;i=i+1){ rin[i] = lin[i]; } + for(i=0;i<4;i=i+1){ lin[i] =tmp4[i]; } + + + /* IP(-1) trans */ + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit0; /* 40 */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit0; /* 8 */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit0; /* 48 */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit0; /* 16 */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit0; /* 56 */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit0; /* 24 */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit0; /* 64 */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit0; /* 32 */ + ip[7]=ipr.abyte; /* byte7: 8 bits */ + + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit1; /* 39 */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit1; /* 7 */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit1; /* 47 */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit1; /* 15 */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit1; /* 55 */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit1; /* 23 */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit1; /* 63 */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit1; /* 31 */ + ip[6]=ipr.abyte; /* byte6: 8 bits */ + + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit2; /* 38 */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit2; /* 6 */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit2; /* 46 */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit2; /* 14 */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit2; /* 54 */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit2; /* 22 */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit2; /* 62 */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit2; /* 30 */ + ip[5]=ipr.abyte; /* byte5: 8 bits */ + + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit3; /* 37 */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit3; /* */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit3; /* */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit3; /* */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit3; /* */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit3; /* */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit3; /* */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit3; /* 29 */ + ip[4]=ipr.abyte; /* byte4: 8 bits */ + + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit4; /* 36 */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit4; /* */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit4; /* */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit4; /* */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit4; /* */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit4; /* */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit4; /* */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit4; /* 28 */ + ip[3]=ipr.abyte; /* byte3: 8 bits */ + + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit5; /* */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit5; /* */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit5; /* */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit5; /* */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit5; /* */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit5; /* */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit5; /* */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit5; /* */ + ip[2]=ipr.abyte; /* byte2: 8 bits */ + + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit6; /* */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit6; /* */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit6; /* */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit6; /* */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit6; /* */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit6; /* */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit6; /* */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit6; /* */ + ip[1]=ipr.abyte; /* byte1: 8 bits */ + + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit7; /* */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit7; /* */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit7; /* */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit7; /* */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit7; /* */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit7; /* */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit7; /* */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit7; /* */ + ip[0]=ipr.abyte; /* byte0: 8 bits */ + + m[7]=ip[7]; + m[6]=ip[6]; + m[5]=ip[5]; + m[4]=ip[4]; + m[3]=ip[3]; + m[2]=ip[2]; + m[1]=ip[1]; + m[0]=ip[0]; + return; +} + +/*----------------------------------------------------------- +UN-DES Main procedure +Description: +-----------------------------------------------------------*/ +void undes(char m[8],char key[8]) +{ + char ip[8]; + char lin[4]; + char rin[4]; + char lup[4]; + char rup[4]; + char tmp[6]; + char tmp4[4]; + char subkey[16][6]; + char i,j; + union hbyte ip1; + union hbyte ipr; + ip1.abyte=0; + ipr.abyte=0; + + /* Subkey Generate */ + Gsubkey(key,subkey); + + /* IP trans */ + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit6; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit6; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit6; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit6; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit6; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit6; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit6; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit6; + ip[7]=ipr.abyte; /* byte7: 8 bits */ + + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit4; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit4; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit4; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit4; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit4; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit4; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit4; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit4; + ip[6]=ipr.abyte; /* byte6: 8 bits */ + + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit2; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit2; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit2; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit2; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit2; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit2; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit2; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit2; + ip[5]=ipr.abyte; /* byte5: 8 bits */ + + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit0; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit0; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit0; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit0; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit0; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit0; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit0; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit0; + ip[4]=ipr.abyte; /* byte4: 8 bits */ + + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit7; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit7; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit7; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit7; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit7; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit7; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit7; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit7; + ip[3]=ipr.abyte; /* byte3: 8 bits */ + + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit5; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit5; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit5; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit5; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit5; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit5; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit5; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit5; + ip[2]=ipr.abyte; /* byte2: 8 bits */ + + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit3; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit3; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit3; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit3; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit3; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit3; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit3; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit3; + ip[1]=ipr.abyte; /* byte1: 8 bits */ + + ip1.abyte=m[0]; ipr.ibyte.bit7=ip1.ibyte.bit1; + ip1.abyte=m[1]; ipr.ibyte.bit6=ip1.ibyte.bit1; + ip1.abyte=m[2]; ipr.ibyte.bit5=ip1.ibyte.bit1; + ip1.abyte=m[3]; ipr.ibyte.bit4=ip1.ibyte.bit1; + ip1.abyte=m[4]; ipr.ibyte.bit3=ip1.ibyte.bit1; + ip1.abyte=m[5]; ipr.ibyte.bit2=ip1.ibyte.bit1; + ip1.abyte=m[6]; ipr.ibyte.bit1=ip1.ibyte.bit1; + ip1.abyte=m[7]; ipr.ibyte.bit0=ip1.ibyte.bit1; + ip[0]=ipr.abyte; /* byte0: 8 bits */ + + /* Generate L0, R0 */ + lin[3]=ip[7];lin[2]=ip[6];lin[1]=ip[5];lin[0]=ip[4]; /* L0 */ + rin[3]=ip[3];rin[2]=ip[2];rin[1]=ip[1];rin[0]=ip[0]; /* R0 */ + + /* Generate Ri, Li (16 Times) */ + for(j=0;j<16;j=j+1){ + + for(i=0;i<4;i=i+1){ lup[i]=lin[i]; } + for(i=0;i<4;i=i+1){ rup[i]=rin[i]; } + /* Expand Operation */ + expand(rup,tmp); + /* 48 bits MOD 2 */ + for(i=0;i<6;i=i+1){ tmp[i]=tmp[i]^subkey[15-j][i]; } + /* Compress Operation */ + compress(tmp,rin); + /* Permutation */ + permutate(rin,tmp4); + /* 32 bits MOD 2 */ + for(i=0;i<4;i=i+1){ rin[i]=lup[i]^tmp4[i]; } /* Ri */ + for(i=0;i<4;i=i+1){ lin[i]=rup[i]; } /* Li */ + + } + /* Generate R16, L16 */ + for(i=0;i<4;i=i+1){ tmp4[i]= rin[i]; } + for(i=0;i<4;i=i+1){ rin[i] = lin[i]; } + for(i=0;i<4;i=i+1){ lin[i] =tmp4[i]; } + + /* IP(-1) trans */ + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit0; /* 40 */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit0; /* 8 */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit0; /* 48 */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit0; /* 16 */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit0; /* 56 */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit0; /* 24 */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit0; /* 64 */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit0; /* 32 */ + ip[7]=ipr.abyte; /* byte7: 8 bits */ + + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit1; /* 39 */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit1; /* 7 */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit1; /* 47 */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit1; /* 15 */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit1; /* 55 */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit1; /* 23 */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit1; /* 63 */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit1; /* 31 */ + ip[6]=ipr.abyte; /* byte6: 8 bits */ + + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit2; /* 38 */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit2; /* 6 */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit2; /* 46 */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit2; /* 14 */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit2; /* 54 */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit2; /* 22 */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit2; /* 62 */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit2; /* 30 */ + ip[5]=ipr.abyte; /* byte5: 8 bits */ + + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit3; /* 37 */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit3; /* */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit3; /* */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit3; /* */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit3; /* */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit3; /* */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit3; /* */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit3; /* 29 */ + ip[4]=ipr.abyte; /* byte4: 8 bits */ + + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit4; /* 36 */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit4; /* */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit4; /* */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit4; /* */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit4; /* */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit4; /* */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit4; /* */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit4; /* 28 */ + ip[3]=ipr.abyte; /* byte3: 8 bits */ + + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit5; /* */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit5; /* */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit5; /* */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit5; /* */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit5; /* */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit5; /* */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit5; /* */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit5; /* */ + ip[2]=ipr.abyte; /* byte2: 8 bits */ + + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit6; /* */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit6; /* */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit6; /* */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit6; /* */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit6; /* */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit6; /* */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit6; /* */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit6; /* */ + ip[1]=ipr.abyte; /* byte1: 8 bits */ + + ip1.abyte=rin[3]; ipr.ibyte.bit7=ip1.ibyte.bit7; /* */ + ip1.abyte=lin[3]; ipr.ibyte.bit6=ip1.ibyte.bit7; /* */ + ip1.abyte=rin[2]; ipr.ibyte.bit5=ip1.ibyte.bit7; /* */ + ip1.abyte=lin[2]; ipr.ibyte.bit4=ip1.ibyte.bit7; /* */ + ip1.abyte=rin[1]; ipr.ibyte.bit3=ip1.ibyte.bit7; /* */ + ip1.abyte=lin[1]; ipr.ibyte.bit2=ip1.ibyte.bit7; /* */ + ip1.abyte=rin[0]; ipr.ibyte.bit1=ip1.ibyte.bit7; /* */ + ip1.abyte=lin[0]; ipr.ibyte.bit0=ip1.ibyte.bit7; /* */ + ip[0]=ipr.abyte; /* byte0: 8 bits */ + + m[7]=ip[7]; + m[6]=ip[6]; + m[5]=ip[5]; + m[4]=ip[4]; + m[3]=ip[3]; + m[2]=ip[2]; + m[1]=ip[1]; + m[0]=ip[0]; + return; +} + + + +void SDes(char orientation, char PlainText[8], char Key[8], char Encipher[8]) +{ + char m[8]; + char k[8]; + + m[0]=PlainText[7]; + m[1]=PlainText[6]; + m[2]=PlainText[5]; + m[3]=PlainText[4]; + m[4]=PlainText[3]; + m[5]=PlainText[2]; + m[6]=PlainText[1]; + m[7]=PlainText[0]; + + k[0]=Key[7]; + k[1]=Key[6]; + k[2]=Key[5]; + k[3]=Key[4]; + k[4]=Key[3]; + k[5]=Key[2]; + k[6]=Key[1]; + k[7]=Key[0]; + + if (orientation==0) des(m,k); + else undes(m,k); + + Encipher[0]=m[7]; + Encipher[1]=m[6]; + Encipher[2]=m[5]; + Encipher[3]=m[4]; + Encipher[4]=m[3]; + Encipher[5]=m[2]; + Encipher[6]=m[1]; + Encipher[7]=m[0]; +} + + +void TDes(char orientation,char *PlainText,char *key, char *ucEncipher) +{ + + char En[8]; + if (orientation==0){ + SDes(0,PlainText,key,En); + SDes(1,En,&key[8],En); + SDes(0,En,&key[0],ucEncipher); + } + else { + SDes(1,PlainText,key,En); + SDes(0,En,&key[8],En); + SDes(1,En,&key[0],ucEncipher); + } + return; +} + + +int cipher2(const char* key,char* plain_text,char* crypted_text,int length) +{ + char t_plain[MAX_CI_LEN]; + char t_crypt[MAX_CI_LEN]; + int en_cnt; + int pad_cnt=0; + int i; + + if(length>MAX_CI_LEN) return -1; + + for(i=0;iMAX_CI_LEN) return -1; + + for(i=0;i= 'a' ? ((what[0]) - 'a')+10 : (what[0] - '0')); + digit *= 16; + digit += (what[1] >= 'a' ? ((what[1]) - 'a')+10 : (what[1] - '0')); + return(digit); +} + +void tohex(const char* ins, char* outs, int len) { + const char* hex = "0123456789abcdef"; + unsigned int v; + int i = 0; + + for (i = 0; i < len; ++i) { + v = (unsigned int)ins[i]; + outs[2 * i] = hex[(v >> 4) & 0x0f]; + outs[2 * i + 1] = hex[v & 0x0f]; + } + outs[2 * i] = 0x00; +} diff --git a/cipher/tdes.h b/cipher/tdes.h new file mode 100644 index 0000000..5b32c29 --- /dev/null +++ b/cipher/tdes.h @@ -0,0 +1,18 @@ +#ifndef _T_DES_H +#define _T_DES_H + +#define MAX_CI_LEN 1024 +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + int cipher2(const char* key,char* plain_text,char* crypted_text,int length); + int decipher2(const char* key,char* plain_text,char* crypted_text,int length); + int cipher3(const char* key,char* plain_text,char* crypted_text,int length); + int decipher3(const char* key,char* plain_text,char* crypted_text,int length); + void TDes(char orientation,char *PlainText,char *key, char *ucEncipher); + char asc_bcd(char *what); + void tohex(const char* ins, char* outs, int len); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _T_DES_H */ diff --git a/cipher/unittest/Makefile b/cipher/unittest/Makefile new file mode 100644 index 0000000..374b3af --- /dev/null +++ b/cipher/unittest/Makefile @@ -0,0 +1,39 @@ +include ../../Makefile.comm +PROJECT = unittest + +SRCS = . +SRCS += ./ut +SRCS += .. +SRCS += ../../base + +LIB = -lstdc++ -lpthread + +INC = -I. +INC += -I.. +INC += -I../../base + +CPP_SRCS = $(foreach d,$(SRCS),$(wildcard $(d)/*.cpp)) +C_SRCS = $(foreach d,$(SRCS),$(wildcard $(d)/*.c)) + +CPP_OBJS = $(patsubst %.cpp, %.o, $(CPP_SRCS)) +C_OBJS = $(patsubst %.c, %.o, $(C_SRCS)) + +OBJS = $(CPP_OBJS) +OBJS += $(C_OBJS) +all : $(PROJECT) + +$(PROJECT) : $(OBJS) $(MODULE) + $(CC) -o $@ $(OBJS) $(LIB) + @echo "" + @echo "+--------------------------------------------+" + @echo "| Finish compilation unittest |" + @echo "+--------------------------------------------+" + @echo "| copyright(c)Wang Yaofu voipman@qq.com |" + @echo "+--------------------------------------------+" + +clean: + rm -rf *.o *.a *_unittest + +install : + test -d ../test || mkdir -p ../test + cp unittest ../test diff --git a/cipher/unittest/cipher_unittest.cpp b/cipher/unittest/cipher_unittest.cpp new file mode 100644 index 0000000..9cc3c58 --- /dev/null +++ b/cipher/unittest/cipher_unittest.cpp @@ -0,0 +1,380 @@ +/* +** Copyright (C) 2014 Wang Yaofu +** All rights reserved. +** +**Author:Wang Yaofu voipman@qq.com +**Description: The unit test file of base64. +*/ + +#include +#include +#include "base/base64.h" +#include "cipher/md5.h" +#include "cipher/digest.h" +#include "cipher/sha1.h" +#include "cipher/sha.h" +#include "cipher/sha256.h" +#include "cipher/sha512.h" +#include "cipher/sha224.h" +#include "cipher/sha384.h" +#include "cipher/hmac.h" +#include "cipher/tdes.h" +#include "cipher/rc4.h" +#include "cipher/pbkdf2_hmac.h" +#include "base/stringutils.h" +#include "ut/test_harness.h" + +using namespace std; +using namespace common; +void EncodeAndDecode(const std::string& s) +{ + string b; + EXPECT_TRUE(Base64Encode(s, &b)); + + string c; + EXPECT_TRUE(Base64Decode(b, &c)); + EXPECT_EQ(c, s); +} + +TEST(Base64Test, BasicTest) +{ + EncodeAndDecode("a"); + EncodeAndDecode("ab"); + EncodeAndDecode("abc"); + EncodeAndDecode("abcd"); + EncodeAndDecode("abcde"); + EncodeAndDecode("abcdef"); + EncodeAndDecode("abcdefg"); +} + +TEST(Base64Test, EncodeEmptyBuffer) +{ + std::string output; + EXPECT_TRUE(Base64Encode("", &output)); +} + +TEST(Base64Test, DecodeEmptyString) +{ + std::string output; + EXPECT_TRUE(Base64Decode("", &output)); +} + +TEST(Base64Test, DecodeWithPadding) +{ + std::string output; + std::string s = "e==="; + EXPECT_TRUE(!Base64Decode(s, &output)); + + s = ""; + EXPECT_TRUE(Base64Decode(s, &output)); + + s = "abcdAFCD\r\neF=="; + EXPECT_TRUE(Base64Decode(s, &output)); + EXPECT_EQ((size_t)7, output.size()); + + s = "abcdAFCD\r\neF==\r\n\r\n"; + EXPECT_TRUE(Base64Decode(s, &output)); + EXPECT_EQ((size_t)7, output.size()); + + s = "abcdAFCD\r\neF=a"; + EXPECT_TRUE(!Base64Decode(s, &output)); + + s = "abcdAFCD\r\ne==="; + EXPECT_TRUE(!Base64Decode(s, &output)); + + s = "abcdAFFCD\r\ne=="; + EXPECT_TRUE(Base64Decode(s, &output)); + EXPECT_EQ((size_t)7, output.size()); + + s = "abcdAFFCD\r\ne=\r\n="; + EXPECT_TRUE(Base64Decode(s, &output)); + EXPECT_EQ((size_t)7, output.size()); + + s = "abcdAF=D\r\nef=="; + EXPECT_TRUE(!Base64Decode(s, &output)); + + s = "abcdA"; + EXPECT_TRUE(!Base64Decode(s, &output)); + Base64Encode("admin:123", &output); + EXPECT_EQ(string("YWRtaW46MTIz"), output); + Base64Decode(output, &s); + EXPECT_EQ(string("admin:123"), s); +} + +TEST(Md5Test, BasicTest) { + unsigned char input[] = "1234567890"; + unsigned char output[100] = {0}; + MD5Calc(input, 10, output); + std::string cryptOut = "e807f1fcf82d132f9bb018ca6738a19f"; + std::string calcOut = StrUtils::Hex((char *)output, 16); + + EXPECT_EQ(cryptOut, calcOut); +} + +TEST(Sha1Test, BasicTest) { + unsigned char input[] = "1234567687890"; + unsigned char output[100] = {0}; + //SHA1Calc(input, 13, output); + SHA_Simple(input, 13, output); + std::string cryptOut = "21885c92cf31020ba246bfaa999e7c8e508c8d53"; + std::string calcOut = StrUtils::Hex((char *)output, 20); + + EXPECT_EQ(cryptOut, calcOut); +} + +TEST(Sha256Test, BasicTest1) +{ + + unsigned char input[] = "abc"; + unsigned char output[33] = {0}; + SHA256_Simple(input, 3, output); + std::string cryptOut = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"; + std::string calcOut = StrUtils::Hex((char *)output, 32); + EXPECT_EQ(cryptOut, calcOut); +} + +TEST(Sha256Test, BasicTest2) +{ + unsigned char input[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + unsigned char output[65] = {0}; + SHA256_Simple(input, 56, output); + std::string cryptOut = "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"; + std::string calcOut = StrUtils::Hex((char *)output, 32); + EXPECT_EQ(cryptOut, calcOut); + +} + +TEST(Sha224Test, BasicTest1) +{ + unsigned char input[] = "abc"; + unsigned char output[33] = { 0 }; + SHA224_Simple(input, 3, output); + std::string cryptOut = "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"; + std::string calcOut = StrUtils::Hex((char *)output, 28); + EXPECT_EQ(cryptOut, calcOut); +} + +TEST(Sha384Test, BasicTest1) +{ + unsigned char input[] = "abc"; + unsigned char output[65] = { 0 }; + SHA384_Simple(input, 3, output); + std::string cryptOut = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"; + std::string calcOut = StrUtils::Hex((char *)output, 48); + EXPECT_EQ(cryptOut, calcOut); +} + +TEST(Sha512Test, BasicTest1) +{ + unsigned char input[] = "abc"; + unsigned char output[65] = {0}; + SHA512_Simple(input, 3, output); + std::string cryptOut = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; + std::string calcOut = StrUtils::Hex((char *)output, 64); + EXPECT_EQ(cryptOut, calcOut); +} + +TEST(Sha512Test, BasicTest2) +{ + unsigned char input[] = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; + unsigned char output[65] = {0}; + SHA512_Simple(input, 112, output); + std::string cryptOut = "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909"; + std::string calcOut = StrUtils::Hex((char *)output, 64); + EXPECT_EQ(cryptOut, calcOut); +} +TEST(Sha512Test, BasicTest3) +{ + unsigned char input[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + unsigned char output[65] = {0}; + SHA512_State s; + int n; + SHA512_Init(&s); + for (n = 0; n < 1000000 / 40; n++) + SHA512_Bytes(&s, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 40); + SHA512_Final(&s, output); + std::string cryptOut = "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"; + std::string calcOut = StrUtils::Hex((char *)output, 64); + EXPECT_EQ(cryptOut, calcOut); +} + +TEST(TdesTest, BasicTest) { + char key[16]={"key"}; + char encpt[100]; + char result[100]; + char plain[] = "1234567890"; + int len = strlen(plain); + cipher2(key, plain, encpt, len); + decipher2(key, result, encpt, strlen(encpt)); + EXPECT_EQ(std::string(plain), std::string(result)); + + cipher3(key, plain, encpt,len); + decipher3(key, result, encpt, strlen(encpt)); + EXPECT_EQ(std::string(plain), std::string(result)); +} + +TEST(TDigestTest, BasicTest) { + unsigned char * pszNonce = (unsigned char*)"xx"; + unsigned char * pszCNonce = (unsigned char*)"248a286a6dda379e"; + unsigned char * pszUser = (unsigned char*)"admin"; + unsigned char * pszRealm = (unsigned char*)"xx"; + unsigned char * pszPass = (unsigned char*)"123456"; + unsigned char * pszAlg = (unsigned char*)"md5"; + unsigned char * szNonceCount = (unsigned char*)"00000001"; + unsigned char * pszMethod = (unsigned char*)"GET"; + unsigned char * pszQop = (unsigned char*)"auth"; + unsigned char * pszURI = (unsigned char*)"/fs/v1/addsite"; + HASHHEX HA1; + HASHHEX HA2 = ""; + HASHHEX Response; + + DigestCalcHA1(pszAlg, pszUser, pszRealm, pszPass, pszNonce, pszCNonce, HA1); + DigestCalcResponse(HA1, pszNonce, szNonceCount, pszCNonce, pszQop, + pszMethod, pszURI, HA2, Response); + string ha1((char *)HA1); + string digest((char *)Response); + EXPECT_EQ(string("ec6d21cdfe89d1a6b0be59a8f65a004f"), ha1); + EXPECT_EQ(string("02233a6d3420e580bf416cd340c43590"), digest); + +} + +TEST(RC4_Test, BasicTest) { + unsigned char* key = (unsigned char*)"key"; + char blk[100] = {0}; + strcpy(blk, "The quick brown fox jumps over the lazy dog"); + + RC4_Sample(key, 3, (unsigned char*)blk, 43); + string hexBlk = StrUtils::Hex(blk, 43); + EXPECT_EQ(string("5f0451cd55fa1229236b6a09792a7cdde91b9546c1948e8f45d3c7cb5c9e5bea7c5896e2c8f5c39c57b898"), hexBlk); + RC4_Sample(key, 3, (unsigned char*)blk, 43); + EXPECT_EQ(string("The quick brown fox jumps over the lazy dog"), string(blk)); +} + +TEST(PKCS5_PBKDF2_HMAC_Test, BasicTest) { + unsigned char* key = (unsigned char*)"key"; + char blk[100] = { 0 }; + strcpy(blk, "The quick brown fox jumps over the lazy dog"); + char hmac[21] = { 0 }; + PKCS5_PBKDF2_HMAC((unsigned char*)blk, 43, key, 3, 10, 20, (unsigned char*)hmac); + string hexBlk = StrUtils::Hex(hmac, 20); + EXPECT_EQ(string("2ca6b06c1ed5599af0546fc0067d1712e236b1de"), hexBlk); +} + +TEST(PKCS5_PBKDF2_HMAC_Test, BasicTest1) { + unsigned char* key = (unsigned char*)"salt"; + char blk[100] = { 0 }; + strcpy(blk, "password"); + char hmac[21] = { 0 }; + PKCS5_PBKDF2_HMAC((unsigned char*)blk, 8, key, 4, 2, 20, (unsigned char*)hmac); + string hexBlk = StrUtils::Hex(hmac, 20); + EXPECT_EQ(string("ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"), hexBlk); +} + +TEST(PKCS5_PBKDF2_HMAC_Test, BasicTestSha256_1) { + unsigned char* key = (unsigned char*)"salt"; + char blk[100] = { 0 }; + strcpy(blk, "password"); + char hmac[33] = { 0 }; + PKCS5_PBKDF2_HMAC2((unsigned char*)blk, 8, key, 4, 2, 32, (unsigned char*)hmac); + string hexBlk = StrUtils::Hex(hmac, 32); + EXPECT_EQ(string("ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43"), hexBlk); +} + +TEST(PKCS5_PBKDF2_HMAC_Test, BasicTestSha256_2) { + unsigned char* key = (unsigned char*)"salt"; + char blk[100] = { 0 }; + strcpy(blk, "password"); + char hmac[33] = { 0 }; + PKCS5_PBKDF2_HMAC2((unsigned char*)blk, 8, key, 4, 1, 32, (unsigned char*)hmac); + string hexBlk = StrUtils::Hex(hmac, 32); + EXPECT_EQ(string("120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b"), hexBlk); +} + + +TEST(PKCS5_PBKDF2_HMAC_Test, BasicTestSha512_2) { + unsigned char* key = (unsigned char*)"salt"; + char blk[100] = { 0 }; + strcpy(blk, "password"); + char hmac[65] = { 0 }; + PKCS5_PBKDF2_HMAC2((unsigned char*)blk, 8, key, 4, 1, 64, (unsigned char*)hmac); + string hexBlk = StrUtils::Hex(hmac, 64); + EXPECT_EQ(string("120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b4dbf3a2f3dad3377264bb7b8e8330d4efc7451418617dabef683735361cdc18c"), hexBlk); +} + +TEST(md5_hmac, BasicTest) { + unsigned char* key = (unsigned char*)"key"; + unsigned char* blk = (unsigned char*)"The quick brown fox jumps over the lazy dog"; + char hmac[21] = {0}; + + hmac_md5(key, 3, blk, 43, (unsigned char*)hmac); + string actualHmac = StrUtils::Hex(hmac, 16); + EXPECT_EQ(string("80070713463e7749b90c2dc24911e275"), actualHmac); + + memset(hmac, 0, sizeof hmac); + hmac_md5(key, 0, blk, 0, (unsigned char*)hmac); + actualHmac = StrUtils::Hex(hmac, 16); + EXPECT_EQ(string("74e6f7298a9c2d168935f58c001bad88"), actualHmac); + +} + +TEST(sha1_hmac, BasicTest) { + unsigned char* key = (unsigned char*)"key"; + unsigned char* blk = (unsigned char*)"wangyaofu try sha256 hash."; + char hmac[21] = { 0 }; + + hmac_sha1(key, 3, blk, 26, (unsigned char*)hmac); + string actualHmac = StrUtils::Hex(hmac, 20); + EXPECT_EQ(string("5e3c90f7bcbbe8c4ae878d7a6b186c112f005714"), actualHmac); + + memset(hmac, 0, sizeof hmac); + hmac_sha1(key, 0, blk, 26, (unsigned char*)hmac); + actualHmac = StrUtils::Hex(hmac, 20); + EXPECT_EQ(string("df50dee5e03d275d9fcfc024893e1dc94e464a8c"), actualHmac); + +} + +TEST(sha224_hmac, BasicTest) { + unsigned char* key = (unsigned char*)"key"; + unsigned char* blk = (unsigned char*)"wangyaofu try sha224 hash."; + char hmac[33] = { 0 }; + + hmac_sha224(key, 3, blk, 26, (unsigned char*)hmac); + string actualHmac = StrUtils::Hex(hmac, 28); + EXPECT_EQ(string("4d5a9a6ed549145dfbc30b0752ae3e05e06ccdd5695ec980f5a5739e"), actualHmac); + + memset(hmac, 0, sizeof hmac); + hmac_sha224(key, 0, blk, 26, (unsigned char*)hmac); + actualHmac = StrUtils::Hex(hmac, 28); + EXPECT_EQ(string("91a5e2e9d550a8bdd82c1e59bb149655fc6d34d90d8a29ce77a391d2"), actualHmac); +} + +TEST(sha256_hmac, BasicTest) { + unsigned char* key = (unsigned char*)"key"; + unsigned char* blk = (unsigned char*)"wangyaofu try sha256 hash."; + char hmac[33] = { 0 }; + + hmac_sha256(key, 3, blk, 26, (unsigned char*)hmac); + string actualHmac = StrUtils::Hex(hmac, 32); + EXPECT_EQ(string("dc1099cd35452f3cf1f6c11d3884bc4c9b637523c4e74060e1332eac01e7ad8e"), actualHmac); + + memset(hmac, 0, sizeof hmac); + hmac_sha256(key, 0, blk, 26, (unsigned char*)hmac); + actualHmac = StrUtils::Hex(hmac, 32); + EXPECT_EQ(string("37df81f1f26bb3949d4aad5ee27bb8bc5f124a7ff4d46e6d572ed96d5bde0ed8"), actualHmac); +} + +TEST(sha512_hmac, BasicTest) { + unsigned char* key = (unsigned char*)"key"; + unsigned char* blk = (unsigned char*)"37df81f1f26bb3949d4aad5ee27bb8bc5f124a7ff4d46e6d572ed96d5bde0ed8"; + char hmac[65] = { 0 }; + + hmac_sha512(key, 3, blk, 64, (unsigned char*)hmac); + string actualHmac = StrUtils::Hex(hmac, 64); + EXPECT_EQ(string("f671db32ad7cc79121e432bd05f2e1a3ecf2f450c73b839584feb0371a4c05d018222a59fea6077e3681dc27322e1f389a35118f0e23188d7d4ca10741ee7746"), actualHmac); + + memset(hmac, 0, sizeof hmac); + hmac_sha512(key, 0, blk, 64, (unsigned char*)hmac); + actualHmac = StrUtils::Hex(hmac, 64); + EXPECT_EQ(string("ac7b05b5c77842d7d8697bd0bb19ee74952f291b5dff9b2a2e58d82192368576dc81277ab3d59c0bc5a8fec61470ca1d8e3766f873d9769290be7c4cc855f32f"), actualHmac); +} diff --git a/cipher/unittest/ut/test_harness.cpp b/cipher/unittest/ut/test_harness.cpp new file mode 100644 index 0000000..5c56b1b --- /dev/null +++ b/cipher/unittest/ut/test_harness.cpp @@ -0,0 +1,95 @@ +#include "test_harness.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace common { + namespace test { + int errCount = 0; + namespace { + struct Test { + const char* base; + const char* name; + void(*func)(); + }; + std::vector* tests; + } + + bool RegisterTest(const char* base, const char* name, void(*func)()) { + if (tests == NULL) { + tests = new std::vector; + } + Test t; + t.base = base; + t.name = name; + t.func = func; + tests->push_back(t); + return true; + } + + int RunAllTests(const char* matcher) { + int num = 0; + if (tests != NULL) { + for (size_t i = 0; i < tests->size(); i++) { + const Test& t = (*tests)[i]; + if (matcher != NULL) { + std::string name = t.base; + name.push_back('.'); + name.append(t.name); + if (strstr(name.c_str(), matcher) == NULL) { + continue; + } + } + fprintf(stderr, "\033[0;32m[ RUN ] ==== Test %s.%s\n", t.base, t.name); + fprintf(stderr, "\033[0m"); + (*t.func)(); + ++num; + } + } + fprintf(stderr, "\033[0;32m[ PASS ] ==== PASSED %d tests\n", num); + fprintf(stderr, "\033[0;31m[ NOPASS ] ==== ERROR %d tests\n", errCount); + fprintf(stderr, "\033[0m\n"); + return 0; + } + + std::string TmpDir() { + return "/tmp"; + } + + int RandomSeed() { + return 301; + } + TestPerfomence::TestPerfomence() { + startMs_ = NowMs(); + } + TestPerfomence::TestPerfomence(int size) { + startMs_ = NowMs(); + fprintf(stderr, + "\033[0;32m[ RUN ] ==== start to run %lu cases.\n", + size); + } + TestPerfomence::~TestPerfomence() { + long endMs = NowMs(); + fprintf(stderr, + "\033[0;32m[ RUN ] ==== start at %lu, stop at %lu, cost:[%lu]\n", + startMs_, endMs, endMs - startMs_); + } + long TestPerfomence::NowMs() { + struct timeval timeNow; + gettimeofday(&timeNow, NULL); + return (timeNow.tv_sec) * 1000 + timeNow.tv_usec / 1000; + } + + } +} // namespace common + +using namespace common::test; +int main(int argc, char** argv) { + common::test::RunAllTests(NULL); + return 0; +} diff --git a/cipher/unittest/ut/test_harness.h b/cipher/unittest/ut/test_harness.h new file mode 100644 index 0000000..e73633e --- /dev/null +++ b/cipher/unittest/ut/test_harness.h @@ -0,0 +1,152 @@ +#pragma once +#include +#include +#include + +namespace common { +namespace test { +extern int errCount; +// Run some of the tests registered by the TEST() macro. If the +// environment variable "LEVELDB_TESTS" is not set, runs all tests. +// Otherwise, runs only the tests whose name contains the value of +// "LEVELDB_TESTS" as a substring. E.g., suppose the tests are: +// TEST(Foo, Hello) { ... } +// TEST(Foo, World) { ... } +// LEVELDB_TESTS=Hello will run the first test +// LEVELDB_TESTS=o will run both tests +// LEVELDB_TESTS=Junk will run no tests +// +// Returns 0 if all tests pass. +// Dies or returns a non-zero value if some test fails. +extern int RunAllTests(const char* matcher); + +// Return the directory to use for temporary storage. +extern std::string TmpDir(); + +// Return a randomization seed for this run. Typically returns the +// same number on repeated invocations of this binary, but automated +// runs may be able to vary the seed. +extern int RandomSeed(); + +// An instance of Tester is allocated to hold temporary state during +// the execution of an assertion. +class Tester { + private: + bool ok_; + const char* fname_; + int line_; + std::stringstream ss_; + + public: + Tester(const char* f, int l) + : ok_(true), fname_(f), line_(l) { + } + + ~Tester() { + if (!ok_) { + fprintf(stderr, "\033[0;31m[ ERROR ] ==== %s:%d:%s\n", + fname_, line_, ss_.str().c_str()); + fprintf(stderr, "\033[0m"); + errCount++; + //exit(1); + } + } + + Tester& Is(bool b, const char* msg) { + if (!b) { + ss_ << " Assertion failure " << msg; + ok_ = false; + } + return *this; + } + +#define BINARY_OP(name,op) \ + template \ + Tester& name(const X& x, const Y& y) { \ + if (! (x op y)) { \ + ss_ << " failed: Expect:" << x << (" " #op " ") << "Actual:" << y; \ + ok_ = false; \ + } \ + return *this; \ + } + + BINARY_OP(IsEq, ==) + BINARY_OP(IsNe, !=) + BINARY_OP(IsGe, >=) + BINARY_OP(IsGt, >) + BINARY_OP(IsLe, <=) + BINARY_OP(IsLt, <) +#undef BINARY_OP +#define DOUBLE_OP(name,op) \ + template \ + Tester& name(const X& x, const Y& y) { \ + if (! (x - y > -0.000001 && x-y <0.000001)) { \ + ss_ << " failed: Expect:" << x << (" " #op " ") << "Actual:" << y; \ + ok_ = false; \ + } \ + return *this; \ + } + DOUBLE_OP(IsDoubleEq, ==) +#undef DOUBLE_OP + + // Attach the specified value to the error message if an error has occurred + template + Tester& operator<<(const V& value) { + if (!ok_) { + ss_ << " " << value; + } + return *this; + } +}; + +#define ASSERT_TRUE(c) ::common::test::Tester(__FILE__, __LINE__).Is((c), #c) +#define ASSERT_FALSE(c) ::common::test::Tester(__FILE__, __LINE__).Is(!(c), #c) +#define ASSERT_EQ(a,b) ::common::test::Tester(__FILE__, __LINE__).IsEq((a),(b)) +#define ASSERT_NE(a,b) ::common::test::Tester(__FILE__, __LINE__).IsNe((a),(b)) +#define ASSERT_GE(a,b) ::common::test::Tester(__FILE__, __LINE__).IsGe((a),(b)) +#define ASSERT_GT(a,b) ::common::test::Tester(__FILE__, __LINE__).IsGt((a),(b)) +#define ASSERT_LE(a,b) ::common::test::Tester(__FILE__, __LINE__).IsLe((a),(b)) +#define ASSERT_LT(a,b) ::common::test::Tester(__FILE__, __LINE__).IsLt((a),(b)) +#define EXPECT_GT(a,b) ::common::test::Tester(__FILE__, __LINE__).IsLt((a),(b)) +#define EXPECT_LT(a,b) ::common::test::Tester(__FILE__, __LINE__).IsLt((a),(b)) +#define EXPECT_EQ(a,b) ::common::test::Tester(__FILE__, __LINE__).IsEq((a),(b)) +#define EXPECT_NE(a,b) ::common::test::Tester(__FILE__, __LINE__).IsNe((a),(b)) +#define EXPECT_DOUBLE_EQ(a,b) ::common::test::Tester(__FILE__, __LINE__).IsDoubleEq((a),(b)) +#define EXPECT_TRUE(a) ::common::test::Tester(__FILE__, __LINE__).IsEq((a),(true)) +#define EXPECT_FALSE(a) ::common::test::Tester(__FILE__, __LINE__).IsEq((a),(false)) +#define EXPECT_THROW(a,exceptions) try {a;} catch(exceptions e) {EXPECT_TRUE(true);} catch(...) {EXPECT_TRUE(false);} +#define EXPECT_ANY_THROW(a) try {a;} catch(...) {EXPECT_TRUE(true);} +#define TCONCAT(a,b) TCONCAT1(a,b) +#define TCONCAT1(a,b) a##b + +#define TEST(base,name) \ +class TCONCAT(_Test_,base##name) : public ::common::test::TestBase { \ + public: \ + void _Run(); \ + static void _RunIt() { \ + TCONCAT(_Test_,base##name) t; \ + t._Run(); \ + } \ +}; \ +bool TCONCAT(_Test_ignored_,base##name) = \ + ::common::test::RegisterTest(#base, #name, &TCONCAT(_Test_,base##name)::_RunIt); \ +void TCONCAT(_Test_,base##name)::_Run() + +// Register the specified test. Typically not used directly, but +// invoked via the macro expansion of TEST. +extern bool RegisterTest(const char* base, const char* name, void (*func)()); + +class TestBase {}; + +class TestPerfomence { +public: + TestPerfomence(); + TestPerfomence(int size); + ~TestPerfomence(); + long NowMs(); +private: + long startMs_; +}; +#define TEST_PERF(a,size) ::common::test::TestPerfomence a(size); +} // namespace test +} // namespace common