blob: 1d23651fb69719c716f2b4aa12ec97167bf85cc9 [file] [log] [blame]
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "securemessage/byte_buffer.h"
#include <climits>
#include <cstring>
#include <iomanip>
#include <sstream>
using std::vector;
namespace securemessage {
ByteBuffer::ByteBuffer() {
// Do nothing
}
ByteBuffer::~ByteBuffer() { Wipe(); }
ByteBuffer::ByteBuffer(const size_t size) {
// Fills the data buffer with size number of zeros
data_.resize(size, 0);
}
void ByteBuffer::SetData(const uint8_t* source_data, const size_t length) {
// reserve() might cause re-allocation, so we wipe first.
Wipe();
data_.clear();
data_.resize(length);
for (size_t i = 0; i < length; i++) {
data_[i] = source_data[i];
}
}
void ByteBuffer::Append(const size_t num_bytes, const uint8_t byte) {
// harmless on size_t overflow, but might cause reallocation which might leak
// data on the heap
data_.reserve(data_.size() + num_bytes);
data_.insert(data_.end(), num_bytes, byte);
}
void ByteBuffer::Prepend(const string& str) {
// might cause reallocation which might leak data on the heap
data_.insert(data_.begin(), str.begin(), str.end());
}
ByteBuffer ByteBuffer::Concat(const ByteBuffer& a, const ByteBuffer& b) {
// We assume compiler implements NRVO here. We avoid initializing
// return_value via a.Copy() because reserve() may result in another
// data copy, which we are trying to eliminate in the first place.
ByteBuffer return_value;
return_value.data_.reserve(a.size() + b.size()); // harmless on overflow
return_value.data_.insert(return_value.data_.end(), a.data_.begin(),
a.data_.end());
return_value.data_.insert(return_value.data_.end(), b.data_.begin(),
b.data_.end());
return return_value;
}
// GCC before 4.7 doesn't support delegated constructors, so we can't be as
// elegant as we could otherwise.
ByteBuffer::ByteBuffer(const uint8_t* source_data, const size_t length) {
SetData(source_data, length);
}
ByteBuffer::ByteBuffer(const char* source_data) {
SetData(reinterpret_cast<const uint8_t*>(source_data), strlen(source_data));
}
ByteBuffer::ByteBuffer(const char* source_data, const size_t length) {
SetData(reinterpret_cast<const uint8_t*>(source_data), length);
}
ByteBuffer::ByteBuffer(const string& source_data) {
SetData(reinterpret_cast<const uint8_t*>(source_data.c_str()),
source_data.length());
}
size_t ByteBuffer::size() const { return data_.size(); }
std::unique_ptr<ByteBuffer> ByteBuffer::SubArray(const size_t offset,
const size_t length) const {
if (length == 0) {
return std::unique_ptr<ByteBuffer>(new ByteBuffer());
}
// Overflow check
if (length > UINT_MAX - offset) {
return nullptr;
}
// Bounds check
if (offset + length > size()) {
return nullptr;
}
return std::unique_ptr<ByteBuffer>(
new ByteBuffer(ImmutableUChar() + offset, length));
}
unsigned char* ByteBuffer::MutableUChar() {
return reinterpret_cast<unsigned char*>(MutableUInt8());
}
unsigned const char* ByteBuffer::ImmutableUChar() const {
return reinterpret_cast<unsigned const char*>(data_.data());
}
uint8_t* ByteBuffer::MutableUInt8() { return data_.data(); }
const uint8_t* ByteBuffer::ImmutableUInt8() const {
return reinterpret_cast<const uint8_t*>(data_.data());
}
string ByteBuffer::String() const {
return string(reinterpret_cast<const char*>(data_.data()), data_.size());
}
vector<uint8_t> ByteBuffer::Vector() const { return vector<uint8_t>(data_); }
bool ByteBuffer::Equals(const ByteBuffer& other) const {
if (other.size() != size()) {
return false;
}
// Make sure to always iterate over all elements to defeat timing attacks
unsigned int result = 0;
for (size_t i = 0; i < size(); i++) {
result |= data_[i] ^ other.ImmutableUInt8()[i];
}
return (result == 0);
}
string ByteBuffer::AsDebugHexString() const {
if (data_.size() == 0) {
return string();
}
const char hex[] = "0123456789abcdef";
string result = string("0x");
for (size_t i = 0; i < data_.size(); i++) {
result.push_back(hex[0xf & (data_[i] >> 4)]);
result.push_back(hex[0xf & data_[i]]);
}
return result;
}
void ByteBuffer::Clear() {
Wipe();
data_.clear();
}
void ByteBuffer::Wipe() { WipeBuffer(data_.data(), data_.size()); }
void ByteBuffer::WipeBuffer(uint8_t* buffer, const size_t length) {
volatile uint8_t* byte_to_wipe = buffer;
for (size_t i = 0; i < length; i++) {
byte_to_wipe[i] = 0;
}
}
} // namespace securemessage