common.cpp (513 lines of code) (raw):
#include "common.h"
#include "lz4.h"
#include <cstdint>
#if defined(_MSC_VER)
#include <stdlib.h>
#define __sls_swap32 _byteswap_ulong
#elif defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define __sls_swap32(x) OSSwapInt32(x)
#elif defined(__linux__)
#include <byteswap.h>
#define __sls_swap32(x) bswap_32(x)
#elif defined(__FreeBSD__)
#include <sys/endian.h>
#define __sls_swap32(x) bswap32(x)
#elif defined(__OpenBSD__)
#include <sys/types.h>
#define __sls_swap32(x) swap32(x)
#else
static uint32_t __sls_swap32 (uint32_t x)
{
return ((x << 24) & 0xff000000 ) |
((x << 8) & 0x00ff0000 ) |
((x >> 8) & 0x0000ff00 ) |
((x >> 24) & 0x000000ff );
}
#endif
namespace aliyun_log_sdk_v6
{
/////////////////////////////////////////////// MACRO //////////////////////////////////////////////////
#define SHIFT_LEFT(a, b) ((a) << (b) | (a) >> (32 - b))
/**
* each operation
*/
#define F(b, c, d) (((b) & (c)) | ( (~(b)) & (d)))
#define G(b, c, d) (((d) & (b)) | ( (~(d)) & (c)))
#define H(b, c, d) ((b) ^ (c) ^ (d))
#define I(b, c, d) ((c) ^ ((b) | (~(d))))
/**
* each round
*/
#define FF(a, b, c, d, word, shift, k) \
{ \
(a) += F((b), (c), (d)) + (word) + (k); \
(a) = SHIFT_LEFT((a), (shift)); \
(a) += (b); \
}
#define GG(a, b, c, d, word, shift, k) \
{ \
(a) += G((b), (c), (d)) + (word) + (k); \
(a) = SHIFT_LEFT((a), (shift)); \
(a) += (b); \
}
#define HH(a, b, c, d, word, shift, k) \
{ \
(a) += H((b), (c), (d)) + (word) + (k); \
(a) = SHIFT_LEFT((a), (shift)); \
(a) += (b); \
}
#define II(a, b, c, d, word, shift, k) \
{ \
(a) += I((b), (c), (d)) + (word) + (k); \
(a) = SHIFT_LEFT((a), (shift)); \
(a) += (b); \
}
////////////////////////////////////////////////////////// GLOBAL VARIABLE /////////////////////////////////////////////////////////
const uint8_t gPadding[64] =
{
0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};
//////////////////////////////////////////////////////// LOCAL DECLEARATION //////////////////////////////////////////////////////////
struct Md5Block
{
uint32_t word[16];
};
/**
* copy a pool into a block, using little endian
*/
void CopyBytesToBlock(const uint8_t* poolIn, struct Md5Block& block)
{
uint32_t j = 0;
for (uint32_t i = 0; i < 32; ++i, j += 4)
{
block.word[i] = ((uint32_t) poolIn[j])
| (((uint32_t) poolIn[j+1]) << 8)
| (((uint32_t) poolIn[j+2]) << 16)
| (((uint32_t) poolIn[j+3]) << 24);
}
}
/**
* calculate md5 hash value from a block
*/
void CalMd5(struct Md5Block block, uint32_t h[4])
{
uint32_t a = h[0];
uint32_t b = h[1];
uint32_t c = h[2];
uint32_t d = h[3];
// Round 1
FF (a, b, c, d, block.word[0], 7, 0xd76aa478);
FF (d, a, b, c, block.word[1], 12, 0xe8c7b756);
FF (c, d, a, b, block.word[2], 17, 0x242070db);
FF (b, c, d, a, block.word[3], 22, 0xc1bdceee);
FF (a, b, c, d, block.word[4], 7, 0xf57c0faf);
FF (d, a, b, c, block.word[5], 12, 0x4787c62a);
FF (c, d, a, b, block.word[6], 17, 0xa8304613);
FF (b, c, d, a, block.word[7], 22, 0xfd469501);
FF (a, b, c, d, block.word[8], 7, 0x698098d8);
FF (d, a, b, c, block.word[9], 12, 0x8b44f7af);
FF (c, d, a, b, block.word[10], 17, 0xffff5bb1);
FF (b, c, d, a, block.word[11], 22, 0x895cd7be);
FF (a, b, c, d, block.word[12], 7, 0x6b901122);
FF (d, a, b, c, block.word[13], 12, 0xfd987193);
FF (c, d, a, b, block.word[14], 17, 0xa679438e);
FF (b, c, d, a, block.word[15], 22, 0x49b40821);
// Round 2
GG (a, b, c, d, block.word[1], 5, 0xf61e2562);
GG (d, a, b, c, block.word[6], 9, 0xc040b340);
GG (c, d, a, b, block.word[11], 14, 0x265e5a51);
GG (b, c, d, a, block.word[0], 20, 0xe9b6c7aa);
GG (a, b, c, d, block.word[5], 5, 0xd62f105d);
GG (d, a, b, c, block.word[10], 9, 0x2441453);
GG (c, d, a, b, block.word[15], 14, 0xd8a1e681);
GG (b, c, d, a, block.word[4], 20, 0xe7d3fbc8);
GG (a, b, c, d, block.word[9], 5, 0x21e1cde6);
GG (d, a, b, c, block.word[14], 9, 0xc33707d6);
GG (c, d, a, b, block.word[3], 14, 0xf4d50d87);
GG (b, c, d, a, block.word[8], 20, 0x455a14ed);
GG (a, b, c, d, block.word[13], 5, 0xa9e3e905);
GG (d, a, b, c, block.word[2], 9, 0xfcefa3f8);
GG (c, d, a, b, block.word[7], 14, 0x676f02d9);
GG (b, c, d, a, block.word[12], 20, 0x8d2a4c8a);
// Round 3
HH (a, b, c, d, block.word[5], 4, 0xfffa3942);
HH (d, a, b, c, block.word[8], 11, 0x8771f681);
HH (c, d, a, b, block.word[11], 16, 0x6d9d6122);
HH (b, c, d, a, block.word[14], 23, 0xfde5380c);
HH (a, b, c, d, block.word[1], 4, 0xa4beea44);
HH (d, a, b, c, block.word[4], 11, 0x4bdecfa9);
HH (c, d, a, b, block.word[7], 16, 0xf6bb4b60);
HH (b, c, d, a, block.word[10], 23, 0xbebfbc70);
HH (a, b, c, d, block.word[13], 4, 0x289b7ec6);
HH (d, a, b, c, block.word[0], 11, 0xeaa127fa);
HH (c, d, a, b, block.word[3], 16, 0xd4ef3085);
HH (b, c, d, a, block.word[6], 23, 0x4881d05);
HH (a, b, c, d, block.word[9], 4, 0xd9d4d039);
HH (d, a, b, c, block.word[12], 11, 0xe6db99e5);
HH (c, d, a, b, block.word[15], 16, 0x1fa27cf8);
HH (b, c, d, a, block.word[2], 23, 0xc4ac5665);
// Round 4
II (a, b, c, d, block.word[0], 6, 0xf4292244);
II (d, a, b, c, block.word[7], 10, 0x432aff97);
II (c, d, a, b, block.word[14], 15, 0xab9423a7);
II (b, c, d, a, block.word[5], 21, 0xfc93a039);
II (a, b, c, d, block.word[12], 6, 0x655b59c3);
II (d, a, b, c, block.word[3], 10, 0x8f0ccc92);
II (c, d, a, b, block.word[10], 15, 0xffeff47d);
II (b, c, d, a, block.word[1], 21, 0x85845dd1);
II (a, b, c, d, block.word[8], 6, 0x6fa87e4f);
II (d, a, b, c, block.word[15], 10, 0xfe2ce6e0);
II (c, d, a, b, block.word[6], 15, 0xa3014314);
II (b, c, d, a, block.word[13], 21, 0x4e0811a1);
II (a, b, c, d, block.word[4], 6, 0xf7537e82);
II (d, a, b, c, block.word[11], 10, 0xbd3af235);
II (c, d, a, b, block.word[2], 15, 0x2ad7d2bb);
II (b, c, d, a, block.word[9], 21, 0xeb86d391);
// Add to hash value
h[0] += a;
h[1] += b;
h[2] += c;
h[3] += d;
}
void DoMd5Little(const uint8_t* poolIn, const uint64_t inputBytesNum, uint8_t hash[16])
{
struct Md5Block block;
///initialize hash value
uint32_t h[4];
h[0] = 0x67452301;
h[1] = 0xEFCDAB89;
h[2] = 0x98BADCFE;
h[3] = 0x10325476;
///padding and divide input data into blocks
uint64_t fullLen = (inputBytesNum >> 6) << 6; ///complete blocked length
uint64_t partLen = inputBytesNum & 0x3F; ///length remained
uint32_t i;
for (i = 0; i < fullLen; i += 64)
{
///copy input data into block
memcpy(block.word, &(poolIn[i]), 64);
///calculate Md5
CalMd5(block, h);
}
if (partLen > 55) ///append two more blocks
{
///copy input data into block and pad
memcpy(block.word, &(poolIn[i]), partLen);
memcpy( ((uint8_t*)&(block.word[partLen >> 2])) + (partLen & 0x3), gPadding, (64 - partLen));
///calculate Md5
CalMd5(block, h);
///set rest byte to 0x0
memset(block.word, 0x0, 64);
}
else ///append one more block
{
///copy input data into block and pad
memcpy(block.word, &(poolIn[i]), partLen);
memcpy( ((uint8_t*)&(block.word[partLen >> 2])) + (partLen & 0x3), gPadding, (64 - partLen));
}
///append length (bits)
uint64_t bitsNum = inputBytesNum * 8;
memcpy(&(block.word[14]), &bitsNum, 8);
///calculate Md5
CalMd5(block, h);
///clear sensitive information
memset(block.word, 0, 64);
///fill hash value
memcpy(&(hash[0]), &(h[0]), 16);
}///DoMd5Little
void DoMd5Big(const uint8_t* poolIn, const uint64_t inputBytesNum, uint8_t hash[16])
{
struct Md5Block block;
uint8_t tempBlock[64];
///initialize hash value
uint32_t h[4];
h[0] = 0x67452301;
h[1] = 0xEFCDAB89;
h[2] = 0x98BADCFE;
h[3] = 0x10325476;
///padding and divide input data into blocks
uint64_t fullLen = (inputBytesNum >> 6) << 6;
uint64_t partLen = inputBytesNum & 0x3F;
uint32_t i;
for (i = 0; i < fullLen; i += 64)
{
///copy input data into block, in little endian
CopyBytesToBlock(&(poolIn[i]), block);
///calculate Md5
CalMd5(block, h);
}
///append two more blocks
if (partLen > 55)
{
///put input data into a temporary block
memcpy(tempBlock, &(poolIn[i]), partLen);
memcpy(&(tempBlock[partLen]), gPadding, (64 - partLen));
///copy temporary data into block, in little endian
CopyBytesToBlock(tempBlock, block);
///calculate Md5
CalMd5(block, h);
memset(tempBlock, 0x0, 64);
}
///append one more block
else
{
memcpy(tempBlock, &(poolIn[i]), partLen);
memcpy( &(tempBlock[partLen]), gPadding, (64 - partLen));
}
///append length (bits)
uint64_t bitsNum = inputBytesNum * 8;
memcpy(&(tempBlock[56]), &bitsNum, 8);
///copy temporary data into block, in little endian
CopyBytesToBlock(tempBlock, block);
///calculate Md5
CalMd5(block, h);
///clear sensitive information
memset(block.word, 0, 64);
memset(tempBlock, 0, 64);
///fill hash value
memcpy(&(hash[0]), &(h[0]), 16);
}///DoMd5Big
void DoMd5(const uint8_t* poolIn, const uint64_t inputBytesNum, uint8_t md5[16])
{
///detect big or little endian
union
{
uint32_t a;
uint8_t b;
} symbol;
symbol.a = 1;
///for little endian
if (symbol.b == 1)
{
DoMd5Little(poolIn, inputBytesNum, md5);
}
///for big endian
else
{
DoMd5Big(poolIn, inputBytesNum, md5);
}
}///DoMd5
/*
* define the rotate left (circular left shift) operation
*/
#define rotl(v,b) (((v)<<(b))|((v)>>(32-(b))))
/*
* Define the basic SHA-1 functions F1 ~ F4. Note that the exclusive-OR
* operation (^) in F1 and F3 may be replaced by a bitwise OR operation
* (|), which produce identical results.
*
* F1 is used in ROUND 0~19, F2 is used in ROUND 20~39
* F3 is used in ROUND 40~59, F4 is used in ROUND 60~79
*/
#define F1(B,C,D) (((B)&(C))^(~(B)&(D)))
#define F2(B,C,D) ((B)^(C)^(D))
#define F3(B,C,D) (((B)&(C))^((B)&(D))^((C)&(D)))
#define F4(B,C,D) ((B)^(C)^(D))
/*
* Use different K in different ROUND
*/
#define K00_19 0x5A827999
#define K20_39 0x6ED9EBA1
#define K40_59 0x8F1BBCDC
#define K60_79 0xCA62C1D6
/*
* Another implementation of the ROUND transformation:
* (here the T is a temp variable)
* For t=0 to 79:
* {
* T=rotl(A,5)+Func(B,C,D)+K+W[t]+E;
* E=D; D=C; C=rotl(B,30); B=A; A=T;
* }
*/
#define ROUND(t,A,B,C,D,E,Func,K) E+=rotl(A,5)+Func(B,C,D)+W[t]+K; B=rotl(B,30);
#define ROUND5(t,Func,K) ROUND(t,A,B,C,D,E,Func,K);\
ROUND(t+1,E,A,B,C,D,Func,K);\
ROUND(t+2,D,E,A,B,C,Func,K );\
ROUND(t+3,C,D,E,A,B,Func,K);\
ROUND(t+4,B,C,D,E,A,Func,K)
#define ROUND20(t,Func,K) ROUND5(t,Func,K);\
ROUND5(t+5,Func,K);\
ROUND5(t+10,Func,K);\
ROUND5(t+15,Func,K)
/*
* Define constant of the initial vector
*/
const uint32_t SHA1::IV[SHA1_DIGEST_WORDS] = {
0x67452301,
0xEFCDAB89,
0x98BADCFE,
0x10325476,
0xC3D2E1F0
};
/*
* the message must be the big-endian32 (or left-most word)
* before calling the transform() function.
*/
const static uint32_t iii=1;
const static bool littleEndian = *(uint8_t*)&iii!=0;
inline void make_big_endian32(uint32_t *data, unsigned n)
{
if (littleEndian) for (; n>0; ++data,--n) *data = __sls_swap32(*data);
}
inline size_t min(size_t a,size_t b) {return a<b ? a : b;}
void SHA1::transform()
{
uint32_t W[80];
memcpy(W, M, SHA1_INPUT_BYTES);
memset((uint8_t*)W+SHA1_INPUT_BYTES, 0, sizeof(W)-SHA1_INPUT_BYTES);
for (unsigned t=16; t<80; t++) {
W[t] = rotl(W[t-16]^W[t-14]^W[t-8]^W[t-3],1);
}
uint32_t A = H[0];
uint32_t B = H[1];
uint32_t C = H[2];
uint32_t D = H[3];
uint32_t E = H[4];
ROUND20( 0,F1,K00_19);
ROUND20(20,F2,K20_39);
ROUND20(40,F3,K40_59);
ROUND20(60,F4,K60_79);
H[0] += A;
H[1] += B;
H[2] += C;
H[3] += D;
H[4] += E;
}
void SHA1::add(const uint8_t* data, size_t data_len)
{
unsigned mlen=(unsigned)((bits>>3)%SHA1_INPUT_BYTES);
bits += (uint64_t)data_len<<3;
unsigned use = (unsigned)min((size_t)(SHA1_INPUT_BYTES - mlen), data_len);
memcpy(M+mlen, data, use);
mlen += use;
while (mlen==SHA1_INPUT_BYTES) {
data_len -= use;
data += use;
make_big_endian32((uint32_t*)M, SHA1_INPUT_WORDS);
transform();
use=(unsigned)min((size_t)SHA1_INPUT_BYTES, data_len);
memcpy(M,data,use);
mlen=use;
}
}
uint8_t *SHA1::result()
{
unsigned mlen = (unsigned)((bits>>3)%SHA1_INPUT_BYTES), padding = SHA1_INPUT_BYTES - mlen;
M[mlen++] = 0x80;
if (padding > BIT_COUNT_BYTES) {
memset(M+mlen, 0x00, padding-BIT_COUNT_BYTES);
make_big_endian32((uint32_t*)M, SHA1_INPUT_WORDS-BIT_COUNT_WORDS);
}
else {
memset(M+mlen, 0x00, SHA1_INPUT_BYTES - mlen);
make_big_endian32((uint32_t*)M, SHA1_INPUT_WORDS);
transform();
memset(M, 0x00, SHA1_INPUT_BYTES-BIT_COUNT_BYTES);
}
uint64_t temp = littleEndian ? bits<<32 | bits>>32 : bits;
memcpy(M + SHA1_INPUT_BYTES - BIT_COUNT_BYTES, &temp, BIT_COUNT_BYTES);
transform();
make_big_endian32(H, SHA1_DIGEST_WORDS);
return (uint8_t*)H;
}
template<typename T>
inline void axor(T *p1, const T *p2, size_t len)
{
for (; len != 0; --len) *p1++ ^= *p2++;
}
HMAC::HMAC(const uint8_t *key, size_t lkey)
{
init(key, lkey);
}
void HMAC::init(const uint8_t *key, size_t lkey)
{
in.init();
out.init();
uint8_t ipad[SHA1_INPUT_BYTES];
uint8_t opad[SHA1_INPUT_BYTES];
memset(ipad, 0x36, sizeof(ipad));
memset(opad, 0x5c, sizeof(opad));
if (lkey <= SHA1_INPUT_BYTES) {
axor(ipad, key, lkey);
axor(opad, key, lkey);
}
else {
SHA1 tmp;
tmp.add(key, lkey);
const uint8_t *key2 = tmp.result();
axor(ipad, key2, SHA1_DIGEST_BYTES);
axor(opad, key2, SHA1_DIGEST_BYTES);
}
in.add((uint8_t*)ipad, sizeof(ipad));
out.add((uint8_t*)opad, sizeof(opad));
}
void Base64Encoding(std::istream& is, std::ostream& os, char makeupChar, const char *alphabet)
{
int out[4];
int remain = 0;
while (!is.eof())
{
int byte1 = is.get();
if (byte1 < 0)
{
break;
}
int byte2 = is.get();
int byte3;
if (byte2 < 0)
{
byte2 = 0;
byte3 = 0;
remain = 1;
}
else
{
byte3 = is.get();
if (byte3 < 0)
{
byte3 = 0;
remain = 2;
}
}
out[0] = static_cast<unsigned>(byte1) >> 2;
out[1] = ((byte1 & 0x03) << 4) + (static_cast<unsigned>(byte2) >> 4);
out[2] = ((byte2 & 0x0F) << 2) + (static_cast<unsigned>(byte3) >> 6);
out[3] = byte3 & 0x3F;
if (remain == 1)
{
os.put(out[0] = alphabet[out[0]]);
os.put(out[1] = alphabet[out[1]]);
os.put(makeupChar);
os.put(makeupChar);
}
else if (remain == 2)
{
os.put(out[0] = alphabet[out[0]]);
os.put(out[1] = alphabet[out[1]]);
os.put(out[2] = alphabet[out[2]]);
os.put(makeupChar);
}
else
{
os.put(out[0] = alphabet[out[0]]);
os.put(out[1] = alphabet[out[1]]);
os.put(out[2] = alphabet[out[2]]);
os.put(out[3] = alphabet[out[3]]);
}
}
}
bool CompressAlgorithm::CompressLz4(const char* srcPtr, const uint32_t srcSize, std::string& dst)
{
uint32_t encodingSize = LZ4_compressBound(srcSize);
dst.resize(encodingSize);
char* compressed = const_cast<char*>(dst.c_str());
try
{
encodingSize = LZ4_compress(srcPtr, compressed, srcSize);
if (encodingSize)
{
dst.resize(encodingSize);
return true;
}
}
catch (...)
{
}
return false;
}
bool CompressAlgorithm::CompressLz4(const std::string& src, std::string& dst)
{
return CompressLz4(src.c_str(), src.length(), dst);
}
bool CompressAlgorithm::UncompressLz4(const char* srcPtr, const uint32_t srcSize, const uint32_t rawSize, std::string& dst)
{
dst.resize(rawSize);
char* unCompressed = const_cast<char*>(dst.c_str());
uint32_t length = 0;
try
{
length = LZ4_decompress_safe(srcPtr, unCompressed, srcSize, rawSize);
}
catch(...)
{
return false;
}
if (length != rawSize)
{
return false;
}
return true;
}
bool CompressAlgorithm::UncompressLz4(const std::string& src, const uint32_t rawSize, std::string& dst)
{
return UncompressLz4(src.c_str(), src.length(), rawSize, dst);
}
template<class T>
inline std::string SignedToString(const T& n)
{
long long ll = static_cast<long long>(n);
char buf[64];
snprintf(buf, sizeof(buf), "%lld", ll);
return std::string(buf);
}
std::string ToString(const int32_t& n)
{
return SignedToString(n);
}
template<class T>
inline std::string UnsignedToString(const T& n)
{
unsigned long long llu = static_cast<unsigned long long>(n);
char buf[64];
snprintf(buf, sizeof(buf), "%llu", llu);
return std::string(buf);
}
std::string ToString(const uint32_t& n)
{
return UnsignedToString(n);
}
std::string ToString(const size_t&n)
{
return UnsignedToString(n);
}
std::string ToString(const int64_t& n)
{
return SignedToString(n);
}
std::string ToString(const bool& n)
{
if(n)
return "true";
else
return "false";
}
}