ChecksumCalculator.cpp revision d90692889a26513d87f9f652221aeb727ad67a94
1/* 2* Copyright (C) 2016 The Android Open Source Project 3* 4* Licensed under the Apache License, Version 2.0 (the "License"); 5* you may not use this file except in compliance with the License. 6* You may obtain a copy of the License at 7* 8* http://www.apache.org/licenses/LICENSE-2.0 9* 10* Unless required by applicable law or agreed to in writing, software 11* distributed under the License is distributed on an "AS IS" BASIS, 12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13* See the License for the specific language governing permissions and 14* limitations under the License. 15*/ 16 17#include "ChecksumCalculator.h" 18 19#include <string.h> 20 21// Checklist when implementing new protocol: 22// 1. update CHECKSUMHELPER_MAX_VERSION 23// 2. update maxChecksumSize() 24// 3. update checksumByteSize() 25// 4. update addBuffer, writeChecksum, resetChecksum, validate 26 27// change CHECKSUMHELPER_MAX_VERSION when you want to update the protocol version 28#define CHECKSUMHELPER_MAX_VERSION 1 29 30// checksum buffer size 31// Please add a new checksum buffer size when implementing a new protocol, 32// as well as modifying the maxChecksumSize function. 33static const size_t kV1ChecksumSize = 8; 34 35static size_t maxChecksumSize() { 36 return 0 > kV1ChecksumSize ? 0 : kV1ChecksumSize; 37} 38 39static const size_t kMaxChecksumSize = maxChecksumSize(); 40 41// utility macros to create checksum string at compilation time 42#define CHECKSUMHELPER_VERSION_STR_PREFIX "ANDROID_EMU_CHECKSUM_HELPER_v" 43#define CHECKSUMHELPER_MACRO_TO_STR(x) #x 44#define CHECKSUMHELPER_MACRO_VAL_TO_STR(x) CHECKSUMHELPER_MACRO_TO_STR(x) 45 46static const uint32_t kMaxVersion = CHECKSUMHELPER_MAX_VERSION; 47static const char* kMaxVersionStrPrefix = CHECKSUMHELPER_VERSION_STR_PREFIX; 48static const char* kMaxVersionStr = CHECKSUMHELPER_VERSION_STR_PREFIX CHECKSUMHELPER_MACRO_VAL_TO_STR(CHECKSUMHELPER_MAX_VERSION); 49 50#undef CHECKSUMHELPER_MAX_VERSION 51#undef CHECKSUMHELPER_VERSION_STR_PREFIX 52#undef CHECKSUMHELPER_MACRO_TO_STR 53#undef CHECKSUMHELPER_MACRO_VAL_TO_STR 54 55uint32_t ChecksumCalculator::getMaxVersion() {return kMaxVersion;} 56const char* ChecksumCalculator::getMaxVersionStr() {return kMaxVersionStr;} 57const char* ChecksumCalculator::getMaxVersionStrPrefix() {return kMaxVersionStrPrefix;} 58 59bool ChecksumCalculator::setVersion(uint32_t version) { 60 if (version > kMaxVersion) { // unsupported version 61 LOG_CHECKSUMHELPER("%s: ChecksumCalculator Set Unsupported version Version %d\n", 62 __FUNCTION__, m_version); 63 return false; 64 } 65 if (m_isEncodingChecksum) { // setVersion is called in the middle of encoding checksums 66 LOG_CHECKSUMHELPER("%s: called between addBuffer and writeChecksum\n", 67 __FUNCTION__); 68 return false; 69 } 70 m_version = version; 71 LOG_CHECKSUMHELPER("%s: ChecksumCalculator Set Version %d\n", __FUNCTION__, 72 m_version); 73 return true; 74} 75 76size_t ChecksumCalculator::checksumByteSize() const { 77 switch (m_version) { 78 case 0: 79 return 0; 80 case 1: 81 return sizeof(uint32_t) + sizeof(m_numWrite); 82 default: 83 return 0; 84 } 85} 86 87ChecksumCalculator::ChecksumCalculator() 88 : m_version(0) 89 , m_numRead(0) 90 , m_numWrite(0) 91 , m_isEncodingChecksum(false) 92 , m_v1BufferTotalLength(0) 93{ 94} 95 96void ChecksumCalculator::addBuffer(const void* buf, size_t packetLen) { 97 m_isEncodingChecksum = true; 98 switch (m_version) { 99 case 1: 100 m_v1BufferTotalLength += packetLen; 101 break; 102 } 103} 104 105bool ChecksumCalculator::writeChecksum(void* outputChecksum, size_t outputChecksumLen) { 106 if (outputChecksumLen < checksumByteSize()) return false; 107 char *checksumPtr = (char *)outputChecksum; 108 switch (m_version) { 109 case 1: { // protocol v1 is to reverse the packetLen and write it at the end 110 uint32_t val = computeV1Checksum(); 111 memcpy(checksumPtr, &val, sizeof(val)); 112 memcpy(checksumPtr+sizeof(val), &m_numWrite, sizeof(m_numWrite)); 113 break; 114 } 115 } 116 resetChecksum(); 117 m_numWrite++; 118 return true; 119} 120 121void ChecksumCalculator::resetChecksum() { 122 switch (m_version) { 123 case 1: 124 m_v1BufferTotalLength = 0; 125 break; 126 } 127 m_isEncodingChecksum = false; 128} 129 130bool ChecksumCalculator::validate(const void* expectedChecksum, size_t expectedChecksumLen) { 131 size_t checksumSize = checksumByteSize(); 132 if (expectedChecksumLen != checksumSize) { 133 m_numRead++; 134 resetChecksum(); 135 return false; 136 } 137 // buffers for computing the checksum 138 unsigned char sChecksumBuffer[kMaxChecksumSize]; 139 switch (m_version) { 140 case 1: { 141 uint32_t val = computeV1Checksum(); 142 memcpy(sChecksumBuffer, &val, sizeof(val)); 143 memcpy(sChecksumBuffer+sizeof(val), &m_numRead, sizeof(m_numRead)); 144 break; 145 } 146 } 147 bool isValid = !memcmp(sChecksumBuffer, expectedChecksum, checksumSize); 148 m_numRead++; 149 resetChecksum(); 150 return isValid; 151} 152 153uint32_t ChecksumCalculator::computeV1Checksum() { 154 uint32_t revLen = m_v1BufferTotalLength; 155 revLen = (revLen & 0xffff0000) >> 16 | (revLen & 0x0000ffff) << 16; 156 revLen = (revLen & 0xff00ff00) >> 8 | (revLen & 0x00ff00ff) << 8; 157 revLen = (revLen & 0xf0f0f0f0) >> 4 | (revLen & 0x0f0f0f0f) << 4; 158 revLen = (revLen & 0xcccccccc) >> 2 | (revLen & 0x33333333) << 2; 159 revLen = (revLen & 0xaaaaaaaa) >> 1 | (revLen & 0x55555555) << 1; 160 return revLen; 161} 162