Add KBOOT.

This commit is contained in:
László Monda
2016-08-10 01:45:15 +02:00
commit e6c1fce5b4
9392 changed files with 3751375 additions and 0 deletions

View File

@@ -0,0 +1,147 @@
/*
* File: AESCounter.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_AESCounter_h_)
#define _AESCounter_h_
#include <string.h>
#include <iostream>
#include "Random.h"
//! An AES-128 counter is 128 bits, or 16 bytes.
typedef uint8_t aes128_counter_t[16];
/*!
* \brief Base class for AESCounter<S>.
*
* This class implements some bigger, non-template methods used in the
* AESCounter<S> templated subclass.
*/
class AESCounterBase
{
public:
//! \brief Reads hex encoded data from \a stream.
void _readFromStream(std::istream &stream, unsigned bytes, uint8_t *buffer);
//! \brief Writes hex encoded data to \a stream.
void _writeToStream(std::ostream &stream, unsigned bytes, const uint8_t *buffer) const;
};
/*!
* \brief Generic AES Counter class.
*
* The template parameter \a S is the number of bits in the counter.
*
* The underlying counter type can be accessed like this: AESCounter<128>::counter_t
*
* When a counter instance is destroyed, it erases the counter data by setting it
* to all zeroes.
*
* \todo Add a way to allow only counter sizes of 128, 192, and 256 bits.
* \todo Find a cross platform way to prevent the counter data from being written
* to the VM swapfile.
*
* AESCounter<128> counter = AESCounter<128>::readFromStream(s);
*/
template <int S>
class AESCounter : public AESCounterBase
{
public:
//! Type for this size of AES counter.
typedef uint8_t counter_t[S / 8];
public:
//! \brief Default constructor.
//!
//! Initializes the counter to 0.
AESCounter() { memset(m_counter, 0, sizeof(m_counter)); }
//! \brief Constructor taking a counter value reference.
AESCounter(const counter_t &counter) { memcpy(m_counter, &counter, sizeof(m_counter)); }
// \brief Constructor taking a counter value pointer.
AESCounter(const counter_t *counter) { memcpy(m_counter, counter, sizeof(m_counter)); }
//! \brief Constructor, reads counter from stream in hex format.
AESCounter(std::istream &stream) { readFromStream(stream); }
//! \brief Copy constructor.
AESCounter(const AESCounter<S> &other) { memcpy(m_counter, other.m_counter, sizeof(m_counter)); }
//! \brief Destructor.
//!
//! Sets the counter value to zero.
~AESCounter() { memset(m_counter, 0, sizeof(m_counter)); }
//! \brief Set to the counter to a randomly generated value.
void randomize()
{
RandomNumberGenerator rng;
rng.generateBlock(m_counter, sizeof(m_counter));
}
//! \brief Reads the counter from a hex encoded data stream.
void readFromStream(std::istream &stream)
{
_readFromStream(stream, S / 8, reinterpret_cast<uint8_t *>(&m_counter));
}
//! \brief Writes the counter to a data stream in hex encoded format.
void writeToStream(std::ostream &stream) const
{
_writeToStream(stream, S / 8, reinterpret_cast<const uint8_t *>(&m_counter));
}
//! \brief Increments the counter by val
void incrementCounter(unsigned val)
{
for (unsigned j = 0; j < val; j++)
{
for (unsigned i = sizeof(AESCounter<S>::counter_t) - 1, carry = 1; (i >= 0) && carry; i--)
{
carry = !++m_counter[i];
}
}
}
//! \name Counter accessors
//@{
inline const counter_t &getCounter() const { return m_counter; }
inline void getCounter(counter_t *counter) const { memcpy(counter, m_counter, sizeof(m_counter)); }
inline void setCounter(const counter_t &counter) { memcpy(m_counter, &counter, sizeof(m_counter)); }
inline void setCounter(const counter_t *counter) { memcpy(m_counter, counter, sizeof(m_counter)); }
inline void setCounter(const AESCounter<S> &counter) { memcpy(m_counter, counter.m_counter, sizeof(m_counter)); }
//@}
//! \name Operators
//@{
const AESCounter<S> &operator=(const AESCounter<S> &counter)
{
setCounter(counter);
return *this;
}
const AESCounter<S> &operator=(const counter_t &counter)
{
setCounter(counter);
return *this;
}
const AESCounter<S> &operator=(const counter_t *counter)
{
setCounter(counter);
return *this;
}
operator const counter_t &() const { return m_counter; }
operator const counter_t *() const { return m_counter; }
friend std::ostream &operator<<(std::ostream &os, const AESCounter<S> &counter)
{
counter.writeToStream(os);
return os;
}
//@}
protected:
counter_t m_counter; //!< The counter value.
};
//! Standard type definition for an AES-128 counter.
typedef AESCounter<128> AES128Counter;
#endif // _AESCounter_h_

View File

@@ -0,0 +1,76 @@
/*
* File: AESKey.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "AESKey.h"
#include <stdexcept>
#include "smart_ptr.h"
#include "HexValues.h"
#include <ctype.h>
//! The data from the stream is expected to be hex encoded. Each two characters
//! from the stream encode a single result byte. All non-hexadecimal characters
//! are ignored, including newlines. Every two hexadecimal characters form
//! an encoded byte. This is true even if the two characters representing the
//! upper and lower nibbles are separated by whitespace or other characters.
//!
//! \post The stream read head is left pointing just after the last encoded byte.
//!
//! \param stream Input stream to read from.
//! \param bytes Number of encoded bytes to read. This is the number of \e
//! result bytes, not the count of bytes to read from the stream.
//! \param[out] buffer Pointer to the buffer where decoded data is written.
//!
//! \exception std::runtime_error This exception will be thrown if less
//! data than required is available from \a stream, or if some other
//! error occurs while reading from \a stream.
void AESKeyBase::_readFromStream(std::istream &stream, unsigned bytes, uint8_t *buffer)
{
char temp[2];
char c;
char n = 0;
while (bytes)
{
if (stream.get(c).fail())
{
throw std::runtime_error("not enough data in stream");
}
if (isHexDigit(c))
{
temp[n++] = c;
if (n == 2)
{
*buffer++ = hexByteToInt(temp);
bytes--;
n = 0;
}
}
}
}
//! Key data is written to \a stream as a sequence of hex encoded octets, each two
//! characters long. No spaces or newlines are inserted between the encoded octets
//! or at the end of the sequence.
//!
//! \exception std::runtime_error Thrown if the \a stream reports an error while
//! writing the key data.
void AESKeyBase::_writeToStream(std::ostream &stream, unsigned bytes, const uint8_t *buffer)
{
const char hexChars[] = "0123456789ABCDEF";
while (bytes--)
{
uint8_t thisByte = *buffer++;
char byteString[2];
byteString[0] = hexChars[(thisByte & 0xf0) >> 4];
byteString[1] = hexChars[thisByte & 0x0f];
if (stream.write(byteString, 2).bad())
{
throw std::runtime_error("error while writing to stream");
}
}
}

View File

@@ -0,0 +1,123 @@
/*
* File: AESKey.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_AESKey_h_)
#define _AESKey_h_
#include "stdafx.h"
#include <string.h>
#include <iostream>
#include "Random.h"
//! An AES-128 key is 128 bits, or 16 bytes.
typedef uint8_t aes128_key_t[16];
/*!
* \brief Base class for AESKey<S>.
*
* This class implements some bigger, non-template methods used in the
* AESKey<S> templated subclass.
*/
class AESKeyBase
{
public:
//! \brief Reads hex encoded data from \a stream.
void _readFromStream(std::istream &stream, unsigned bytes, uint8_t *buffer);
//! \brief Writes hex encoded data to \a stream.
void _writeToStream(std::ostream &stream, unsigned bytes, const uint8_t *buffer);
};
/*!
* \brief Generic AES key class.
*
* The template parameter \a S is the number of bits in the key.
*
* The underlying key type can be accessed like this: AESKey<128>::key_t
*
* When a key instance is destroyed, it erases the key data by setting it
* to all zeroes.
*
* \todo Add a way to allow only key sizes of 128, 192, and 256 bits.
* \todo Find a cross platform way to prevent the key data from being written
* to the VM swapfile.
*
* AESKey<128> key = AESKey<128>::readFromStream(s);
*/
template <int S>
class AESKey : public AESKeyBase
{
public:
//! Type for this size of AES key.
typedef uint8_t key_t[S / 8];
public:
//! \brief Default constructor.
//!
//! Initializes the key to 0.
AESKey() { memset(m_key, 0, sizeof(m_key)); }
//! \brief Constructor taking a key value reference.
AESKey(const key_t &key) { memcpy(m_key, &key, sizeof(m_key)); }
// \brief Constructor taking a key value pointer.
AESKey(const key_t *key) { memcpy(m_key, key, sizeof(m_key)); }
//! \brief Constructor, reads key from stream in hex format.
AESKey(std::istream &stream) { readFromStream(stream); }
//! \brief Copy constructor.
AESKey(const AESKey<S> &other) { memcpy(m_key, other.m_key, sizeof(m_key)); }
//! \brief Destructor.
//!
//! Sets the key value to zero.
~AESKey() { memset(m_key, 0, sizeof(m_key)); }
//! \brief Set to the key to a randomly generated value.
void randomize()
{
RandomNumberGenerator rng;
rng.generateBlock(m_key, sizeof(m_key));
}
//! \brief Reads the key from a hex encoded data stream.
void readFromStream(std::istream &stream) { _readFromStream(stream, S / 8, reinterpret_cast<uint8_t *>(&m_key)); }
//! \brief Writes the key to a data stream in hex encoded format.
void writeToStream(std::ostream &stream) { _writeToStream(stream, S / 8, reinterpret_cast<uint8_t *>(&m_key)); }
//! \name Key accessors
//@{
inline const key_t &getKey() const { return m_key; }
inline void getKey(key_t *key) const { memcpy(key, m_key, sizeof(m_key)); }
inline void setKey(const key_t &key) { memcpy(m_key, &key, sizeof(m_key)); }
inline void setKey(const key_t *key) { memcpy(m_key, key, sizeof(m_key)); }
inline void setKey(const AESKey<S> &key) { memcpy(m_key, key.m_key, sizeof(m_key)); }
//@}
//! \name Operators
//@{
const AESKey<S> &operator=(const AESKey<S> &key)
{
setKey(key);
return *this;
}
const AESKey<S> &operator=(const key_t &key)
{
setKey(key);
return *this;
}
const AESKey<S> &operator=(const key_t *key)
{
setKey(key);
return *this;
}
operator const key_t &() const { return m_key; }
operator const key_t *() const { return m_key; }
//@}
protected:
key_t m_key; //!< The key value.
};
//! Standard type definition for an AES-128 key.
typedef AESKey<128> AES128Key;
#endif // _AESKey_h_

View File

@@ -0,0 +1,122 @@
/*
* File: Blob.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "Blob.h"
#include <stdexcept>
#include <stdlib.h>
#include <string.h>
Blob::Blob()
: m_data(0)
, m_length(0)
{
}
//! Makes a local copy of the \a data argument.
//!
Blob::Blob(const uint8_t *data, unsigned length)
: m_data(0)
, m_length(length)
{
m_data = reinterpret_cast<uint8_t *>(malloc(length));
memcpy(m_data, data, length);
}
//! Makes a local copy of the data owned by \a other.
//!
Blob::Blob(const Blob &other)
: m_data(0)
, m_length(other.m_length)
{
m_data = reinterpret_cast<uint8_t *>(malloc(m_length));
memcpy(m_data, other.m_data, m_length);
}
//! Disposes of the binary data associated with this object.
Blob::~Blob()
{
if (m_data)
{
free(m_data);
}
}
//! Copies \a data onto the blob's data. The blob does not assume ownership
//! of \a data.
//!
//! \param data Pointer to a buffer containing the data which will be copied
//! into the blob.
//! \param length Number of bytes pointed to by \a data.
void Blob::setData(const uint8_t *data, unsigned length)
{
setLength(length);
memcpy(m_data, data, length);
}
//! Sets the #m_length member variable to \a length and resizes #m_data to
//! the new length. The contents of #m_data past any previous contents are undefined.
//! If the new \a length is 0 then the data will be freed and a subsequent call
//! to getData() will return NULL.
//!
//! \param length New length of the blob's data in bytes.
void Blob::setLength(unsigned length)
{
if (length == 0)
{
clear();
return;
}
// Allocate new block.
if (!m_data)
{
m_data = reinterpret_cast<uint8_t *>(malloc(length));
if (!m_data)
{
throw std::runtime_error("failed to allocate memory");
}
}
// Reallocate previous block.
else
{
void *newBlob = realloc(m_data, length);
if (!newBlob)
{
throw std::runtime_error("failed to reallocate memory");
}
m_data = reinterpret_cast<uint8_t *>(newBlob);
}
// Set length.
m_length = length;
}
void Blob::append(const uint8_t *newData, unsigned newDataLength)
{
unsigned oldLength = m_length;
setLength(m_length + newDataLength);
memcpy(m_data + oldLength, newData, newDataLength);
}
void Blob::clear()
{
if (m_data)
{
free(m_data);
m_data = NULL;
}
m_length = 0;
}
void Blob::relinquish()
{
m_data = NULL;
m_length = 0;
}

View File

@@ -0,0 +1,69 @@
/*
* File: Blob.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_Blob_h_)
#define _Blob_h_
#include "stdafx.h"
/*!
* \brief Manages a binary object of arbitrary length.
*
* The data block is allocated with malloc() instead of the new
* operator so that we can use realloc() to resize it.
*/
class Blob
{
public:
//! \brief Default constructor.
Blob();
//! \brief Constructor.
Blob(const uint8_t *data, unsigned length);
//! \brief Copy constructor.
Blob(const Blob &other);
//! \brief Destructor.
virtual ~Blob();
//! \name Operations
//@{
//! \brief Replaces the blob's data.
void setData(const uint8_t *data, unsigned length);
//! \brief Change the size of the blob's data.
void setLength(unsigned length);
//! \brief Adds data to the end of the blob.
void append(const uint8_t *newData, unsigned newDataLength);
//! \brief Disposes of the data.
void clear();
//! \brief Tell the blob that it no longer owns its data.
void relinquish();
//@}
//! \name Accessors
//@{
uint8_t *getData() { return m_data; }
const uint8_t *getData() const { return m_data; }
unsigned getLength() const { return m_length; }
//@}
//! \name Operators
//@{
operator uint8_t *() { return m_data; }
operator const uint8_t *() const { return m_data; }
//@}
protected:
uint8_t *m_data; //!< The binary data held by this object.
unsigned m_length; //!< Number of bytes pointed to by #m_data.
};
#endif // _Blob_h_

View File

@@ -0,0 +1,50 @@
/*
* File: BootImage.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_BootImage_h_)
#define _BootImage_h_
#include <iostream>
#include "Version.h"
namespace elftosb
{
/*!
* \brief Abstract base class for all boot image format classes.
*
* Provides virtual methods for all of the common features between different
* boot image formats. These are the product and component version numbers
* and the drive tag.
*
* Also provided is the virtual method writeToStream() that lets the caller
* stream out the boot image without knowing the underlying format type.
*/
class BootImage
{
public:
//! \brief Constructor.
BootImage() {}
//! \brief Destructor.
virtual ~BootImage() {}
//! \name Versions
//@{
virtual void setProductVersion(const version_t &version) = 0;
virtual void setComponentVersion(const version_t &version) = 0;
//@}
//! \brief Specify the drive tag to be set in the output file header.
virtual void setDriveTag(uint16_t tag) = 0;
//! \brief Returns a string containing the preferred file extension for image format.
virtual std::string getFileExtension() const = 0;
//! \brief Write the boot image to an output stream.
virtual void writeToStream(std::ostream &stream) = 0;
};
}; // namespace elftosb
#endif // _BootImage_h_

View File

@@ -0,0 +1,244 @@
/*
* File: DataSource.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "DataSource.h"
#include "DataTarget.h"
#include <assert.h>
#include <string.h>
#include <algorithm>
using namespace elftosb;
#pragma mark *** DataSource::PatternSegment ***
DataSource::PatternSegment::PatternSegment(DataSource &source)
: DataSource::Segment(source)
, m_pattern()
{
}
DataSource::PatternSegment::PatternSegment(DataSource &source, const SizedIntegerValue &pattern)
: DataSource::Segment(source)
, m_pattern(pattern)
{
}
DataSource::PatternSegment::PatternSegment(DataSource &source, uint8_t pattern)
: DataSource::Segment(source)
, m_pattern(static_cast<uint8_t>(pattern))
{
}
DataSource::PatternSegment::PatternSegment(DataSource &source, uint16_t pattern)
: DataSource::Segment(source)
, m_pattern(static_cast<uint16_t>(pattern))
{
}
DataSource::PatternSegment::PatternSegment(DataSource &source, uint32_t pattern)
: DataSource::Segment(source)
, m_pattern(static_cast<uint32_t>(pattern))
{
}
unsigned DataSource::PatternSegment::getData(unsigned offset, unsigned maxBytes, uint8_t *buffer)
{
memset(buffer, 0, maxBytes);
return maxBytes;
}
//! The pattern segment's length is a function of the data target. If the
//! target is bounded, then the segment's length is simply the target's
//! length. Otherwise, if no target has been set or the target is unbounded,
//! then the length returned is 0.
unsigned DataSource::PatternSegment::getLength()
{
DataTarget *target = m_source.getTarget();
if (!target)
{
return 0;
}
uint32_t length;
if (target->isBounded())
{
length = target->getEndAddress() - target->getBeginAddress();
}
else
{
length = m_pattern.getSize();
}
return length;
}
#pragma mark *** PatternSource ***
PatternSource::PatternSource()
: DataSource()
, DataSource::PatternSegment((DataSource &)*this)
{
}
PatternSource::PatternSource(const SizedIntegerValue &value)
: DataSource()
, DataSource::PatternSegment((DataSource &)*this, value)
{
}
#pragma mark *** UnmappedDataSource ***
UnmappedDataSource::UnmappedDataSource()
: DataSource()
, DataSource::Segment((DataSource &)*this)
, m_data()
, m_length(0)
{
}
UnmappedDataSource::UnmappedDataSource(const uint8_t *data, unsigned length)
: DataSource()
, DataSource::Segment((DataSource &)*this)
, m_data()
, m_length(0)
{
setData(data, length);
}
//! Makes a copy of \a data that is freed when the data source is
//! destroyed. The caller does not have to maintain \a data after this call
//! returns.
void UnmappedDataSource::setData(const uint8_t *data, unsigned length)
{
m_data.safe_delete();
uint8_t *dataCopy = new uint8_t[length];
memcpy(dataCopy, data, length);
m_data = dataCopy;
m_length = length;
}
unsigned UnmappedDataSource::getData(unsigned offset, unsigned maxBytes, uint8_t *buffer)
{
assert(offset < m_length);
unsigned copyBytes = std::min<unsigned>(m_length - offset, maxBytes);
memcpy(buffer, m_data.get(), copyBytes);
return copyBytes;
}
#pragma mark *** MemoryImageDataSource ***
MemoryImageDataSource::MemoryImageDataSource(StExecutableImage *image)
: DataSource()
, m_image(image)
{
// reserve enough room for all segments
m_segments.reserve(m_image->getRegionCount());
}
MemoryImageDataSource::~MemoryImageDataSource()
{
segment_array_t::iterator it = m_segments.begin();
for (; it != m_segments.end(); ++it)
{
// delete this segment if it has been created
if (*it)
{
delete *it;
}
}
}
unsigned MemoryImageDataSource::getSegmentCount()
{
return m_image->getRegionCount();
}
DataSource::Segment *MemoryImageDataSource::getSegmentAt(unsigned index)
{
// return previously created segment
if (index < m_segments.size() && m_segments[index])
{
return m_segments[index];
}
// extend array out to this index
if (index >= m_segments.size() && index < m_image->getRegionCount())
{
m_segments.resize(index + 1, NULL);
}
// create the new segment object
DataSource::Segment *newSegment;
const StExecutableImage::MemoryRegion &region = m_image->getRegionAtIndex(index);
if (region.m_type == StExecutableImage::TEXT_REGION)
{
newSegment = new TextSegment(*this, m_image, index);
}
else if (region.m_type == StExecutableImage::FILL_REGION)
{
newSegment = new FillSegment(*this, m_image, index);
}
m_segments[index] = newSegment;
return newSegment;
}
#pragma mark *** MemoryImageDataSource::TextSegment ***
MemoryImageDataSource::TextSegment::TextSegment(MemoryImageDataSource &source, StExecutableImage *image, unsigned index)
: DataSource::Segment(source)
, m_image(image)
, m_index(index)
{
}
unsigned MemoryImageDataSource::TextSegment::getData(unsigned offset, unsigned maxBytes, uint8_t *buffer)
{
const StExecutableImage::MemoryRegion &region = m_image->getRegionAtIndex(m_index);
assert(region.m_type == StExecutableImage::TEXT_REGION);
unsigned copyBytes = std::min<unsigned>(region.m_length - offset, maxBytes);
memcpy(buffer, &region.m_data[offset], copyBytes);
return copyBytes;
}
unsigned MemoryImageDataSource::TextSegment::getLength()
{
const StExecutableImage::MemoryRegion &region = m_image->getRegionAtIndex(m_index);
return region.m_length;
}
uint32_t MemoryImageDataSource::TextSegment::getBaseAddress()
{
const StExecutableImage::MemoryRegion &region = m_image->getRegionAtIndex(m_index);
return region.m_address;
}
#pragma mark *** MemoryImageDataSource::FillSegment ***
MemoryImageDataSource::FillSegment::FillSegment(MemoryImageDataSource &source, StExecutableImage *image, unsigned index)
: DataSource::PatternSegment(source)
, m_image(image)
, m_index(index)
{
SizedIntegerValue zero(0, kWordSize);
setPattern(zero);
}
unsigned MemoryImageDataSource::FillSegment::getLength()
{
const StExecutableImage::MemoryRegion &region = m_image->getRegionAtIndex(m_index);
return region.m_length;
}
uint32_t MemoryImageDataSource::FillSegment::getBaseAddress()
{
const StExecutableImage::MemoryRegion &region = m_image->getRegionAtIndex(m_index);
return region.m_address;
}

View File

@@ -0,0 +1,300 @@
/*
* File: DataSource.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_DataSource_h_)
#define _DataSource_h_
#include <vector>
#include "Value.h"
#include "smart_ptr.h"
#include "StExecutableImage.h"
namespace elftosb
{
// Forward declaration
class DataTarget;
/*!
* \brief Abstract base class for data sources.
*
* Data sources represent any sort of data that can be placed or loaded
* into a target region. Sources may be a single blob of data read from
* a file or may consist of many segments.
*
* The three most important features of data sources are:
* - Sources may be multi-segmented.
* - Sources and/or segments can have a "natural" or default target location.
* - The target for a source may be taken into consideration when the source
* describes itself.
*/
class DataSource
{
public:
/*!
* \brief Discrete, contiguous part of the source's data.
*
* This class is purely abstract and subclasses of DataSource are expected
* to subclass it to implement a segment particular to their needs.
*/
class Segment
{
public:
//! \brief Default constructor.
Segment(DataSource &source)
: m_source(source)
{
}
//! \brief Destructor.
virtual ~Segment() {}
//! \brief Gets all or a portion of the segment's data.
//!
//! The data is copied into \a buffer. Up to \a maxBytes bytes may be
//! copied, so \a buffer must be at least that large.
//!
//! \param offset Index of the first byte to start copying from.
//! \param maxBytes The maximum number of bytes that can be returned. \a buffer
//! must be at least this large.
//! \param buffer Pointer to buffer where the data is copied.
//! \return The number of bytes copied into \a buffer.
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer) = 0;
//! \brief Gets the length of the segment's data.
virtual unsigned getLength() = 0;
//! \brief Returns whether the segment has an associated address.
virtual bool hasNaturalLocation() = 0;
//! \brief Returns the address associated with the segment.
virtual uint32_t getBaseAddress() { return 0; }
protected:
DataSource &m_source; //!< The data source to which this segment belongs.
};
/*!
* \brief This is a special type of segment containing a repeating pattern.
*
* By default the segment doesn't have a specific length or data. The length depends
* on the target's address range. And the data is just the pattern, repeated
* many times. In addition, pattern segments do not have a natural location.
*
* Calling code should look for instances of PatternSegment and handle them
* as special cases that can be optimized.
*/
class PatternSegment : public Segment
{
public:
//! \brief Default constructor.
PatternSegment(DataSource &source);
//! \brief Constructor taking a fill pattern.
PatternSegment(DataSource &source, const SizedIntegerValue &pattern);
//! \brief Constructor taking a byte fill pattern.
PatternSegment(DataSource &source, uint8_t pattern);
//! \brief Constructor taking a half-word fill pattern.
PatternSegment(DataSource &source, uint16_t pattern);
//! \brief Constructor taking a word fill pattern.
PatternSegment(DataSource &source, uint32_t pattern);
//! \name Segment methods
//@{
//! \brief Pattern segments have no natural address.
virtual bool hasNaturalLocation() { return false; }
//! \brief Performs a pattern fill into the \a buffer.
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer);
//! \brief Returns a length based on the data target's address range.
virtual unsigned getLength();
//@}
//! \name Pattern accessors
//@{
//! \brief Assigns a new fill pattern.
inline void setPattern(const SizedIntegerValue &newPattern) { m_pattern = newPattern; }
//! \brief Return the fill pattern for the segment.
inline SizedIntegerValue &getPattern() { return m_pattern; }
//! \brief Assignment operator, sets the pattern value and length.
PatternSegment &operator=(const SizedIntegerValue &value)
{
m_pattern = value;
return *this;
}
//@}
protected:
SizedIntegerValue m_pattern; //!< The fill pattern.
};
public:
//! \brief Default constructor.
DataSource()
: m_target(0)
{
}
//! \brief Destructor.
virtual ~DataSource() {}
//! \name Data target
//@{
//! \brief Sets the associated data target.
inline void setTarget(DataTarget *target) { m_target = target; }
//! \brief Gets the associated data target.
inline DataTarget *getTarget() const { return m_target; }
//@}
//! \name Segments
//@{
//! \brief Returns the number of segments in this data source.
virtual unsigned getSegmentCount() = 0;
//! \brief Returns segment number \a index of the data source.
virtual Segment *getSegmentAt(unsigned index) = 0;
//@}
protected:
DataTarget *m_target; //!< Corresponding target for this source.
};
/*!
* \brief Data source for a repeating pattern.
*
* The pattern is represented by a SizedIntegerValue object. Thus the pattern
* can be either byte, half-word, or word sized.
*
* This data source has only one segment, and the PatternSource instance acts
* as its own single segment.
*/
class PatternSource : public DataSource, public DataSource::PatternSegment
{
public:
//! \brief Default constructor.
PatternSource();
//! \brief Constructor taking the pattern value.
PatternSource(const SizedIntegerValue &value);
//! \brief There is only one segment.
virtual unsigned getSegmentCount() { return 1; }
//! \brief Returns this object, as it is its own segment.
virtual DataSource::Segment *getSegmentAt(unsigned index) { return this; }
//! \brief Assignment operator, sets the pattern value and length.
PatternSource &operator=(const SizedIntegerValue &value)
{
setPattern(value);
return *this;
}
};
/*!
* \brief Data source for data that is not memory mapped (has no natural address).
*
* This data source can only manage a single block of data, which has no
* associated address. It acts as its own Segment.
*/
class UnmappedDataSource : public DataSource, public DataSource::Segment
{
public:
//! \brief Default constructor.
UnmappedDataSource();
//! \brief Constructor taking the data, which is copied.
UnmappedDataSource(const uint8_t *data, unsigned length);
//! \brief Sets the source's data.
void setData(const uint8_t *data, unsigned length);
//! \brief There is only one segment.
virtual unsigned getSegmentCount() { return 1; }
//! \brief Returns this object, as it is its own segment.
virtual DataSource::Segment *getSegmentAt(unsigned index) { return this; }
//! \name Segment methods
//@{
//! \brief Unmapped data sources have no natural address.
virtual bool hasNaturalLocation() { return false; }
//! \brief Copies a portion of the data into \a buffer.
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer);
//! \brief Returns the number of bytes of data managed by the source.
virtual unsigned getLength() { return m_length; }
//@}
protected:
smart_array_ptr<uint8_t> m_data; //!< The data.
unsigned m_length; //!< Byte count of the data.
};
/*!
* \brief Data source that takes its data from an executable image.
*
* \see StExecutableImage
*/
class MemoryImageDataSource : public DataSource
{
public:
//! \brief Default constructor.
MemoryImageDataSource(StExecutableImage *image);
//! \brief Destructor.
virtual ~MemoryImageDataSource();
//! \brief Returns the number of memory regions in the image.
virtual unsigned getSegmentCount();
//! \brief Returns the data source segment at position \a index.
virtual DataSource::Segment *getSegmentAt(unsigned index);
protected:
/*!
* \brief Segment corresponding to a text region of the executable image.
*/
class TextSegment : public DataSource::Segment
{
public:
//! \brief Default constructor
TextSegment(MemoryImageDataSource &source, StExecutableImage *image, unsigned index);
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer);
virtual unsigned getLength();
virtual bool hasNaturalLocation() { return true; }
virtual uint32_t getBaseAddress();
protected:
StExecutableImage *m_image; //!< Coalesced image of the file.
unsigned m_index; //!< Record index.
};
/*!
* \brief Segment corresponding to a fill region of the executable image.
*/
class FillSegment : public DataSource::PatternSegment
{
public:
FillSegment(MemoryImageDataSource &source, StExecutableImage *image, unsigned index);
virtual unsigned getLength();
virtual bool hasNaturalLocation() { return true; }
virtual uint32_t getBaseAddress();
protected:
StExecutableImage *m_image; //!< Coalesced image of the file.
unsigned m_index; //!< Record index.
};
protected:
StExecutableImage *m_image; //!< The memory image that is the data source.
typedef std::vector<DataSource::Segment *> segment_array_t; //!< An array of segments.
segment_array_t m_segments; //!< The array of Segment instances.
};
}; // namespace elftosb
#endif // _DataSource_h_

View File

@@ -0,0 +1,142 @@
/*
* File: DataSourceImager.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "DataSourceImager.h"
#include <stdlib.h>
#include <string.h>
using namespace elftosb;
DataSourceImager::DataSourceImager()
: Blob()
, m_fill(0)
, m_baseAddress(0)
, m_isBaseAddressSet(false)
{
}
void DataSourceImager::setBaseAddress(uint32_t address)
{
m_baseAddress = address;
m_isBaseAddressSet = true;
}
void DataSourceImager::setFillPattern(uint8_t pattern)
{
m_fill = pattern;
}
void DataSourceImager::reset()
{
clear();
m_fill = 0;
m_baseAddress = 0;
m_isBaseAddressSet = false;
}
//! \param dataSource Pointer to an instance of a concrete data source subclass.
//!
void DataSourceImager::addDataSource(DataSource *source)
{
unsigned segmentCount = source->getSegmentCount();
unsigned index = 0;
for (; index < segmentCount; ++index)
{
addDataSegment(source->getSegmentAt(index));
}
}
//! \param segment The segment to add. May be any type of data segment, including
//! a pattern segment.
void DataSourceImager::addDataSegment(DataSource::Segment *segment)
{
DataSource::PatternSegment *patternSegment = dynamic_cast<DataSource::PatternSegment *>(segment);
unsigned segmentLength = segment->getLength();
bool segmentHasLocation = segment->hasNaturalLocation();
uint32_t segmentAddress = segment->getBaseAddress();
uint8_t *toPtr = NULL;
unsigned addressDelta;
unsigned newLength;
// If a pattern segment's length is 0 then make it as big as the fill pattern.
// This needs to be done before the buffer is adjusted.
if (patternSegment && segmentLength == 0)
{
SizedIntegerValue &pattern = patternSegment->getPattern();
segmentLength = pattern.getSize();
}
if (segmentLength)
{
if (segmentHasLocation)
{
// Make sure a base address is set.
if (!m_isBaseAddressSet)
{
m_baseAddress = segmentAddress;
m_isBaseAddressSet = true;
}
// The segment is located before our buffer's first address.
// toPtr is not set in this if, but in the else branch of the next if.
// Unless the segment completely overwrite the current data.
if (segmentAddress < m_baseAddress)
{
addressDelta = m_baseAddress - segmentAddress;
uint8_t *newData = (uint8_t *)malloc(m_length + addressDelta);
memcpy(&newData[addressDelta], m_data, m_length);
free(m_data);
m_data = newData;
m_length += addressDelta;
m_baseAddress = segmentAddress;
}
// This segment is located or extends outside of our buffer.
if (segmentAddress + segmentLength > m_baseAddress + m_length)
{
newLength = segmentAddress + segmentLength - m_baseAddress;
m_data = (uint8_t *)realloc(m_data, newLength);
// Clear any bytes between the old data and the new segment.
addressDelta = segmentAddress - (m_baseAddress + m_length);
if (addressDelta)
{
memset(m_data + m_length, 0, addressDelta);
}
toPtr = m_data + (segmentAddress - m_baseAddress);
m_length = newLength;
}
else
{
toPtr = m_data + (segmentAddress - m_baseAddress);
}
}
// Segment has no natural location, so just append it to the end of our buffer.
else
{
newLength = m_length + segmentLength;
m_data = (uint8_t *)realloc(m_data, newLength);
toPtr = m_data + m_length;
m_length = newLength;
}
}
// A loop is used because getData() may fill in less than the requested
// number of bytes per call.
unsigned offset = 0;
while (offset < segmentLength)
{
offset += segment->getData(offset, segmentLength - offset, toPtr + offset);
}
}

View File

@@ -0,0 +1,53 @@
/*
* File: DataSourceImager.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_DataSourceImager_h_)
#define _DataSourceImager_h_
#include "Blob.h"
#include "DataSource.h"
namespace elftosb
{
/*!
* \brief Converts a DataSource into a single binary buffer.
*/
class DataSourceImager : public Blob
{
public:
//! \brief Constructor.
DataSourceImager();
//! \name Setup
//@{
void setBaseAddress(uint32_t address);
void setFillPattern(uint8_t pattern);
//@}
void reset();
//! \name Accessors
//@{
uint32_t getBaseAddress() { return m_baseAddress; }
//@}
//! \name Operations
//@{
//! \brief Adds all of the segments of which \a dataSource is composed.
void addDataSource(DataSource *source);
//! \brief Adds the data from one data segment.
void addDataSegment(DataSource::Segment *segment);
//@}
protected:
uint8_t m_fill;
uint32_t m_baseAddress;
bool m_isBaseAddressSet;
};
};
#endif // _DataSourceImager_h_

View File

@@ -0,0 +1,64 @@
/*
* File: DataTarget.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "DataTarget.h"
#include "DataSource.h"
#include "ElftosbErrors.h"
#include <algorithm>
using namespace elftosb;
//! \exception elftosb::semantic_error Thrown if the source has multiple segments.
DataTarget::AddressRange ConstantDataTarget::getRangeForSegment(DataSource &source, DataSource::Segment &segment)
{
// can't handle multi-segment data sources
if (source.getSegmentCount() > 1)
{
throw semantic_error("constant targets only support single-segment sources");
}
// always relocate the segment to our begin address
AddressRange range;
range.m_begin = m_begin;
if (isBounded())
{
// we have an end address. trim the result range to the segment size
// or let the end address crop the segment.
uint64_t sourceBasedEnd = static_cast<uint64_t>(m_begin) + static_cast<uint64_t>(segment.getLength());
if (sourceBasedEnd > ULONG_MAX)
{
sourceBasedEnd = ULONG_MAX;
}
range.m_end = std::min<uint32_t>(m_end, static_cast<uint32_t>(sourceBasedEnd));
}
else
{
// we have no end address, so the segment size determines it.
range.m_end = m_begin + segment.getLength();
}
return range;
}
//! If the \a segment has a natural location, the returned address range extends
//! from the segment's base address to its base address plus its length.
//!
//! \exception elftosb::semantic_error This exception is thrown if the \a segment
//! does not have a natural location associated with it.
DataTarget::AddressRange NaturalDataTarget::getRangeForSegment(DataSource &source, DataSource::Segment &segment)
{
if (!segment.hasNaturalLocation())
{
throw semantic_error("source has no natural location");
}
AddressRange range;
range.m_begin = segment.getBaseAddress();
range.m_end = segment.getBaseAddress() + segment.getLength();
return range;
}

View File

@@ -0,0 +1,132 @@
/*
* File: DataTarget.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_DataTarget_h_)
#define _DataTarget_h_
#include "stdafx.h"
#include "DataSource.h"
namespace elftosb
{
// Forward declaration
class DataSource;
/*!
* \brief Abstract base class for the target address or range of data.
*
* Targets at the most basic level have a single address, and potentially
* an address range. Unbounded targets have a beginning address but no
* specific end address, while bounded targets do have an end address.
*
* Users of a data target can access the begin and end addresses directly.
* However, the most powerful way to use a target is with the
* getRangeForSegment() method. This method returns the target address range
* for a segment of a data source. The value of the resulting range can be
* completely dependent upon the segment's properties, those of its data
* source, and the type of data target.
*
* \see elftosb::DataSource
*/
class DataTarget
{
public:
//! \brief Simple structure that describes an addressed region of memory.
//! \todo Decide if the end address is inclusive or not.
struct AddressRange
{
uint32_t m_begin;
uint32_t m_end;
};
public:
//! \brief Default constructor.
DataTarget()
: m_source(0)
{
}
//! \brief Destructor.
virtual ~DataTarget() {}
//! \brief Whether the target is just a single address or has an end to it.
virtual bool isBounded() { return false; }
virtual uint32_t getBeginAddress() { return 0; }
virtual uint32_t getEndAddress() { return 0; }
//! \brief Return the address range for a segment of a data source.
virtual DataTarget::AddressRange getRangeForSegment(DataSource &source, DataSource::Segment &segment) = 0;
inline void setSource(DataSource *source) { m_source = source; }
inline DataSource *getSource() const { return m_source; }
protected:
DataSource *m_source; //!< Corresponding data source for this target.
};
/*!
* \brief Target with a constant values for the addresses.
*
* This target type supports can be both bounded and unbounded. It always has
* at least one address, the beginning address. The end address is optional,
* and if not provided makes the target unbounded.
*/
class ConstantDataTarget : public DataTarget
{
public:
//! \brief Constructor taking only a begin address.
ConstantDataTarget(uint32_t start)
: DataTarget()
, m_begin(start)
, m_end(0)
, m_hasEnd(false)
{
}
//! \brief Constructor taking both begin and end addresses.
ConstantDataTarget(uint32_t start, uint32_t end)
: DataTarget()
, m_begin(start)
, m_end(end)
, m_hasEnd(true)
{
}
//! \brief The target is bounded if an end address was specified.
virtual bool isBounded() { return m_hasEnd; }
virtual uint32_t getBeginAddress() { return m_begin; }
virtual uint32_t getEndAddress() { return m_end; }
//! \brief Return the address range for a segment of a data source.
virtual DataTarget::AddressRange getRangeForSegment(DataSource &source, DataSource::Segment &segment);
protected:
uint32_t m_begin; //!< Start address.
uint32_t m_end; //!< End address.
bool m_hasEnd; //!< Was an end address specified?
};
/*!
* \brief Target address that is the "natural" location of whatever the source data is.
*
* The data source used with the target must have a natural location. If
* getRangeForSegment() is called with a segment that does not have a natural
* location, a semantic_error will be thrown.
*/
class NaturalDataTarget : public DataTarget
{
public:
//! \brief Default constructor.
NaturalDataTarget()
: DataTarget()
{
}
//! \brief Natural data targets are bounded by their source's segment lengths.
virtual bool isBounded() { return true; }
//! \brief Return the address range for a segment of a data source.
virtual DataTarget::AddressRange getRangeForSegment(DataSource &source, DataSource::Segment &segment);
};
}; // namespace elftosb
#endif // _DataTarget_h_

349
apps/elftosb/common/ELF.h Normal file
View File

@@ -0,0 +1,349 @@
/*
* File: ELF.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_ELF_h_)
#define _ELF_h_
//! \name ELF types
//! Types used in ELF file structures.
//@{
typedef uint32_t Elf32_Addr;
typedef uint16_t Elf32_Half;
typedef /*off_t*/ uint32_t Elf32_Off;
typedef int32_t Elf32_Sword;
typedef uint32_t Elf32_Word;
//@}
// All ELF structures are byte aligned. Any alignment padding is explicit.
#pragma pack(1)
//! \name File header
//@{
/*!
* Constants for the various fields of Elf32_Ehdr.e_ident.
*/
enum
{
EI_MAG0 = 0,
EI_MAG1,
EI_MAG2,
EI_MAG3,
EI_CLASS,
EI_DATA,
EI_VERSION,
EI_PAD,
EI_NIDENT = 16,
// Magic number.
ELFMAG0 = 0x7f,
ELFMAG1 = 'E',
ELFMAG2 = 'L',
ELFMAG3 = 'F',
// EI_CLASS
ELFCLASSNONE = 0,
ELFCLASS32 = 1,
ELFCLASS64 = 2,
// EI_DATA
ELFDATANONE = 0,
ELFDATA2LSB = 1,
ELFDATA2MSB = 2
};
/*!
* \brief ELF file header.
*/
struct Elf32_Ehdr
{
unsigned char e_ident[EI_NIDENT]; //!< Magic number identifying the file format.
Elf32_Half e_type; //!< Identifies the object file format.
Elf32_Half e_machine; //!< Specified the architecture for the object file.
Elf32_Word e_version; //!< Object file version.
Elf32_Addr e_entry; //!< Virtual address of the entry point, or 0.
Elf32_Off e_phoff; //!< Program header table offset in bytes, or 0 if no program header table.
Elf32_Off e_shoff; //!< Section header table offset in bytes, or 0 if no section header table.
Elf32_Word e_flags; //!< Processor-specific flags associated with the file.
Elf32_Half e_ehsize; //!< The ELF header's size in bytes.
Elf32_Half e_phentsize; //!< Size in bytes of one entry in the program header table.
Elf32_Half e_phnum; //!< Number of entries in the program header table.
Elf32_Half e_shentsize; //!< Size in bytes of an entry in the section header table.
Elf32_Half e_shnum; //!< Number of entries in the section header table.
Elf32_Half e_shstrndx; //!< Section header table index of the section name string table.
};
/*!
* Constants for #Elf32_Ehdr.e_type.
*/
enum
{
ET_NONE, //!< No file type.
ET_REL, //!< Relocatable file.
ET_EXEC, //!< Executable file.
ET_DYN, //!< Shared object file.
ET_CORE, //!< Core file.
ET_LOPROC, //!< Low bound of processor-specific file types.
ET_HIPROC //!< High bound of processor-specific file types.
};
/*!
* ARM-specific #Elf32_Ehdr.e_flags
*/
enum
{
EF_ARM_HASENTRY = 0x02, //!< #Elf32_Ehdr.e_entry contains a program-loader entry point.
EF_ARM_SYMSARESORTED = 0x04, //!< Each subsection of the symbol table is sorted by symbol value.
EF_ARM_DYNSYMSUSESEGIDX = 0x08, //!< Symbols in dynamic symbol tables that are defined in sections included in
//!program segment n have #Elf32_Sym.st_shndx = n + 1.
EF_ARM_MAPSYMSFIRST = 0x10, //!< Mapping symbols precede other local symbols in the symbol table.
EF_ARM_EABIMASK = 0xff000000, //!< This masks an 8-bit version number, the version of the ARM EABI to which this ELF
//!file conforms. The current EABI version is #ARM_EABI_VERSION.
ARM_EABI_VERSION = 0x02000000 //!< Current ARM EABI version.
};
//@}
//! \name Sections
//@{
/*!
* \brief ELF section header.
*
* An object file's section header table lets one locate all the file's
* sections. The section header table is an array of #Elf32_Shdr structures.
* A section header table index is a subscript into this array. The ELF
* header's #Elf32_Ehdr::e_shoff member gives the byte offset from the beginning of
* the file to the section header table; #Elf32_Ehdr::e_shnum tells how many entries
* the section header table contains; #Elf32_Ehdr::e_shentsize gives the size in bytes
* of each entry.
*
* Some section header table indexes are reserved. An object file will not
* have sections for these special indexes:
* - #SHN_UNDEF
* - #SHN_LORESERVE
* - #SHN_LOPROC
* - #SHN_HIPROC
* - #SHN_ABS
* - #SHN_COMMON
* - #SHN_HIRESERVE
*/
struct Elf32_Shdr
{
Elf32_Word sh_name; //!< The section's name. Index into the section header string table section.
Elf32_Word sh_type; //!< Section type, describing the contents and semantics.
Elf32_Word sh_flags; //!< Section flags describing various attributes.
Elf32_Addr sh_addr; //!< The address at which the section will appear in the memory image, or 0.
Elf32_Off sh_offset; //!< Offset from beginning of the file to the first byte in the section.
Elf32_Word sh_size; //!< The section's size in bytes.
Elf32_Word sh_link; //!< Section header table link index. Interpretation depends on section type.
Elf32_Word sh_info; //!< Extra information about the section. Depends on section type.
Elf32_Word sh_addralign; //!< Address alignment constraint. Values are 0 and positive powers of 2.
Elf32_Word sh_entsize; //!< Size in bytes of section entries, or 0 if the section does not have fixed-size entries.
};
/*!
* Special section indexes.
*/
enum
{
SHN_UNDEF = 0,
SHN_LORESERVE = 0xff00,
SHN_LOPROC = 0xff00,
SHN_HIPROC = 0xff1f,
SHN_ABS = 0xfff1, //!< The symbol has an absolute value that will not change because of relocation.
SHN_COMMON = 0xfff2, //!< The symbol labels a common block that has not yet been allocated.
SHN_HIRESERVE = 0xffff
};
/*!
* Section type constants.
*/
enum
{
SHT_NULL = 0,
SHT_PROGBITS = 1,
SHT_SYMTAB = 2,
SHT_STRTAB = 3,
SHT_RELA = 4,
SHT_HASH = 5,
SHT_DYNAMIC = 6,
SHT_NOTE = 7,
SHT_NOBITS = 8,
SHT_REL = 9,
SHT_SHLIB = 10,
SHT_DYNSYM = 11
};
/*!
* Section flag constants.
*/
enum
{
SHF_WRITE = 0x1, //!< Section is writable.
SHF_ALLOC = 0x2, //!< Allocate section.
SHF_EXECINSTR = 0x4 //!< Section contains executable instructions.
};
/*!
* ARM-specific section flag constants
*/
enum
{
SHF_ENTRYSECT = 0x10000000, //!< The section contains an entry point.
SHF_COMDEF = 0x80000000 //!< The section may be multiply defined in the input to a link step.
};
#define BSS_SECTION_NAME ".bss"
#define DATA_SECTION_NAME ".data"
#define TEXT_SECTION_NAME ".text"
#define SHSTRTAB_SECTION_NAME ".shstrtab"
#define STRTAB_SECTION_NAME ".strtab"
#define SYMTAB_SECTION_NAME ".symtab"
//@}
//! \name Segments
//@{
/*!
* \brief ELF program header.
*
* An executable or shared object file's program header table is an array of
* structures, each describing a segment or other information the system needs
* to prepare the program for execution. An object file segment contains one
* or more sections. Program headers are meaningful only for executable and
* shared object files. A file specifies its own program header size with the
* ELF header's #Elf32_Ehdr::e_phentsize and #Elf32_Ehdr::e_phnum members.
*/
struct Elf32_Phdr
{
Elf32_Word p_type; //!< What type of segment this header describes.
Elf32_Off p_offset; //!< Offset in bytes from start of file to the first byte of the segment.
Elf32_Addr p_vaddr; //!< Virtual address at which the segment will reside in memory.
Elf32_Addr p_paddr; //!< Physical address, for systems where this is relevant.
Elf32_Word p_filesz; //!< Number of bytes of file data the segment consumes. May be zero.
Elf32_Word p_memsz; //!< Size in bytes of the segment in memory. May be zero.
Elf32_Word p_flags; //!< Flags relevant to the segment.
Elf32_Word p_align; //!< Alignment constraint for segment addresses. Possible values are 0 and positive powers of 2.
};
/*!
* Segment type constants.
*/
enum
{
PT_NULL = 0,
PT_LOAD = 1,
PT_DYNAMIC = 2,
PT_INTERP = 3,
PT_NOTE = 4,
PT_SHLIB = 5,
PT_PHDR = 6
};
/*!
* Program header flag constants.
*/
enum
{
PF_X = 0x1, //!< Segment is executable.
PF_W = 0x2, //!< Segment is writable.
PF_R = 0x4 //!< Segment is readable.
};
//@}
//! \name Symbol table
//@{
enum
{
STN_UNDEF = 0 //!< Undefined symbol index.
};
/*!
* \brief ELF symbol table entry.
*
* An object file's symbol table holds information needed to locate and
* relocate a program's symbolic definitions and references. A symbol
* table index is a subscript into this array. Index 0 both designates
* the first entry in the table and serves as the undefined symbol index.
*/
struct Elf32_Sym
{
Elf32_Word st_name; //!< Index into file's string table.
Elf32_Addr st_value; //!< Value associated with the symbol. Depends on context.
Elf32_Word st_size; //!< Size associated with symbol. 0 if the symbol has no size or an unknown size.
unsigned char st_info; //!< Specified the symbol's type and binding attributes.
unsigned char st_other; //!< Currently 0 (reserved).
Elf32_Half st_shndx; //!< Section header table index for this symbol.
};
//! \name st_info macros
//! Macros for manipulating the st_info field of Elf32_Sym struct.
//@{
#define ELF32_ST_BIND(i) ((i) >> 4) //!< Get binding attributes.
#define ELF32_ST_TYPE(i) ((i)&0x0f) //!< Get symbol type.
#define ELF32_ST_INFO(b, t) \
(((b) << 4) + ((t)&0x0f)) //!< Construct st_info value from binding attributes and symbol type.
//@}
/*!
* \brief Symbol binding attributes.
*
* These constants are mask values.
*/
enum
{
STB_LOCAL = 0, //!< Local symbol not visible outside the object file.
STB_GLOBAL = 1, //!< Symbol is visible to all object files being linked together.
STB_WEAK = 2, //!< Like global symbols, but with lower precedence.
// Processor-specific semantics.
STB_LOPROC = 13,
STB_HIPROC = 15
};
/*!
* \brief Symbol types.
*/
enum
{
STT_NOTYPE = 0, //!< The symbol's type is not specified.
STT_OBJECT = 1, //!< The symbol is associated with a data object, such as a variable or array.
STT_FUNC = 2, //!< The symbol is associated with a function or other executable code.
STT_SECTION = 3, //!< The synmbol is associated with a section. Primarily used for relocation.
STT_FILE = 4, //!< A file symbol has STB_LOCAL binding, its section index is SHN_ABS, and it precedes the other
//!STB_LOCAL symbols for the file, if it is present.
STT_LOPROC = 13, //!< Low bound of processor-specific symbol types.
STT_HIPROC = 15 //!< High bound of processor-specific symbol types.
};
/*!
* GHS-specific constants
*/
enum
{
STO_THUMB = 1 //!< This flag is set on #Elf32_Sym.st_other if the symbol is Thumb mode code.
};
#define ARM_SEQUENCE_MAPSYM "$a"
#define DATA_SEQUENCE_MAPSYM "$d"
#define THUMB_SEQUENCE_MAPSYM "$t"
#define THUMB_BL_TAGSYM "$b"
#define FN_PTR_CONST_TAGSYM "$f"
#define INDIRECT_FN_CALL_TAGSYM "$p"
#define MAPPING_SYMBOL_COUNT_TAGSYM "$m"
//@}
#pragma pack()
#endif // _ELF_h_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,225 @@
/*
* File: ELFSourceFile.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_ELFSourceFile_h_)
#define _ELFSourceFile_h_
#include "SourceFile.h"
#include "StELFFile.h"
#include "smart_ptr.h"
#include "DataSource.h"
#include "DataTarget.h"
#include "ELF.h"
namespace elftosb
{
//! Set of supported compiler toolsets.
enum elf_toolset_t
{
kUnknownToolset, //!< Unknown.
kGHSToolset, //!< Green Hills Software MULTI
kGCCToolset, //!< GNU GCC
kADSToolset, //!< ARM UK RealView
kIARToolset, //!< IAR
kKDSToolset, //!< KDS
kKeilToolset //!< Keil
};
//! Options for handling the .secinfo section in GHS-produced ELF files.
enum secinfo_clear_t
{
// Default value for the .secinfo action.
kSecinfoDefault,
//! Ignore the .secinfo section if present. The standard ELF loading
//! rules are followed.
kSecinfoIgnore,
//! The boot ROM clears only those SHT_NOBITS sections present in .secinfo.
kSecinfoROMClear,
//! The C startup is responsible for clearing sections. No fill commands
//! are generated for any SHT_NOBITS sections.
kSecinfoCStartupClear
};
/*!
* \brief Executable and Loading Format (ELF) source file.
*/
class ELFSourceFile : public SourceFile
{
public:
//! \brief Default constructor.
ELFSourceFile(const std::string &path);
//! \brief Destructor.
virtual ~ELFSourceFile();
//! \brief Identifies whether the stream contains an ELF file.
static bool isELFFile(std::istream &stream);
//! \name Opening and closing
//@{
//! \brief Opens the file.
virtual void open();
//! \brief Closes the file.
virtual void close();
//@}
//! \name Format capabilities
//@{
virtual bool supportsNamedSections() const { return true; }
virtual bool supportsNamedSymbols() const { return true; }
//@}
//! \name Data source
//@{
//! \brief Creates a data source from the entire file.
virtual DataSource *createDataSource();
//! \brief Creates a data source from one or more sections of the file.
virtual DataSource *createDataSource(StringMatcher &matcher);
//@}
//! \name Entry point
//@{
//! \brief Returns true if an entry point was set in the file.
virtual bool hasEntryPoint();
//! \brief Returns the entry point address.
virtual uint32_t getEntryPointAddress();
//@}
//! \name Data target
//@{
virtual DataTarget *createDataTargetForSection(const std::string &section);
virtual DataTarget *createDataTargetForSymbol(const std::string &symbol);
//@}
//! \name Symbols
//@{
//! \brief Returns whether a symbol exists in the source file.
virtual bool hasSymbol(const std::string &name);
//! \brief Returns the value of a symbol.
virtual uint32_t getSymbolValue(const std::string &name);
//! \brief Returns the size of a symbol.
virtual unsigned getSymbolSize(const std::string &name);
//@}
//! \name Direct ELF format access
//@{
//! \brief Returns the underlying StELFFile object.
StELFFile *getELFFile() { return m_file; }
//! \brief Gets information about a symbol in the ELF file.
bool lookupSymbol(const std::string &name, Elf32_Sym &info);
//@}
protected:
smart_ptr<StELFFile> m_file; //!< Parser for the ELF file.
elf_toolset_t m_toolset; //!< Toolset that produced the ELF file.
secinfo_clear_t m_secinfoOption; //!< How to deal with the .secinfo section. Ignored if the toolset is not GHS.
protected:
//! \brief Parses the toolset option value.
elf_toolset_t readToolsetOption();
//! \brief Reads the secinfoClear option.
secinfo_clear_t readSecinfoClearOption();
protected:
/*!
* \brief A data source with ELF file sections as the contents.
*
* Each segment of this data source corresponds directly with a named section
* of the ELF file it represents. When the data source is created, it contains
* no segments. Segments are created with the addSection() method, which takes
* the index of an ELF section and creates a corresponding segment.
*
* Two segment subclasses are used with this data source. The first, ProgBitsSegment,
* is used to represent sections whose type is #SHT_PROGBITS. These sections have
* binary data stored in the ELF file. The second segment type is NoBitsSegment.
* It is used to represent sections whose type is #SHT_NOBITS. These sections have
* no data, but simply allocate a region of memory to be filled with zeroes.
* As such, the NoBitsSegment class is a subclass of DataSource::PatternSegment.
*/
class ELFDataSource : public DataSource
{
public:
/*!
* \brief Represents one named #SHT_PROGBITS section within the ELF file.
*/
class ProgBitsSegment : public DataSource::Segment
{
public:
ProgBitsSegment(ELFDataSource &source, StELFFile *elf, unsigned index);
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer);
virtual unsigned getLength();
virtual bool hasNaturalLocation() { return true; }
virtual uint32_t getBaseAddress();
protected:
StELFFile *m_elf; //!< The format parser instance for this ELF file.
unsigned m_sectionIndex; //!< The index of the section this segment represents.
};
/*!
* \brief Represents one named #SHT_NOBITS section within the ELF file.
*
* This segment class is a subclass of DataSource::PatternSegment since it
* represents a region of memory to be filled with zeroes.
*/
class NoBitsSegment : public DataSource::PatternSegment
{
public:
NoBitsSegment(ELFDataSource &source, StELFFile *elf, unsigned index);
virtual unsigned getLength();
virtual bool hasNaturalLocation() { return true; }
virtual uint32_t getBaseAddress();
protected:
StELFFile *m_elf; //!< The format parser instance for this ELF file.
unsigned m_sectionIndex; //!< The index of the section this segment represents.
};
public:
//! \brief Default constructor.
ELFDataSource(StELFFile *elf)
: DataSource()
, m_elf(elf)
{
}
//! \brief Destructor.
virtual ~ELFDataSource();
//! Set the option to control .secinfo usage.
inline void setSecinfoOption(secinfo_clear_t option) { m_secinfoOption = option; }
//! \brief Adds the ELF section at position \a sectionIndex to the data source.
void addSection(unsigned sectionIndex);
//! \brief Returns the number of segments in the source.
virtual unsigned getSegmentCount() { return (unsigned)m_segments.size(); }
//! \brief Returns the segment at position \a index.
virtual DataSource::Segment *getSegmentAt(unsigned index) { return m_segments[index]; }
protected:
StELFFile *m_elf; //!< The ELF file parser.
secinfo_clear_t m_secinfoOption; //!< How to deal with the .secinfo section. Ignored if the toolset is not GHS.
typedef std::vector<DataSource::Segment *> segment_vector_t; //!< A list of segment instances.
segment_vector_t m_segments; //!< The segments of this data source.
};
};
}; // namespace elftosb
#endif // _ELFSourceFile_h_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,371 @@
/*
* File: EncoreBootImageReader.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "EncoreBootImageReader.h"
#include "SHA1.h"
#include "rijndael.h"
#include "RijndaelCBCMAC.h"
#include <assert.h>
#include "EndianUtilities.h"
#include "Logging.h"
using namespace elftosb;
//! \post Stream head points to just after the image header.
//! \exception read_error Thrown if the image header is invalid.
void EncoreBootImageReader::readImageHeader()
{
// seek to beginning of the stream/file and read the plaintext header
m_stream.seekg(0, std::ios_base::beg);
if (m_stream.read((char *)&m_header, sizeof(m_header)).bad())
{
throw read_error("failed to read image header");
}
m_header.m_flags = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_flags);
m_header.m_imageBlocks = ENDIAN_LITTLE_TO_HOST_U32(m_header.m_imageBlocks);
m_header.m_firstBootTagBlock = ENDIAN_LITTLE_TO_HOST_U32(m_header.m_firstBootTagBlock);
m_header.m_firstBootableSectionID = ENDIAN_LITTLE_TO_HOST_U32(m_header.m_firstBootableSectionID);
m_header.m_keyCount = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_keyCount);
m_header.m_keyDictionaryBlock = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_keyDictionaryBlock);
m_header.m_headerBlocks = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_headerBlocks);
m_header.m_sectionCount = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_sectionCount);
m_header.m_sectionHeaderSize = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_sectionHeaderSize);
m_header.m_timestamp = ENDIAN_LITTLE_TO_HOST_U64(m_header.m_timestamp);
// m_header.m_componentVersion.m_major = ENDIAN_BIG_TO_HOST_U16(m_header.m_componentVersion.m_major);
// m_header.m_componentVersion.m_minor = ENDIAN_BIG_TO_HOST_U16(m_header.m_componentVersion.m_minor);
// m_header.m_componentVersion.m_revision = ENDIAN_BIG_TO_HOST_U16(m_header.m_componentVersion.m_revision);
// m_header.m_productVersion.m_major = ENDIAN_BIG_TO_HOST_U16(m_header.m_productVersion.m_major);
// m_header.m_productVersion.m_minor = ENDIAN_BIG_TO_HOST_U16(m_header.m_productVersion.m_minor);
// m_header.m_productVersion.m_revision = ENDIAN_BIG_TO_HOST_U16(m_header.m_productVersion.m_revision);
// check header signature 1
if (m_header.m_signature[0] != 'S' || m_header.m_signature[1] != 'T' || m_header.m_signature[2] != 'M' ||
m_header.m_signature[3] != 'P')
{
throw read_error("invalid signature 1");
}
// check header signature 2 for version 1.1 and greater
if ((m_header.m_majorVersion > 1 || (m_header.m_majorVersion == 1 && m_header.m_minorVersion >= 2)) &&
(m_header.m_signature2[0] != 's' || m_header.m_signature2[1] != 'g' || m_header.m_signature2[2] != 't' ||
m_header.m_signature2[3] != 'l'))
{
// throw read_error("invalid signature 2");
Log::log(Logger::WARNING, "warning: invalid signature 2\n");
}
}
//! \pre The image header must have already been read with a call to readImageHeader().
//!
void EncoreBootImageReader::computeHeaderDigest(sha1_digest_t &digest)
{
CSHA1 hash;
hash.Reset();
hash.Update((uint8_t *)&m_header.m_signature, sizeof(m_header) - sizeof(sha1_digest_t));
hash.Final();
hash.GetHash(digest);
}
//! \pre The image header must have already been read.
//! \pre The DEK must have been found already.
//! \post The stream head is at the end of the digest.
void EncoreBootImageReader::readImageDigest()
{
unsigned digestPosition = sizeOfCipherBlocks(m_header.m_imageBlocks - 2);
m_stream.seekg(digestPosition, std::ios_base::beg);
// read the two cipher blocks containing the digest, including padding
cipher_block_t digestBlocks[2];
if (m_stream.read((char *)&digestBlocks, sizeof(digestBlocks)).bad())
{
throw read_error("failed to read image digest");
}
// decrypt the digest
if (isEncrypted())
{
Rijndael cipher;
cipher.init(Rijndael::CBC, Rijndael::Decrypt, m_dek, Rijndael::Key16Bytes, m_header.m_iv);
cipher.blockDecrypt((uint8_t *)&digestBlocks, sizeof(digestBlocks) * 8, (uint8_t *)&digestBlocks);
}
// copy the digest out of the padded blocks
memcpy(m_digest, &digestBlocks, sizeof(m_digest));
}
//! \pre The image header must have already been read with a call to readImageHeader().
//! \post The stream head is at the end of the image minus the last two cipher blocks.
//! \param digest Where to store the resulting digest.
//! \exception read_error Thrown if the image header is invalid.
void EncoreBootImageReader::computeImageDigest(sha1_digest_t &digest)
{
m_stream.seekg(0, std::ios_base::beg);
CSHA1 hash;
hash.Reset();
unsigned blockCount = m_header.m_imageBlocks - 2; // exclude digest at end of image
while (blockCount--)
{
cipher_block_t block;
if (m_stream.read((char *)&block, sizeof(block)).bad())
{
throw read_error("failed to read block while computing image digest");
}
hash.Update(block, sizeof(block));
}
hash.Final();
hash.GetHash(digest);
}
//! \pre Image header must have been read before this method is called.
//!
void EncoreBootImageReader::readSectionTable()
{
// seek to the table
m_stream.seekg(sizeOfCipherBlocks(m_header.m_headerBlocks), std::ios_base::beg);
unsigned sectionCount = m_header.m_sectionCount;
while (sectionCount--)
{
EncoreBootImage::section_header_t header;
if (m_stream.read((char *)&header, sizeof(header)).bad())
{
throw read_error("failed to read section header");
}
// swizzle section header
header.m_tag = ENDIAN_LITTLE_TO_HOST_U32(header.m_tag);
header.m_offset = ENDIAN_LITTLE_TO_HOST_U32(header.m_offset);
header.m_length = ENDIAN_LITTLE_TO_HOST_U32(header.m_length);
header.m_flags = ENDIAN_LITTLE_TO_HOST_U32(header.m_flags);
m_sections.push_back(header);
}
}
//! Requires that an OTP key has been provided as the sole argument. Passing the
//! key into this method lets the caller search the key dictionary for any number
//! of keys and determine which are valid. If \a kek is found in the dictionary,
//! the decrypted DEK is saved and true is returned. A result of false means
//! that \a kek was not found.
//!
//! \pre The image header and section table must have been read already.
//! \post The stream head points somewhere inside the key dictionary, or just after it.
//! \post If the search was successful, the #m_dek member will contain the decrypted
//! session key. Otherwise #m_dek is not modified.
//! \param kek Search for this KEK in the dictionary.
//! \retval true The DEK was found and decrypted. True is also returned when the
//! image is not encrypted at all.
//! \retval false No matching key entry was found. The image cannot be decrypted.
bool EncoreBootImageReader::readKeyDictionary(const AESKey<128> &kek)
{
// do nothing if the image is not encrypted
if (!isEncrypted())
{
return true;
}
// first compute a CBC-MAC over the image header with our KEK
RijndaelCBCMAC mac(kek);
mac.update((const uint8_t *)&m_header, sizeof(m_header));
// run the CBC-MAC over each entry in the section table too
section_array_t::iterator it = m_sections.begin();
for (; it != m_sections.end(); ++it)
{
mac.update((const uint8_t *)&(*it), sizeof(EncoreBootImage::section_header_t));
}
// get the CBC-MAC result
mac.finalize();
const RijndaelCBCMAC::block_t &macResult = mac.getMAC();
// seek to the key dictionary
m_stream.seekg(sizeOfCipherBlocks(m_header.m_keyDictionaryBlock), std::ios_base::beg);
// decipher each key entry
unsigned entries = m_header.m_keyCount;
while (entries--)
{
// read the entry
EncoreBootImage::dek_dictionary_entry_t entry;
if (m_stream.read((char *)&entry, sizeof(entry)).bad())
{
throw read_error("failed to read key dictionary entry");
}
// compare the CBC-MAC we computed with the one in this entry
if (memcmp(macResult, entry.m_mac, sizeof(cipher_block_t)) == 0)
{
// it's a match! now decrypt this entry's key in place
Rijndael cipher;
cipher.init(Rijndael::CBC, Rijndael::Decrypt, kek, Rijndael::Key16Bytes, m_header.m_iv);
cipher.blockDecrypt(entry.m_dek, sizeof(entry.m_dek) * 8, entry.m_dek);
m_dek = entry.m_dek;
memset(entry.m_dek, 0, sizeof(entry.m_dek)); // wipe the key value from memory
return true;
}
}
// if we exit the loop normally then no matching MAC was found
return false;
}
//! Before the boot tag is added to the #m_bootTags member, some basic checks are performed.
//! The command tag field is checked to make sure it matches #ROM_TAG_CMD. And
//! the checksum field is verified to be sure it's correct.
//!
//! After the call to this method returns, the array of boot tags is accessible
//! with the getBootTags() method. The array is sorted in the order in which
//! the boot tags appeared in the image.
//!
//! \pre Image header must have been read.
//! \pre Key dictionary must have been read and a valid DEK found.
//! \post The stream head is left pointing just after the last boot tag.
//! \exception read_error A failure to read the boot tag, or a failure on one
//! of the consistency checks will cause this exception to be thrown.
void EncoreBootImageReader::readBootTags()
{
assert(m_header.m_firstBootTagBlock != 0);
unsigned bootTagOffset = m_header.m_firstBootTagBlock;
while (1)
{
// seek to this boot tag and read it into a temporary buffer
EncoreBootImage::boot_command_t header;
m_stream.seekg(sizeOfCipherBlocks(bootTagOffset), std::ios_base::beg);
if (m_stream.read((char *)&header, sizeof(header)).bad())
{
throw read_error("failed to read boot tag");
}
// swizzle to command header
header.m_flags = ENDIAN_LITTLE_TO_HOST_U16(header.m_flags);
header.m_address = ENDIAN_LITTLE_TO_HOST_U32(header.m_address);
header.m_count = ENDIAN_LITTLE_TO_HOST_U32(header.m_count);
header.m_data = ENDIAN_LITTLE_TO_HOST_U32(header.m_data);
// decrypt in place
if (isEncrypted())
{
Rijndael cipher;
cipher.init(Rijndael::CBC, Rijndael::Decrypt, m_dek, Rijndael::Key16Bytes, m_header.m_iv);
cipher.blockDecrypt((uint8_t *)&header, sizeof(header) * 8, (uint8_t *)&header);
}
// perform some basic checks
if (header.m_tag != EncoreBootImage::ROM_TAG_CMD)
{
throw read_error("boot tag is wrong command type");
}
uint8_t checksum = calculateCommandChecksum(header);
if (checksum != header.m_checksum)
{
throw read_error("boot tag checksum is invalid");
}
// save this boot tag
m_bootTags.push_back(header);
// and finally, update offset and break out of loop
bootTagOffset += header.m_count + 1; // include this boot tag in offset
if (header.m_flags & EncoreBootImage::ROM_LAST_TAG || bootTagOffset >= m_header.m_imageBlocks - 2)
{
break;
}
}
}
uint8_t EncoreBootImageReader::calculateCommandChecksum(EncoreBootImage::boot_command_t &header)
{
uint8_t *bytes = reinterpret_cast<uint8_t *>(&header);
uint8_t checksum = 0x5a;
int i;
// start at one to skip checksum field
for (i = 1; i < sizeof(header); ++i)
{
checksum += bytes[i];
}
return checksum;
}
//! \param index The index of the section to read.
//!
//! \pre Both the image header and section table must have been read already before
//! calling this method.
//! \exception read_error This exception is raised if the stream reports an error while
//! trying to read from the section.
EncoreBootImage::Section *EncoreBootImageReader::readSection(unsigned index)
{
// look up section header
assert(index < m_sections.size());
EncoreBootImage::section_header_t &header = m_sections[index];
// seek to the section
m_stream.seekg(sizeOfCipherBlocks(header.m_offset), std::ios_base::beg);
uint8_t *contents = NULL;
try
{
// allocate memory for the section contents and read the whole thing
unsigned contentLength = sizeOfCipherBlocks(header.m_length);
contents = new uint8_t[contentLength];
if (m_stream.read((char *)contents, contentLength).bad())
{
throw read_error("failed to read section");
}
// decrypt the entire section at once, if the image is encrypted and
// the cleartext flag is not set
if (isEncrypted() && (header.m_flags & EncoreBootImage::ROM_SECTION_CLEARTEXT) == 0)
{
Rijndael cipher;
cipher.init(Rijndael::CBC, Rijndael::Decrypt, m_dek, Rijndael::Key16Bytes, m_header.m_iv);
cipher.blockDecrypt(contents, contentLength * 8, contents);
}
// create section object
EncoreBootImage::Section *resultSection = NULL;
if (header.m_flags & EncoreBootImage::ROM_SECTION_BOOTABLE)
{
// a boot command section.
EncoreBootImage::BootSection *bootSection = new EncoreBootImage::BootSection(header.m_tag);
bootSection->fillFromData((cipher_block_t *)contents, header.m_length);
resultSection = bootSection;
}
else
{
// this is a raw data section
EncoreBootImage::DataSection *dataSection = new EncoreBootImage::DataSection(header.m_tag);
dataSection->setDataNoCopy(contents, contentLength);
contents = NULL;
resultSection = dataSection;
}
return resultSection;
}
catch (...)
{
if (contents)
{
delete[] contents;
}
throw;
}
}

View File

@@ -0,0 +1,117 @@
/*
* File: EncoreBootImageReader.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_EncoreBootImageReader_h_)
#define _EncoreBootImageReader_h_
#include "EncoreBootImage.h"
namespace elftosb
{
/*!
* \brief Reads a Piano/Encore boot image from an input stream.
*/
class EncoreBootImageReader
{
public:
/*!
* \brief Exception class used for error found while reading a boot image.
*/
class read_error : public std::runtime_error
{
public:
//! \brief Constructor.
read_error(const std::string &msg)
: std::runtime_error(msg)
{
}
};
//! \brief An array of section headers.
typedef std::vector<EncoreBootImage::section_header_t> section_array_t;
//! \brief An array of boot tags.
typedef std::vector<EncoreBootImage::boot_command_t> boot_tag_array_t;
public:
//! \brief Default constructor.
EncoreBootImageReader(std::istream &stream)
: m_stream(stream)
{
}
//! \brief Destructor.
virtual ~EncoreBootImageReader() {}
//! \name Decryption key
//! These methods provide access to the Data Encryption Key (DEK). Normally
//! the DEK is discovered using the readKeyDictionary() method.
//@{
inline void setKey(const AESKey<128> &key) { m_dek = key; }
inline const AESKey<128> &getKey() const { return m_dek; }
//@}
//! \name Readers
//! This group of methods is responsible for reading and parsing different
//! pieces and parts of the boot image file.
//@{
//! \brief Reads the header from the image.
void readImageHeader();
//! \brief Computes the actual SHA-1 digest of the image header.
void computeHeaderDigest(sha1_digest_t &digest);
//! \brief Reads the digest at the end of the image.
void readImageDigest();
//! \brief Run a SHA-1 digest over the entire image.
void computeImageDigest(sha1_digest_t &digest);
//! \brief Read the plaintext section table entries.
void readSectionTable();
//! \brief Reads the key dictionary, if the image is encrypted.
bool readKeyDictionary(const AESKey<128> &kek);
//! \brief
void readBootTags();
//! \brief
EncoreBootImage::Section *readSection(unsigned index);
//@}
//! \name Accessors
//! Information retrieved with reader methods is accessible through
//! these methods.
//@{
//! \brief Returns whether the image is encrypted or not.
//! \pre The header must have been read already.
inline bool isEncrypted() const { return m_header.m_keyCount > 0; }
//! \brief Returns a reference to the image's header.
const EncoreBootImage::boot_image_header_t &getHeader() const { return m_header; }
//! \brief Returns a reference to the SHA-1 digest read from the image.
const sha1_digest_t &getDigest() const { return m_digest; }
//! \brief Returns a reference to the STL container holding the section headers.
inline const section_array_t &getSections() const { return m_sections; }
//! \brief Returns a reference to the STL container holding the boot tags.
inline const boot_tag_array_t &getBootTags() const { return m_bootTags; }
//@}
protected:
std::istream &m_stream; //!< The input stream to read the image from.
AESKey<128> m_dek; //!< DEK (data encryption key) read from the key dictionary.
EncoreBootImage::boot_image_header_t m_header; //!< Header from the boot image.
sha1_digest_t m_digest; //!< SHA-1 digest as read from the image.
section_array_t m_sections; //!< The section table.
boot_tag_array_t m_bootTags; //!< The array of boot tags read from the image.
protected:
//! \brief Calculates the 8-bit checksum on a boot command header.
uint8_t calculateCommandChecksum(EncoreBootImage::boot_command_t &header);
};
}; // namespace elftosb
#endif // _EncoreBootImageReader_h_

View File

@@ -0,0 +1,149 @@
/*
* File: EndianUtilities.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_EndianUtilities_h_)
#define _EndianUtilities_h_
//! \name Swap macros
//! These macros always swap the data.
//@{
//! Byte swap 16-bit value.
#define _BYTESWAP16(value) (((((uint16_t)value) << 8) & 0xFF00) | ((((uint16_t)value) >> 8) & 0x00FF))
//! Byte swap 32-bit value.
#define _BYTESWAP32(value) \
(((((uint32_t)value) << 24) & 0xFF000000) | ((((uint32_t)value) << 8) & 0x00FF0000) | \
((((uint32_t)value) >> 8) & 0x0000FF00) | ((((uint32_t)value) >> 24) & 0x000000FF))
//! Byte swap 64-bit value.
#define _BYTESWAP64(value) \
(((((uint64_t)value) << 56) & 0xFF00000000000000ULL) | ((((uint64_t)value) << 40) & 0x00FF000000000000ULL) | \
((((uint64_t)value) << 24) & 0x0000FF0000000000ULL) | ((((uint64_t)value) << 8) & 0x000000FF00000000ULL) | \
((((uint64_t)value) >> 8) & 0x00000000FF000000ULL) | ((((uint64_t)value) >> 24) & 0x0000000000FF0000ULL) | \
((((uint64_t)value) >> 40) & 0x000000000000FF00ULL) | ((((uint64_t)value) >> 56) & 0x00000000000000FFULL))
//@}
//! \name Inline swap functions
//@{
inline uint16_t _swap_u16(uint16_t value)
{
return _BYTESWAP16(value);
}
inline int16_t _swap_s16(int16_t value)
{
return (int16_t)_BYTESWAP16((uint16_t)value);
}
inline uint32_t _swap_u32(uint32_t value)
{
return _BYTESWAP32(value);
}
inline int32_t _swap_s32(int32_t value)
{
return (int32_t)_BYTESWAP32((uint32_t)value);
}
inline uint64_t _swap_u64(uint64_t value)
{
return _BYTESWAP64(value);
}
inline int64_t _swap_s64(int64_t value)
{
return (uint64_t)_BYTESWAP64((uint64_t)value);
}
//@}
#if defined(__LITTLE_ENDIAN__)
/* little endian host */
#define ENDIAN_BIG_TO_HOST_U16(value) (_swap_u16(value))
#define ENDIAN_HOST_TO_BIG_U16(value) (_swap_u16(value))
#define ENDIAN_BIG_TO_HOST_S16(value) (_swap_s16(value))
#define ENDIAN_HOST_TO_BIG_S16(value) (_swap_s16(value))
#define ENDIAN_BIG_TO_HOST_U32(value) (_swap_u32(value))
#define ENDIAN_HOST_TO_BIG_U32(value) (_swap_u32(value))
#define ENDIAN_BIG_TO_HOST_S32(value) (_swap_s32(value))
#define ENDIAN_HOST_TO_BIG_S32(value) (_swap_s32(value))
#define ENDIAN_BIG_TO_HOST_U64(value) (_swap_u64(value))
#define ENDIAN_HOST_TO_BIG_U64(value) (_swap_u64(value))
#define ENDIAN_BIG_TO_HOST_S64(value) (_swap_s64(value))
#define ENDIAN_HOST_TO_BIG_S64(value) (_swap_s64(value))
/* no-ops */
#define ENDIAN_LITTLE_TO_HOST_U16(value) (value)
#define ENDIAN_HOST_TO_LITTLE_U16(value) (value)
#define ENDIAN_LITTLE_TO_HOST_S16(value) (value)
#define ENDIAN_HOST_TO_LITTLE_S16(value) (value)
#define ENDIAN_LITTLE_TO_HOST_U32(value) (value)
#define ENDIAN_HOST_TO_LITTLE_U32(value) (value)
#define ENDIAN_LITTLE_TO_HOST_S32(value) (value)
#define ENDIAN_HOST_TO_LITTLE_S32(value) (value)
#define ENDIAN_LITTLE_TO_HOST_U64(value) (value)
#define ENDIAN_HOST_TO_LITTLE_U64(value) (value)
#define ENDIAN_LITTLE_TO_HOST_S64(value) (value)
#define ENDIAN_HOST_TO_LITTLE_S64(value) (value)
#elif defined(__BIG_ENDIAN__)
/* big endian host */
#define ENDIAN_LITTLE_TO_HOST_U16(value) (_swap_u16(value))
#define ENDIAN_HOST_TO_LITTLE_U16(value) (_swap_u16(value))
#define ENDIAN_LITTLE_TO_HOST_S16(value) (_swap_s16(value))
#define ENDIAN_HOST_TO_LITTLE_S16(value) (_swap_s16(value))
#define ENDIAN_LITTLE_TO_HOST_U32(value) (_swap_u32(value))
#define ENDIAN_HOST_TO_LITTLE_U32(value) (_swap_u32(value))
#define ENDIAN_LITTLE_TO_HOST_S32(value) (_swap_s32(value))
#define ENDIAN_HOST_TO_LITTLE_S32(value) (_swap_s32(value))
#define ENDIAN_LITTLE_TO_HOST_U64(value) (_swap_u64(value))
#define ENDIAN_HOST_TO_LITTLE_U64(value) (_swap_u64(value))
#define ENDIAN_LITTLE_TO_HOST_S64(value) (_swap_s64(value))
#define ENDIAN_HOST_TO_LITTLE_S64(value) (_swap_s64(value))
/* no-ops */
#define ENDIAN_BIG_TO_HOST_U16(value) (value)
#define ENDIAN_HOST_TO_BIG_U16(value) (value)
#define ENDIAN_BIG_TO_HOST_S16(value) (value)
#define ENDIAN_HOST_TO_BIG_S16(value) (value)
#define ENDIAN_BIG_TO_HOST_U32(value) (value)
#define ENDIAN_HOST_TO_BIG_U32(value) (value)
#define ENDIAN_BIG_TO_HOST_S32(value) (value)
#define ENDIAN_HOST_TO_BIG_S32(value) (value)
#define ENDIAN_BIG_TO_HOST_U64(value) (value)
#define ENDIAN_HOST_TO_BIG_U64(value) (value)
#define ENDIAN_BIG_TO_HOST_S64(value) (value)
#define ENDIAN_HOST_TO_BIG_S64(value) (value)
#endif
#endif // _EndianUtilities_h_

View File

@@ -0,0 +1,110 @@
/*
* File: EvalContext.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "EvalContext.h"
#include <stdexcept>
#include "format_string.h"
using namespace elftosb;
EvalContext::EvalContext()
: m_sourcesManager(0)
{
}
EvalContext::~EvalContext()
{
}
bool EvalContext::isVariableDefined(const std::string &name)
{
variable_map_t::const_iterator it = m_variables.find(name);
return it != m_variables.end();
}
uint32_t EvalContext::getVariableValue(const std::string &name)
{
variable_map_t::const_iterator it = m_variables.find(name);
if (it == m_variables.end())
{
throw std::runtime_error(format_string("undefined variable '%s'", name.c_str()));
}
return it->second.m_value;
}
int_size_t EvalContext::getVariableSize(const std::string &name)
{
variable_map_t::const_iterator it = m_variables.find(name);
if (it == m_variables.end())
{
throw std::runtime_error(format_string("undefined variable '%s'", name.c_str()));
}
return it->second.m_size;
}
void EvalContext::setVariable(const std::string &name, uint32_t value, int_size_t size)
{
// check if var is locked
variable_map_t::const_iterator it = m_variables.find(name);
if (it != m_variables.end() && it->second.m_isLocked)
{
return;
}
// set var info
variable_info_t info;
info.m_value = value;
info.m_size = size;
info.m_isLocked = false;
m_variables[name] = info;
}
bool EvalContext::isVariableLocked(const std::string &name)
{
variable_map_t::const_iterator it = m_variables.find(name);
if (it == m_variables.end())
{
throw std::runtime_error(format_string("undefined variable '%s'", name.c_str()));
}
return it->second.m_isLocked;
}
void EvalContext::lockVariable(const std::string &name)
{
variable_map_t::iterator it = m_variables.find(name);
if (it == m_variables.end())
{
throw std::runtime_error(format_string("undefined variable '%s'", name.c_str()));
}
it->second.m_isLocked = true;
}
void EvalContext::unlockVariable(const std::string &name)
{
variable_map_t::iterator it = m_variables.find(name);
if (it == m_variables.end())
{
throw std::runtime_error("undefined variable");
}
it->second.m_isLocked = false;
}
void EvalContext::dump()
{
variable_map_t::iterator it = m_variables.begin();
for (; it != m_variables.end(); ++it)
{
variable_info_t &info = it->second;
const char *lockedString = info.m_isLocked ? "locked" : "unlocked";
printf("%s = %u:%d (%s)\n", it->first.c_str(), info.m_value, (int)info.m_size, lockedString);
}
}

View File

@@ -0,0 +1,97 @@
/*
* File: EvalContext.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_EvalContext_h_)
#define _EvalContext_h_
#include <map>
#include <string>
#include "Value.h"
#include "int_size.h"
#include "SourceFile.h"
namespace elftosb
{
/*!
* \brief Context for evaluating AST tree and expressions.
*
* Keeps a map of variable names to integer values. Each integer value has a
* size attribute in addition to the actual value. Variables can be locked, which
* simply means that they cannot be assigned a new value.
*
* \todo Switch to using Value instances to keep track of variable values. This
* will enable variables to have string values, for one.
*/
class EvalContext
{
public:
/*!
* \brief Abstract interface for a manager of source files.
*/
class SourceFileManager
{
public:
//! \brief Returns true if a source file with the name \a name exists.
virtual bool hasSourceFile(const std::string &name) = 0;
//! \brief Gets the requested source file.
virtual SourceFile *getSourceFile(const std::string &name) = 0;
//! \brief Returns the default source file, or NULL if none is set.
virtual SourceFile *getDefaultSourceFile() = 0;
};
public:
//! \brief Constructor.
EvalContext();
//! \brief Destructor.
virtual ~EvalContext();
//! \name Source file manager
//@{
//! \brief
void setSourceFileManager(SourceFileManager *manager) { m_sourcesManager = manager; }
//! \brief
SourceFileManager *getSourceFileManager() { return m_sourcesManager; }
//@}
//! \name Variables
//@{
bool isVariableDefined(const std::string &name);
uint32_t getVariableValue(const std::string &name);
int_size_t getVariableSize(const std::string &name);
void setVariable(const std::string &name, uint32_t value, int_size_t size = kWordSize);
//@}
//! \name Locks
//@{
bool isVariableLocked(const std::string &name);
void lockVariable(const std::string &name);
void unlockVariable(const std::string &name);
//@}
void dump();
protected:
//! Information about a variable's value.
struct variable_info_t
{
uint32_t m_value; //!< Variable value.
int_size_t m_size; //!< Number of bytes
bool m_isLocked; //!< Can this variable's value be changed?
};
//! Type to maps between the variable name and its info.
typedef std::map<std::string, variable_info_t> variable_map_t;
SourceFileManager *m_sourcesManager; //!< Interface to source file manager.
variable_map_t m_variables; //!< Map of variables to their final values.
};
}; // namespace elftosb
#endif // _EvalContext_h_

View File

@@ -0,0 +1,87 @@
/*
* File: ExcludesListMatcher.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "ExcludesListMatcher.h"
using namespace elftosb;
ExcludesListMatcher::ExcludesListMatcher()
: GlobMatcher("")
{
}
ExcludesListMatcher::~ExcludesListMatcher()
{
}
//! \param isInclude True if this pattern is an include, false if it is an exclude.
//! \param pattern String containing the glob pattern.
void ExcludesListMatcher::addPattern(bool isInclude, const std::string &pattern)
{
glob_list_item_t item;
item.m_isInclude = isInclude;
item.m_glob = pattern;
// add to end of list
m_patterns.push_back(item);
}
//! If there are no entries in the match list, the match fails.
//!
//! \param testValue The string to match against the pattern list.
//! \retval true The \a testValue argument matches.
//! \retval false No match was made against the argument.
bool ExcludesListMatcher::match(const std::string &testValue)
{
if (!m_patterns.size())
{
return false;
}
// Iterate over the match list. Includes act as an OR operator, while
// excludes act as an AND operator.
bool didMatch = false;
bool isFirstItem = true;
glob_list_t::iterator it = m_patterns.begin();
for (; it != m_patterns.end(); ++it)
{
glob_list_item_t &item = *it;
// if this pattern is an include and it doesn't match, or
// if this pattern is an exclude and it does match, then the match fails
bool didItemMatch = globMatch(testValue.c_str(), item.m_glob.c_str());
if (item.m_isInclude)
{
// Include
if (isFirstItem)
{
didMatch = didItemMatch;
}
else
{
didMatch = didMatch || didItemMatch;
}
}
else
{
// Exclude
if (isFirstItem)
{
didMatch = !didItemMatch;
}
else
{
didMatch = didMatch && !didItemMatch;
}
}
isFirstItem = false;
}
return didMatch;
}

View File

@@ -0,0 +1,66 @@
/*
* File: ExcludesListMatcher.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_ExcludesListMatcher_h_)
#define _ExcludesListMatcher_h_
#include "GlobMatcher.h"
#include <vector>
#include <string>
namespace elftosb
{
/*!
* \brief Matches strings using a series of include and exclude glob patterns.
*
* This string matcher class uses a sequential, ordered list of glob patterns to
* determine whether a string matches. Attached to each pattern is an include/exclude
* action. The patterns in the list effectively form a Boolean expression. Includes
* act as an OR operator while excludes act as an AND NOT operator.
*
* Examples (plus prefix is include, minus prefix is exclude):
* - +foo: foo
* - -foo: !foo
* - +foo, +bar: foo || bar
* - +foo, -bar: foo && !bar
* - +foo, -bar, +baz: foo && !bar || baz
*
* The only reason for inheriting from GlobMatcher is so we can access the protected
* globMatch() method.
*/
class ExcludesListMatcher : public GlobMatcher
{
public:
//! \brief Default constructor.
ExcludesListMatcher();
//! \brief Destructor.
~ExcludesListMatcher();
//! \name Pattern list
//@{
//! \brief Add one include or exclude pattern to the end of the match list.
void addPattern(bool isInclude, const std::string &pattern);
//@}
//! \brief Performs a single string match test against testValue.
virtual bool match(const std::string &testValue);
protected:
//! \brief Information about one glob pattern entry in a match list.
struct glob_list_item_t
{
bool m_isInclude; //!< True if include, false if exclude.
std::string m_glob; //!< The glob pattern to match.
};
typedef std::vector<glob_list_item_t> glob_list_t;
glob_list_t m_patterns; //!< Ordered list of include and exclude patterns.
};
}; // namespace elftosb
#endif // _ExcludesListMatcher_h_

View File

@@ -0,0 +1,103 @@
/*
* File: GHSSecInfo.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "GHSSecInfo.h"
#include <stdexcept>
#include "Logging.h"
#include "EndianUtilities.h"
//! The name of the GHS-specific section info table ELF section.
const char *const kSecInfoSectionName = ".secinfo";
using namespace elftosb;
//! The ELF file passed into this constructor as the \a elf argument must remain
//! valid for the life of this object.
//!
//! \param elf The ELF file parser. An assertion is raised if this is NULL.
GHSSecInfo::GHSSecInfo(StELFFile *elf)
: m_elf(elf)
, m_hasInfo(false)
, m_info(0)
, m_entryCount(0)
{
assert(elf);
// look up the section. if it's not there just leave m_info and m_entryCount to 0
unsigned sectionIndex = m_elf->getIndexOfSectionWithName(kSecInfoSectionName);
if (sectionIndex == SHN_UNDEF)
{
return;
}
// get the section data
const Elf32_Shdr &secInfo = m_elf->getSectionAtIndex(sectionIndex);
if (secInfo.sh_type != SHT_PROGBITS)
{
// .secinfo section isn't the right type, so something is wrong
return;
}
m_hasInfo = true;
m_info = (ghs_secinfo_t *)m_elf->getSectionDataAtIndex(sectionIndex);
m_entryCount = secInfo.sh_size / sizeof(ghs_secinfo_t);
}
//! Looks up \a addr for \a length in the .secinfo array. Only if that address is in the
//! .secinfo array does this section need to be filled. If the section is found but the
//! length does not match the \a length argument, a message is logged at the
//! #Logger::WARNING level.
//!
//! If the .secinfo section is not present in the ELF file, this method always returns
//! true.
//!
//! \param addr The start address of the section to query.
//! \param length The length of the section. If a section with a start address matching
//! \a addr is found, its length must match \a length to be considered.
//!
//! \retval true The section matching \a addr and \a length was found and should be filled.
//! True is also returned when the ELF file does not have a .secinfo section.
//! \retval false The section was not found and should not be filled.
bool GHSSecInfo::isSectionFilled(uint32_t addr, uint32_t length)
{
if (!m_hasInfo)
{
return true;
}
unsigned i;
for (i = 0; i < m_entryCount; ++i)
{
// byte swap these values into host endianness
uint32_t clearAddr = ENDIAN_LITTLE_TO_HOST_U32(m_info[i].m_clearAddr);
uint32_t numBytesToClear = ENDIAN_LITTLE_TO_HOST_U32(m_info[i].m_numBytesToClear);
// we only consider non-zero length clear regions
if ((addr == clearAddr) && (numBytesToClear != 0))
{
// it is an error if the address matches but the length does not
if (length != numBytesToClear)
{
Log::log(Logger::WARNING, "ELF Error: Size mismatch @ sect=%u, .secinfo=%u at addr 0x%08X\n", length,
numBytesToClear, addr);
}
return true;
}
}
return false;
}
//! Simply calls through to isSectionFilled(uint32_t, uint32_t) to determine
//! if \a section should be filled.
//!
//! If the .secinfo section is not present in the ELF file, this method always returns
//! true.
bool GHSSecInfo::isSectionFilled(const Elf32_Shdr &section)
{
return isSectionFilled(section.sh_addr, section.sh_size);
}

View File

@@ -0,0 +1,70 @@
/*
* File: GHSSecInfo.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_GHSSecInfo_h_)
#define _GHSSecInfo_h_
#include "StELFFile.h"
#include "smart_ptr.h"
namespace elftosb
{
/*!
* \brief Wrapper around the GHS-specific .secinfo ELF section.
*
* ELF files produced by the Green Hills MULTI toolset will have a
* special .secinfo section. For the most part, this section contains
* a list of address
* ranges that should be filled by the C runtime startup code. The
* address ranges correspond to those of ELF sections whose type is
* #SHT_NOBITS. The GHS runtime uses this table instead of just filling
* all #SHT_NOBITS sections because the linker command file can
* be used to optionally not fill individual sections.
*
* The isSectionFilled() methods let calling code determine if an ELF
* section is found in the .secinfo table. If the section is found,
* then it should be filled.
*/
class GHSSecInfo
{
public:
//! \brief Default constructor.
GHSSecInfo(StELFFile *elf);
//! \brief Returns true if there is a .secinfo section present in the ELF file.
bool hasSecinfo() const { return m_hasInfo; }
//! \brief Determines if a section should be filled.
bool isSectionFilled(uint32_t addr, uint32_t length);
//! \brief Determines if \a section should be filled.
bool isSectionFilled(const Elf32_Shdr &section);
protected:
#pragma pack(1)
/*!
* \brief The structure of one .secinfo entry.
*/
struct ghs_secinfo_t
{
uint32_t m_clearAddr; //!< Address to start filling from.
uint32_t m_clearValue; //!< Value to fill with.
uint32_t m_numBytesToClear; //!< Number of bytes to fill.
};
#pragma pack()
protected:
StELFFile *m_elf; //!< The parser object for our ELF file.
bool m_hasInfo; //!< Whether .secinfo is present in the ELF file.
smart_array_ptr<ghs_secinfo_t>
m_info; //!< Pointer to the .secinfo entries. Will be NULL if there is no .secinfo section in the file.
unsigned m_entryCount; //!< Number of entries in #m_info.
};
}; // namespace elftosb
#endif // _GHSSecInfo_h_

View File

@@ -0,0 +1,135 @@
/*
* File: GlobMatcher.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "GlobMatcher.h"
#ifndef NEGATE
#define NEGATE '^' // std cset negation char
#endif
using namespace elftosb;
//! The glob pattern must match the \e entire test value argument in order
//! for the match to be considered successful. Thus, even if, for example,
//! the pattern matches all but the last character the result will be false.
//!
//! \retval true The test value does match the glob pattern.
//! \retval false The test value does not match the glob pattern.
bool GlobMatcher::match(const std::string &testValue)
{
return globMatch(testValue.c_str(), m_pattern.c_str());
}
//! \note This glob implementation was originally written by ozan s. yigit in
//! December 1994. This is public domain source code.
bool GlobMatcher::globMatch(const char *str, const char *p)
{
int negate;
int match;
int c;
while (*p)
{
if (!*str && *p != '*')
return false;
switch (c = *p++)
{
case '*':
while (*p == '*')
p++;
if (!*p)
return true;
if (*p != '?' && *p != '[' && *p != '\\')
while (*str && *p != *str)
str++;
while (*str)
{
if (globMatch(str, p))
return true;
str++;
}
return false;
case '?':
if (*str)
break;
return false;
// set specification is inclusive, that is [a-z] is a, z and
// everything in between. this means [z-a] may be interpreted
// as a set that contains z, a and nothing in between.
case '[':
if (*p != NEGATE)
negate = false;
else
{
negate = true;
p++;
}
match = false;
while (!match && (c = *p++))
{
if (!*p)
return false;
if (*p == '-')
{ // c-c
if (!*++p)
return false;
if (*p != ']')
{
if (*str == c || *str == *p || (*str > c && *str < *p))
match = true;
}
else
{ // c-]
if (*str >= c)
match = true;
break;
}
}
else
{ // cc or c]
if (c == *str)
match = true;
if (*p != ']')
{
if (*p == *str)
match = true;
}
else
break;
}
}
if (negate == match)
return false;
// if there is a match, skip past the cset and continue on
while (*p && *p != ']')
p++;
if (!*p++) // oops!
return false;
break;
case '\\':
if (*p)
c = *p++;
default:
if (c != *str)
return false;
break;
}
str++;
}
return !*str;
}

View File

@@ -0,0 +1,59 @@
/*
* File: GlobMatcher.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_GlobMatcher_h_)
#define _GlobMatcher_h_
#include "StringMatcher.h"
namespace elftosb
{
/*!
* \brief This class uses glob pattern matching to match strings.
*
* Glob patterns:
* - * matches zero or more characters
* - ? matches any single character
* - [set] matches any character in the set
* - [^set] matches any character NOT in the set
* where a set is a group of characters or ranges. a range
* is written as two characters seperated with a hyphen: a-z denotes
* all characters between a to z inclusive.
* - [-set] set matches a literal hypen and any character in the set
* - []set] matches a literal close bracket and any character in the set
*
* - char matches itself except where char is '*' or '?' or '['
* - \\char matches char, including any pattern character
*
* Examples:
* - a*c ac abc abbc ...
* - a?c acc abc aXc ...
* - a[a-z]c aac abc acc ...
* - a[-a-z]c a-c aac abc ...
*/
class GlobMatcher : public StringMatcher
{
public:
//! \brief Constructor.
GlobMatcher(const std::string &pattern)
: StringMatcher()
, m_pattern(pattern)
{
}
//! \brief Returns whether \a testValue matches the glob pattern.
virtual bool match(const std::string &testValue);
protected:
std::string m_pattern; //!< The glob pattern to match against.
//! \brief Glob implementation.
bool globMatch(const char *str, const char *p);
};
}; // namespace elftosb
#endif // _GlobMatcher_h_

View File

@@ -0,0 +1,34 @@
/*
* File: HexValues.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "HexValues.h"
bool isHexDigit(char c)
{
return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
//! \return The integer equivalent to \a c.
//! \retval -1 The character \a c is not a hex character.
uint8_t hexCharToInt(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
else
return static_cast<uint8_t>(-1);
}
//! \param encodedByte Must point to at least two ASCII hex characters.
//!
uint8_t hexByteToInt(const char *encodedByte)
{
return (hexCharToInt(encodedByte[0]) << 4) | hexCharToInt(encodedByte[1]);
}

View File

@@ -0,0 +1,21 @@
/*
* File: HexValues.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_HexValues_h_)
#define _HexValues_h_
#include "stdafx.h"
//! \brief Determines whether \a c is a hex digit character.
bool isHexDigit(char c);
//! \brief Converts a hexidecimal character to the integer equivalent.
uint8_t hexCharToInt(char c);
//! \brief Converts a hex-encoded byte to the integer equivalent.
uint8_t hexByteToInt(const char *encodedByte);
#endif // _HexValues_h_

View File

@@ -0,0 +1,111 @@
/*
* File: DataSource.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
*
* Freescale Semiconductor, Inc.
* Proprietary & Confidential
*
* This source code and the algorithms implemented therein constitute
* confidential information and may comprise trade secrets of Freescale Semiconductor, Inc.
* or its associates, and any use thereof is subject to the terms and
* conditions of the Confidential Disclosure Agreement pursual to which this
* source code was originally received.
*/
#include "IVTDataSource.h"
#include "DataTarget.h"
#include "EndianUtilities.h"
#include <algorithm>
#include <stdlib.h>
#include <string.h>
using namespace elftosb;
IVTDataSource::IVTDataSource()
: DataSource()
, DataSource::Segment((DataSource &)*this)
, m_isSelfSet(false)
{
// Init the IVT structure.
memset(&m_ivt, 0, sizeof(m_ivt));
hab_hdr_t hdr = IVT_HDR(sizeof(m_ivt), HAB_VERSION);
m_ivt.hdr = hdr;
}
unsigned IVTDataSource::getData(unsigned offset, unsigned maxBytes, uint8_t *buffer)
{
// Bail if the offset is out of range.
if (offset >= sizeof(m_ivt))
{
return 0;
}
// If we have an associated target, and the IVT self pointer is not set, then
// fill in the self pointer from the target address.
if (m_target && !m_isSelfSet)
{
m_ivt.self = ENDIAN_HOST_TO_LITTLE_U32(m_target->getBeginAddress());
}
// Truncate max bytes at the end of the IVT.
maxBytes = std::min<unsigned>(maxBytes, sizeof(m_ivt) - offset);
// Copy into output buffer.
if (maxBytes)
{
memcpy(buffer, (uint8_t *)&m_ivt + offset, maxBytes);
}
return maxBytes;
}
unsigned IVTDataSource::getLength()
{
return sizeof(m_ivt);
}
//! The IVT has a natural location if its self pointer was explicitly specified.
//!
bool IVTDataSource::hasNaturalLocation()
{
return m_isSelfSet;
}
//!
uint32_t IVTDataSource::getBaseAddress()
{
return m_ivt.self;
}
bool IVTDataSource::setFieldByName(const std::string &name, uint32_t value)
{
if (name == "entry")
{
m_ivt.entry = ENDIAN_HOST_TO_LITTLE_U32(value);
}
else if (name == "dcd")
{
m_ivt.dcd = ENDIAN_HOST_TO_LITTLE_U32(value);
}
else if (name == "boot_data")
{
m_ivt.boot_data = ENDIAN_HOST_TO_LITTLE_U32(value);
}
else if (name == "self")
{
m_ivt.self = ENDIAN_HOST_TO_LITTLE_U32(value);
m_isSelfSet = true;
}
else if (name == "csf")
{
m_ivt.csf = ENDIAN_HOST_TO_LITTLE_U32(value);
}
else
{
// Unrecognized field name.
return false;
}
return true;
}

View File

@@ -0,0 +1,285 @@
/*
* File: DataSource.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
*
* Freescale Semiconductor, Inc.
* Proprietary & Confidential
*
* This source code and the algorithms implemented therein constitute
* confidential information and may comprise trade secrets of Freescale Semiconductor, Inc.
* or its associates, and any use thereof is subject to the terms and
* conditions of the Confidential Disclosure Agreement pursual to which this
* source code was originally received.
*/
#if !defined(_IVTDataSource_h_)
#define _IVTDataSource_h_
#include "DataSource.h"
/** Header field components
* @ingroup hdr
*/
typedef struct hab_hdr
{
uint8_t tag; /**< Tag field */
uint8_t len[2]; /**< Length field in bytes (big-endian) */
uint8_t par; /**< Parameters field */
} hab_hdr_t;
/** Image entry function prototype
* @ingroup rvt
*
* This typedef serves as the return type for hab_rvt.authenticate_image(). It
* specifies a void-void function pointer, but can be cast to another function
* pointer type if required.
*/
typedef void (*hab_image_entry_f)(void);
/** @ref ivt structure
* @ingroup ivt
*
* @par Format
*
* An @ref ivt consists of a @ref hdr followed by a list of addresses as
* described further below.
*
* @warning The @a entry address may not be NULL.
*
* @warning On an IC not configured as #HAB_CFG_CLOSED, the
* @a csf address may be NULL. If it is not NULL, the @ref csf will be
* processed, but any failures should be non-fatal.
*
* @warning On an IC configured as #HAB_CFG_CLOSED, the @a
* csf address may not be NULL, and @ref csf failures are typically fatal.
*
* @remark The Boot Data located using the @a boot_data field is interpreted
* by the HAB caller in a boot-mode specific manner. This may be used by the
* boot ROM as to determine the load address and boot device configuration for
* images loaded from block devices (see @ref ref_rug for details).
*
* @remark All addresses given in the IVT, including the Boot Data (if
* present) are those for the final load location.
*
* @anchor ila
*
* @par Initial load addresses
*
* The @a self field is used to calculate addresses in boot modes where an
* initial portion of the image is loaded to an initial location. In such
* cases, the IVT, Boot Data (if present) and DCD (if present) are used in
* configuring the IC and loading the full image to its final location. Only
* the IVT, Boot Data (if present) and DCD (if present) are required to be
* within the initial image portion.
*
* The method for calculating an initial load address for the DCD is
* illustrated in the following C fragment. Similar calculations apply to
* other fields.
*
@verbatim
hab_ivt_t* ivt_initial = <initial IVT load address>;
const void* dcd_initial = ivt_initial->dcd;
if (ivt_initial->dcd != NULL)
dcd_initial = (const uint8_t*)ivt_initial
+ (ivt_initial->dcd - ivt_initial->self)
@endverbatim
* \note The void* types in this structure have been changed to uint32_t so
* that this code will work correctly when compiled on a 64-bit host.
* Otherwise the structure would come out incorrect.
*/
struct hab_ivt
{
/** @ref hdr with tag #HAB_TAG_IVT, length and HAB version fields
* (see @ref data)
*/
hab_hdr_t hdr;
/** Absolute address of the first instruction to execute from the
* image
*/
/*hab_image_entry_f*/ uint32_t entry;
/** Reserved in this version of HAB: should be NULL. */
/*const void*/ uint32_t reserved1;
/** Absolute address of the image DCD: may be NULL. */
/*const void*/ uint32_t dcd;
/** Absolute address of the Boot Data: may be NULL, but not interpreted
* any further by HAB
*/
/*const void*/ uint32_t boot_data;
/** Absolute address of the IVT.*/
/*const void*/ uint32_t self;
/** Absolute address of the image CSF.*/
/*const void*/ uint32_t csf;
/** Reserved in this version of HAB: should be zero. */
uint32_t reserved2;
};
/** @ref ivt type
* @ingroup ivt
*/
typedef struct hab_ivt hab_ivt_t;
/*
* Helper macros
*/
#define HAB_CMD_UNS 0xff
#define DEFAULT_IMG_KEY_IDX 2
#define GEN_MASK(width) ((1UL << (width)) - 1)
#define GEN_FIELD(f, width, shift) (((f)&GEN_MASK(width)) << (shift))
#define PACK_UINT32(a, b, c, d) ((((a)&0xFF) << 24) | (((b)&0xFF) << 16) | (((c)&0xFF) << 8) | (((d)&0xFF)))
#define EXPAND_UINT32(w) (uint8_t)((w) >> 24), (uint8_t)((w) >> 16), (uint8_t)((w) >> 8), (uint8_t)(w)
#define HDR(tag, bytes, par) (uint8_t)(tag), (uint8_t)((bytes) >> 8), (uint8_t)(bytes), (uint8_t)(par)
#define HAB_VER(maj, min) \
(GEN_FIELD((maj), HAB_VER_MAJ_WIDTH, HAB_VER_MAJ_SHIFT) | GEN_FIELD((min), HAB_VER_MIN_WIDTH, HAB_VER_MIN_SHIFT))
/*
* CSF header
*/
#define CSF_HDR(bytes, HABVER) HDR(HAB_TAG_CSF, (bytes), HABVER)
/*
* DCD header
*/
#define DCD_HDR(bytes, HABVER) HDR(HAB_TAG_DCD, (bytes), HABVER)
/*
* IVT header (goes in the struct's hab_hdr_t field, not a byte array)
*/
#define IVT_HDR(bytes, HABVER) \
{ \
HAB_TAG_IVT, { (uint8_t)((bytes) >> 8), (uint8_t)(bytes) }, HABVER \
}
/** @name External data structure tags
* @anchor dat_tag
*
* Tag values 0x00 .. 0xef are reserved for HAB. Values 0xf0 .. 0xff
* are available for custom use.
*/
/*@{*/
#define HAB_TAG_IVT 0xd1 /**< Image Vector Table */
#define HAB_TAG_DCD 0xd2 /**< Device Configuration Data */
#define HAB_TAG_CSF 0xd4 /**< Command Sequence File */
#define HAB_TAG_CRT 0xd7 /**< Certificate */
#define HAB_TAG_SIG 0xd8 /**< Signature */
#define HAB_TAG_EVT 0xdb /**< Event */
#define HAB_TAG_RVT 0xdd /**< ROM Vector Table */
/* Values b0 ... cf reserved for CSF commands. Values e0 ... ef reserved for
* key types.
*
* Available values: 03, 05, 06, 09, 0a, 0c, 0f, 11, 12, 14, 17, 18, 1b, 1d,
* 1e, 21, 22, 24, 27, 28, 2b, 2d, 2e, 30, 33, 35, 36, 39, 3a, 3c, 3f, 41, 42,
* 44, 47, 48, 4b, 4d, 4e, 50, 53, 55, 56, 59, 5a, 5c, 5f, 60, 63, 65, 66, 69,
* 6a, 6c, 6f, 71, 72, 74, 77, 78, 7b, 7d, 7e, 81, 82, 84, 87, 88, 8b, 8d, 8e,
* 90, 93, 95, 96, 99, 9a, 9c, 9f, a0, a3, a5, a6, a9, aa, ac, af, b1, b2, b4,
* b7, b8, bb, bd, be
*
* Custom values: f0, f3, f5, f6, f9, fa, fc, ff
*/
/*@}*/
/** @name HAB version */
/*@{*/
#define HAB_MAJOR_VERSION 4 /**< Major version of this HAB release */
#define HAB_MINOR_VERSION 0 /**< Minor version of this HAB release */
#define HAB_VER_MAJ_WIDTH 4 /**< Major version field width */
#define HAB_VER_MAJ_SHIFT 4 /**< Major version field offset */
#define HAB_VER_MIN_WIDTH 4 /**< Minor version field width */
#define HAB_VER_MIN_SHIFT 0 /**< Minor version field offset */
/** Full version of this HAB release @hideinitializer */
#define HAB_VERSION HAB_VER(HAB_MAJOR_VERSION, HAB_MINOR_VERSION)
/** Base version for this HAB release @hideinitializer */
#define HAB_BASE_VERSION HAB_VER(HAB_MAJOR_VERSION, 0)
/*@}*/
namespace elftosb
{
/*!
* \brief Data source for an IVT structure used by HAB4.
*
* This data source represents an IVT structure used by HAB4. Fields of the IVT can be set
* by name, making it easy to interface with a parser. And it has some intelligence regarding
* the IVT's self pointer. Before the data is copied out by the getData() method, the self field
* will be filled in automatically if it has not already been set and there is an associated
* data target object. This lets the IVT pick up its own address from the location where it is
* being loaded. Alternatively, if the self pointer is filled in explicitly, then the data
* source will have a natural location equal to the self pointer.
*
* This data source acts as its own segment.
*/
class IVTDataSource : public DataSource, public DataSource::Segment
{
public:
//! \brief Default constructor.
IVTDataSource();
//! \brief There is only one segment.
virtual unsigned getSegmentCount() { return 1; }
//! \brief Returns this object, as it is its own segment.
virtual DataSource::Segment *getSegmentAt(unsigned index) { return this; }
//! \name Segment methods
//@{
//! \brief Copy out some or all of the IVT structure.
//!
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer);
//! \brief Gets the length of the segment's data.
virtual unsigned getLength();
//! \brief Returns whether the segment has an associated address.
virtual bool hasNaturalLocation();
//! \brief Returns the address associated with the segment.
virtual uint32_t getBaseAddress();
//@}
//! \name IVT access
//@{
//! \brief Set one of the IVT's fields by providing its name.
//!
//! Acceptable field names are:
//! - entry
//! - dcd
//! - boot_data
//! - self
//! - csf
//!
//! As long as the \a name parameter specifies one of these fields, the return value
//! will be true. If \a name contains any other value, then false will be returned and
//! the IVT left unmodified.
//!
//! Once the \a self field has been set to any value, the data source will have a
//! natural location. This works even if the \a self address is 0.
//!
//! \param name The name of the field to set. Field names are case sensitive, just like in
//! the C language.
//! \param value The value to which the field will be set.
//! \retval true The field was set successfully.
//! \retval false There is no field with the provided name.
bool setFieldByName(const std::string &name, uint32_t value);
//! \brief Returns a reference to the IVT structure.
hab_ivt_t &getIVT() { return m_ivt; }
//@}
protected:
hab_ivt_t m_ivt; //!< The IVT structure.
bool m_isSelfSet; //!< True if the IVT self pointer was explicitly set.
};
} // elftosb
#endif // _IVTDataSource_h_

View File

@@ -0,0 +1,376 @@
/*
* File: Keyblob.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include <cstring>
#include <algorithm>
#include <sstream>
#include <fstream>
#if WIN32
#include <intrin.h>
#endif
#include <stdio.h>
#include "Keyblob.h"
#include "Logging.h"
#include "aes128_key_wrap_unwrap.h"
#include "crc.h"
#include "RijndaelCTR.h"
#define PRINT_KEYBLOB 0
#define DEBUG_DATA 0
// From bytes_aes.c.
extern "C" void KeyExpansion(unsigned char ckey[], int nbits, unsigned int w[]);
using namespace elftosb;
void Keyblob::encrypt(uint32_t length, uint8_t *data, AESKey<128> *key, AESCounter<128> *counter)
{
// Create counter mode encrypter.
RijndaelCTR encrypter(*key, *counter);
uint32_t tempBlock[k_encryptBlockSize / sizeof(uint32_t)];
uint32_t bytesEncrypted = 0;
const uint32_t blockSize = k_encryptBlockSize;
// length must be a multiple of k_blockSize and k_qspiAlignlength.
assert(length && !(length % blockSize) && !(length % k_qspiAlignlength));
// Encrypt all blocks of data from the image.
while (bytesEncrypted < length)
{
memset(tempBlock, 0, sizeof(tempBlock));
// Copy in plaintext data.
memcpy(tempBlock, data, blockSize);
// We endian swap each uint32_t in the block and then swap word 0 <-> word 1 and word 2 <-> word 3
// to counter for endian issues and 64 bit writes on the device with a QSPI configuration for 64 bit LE
// this lets unencrypted byte streams as well as this encrypted byte stream be transparently used by the driver
#if WIN32
tempBlock[0] = _byteswap_ulong(tempBlock[0]);
tempBlock[1] = _byteswap_ulong(tempBlock[1]);
tempBlock[2] = _byteswap_ulong(tempBlock[2]);
tempBlock[3] = _byteswap_ulong(tempBlock[3]);
#else
tempBlock[0] = __builtin_bswap32(tempBlock[0]);
tempBlock[1] = __builtin_bswap32(tempBlock[1]);
tempBlock[2] = __builtin_bswap32(tempBlock[2]);
tempBlock[3] = __builtin_bswap32(tempBlock[3]);
#endif
std::swap(tempBlock[0], tempBlock[1]);
std::swap(tempBlock[2], tempBlock[3]);
encrypter.encrypt((uint8_t *)tempBlock, sizeof(tempBlock), (uint8_t *)tempBlock);
// Reverse the above transform so that it is back in its original order when decrypted
std::swap(tempBlock[0], tempBlock[1]);
std::swap(tempBlock[2], tempBlock[3]);
#if WIN32
tempBlock[0] = _byteswap_ulong(tempBlock[0]);
tempBlock[1] = _byteswap_ulong(tempBlock[1]);
tempBlock[2] = _byteswap_ulong(tempBlock[2]);
tempBlock[3] = _byteswap_ulong(tempBlock[3]);
#else
tempBlock[0] = __builtin_bswap32(tempBlock[0]);
tempBlock[1] = __builtin_bswap32(tempBlock[1]);
tempBlock[2] = __builtin_bswap32(tempBlock[2]);
tempBlock[3] = __builtin_bswap32(tempBlock[3]);
#endif
// Overwrite plaintext data with enrypted data.
std::memcpy(data, tempBlock, blockSize);
bytesEncrypted += blockSize;
data += blockSize;
}
}
AESCounter<128> *buildCounter(const std::string &counterVal, uint32_t startAddress)
{
/* CTRn_x[127-0] = {CTR_W0_x[C0...C3], // 32 bits of pre-programmed CTR
CTR_W1_x[C4...C7], // another 32 bits of CTR
CTR_W0_x[C0...C3] ^ CTR_W1_x[C4...C7], // exclusive-OR of CTR values
systemAddress[31-4], 0000b} // 0-modulo-16 system address */
assert(counterVal.size() == 16); // We need 16 characters for the counter value
assert(!(startAddress % 16)); // Start adress has to be 16 byte aligned
AESCounter<128>::counter_t counter;
std::string counterW0String = counterVal.substr(0, 8);
std::string counterW1String = counterVal.substr(8, 8);
uint32_t counterW0 = strtoul(counterW0String.c_str(), NULL, 16);
uint32_t counterW1 = strtoul(counterW1String.c_str(), NULL, 16);
uint32_t counterXOR = counterW0 ^ counterW1;
// Form the collected data into a 16 byte array
counter[15] = startAddress & 0xFF;
counter[14] = (startAddress & 0xFF00) >> 8;
counter[13] = static_cast<uint8_t>((startAddress & 0xFF0000) >> 16);
counter[12] = (startAddress & 0xFF000000) >> 24;
counter[11] = counterXOR & 0xFF;
counter[10] = (counterXOR & 0xFF00) >> 8;
counter[9] = static_cast<uint8_t>((counterXOR & 0xFF0000) >> 16);
counter[8] = (counterXOR & 0xFF000000) >> 24;
counter[7] = counterW1 & 0xFF;
counter[6] = (counterW1 & 0xFF00) >> 8;
counter[5] = static_cast<uint8_t>((counterW1 & 0xFF0000) >> 16);
counter[4] = (counterW1 & 0xFF000000) >> 24;
counter[3] = counterW0 & 0xFF;
counter[2] = (counterW0 & 0xFF00) >> 8;
counter[1] = static_cast<uint8_t>((counterW0 & 0xFF0000) >> 16);
counter[0] = (counterW0 & 0xFF000000) >> 24;
return new AESCounter<128>(counter); // caller must deallocate
}
bool Keyblob::encryptMatchingRange(uint32_t start, uint32_t len, uint8_t *data)
{
assert(data);
option_vector_t *options = getOptions();
unsigned matchedCount = 0;
#if DEBUG_DATA
std::ofstream qspiBin("enc.bin", std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
#endif
// Go through each option entry to find matching range.
// Encrypt the data in place.
option_vector_t::iterator it = options->begin();
for (; it != options->end(); ++it)
{
uint32_t entryStart = 0;
uint32_t entryEnd = 0;
const char *keyHex = NULL;
const char *counterHex = NULL;
// Ignore entry if not all options are present.
if (!getOptionValues(**it, &keyHex, &counterHex, &entryStart, &entryEnd))
{
continue;
}
// Start address must exactly match region address.
// Region addersses are already forced to modulo 1024.
if (entryStart == start)
{
// Build counter value.
std::string counterStr(counterHex);
AESCounter<128> *counter = buildCounter(counterStr, start);
// Build key value.
AESKey<128> key;
std::stringstream infoStream;
infoStream << keyHex;
key.readFromStream(infoStream);
Log::log(Logger::INFO2, "creating encrypted range 0x%x len 0x%x\n", start, len);
++matchedCount;
encrypt(len, data, &key, counter);
#if DEBUG_DATA
qspiBin.write(reinterpret_cast<char *>(data), 0x400);
#endif
delete counter;
break; // only one entry is processed per base address
}
}
return (matchedCount > 0);
}
void hexToBytes(const char *hexStr, unsigned char *bytes, int numBytes)
{
for (int i = 0; i < numBytes; ++i)
{
char digitBuf[3];
digitBuf[0] = *hexStr++;
digitBuf[1] = *hexStr++;
digitBuf[2] = '\0';
bytes[i] = (unsigned char)strtoul(digitBuf, NULL, 16);
}
}
void Keyblob::populateKeyBlob(keyblob_t *blob, uint32_t start, uint32_t end, const char *keyHex, const char *counterHex)
{
// Populate key value.
hexToBytes(keyHex, blob->key, sizeof(blob->key));
// Poplulate Counter value.
hexToBytes(counterHex, blob->ctr, sizeof(blob->ctr));
blob->srtaddr = start & ~kRegionAddrMask;
blob->endaddr = end | kRegionAddrMask;
// Add default flags to endaddr register.
blob->endaddr &= ~kFlagMask;
blob->endaddr |= kKeyFlags;
// Add CRC32.
uint32_t result;
CRC32 crc;
crc.update(reinterpret_cast<uint8_t *>(blob), kCrc32SizeBytes);
crc.truncatedFinal(reinterpret_cast<uint8_t *>(&result), sizeof(result));
blob->key_blob_crc32 = result;
}
uint8_t *Keyblob::createWrappedKeyblobData(uint8_t *kek, uint32_t *byteCount)
{
assert(kek);
assert(byteCount);
option_vector_t *options = getOptions();
uint32_t entryCount = options->size();
uint8_t *unwrappedData = new uint8_t[entryCount * sizeof(keyblob_t)];
keyblob_t *blob = (keyblob_t *)&unwrappedData[0];
uint8_t *wrappedData = new uint8_t[entryCount * sizeof(keyblob_t)];
uint8_t *wrapped = wrappedData;
// Create expanded KeK for AES128 encryption.
unsigned int *expandedKek = new unsigned int[kExpandedKekSizeInts];
KeyExpansion(reinterpret_cast<unsigned char *>(&kek[0]), kKeySizeBits, expandedKek);
option_vector_t::iterator it = options->begin();
for (; it != options->end(); ++it)
{
uint32_t start = 0;
uint32_t end = 0;
const char *keyHex = NULL;
const char *counterHex = NULL;
// If not all options are present, make it a null entry.
bool isValidEntry = getOptionValues(**it, &keyHex, &counterHex, &start, &end);
// Clear this wrapped entry.
memset(wrapped, 0, kKeyBlobSizeBytes);
if (isValidEntry)
{
// Fill in keyblob data.
memset(blob, 0, sizeof(keyblob_t));
populateKeyBlob(blob, start, end, keyHex, counterHex);
#if PRINT_KEYBLOB
uint8_t *keyData = reinterpret_cast<uint8_t *>(blob);
Log::log(" ;plaintext\n");
for (int i = 0; i < kKeyBlobSizeBytes / kOutputLineSize; ++i)
{
Log::log(" ; ");
for (int j = 0; j < kOutputLineSize - 1; ++j)
{
Log::log("0x%02x, ", *keyData++);
}
Log::log("0x%02x\n", *keyData++);
}
#endif
// Wrap keyblob entry.
do_aes128_key_wrap(reinterpret_cast<uint8_t *>(blob), wrapped, expandedKek);
#if PRINT_KEYBLOB
keyData = wrapped;
Log::log(" ;wrapped\n");
for (int i = 0; i < kKeyBlobSizeBytes / kOutputLineSize; ++i)
{
printf(" DC8 ");
for (int j = 0; j < kOutputLineSize - 1; ++j)
{
printf("0x%02x, ", *keyData++);
}
printf("0x%02x\n", *keyData++);
}
#endif
}
// Next unwrapped and wrapped keyblob data pointers.
++blob;
wrapped += sizeof(keyblob_t);
}
delete[] expandedKek;
delete[] unwrappedData;
*byteCount = entryCount * sizeof(keyblob_t);
return wrappedData; // must be deleted by caller
}
bool Keyblob::getOptionValues(OptionContext &opt, const char **key, const char **ctr, uint32_t *start, uint32_t *end)
{
assert(key && ctr && start && end);
if (!(opt.hasOption(kKeyblobOptionNameStart) && opt.hasOption(kKeyblobOptionNameEnd) &&
opt.hasOption(kKeyblobOptionNameKey) && opt.hasOption(kKeyblobOptionNameCounter)))
{
return false;
}
if (opt.hasOption(kKeyblobOptionNameStart))
{
const Value *value = opt.getOption(kKeyblobOptionNameStart);
const IntegerValue *intValue = dynamic_cast<const IntegerValue *>(value);
if (!intValue)
{
Log::log(Logger::WARNING, "invalid type for %s option\n", kKeyblobOptionNameStart);
return false;
}
else
{
*start = intValue->getValue();
}
}
if (opt.hasOption(kKeyblobOptionNameEnd))
{
const Value *value = opt.getOption(kKeyblobOptionNameEnd);
const IntegerValue *intValue = dynamic_cast<const IntegerValue *>(value);
if (!intValue)
{
Log::log(Logger::WARNING, "invalid type for %s option\n", kKeyblobOptionNameEnd);
return false;
}
else
{
*end = intValue->getValue();
}
}
if (opt.hasOption(kKeyblobOptionNameKey))
{
const Value *value = opt.getOption(kKeyblobOptionNameKey);
const StringValue *stringValue = dynamic_cast<const StringValue *>(value);
if (!stringValue)
{
Log::log(Logger::WARNING, "invalid type for %s option\n", kKeyblobOptionNameKey);
return false;
}
else
{
*key = *stringValue;
}
}
if (opt.hasOption(kKeyblobOptionNameCounter))
{
const Value *value = opt.getOption(kKeyblobOptionNameCounter);
const StringValue *stringValue = dynamic_cast<const StringValue *>(value);
if (!stringValue)
{
Log::log(Logger::WARNING, "invalid type for %s option\n", kKeyblobOptionNameCounter);
return false;
}
else
{
*ctr = *stringValue;
}
}
return true;
}

View File

@@ -0,0 +1,120 @@
/*
* File: Keyblob.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_Keyblob_h_)
#define _Keyblob_h_
#include "smart_ptr.h"
#include "OptionContext.h"
#include "DataTarget.h"
#include "AESKey.h"
#include "AESCounter.h"
//! The names of the options.
#define kKeyblobOptionNameStart "start"
#define kKeyblobOptionNameEnd "end"
#define kKeyblobOptionNameKey "key"
#define kKeyblobOptionNameCounter "counter"
namespace elftosb
{
/*!
* @brief Keyblob specification.
*/
class Keyblob
{
public:
typedef std::vector<OptionContext *> option_vector_t; //!< List of options entries.
//! @brief Constants for encryption.
enum _encryption_constants
{
k_encryptBlockSize = 16, //!< Block size for AES-128 encryption
k_qspiAlignlength =
512 //!< QSPI image alignment length, 512 is supposed to be the safe alignment level for any QSPI device
//!< this means that all QSPI images generated by this tool will be sizes of multiple 512
};
public:
Keyblob()
: m_id(0)
, m_options(0)
{
}
Keyblob(uint32_t identifier)
: m_id(identifier)
, m_options(0)
{
}
virtual ~Keyblob() {}
static uint32_t getKekSizeBytes() { return kKekSizeBytes; }
void setIdentifier(uint32_t identifier) { m_id = identifier; }
uint32_t getIdentifier() const { return m_id; }
//! \brief Add options.
inline void addOptions(OptionContext *context) { m_options.push_back(context); }
//! \brief Return options vector.
inline option_vector_t *getOptions() { return &m_options; }
//! \brief Create and wrap keyblob data based on options.
//!
//! \retval Pointer to new wrapped data (caller must delete)
//! \retval Number of bytes in wrapped data
uint8_t *createWrappedKeyblobData(uint8_t *kek, uint32_t *byteCount);
//! \brief Encrypt for OTFAD if range is within a keyblob entry range.
//!
//! len must be a multiple of k_qspiAlignlength, which is also
//! a multiple of k_encryptBlockSize.
//!
//! \retval True if data was encrypted (range matched)
bool encryptMatchingRange(uint32_t start, uint32_t len, uint8_t *data);
protected:
//! @brief Keywrap constants.
enum _keywrap_constants
{
kKeySizeBits = 128, //!< AES-128
kExpandedKekSizeInts = 64, //!< Expanded KeK size
kNumKeyBlobs = 4, //!< Number of key blobs
kKeyBlobSizeBytes = 64, //!< Key blob size in bytes
kOutputLineSize = 16, //!< Number of bytes per output line
kRegionAddrMask = (0x400 - 1), //!< Region addresses are modulo 1024
kFlagMask = 0x07, //!< Key flags mask
kKeyFlags = 0x03, //!< Default flags: RO=0, ADE=1, VLD=1
kAesKeySizeBytes = 16, //!< Number of bytes in AES-128 key
kCtrSizeBytes = 8, //!< Number of bytes in Ctr
kKekSizeBytes = 16, //!< Number of bytes in KeK
kNumKeyChars = 32, //!< Number of characters in key string
kNumCtrChars = 16, //!< Number of characters in ctr string
kCrc32SizeBytes = 32 //!< Number of bytes covered by CRC32
};
//! @brief Key Blob format.
typedef struct KeyBlob
{
unsigned char key[kAesKeySizeBytes]; // 16 bytes, 128-bits, KEY[A15...A00]
unsigned char ctr[kCtrSizeBytes]; // 8 bytes, 64-bits, CTR[C7...C0]
unsigned int srtaddr; // region start, STRADDR[31 - 10]
unsigned int endaddr; // region end, ENDADDR[31 - 10]
// end of 32-byte area covered by CRC
unsigned int zero_fill; // zeros
unsigned int key_blob_crc32; // crc32 over 1st 32-bytes
// end of 40 byte (5*64-bit) key blob data
unsigned char expanded_wrap_data[8]; // 8 bytes, used for wrap expanded data
// end of 48 byte (6*64-bit) wrap data
unsigned char unused_filler[16]; // unused fill to 64 bytes
} keyblob_t;
void populateKeyBlob(keyblob_t *blob, uint32_t start, uint32_t end, const char *keyHex, const char *counterHex);
void encrypt(uint32_t length, uint8_t *data, AESKey<128> *key, AESCounter<128> *counter);
bool getOptionValues(OptionContext &opt, const char **key, const char **ctr, uint32_t *start, uint32_t *end);
uint32_t m_id; //!< Unique identifier.
option_vector_t m_options; //!< List of option entries.
};
}; // namespace elftosb
#endif // _Keyblob_h_

View File

@@ -0,0 +1,48 @@
/*
* File: KeyblobEntry.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_KeyblobEntry_h_)
#define _KeyblobEntry_h_
#include "smart_ptr.h"
#include "OptionContext.h"
namespace elftosb
{
/*!
* @brief Base class for data model of sections of the output file.
*/
class KeyblobEntry
{
public:
KeyblobEntry()
: m_id(0)
, m_options(0)
{
}
KeyblobEntry(uint32_t identifier)
: m_id(identifier)
, m_options(0)
{
}
virtual ~KeyblobEntry() {}
void setIdentifier(uint32_t identifier) { m_id = identifier; }
uint32_t getIdentifier() const { return m_id; }
//! \brief Set the option context.
//!
//! The keyblob entry object will assume ownership of the option context
//! and delete it when the section is deleted.
inline void setOptions(OptionContext *context) { m_options = context; }
//! \brief Return the option context.
inline const OptionContext *getOptions() const { return m_options; }
protected:
uint32_t m_id; //!< Unique identifier.
smart_ptr<OptionContext> m_options; //!< Options associated with just this keyblob entry.
};
}; // namespace elftosb
#endif // _KeyblobEntry_h_

View File

@@ -0,0 +1,90 @@
/*
* File: Logging.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "Logging.h"
#include <stdarg.h>
#include <stdio.h>
#include "smart_ptr.h"
// init global logger to null
Logger *Log::s_logger = NULL;
void Logger::log(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
log(m_level, fmt, args);
va_end(args);
}
void Logger::log(log_level_t level, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
log(level, fmt, args);
va_end(args);
}
void Logger::log(const char *fmt, va_list args)
{
log(m_level, fmt, args);
}
//! Allocates a temporary 1KB buffer which is used to hold the
//! formatted string.
void Logger::log(log_level_t level, const char *fmt, va_list args)
{
smart_array_ptr<char> buffer = new char[1024];
vsprintf(buffer, fmt, args);
if (level <= m_filter)
{
_log(buffer);
}
}
void Log::log(const char *fmt, ...)
{
if (s_logger)
{
va_list args;
va_start(args, fmt);
s_logger->log(fmt, args);
va_end(args);
}
}
void Log::log(const std::string &msg)
{
if (s_logger)
{
s_logger->log(msg);
}
}
void Log::log(Logger::log_level_t level, const char *fmt, ...)
{
if (s_logger)
{
va_list args;
va_start(args, fmt);
s_logger->log(level, fmt, args);
va_end(args);
}
}
void Log::log(Logger::log_level_t level, const std::string &msg)
{
if (s_logger)
{
s_logger->log(level, msg);
}
}
void StdoutLogger::_log(const char *msg)
{
printf("%s", msg);
}

View File

@@ -0,0 +1,219 @@
/*
* File: Logging.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_Logging_h_)
#define _Logging_h_
#include <string>
#include <assert.h>
#include <stdarg.h>
/*!
* \brief Base logger class.
*
* There are two types of logging levels that are used by this class. First
* there is the filter level. Any log message that is assigned a level
* higher than the current filter level is discarded. Secondly there is the
* current output level. Log messages that do not have their own level
* use the current output level to determine if they should be shown or
* not.
*
* The two methods setFilterLevel() and setOutputLevel() set the filter
* and default output logging levels, respectively. There are corresponding
* getter methods as well. Both the filter and output levels are
* initialized to #INFO during object construction.
*
* Most use of the logger classes is expected to be through the Log
* class. It provides static logging methods that call through to a global
* singleton logger instance. There is also a Log::SetOutputLevel utility
* class that makes it extremely easiy to temporarily change the default
* output logging level.
*
* Of all the overloaded log() methods in this class, none of them are
* really expected to be reimplemented by subclasses. Instead, there is
* the single protected _log() method that takes a simple string pointer.
* The other log methods all wind up calling _log(), so it provides a
* single point to override. In fact, _log() is pure virtual, so subclasses
* must implement it.
*
* \see Log
*/
class Logger
{
public:
//! \brief Logging levels.
enum log_level_t
{
URGENT = 0, //!< The lowest level, for messages that must always be logged.
ERROR, //!< For fatal error messages.
WARNING, //!< For non-fatal warning messages.
INFO, //!< The normal log level, for status messages.
INFO2, //!< For verbose status messages.
DEBUG, //!< For internal reporting.
DEBUG2 //!< Highest log level; verbose debug logging.
};
public:
//! \brief Default constructor.
Logger()
: m_filter(INFO)
, m_level(INFO)
{
}
//! \brief Destructor.
virtual ~Logger() {}
//! \name Logging levels
//@{
//! \brief Changes the logging level to \a level.
inline void setFilterLevel(log_level_t level) { m_filter = level; }
//! \brief Returns the current logging filter level.
inline log_level_t getFilterLevel() const { return m_filter; }
//! \brief Changes the logging output level to \a level.
inline void setOutputLevel(log_level_t level) { m_level = level; }
//! \brief Returns the current logging output level.
inline log_level_t getOutputLevel() const { return m_level; }
//@}
//! \name Logging
//@{
//! \brief Log with format.
virtual void log(const char *fmt, ...);
//! \brief Log a string object.
virtual void log(const std::string &msg) { log(msg.c_str()); }
//! \brief Log with format at a specific output level.
virtual void log(log_level_t level, const char *fmt, ...);
//! \brief Log a string output at a specific output level.
virtual void log(log_level_t level, const std::string &msg) { log(level, msg.c_str()); }
//! \brief Log with format using an argument list.
virtual void log(const char *fmt, va_list args);
//! \brief Log with format using an argument with a specific output level.
virtual void log(log_level_t level, const char *fmt, va_list args);
//@}
protected:
log_level_t m_filter; //!< The current logging filter level.
log_level_t m_level; //!< The current log output level.
protected:
//! \brief The base pure virtual logging function implemented by subclasses.
virtual void _log(const char *msg) = 0;
};
/*!
* \brief Wraps a set of static functions for easy global logging access.
*
* This class has a set of static methods that make it easy to access a global
* logger instance without having to worry about extern symbols. It does this
* by keeping a static member variable pointing at the singleton logger instance,
* which is set with the setLogger() static method.
*
* There is also an inner utility class called SetOutputLevel that uses
* C++ scoping rules to temporarily change the output logging level. When the
* SetOutputLevel instance falls out of scope the output level is restored
* to the previous value.
*/
class Log
{
public:
//! \name Singleton logger access
//@{
//! \brief Returns the current global logger singleton.
static inline Logger *getLogger() { return s_logger; }
//! \brief Sets the global logger singleton instance.
static inline void setLogger(Logger *logger) { s_logger = logger; }
//@}
//! \name Logging
//@{
//! \brief Log with format.
static void log(const char *fmt, ...);
//! \brief Log a string object.
static void log(const std::string &msg);
//! \brief Log with format at a specific output level.
static void log(Logger::log_level_t level, const char *fmt, ...);
//! \brief Log a string output at a specific output level.
static void log(Logger::log_level_t level, const std::string &msg);
//@}
protected:
static Logger *s_logger; //!< The single global logger instance.
public:
/*!
* \brief Utility class to temporarily change the logging output level.
*
* This class will change the current logging output level of a given
* logger instance. Then when it falls out of scope it will set the
* level back to what it was originally.
*
* Use like this:
* \code
* // output level is some value here
* {
* Log::SetOutputLevel leveler(Logger::DEBUG);
* // now output level is DEBUG
* Log::log("my debug message 1");
* Log::log("my debug message 2");
* }
* // output level is restored to previous value
* \endcode
*/
class SetOutputLevel
{
public:
//! \brief Default constructor.
//!
//! Saves the current logging output level of the global logger,
//! as managed by the Log class, and sets the new level to \a level.
SetOutputLevel(Logger::log_level_t level)
: m_logger(Log::getLogger())
, m_saved(Logger::INFO)
{
assert(m_logger);
m_saved = m_logger->getOutputLevel();
m_logger->setOutputLevel(level);
}
//! \brief Constructor.
//!
//! Saves the current logging output level of \a logger and sets
//! the new level to \a level.
SetOutputLevel(Logger *logger, Logger::log_level_t level)
: m_logger(logger)
, m_saved(logger->getOutputLevel())
{
assert(m_logger);
m_logger->setOutputLevel(level);
}
//! \brief Destructor.
//!
//! Restores the saved logging output level.
~SetOutputLevel() { m_logger->setOutputLevel(m_saved); }
protected:
Logger *m_logger; //!< The logger instance we're controlling.
Logger::log_level_t m_saved; //!< Original logging output level.
};
};
/*!
* \brief Simple logger that writes to stdout.
*/
class StdoutLogger : public Logger
{
protected:
//! \brief Logs the message to stdout.
virtual void _log(const char *msg);
};
#endif // _Logging_h_

View File

@@ -0,0 +1,87 @@
/*
* File: Operation.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "Operation.h"
using namespace elftosb;
//! The operation object takes ownership of \a source.
//!
//! Cross references between the target and source are updated.
void LoadOperation::setSource(DataSource *source)
{
m_source = source;
if (m_target)
{
m_target->setSource(m_source);
}
if (m_source)
{
m_source->setTarget(m_target);
}
}
//! The operation object takes ownership of \a target.
//!
//! Cross references between the target and source are updated.
void LoadOperation::setTarget(DataTarget *target)
{
m_target = target;
if (m_target)
{
m_target->setSource(m_source);
}
if (m_source)
{
m_source->setTarget(m_target);
}
}
void FlashEraseOperation::getRange(uint32_t *start, uint32_t *count) const
{
if (start)
{
*start = m_startAddress;
}
if (count)
{
*count = m_byteCount;
}
}
void MemEnableOperation::getRange(uint32_t *start, uint32_t *count) const
{
if (start)
{
*start = m_startAddress;
}
if (count)
{
*count = m_byteCount;
}
}
//! Disposes of operations objects in the sequence.
OperationSequence::~OperationSequence()
{
// iterator_t it = begin();
// for (; it != end(); ++it)
// {
// delete it->second;
// }
}
void OperationSequence::append(const OperationSequence *other)
{
const_iterator_t it = other->begin();
for (; it != other->end(); ++it)
{
m_operations.push_back(*it);
}
}

View File

@@ -0,0 +1,374 @@
/*
* File: Operation.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_Operation_h_)
#define _Operation_h_
#include "stdafx.h"
#include <vector>
#include "DataSource.h"
#include "DataTarget.h"
#include "smart_ptr.h"
#include "keyblob.h"
namespace elftosb
{
/*!
* \brief Abstract base class for all boot operations.
*/
class Operation
{
public:
Operation() {}
virtual ~Operation() {}
};
/*!
* \brief Load data into memory operation.
*/
class LoadOperation : public Operation
{
public:
LoadOperation()
: Operation()
, m_source()
, m_target()
, m_isDCDLoad(false)
{
}
void setSource(DataSource *source);
inline DataSource *getSource() { return m_source; }
void setTarget(DataTarget *target);
inline DataTarget *getTarget() { return m_target; }
inline void setDCDLoad(bool isDCD) { m_isDCDLoad = isDCD; }
inline bool isDCDLoad() const { return m_isDCDLoad; }
protected:
smart_ptr<DataSource> m_source;
smart_ptr<DataTarget> m_target;
bool m_isDCDLoad;
};
/*!
* \brief Operation to execute code at a certain address.
*/
class ExecuteOperation : public Operation
{
public:
enum execute_type_t
{
kJump,
kCall
};
public:
ExecuteOperation()
: Operation()
, m_target()
, m_argument(0)
, m_type(kCall)
, m_isHAB(false)
, m_stackPointer(0)
, m_isStackPointerSet(false)
{
}
inline void setTarget(DataTarget *target) { m_target = target; }
inline DataTarget *getTarget() { return m_target; }
inline void setArgument(uint32_t arg) { m_argument = arg; }
inline uint32_t getArgument() { return m_argument; }
inline void setExecuteType(execute_type_t type) { m_type = type; }
inline execute_type_t getExecuteType() { return m_type; }
inline void setIsHAB(bool isHAB) { m_isHAB = isHAB; }
inline bool isHAB() const { return m_isHAB; }
inline void setStackPointer(uint32_t sp) { m_stackPointer = sp; }
inline uint32_t getStackPointer() { return m_stackPointer; }
inline void setIsStackPointerSet(bool isSet) { m_isStackPointerSet = isSet; }
inline bool isStackPonterSet() const { return m_isStackPointerSet; }
protected:
smart_ptr<DataTarget> m_target;
uint32_t m_argument;
uint32_t m_stackPointer;
execute_type_t m_type;
bool m_isHAB;
bool m_isStackPointerSet;
};
/*!
* \brief Authenticate with HAB and execute the entry point.
*/
class HABExecuteOperation : public ExecuteOperation
{
public:
HABExecuteOperation()
: ExecuteOperation()
{
}
};
/*!
* \brief Operation to switch boot modes.
*/
class BootModeOperation : public Operation
{
public:
BootModeOperation()
: Operation()
, m_bootMode(0)
{
}
inline void setBootMode(uint32_t mode) { m_bootMode = mode; }
inline uint32_t getBootMode() const { return m_bootMode; }
protected:
uint32_t m_bootMode; //!< The new boot mode value.
};
/*!
* \brief Operation to reset the device.
*/
class ResetOperation : public Operation
{
public:
ResetOperation()
: Operation()
{
}
};
/*!
* \brief Operation to erase flash memory.
*/
class FlashEraseOperation : public Operation
{
public:
FlashEraseOperation()
: Operation()
, m_startAddress(0)
, m_byteCount(0)
{
}
void setRange(uint32_t start, uint32_t count)
{
m_startAddress = start;
m_byteCount = count;
}
void getRange(uint32_t *start, uint32_t *count) const;
protected:
uint32_t m_startAddress;
uint32_t m_byteCount;
};
/*!
* \brief Operation to erase the entire flash memory array.
*/
class FlashEraseAllOperation : public FlashEraseOperation
{
public:
FlashEraseAllOperation()
: FlashEraseOperation()
{
}
};
/*!
* \brief Operation to erase the entire external flash memory array.
*/
class FlashEraseAllExternalOperation : public FlashEraseOperation
{
public:
FlashEraseAllExternalOperation()
: FlashEraseOperation()
, m_memoryId(0)
{
}
void setMemoryId(uint32_t memId) { m_memoryId = memId; }
uint32_t getMemoryId() const { return m_memoryId; }
protected:
uint32_t m_memoryId;
};
/*!
* \brief Operation to erase the entire flash memory array, unsecure version.
*/
class FlashEraseAllUnsecureOperation : public FlashEraseOperation
{
public:
FlashEraseAllUnsecureOperation()
: FlashEraseOperation()
{
}
};
/*!
* \brief Operation to enable external memory access.
*/
class MemEnableOperation : public Operation
{
public:
MemEnableOperation()
: Operation()
, m_startAddress(0)
, m_byteCount(0)
, m_memControllerId(0)
{
}
void setMemControllerId(uint32_t memControllerId) { m_memControllerId = memControllerId; }
uint32_t getMemControllerId() const { return m_memControllerId; }
void setRange(uint32_t start, uint32_t count)
{
m_startAddress = start;
m_byteCount = count;
}
void getRange(uint32_t *start, uint32_t *count) const;
protected:
uint32_t m_startAddress;
uint32_t m_byteCount;
uint32_t m_memControllerId;
};
/*!
* \brief Operation to program persistent bits.
*/
class ProgramOperation : public LoadOperation
{
public:
//! \brief Default constructor.
ProgramOperation()
: LoadOperation()
, m_memSpace(0)
{
}
//! \brief Constructor. Takes a memory space argument.
ProgramOperation(uint32_t memSpace)
: LoadOperation()
, m_memSpace(memSpace)
{
}
void setMemorySpace(uint32_t memSpace) { m_memSpace = memSpace; }
uint32_t getMemorySpace() const { return m_memSpace; }
protected:
uint32_t m_memSpace;
};
/*!
* \brief Operation to wrap and program keys.
*/
class KeywrapOperation : public LoadOperation
{
public:
//! \brief Default constructor.
KeywrapOperation()
: LoadOperation()
, m_keyblob()
{
}
//! \brief Constructor. Takes a keyblob argument.
KeywrapOperation(Keyblob *keyblob)
: LoadOperation()
, m_keyblob(keyblob)
{
}
void setKeyblob(Keyblob *keyblob) { m_keyblob = keyblob; }
Keyblob *getKeyblob() { return m_keyblob; }
protected:
smart_ptr<Keyblob> m_keyblob; //!< Active keyblob during this load.
};
/*!
* \brief Operation to encrypt data for OTFAD.
*/
class EncryptOperation : public LoadOperation
{
public:
//! \brief Default constructor.
EncryptOperation()
: LoadOperation()
, m_keyblob()
{
}
//! \brief Constructor. Takes a keyblob argument.
EncryptOperation(Keyblob *keyblob)
: LoadOperation()
, m_keyblob(keyblob)
{
}
void setKeyblob(Keyblob *keyblob) { m_keyblob = keyblob; }
Keyblob *getKeyblob() { return m_keyblob; }
protected:
smart_ptr<Keyblob> m_keyblob; //!< Active keyblob during this load.
};
/*!
* \brief Ordered sequence of operations.
*
* The operation objects owned by the sequence are \e not deleted when the
* sequence is destroyed. The owner of the sequence must manually delete
* the operation objects.
*/
class OperationSequence
{
public:
typedef std::vector<Operation *> operation_list_t; //!< Type for a list of operation objects.
typedef operation_list_t::iterator iterator_t; //!< Iterator over operations.
typedef operation_list_t::const_iterator const_iterator_t; //!< Const iterator over operations.
public:
//! \brief Default constructor.
OperationSequence() {}
//! \brief Constructor. Makes a one-element sequence from \a soleElement.
OperationSequence(Operation *soleElement) { m_operations.push_back(soleElement); }
//! \brief Destructor.
virtual ~OperationSequence();
//! \name Iterators
//@{
inline iterator_t begin() { return m_operations.begin(); }
inline const_iterator_t begin() const { return m_operations.begin(); }
inline iterator_t end() { return m_operations.end(); }
inline const_iterator_t end() const { return m_operations.end(); }
//@}
inline Operation *operator[](unsigned index) const { return m_operations[index]; }
//! \name Status
//@{
//! \brief Returns the number of operations in the sequence.
inline unsigned getCount() const { return m_operations.size(); }
//@}
//! \name Operations
//@{
//! \brief Append one operation object to the sequence.
inline void append(Operation *op) { m_operations.push_back(op); }
//! \brief Append the contents of \a other onto this sequence.
void append(const OperationSequence *other);
//! \brief Appends \a other onto this sequence.
OperationSequence &operator+=(const OperationSequence *other)
{
append(other);
return *this;
}
//@}
protected:
operation_list_t m_operations; //!< The list of operations.
};
}; // namespace elftosb
#endif // _Operation_h_

View File

@@ -0,0 +1,51 @@
/*
* File: OptionContext.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_OptionContext_h_)
#define _OptionContext_h_
#include <string>
#include "Value.h"
namespace elftosb
{
/*!
* \brief Pure abstract interface class to a table of options.
*/
class OptionContext
{
public:
//! Make the dtor virtual.
virtual ~OptionContext() {}
//! \brief Detemine whether the named option is present in the table.
//! \param name The name of the option to query.
//! \retval true The option is present and has a value.
//! \retval false No option with that name is in the table.
virtual bool hasOption(const std::string &name) const = 0;
//! \brief Returns the option's value.
//! \param name The name of the option.
//! \return The value for the option named \a name.
//! \retval NULL No option is in the table with that name.
virtual const Value *getOption(const std::string &name) const = 0;
//! \brief Adds or changes an option's value.
//!
//! If the option was not already present in the table, it is added.
//! Otherwise the old value is replaced.
//!
//! \param name The option's name.
//! \param value New value for the option.
virtual void setOption(const std::string &name, Value *value) = 0;
//! \brief Removes an option from the table.
//! \param name The name of the option to remove.
virtual void deleteOption(const std::string &name) = 0;
};
}; // namespace elftosb
#endif // _OptionContext_h_

View File

@@ -0,0 +1,168 @@
/*
* File: OptionDictionary.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "OptionDictionary.h"
using namespace elftosb;
//! Deletes all of the option values that have been assigned locally.
//!
OptionDictionary::~OptionDictionary()
{
option_map_t::iterator it = m_options.begin();
for (; it != m_options.end(); ++it)
{
if (it->second.m_value)
{
delete it->second.m_value;
}
}
}
//! If a parent context has been set and the option does not exist in
//! this instance, then the parent is asked if it contains the option.
//!
//! \param name The name of the option to query.
//! \retval true The option is present in this instance or one of the parent.
//! \retval false No option with that name is in the dictionary, or any parent
bool OptionDictionary::hasOption(const std::string &name) const
{
bool hasIt = (m_options.find(name) != m_options.end());
if (!hasIt && m_parent)
{
return m_parent->hasOption(name);
}
return hasIt;
}
//! If this object does not contain an option with the name of \a name,
//! then the parent is asked for the value (if a parent has been set).
//!
//! \param name The name of the option.
//! \return The value for the option named \a name.
//! \retval NULL No option is in the table with that name. An option may also
//! explicitly be set to a NULL value. The only way to tell the difference
//! is to use the hasOption() method.
const Value *OptionDictionary::getOption(const std::string &name) const
{
option_map_t::const_iterator it = m_options.find(name);
if (it == m_options.end())
{
if (m_parent)
{
return m_parent->getOption(name);
}
else
{
return NULL;
}
}
return it->second.m_value;
}
//! If the option was not already present in the table, it is added.
//! Otherwise the old value is replaced. The option is always set locally;
//! parent objects are never modified.
//!
//! If the option has been locked with a call to lockOption() before trying
//! to set its value, the setOption() is effectively ignored. To tell if
//! an option is locked, use the isOptionLocked() method.
//!
//! \warning If the option already had a value, that previous value is deleted.
//! This means that it cannot currently be in use by another piece of code.
//! See the note in getOption().
//!
//! \param name The option's name.
//! \param value New value for the option.
void OptionDictionary::setOption(const std::string &name, Value *value)
{
option_map_t::iterator it = m_options.find(name);
OptionValue newValue;
// delete the option value instance before replacing it
if (it != m_options.end())
{
// Cannot modify value if locked.
if (it->second.m_isLocked)
{
return;
}
if (it->second.m_value)
{
delete it->second.m_value;
}
// save previous locked value
newValue.m_isLocked = it->second.m_isLocked;
}
// set new option value
newValue.m_value = value;
m_options[name] = newValue;
}
//! \param name The name of the option to remove.
//!
void OptionDictionary::deleteOption(const std::string &name)
{
if (m_options.find(name) != m_options.end())
{
if (m_options[name].m_value)
{
delete m_options[name].m_value;
}
m_options.erase(name);
}
}
//! \param name Name of the option to query.
//!
//! \return True if the option is locked, false if unlocked or not present.
//!
bool OptionDictionary::isOptionLocked(const std::string &name) const
{
option_map_t::const_iterator it = m_options.find(name);
if (it != m_options.end())
{
return it->second.m_isLocked;
}
return false;
}
//! \param name Name of the option to lock.
//!
void OptionDictionary::lockOption(const std::string &name)
{
if (!hasOption(name))
{
m_options[name].m_value = 0;
}
m_options[name].m_isLocked = true;
}
//! \param name Name of the option to unlock.
//!
void OptionDictionary::unlockOption(const std::string &name)
{
if (!hasOption(name))
{
m_options[name].m_value = 0;
}
m_options[name].m_isLocked = false;
}
//! Simply calls getOption().
//!
const Value *OptionDictionary::operator[](const std::string &name) const
{
return getOption(name);
}

View File

@@ -0,0 +1,115 @@
/*
* File: OptionDictionary.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_OptionDictionary_h_)
#define _OptionDictionary_h_
#include "OptionContext.h"
#include <map>
namespace elftosb
{
/*!
* \brief Concrete implementation of OptionContext.
*
* This context subclass supports having a parent context. If an option is not
* found in the receiving instance, the request is passed to the parent.
* The hasOption() and getOption() methods will ask up the parent chain
* if the requested option does not exist in the receiving instance.
* But the setOption() and deleteOption() methods only operate locally,
* on the instance on which they were called. This allows a caller to
* locally override an option value without affecting any of the parent
* contexts.
*/
class OptionDictionary : public OptionContext
{
public:
//! \brief Default constructor.
OptionDictionary()
: m_parent(0)
{
}
//! \brief Constructor taking a parent context.
OptionDictionary(OptionContext *parent)
: m_parent(parent)
{
}
//! \brief Destructor.
~OptionDictionary();
//! \name Parents
//@{
//! \brief Returns the current parent context.
//! \return The current parent context instance.
//! \retval NULL No parent has been set.
inline OptionContext *getParent() const { return m_parent; }
//! \brief Change the parent context.
//! \param newParent The parent context object. May be NULL, in which case
//! the object will no longer have a parent context.
inline void setParent(OptionContext *newParent) { m_parent = newParent; }
//@}
//! \name Options
//@{
//! \brief Detemine whether the named option is present in the table.
virtual bool hasOption(const std::string &name) const;
//! \brief Returns the option's value.
virtual const Value *getOption(const std::string &name) const;
//! \brief Adds or changes an option's value.
virtual void setOption(const std::string &name, Value *value);
//! \brief Removes an option from the table.
virtual void deleteOption(const std::string &name);
//@}
//! \name Locking
//@{
//! \brief Returns true if the specified option is locked from further changes.
bool isOptionLocked(const std::string &name) const;
//! \brief Prevent further modifications of an option's value.
void lockOption(const std::string &name);
//! \brief Allow an option to be changed.
void unlockOption(const std::string &name);
//@}
//! \name Operators
//@{
//! \brief Indexing operator; returns the value for the option \a name.
const Value *operator[](const std::string &name) const;
//@}
protected:
OptionContext *m_parent; //!< Our parent context.
/*!
* \brief Information about one option's value.
*/
struct OptionValue
{
Value *m_value; //!< The object for this option's value.
bool m_isLocked; //!< True if this value is locked from further changes.
//! \brief Constructor.
OptionValue()
: m_value(0)
, m_isLocked(false)
{
}
};
typedef std::map<std::string, OptionValue> option_map_t; //!< Map from option name to value.
option_map_t m_options; //!< The option dictionary.
};
}; // namespace elftosb
#endif // _OptionDictionary_h_

View File

@@ -0,0 +1,8 @@
/*
* File: OutputSection.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "OutputSection.h"

View File

@@ -0,0 +1,88 @@
/*
* File: OutputSection.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_OutputSection_h_)
#define _OutputSection_h_
#include "Operation.h"
#include "smart_ptr.h"
#include "Blob.h"
#include "OptionContext.h"
namespace elftosb
{
/*!
* @brief Base class for data model of sections of the output file.
*/
class OutputSection
{
public:
OutputSection()
: m_id(0)
, m_options(0)
{
}
OutputSection(uint32_t identifier)
: m_id(identifier)
, m_options(0)
{
}
virtual ~OutputSection() {}
void setIdentifier(uint32_t identifier) { m_id = identifier; }
uint32_t getIdentifier() const { return m_id; }
//! \brief Set the option context.
//!
//! The output section object will assume ownership of the option context
//! and delete it when the section is deleted.
inline void setOptions(OptionContext *context) { m_options = context; }
//! \brief Return the option context.
inline const OptionContext *getOptions() const { return m_options; }
protected:
uint32_t m_id; //!< Unique identifier.
smart_ptr<OptionContext> m_options; //!< Options associated with just this section.
};
/*!
* @brief A section of the output that contains boot operations.
*/
class OperationSequenceSection : public OutputSection
{
public:
OperationSequenceSection()
: OutputSection()
{
}
OperationSequenceSection(uint32_t identifier)
: OutputSection(identifier)
{
}
OperationSequence &getSequence() { return m_sequence; }
protected:
OperationSequence m_sequence;
};
/*!
* @brief A section of the output file that contains arbitrary binary data.
*/
class BinaryDataSection : public OutputSection, public Blob
{
public:
BinaryDataSection()
: OutputSection()
, Blob()
{
}
BinaryDataSection(uint32_t identifier)
: OutputSection(identifier)
, Blob()
{
}
};
}; // namespace elftosb
#endif // _OutputSection_h_

View File

@@ -0,0 +1,81 @@
/*
* File: Random.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "Random.h"
#include <stdexcept>
#ifdef WIN32
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif
#include <windows.h>
#include <wincrypt.h>
#else // WIN32
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#endif // WIN32
#ifdef WIN32
MicrosoftCryptoProvider::MicrosoftCryptoProvider()
{
if (!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
throw std::runtime_error("CryptAcquireContext");
}
}
MicrosoftCryptoProvider::~MicrosoftCryptoProvider()
{
CryptReleaseContext(m_hProvider, 0);
}
#endif // WIN32
RandomNumberGenerator::RandomNumberGenerator()
{
#ifndef WIN32
m_fd = open("/dev/urandom", O_RDONLY);
if (m_fd == -1)
{
throw std::runtime_error("open /dev/urandom");
}
#endif // WIN32
}
RandomNumberGenerator::~RandomNumberGenerator()
{
#ifndef WIN32
close(m_fd);
#endif // WIN32
}
uint8_t RandomNumberGenerator::generateByte()
{
uint8_t result;
generateBlock(&result, 1);
return result;
}
void RandomNumberGenerator::generateBlock(uint8_t *output, unsigned count)
{
#ifdef WIN32
#ifdef WORKAROUND_MS_BUG_Q258000
static MicrosoftCryptoProvider m_provider;
#endif
if (!CryptGenRandom(m_provider.GetProviderHandle(), count, output))
{
throw std::runtime_error("CryptGenRandom");
}
#else // WIN32
if (read(m_fd, output, count) != count)
{
throw std::runtime_error("read /dev/urandom");
}
#endif // WIN32
}

View File

@@ -0,0 +1,56 @@
/*
* File: Random.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_Random_h_)
#define _Random_h_
#include "stdafx.h"
#ifdef WIN32
/*!
* This class is from the crypto++ library.
*/
class MicrosoftCryptoProvider
{
public:
MicrosoftCryptoProvider();
~MicrosoftCryptoProvider();
#if defined(_WIN64)
typedef unsigned __int64 ProviderHandle; // type HCRYPTPROV, avoid #include <windows.h>
#else
typedef unsigned long ProviderHandle;
#endif
ProviderHandle GetProviderHandle() const { return m_hProvider; }
private:
ProviderHandle m_hProvider;
};
#pragma comment(lib, "advapi32.lib")
#endif // WIN32
/*!
* Encapsulates the Windows CryptoAPI's CryptGenRandom or /dev/urandom on Unix systems.
*/
class RandomNumberGenerator
{
public:
RandomNumberGenerator();
~RandomNumberGenerator();
uint8_t generateByte();
void generateBlock(uint8_t *output, unsigned count);
protected:
#ifdef WIN32
#ifndef WORKAROUND_MS_BUG_Q258000
MicrosoftCryptoProvider m_provider;
#endif
#else // WIN32
int m_fd;
#endif // WIN32
};
#endif // _Random_h_

View File

@@ -0,0 +1,85 @@
/*
* File: RijndaelCBCMAC.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "RijndaelCBCMAC.h"
#include "rijndael.h"
#include <assert.h>
#include "Logging.h"
void logHexArray(Logger::log_level_t level, const uint8_t *bytes, unsigned count);
//! \param key The key to use as the CBC-MAC secret.
//! \param iv Initialization vector. Defaults to zero if not provided.
RijndaelCBCMAC::RijndaelCBCMAC(const AESKey<128> &key, const uint8_t *iv)
: m_key(key)
{
if (iv)
{
memcpy(m_mac, iv, sizeof(m_mac));
}
else
{
memset(m_mac, 0, sizeof(m_mac));
}
}
//! \param data Pointer to data to process.
//! \param length Number of bytes to process. Must be evenly divisible by #BLOCK_SIZE.
void RijndaelCBCMAC::update(const uint8_t *data, unsigned length)
{
assert(length % BLOCK_SIZE == 0);
unsigned blocks = length / BLOCK_SIZE;
while (blocks--)
{
updateOneBlock(data);
data += BLOCK_SIZE;
}
}
//! It appears that some forms of CBC-MAC encrypt the final output block again in
//! order to protect against a plaintext attack. This method is a placeholder for
//! such an operation, but it currently does nothing.
void RijndaelCBCMAC::finalize()
{
}
//! On entry the current value of m_mac becomes the initialization vector
//! for the CBC encryption of this block. The output of the encryption then
//! becomes the new MAC, which is stored in m_mac.
void RijndaelCBCMAC::updateOneBlock(const uint8_t *data)
{
Rijndael cipher;
cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_key, Rijndael::Key16Bytes, m_mac);
cipher.blockEncrypt(data, BLOCK_SIZE * 8, m_mac); // size is in bits
// Log::log(Logger::DEBUG2, "CBC-MAC output block:\n");
// logHexArray(Logger::DEBUG2, (const uint8_t *)&m_mac, sizeof(m_mac));
}
/*!
* \brief Log an array of bytes as hex.
*/
void logHexArray(Logger::log_level_t level, const uint8_t *bytes, unsigned count)
{
Log::SetOutputLevel leveler(level);
// Log::log(" ");
unsigned i;
for (i = 0; i < count; ++i, ++bytes)
{
if ((i % 16 == 0) && (i < count - 1))
{
if (i != 0)
{
Log::log("\n");
}
Log::log(" 0x%04x: ", i);
}
Log::log("%02x ", *bytes & 0xff);
}
Log::log("\n");
}

View File

@@ -0,0 +1,60 @@
/*
* File: RijndaelCBCMAC.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_RijndaelCBCMAC_h_)
#define _RijndaelCBCMAC_h_
#include "AESKey.h"
#include <string.h>
/*!
* \brief Class to compute CBC-MAC using the AES/Rijndael cipher.
*
* Currently only supports 128-bit keys and block sizes.
*/
class RijndaelCBCMAC
{
public:
enum
{
BLOCK_SIZE = 16 //!< Number of bytes in one cipher block.
};
//! The cipher block data type.
typedef uint8_t block_t[BLOCK_SIZE];
public:
//! \brief Default constructor.
//!
//! The key and IV are both set to zero.
RijndaelCBCMAC() {}
//! \brief Constructor.
RijndaelCBCMAC(const AESKey<128> &key, const uint8_t *iv = 0);
//! \brief Process data.
void update(const uint8_t *data, unsigned length);
//! \brief Signal that all data has been processed.
void finalize();
//! \brief Returns a reference to the current MAC value.
const block_t &getMAC() const { return m_mac; }
//! \brief Assignment operator.
RijndaelCBCMAC &operator=(const RijndaelCBCMAC &other)
{
m_key = other.m_key;
memcpy(m_mac, other.m_mac, sizeof(m_mac));
return *this;
}
protected:
AESKey<128> m_key; //!< 128-bit key to use for the CBC-MAC.
block_t m_mac; //!< Current message authentication code value.
void updateOneBlock(const uint8_t *data);
};
#endif // _RijndaelCBCMAC_h_

View File

@@ -0,0 +1,77 @@
/*
* File: RijndaelCTR.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "RijndaelCTR.h"
#include "rijndael.h"
#include <assert.h>
#include "Logging.h"
void logHexArray(Logger::log_level_t level, const uint8_t *bytes, unsigned count);
//! \param key The key to use
//! \param counter The counter to use
RijndaelCTR::RijndaelCTR(const AESKey<128> &key, const AESCounter<128> &counter)
: m_key(key)
, m_counter(counter)
{
}
void RijndaelCTR::decrypt(const uint8_t *data, unsigned length, uint8_t *dest)
{
baseProcess(data, length, dest);
}
void RijndaelCTR::encrypt(const uint8_t *data, unsigned length, uint8_t *dest)
{
baseProcess(data, length, dest);
}
void RijndaelCTR::baseProcess(const uint8_t *data, unsigned length, uint8_t *dest)
{
Rijndael cipher;
unsigned blocks = length / BLOCK_SIZE;
block_t remainder;
AESCounter<128>::counter_t currentCounter;
cipher.init(Rijndael::ECB, Rijndael::Encrypt, m_key, Rijndael::Key16Bytes);
while (blocks--)
{
m_counter.getCounter(&currentCounter);
cipher.blockEncrypt(currentCounter, BLOCK_SIZE * 8, currentCounter);
for (int i = 0; i < BLOCK_SIZE; i++)
{
dest[i] = data[i] ^ currentCounter[i];
}
data += BLOCK_SIZE;
dest += BLOCK_SIZE;
m_counter.incrementCounter(BLOCK_SIZE);
}
if (length % sizeof(block_t))
{
m_counter.getCounter(&currentCounter);
memset(remainder, 0, sizeof(remainder));
memcpy(remainder, data, length % sizeof(block_t));
cipher.blockEncrypt(currentCounter, BLOCK_SIZE * 8, currentCounter);
for (unsigned int i = 0; i < length % sizeof(block_t); i++)
{
remainder[i] = data[i] ^ currentCounter[i];
}
memcpy(dest, remainder, length % sizeof(block_t));
m_counter.incrementCounter(BLOCK_SIZE);
}
}

View File

@@ -0,0 +1,60 @@
/*
* File: RijndaelCTR.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_RijndaelCTR_h_)
#define _RijndaelCTR_h_
#include "AESKey.h"
#include "AESCounter.h"
#include <string.h>
/*!
* \brief Class to compute AES 128 CTR encryption/decryption.
*
* Currently only supports 128-bit keys and block sizes.
*/
class RijndaelCTR
{
public:
enum
{
BLOCK_SIZE = 16 //!< Number of bytes in one cipher block.
};
//! The cipher block data type.
typedef uint8_t block_t[BLOCK_SIZE];
public:
//! \brief Constructor.
RijndaelCTR(const AESKey<128> &key, const AESCounter<128> &counter);
//! \brief Encrypt data.
void encrypt(const uint8_t *data, unsigned length, uint8_t *dest);
//! \brief Encrypt data.
void decrypt(const uint8_t *data, unsigned length, uint8_t *dest);
//! \brief Assignment operator.
RijndaelCTR &operator=(const RijndaelCTR &other)
{
m_key = other.m_key;
m_counter = other.m_counter;
return *this;
}
protected:
AESKey<128> m_key; //!< 128-bit key to use for encrypt/decrypt
AESCounter<128> m_counter; //!< Counter value for encrypt/decrypt
void incrementCounter(AESCounter<128>::counter_t *counter);
void baseProcess(const uint8_t *data, unsigned length, uint8_t *dest);
private:
//! \brief inaccessible default constructor.
RijndaelCTR() {}
};
#endif // _RijndaelCTR_h_

View File

@@ -0,0 +1,361 @@
/*
100% free public domain implementation of the SHA-1 algorithm
by Dominik Reichl <dominik.reichl@t-online.de>
Web: http://www.dominik-reichl.de/
Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
- You can set the endianness in your files, no need to modify the
header file of the CSHA1 class any more
- Aligned data support
- Made support/compilation of the utility functions (ReportHash
and HashFile) optional (useful, if bytes count, for example in
embedded environments)
Version 1.5 - 2005-01-01
- 64-bit compiler compatibility added
- Made variable wiping optional (define SHA1_WIPE_VARIABLES)
- Removed unnecessary variable initializations
- ROL32 improvement for the Microsoft compiler (using _rotl)
======== Test Vectors (from FIPS PUB 180-1) ========
SHA1("abc") =
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
SHA1(A million repetitions of "a") =
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
#include "SHA1.h"
#ifdef SHA1_UTILITY_FUNCTIONS
#define SHA1_MAX_FILE_BUFFER 8000
#endif
// Rotate x bits to the left
#ifndef ROL32
#ifdef _MSC_VER
#define ROL32(_val32, _nBits) _rotl(_val32, _nBits)
#else
#define ROL32(_val32, _nBits) (((_val32) << (_nBits)) | ((_val32) >> (32 - (_nBits))))
#endif
#endif
#ifdef SHA1_LITTLE_ENDIAN
#define SHABLK0(i) (m_block->l[i] = (ROL32(m_block->l[i], 24) & 0xFF00FF00) | (ROL32(m_block->l[i], 8) & 0x00FF00FF))
#else
#define SHABLK0(i) (m_block->l[i])
#endif
#define SHABLK(i) \
(m_block->l[i & 15] = ROL32( \
m_block->l[(i + 13) & 15] ^ m_block->l[(i + 8) & 15] ^ m_block->l[(i + 2) & 15] ^ m_block->l[i & 15], 1))
// SHA-1 rounds
#define _R0(v, w, x, y, z, i) \
{ \
z += ((w & (x ^ y)) ^ y) + SHABLK0(i) + 0x5A827999 + ROL32(v, 5); \
w = ROL32(w, 30); \
}
#define _R1(v, w, x, y, z, i) \
{ \
z += ((w & (x ^ y)) ^ y) + SHABLK(i) + 0x5A827999 + ROL32(v, 5); \
w = ROL32(w, 30); \
}
#define _R2(v, w, x, y, z, i) \
{ \
z += (w ^ x ^ y) + SHABLK(i) + 0x6ED9EBA1 + ROL32(v, 5); \
w = ROL32(w, 30); \
}
#define _R3(v, w, x, y, z, i) \
{ \
z += (((w | x) & y) | (w & x)) + SHABLK(i) + 0x8F1BBCDC + ROL32(v, 5); \
w = ROL32(w, 30); \
}
#define _R4(v, w, x, y, z, i) \
{ \
z += (w ^ x ^ y) + SHABLK(i) + 0xCA62C1D6 + ROL32(v, 5); \
w = ROL32(w, 30); \
}
CSHA1::CSHA1()
{
m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace;
Reset();
}
CSHA1::~CSHA1()
{
Reset();
}
void CSHA1::Reset()
{
// SHA1 initialization constants
m_state[0] = 0x67452301;
m_state[1] = 0xEFCDAB89;
m_state[2] = 0x98BADCFE;
m_state[3] = 0x10325476;
m_state[4] = 0xC3D2E1F0;
m_count[0] = 0;
m_count[1] = 0;
}
void CSHA1::Transform(uint32_t *state, const uint8_t *buffer)
{
// Copy state[] to working vars
uint32_t a = state[0], b = state[1], c = state[2], d = state[3], e = state[4];
memcpy(m_block, buffer, 64);
// 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 state
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
// Wipe variables
#ifdef SHA1_WIPE_VARIABLES
a = b = c = d = e = 0;
#endif
}
// Use this function to hash in binary data and strings
void CSHA1::Update(const uint8_t *data, uint32_t len)
{
uint32_t i, j;
j = (m_count[0] >> 3) & 63;
if ((m_count[0] += len << 3) < (len << 3))
m_count[1]++;
m_count[1] += (len >> 29);
if ((j + len) > 63)
{
i = 64 - j;
memcpy(&m_buffer[j], data, i);
Transform(m_state, m_buffer);
for (; i + 63 < len; i += 64)
Transform(m_state, &data[i]);
j = 0;
}
else
i = 0;
memcpy(&m_buffer[j], &data[i], len - i);
}
#ifdef SHA1_UTILITY_FUNCTIONS
// Hash in file contents
bool CSHA1::HashFile(char *szFileName)
{
unsigned long ulFileSize, ulRest, ulBlocks;
unsigned long i;
uint8_t uData[SHA1_MAX_FILE_BUFFER];
FILE *fIn;
if (szFileName == NULL)
return false;
fIn = fopen(szFileName, "rb");
if (fIn == NULL)
return false;
fseek(fIn, 0, SEEK_END);
ulFileSize = (unsigned long)ftell(fIn);
fseek(fIn, 0, SEEK_SET);
if (ulFileSize != 0)
{
ulBlocks = ulFileSize / SHA1_MAX_FILE_BUFFER;
ulRest = ulFileSize % SHA1_MAX_FILE_BUFFER;
}
else
{
ulBlocks = 0;
ulRest = 0;
}
for (i = 0; i < ulBlocks; i++)
{
fread(uData, 1, SHA1_MAX_FILE_BUFFER, fIn);
Update((uint8_t *)uData, SHA1_MAX_FILE_BUFFER);
}
if (ulRest != 0)
{
fread(uData, 1, ulRest, fIn);
Update((uint8_t *)uData, ulRest);
}
fclose(fIn);
fIn = NULL;
return true;
}
#endif
void CSHA1::Final()
{
uint32_t i;
uint8_t finalcount[8];
for (i = 0; i < 8; i++)
finalcount[i] = (uint8_t)((m_count[((i >= 4) ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); // Endian independent
Update((uint8_t *)"\200", 1);
while ((m_count[0] & 504) != 448)
Update((uint8_t *)"\0", 1);
Update(finalcount, 8); // Cause a SHA1Transform()
for (i = 0; i < 20; i++)
{
m_digest[i] = (uint8_t)((m_state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
}
// Wipe variables for security reasons
#ifdef SHA1_WIPE_VARIABLES
i = 0;
memset(m_buffer, 0, 64);
memset(m_state, 0, 20);
memset(m_count, 0, 8);
memset(finalcount, 0, 8);
Transform(m_state, m_buffer);
#endif
}
#ifdef SHA1_UTILITY_FUNCTIONS
// Get the final hash as a pre-formatted string
void CSHA1::ReportHash(char *szReport, unsigned char uReportType)
{
unsigned char i;
char szTemp[16];
if (szReport == NULL)
return;
if (uReportType == REPORT_HEX)
{
sprintf(szTemp, "%02X", m_digest[0]);
strcat(szReport, szTemp);
for (i = 1; i < 20; i++)
{
sprintf(szTemp, " %02X", m_digest[i]);
strcat(szReport, szTemp);
}
}
else if (uReportType == REPORT_DIGIT)
{
sprintf(szTemp, "%u", m_digest[0]);
strcat(szReport, szTemp);
for (i = 1; i < 20; i++)
{
sprintf(szTemp, " %u", m_digest[i]);
strcat(szReport, szTemp);
}
}
else
strcpy(szReport, "Error: Unknown report type!");
}
#endif
// Get the raw message digest
void CSHA1::GetHash(uint8_t *puDest)
{
memcpy(puDest, m_digest, 20);
}

149
apps/elftosb/common/SHA1.h Normal file
View File

@@ -0,0 +1,149 @@
/*
100% free public domain implementation of the SHA-1 algorithm
by Dominik Reichl <dominik.reichl@t-online.de>
Web: http://www.dominik-reichl.de/
Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
- You can set the endianness in your files, no need to modify the
header file of the CSHA1 class any more
- Aligned data support
- Made support/compilation of the utility functions (ReportHash
and HashFile) optional (useful, if bytes count, for example in
embedded environments)
Version 1.5 - 2005-01-01
- 64-bit compiler compatibility added
- Made variable wiping optional (define SHA1_WIPE_VARIABLES)
- Removed unnecessary variable initializations
- ROL32 improvement for the Microsoft compiler (using _rotl)
======== Test Vectors (from FIPS PUB 180-1) ========
SHA1("abc") =
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
SHA1(A million repetitions of "a") =
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
#ifndef ___SHA1_HDR___
#define ___SHA1_HDR___
#if !defined(SHA1_UTILITY_FUNCTIONS) && !defined(SHA1_NO_UTILITY_FUNCTIONS)
#define SHA1_UTILITY_FUNCTIONS
#endif
#include <memory.h> // Needed for memset and memcpy
#include "stdafx.h"
#ifdef SHA1_UTILITY_FUNCTIONS
#include <stdio.h> // Needed for file access and sprintf
#include <string.h> // Needed for strcat and strcpy
#endif
#ifdef _MSC_VER
#include <stdlib.h>
#endif
// You can define the endian mode in your files, without modifying the SHA1
// source files. Just #define SHA1_LITTLE_ENDIAN or #define SHA1_BIG_ENDIAN
// in your files, before including the SHA1.h header file. If you don't
// define anything, the class defaults to little endian.
#if !defined(SHA1_LITTLE_ENDIAN) && !defined(SHA1_BIG_ENDIAN)
#define SHA1_LITTLE_ENDIAN
#endif
// Same here. If you want variable wiping, #define SHA1_WIPE_VARIABLES, if
// not, #define SHA1_NO_WIPE_VARIABLES. If you don't define anything, it
// defaults to wiping.
#if !defined(SHA1_WIPE_VARIABLES) && !defined(SHA1_NO_WIPE_VARIABLES)
#define SHA1_WIPE_VARIABLES
#endif
/////////////////////////////////////////////////////////////////////////////
// Define 8- and 32-bit variables
//#ifndef uint32_t
//
//#ifdef _MSC_VER
//
//#define uint8_t unsigned __int8
//#define uint32_t unsigned __int32
//
//#else
//
//#define uint8_t unsigned char
//
//#if (ULONG_MAX == 0xFFFFFFFF)
//#define uint32_t unsigned long
//#else
//#define uint32_t unsigned int
//#endif
//
//#endif
//#endif
/////////////////////////////////////////////////////////////////////////////
// Declare SHA1 workspace
typedef union
{
uint8_t c[64];
uint32_t l[16];
} SHA1_WORKSPACE_BLOCK;
class CSHA1
{
public:
#ifdef SHA1_UTILITY_FUNCTIONS
// Two different formats for ReportHash(...)
enum
{
REPORT_HEX = 0,
REPORT_DIGIT = 1
};
#endif
// Constructor and Destructor
CSHA1();
~CSHA1();
uint32_t m_state[5];
uint32_t m_count[2];
uint32_t __reserved1[1];
uint8_t m_buffer[64];
uint8_t m_digest[20];
uint32_t __reserved2[3];
void Reset();
// Update the hash value
void Update(const uint8_t *data, uint32_t len);
#ifdef SHA1_UTILITY_FUNCTIONS
bool HashFile(char *szFileName);
#endif
// Finalize hash and report
void Final();
// Report functions: as pre-formatted and raw data
#ifdef SHA1_UTILITY_FUNCTIONS
void ReportHash(char *szReport, unsigned char uReportType = REPORT_HEX);
#endif
void GetHash(uint8_t *puDest);
private:
// Private SHA-1 transformation
void Transform(uint32_t *state, const uint8_t *buffer);
// Member variables
uint8_t m_workspace[64];
SHA1_WORKSPACE_BLOCK *m_block; // SHA1 pointer to the byte array above
};
#endif

View File

@@ -0,0 +1,178 @@
/*
* File: SRecordSourceFile.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "SRecordSourceFile.h"
#include "Logging.h"
#include "smart_ptr.h"
#include <assert.h>
#include <string.h>
enum
{
//! Size in bytes of the buffer used to collect S-record data records
//! before adding them to the executable image. Currently 64KB.
COLLECTION_BUFFER_SIZE = 64 * 1024
};
using namespace elftosb;
SRecordSourceFile::SRecordSourceFile(const std::string &path)
: SourceFile(path)
, m_image(0)
, m_hasEntryRecord(false)
{
}
bool SRecordSourceFile::isSRecordFile(std::istream &stream)
{
StSRecordFile srec(stream);
return srec.isSRecordFile();
}
void SRecordSourceFile::open()
{
SourceFile::open();
// create file parser and examine file
m_file = new StSRecordFile(*m_stream);
m_file->parse();
// build an image of the file
m_image = new StExecutableImage();
buildMemoryImage();
// dispose of file parser object
delete m_file;
m_file = 0;
}
void SRecordSourceFile::close()
{
assert(m_image);
SourceFile::close();
// dispose of memory image
delete m_image;
m_image = 0;
}
//! \pre The file must be open before this method can be called.
//!
DataSource *SRecordSourceFile::createDataSource()
{
assert(m_image);
return new MemoryImageDataSource(m_image);
}
//! \retval true The file has an S7, S8, or S9 record.
//! \retval false No entry point is available.
bool SRecordSourceFile::hasEntryPoint()
{
return m_hasEntryRecord;
}
//! If no entry point is available then 0 is returned instead. The method scans
//! the records in the file looking for S7, S8, or S9 records. Thus, 16-bit,
//! 24-bit, and 32-bit entry point records are supported.
//!
//! \return Entry point address.
//! \retval 0 No entry point is available.
uint32_t SRecordSourceFile::getEntryPointAddress()
{
if (m_hasEntryRecord)
{
// the address in the record is the entry point
Log::log(Logger::DEBUG2, "entry point address is 0x%08x\n", m_entryRecord.m_address);
return m_entryRecord.m_address;
}
return 0;
}
//! Scans the S-records of the file looking for data records. These are S3, S2, or
//! S1 records. The contents of these records are added to an StExecutableImage
//! object, which coalesces the individual records into contiguous regions of
//! memory.
//!
//! Also looks for S7, S8, or S9 records that contain the entry point. The first
//! match of one of these records is saved off into the #m_entryRecord member.
//!
//! \pre The #m_file member must be valid.
//! \pre The #m_image member variable must have been instantiated.
void SRecordSourceFile::buildMemoryImage()
{
assert(m_file);
assert(m_image);
// Clear the entry point related members.
m_hasEntryRecord = false;
memset(&m_entryRecord, 0, sizeof(m_entryRecord));
// Allocate buffer to hold data before adding it to the executable image.
// Contiguous records are added to this buffer. When overflowed or when a
// non-contiguous record is encountered the buffer is added to the executable
// image where it will be coalesced further. We don't add records individually
// to the image because coalescing record by record is very slow.
smart_array_ptr<uint8_t> buffer = new uint8_t[COLLECTION_BUFFER_SIZE];
unsigned startAddress;
unsigned nextAddress;
unsigned dataLength = 0;
// process SRecords
StSRecordFile::const_iterator it = m_file->getBegin();
for (; it != m_file->getEnd(); it++)
{
const StSRecordFile::SRecord &theRecord = *it;
// only handle S3,2,1 records
bool isDataRecord = theRecord.m_type == 3 || theRecord.m_type == 2 || theRecord.m_type == 1;
bool hasData = theRecord.m_data && theRecord.m_dataCount;
if (isDataRecord && hasData)
{
// If this record's data would overflow the collection buffer, or if the
// record is not contiguous with the rest of the data in the collection
// buffer, then flush the buffer to the executable image and restart.
if (dataLength &&
((dataLength + theRecord.m_dataCount > COLLECTION_BUFFER_SIZE) || (theRecord.m_address != nextAddress)))
{
m_image->addTextRegion(startAddress, buffer, dataLength);
dataLength = 0;
}
// Capture addresses when starting an empty buffer.
if (dataLength == 0)
{
startAddress = theRecord.m_address;
nextAddress = startAddress;
}
// Copy record data into place in the collection buffer and update
// size and address.
memcpy(&buffer[dataLength], theRecord.m_data, theRecord.m_dataCount);
dataLength += theRecord.m_dataCount;
nextAddress += theRecord.m_dataCount;
}
else if (!m_hasEntryRecord)
{
// look for S7,8,9 records
bool isEntryPointRecord = theRecord.m_type == 7 || theRecord.m_type == 8 || theRecord.m_type == 9;
if (isEntryPointRecord)
{
// save off the entry point record so we don't have to scan again
memcpy(&m_entryRecord, &theRecord, sizeof(m_entryRecord));
m_hasEntryRecord = true;
}
}
}
// Add any leftover data in the collection buffer to the executable image.
if (dataLength)
{
m_image->addTextRegion(startAddress, buffer, dataLength);
}
}

View File

@@ -0,0 +1,81 @@
/*
* File: SRecordSourceFile.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_SRecordSourceFile_h_)
#define _SRecordSourceFile_h_
#include "SourceFile.h"
#include "StSRecordFile.h"
#include "StExecutableImage.h"
namespace elftosb
{
/*!
* \brief Executable file in the Motorola S-record format.
*
* Instead of presenting each S-record in the file separately, this class
* builds up a memory image of all of the records. Records next to each other
* in memory are coalesced into a single memory region. The data source that
* is returned from createDataSource() exposes these regions as its segments.
*
* Because the S-record format does not support the concepts, no support is
* provided for named sections or symbols.
*/
class SRecordSourceFile : public SourceFile
{
public:
//! \brief Default constructor.
SRecordSourceFile(const std::string &path);
//! \brief Destructor.
virtual ~SRecordSourceFile() {}
//! \brief Test whether the \a stream contains a valid S-record file.
static bool isSRecordFile(std::istream &stream);
//! \name Opening and closing
//@{
//! \brief Opens the file.
virtual void open();
//! \brief Closes the file.
virtual void close();
//@}
//! \name Format capabilities
//@{
virtual bool supportsNamedSections() const { return false; }
virtual bool supportsNamedSymbols() const { return false; }
//@}
//! \name Data sources
//@{
//! \brief Returns data source for the entire file.
virtual DataSource *createDataSource();
//@}
//! \name Entry point
//@{
//! \brief Returns true if an entry point was set in the file.
virtual bool hasEntryPoint();
//! \brief Returns the entry point address.
virtual uint32_t getEntryPointAddress();
//@}
protected:
StSRecordFile *m_file; //!< S-record parser instance.
StExecutableImage *m_image; //!< Memory image of the S-record file.
bool m_hasEntryRecord; //!< Whether an S7,8,9 record was found.
StSRecordFile::SRecord m_entryRecord; //!< Record for the entry point.
protected:
//! \brief Build memory image of the S-record file.
void buildMemoryImage();
};
}; // namespace elftosb
#endif // _SRecordSourceFile_h_

View File

@@ -0,0 +1,121 @@
/*
* File: SearchPath.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "SearchPath.h"
#include <stdio.h>
#if defined(WIN32)
#define PATH_SEP_CHAR '\\'
#define PATH_SEP_STRING "\\"
#else
#define PATH_SEP_CHAR '/'
#define PATH_SEP_STRING "/"
#endif
PathSearcher *PathSearcher::s_searcher = NULL;
//! This function will create the global path search object if it has
//! not already been created.
PathSearcher &PathSearcher::getGlobalSearcher()
{
if (!s_searcher)
{
s_searcher = new PathSearcher;
}
return *s_searcher;
}
void PathSearcher::addSearchPath(std::string &path)
{
m_paths.push_back(path);
}
//! The \a base path argument can be either a relative or absolute path. If the path
//! is relative, then it is joined with search paths one after another until a matching
//! file is located or all search paths are exhausted. If the \a base is absolute,
//! only that path is tested and if invalid false is returned.
//!
//! \param base A path to the file that is to be found.
//! \param targetType Currently ignored. In the future it will let you select whether to
//! find a file or directory.
//! \param searchCwd If set to true, the current working directory is searched before using
//! any of the search paths. Otherwise only the search paths are considered.
//! \param[out] result When true is returned this string is set to the first path at which
//! a valid file was found.
//!
//! \retval true A matching file was found among the search paths. The contents of \a result
//! are a valid path.
//! \retval false No match could be made. \a result has been left unmodified.
bool PathSearcher::search(const std::string &base, target_type_t targetType, bool searchCwd, std::string &result)
{
FILE *tempFile;
bool absolute = isAbsolute(base);
// Try cwd first if requested. Same process applies to absolute paths.
if (absolute || searchCwd)
{
tempFile = fopen(base.c_str(), "r");
if (tempFile)
{
fclose(tempFile);
result = base;
return true;
}
}
// If the base path is absolute and the previous test failed, then we don't go any further.
if (absolute)
{
return false;
}
// Iterate over all search paths.
string_list_t::const_iterator it = m_paths.begin();
for (; it != m_paths.end(); ++it)
{
std::string searchPath = joinPaths(*it, base);
tempFile = fopen(searchPath.c_str(), "r");
if (tempFile)
{
fclose(tempFile);
result = searchPath;
return true;
}
}
// Couldn't find anything matching the base path.
return false;
}
bool PathSearcher::isAbsolute(const std::string &path)
{
#if __WIN32__
return path.size() >= 3 && path[1] == ':' && path[2] == '\\';
#else
return path.size() >= 1 && path[0] == '/';
#endif
}
std::string PathSearcher::joinPaths(const std::string &first, const std::string &second)
{
// Start with first string.
std::string result = first;
// Add path separator if needed
if ((first[first.size() - 1] != PATH_SEP_CHAR) && (second[0] != PATH_SEP_CHAR))
{
result += PATH_SEP_STRING;
}
// Append the second string.
result += second;
// And return the whole mess.
return result;
}

View File

@@ -0,0 +1,57 @@
/*
* File: SearchPath.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_searchpath_h_)
#define _searchpath_h_
#include <string>
#include <list>
/*!
* \brief Handles searching a list of paths for a file.
*/
class PathSearcher
{
public:
//!
enum _target_type
{
kFindFile,
kFindDirectory
};
//!
typedef enum _target_type target_type_t;
protected:
//! Global search object singleton.
static PathSearcher *s_searcher;
public:
//! \brief Access global path searching object.
static PathSearcher &getGlobalSearcher();
public:
//! \brief Constructor.
PathSearcher() {}
//! \brief Add a new search path to the end of the list.
void addSearchPath(std::string &path);
//! \brief Attempts to locate a file by using the search paths.
bool search(const std::string &base, target_type_t targetType, bool searchCwd, std::string &result);
protected:
typedef std::list<std::string> string_list_t; //!< Linked list of strings.
string_list_t m_paths; //!< Ordered list of paths to search.
//! \brief Returns whether \a path is absolute.
bool isAbsolute(const std::string &path);
//! \brief Combines two paths into a single one.
std::string joinPaths(const std::string &first, const std::string &second);
};
#endif // _searchpath_h_

View File

@@ -0,0 +1,179 @@
/*
* File: SourceFile.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "SourceFile.h"
#include "ELFSourceFile.h"
#include "SRecordSourceFile.h"
#include <assert.h>
#include "format_string.h"
#include "SearchPath.h"
using namespace elftosb;
//! The supported file types are currently:
//! - ELF files
//! - Motorola S-record files
//! - Binary files
//!
//! Any file that is not picked up by the other subclasses will result in a
//! an instance of BinaryDataFile.
//!
//! \return An instance of the correct subclass of SourceFile for the given path.
//!
//! \exception std::runtime_error Thrown if the file cannot be opened.
//!
//! \see elftosb::ELFSourceFile
//! \see elftosb::SRecordSourceFile
//! \see elftosb::BinarySourceFile
SourceFile *SourceFile::openFile(const std::string &path)
{
// Search for file using search paths
std::string actualPath;
bool found = PathSearcher::getGlobalSearcher().search(path, PathSearcher::kFindFile, true, actualPath);
if (!found)
{
throw std::runtime_error(format_string("unable to find file %s\n", path.c_str()));
}
std::ifstream testStream(actualPath.c_str(), std::ios_base::in | std::ios_base::binary);
if (!testStream.is_open())
{
throw std::runtime_error(format_string("failed to open file: %s", actualPath.c_str()));
}
// catch exceptions so we can close the file stream
try
{
if (ELFSourceFile::isELFFile(testStream))
{
testStream.close();
return new ELFSourceFile(actualPath);
}
else if (SRecordSourceFile::isSRecordFile(testStream))
{
testStream.close();
return new SRecordSourceFile(actualPath);
}
// treat it as a binary file
testStream.close();
return new BinarySourceFile(actualPath);
}
catch (...)
{
testStream.close();
throw;
}
}
SourceFile::SourceFile(const std::string &path)
: m_path(path)
, m_stream()
{
}
//! The file is closed if it had been left opened.
//!
SourceFile::~SourceFile()
{
if (isOpen())
{
m_stream->close();
}
}
//! \exception std::runtime_error Raised if the file could not be opened successfully.
void SourceFile::open()
{
assert(!isOpen());
m_stream = new std::ifstream(m_path.c_str(), std::ios_base::in | std::ios_base::binary);
if (!m_stream->is_open())
{
throw std::runtime_error(format_string("failed to open file: %s", m_path.c_str()));
}
}
void SourceFile::close()
{
assert(isOpen());
m_stream->close();
m_stream.safe_delete();
}
unsigned SourceFile::getSize()
{
bool wasOpen = isOpen();
std::ifstream::pos_type oldPosition;
if (!wasOpen)
{
open();
}
assert(m_stream);
oldPosition = m_stream->tellg();
m_stream->seekg(0, std::ios_base::end);
unsigned resultSize = static_cast<unsigned>(m_stream->tellg());
m_stream->seekg(oldPosition);
if (!wasOpen)
{
close();
}
return resultSize;
}
//! If the file does not support named sections, or if there is not a
//! section with the given name, this method may return NULL.
//!
//! This method is just a small wrapper that creates an
//! FixedMatcher string matcher instance and uses the createDataSource()
//! that takes a reference to a StringMatcher.
DataSource *SourceFile::createDataSource(const std::string &section)
{
FixedMatcher matcher(section);
return createDataSource(matcher);
}
DataTarget *SourceFile::createDataTargetForEntryPoint()
{
if (!hasEntryPoint())
{
return NULL;
}
return new ConstantDataTarget(getEntryPointAddress());
}
DataSource *BinarySourceFile::createDataSource()
{
std::istream *fileStream = getStream();
assert(fileStream);
// get stream size
fileStream->seekg(0, std::ios_base::end);
int length = static_cast<int>(fileStream->tellg());
// allocate buffer
smart_array_ptr<uint8_t> data = new uint8_t[length];
// if (!data)
// {
// throw std::bad_alloc();
// }
// read entire file into the buffer
fileStream->seekg(0, std::ios_base::beg);
if (fileStream->read((char *)data.get(), length).bad())
{
throw std::runtime_error(format_string("unexpected end of file: %s", m_path.c_str()));
}
// create the data source. the buffer is copied, so we can dispose of it.
return new UnmappedDataSource(data, length);
}

View File

@@ -0,0 +1,152 @@
/*
* File: SourceFile.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_SourceFile_h_)
#define _SourceFile_h_
#include <string>
#include <iostream>
#include <fstream>
#include "smart_ptr.h"
#include "DataSource.h"
#include "DataTarget.h"
#include "StringMatcher.h"
#include "OptionContext.h"
namespace elftosb
{
/*!
* \brief Abstract base class for a source file containing executable code.
*
* The purpose of this class cluster is to provide a common interface for
* accessing the contents of different file formats. This is accomplished
* through several small sets of methods along with the DataSource and
* DataTarget classes.
*
* The primary interface for creating instances of SourceFile is the static
* SourceFile::openFile() function. It will create the correct subclass of
* SourceFile by inspecting the file to determine its type.
*/
class SourceFile
{
public:
// \brief Factory function that creates the correct subclass of SourceFile.
static SourceFile *openFile(const std::string &path);
public:
//! \brief Default constructor.
SourceFile(const std::string &path);
//! \brief Destructor.
virtual ~SourceFile();
//! \brief Set the option context.
//!
//! The source file will take ownership of the @a context and delete it
//! when the source file is itself deleted.
inline void setOptions(OptionContext *context) { m_options = context; }
//! \brief Return the option context.
inline const OptionContext *getOptions() const { return m_options; }
//! \brief Returns the path to the file.
inline const std::string &getPath() const { return m_path; }
//! \brief Get the size in bytes of the file.
unsigned getSize();
//! \name Opening and closing
//@{
//! \brief Opens the file.
virtual void open();
//! \brief Closes the file.
virtual void close();
//! \brief Returns whether the file is already open.
virtual bool isOpen() const { return (bool)m_stream && const_cast<std::ifstream *>(m_stream.get())->is_open(); }
//@}
//! \name Format capabilities
//@{
virtual bool supportsNamedSections() const = 0;
virtual bool supportsNamedSymbols() const = 0;
//@}
//! \name Data source creation
//@{
//! \brief Creates a data source from the entire file.
virtual DataSource *createDataSource() = 0;
//! \brief Creates a data source out of one or more sections of the file.
//!
//! The \a selector object is used to perform the section name comparison.
//! If the file does not support named sections, or if there is not a
//! section with the given name, this method may return NULL.
virtual DataSource *createDataSource(StringMatcher &matcher) { return NULL; }
//! \brief Creates a data source out of one section of the file.
virtual DataSource *createDataSource(const std::string &section);
//@}
//! \name Entry point
//@{
//! \brief Returns true if an entry point was set in the file.
virtual bool hasEntryPoint() = 0;
//! \brief Returns the entry point address.
virtual uint32_t getEntryPointAddress() { return 0; }
//@}
//! \name Data target creation
//@{
virtual DataTarget *createDataTargetForSection(const std::string &section) { return NULL; }
virtual DataTarget *createDataTargetForSymbol(const std::string &symbol) { return NULL; }
virtual DataTarget *createDataTargetForEntryPoint();
//@}
//! \name Symbols
//@{
//! \brief Returns whether a symbol exists in the source file.
virtual bool hasSymbol(const std::string &name) { return false; }
//! \brief Returns the value of a symbol.
virtual uint32_t getSymbolValue(const std::string &name) { return 0; }
//! \brief Returns the size of a symbol.
virtual unsigned getSymbolSize(const std::string &name) { return 0; }
//@}
protected:
std::string m_path; //!< Path to the file.
smart_ptr<std::ifstream> m_stream; //!< File stream, or NULL if file is closed.
smart_ptr<OptionContext> m_options; //!< Table of option values.
//! \brief Internal access to the input stream object.
inline std::ifstream *getStream() { return m_stream; }
};
/*!
* \brief Binary data file.
*/
class BinarySourceFile : public SourceFile
{
public:
//! \brief Default constructor.
BinarySourceFile(const std::string &path)
: SourceFile(path)
{
}
//! \name Format capabilities
//@{
virtual bool supportsNamedSections() const { return false; }
virtual bool supportsNamedSymbols() const { return false; }
//@}
//! \brief Creates an unmapped data source from the entire file.
virtual DataSource *createDataSource();
virtual bool hasEntryPoint() { return false; }
};
}; // namespace elftosb
#endif // _SourceFile_h_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,196 @@
/*
* File: StELFFile.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_StELFFile_h_)
#define _StELFFile_h_
#include "stdafx.h"
#include <string>
#include <vector>
#include <map>
#include <iostream>
#include <stdexcept>
#include "ELF.h"
//! Variations of the ARM ELF format.
typedef enum
{
eARMVariant = 1, //!< Standard ARM ELF specification.
eGHSVariant, //!< Green Hills Software variant.
eGCCVariant //!< GNU Compiler Collection variant.
} ELFVariant_t;
//! Possible ARM ELF symbol types.
typedef enum
{
eUnknownSymbol,
eARMSymbol,
eThumbSymbol,
eDataSymbol
} ARMSymbolType_t;
/*!
* \brief Parser for Executable and Linking Format (ELF) files.
*
* The stream passed into the constructor needs to stay open for the life
* of the object. This is because calls to getSectionDataAtIndex() and
* getSegmentDataAtIndex() read the data directly from the input stream.
*/
class StELFFile
{
public:
typedef std::vector<Elf32_Shdr>::const_iterator const_section_iterator;
typedef std::vector<Elf32_Phdr>::const_iterator const_segment_iterator;
public:
//! \brief Constructor.
StELFFile(std::istream &inStream);
//! \brief Destructor.
virtual ~StELFFile();
//! \name File format variant
//@{
//! \brief Return the ELF format variant to which this file is set.
virtual ELFVariant_t ELFVariant() { return m_elfVariant; }
//! \brief Set the ELF format variation to either #eARMVariant or #eGHSVariant.
virtual void setELFVariant(ELFVariant_t variant) { m_elfVariant = variant; }
//@}
//! \name File name
//@{
virtual void setName(const std::string &inName) { m_name = inName; }
virtual std::string getName() const { return m_name; }
//@}
//! \name ELF header
//@{
//! \brief Returns the ELF file header.
inline const Elf32_Ehdr &getFileHeader() const { return m_header; }
//@}
//! \name Sections
//! Methods pertaining to the object file's sections.
//@{
//! \brief Returns the number of sections in the file.
inline unsigned getSectionCount() const { return static_cast<unsigned>(m_sectionHeaders.size()); }
//! \brief Returns a reference to section number \a inIndex.
const Elf32_Shdr &getSectionAtIndex(unsigned inIndex) const;
inline const_section_iterator getSectionBegin() const { return m_sectionHeaders.begin(); }
inline const_section_iterator getSectionEnd() const { return m_sectionHeaders.end(); }
//! \brief Returns the index of the section with the name \a inName.
unsigned getIndexOfSectionWithName(const std::string &inName);
//! \brief Returns the data for the section.
uint8_t *getSectionDataAtIndex(unsigned inIndex);
//! \brief Returns the data for the section.
uint8_t *getSectionData(const_section_iterator inSection);
//@}
//! \name Segments
//! Methods for accessing the file's program headers for segments.
//@{
//! \brief Returns the number of segments, or program headers, in the file.
inline unsigned getSegmentCount() const { return static_cast<unsigned>(m_programHeaders.size()); }
//! \brief Returns a reference to the given segment.
const Elf32_Phdr &getSegmentAtIndex(unsigned inIndex) const;
inline const_segment_iterator getSegmentBegin() const { return m_programHeaders.begin(); }
inline const_segment_iterator getSegmentEnd() const { return m_programHeaders.end(); }
//! \brief Returns the data of the specified segment.
uint8_t *getSegmentDataAtIndex(unsigned inIndex);
//! \brief Returns the data of the specified segment.
uint8_t *getSegmentData(const_segment_iterator inSegment);
//@}
//! \name String table
//! Methods for accessing the string tables.
//@{
//! \brief Returns a string from the file's section name string table.
std::string getSectionNameAtIndex(unsigned inIndex);
//! \brief Returns a string from any string table in the object file.
std::string getStringAtIndex(unsigned inStringTableSectionIndex, unsigned inStringIndex);
//@}
//! \name Symbol table
//! Methods for accessing the object file's symbol table. Currently only
//! a single symbol table with the section name ".symtab" is supported.
//@{
//! \brief Returns the number of symbols in the default ".symtab" symbol table.
unsigned getSymbolCount();
//! \brief Returns the symbol with index \a inIndex.
const Elf32_Sym &getSymbolAtIndex(unsigned inIndex);
//! \brief Returns the section index of the string table containing symbol names.
unsigned getSymbolNameStringTableIndex() const;
//! \brief Returns the name of the symbol described by \a inSymbol.
std::string getSymbolName(const Elf32_Sym &inSymbol);
unsigned getIndexOfSymbolAtAddress(uint32_t symbolAddress, bool strict = true);
ARMSymbolType_t getTypeOfSymbolAtIndex(unsigned symbolIndex);
//@}
//! \name Debugging
//@{
void dumpSections();
void dumpSymbolTable();
//@}
protected:
std::istream &m_stream; //!< The source stream for the ELF file.
ELFVariant_t m_elfVariant; //!< Variant of the ARM ELF format specification.
std::string m_name; //!< File name. (optional)
Elf32_Ehdr m_header; //!< The ELF file header.
std::vector<Elf32_Shdr> m_sectionHeaders; //!< All of the section headers.
std::vector<Elf32_Phdr> m_programHeaders; //!< All of the program headers.
unsigned m_symbolTableIndex; //!< Index of ".symtab" section, or #SHN_UNDEF if not present.
/*!
* Little structure containing information about cached section data.
*/
struct SectionDataInfo
{
uint8_t *m_data; //!< Pointer to section data.
unsigned m_size; //!< Section data size in bytes.
bool m_swapped; //!< Has this section been byte swapped yet? Used for symbol table.
};
typedef std::map<unsigned, SectionDataInfo> SectionDataMap;
SectionDataMap m_sectionDataCache; //!< Cached data of sections.
//! \brief Reads a section's data either from cache or from disk.
SectionDataInfo &getCachedSectionData(unsigned inSectionIndex);
//! \brief Reads the file, section, and program headers into memory.
void readFileHeaders();
uint8_t *readSectionData(const Elf32_Shdr &inHeader);
uint8_t *readSegmentData(const Elf32_Phdr &inHeader);
//! \brief Byte swaps the symbol table data into host endianness.
void byteSwapSymbolTable(const Elf32_Shdr &header, SectionDataInfo &info);
};
/*!
* \brief Simple exception thrown to indicate an error in the input ELF file format.
*/
class StELFFileException : public std::runtime_error
{
public:
//! \brief Default constructor.
StELFFileException(const std::string &inMessage)
: std::runtime_error(inMessage)
{
}
};
#endif // _StELFFile_h_

View File

@@ -0,0 +1,464 @@
/*
* File: StExecutableImage.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "StExecutableImage.h"
#include <stdexcept>
#include <algorithm>
#include <string.h>
#include <stdio.h>
StExecutableImage::StExecutableImage(int inAlignment)
: m_alignment(inAlignment)
, m_hasEntry(false)
, m_entry(0)
{
}
//! Makes a duplicate of each memory region.
StExecutableImage::StExecutableImage(const StExecutableImage &inOther)
: m_name(inOther.m_name)
, m_alignment(inOther.m_alignment)
, m_hasEntry(inOther.m_hasEntry)
, m_entry(inOther.m_entry)
, m_filters(inOther.m_filters)
{
const_iterator it = inOther.getRegionBegin();
for (; it != inOther.getRegionEnd(); ++it)
{
const MemoryRegion &region = *it;
MemoryRegion regionCopy(region);
if (region.m_type == FILL_REGION && region.m_data != NULL)
{
regionCopy.m_data = new uint8_t[region.m_length];
memcpy(regionCopy.m_data, region.m_data, region.m_length);
}
m_image.push_back(regionCopy);
}
}
//! Disposes of memory allocated for each region.
StExecutableImage::~StExecutableImage()
{
MemoryRegionList::iterator it;
for (it = m_image.begin(); it != m_image.end(); ++it)
{
if (it->m_data)
{
delete[] it->m_data;
it->m_data = NULL;
}
}
}
//! A copy of \a inName is made, so the original may be disposed of by the caller
//! after this method returns.
void StExecutableImage::setName(const std::string &inName)
{
m_name = inName;
}
std::string StExecutableImage::getName() const
{
return m_name;
}
// The region is added with read and write flags set.
//! \exception std::runtime_error will be thrown if the new overlaps an
//! existing region.
void StExecutableImage::addFillRegion(uint32_t inAddress, unsigned inLength)
{
MemoryRegion region;
region.m_type = FILL_REGION;
region.m_address = inAddress;
region.m_data = NULL;
region.m_length = inLength;
region.m_flags = REGION_RW_FLAG;
insertOrMergeRegion(region);
}
//! A copy of \a inData is made before returning. The copy will be deleted when
//! the executable image is destructed. Currently, the text region is created with
//! read, write, and executable flags set.
//! \exception std::runtime_error will be thrown if the new overlaps an
//! existing region.
//! \exception std::bad_alloc is thrown if memory for the copy of \a inData
//! cannot be allocated.
void StExecutableImage::addTextRegion(uint32_t inAddress, const uint8_t *inData, unsigned inLength)
{
MemoryRegion region;
region.m_type = TEXT_REGION;
region.m_address = inAddress;
region.m_flags = REGION_RW_FLAG | REGION_EXEC_FLAG;
// copy the data
region.m_data = new uint8_t[inLength];
region.m_length = inLength;
memcpy(region.m_data, inData, inLength);
insertOrMergeRegion(region);
}
//! \exception std::out_of_range is thrown if \a inIndex is out of range.
//!
const StExecutableImage::MemoryRegion &StExecutableImage::getRegionAtIndex(unsigned inIndex) const
{
// check bounds
if (inIndex >= m_image.size())
throw std::out_of_range("inIndex");
// find region by index
MemoryRegionList::const_iterator it = m_image.begin();
unsigned i = 0;
for (; it != m_image.end(); ++it, ++i)
{
if (i == inIndex)
break;
}
return *it;
}
//! The list of address filters is kept sorted as filters are added.
//!
void StExecutableImage::addAddressFilter(const AddressFilter &filter)
{
m_filters.push_back(filter);
m_filters.sort();
}
//!
void StExecutableImage::clearAddressFilters()
{
m_filters.clear();
}
//! \exception StExecutableImage::address_filter_exception Raised when a filter
//! with the type #ADDR_FILTER_ERROR or #ADDR_FILTER_WARNING is matched.
//!
//! \todo Build a list of all matching filters and then execute them at once.
//! For the warning and error filters, a single exception should be raised
//! that identifies all the overlapping errors. Currently the user will only
//! see the first (lowest address) overlap.
void StExecutableImage::applyAddressFilters()
{
restart_loops:
// Iterate over filters.
AddressFilterList::const_iterator fit = m_filters.begin();
for (; fit != m_filters.end(); ++fit)
{
const AddressFilter &filter = *fit;
// Iterator over regions.
MemoryRegionList::iterator rit = m_image.begin();
for (; rit != m_image.end(); ++rit)
{
MemoryRegion &region = *rit;
if (filter.matchesMemoryRegion(region))
{
switch (filter.m_action)
{
case ADDR_FILTER_NONE:
// Do nothing.
break;
case ADDR_FILTER_ERROR:
// throw error exception
throw address_filter_exception(true, m_name, filter);
break;
case ADDR_FILTER_WARNING:
// throw warning exception
throw address_filter_exception(false, m_name, filter);
break;
case ADDR_FILTER_CROP:
// Delete the offending portion of the region and restart
// the iteration loops.
cropRegionToFilter(region, filter);
goto restart_loops;
break;
}
}
}
}
}
//! There are several possible cases here:
//! - No overlap at all. Nothing is done.
//!
//! - All of the memory region is matched by the \a filter. The region is
//! removed from #StExecutableImage::m_image and its data memory freed.
//!
//! - The remaining portion of the region is one contiguous chunk. In this
//! case, \a region is simply modified.
//!
//! - The region is split in the middle by the filter. The original \a region
//! is modified to match the first remaining chunk. And a new #StExecutableImage::MemoryRegion
//! instance is created to hold the other leftover piece.
void StExecutableImage::cropRegionToFilter(MemoryRegion &region, const AddressFilter &filter)
{
uint32_t firstByte = region.m_address; // first byte occupied by this region
uint32_t lastByte = region.endAddress(); // last used byte in this region
// compute new address range
uint32_t cropFrom = filter.m_fromAddress;
if (cropFrom < firstByte)
{
cropFrom = firstByte;
}
uint32_t cropTo = filter.m_toAddress;
if (cropTo > lastByte)
{
cropTo = lastByte;
}
// is there actually a match?
if (cropFrom > filter.m_toAddress || cropTo < filter.m_fromAddress)
{
// nothing to do, so bail
return;
}
printf("Deleting region 0x%08x-0x%08x\n", cropFrom, cropTo);
// handle if the entire region is to be deleted
if (cropFrom == firstByte && cropTo == lastByte)
{
delete[] region.m_data;
region.m_data = NULL;
m_image.remove(region);
}
// there is at least a little of the original region remaining
uint32_t newLength = cropTo - cropFrom + 1;
uint32_t leftoverLength = lastByte - cropTo;
uint8_t *oldData = region.m_data;
// update the region
region.m_address = cropFrom;
region.m_length = newLength;
// crop data buffer for text regions
if (region.m_type == TEXT_REGION && oldData)
{
region.m_data = new uint8_t[newLength];
memcpy(region.m_data, &oldData[cropFrom - firstByte], newLength);
// dispose of old data
delete[] oldData;
}
// create a new region for any part of the original region that was past
// the crop to address. this will happen if the filter range falls in the
// middle of the region.
if (leftoverLength)
{
MemoryRegion newRegion;
newRegion.m_type = region.m_type;
newRegion.m_flags = region.m_flags;
newRegion.m_address = cropTo + 1;
newRegion.m_length = leftoverLength;
if (region.m_type == TEXT_REGION && oldData)
{
newRegion.m_data = new uint8_t[leftoverLength];
memcpy(newRegion.m_data, &oldData[cropTo - firstByte + 1], leftoverLength);
}
insertOrMergeRegion(newRegion);
}
}
//! \exception std::runtime_error will be thrown if \a inRegion overlaps an
//! existing region.
//!
//! \todo Need to investigate if we can use the STL sort algorithm at all. Even
//! though we're doing merges too, we could sort first then examine the list
//! for merges.
void StExecutableImage::insertOrMergeRegion(MemoryRegion &inRegion)
{
uint32_t newStart = inRegion.m_address;
uint32_t newEnd = newStart + inRegion.m_length;
MemoryRegionList::iterator it = m_image.begin();
// MemoryRegionList::iterator sortedPosition = m_image.begin();
for (; it != m_image.end(); ++it)
{
MemoryRegion &region = *it;
uint32_t thisStart = region.m_address;
uint32_t thisEnd = thisStart + region.m_length;
// keep track of where to insert it to retain sort order
if (thisStart >= newEnd)
{
break;
}
// region types and flags must match in order to merge
if (region.m_type == inRegion.m_type && region.m_flags == inRegion.m_flags)
{
if (newStart == thisEnd || newEnd == thisStart)
{
mergeRegions(region, inRegion);
return;
}
else if ((newStart >= thisStart && newStart < thisEnd) || (newEnd >= thisStart && newEnd < thisEnd))
{
throw std::runtime_error("new region overlaps existing region");
}
}
}
// not merged, so just insert it in the sorted position
m_image.insert(it, inRegion);
}
//! Extends \a inNewRegion to include the data in \a inOldRegion. It is
//! assumed that the two regions are compatible. The new region may come either
//! before or after the old region in memory. Note that while the two regions
//! don't necessarily have to be touching, it's probably a good idea. That's
//! because any data between the regions will be set to 0.
//!
//! For TEXT_REGION types, the two original regions will have their data deleted
//! during the merge. Thus, this method is not safe if any outside callers may
//! be accessing the region's data.
void StExecutableImage::mergeRegions(MemoryRegion &inOldRegion, MemoryRegion &inNewRegion)
{
bool isOldBefore = inOldRegion.m_address < inNewRegion.m_address;
uint32_t oldEnd = inOldRegion.m_address + inOldRegion.m_length;
uint32_t newEnd = inNewRegion.m_address + inNewRegion.m_length;
switch (inOldRegion.m_type)
{
case TEXT_REGION:
{
// calculate new length
unsigned newLength;
if (isOldBefore)
{
newLength = newEnd - inOldRegion.m_address;
}
else
{
newLength = oldEnd - inNewRegion.m_address;
}
// alloc memory
uint8_t *newData = new uint8_t[newLength];
memset(newData, 0, newLength);
// copy data from the two regions into new block
if (isOldBefore)
{
memcpy(newData, inOldRegion.m_data, inOldRegion.m_length);
memcpy(&newData[newLength - inNewRegion.m_length], inNewRegion.m_data, inNewRegion.m_length);
}
else
{
memcpy(newData, inNewRegion.m_data, inNewRegion.m_length);
memcpy(&newData[newLength - inOldRegion.m_length], inOldRegion.m_data, inOldRegion.m_length);
inOldRegion.m_address = inNewRegion.m_address;
}
// replace old region's data
delete[] inOldRegion.m_data;
inOldRegion.m_data = newData;
inOldRegion.m_length = newLength;
// delete new region's data
delete[] inNewRegion.m_data;
inNewRegion.m_data = NULL;
break;
}
case FILL_REGION:
{
if (isOldBefore)
{
inOldRegion.m_length = newEnd - inOldRegion.m_address;
}
else
{
inOldRegion.m_length = oldEnd - inNewRegion.m_address;
inOldRegion.m_address = inNewRegion.m_address;
}
break;
}
}
}
//! Used when we remove a region from the region list by value. Because this
//! operator compares the #m_data member, it will only return true for either an
//! exact copy or a reference to the original.
bool StExecutableImage::MemoryRegion::operator==(const MemoryRegion &other) const
{
return (m_type == other.m_type) && (m_address == other.m_address) && (m_length == other.m_length) &&
(m_flags == other.m_flags) && (m_data == other.m_data);
}
//! Returns true if the address filter overlaps \a region.
bool StExecutableImage::AddressFilter::matchesMemoryRegion(const MemoryRegion &region) const
{
uint32_t firstByte = region.m_address; // first byte occupied by this region
uint32_t lastByte = region.endAddress(); // last used byte in this region
return (firstByte >= m_fromAddress && firstByte <= m_toAddress) ||
(lastByte >= m_fromAddress && lastByte <= m_toAddress);
}
//! The comparison does \em not take the action into account. It only looks at the
//! priority and address ranges of each filter. Priority is considered only if the two
//! filters overlap. Lower priority filters will come after higher priority ones.
//!
//! \retval -1 This filter is less than filter \a b.
//! \retval 0 This filter is equal to filter \a b.
//! \retval 1 This filter is greater than filter \a b.
int StExecutableImage::AddressFilter::compare(const AddressFilter &other) const
{
if (m_priority != other.m_priority &&
((m_fromAddress >= other.m_fromAddress && m_fromAddress <= other.m_toAddress) ||
(m_toAddress >= other.m_fromAddress && m_toAddress <= other.m_toAddress)))
{
// we know the priorities are not equal
if (m_priority > other.m_priority)
{
return -1;
}
else
{
return 1;
}
}
if (m_fromAddress == other.m_fromAddress)
{
if (m_toAddress == other.m_toAddress)
{
return 0;
}
else if (m_toAddress < other.m_toAddress)
{
return -1;
}
else
{
return 1;
}
}
else if (m_fromAddress < other.m_fromAddress)
{
return -1;
}
else
{
return 1;
}
}

View File

@@ -0,0 +1,257 @@
/*
* File: StExecutableImage.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_StExecutableImage_h_)
#define _StExecutableImage_h_
#include "stdafx.h"
#include <list>
/*!
* \brief Used to build a representation of memory regions.
*
* An intermediate representation of the memory regions and segments loaded
* from an executable file. Also used to find contiguous segments that are
* specified separately in the source file.
*
* When regions are added, an attempt is made to coalesce contiguous regions.
* In order for this to succeed, the touching regions must be of the same
* type and have the same permissions. Regions are also kept sorted by their
* address range as they are added.
*
* \todo Implement alignment support.
*/
class StExecutableImage
{
public:
//! Possible types of memory regions.
typedef enum
{
TEXT_REGION, //!< A region containing data or instructions.
FILL_REGION //!< Region to be initialized with zero bytes.
} MemoryRegionType;
//! Memory region flag constants.
enum
{
REGION_READ_FLAG = 1, //!< Region is readable.
REGION_WRITE_FLAG = 2, //!< Region is writable.
REGION_EXEC_FLAG = 4, //!< Region may contain executable code.
REGION_RW_FLAG = REGION_READ_FLAG | REGION_WRITE_FLAG, //!< Region is read-write.
//! Mask to access only permissions flags for a region.
REGION_PERM_FLAG_MASK = 0x7
};
/*!
* Representation of a contiguous region of memory.
*
* \todo Add comparison operators so we can use the STL sort algorithm.
*/
struct MemoryRegion
{
MemoryRegionType m_type; //!< Memory region type.
uint32_t m_address; //!< The 32-bit start address of this region.
uint32_t m_length; //!< Number of bytes in this region.
uint8_t *m_data; //!< Pointer to data. Will be NULL for FILL_REGION type.
unsigned m_flags; //!< Flags for the region.
//! \brief Calculates the address of the last byte occupied by this region.
inline uint32_t endAddress() const { return m_address + m_length - 1; }
//! \brief Equality operator.
bool operator==(const MemoryRegion &other) const;
};
//! A list of #StExecutableImage::MemoryRegion objects.
typedef std::list<MemoryRegion> MemoryRegionList;
//! The iterator type used to access #StExecutableImage::MemoryRegion objects. This type
//! is used by the methods #getRegionBegin() and #getRegionEnd().
typedef MemoryRegionList::const_iterator const_iterator;
//! The possible actions for regions matching an address filter range.
typedef enum
{
ADDR_FILTER_NONE, //!< Do nothing.
ADDR_FILTER_ERROR, //!< Raise an error exception.
ADDR_FILTER_WARNING, //!< Raise a warning exception.
ADDR_FILTER_CROP //!< Don't include the matching address range in the executable image.
} AddressFilterAction;
/*!
* An address filter consists of a single address range and an action. If a
* memory region overlaps the filter's range then the action will be performed.
* The possible filter actions are defined by the #AddressFilterAction enumeration.
*/
struct AddressFilter
{
AddressFilterAction m_action; //!< Action to be performed when the filter is matched.
uint32_t m_fromAddress; //!< Start address of the filter. Should be lower than or equal to #m_toAddress.
uint32_t m_toAddress; //!< End address of the filter. Should be higher than or equal to #m_fromAddress.
unsigned m_priority; //!< Priority for this filter. Zero is the lowest priority.
//! \brief Constructor.
AddressFilter(AddressFilterAction action, uint32_t from, uint32_t to, unsigned priority = 0)
: m_action(action)
, m_fromAddress(from)
, m_toAddress(to)
, m_priority(priority)
{
}
//! \brief Test routine.
bool matchesMemoryRegion(const MemoryRegion &region) const;
//! \brief Compares two address filter objects.
int compare(const AddressFilter &other) const;
//! \name Comparison operators
//@{
inline bool operator<(const AddressFilter &other) const { return compare(other) == -1; }
inline bool operator>(const AddressFilter &other) const { return compare(other) == 1; }
inline bool operator==(const AddressFilter &other) const { return compare(other) == 0; }
inline bool operator<=(const AddressFilter &other) const { return compare(other) != 1; }
inline bool operator>=(const AddressFilter &other) const { return compare(other) != -1; }
//@}
};
//! List of #StExecutableImage::AddressFilter objects.
typedef std::list<AddressFilter> AddressFilterList;
//! The exception class raised for the #ADDR_FILTER_ERROR and #ADDR_FILTER_WARNING
//! filter actions.
class address_filter_exception
{
public:
//! \brief Constructor.
//!
//! A local copy of \a matchingFilter is made, in case the image and/or filter
//! are on the stack and would be disposed of when the exception is raised.
address_filter_exception(bool isError, std::string &imageName, const AddressFilter &matchingFilter)
: m_isError(isError)
, m_imageName(imageName)
, m_filter(matchingFilter)
{
}
//! \brief Returns true if the exception is an error. Otherwise the exception
//! is for a warning.
inline bool isError() const { return m_isError; }
//! \brief
inline std::string getImageName() const { return m_imageName; }
//! \brief
inline const AddressFilter &getMatchingFilter() const { return m_filter; }
protected:
bool m_isError;
std::string m_imageName;
AddressFilter m_filter;
};
public:
//! \brief Constructor.
StExecutableImage(int inAlignment = 256);
//! \brief Copy constructor.
StExecutableImage(const StExecutableImage &inOther);
//! \brief Destructor.
virtual ~StExecutableImage();
//! \name Image name
//! Methods for getting and setting the image name.
//@{
//! \brief Sets the image's name to \a inName.
virtual void setName(const std::string &inName);
//! \brief Returns a copy of the image's name.
virtual std::string getName() const;
//@}
//! \name Regions
//! Methods to add and access memory regions.
//@{
//! \brief Add a region to be filled with zeroes.
virtual void addFillRegion(uint32_t inAddress, unsigned inLength);
//! \brief Add a region containing data to be loaded.
virtual void addTextRegion(uint32_t inAddress, const uint8_t *inData, unsigned inLength);
//! \brief Returns the total number of regions.
//!
//! Note that this count may not be the same as the number of calls to
//! addFillRegion() and addTextRegion() due to region coalescing.
inline unsigned getRegionCount() const { return static_cast<unsigned>(m_image.size()); }
//! \brief Returns a reference to the region specified by \a inIndex.
const MemoryRegion &getRegionAtIndex(unsigned inIndex) const;
//! \brief Return an iterator to the first region.
inline const_iterator getRegionBegin() const { return m_image.begin(); }
//! \brief Return an iterator to the next-after-last region.
inline const_iterator getRegionEnd() const { return m_image.end(); }
//@}
//! \name Entry point
//@{
//! \brief Sets the entry point address.
inline void setEntryPoint(uint32_t inEntryAddress)
{
m_entry = inEntryAddress;
m_hasEntry = true;
}
//! \brief Returns true if an entry point has been set.
inline bool hasEntryPoint() const { return m_hasEntry; }
//! \brief Returns the entry point address.
inline uint32_t getEntryPoint() const { return hasEntryPoint() ? m_entry : 0; }
//@}
//! \name Address filter
//@{
//! \brief Add a new address filter.
virtual void addAddressFilter(const AddressFilter &filter);
//! \brief Add multiple address filters at once.
//!
//! The template argument \a _T must be an iterator or const iterator that
//! dereferences to an StExecutableImage::AddressFilter reference. All filters
//! from \a from to \a to will be added to the address filter list.
template <typename _T>
void addAddressFilters(_T from, _T to)
{
_T it = from;
for (; it != to; ++it)
{
addAddressFilter(*it);
}
}
//! \brief Remove all active filters.
virtual void clearAddressFilters();
//! \brief Process all active filters and perform associated actions.
virtual void applyAddressFilters();
//@}
protected:
std::string m_name; //!< The name of the image (can be a file name, for instance).
int m_alignment; //!< The required address alignment for each memory region.
bool m_hasEntry; //!< True if an entry point has been set.
uint32_t m_entry; //!< Entry point address.
MemoryRegionList m_image; //!< The memory regions.
AddressFilterList m_filters; //!< List of active address filters.
//! \brief Deletes the portion \a region that overlaps \a filter.
void cropRegionToFilter(MemoryRegion &region, const AddressFilter &filter);
//! \brief Inserts the region in sorted order or merges with one already in the image.
void insertOrMergeRegion(MemoryRegion &inRegion);
//! \brief Merges two memory regions into one.
void mergeRegions(MemoryRegion &inOldRegion, MemoryRegion &inNewRegion);
};
#endif // _StExecutableImage_h_

View File

@@ -0,0 +1,236 @@
/*
* File: StSRecordFile.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "stdafx.h"
#include "StSRecordFile.h"
#include "string.h"
StSRecordFile::StSRecordFile(std::istream &inStream)
: m_stream(inStream)
{
}
//! Frees any data allocated as part of an S-record.
StSRecordFile::~StSRecordFile()
{
const_iterator it;
for (it = m_records.begin(); it != m_records.end(); it++)
{
SRecord &theRecord = (SRecord &)*it;
if (theRecord.m_data)
{
delete[] theRecord.m_data;
theRecord.m_data = NULL;
}
}
}
//! Just looks for "S[0-9]" as the first two characters of the file.
bool StSRecordFile::isSRecordFile()
{
int savePosition = static_cast<int>(m_stream.tellg());
m_stream.seekg(0, std::ios_base::beg);
char buffer[2];
m_stream.read(buffer, 2);
bool isSRecord = (buffer[0] == 'S' && isdigit(buffer[1]));
m_stream.seekg(savePosition, std::ios_base::beg);
return isSRecord;
}
//! Extract records one line at a time and hand them to the parseLine()
//! method. Either CR, LF, or CRLF line endings are supported. The input
//! stream is read until EOF.
//! The parse() method must be called after the object has been constructed
//! before any of the records will become accessible.
//! \exception StSRecordParseException will be thrown if any error occurs while
//! parsing the input.
void StSRecordFile::parse()
{
// back to start of stream
m_stream.seekg(0, std::ios_base::beg);
std::string thisLine;
do
{
char thisChar;
m_stream.get(thisChar);
if (thisChar == '\r' || thisChar == '\n')
{
// skip the LF in a CRLF
if (thisChar == '\r' && m_stream.peek() == '\n')
m_stream.ignore();
// parse line if it's not empty
if (!thisLine.empty())
{
parseLine(thisLine);
// reset line
thisLine.clear();
}
}
else
{
thisLine += thisChar;
}
} while (!m_stream.eof());
}
bool StSRecordFile::isHexDigit(char c)
{
return (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
}
int StSRecordFile::hexDigitToInt(char digit)
{
if (isdigit(digit))
return digit - '0';
else if (digit >= 'a' && digit <= 'f')
return 10 + digit - 'a';
else if (digit >= 'A' && digit <= 'F')
return 10 + digit - 'A';
// unknow char
return 0;
}
//! \exception StSRecordParseException is thrown if either of the nibble characters
//! is not a valid hex digit.
int StSRecordFile::readHexByte(std::string &inString, int inIndex)
{
char nibbleCharHi = inString[inIndex];
char nibbleCharLo = inString[inIndex + 1];
// must be hex digits
if (!(isHexDigit(nibbleCharHi) && isHexDigit(nibbleCharLo)))
{
throw StSRecordParseException("invalid hex digit");
}
return (hexDigitToInt(nibbleCharHi) << 4) | hexDigitToInt(nibbleCharLo);
}
//! \brief Parses individual S-records.
//!
//! Takes a single S-record line as input and appends a new SRecord struct
//! to the m_records vector.
//! \exception StSRecordParseException will be thrown if any error occurs while
//! parsing \a inLine.
void StSRecordFile::parseLine(std::string &inLine)
{
int checksum = 0;
SRecord newRecord;
memset(&newRecord, 0, sizeof(newRecord));
// must start with "S" and be at least a certain length
if (inLine[0] != SRECORD_START_CHAR && inLine.length() >= SRECORD_MIN_LENGTH)
{
throw StSRecordParseException("invalid record length");
}
// parse type field
char typeChar = inLine[1];
if (!isdigit(typeChar))
{
throw StSRecordParseException("invalid S-record type");
}
newRecord.m_type = typeChar - '0';
// parse count field
newRecord.m_count = readHexByte(inLine, 2);
checksum += newRecord.m_count;
// verify the record length now that we know the count
if (inLine.length() != 4 + newRecord.m_count * 2)
{
throw StSRecordParseException("invalid record length");
}
// get address length
int addressLength = 0; // len in bytes
bool hasData = false;
switch (newRecord.m_type)
{
case 0: // contains header information
addressLength = 2;
hasData = true;
break;
case 1: // data record with 2-byte address
addressLength = 2;
hasData = true;
break;
case 2: // data record with 3-byte address
addressLength = 3;
hasData = true;
break;
case 3: // data record with 4-byte address
addressLength = 4;
hasData = true;
break;
case 5: // the 2-byte address field contains a count of all prior S1, S2, and S3 records
addressLength = 2;
break;
case 7: // entry point record with 4-byte address
addressLength = 4;
break;
case 8: // entry point record with 3-byte address
addressLength = 3;
break;
case 9: // entry point record with 2-byte address
addressLength = 2;
break;
default:
// unrecognized type
// throw StSRecordParseException("unknown S-record type");
break;
}
// read address
int address = 0;
int i;
for (i = 0; i < addressLength; ++i)
{
int addressByte = readHexByte(inLine, SRECORD_ADDRESS_START_CHAR_INDEX + i * 2);
address = (address << 8) | addressByte;
checksum += addressByte;
}
newRecord.m_address = address;
// read data
if (hasData)
{
int dataStartCharIndex = 4 + addressLength * 2;
int dataLength = newRecord.m_count - addressLength - 1; // total rem - addr - cksum (in bytes)
uint8_t *data = new uint8_t[dataLength];
for (i = 0; i < dataLength; ++i)
{
int dataByte = readHexByte(inLine, dataStartCharIndex + i * 2);
data[i] = dataByte;
checksum += dataByte;
}
newRecord.m_data = data;
newRecord.m_dataCount = dataLength;
}
// read and compare checksum byte
checksum = (~checksum) & 0xff; // low byte of one's complement of sum of other bytes
newRecord.m_checksum = readHexByte(inLine, (int)inLine.length() - 2);
if (checksum != newRecord.m_checksum)
{
throw StSRecordParseException("invalid checksum");
}
// now save the new S-record
m_records.push_back(newRecord);
}

View File

@@ -0,0 +1,122 @@
/*
* File: StSRecordFile.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_StSRecordFile_h_)
#define _StSRecordFile_h_
//#include <stdint.h>
#include "stdafx.h"
#include <istream>
#include <string>
#include <vector>
#include <stdexcept>
enum
{
//! The required first character of an S-record.
SRECORD_START_CHAR = 'S',
//! The minimum length of a S-record. This is the type (2) + count (2) + addr (4) + cksum (2).
SRECORD_MIN_LENGTH = 10,
//! Index of the first character of the address field.
SRECORD_ADDRESS_START_CHAR_INDEX = 4
};
/*!
* \brief S-record parser.
*
* This class takes an input stream and parses it as an S-record file. While
* the individual records that comprise the file are available for access, the
* class also provides a higher-level view of the contents. It processes the
* individual records and builds an image of what the memory touched by the
* file looks like. Then you can access the contiguous sections of memory.
*/
class StSRecordFile
{
public:
/*!
* Structure representing each individual line of the S-record input data.
*/
struct SRecord
{
unsigned m_type; //!< Record number type, such as 9 for "S9", 3 for "S3" and so on.
unsigned m_count; //!< Number of character pairs (bytes) from address through checksum.
uint32_t m_address; //!< The address specified as part of the S-record.
unsigned m_dataCount; //!< Number of bytes of data.
uint8_t *m_data; //!< Pointer to data, or NULL if no data for this record type.
uint8_t m_checksum; //!< The checksum byte present in the S-record.
};
//! Iterator type.
typedef std::vector<SRecord>::const_iterator const_iterator;
public:
//! \brief Constructor.
StSRecordFile(std::istream &inStream);
//! \brief Destructor.
virtual ~StSRecordFile();
//! \name File name
//@{
virtual void setName(const std::string &inName) { m_name = inName; }
virtual std::string getName() const { return m_name; }
//@}
//! \name Parsing
//@{
//! \brief Determine if the file is an S-record file.
virtual bool isSRecordFile();
//! \brief Parses the entire S-record input stream.
virtual void parse();
//@}
//! \name Record access
//@{
//! \return the number of S-records that have been parsed from the input stream.
inline unsigned getRecordCount() const { return static_cast<unsigned>(m_records.size()); }
//! \return iterator for
inline const_iterator getBegin() const { return m_records.begin(); }
inline const_iterator getEnd() const { return m_records.end(); }
//@}
//! \name Operators
//@{
inline const SRecord &operator[](unsigned inIndex) { return m_records[inIndex]; }
//@}
protected:
std::istream &m_stream; //!< The input stream for the S-record data.
std::vector<SRecord> m_records; //!< Vector of S-records in the input data.
std::string m_name; //!< File name. (optional)
//! \name Parsing utilities
//@{
virtual void parseLine(std::string &inLine);
bool isHexDigit(char c);
int hexDigitToInt(char digit);
int readHexByte(std::string &inString, int inIndex);
//@}
};
/*!
* \brief Simple exception thrown to indicate an error in the input SRecord data format.
*/
class StSRecordParseException : public std::runtime_error
{
public:
//! \brief Default constructor.
StSRecordParseException(const std::string &inMessage)
: std::runtime_error(inMessage)
{
}
};
#endif // _StSRecordFile_h_

View File

@@ -0,0 +1,60 @@
/*
* File: GlobSectionSelector.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_StringMatcher_h_)
#define _StringMatcher_h_
#include <string>
namespace elftosb
{
/*!
* \brief Abstract interface class used to select strings by name.
*/
class StringMatcher
{
public:
//! \brief Performs a single string match test against testValue.
//!
//! \retval true The \a testValue argument matches.
//! \retval false No match was made against the argument.
virtual bool match(const std::string &testValue) = 0;
};
/*!
* \brief String matcher subclass that matches all test strings.
*/
class WildcardMatcher : public StringMatcher
{
public:
//! \brief Always returns true, indicating a positive match.
virtual bool match(const std::string &testValue) { return true; }
};
/*!
* \brief Simple string matcher that compares against a fixed value.
*/
class FixedMatcher : public StringMatcher
{
public:
//! \brief Constructor. Sets the string to compare against to be \a fixedValue.
FixedMatcher(const std::string &fixedValue)
: m_value(fixedValue)
{
}
//! \brief Returns whether \a testValue is the same as the value passed to the constructor.
//!
//! \retval true The \a testValue argument matches the fixed compare value.
//! \retval false The argument is not the same as the compare value.
virtual bool match(const std::string &testValue) { return testValue == m_value; }
protected:
const std::string &m_value; //!< The section name to look for.
};
}; // namespace elftosb
#endif // _StringMatcher_h_

View File

@@ -0,0 +1,42 @@
/*
* File: Value.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "Value.h"
using namespace elftosb;
//! Returns a varying size depending on the word size attribute.
//!
size_t SizedIntegerValue::getSize() const
{
switch (m_size)
{
case kWordSize:
return sizeof(uint32_t);
case kHalfWordSize:
return sizeof(uint16_t);
case kByteSize:
return sizeof(uint8_t);
}
return kWordSize;
}
//! The resulting mask can be used to truncate the integer value to be
//! certain it doesn't extend beyond the associated word size.
uint32_t SizedIntegerValue::getWordSizeMask() const
{
switch (m_size)
{
case kWordSize:
return 0xffffffff;
case kHalfWordSize:
return 0x0000ffff;
case kByteSize:
return 0x000000ff;
}
return 0;
}

206
apps/elftosb/common/Value.h Normal file
View File

@@ -0,0 +1,206 @@
/*
* File: Value.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_Value_h_)
#define _Value_h_
#include "stdafx.h"
#include <string>
#include "int_size.h"
#include "Blob.h"
namespace elftosb
{
/*!
* \brief Abstract base class for values of arbitrary types.
*/
class Value
{
public:
Value() {}
virtual ~Value() {}
virtual std::string getTypeName() const = 0;
virtual size_t getSize() const = 0;
};
/*!
* \brief 32-bit signed integer value.
*/
class IntegerValue : public Value
{
public:
IntegerValue()
: m_value(0)
{
}
IntegerValue(uint32_t value)
: m_value(value)
{
}
IntegerValue(const IntegerValue &other)
: m_value(other.m_value)
{
}
virtual std::string getTypeName() const { return "integer"; }
virtual size_t getSize() const { return sizeof(m_value); }
inline uint32_t getValue() const { return m_value; }
inline operator uint32_t() const { return m_value; }
inline IntegerValue &operator=(uint32_t value)
{
m_value = value;
return *this;
}
protected:
uint32_t m_value; //!< The integer value.
};
/*!
* \brief Adds a word size attribute to IntegerValue.
*
* The word size really only acts as an attribute that is carried along
* with the integer value. It doesn't affect the actual value at all.
* However, you can use the getWordSizeMask() method to mask off bits
* that should not be there.
*
* The word size defaults to a 32-bit word.
*/
class SizedIntegerValue : public IntegerValue
{
public:
SizedIntegerValue()
: IntegerValue()
, m_size(kWordSize)
{
}
SizedIntegerValue(uint32_t value, int_size_t size = kWordSize)
: IntegerValue(value)
, m_size(size)
{
}
SizedIntegerValue(uint16_t value)
: IntegerValue(value)
, m_size(kHalfWordSize)
{
}
SizedIntegerValue(uint8_t value)
: IntegerValue(value)
, m_size(kByteSize)
{
}
SizedIntegerValue(const SizedIntegerValue &other)
: IntegerValue(other)
, m_size(other.m_size)
{
}
virtual std::string getTypeName() const { return "sized integer"; }
virtual size_t getSize() const;
inline int_size_t getWordSize() const { return m_size; }
inline void setWordSize(int_size_t size) { m_size = size; }
//! \brief Returns a 32-bit mask value dependant on the word size attribute.
uint32_t getWordSizeMask() const;
//! \name Assignment operators
//! These operators set the word size as well as the integer value.
//@{
SizedIntegerValue &operator=(uint8_t value)
{
m_value = value;
m_size = kByteSize;
return *this;
}
SizedIntegerValue &operator=(uint16_t value)
{
m_value = value;
m_size = kHalfWordSize;
return *this;
}
SizedIntegerValue &operator=(uint32_t value)
{
m_value = value;
m_size = kWordSize;
return *this;
}
//@}
protected:
int_size_t m_size; //!< Size of the integer.
};
/*!
* \brief String value.
*
* Simply wraps the STL std::string class.
*/
class StringValue : public Value
{
public:
StringValue()
: m_value()
{
}
StringValue(const std::string &value)
: m_value(value)
{
}
StringValue(const std::string *value)
: m_value(*value)
{
}
StringValue(const StringValue &other)
: m_value(other.m_value)
{
}
virtual std::string getTypeName() const { return "string"; }
virtual size_t getSize() const { return m_value.size(); }
operator const char *() const { return m_value.c_str(); }
operator const std::string &() const { return m_value; }
operator std::string &() { return m_value; }
operator const std::string *() { return &m_value; }
operator std::string *() { return &m_value; }
StringValue &operator=(const StringValue &other)
{
m_value = other.m_value;
return *this;
}
StringValue &operator=(const std::string &value)
{
m_value = value;
return *this;
}
StringValue &operator=(const char *value)
{
m_value = value;
return *this;
}
protected:
std::string m_value;
};
/*!
* \brief Binary object value of arbitrary size.
*/
class BinaryValue : public Value, public Blob
{
public:
BinaryValue()
: Value()
, Blob()
{
}
virtual std::string getTypeName() const { return "binary"; }
virtual size_t getSize() const { return getLength(); }
};
}; // namespace elftosb
#endif // _Value_h_

View File

@@ -0,0 +1,143 @@
/*
* File: Version.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "Version.h"
#include "EndianUtilities.h"
using namespace elftosb;
/*!
* Parses a string in the form "xxx.xxx.xxx" (where x is a digit) into
* three version fields for major, minor, and revision. The output is
* right aligned BCD in host-natural byte order.
*
* \param versionString String containing the version.
*/
void version_t::set(const std::string &versionString)
{
size_t length = versionString.size();
unsigned version = 0;
unsigned index = 0;
typedef enum
{
kVersionStateNone,
kVersionStateMajor,
kVersionStateMinor,
kVersionStateRevision
} VersionParseState;
// set initial versions to 0s
m_major = 0;
m_minor = 0;
m_revision = 0;
VersionParseState parseState = kVersionStateNone;
bool done = false;
for (; index < length && !done; ++index)
{
char c = versionString[index];
if (isdigit(c))
{
switch (parseState)
{
case kVersionStateNone:
parseState = kVersionStateMajor;
version = c - '0';
break;
case kVersionStateMajor:
case kVersionStateMinor:
case kVersionStateRevision:
version = (version << 4) | (c - '0');
break;
}
}
else if (c == '.')
{
switch (parseState)
{
case kVersionStateNone:
parseState = kVersionStateNone;
break;
case kVersionStateMajor:
m_major = version;
version = 0;
parseState = kVersionStateMinor;
break;
case kVersionStateMinor:
m_minor = version;
version = 0;
parseState = kVersionStateRevision;
break;
case kVersionStateRevision:
m_revision = version;
version = 0;
done = true;
break;
}
}
else
{
switch (parseState)
{
case kVersionStateNone:
parseState = kVersionStateNone;
break;
case kVersionStateMajor:
m_major = version;
done = true;
break;
case kVersionStateMinor:
m_minor = version;
done = true;
break;
case kVersionStateRevision:
m_revision = version;
done = true;
break;
}
}
}
switch (parseState)
{
case kVersionStateMajor:
m_major = version;
break;
case kVersionStateMinor:
m_minor = version;
break;
case kVersionStateRevision:
m_revision = version;
break;
default:
// do nothing
break;
}
}
//! \brief Converts host endian BCD version values to the equivalent big-endian BCD values.
//!
//! The output is a half-word. And BCD is inherently big-endian, or byte ordered, if
//! you prefer to think of it that way. So for little endian systems, we need to convert
//! the output half-word in reverse byte order. When it is written to disk or a
//! buffer it will come out big endian.
//!
//! For example:
//! - The input is BCD in host endian format, so 0x1234. Written to a file, this would
//! come out as 0x34 0x12, reverse of what we want.
//! - The desired BCD output is the two bytes 0x12 0x34.
//! - So the function's uint16_t result must be 0x3412 on a little-endian host.
//!
//! On big endian hosts, we don't have to worry about byte swapping.
void version_t::fixByteOrder()
{
m_major = ENDIAN_HOST_TO_BIG_U16(m_major);
m_minor = ENDIAN_HOST_TO_BIG_U16(m_minor);
m_revision = ENDIAN_HOST_TO_BIG_U16(m_revision);
}

View File

@@ -0,0 +1,65 @@
/*
* File: Version.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_Version_h_)
#define _Version_h_
#include <string>
#include "stdafx.h"
namespace elftosb
{
//! Same version struct used for 3600 boot image.
struct version_t
{
uint16_t m_major;
uint16_t m_pad0;
uint16_t m_minor;
uint16_t m_pad1;
uint16_t m_revision;
uint16_t m_pad2;
version_t()
: m_major(0x999)
, m_pad0(0)
, m_minor(0x999)
, m_pad1(0)
, m_revision(0x999)
, m_pad2(0)
{
}
version_t(uint16_t maj, uint16_t min, uint16_t rev)
: m_major(maj)
, m_pad0(0)
, m_minor(min)
, m_pad1(0)
, m_revision(rev)
, m_pad2(0)
{
}
version_t(const std::string &versionString)
: m_major(0x999)
, m_pad0(0)
, m_minor(0x999)
, m_pad1(0)
, m_revision(0x999)
, m_pad2(0)
{
set(versionString);
}
//! \brief Sets the version by parsing a string.
void set(const std::string &versionString);
//! \brief
void fixByteOrder();
};
}; // namespace elftosb
#endif // _Version_h_

View File

@@ -0,0 +1,309 @@
/*
* Copyright (c) 2014, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define BOOTLOADER_HOST
#include "aes128_key_wrap_unwrap.h"
#if !defined(BOOTLOADER_HOST)
#include "security/aes_security.h"
#endif
#if defined(BOOTLOADER_HOST)
// From bytes_aes.c.
extern void Cipher(unsigned char cin[], unsigned int w[], int nr, unsigned char cout[]);
extern void InvCipher(unsigned char cin[], unsigned int w[], int nr, unsigned char cout[]);
#endif
////////////////////////////////////////////////////////////////////////////////
// Definitions
////////////////////////////////////////////////////////////////////////////////
//! @brief number of 64-bit data blocks
#define N 5
//! @brief 64-bit initialization vector
static const unsigned char iv[8] = { 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6 };
//! @brief 64-bit integrity check register
static unsigned char a[8];
//! @brief 8-bit array of 64-bit registers
static unsigned char r[8 * (N + 1)];
////////////////////////////////////////////////////////////////////////////////
// Code
////////////////////////////////////////////////////////////////////////////////
// See aes128_key_wrap_unwrap.h for documentation on this function.
void do_aes128_key_wrap(const unsigned char plaintext[],
unsigned char wrapped_ciphertext[],
unsigned int expanded_kek[])
{
unsigned int i, j; // loop counters
unsigned char in[16]; // 128-bit temporary plaintext input vector
// step 1: initialize the byte-sized data variables
// set A = IV
// for i = 1 to n
// R[i] = P[i]
a[0] = iv[0];
a[1] = iv[1];
a[2] = iv[2];
a[3] = iv[3];
a[4] = iv[4];
a[5] = iv[5];
a[6] = iv[6];
a[7] = iv[7];
for (i = 1; i <= N; i++)
{
r[8 * i + 0] = plaintext[8 * (i - 1) + 0];
r[8 * i + 1] = plaintext[8 * (i - 1) + 1];
r[8 * i + 2] = plaintext[8 * (i - 1) + 2];
r[8 * i + 3] = plaintext[8 * (i - 1) + 3];
r[8 * i + 4] = plaintext[8 * (i - 1) + 4];
r[8 * i + 5] = plaintext[8 * (i - 1) + 5];
r[8 * i + 6] = plaintext[8 * (i - 1) + 6];
r[8 * i + 7] = plaintext[8 * (i - 1) + 7];
}
// step 2: calculate intermediate values
// for j = 0 to 5
// for i = 1 to n
// B = AES(K, A | R[i])
// A = MSB(64, B) ^ (n*j)+i
// R[i] = LSB(64, B)
for (j = 0; j <= 5; j++)
{
for (i = 1; i <= N; i++)
{
in[0] = a[0];
in[1] = a[1];
in[2] = a[2];
in[3] = a[3];
in[4] = a[4];
in[5] = a[5];
in[6] = a[6];
in[7] = a[7];
in[8] = r[8 * i + 0];
in[9] = r[8 * i + 1];
in[10] = r[8 * i + 2];
in[11] = r[8 * i + 3];
in[12] = r[8 * i + 4];
in[13] = r[8 * i + 5];
in[14] = r[8 * i + 6];
in[15] = r[8 * i + 7];
#if defined BOOTLOADER_HOST
Cipher(in, expanded_kek, 10, in); // perform aes128 encryption
#else
aes_encrypt((unsigned int *)in, expanded_kek, (unsigned int *)in);
#endif // BOOTLOADER_HOST
a[0] = in[0];
a[1] = in[1];
a[2] = in[2];
a[3] = in[3];
a[4] = in[4];
a[5] = in[5];
a[6] = in[6];
a[7] = in[7] ^ ((N * j) + i);
r[8 * i + 0] = in[8];
r[8 * i + 1] = in[9];
r[8 * i + 2] = in[10];
r[8 * i + 3] = in[11];
r[8 * i + 4] = in[12];
r[8 * i + 5] = in[13];
r[8 * i + 6] = in[14];
r[8 * i + 7] = in[15];
} // end for (i)
} // end for (j)
// step 3: output the results
// set C[0] = A
// for i = 1 to n
// C[i] = R[i]
wrapped_ciphertext[0] = a[0];
wrapped_ciphertext[1] = a[1];
wrapped_ciphertext[2] = a[2];
wrapped_ciphertext[3] = a[3];
wrapped_ciphertext[4] = a[4];
wrapped_ciphertext[5] = a[5];
wrapped_ciphertext[6] = a[6];
wrapped_ciphertext[7] = a[7];
for (i = 1; i <= N; i++)
{
wrapped_ciphertext[8 * i + 0] = r[8 * i + 0];
wrapped_ciphertext[8 * i + 1] = r[8 * i + 1];
wrapped_ciphertext[8 * i + 2] = r[8 * i + 2];
wrapped_ciphertext[8 * i + 3] = r[8 * i + 3];
wrapped_ciphertext[8 * i + 4] = r[8 * i + 4];
wrapped_ciphertext[8 * i + 5] = r[8 * i + 5];
wrapped_ciphertext[8 * i + 6] = r[8 * i + 6];
wrapped_ciphertext[8 * i + 7] = r[8 * i + 7];
}
}
//******************************************************************************
//******************************************************************************
// See aes128_key_wrap_unwrap.h for documentation on this function.
unsigned int do_aes128_key_unwrap(const unsigned char wrapped_ciphertext[],
unsigned char unwrapped_plaintext[],
unsigned int expanded_kek[])
{
signed int i, j; // loop counters
unsigned char in[16]; // 128-bit temporary ciphertext input vector
// step 1: initialize variables
// set A = C[0]
// for i = 1 to n
// R[i] = C[i]
a[0] = wrapped_ciphertext[0];
a[1] = wrapped_ciphertext[1];
a[2] = wrapped_ciphertext[2];
a[3] = wrapped_ciphertext[3];
a[4] = wrapped_ciphertext[4];
a[5] = wrapped_ciphertext[5];
a[6] = wrapped_ciphertext[6];
a[7] = wrapped_ciphertext[7];
for (i = 1; i <= N; i++)
{
r[8 * i + 0] = wrapped_ciphertext[8 * i + 0];
r[8 * i + 1] = wrapped_ciphertext[8 * i + 1];
r[8 * i + 2] = wrapped_ciphertext[8 * i + 2];
r[8 * i + 3] = wrapped_ciphertext[8 * i + 3];
r[8 * i + 4] = wrapped_ciphertext[8 * i + 4];
r[8 * i + 5] = wrapped_ciphertext[8 * i + 5];
r[8 * i + 6] = wrapped_ciphertext[8 * i + 6];
r[8 * i + 7] = wrapped_ciphertext[8 * i + 7];
}
// step 2: calculate intermediate values
// for j = 5 to 0
// for i = n to 1
// B = AES-1(K, (A ^ (n*j+i) | R[i])
// A = MSB(64, B)
// R[i] = LSB(64, B)
for (j = 5; j >= 0; j--)
{
for (i = N; i >= 1; i--)
{
in[0] = a[0];
in[1] = a[1];
in[2] = a[2];
in[3] = a[3];
in[4] = a[4];
in[5] = a[5];
in[6] = a[6];
in[7] = a[7] ^ ((N * j) + i);
in[8] = r[8 * i + 0];
in[9] = r[8 * i + 1];
in[10] = r[8 * i + 2];
in[11] = r[8 * i + 3];
in[12] = r[8 * i + 4];
in[13] = r[8 * i + 5];
in[14] = r[8 * i + 6];
in[15] = r[8 * i + 7];
#if defined BOOTLOADER_HOST
InvCipher(in, expanded_kek, 10, in); // perform aes128 decryption
#else
// TODO aes_decrypt reverses bytes(?)
aes_decrypt((unsigned int *)in, expanded_kek, (unsigned int *)in);
#endif // BOOTLOADER_HOST
a[0] = in[0];
a[1] = in[1];
a[2] = in[2];
a[3] = in[3];
a[4] = in[4];
a[5] = in[5];
a[6] = in[6];
a[7] = in[7];
r[8 * i + 0] = in[8];
r[8 * i + 1] = in[9];
r[8 * i + 2] = in[10];
r[8 * i + 3] = in[11];
r[8 * i + 4] = in[12];
r[8 * i + 5] = in[13];
r[8 * i + 6] = in[14];
r[8 * i + 7] = in[15];
} // end for (i)
} // end for (j)
// step 3: output the results
// if A == IV
// then
// for i = 1 to n
// P[i] = R[i]
// else
// return an error
unwrapped_plaintext[0] = a[0];
unwrapped_plaintext[1] = a[1];
unwrapped_plaintext[2] = a[2];
unwrapped_plaintext[3] = a[3];
unwrapped_plaintext[4] = a[4];
unwrapped_plaintext[5] = a[5];
unwrapped_plaintext[6] = a[6];
unwrapped_plaintext[7] = a[7];
for (i = 1; i <= N; i++)
{
unwrapped_plaintext[8 * i + 0] = r[8 * i + 0];
unwrapped_plaintext[8 * i + 1] = r[8 * i + 1];
unwrapped_plaintext[8 * i + 2] = r[8 * i + 2];
unwrapped_plaintext[8 * i + 3] = r[8 * i + 3];
unwrapped_plaintext[8 * i + 4] = r[8 * i + 4];
unwrapped_plaintext[8 * i + 5] = r[8 * i + 5];
unwrapped_plaintext[8 * i + 6] = r[8 * i + 6];
unwrapped_plaintext[8 * i + 7] = r[8 * i + 7];
}
if ((unwrapped_plaintext[0] == iv[0]) && (unwrapped_plaintext[1] == iv[1]) && (unwrapped_plaintext[2] == iv[2]) &&
(unwrapped_plaintext[3] == iv[3]) && (unwrapped_plaintext[4] == iv[4]) && (unwrapped_plaintext[5] == iv[5]) &&
(unwrapped_plaintext[6] == iv[6]) && (unwrapped_plaintext[7] == iv[7]))
return 0; // error-free exit
else
return -1; // error exit
}
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2014, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _aes128_key_wrap_unwrap_h
#define _aes128_key_wrap_unwrap_h
//! @addtogroup aes_key_wrap
//! @{
////////////////////////////////////////////////////////////////////////////////
// API
////////////////////////////////////////////////////////////////////////////////
#if defined(__cplusplus)
extern "C" {
#endif
//! @name aes_key_wrap
//@{
//! @brief Encrypt and wrap plaintext key.
//!
//! @param plaintext 40 byte plaintext input array
//! @param wrapped_ciphertext 48 byte wrapped output array
//! @param expanded_kek Expanded kek (64 bytes)
void do_aes128_key_wrap(const unsigned char plaintext[],
unsigned char wrapped_ciphertext[],
unsigned int expanded_kek[]);
//! @brief Decrypt and unwrap wrapped key.
//!
//! @param wrapped_ciphertext 48 byte wrapped input array
//! @param unwrapped_plaintext 48 byte plaintext output array, Note: this includes an 8 byte IV header
//! that is added to start of the original 40 input bytes by the wrapping
//! @param expanded_kek Expanded kek (64 ints on host, 4 ints on device)
//! @retval -1 on error
//! @retval 0 on success
unsigned int do_aes128_key_unwrap(const unsigned char wrapped_ciphertext[],
unsigned char unwrapped_plaintext[],
unsigned int expanded_kek[]);
//@}
#if defined(__cplusplus)
}
#endif
//! @}
#endif // _aes128_key_wrap_unwrap_h
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,432 @@
/*
* Copyright (c) 2014, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Advanced Encryption Standard
#ifdef DEBUG
#include <stdio.h>
#endif
#define SubBytes(i) (Sbox[(i) >> 24] << 24 | Sbox[(i) >> 16 & 0xff] << 16 | Sbox[(i) >> 8 & 0xff] << 8 | Sbox[(i)&0xff])
#define InvSubBytes(i) \
(InvSbox[(i) >> 24] << 24 | InvSbox[(i) >> 16 & 0xff] << 16 | InvSbox[(i) >> 8 & 0xff] << 8 | InvSbox[(i)&0xff])
static unsigned char Sbox[] = {
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 unsigned char InvSbox[] = {
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 unsigned char x2[] = {
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24,
0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a,
0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70,
0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96,
0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc,
0xbe, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2,
0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x1b, 0x19, 0x1f, 0x1d, 0x13,
0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35,
0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25, 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f,
0x4d, 0x43, 0x41, 0x47, 0x45, 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61,
0x67, 0x65, 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85, 0xbb,
0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, 0xdb, 0xd9, 0xdf, 0xdd,
0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7,
0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
};
static unsigned char x3[] = {
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, 0x30, 0x33, 0x36,
0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f,
0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48,
0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41, 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd,
0xd4, 0xd7, 0xd2, 0xd1, 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2,
0xe1, 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1, 0x90, 0x93,
0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 0x9b, 0x98, 0x9d, 0x9e, 0x97,
0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2,
0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba, 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5,
0xe6, 0xef, 0xec, 0xe9, 0xea, 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc,
0xd9, 0xda, 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a, 0x6b,
0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, 0x3b, 0x38, 0x3d, 0x3e,
0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01,
0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
};
static unsigned char x9[] = {
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, 0x90, 0x99, 0x82,
0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16,
0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3,
0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc, 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25,
0x1a, 0x13, 0x08, 0x01, 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98,
0x91, 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a, 0xdd, 0xd4,
0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, 0xec, 0xe5, 0xfe, 0xf7, 0xc8,
0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43,
0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b, 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d,
0x84, 0xbb, 0xb2, 0xa9, 0xa0, 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22,
0x39, 0x30, 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed, 0x0a,
0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, 0xa1, 0xa8, 0xb3, 0xba,
0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07,
0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
};
static unsigned char xb[] = {
0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, 0xb0, 0xbb, 0xa6,
0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c,
0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93,
0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2, 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3,
0x82, 0x89, 0x94, 0x9f, 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24,
0x2f, 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4, 0x3d, 0x36,
0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, 0xf7, 0xfc, 0xe1, 0xea, 0xdb,
0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76,
0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e, 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2,
0xc9, 0xf8, 0xf3, 0xee, 0xe5, 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43,
0x5e, 0x55, 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68, 0xb1,
0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, 0x7a, 0x71, 0x6c, 0x67,
0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0,
0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
};
static unsigned char xd[] = {
0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, 0xd0, 0xdd, 0xca,
0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82,
0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03,
0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20, 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12,
0x31, 0x3c, 0x2b, 0x26, 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb,
0xf6, 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d, 0x06, 0x0b,
0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, 0xda, 0xd7, 0xc0, 0xcd, 0xee,
0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29,
0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41, 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13,
0x1e, 0x3d, 0x30, 0x27, 0x2a, 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0,
0xf7, 0xfa, 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc, 0x67,
0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, 0x0c, 0x01, 0x16, 0x1b,
0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2,
0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
};
static unsigned char xe[] = {
0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, 0xe0, 0xee, 0xfc,
0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed,
0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b,
0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61, 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf,
0xe5, 0xeb, 0xf9, 0xf7, 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19,
0x17, 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c, 0x96, 0x98,
0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, 0x41, 0x4f, 0x5d, 0x53, 0x79,
0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b,
0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb, 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6,
0xf8, 0xd2, 0xdc, 0xce, 0xc0, 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c,
0x2e, 0x20, 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6, 0x0c,
0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, 0x37, 0x39, 0x2b, 0x25,
0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3,
0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
};
static unsigned int Rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000 };
void Cipher(unsigned char cin[], unsigned int w[], int nr, unsigned char cout[])
{
unsigned int state[4], temp[4], in[4], out[4];
unsigned int s00, s01, s02, s03, s10, s11, s12, s13;
unsigned int s20, s21, s22, s23, s30, s31, s32, s33;
int i;
in[0] = cin[0] << 24 | cin[1] << 16 | cin[2] << 8 | cin[3];
in[1] = cin[4] << 24 | cin[5] << 16 | cin[6] << 8 | cin[7];
in[2] = cin[8] << 24 | cin[9] << 16 | cin[10] << 8 | cin[11];
in[3] = cin[12] << 24 | cin[13] << 16 | cin[14] << 8 | cin[15];
#ifdef DEBUG
printf("input: %.8x %.8x %.8x %.8x\n", in[0], in[1], in[2], in[3]);
printf("k_sch: %.8x %.8x %.8x %.8x\n", w[0], w[1], w[2], w[3]);
#endif
state[0] = in[0] ^ w[0];
state[1] = in[1] ^ w[1];
state[2] = in[2] ^ w[2];
state[3] = in[3] ^ w[3];
for (i = 4; i < 4 * nr; i += 4)
{
#ifdef DEBUG
printf("start: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
#endif
state[0] = SubBytes(state[0]);
state[1] = SubBytes(state[1]);
state[2] = SubBytes(state[2]);
state[3] = SubBytes(state[3]);
#ifdef DEBUG
printf("s_box: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
#endif
temp[0] = (state[0] & 0xff000000) | (state[1] & 0xff0000) | (state[2] & 0xff00) | (state[3] & 0xff);
temp[1] = (state[1] & 0xff000000) | (state[2] & 0xff0000) | (state[3] & 0xff00) | (state[0] & 0xff);
temp[2] = (state[2] & 0xff000000) | (state[3] & 0xff0000) | (state[0] & 0xff00) | (state[1] & 0xff);
temp[3] = (state[3] & 0xff000000) | (state[0] & 0xff0000) | (state[1] & 0xff00) | (state[2] & 0xff);
#ifdef DEBUG
printf("s_row: %.8x %.8x %.8x %.8x\n", temp[0], temp[1], temp[2], temp[3]);
#endif
s00 = temp[0] >> 24 & 0xff;
s10 = temp[0] >> 16 & 0xff;
s20 = temp[0] >> 8 & 0xff;
s30 = temp[0] & 0xff;
s01 = temp[1] >> 24 & 0xff;
s11 = temp[1] >> 16 & 0xff;
s21 = temp[1] >> 8 & 0xff;
s31 = temp[1] & 0xff;
s02 = temp[2] >> 24 & 0xff;
s12 = temp[2] >> 16 & 0xff;
s22 = temp[2] >> 8 & 0xff;
s32 = temp[2] & 0xff;
s03 = temp[3] >> 24 & 0xff;
s13 = temp[3] >> 16 & 0xff;
s23 = temp[3] >> 8 & 0xff;
s33 = temp[3] & 0xff;
state[0] = (x2[s00] ^ x3[s10] ^ s20 ^ s30) << 24 | (s00 ^ x2[s10] ^ x3[s20] ^ s30) << 16 |
(s00 ^ s10 ^ x2[s20] ^ x3[s30]) << 8 | (x3[s00] ^ s10 ^ s20 ^ x2[s30]);
state[1] = (x2[s01] ^ x3[s11] ^ s21 ^ s31) << 24 | (s01 ^ x2[s11] ^ x3[s21] ^ s31) << 16 |
(s01 ^ s11 ^ x2[s21] ^ x3[s31]) << 8 | (x3[s01] ^ s11 ^ s21 ^ x2[s31]);
state[2] = (x2[s02] ^ x3[s12] ^ s22 ^ s32) << 24 | (s02 ^ x2[s12] ^ x3[s22] ^ s32) << 16 |
(s02 ^ s12 ^ x2[s22] ^ x3[s32]) << 8 | (x3[s02] ^ s12 ^ s22 ^ x2[s32]);
state[3] = (x2[s03] ^ x3[s13] ^ s23 ^ s33) << 24 | (s03 ^ x2[s13] ^ x3[s23] ^ s33) << 16 |
(s03 ^ s13 ^ x2[s23] ^ x3[s33]) << 8 | (x3[s03] ^ s13 ^ s23 ^ x2[s33]);
#ifdef DEBUG
printf("m_col: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
printf("k_sch: %.8x %.8x %.8x %.8x\n", w[i], w[i + 1], w[i + 2], w[i + 3]);
#endif
state[0] ^= w[i];
state[1] ^= w[i + 1];
state[2] ^= w[i + 2];
state[3] ^= w[i + 3];
}
#ifdef DEBUG
printf("start: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
#endif
state[0] = SubBytes(state[0]);
state[1] = SubBytes(state[1]);
state[2] = SubBytes(state[2]);
state[3] = SubBytes(state[3]);
#ifdef DEBUG
printf("s_box: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
#endif
temp[0] = (state[0] & 0xff000000) | (state[1] & 0xff0000) | (state[2] & 0xff00) | (state[3] & 0xff);
temp[1] = (state[1] & 0xff000000) | (state[2] & 0xff0000) | (state[3] & 0xff00) | (state[0] & 0xff);
temp[2] = (state[2] & 0xff000000) | (state[3] & 0xff0000) | (state[0] & 0xff00) | (state[1] & 0xff);
temp[3] = (state[3] & 0xff000000) | (state[0] & 0xff0000) | (state[1] & 0xff00) | (state[2] & 0xff);
#ifdef DEBUG
printf("s_row: %.8x %.8x %.8x %.8x\n", temp[0], temp[1], temp[2], temp[3]);
printf("k_sch: %.8x %.8x %.8x %.8x\n", w[4 * nr], w[4 * nr + 1], w[4 * nr + 2], w[4 * nr + 3]);
#endif
out[0] = temp[0] ^ w[4 * nr];
out[1] = temp[1] ^ w[4 * nr + 1];
out[2] = temp[2] ^ w[4 * nr + 2];
out[3] = temp[3] ^ w[4 * nr + 3];
#ifdef DEBUG
printf("output: %.8x %.8x %.8x %.8x\n", out[0], out[1], out[2], out[3]);
#endif
cout[0] = out[0] >> 24 & 0xff;
cout[1] = out[0] >> 16 & 0xff;
cout[2] = out[0] >> 8 & 0xff;
cout[3] = out[0] & 0xff;
cout[4] = out[1] >> 24 & 0xff;
cout[5] = out[1] >> 16 & 0xff;
cout[6] = out[1] >> 8 & 0xff;
cout[7] = out[1] & 0xff;
cout[8] = out[2] >> 24 & 0xff;
cout[9] = out[2] >> 16 & 0xff;
cout[10] = out[2] >> 8 & 0xff;
cout[11] = out[2] & 0xff;
cout[12] = out[3] >> 24 & 0xff;
cout[13] = out[3] >> 16 & 0xff;
cout[14] = out[3] >> 8 & 0xff;
cout[15] = out[3] & 0xff;
}
void InvCipher(unsigned char cin[], unsigned int w[], int nr, unsigned char cout[])
{
unsigned int state[4], temp[4], in[4], out[4];
unsigned int s00, s01, s02, s03, s10, s11, s12, s13;
unsigned int s20, s21, s22, s23, s30, s31, s32, s33;
int i;
in[0] = cin[0] << 24 | cin[1] << 16 | cin[2] << 8 | cin[3];
in[1] = cin[4] << 24 | cin[5] << 16 | cin[6] << 8 | cin[7];
in[2] = cin[8] << 24 | cin[9] << 16 | cin[10] << 8 | cin[11];
in[3] = cin[12] << 24 | cin[13] << 16 | cin[14] << 8 | cin[15];
#ifdef DEBUG
printf("iinput: %.8x %.8x %.8x %.8x\n", in[0], in[1], in[2], in[3]);
printf("ik_sch: %.8x %.8x %.8x %.8x\n", w[4 * nr], w[4 * nr + 1], w[4 * nr + 2], w[4 * nr + 3]);
#endif
state[0] = in[0] ^ w[4 * nr];
state[1] = in[1] ^ w[4 * nr + 1];
state[2] = in[2] ^ w[4 * nr + 2];
state[3] = in[3] ^ w[4 * nr + 3];
for (i = 4 * nr - 4; i > 0; i -= 4)
{
#ifdef DEBUG
printf("istart: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
#endif
temp[0] = (state[0] & 0xff000000) | (state[3] & 0xff0000) | (state[2] & 0xff00) | (state[1] & 0xff);
temp[1] = (state[1] & 0xff000000) | (state[0] & 0xff0000) | (state[3] & 0xff00) | (state[2] & 0xff);
temp[2] = (state[2] & 0xff000000) | (state[1] & 0xff0000) | (state[0] & 0xff00) | (state[3] & 0xff);
temp[3] = (state[3] & 0xff000000) | (state[2] & 0xff0000) | (state[1] & 0xff00) | (state[0] & 0xff);
#ifdef DEBUG
printf("is_row: %.8x %.8x %.8x %.8x\n", temp[0], temp[1], temp[2], temp[3]);
#endif
state[0] = InvSubBytes(temp[0]);
state[1] = InvSubBytes(temp[1]);
state[2] = InvSubBytes(temp[2]);
state[3] = InvSubBytes(temp[3]);
#ifdef DEBUG
printf("is_box: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
printf("ik_sch: %.8x %.8x %.8x %.8x\n", w[i], w[i + 1], w[i + 2], w[i + 3]);
#endif
state[0] ^= w[i];
state[1] ^= w[i + 1];
state[2] ^= w[i + 2];
state[3] ^= w[i + 3];
#ifdef DEBUG
printf("ik_add: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
#endif
s00 = state[0] >> 24 & 0xff;
s10 = state[0] >> 16 & 0xff;
s20 = state[0] >> 8 & 0xff;
s30 = state[0] & 0xff;
s01 = state[1] >> 24 & 0xff;
s11 = state[1] >> 16 & 0xff;
s21 = state[1] >> 8 & 0xff;
s31 = state[1] & 0xff;
s02 = state[2] >> 24 & 0xff;
s12 = state[2] >> 16 & 0xff;
s22 = state[2] >> 8 & 0xff;
s32 = state[2] & 0xff;
s03 = state[3] >> 24 & 0xff;
s13 = state[3] >> 16 & 0xff;
s23 = state[3] >> 8 & 0xff;
s33 = state[3] & 0xff;
state[0] = (xe[s00] ^ xb[s10] ^ xd[s20] ^ x9[s30]) << 24 | (x9[s00] ^ xe[s10] ^ xb[s20] ^ xd[s30]) << 16 |
(xd[s00] ^ x9[s10] ^ xe[s20] ^ xb[s30]) << 8 | (xb[s00] ^ xd[s10] ^ x9[s20] ^ xe[s30]);
state[1] = (xe[s01] ^ xb[s11] ^ xd[s21] ^ x9[s31]) << 24 | (x9[s01] ^ xe[s11] ^ xb[s21] ^ xd[s31]) << 16 |
(xd[s01] ^ x9[s11] ^ xe[s21] ^ xb[s31]) << 8 | (xb[s01] ^ xd[s11] ^ x9[s21] ^ xe[s31]);
state[2] = (xe[s02] ^ xb[s12] ^ xd[s22] ^ x9[s32]) << 24 | (x9[s02] ^ xe[s12] ^ xb[s22] ^ xd[s32]) << 16 |
(xd[s02] ^ x9[s12] ^ xe[s22] ^ xb[s32]) << 8 | (xb[s02] ^ xd[s12] ^ x9[s22] ^ xe[s32]);
state[3] = (xe[s03] ^ xb[s13] ^ xd[s23] ^ x9[s33]) << 24 | (x9[s03] ^ xe[s13] ^ xb[s23] ^ xd[s33]) << 16 |
(xd[s03] ^ x9[s13] ^ xe[s23] ^ xb[s33]) << 8 | (xb[s03] ^ xd[s13] ^ x9[s23] ^ xe[s33]);
}
#ifdef DEBUG
printf("istart: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
#endif
temp[0] = (state[0] & 0xff000000) | (state[3] & 0xff0000) | (state[2] & 0xff00) | (state[1] & 0xff);
temp[1] = (state[1] & 0xff000000) | (state[0] & 0xff0000) | (state[3] & 0xff00) | (state[2] & 0xff);
temp[2] = (state[2] & 0xff000000) | (state[1] & 0xff0000) | (state[0] & 0xff00) | (state[3] & 0xff);
temp[3] = (state[3] & 0xff000000) | (state[2] & 0xff0000) | (state[1] & 0xff00) | (state[0] & 0xff);
#ifdef DEBUG
printf("is_row: %.8x %.8x %.8x %.8x\n", temp[0], temp[1], temp[2], temp[3]);
#endif
state[0] = InvSubBytes(temp[0]);
state[1] = InvSubBytes(temp[1]);
state[2] = InvSubBytes(temp[2]);
state[3] = InvSubBytes(temp[3]);
#ifdef DEBUG
printf("is_box: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
printf("ik_sch: %.8x %.8x %.8x %.8x\n", w[0], w[1], w[2], w[3]);
#endif
out[0] = state[0] ^ w[0];
out[1] = state[1] ^ w[1];
out[2] = state[2] ^ w[2];
out[3] = state[3] ^ w[3];
#ifdef DEBUG
printf("ioutput: %.8x %.8x %.8x %.8x\n", out[0], out[1], out[2], out[3]);
#endif
cout[0] = out[0] >> 24 & 0xff;
cout[1] = out[0] >> 16 & 0xff;
cout[2] = out[0] >> 8 & 0xff;
cout[3] = out[0] & 0xff;
cout[4] = out[1] >> 24 & 0xff;
cout[5] = out[1] >> 16 & 0xff;
cout[6] = out[1] >> 8 & 0xff;
cout[7] = out[1] & 0xff;
cout[8] = out[2] >> 24 & 0xff;
cout[9] = out[2] >> 16 & 0xff;
cout[10] = out[2] >> 8 & 0xff;
cout[11] = out[2] & 0xff;
cout[12] = out[3] >> 24 & 0xff;
cout[13] = out[3] >> 16 & 0xff;
cout[14] = out[3] >> 8 & 0xff;
cout[15] = out[3] & 0xff;
}
void KeyExpansion(unsigned char ckey[], int nbits, unsigned int w[])
{
int i, j;
unsigned int temp, tempx;
j = nbits / 32;
for (i = 0; i < j; i++)
w[i] = ckey[4 * i] << 24 | ckey[4 * i + 1] << 16 | ckey[4 * i + 2] << 8 | ckey[4 * i + 3];
for (i = j; i < 4 * j + 28; i++)
{
temp = w[i - 1];
if ((i % j) == 0)
{
tempx = temp << 8 | (temp >> 24 & 0xff);
temp = SubBytes(tempx) ^ Rcon[i / j - 1];
}
else if (j == 8 && (i % j) == 4)
temp = SubBytes(temp);
w[i] = w[i - j] ^ temp;
}
}

269
apps/elftosb/common/crc.cpp Normal file
View File

@@ -0,0 +1,269 @@
/*
* File: crc.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "crc.h"
//! Table of CRC-32's of all single byte values. The values in
//! this table are those used in the Ethernet CRC algorithm.
const uint32_t CRC32::m_tab[] = {
//#ifdef __LITTLE_ENDIAN__
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8,
0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6,
0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84,
0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a,
0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9,
0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b,
0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c,
0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x0315d626,
0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a,
0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093,
0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679,
0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667,
0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
//#else
// 0x00000000,
// 0xb71dc104, 0x6e3b8209, 0xd926430d, 0xdc760413, 0x6b6bc517,
// 0xb24d861a, 0x0550471e, 0xb8ed0826, 0x0ff0c922, 0xd6d68a2f,
// 0x61cb4b2b, 0x649b0c35, 0xd386cd31, 0x0aa08e3c, 0xbdbd4f38,
// 0x70db114c, 0xc7c6d048, 0x1ee09345, 0xa9fd5241, 0xacad155f,
// 0x1bb0d45b, 0xc2969756, 0x758b5652, 0xc836196a, 0x7f2bd86e,
// 0xa60d9b63, 0x11105a67, 0x14401d79, 0xa35ddc7d, 0x7a7b9f70,
// 0xcd665e74, 0xe0b62398, 0x57abe29c, 0x8e8da191, 0x39906095,
// 0x3cc0278b, 0x8bdde68f, 0x52fba582, 0xe5e66486, 0x585b2bbe,
// 0xef46eaba, 0x3660a9b7, 0x817d68b3, 0x842d2fad, 0x3330eea9,
// 0xea16ada4, 0x5d0b6ca0, 0x906d32d4, 0x2770f3d0, 0xfe56b0dd,
// 0x494b71d9, 0x4c1b36c7, 0xfb06f7c3, 0x2220b4ce, 0x953d75ca,
// 0x28803af2, 0x9f9dfbf6, 0x46bbb8fb, 0xf1a679ff, 0xf4f63ee1,
// 0x43ebffe5, 0x9acdbce8, 0x2dd07dec, 0x77708634, 0xc06d4730,
// 0x194b043d, 0xae56c539, 0xab068227, 0x1c1b4323, 0xc53d002e,
// 0x7220c12a, 0xcf9d8e12, 0x78804f16, 0xa1a60c1b, 0x16bbcd1f,
// 0x13eb8a01, 0xa4f64b05, 0x7dd00808, 0xcacdc90c, 0x07ab9778,
// 0xb0b6567c, 0x69901571, 0xde8dd475, 0xdbdd936b, 0x6cc0526f,
// 0xb5e61162, 0x02fbd066, 0xbf469f5e, 0x085b5e5a, 0xd17d1d57,
// 0x6660dc53, 0x63309b4d, 0xd42d5a49, 0x0d0b1944, 0xba16d840,
// 0x97c6a5ac, 0x20db64a8, 0xf9fd27a5, 0x4ee0e6a1, 0x4bb0a1bf,
// 0xfcad60bb, 0x258b23b6, 0x9296e2b2, 0x2f2bad8a, 0x98366c8e,
// 0x41102f83, 0xf60dee87, 0xf35da999, 0x4440689d, 0x9d662b90,
// 0x2a7bea94, 0xe71db4e0, 0x500075e4, 0x892636e9, 0x3e3bf7ed,
// 0x3b6bb0f3, 0x8c7671f7, 0x555032fa, 0xe24df3fe, 0x5ff0bcc6,
// 0xe8ed7dc2, 0x31cb3ecf, 0x86d6ffcb, 0x8386b8d5, 0x349b79d1,
// 0xedbd3adc, 0x5aa0fbd8, 0xeee00c69, 0x59fdcd6d, 0x80db8e60,
// 0x37c64f64, 0x3296087a, 0x858bc97e, 0x5cad8a73, 0xebb04b77,
// 0x560d044f, 0xe110c54b, 0x38368646, 0x8f2b4742, 0x8a7b005c,
// 0x3d66c158, 0xe4408255, 0x535d4351, 0x9e3b1d25, 0x2926dc21,
// 0xf0009f2c, 0x471d5e28, 0x424d1936, 0xf550d832, 0x2c769b3f,
// 0x9b6b5a3b, 0x26d61503, 0x91cbd407, 0x48ed970a, 0xfff0560e,
// 0xfaa01110, 0x4dbdd014, 0x949b9319, 0x2386521d, 0x0e562ff1,
// 0xb94beef5, 0x606dadf8, 0xd7706cfc, 0xd2202be2, 0x653deae6,
// 0xbc1ba9eb, 0x0b0668ef, 0xb6bb27d7, 0x01a6e6d3, 0xd880a5de,
// 0x6f9d64da, 0x6acd23c4, 0xddd0e2c0, 0x04f6a1cd, 0xb3eb60c9,
// 0x7e8d3ebd, 0xc990ffb9, 0x10b6bcb4, 0xa7ab7db0, 0xa2fb3aae,
// 0x15e6fbaa, 0xccc0b8a7, 0x7bdd79a3, 0xc660369b, 0x717df79f,
// 0xa85bb492, 0x1f467596, 0x1a163288, 0xad0bf38c, 0x742db081,
// 0xc3307185, 0x99908a5d, 0x2e8d4b59, 0xf7ab0854, 0x40b6c950,
// 0x45e68e4e, 0xf2fb4f4a, 0x2bdd0c47, 0x9cc0cd43, 0x217d827b,
// 0x9660437f, 0x4f460072, 0xf85bc176, 0xfd0b8668, 0x4a16476c,
// 0x93300461, 0x242dc565, 0xe94b9b11, 0x5e565a15, 0x87701918,
// 0x306dd81c, 0x353d9f02, 0x82205e06, 0x5b061d0b, 0xec1bdc0f,
// 0x51a69337, 0xe6bb5233, 0x3f9d113e, 0x8880d03a, 0x8dd09724,
// 0x3acd5620, 0xe3eb152d, 0x54f6d429, 0x7926a9c5, 0xce3b68c1,
// 0x171d2bcc, 0xa000eac8, 0xa550add6, 0x124d6cd2, 0xcb6b2fdf,
// 0x7c76eedb, 0xc1cba1e3, 0x76d660e7, 0xaff023ea, 0x18ede2ee,
// 0x1dbda5f0, 0xaaa064f4, 0x738627f9, 0xc49be6fd, 0x09fdb889,
// 0xbee0798d, 0x67c63a80, 0xd0dbfb84, 0xd58bbc9a, 0x62967d9e,
// 0xbbb03e93, 0x0cadff97, 0xb110b0af, 0x060d71ab, 0xdf2b32a6,
// 0x6836f3a2, 0x6d66b4bc, 0xda7b75b8, 0x035d36b5, 0xb440f7b1
//#endif // __LITTLE_ENDIAN__
// This is the original table that came with this source.
//#ifdef __LITTLE_ENDIAN__
// 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
// 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
// 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
// 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
// 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
// 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
// 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
// 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
// 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
// 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
// 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
// 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
// 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
// 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
// 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
// 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
// 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
// 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
// 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
// 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
// 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
// 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
// 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
// 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
// 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
// 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
// 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
// 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
// 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
// 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
// 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
// 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
// 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
// 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
// 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
// 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
// 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
// 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
// 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
// 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
// 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
// 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
// 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
// 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
// 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
// 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
// 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
// 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
// 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
// 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
// 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
// 0x2d02ef8dL
//#else
// 0x00000000L, 0x96300777L, 0x2c610eeeL, 0xba510999L, 0x19c46d07L,
// 0x8ff46a70L, 0x35a563e9L, 0xa395649eL, 0x3288db0eL, 0xa4b8dc79L,
// 0x1ee9d5e0L, 0x88d9d297L, 0x2b4cb609L, 0xbd7cb17eL, 0x072db8e7L,
// 0x911dbf90L, 0x6410b71dL, 0xf220b06aL, 0x4871b9f3L, 0xde41be84L,
// 0x7dd4da1aL, 0xebe4dd6dL, 0x51b5d4f4L, 0xc785d383L, 0x56986c13L,
// 0xc0a86b64L, 0x7af962fdL, 0xecc9658aL, 0x4f5c0114L, 0xd96c0663L,
// 0x633d0ffaL, 0xf50d088dL, 0xc8206e3bL, 0x5e10694cL, 0xe44160d5L,
// 0x727167a2L, 0xd1e4033cL, 0x47d4044bL, 0xfd850dd2L, 0x6bb50aa5L,
// 0xfaa8b535L, 0x6c98b242L, 0xd6c9bbdbL, 0x40f9bcacL, 0xe36cd832L,
// 0x755cdf45L, 0xcf0dd6dcL, 0x593dd1abL, 0xac30d926L, 0x3a00de51L,
// 0x8051d7c8L, 0x1661d0bfL, 0xb5f4b421L, 0x23c4b356L, 0x9995bacfL,
// 0x0fa5bdb8L, 0x9eb80228L, 0x0888055fL, 0xb2d90cc6L, 0x24e90bb1L,
// 0x877c6f2fL, 0x114c6858L, 0xab1d61c1L, 0x3d2d66b6L, 0x9041dc76L,
// 0x0671db01L, 0xbc20d298L, 0x2a10d5efL, 0x8985b171L, 0x1fb5b606L,
// 0xa5e4bf9fL, 0x33d4b8e8L, 0xa2c90778L, 0x34f9000fL, 0x8ea80996L,
// 0x18980ee1L, 0xbb0d6a7fL, 0x2d3d6d08L, 0x976c6491L, 0x015c63e6L,
// 0xf4516b6bL, 0x62616c1cL, 0xd8306585L, 0x4e0062f2L, 0xed95066cL,
// 0x7ba5011bL, 0xc1f40882L, 0x57c40ff5L, 0xc6d9b065L, 0x50e9b712L,
// 0xeab8be8bL, 0x7c88b9fcL, 0xdf1ddd62L, 0x492dda15L, 0xf37cd38cL,
// 0x654cd4fbL, 0x5861b24dL, 0xce51b53aL, 0x7400bca3L, 0xe230bbd4L,
// 0x41a5df4aL, 0xd795d83dL, 0x6dc4d1a4L, 0xfbf4d6d3L, 0x6ae96943L,
// 0xfcd96e34L, 0x468867adL, 0xd0b860daL, 0x732d0444L, 0xe51d0333L,
// 0x5f4c0aaaL, 0xc97c0dddL, 0x3c710550L, 0xaa410227L, 0x10100bbeL,
// 0x86200cc9L, 0x25b56857L, 0xb3856f20L, 0x09d466b9L, 0x9fe461ceL,
// 0x0ef9de5eL, 0x98c9d929L, 0x2298d0b0L, 0xb4a8d7c7L, 0x173db359L,
// 0x810db42eL, 0x3b5cbdb7L, 0xad6cbac0L, 0x2083b8edL, 0xb6b3bf9aL,
// 0x0ce2b603L, 0x9ad2b174L, 0x3947d5eaL, 0xaf77d29dL, 0x1526db04L,
// 0x8316dc73L, 0x120b63e3L, 0x843b6494L, 0x3e6a6d0dL, 0xa85a6a7aL,
// 0x0bcf0ee4L, 0x9dff0993L, 0x27ae000aL, 0xb19e077dL, 0x44930ff0L,
// 0xd2a30887L, 0x68f2011eL, 0xfec20669L, 0x5d5762f7L, 0xcb676580L,
// 0x71366c19L, 0xe7066b6eL, 0x761bd4feL, 0xe02bd389L, 0x5a7ada10L,
// 0xcc4add67L, 0x6fdfb9f9L, 0xf9efbe8eL, 0x43beb717L, 0xd58eb060L,
// 0xe8a3d6d6L, 0x7e93d1a1L, 0xc4c2d838L, 0x52f2df4fL, 0xf167bbd1L,
// 0x6757bca6L, 0xdd06b53fL, 0x4b36b248L, 0xda2b0dd8L, 0x4c1b0aafL,
// 0xf64a0336L, 0x607a0441L, 0xc3ef60dfL, 0x55df67a8L, 0xef8e6e31L,
// 0x79be6946L, 0x8cb361cbL, 0x1a8366bcL, 0xa0d26f25L, 0x36e26852L,
// 0x95770cccL, 0x03470bbbL, 0xb9160222L, 0x2f260555L, 0xbe3bbac5L,
// 0x280bbdb2L, 0x925ab42bL, 0x046ab35cL, 0xa7ffd7c2L, 0x31cfd0b5L,
// 0x8b9ed92cL, 0x1daede5bL, 0xb0c2649bL, 0x26f263ecL, 0x9ca36a75L,
// 0x0a936d02L, 0xa906099cL, 0x3f360eebL, 0x85670772L, 0x13570005L,
// 0x824abf95L, 0x147ab8e2L, 0xae2bb17bL, 0x381bb60cL, 0x9b8ed292L,
// 0x0dbed5e5L, 0xb7efdc7cL, 0x21dfdb0bL, 0xd4d2d386L, 0x42e2d4f1L,
// 0xf8b3dd68L, 0x6e83da1fL, 0xcd16be81L, 0x5b26b9f6L, 0xe177b06fL,
// 0x7747b718L, 0xe65a0888L, 0x706a0fffL, 0xca3b0666L, 0x5c0b0111L,
// 0xff9e658fL, 0x69ae62f8L, 0xd3ff6b61L, 0x45cf6c16L, 0x78e20aa0L,
// 0xeed20dd7L, 0x5483044eL, 0xc2b30339L, 0x612667a7L, 0xf71660d0L,
// 0x4d476949L, 0xdb776e3eL, 0x4a6ad1aeL, 0xdc5ad6d9L, 0x660bdf40L,
// 0xf03bd837L, 0x53aebca9L, 0xc59ebbdeL, 0x7fcfb247L, 0xe9ffb530L,
// 0x1cf2bdbdL, 0x8ac2bacaL, 0x3093b353L, 0xa6a3b424L, 0x0536d0baL,
// 0x9306d7cdL, 0x2957de54L, 0xbf67d923L, 0x2e7a66b3L, 0xb84a61c4L,
// 0x021b685dL, 0x942b6f2aL, 0x37be0bb4L, 0xa18e0cc3L, 0x1bdf055aL,
// 0x8def022dL
//#endif
};
CRC32::CRC32()
{
reset();
}
void CRC32::update(const uint8_t *s, unsigned n)
{
uint32_t crc = m_crc;
m_count += n;
while (n--)
{
uint8_t c = *s++ & 0xff;
crc = (crc << 8) ^ m_tab[(crc >> 24) ^ c];
}
// for(; !((reinterpret_cast<uint32_t>(s) & 0x3) == 0) && n > 0; n--)
// {
// crc = m_tab[CRC32_INDEX(crc) ^ *s++] ^ CRC32_SHIFTED(crc);
// }
//
// while (n >= 4)
// {
// crc ^= *(const uint32_t *)s;
// crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
// crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
// crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
// crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
// n -= 4;
// s += 4;
// }
//
// while (n--)
// {
// crc = m_tab[CRC32_INDEX(crc) ^ *s++] ^ CRC32_SHIFTED(crc);
// }
m_crc = crc;
}
void CRC32::truncatedFinal(uint8_t *hash, unsigned size)
{
// pad with zeroes
if (m_count % 4)
{
unsigned i;
for (i = m_count % 4; i < 4; i++)
{
m_crc = (m_crc << 8) ^ m_tab[(m_crc >> 24) ^ 0];
}
}
// m_crc ^= CRC32_NEGL;
unsigned i;
for (i = 0; i < size; i++)
{
hash[i] = getCrcByte(i);
}
reset();
}

51
apps/elftosb/common/crc.h Normal file
View File

@@ -0,0 +1,51 @@
/*
* File: crc.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_crc_h_)
#define CRYPTOPP_CRC32_H
#include "stdafx.h"
const uint32_t CRC32_NEGL = 0xffffffffL;
#ifdef __LITTLE_ENDIAN__
#define CRC32_INDEX(c) (c & 0xff)
#define CRC32_SHIFTED(c) (c >> 8)
#else
#define CRC32_INDEX(c) (c >> 24)
#define CRC32_SHIFTED(c) (c << 8)
#endif
//! CRC Checksum Calculation
class CRC32
{
public:
enum
{
DIGESTSIZE = 4
};
CRC32();
void update(const uint8_t *input, unsigned length);
void truncatedFinal(uint8_t *hash, unsigned size);
void updateByte(uint8_t b) { m_crc = m_tab[CRC32_INDEX(m_crc) ^ b] ^ CRC32_SHIFTED(m_crc); }
uint8_t getCrcByte(unsigned i) const { return ((uint8_t *)&(m_crc))[i]; }
private:
void reset()
{
m_crc = CRC32_NEGL;
m_count = 0;
}
static const uint32_t m_tab[256];
uint32_t m_crc;
unsigned m_count;
};
#endif // _crc_h_

View File

@@ -0,0 +1,78 @@
/*
* File: format_string.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "format_string.h"
#include <stdio.h>
#include <stdarg.h>
#include <stdexcept>
#include <string.h>
#include <stdlib.h>
//! Size of the temporary buffer to hold the formatted output string.
#define WIN32_FMT_BUF_LEN (512)
/*!
* \brief Simple template class to free a pointer.
*/
template <typename T>
class free_ptr
{
public:
//! \brief Constructor.
free_ptr(T ptr)
: m_p(ptr)
{
}
//! \brief Destructor.
~free_ptr()
{
if (m_p)
{
free(m_p);
}
}
protected:
T m_p; //!< The value to free.
};
//! The purpose of this function to provide a convenient way of generating formatted
//! STL strings inline. This is especially useful when throwing exceptions that take
//! a std::string for a message. The length of the formatted output string is limited
//! only by memory. Memory temporarily allocated for the output string is disposed of
//! before returning.
//!
//! Example usage:
//! \code
//! throw std::runtime_error(format_string("error on line %d", line));
//! \endcode
//!
//! \param fmt Format string using printf-style format markers.
//! \return An STL string object of the formatted output.
std::string format_string(const char *fmt, ...)
{
char *buf = 0;
va_list vargs;
va_start(vargs, fmt);
int result = -1;
#if WIN32
buf = (char *)malloc(WIN32_FMT_BUF_LEN);
if (buf)
{
result = _vsnprintf(buf, WIN32_FMT_BUF_LEN, fmt, vargs);
}
#else // WIN32
result = vasprintf(&buf, fmt, vargs);
#endif // WIN32
va_end(vargs);
if (result != -1 && buf)
{
free_ptr<char *> freebuf(buf);
return std::string(buf);
}
return "";
}

View File

@@ -0,0 +1,18 @@
/*
* File: format_string.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_format_string_h_)
#define _format_string_h_
#include <string>
#include <stdexcept>
/*!
* \brief Returns a formatted STL string using printf format strings.
*/
std::string format_string(const char *fmt, ...);
#endif // _format_string_h_

View File

@@ -0,0 +1,22 @@
/*
* File: int_size.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_int_size_h_)
#define _int_size_h_
namespace elftosb
{
//! Supported sizes of integers.
typedef enum
{
kWordSize, //!< 32-bit word.
kHalfWordSize, //!< 16-bit half word.
kByteSize //!< 8-bit byte.
} int_size_t;
}; // namespace elftosb
#endif // _int_size_h_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,456 @@
// ****************************************************************************
// ^FILE: options.h - option parsing classes
//
// ^DESCRIPTION:
// This file defines classes used to parse command-line options.
// Options may be parsed from an array of strings, or from any structure
// for which a corresponding option-iterator exists.
//
// ^HISTORY:
// 03/06/92 Brad Appleton <bradapp@enteract.com> Created
//
// 03/23/93 Brad Appleton <bradapp@enteract.com>
// - Added OptIstreamIter class
//
// 03/08/94 Brad Appleton <bradapp@enteract.com>
// - Added Options::reset() member function
//
// 07/31/97 Brad Appleton <bradapp@enteract.com>
// - Added PARSE_POS control flag and POSITIONAL return value
//
// 04/30/06 Chris Reed
// - Updated to modern C++ and STL
// - Converted comments to doxygen style
// ^^**************************************************************************
#ifndef _options_h
#define _options_h
#ifdef USE_STDIO
#include <stdio.h>
#else
#include <iostream>
#endif
//! Abstract class to iterate through options/arguments
//!
class OptIter
{
public:
OptIter(void) {}
virtual ~OptIter(void);
//! curr() returns the current item in the iterator without
//! advancing on to the next item. If we are at the end of items
//! then NULL is returned.
virtual const char *curr(void) = 0;
//! next() advances to the next item.
virtual void next(void) = 0;
//! operator() returns the current item in the iterator and then
//! advances on to the next item. If we are at the end of items
//! then NULL is returned.
virtual const char *operator()(void);
};
//! Abstract class for a rewindable OptIter
//!
class OptIterRwd : public OptIter
{
public:
OptIterRwd(void);
virtual ~OptIterRwd(void);
virtual const char *curr(void) = 0;
virtual void next(void) = 0;
virtual const char *operator()(void) = 0;
//! rewind() resets the "current-element" to the first one in the "list"
virtual void rewind(void) = 0;
};
//! Class to iterate through an array of tokens. The array may be terminated
//! by NULL or a count containing the number of tokens may be given.
//!
class OptArgvIter : public OptIterRwd
{
private:
int ndx; // index of current arg
int ac; // arg count
const char *const *av; // arg vector
public:
OptArgvIter(const char *const argv[])
: av(argv)
, ac(-1)
, ndx(0)
{
}
OptArgvIter(int argc, const char *const argv[])
: av(argv)
, ac(argc)
, ndx(0)
{
}
virtual ~OptArgvIter(void);
virtual const char *curr(void);
virtual void next(void);
virtual const char *operator()(void);
virtual void rewind(void);
//! index returns the current index to use for argv[]
int index(void) { return ndx; }
};
//! Class to iterate through a string containing delimiter-separated tokens
//!
class OptStrTokIter : public OptIterRwd
{
private:
unsigned len; // length of token-string
const char *str; // the token-string
const char *seps; // delimiter-set (separator-characters)
const char *cur; // current token
char *tokstr; // our copy of the token-string
static const char *default_delims; // default delimiters = whitespace
public:
OptStrTokIter(const char *tokens, const char *delimiters = 0);
virtual ~OptStrTokIter(void);
virtual const char *curr(void);
virtual void next(void);
virtual const char *operator()(void);
virtual void rewind(void);
//! delimiters() with NO arguments returns the current set of delimiters,
//! If an argument is given then it is used as the new set of delimiters.
const char *delimiters(void) { return seps; }
void delimiters(const char *delims) { seps = (delims) ? delims : default_delims; }
};
//! OptIstreamIter is a class for iterating over arguments that come
//! from an input stream. Each line of the input stream is considered
//! to be a set of white-space separated tokens. If the the first
//! non-white character on a line is '#' ('!' for VMS systems) then
//! the line is considered a comment and is ignored.
//!
//! \note If a line is more than 1022 characters in length then we
//! treat it as if it were several lines of length 1022 or less.
//!
//! \note The string tokens returned by this iterator are pointers
//! to temporary buffers which may not necessarily stick around
//! for too long after the call to curr() or operator(), hence
//! if you need the string value to persist - you will need to
//! make a copy.
//!
class OptIstreamIter : public OptIter
{
private:
std::istream &is;
OptStrTokIter *tok_iter;
void fill(void);
public:
static const unsigned MAX_LINE_LEN;
OptIstreamIter(std::istream &input);
virtual ~OptIstreamIter(void);
virtual const char *curr(void);
virtual void next(void);
virtual const char *operator()(void);
};
//! \brief parse command-line options
//!
//! \section Synopsis
//! \code
//! #include <options.h>
//!
//! Options opts(cmdname, optv);
//! char cmdname[], *optv[];
//! \endcode
//! \section Description
//! The Options constructor expects a command-name (usually argv[0]) and
//! a pointer to an array of strings. The last element in this array MUST
//! be NULL. Each non-NULL string in the array must have the following format:
//!
//! The 1st character must be the option-name ('c' for a -c option).
//!
//! The 2nd character must be one of '|', '?', ':', '*', or '+'.
//! '|' -- indicates that the option takes NO argument;
//! '?' -- indicates that the option takes an OPTIONAL argument;
//! ':' -- indicates that the option takes a REQUIRED argument;
//! '*' -- indicates that the option takes 0 or more arguments;
//! '+' -- indicates that the option takes 1 or more arguments;
//!
//! The remainder of the string must be the long-option name.
//!
//! If desired, the long-option name may be followed by one or more
//! spaces and then by the name of the option value. This name will
//! be used when printing usage messages. If the option-value-name
//! is not given then the string "<value>" will be used in usage
//! messages.
//!
//! One may use a space to indicate that a particular option does not
//! have a corresponding long-option. For example, "c: " (or "c:")
//! means the -c option takes a value & has NO corresponding long-option.
//!
//! To specify a long-option that has no corresponding single-character
//! option is a bit trickier: Options::operator() still needs an "option-
//! character" to return when that option is matched. One may use a whitespace
//! character or a non-printable character as the single-character option
//! in such a case. (hence " |hello" would only match "--hello").
//!
//! \section Exceptions Exceptions to the above
//! If the 1st character of the string is '-', then the rest of the
//! string must correspond to the above format, and the option is
//! considered to be a hidden-option. This means it will be parsed
//! when actually matching options from the command-line, but will
//! NOT show-up if a usage message is printed using the usage() member
//! function. Such an example might be "-h|hidden". If you want to
//! use any "dummy" options (options that are not parsed, but that
//! to show up in the usage message), you can specify them along with
//! any positional parameters to the usage() member function.
//!
//! If the 2nd character of the string is '\0' then it is assumed
//! that there is no corresponding long-option and that the option
//! takes no argument (hence "f", and "f| " are equivalent).
//!
//! \code
//! const char * optv[] = {
//! "c:count <number>",
//! "s?str <string>",
//! "x",
//! " |hello",
//! "g+groups <newsgroup>",
//! NULL
//! } ;
//! \endcode
//! optv[] now corresponds to the following:
//!
//! usage: cmdname [-c|--count <number>] [-s|--str [<string>]]
//! [-x] [--hello] [-g|--groups <newsgroup> ...]
//!
//! Long-option names are matched case-insensitive and only a unique prefix
//! of the name needs to be specified.
//!
//! Option-name characters are case-sensitive!
//!
//! \section Caveat
//! Because of the way in which multi-valued options and options with optional
//! values are handled, it is NOT possible to supply a value to an option in
//! a separate argument (different argv[] element) if the value is OPTIONAL
//! and begins with a '-'. What this means is that if an option "-s" takes an
//! optional value value and you wish to supply a value of "-foo" then you must
//! specify this on the command-line as "-s-foo" instead of "-s -foo" because
//! "-s -foo" will be considered to be two separate sets of options.
//!
//! A multi-valued option is terminated by another option or by the end-of
//! options. The following are all equivalent (if "-l" is a multi-valued
//! option and "-x" is an option that takes no value):
//!
//! cmdname -x -l item1 item2 item3 -- arg1 arg2 arg3
//! cmdname -x -litem1 -litem2 -litem3 -- arg1 arg2 arg3
//! cmdname -l item1 item2 item3 -x arg1 arg2 arg3
//!
//!
//! \code
//! #include <options.h>
//!
//! static const char * optv[] = {
//! "H|help",
//! "c:count <number>",
//! "s?str <string>",
//! "x",
//! " |hello",
//! "g+groups <newsgroup>",
//! NULL
//! } ;
//!
//! main(int argc, char * argv[]) {
//! int optchar;
//! const char * optarg;
//! const char * str = "default_string";
//! int count = 0, xflag = 0, hello = 0;
//! int errors = 0, ngroups = 0;
//!
//! Options opts(*argv, optv);
//! OptArgvIter iter(--argc, ++argv);
//!
//! while( optchar = opts(iter, optarg) ) {
//! switch (optchar) {
//! case 'H' :
//! opts.usage(cout, "files ...");
//! exit(0);
//! break;
//! case 'g' :
//! ++ngroups; break; //! the groupname is in "optarg"
//! case 's' :
//! str = optarg; break;
//! case 'x' :
//! ++xflag; break;
//! case ' ' :
//! ++hello; break;
//! case 'c' :
//! if (optarg == NULL) ++errors;
//! else count = (int) atol(optarg);
//! break;
//! default : ++errors; break;
//! } //!switch
//! }
//!
//! if (errors || (iter.index() == argc)) {
//! if (! errors) {
//! cerr << opts.name() << ": no filenames given." << endl ;
//! }
//! opts.usage(cerr, "files ...");
//! exit(1);
//! }
//!
//! cout << "xflag=" << ((xflag) ? "ON" : "OFF") << endl
//! << "hello=" << ((hello) ? "YES" : "NO") << endl
//! << "count=" << count << endl
//! << "str=\"" << ((str) ? str : "No value given!") << "\"" << endl
//! << "ngroups=" << ngroups << endl ;
//!
//! if (iter.index() < argc) {
//! cout << "files=" ;
//! for (int i = iter.index() ; i < argc ; i++) {
//! cout << "\"" << argv[i] << "\" " ;
//! }
//! cout << endl ;
//! }
//! }
//! \endcode
class Options
{
private:
unsigned explicit_end : 1; //!< were we terminated because of "--"?
unsigned optctrls : 7; //!< control settings (a set of OptCtrl masks)
const char *const *optvec; //!< vector of option-specifications (last=NULL)
const char *nextchar; //!< next option-character to process
const char *listopt; //!< last list-option we matched
const char *cmdname; //!< name of the command
void check_syntax(void) const;
const char *match_opt(char opt, int ignore_case = 0) const;
const char *match_longopt(const char *opt, int len, int &ambiguous) const;
int parse_opt(OptIter &iter, const char *&optarg);
int parse_longopt(OptIter &iter, const char *&optarg);
public:
enum OptCtrl
{
DEFAULT = 0x00, //!< Default setting
ANYCASE = 0x01, //!< Ignore case when matching short-options
QUIET = 0x02, //!< Dont print error messages
PLUS = 0x04, //!< Allow "+" as a long-option prefix
SHORT_ONLY = 0x08, //!< Dont accept long-options
LONG_ONLY = 0x10, //!< Dont accept short-options
//!< (also allows "-" as a long-option prefix).
NOGUESSING = 0x20, //!< Normally, when we see a short (long) option
//!< on the command line that doesnt match any
//!< known short (long) options, then we try to
//!< "guess" by seeing if it will match any known
//!< long (short) option. Setting this mask prevents
//!< this "guessing" from occurring.
PARSE_POS = 0x40 //!< By default, Options will not present positional
//!< command-line arguments to the user and will
//!< instead stop parsing when the first positonal
//!< argument has been encountered. If this flag
//!< is given, Options will present positional
//!< arguments to the user with a return code of
//!< POSITIONAL; ENDOPTS will be returned only
//!< when the end of the argument list is reached.
};
//! Error return values for operator()
//!
enum OptRC
{
ENDOPTS = 0,
BADCHAR = -1,
BADKWD = -2,
AMBIGUOUS = -3,
POSITIONAL = -4
};
Options(const char *name, const char *const optv[]);
virtual ~Options(void);
//! name() returns the command name
const char *name(void) const { return cmdname; }
//! ctrls() (with no arguments) returns the existing control settings
unsigned ctrls(void) const { return optctrls; }
//! ctrls() (with 1 argument) sets new control settings
void ctrls(unsigned newctrls) { optctrls = newctrls; }
//! reset for another pass to parse for options
void reset(void) { nextchar = listopt = NULL; }
//! usage() prints options usage (followed by any positional arguments
//! listed in the parameter "positionals") on the given outstream
void usage(std::ostream &os, const char *positionals) const;
//! operator() iterates through the arguments as necessary (using the
//! given iterator) and returns the character value of the option
//! (or long-option) that it matched. If the option has a value
//! then the value given may be found in optarg (otherwise optarg
//! will be NULL).
//!
//! 0 is returned upon end-of-options. At this point, "iter" may
//! be used to process any remaining positional parameters. If the
//! PARSE_POS control-flag is set then 0 is returned only when all
//! arguments in "iter" have been exhausted.
//!
//! If an invalid option is found then BADCHAR is returned and *optarg
//! is the unrecognized option character.
//!
//! If an invalid long-option is found then BADKWD is returned and optarg
//! points to the bad long-option.
//!
//! If an ambiguous long-option is found then AMBIGUOUS is returned and
//! optarg points to the ambiguous long-option.
//!
//! If the PARSE_POS control-flag is set then POSITIONAL is returned
//! when a positional argument is encountered and optarg points to
//! the positonal argument (and "iter" is advanced to the next argument
//! in the iterator).
//!
//! Unless Options::QUIET is used, missing option-arguments and
//! invalid options (and the like) will automatically cause error
//! messages to be issued to cerr.
int operator()(OptIter &iter, const char *&optarg);
//! Call this member function after operator() has returned 0
//! if you want to know whether or not options were explicitly
//! terminated because "--" appeared on the command-line.
//!
int explicit_endopts() const { return explicit_end; }
};
#endif /* _options_h */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,180 @@
#ifndef _RIJNDAEL_H_
#define _RIJNDAEL_H_
//
// File : rijndael.h
// Creation date : Sun Nov 5 2000 03:21:05 CEST
// Author : Szymon Stefanek (stefanek@tin.it)
//
// Another implementation of the Rijndael cipher.
// This is intended to be an easily usable library file.
// This code is public domain.
// Based on the Vincent Rijmen and K.U.Leuven implementation 2.4.
//
//
// Original Copyright notice:
//
// rijndael-alg-fst.c v2.4 April '2000
// rijndael-alg-fst.h
// rijndael-api-fst.c
// rijndael-api-fst.h
//
// Optimised ANSI C code
//
// authors: v1.0: Antoon Bosselaers
// v2.0: Vincent Rijmen, K.U.Leuven
// v2.3: Paulo Barreto
// v2.4: Vincent Rijmen, K.U.Leuven
//
// This code is placed in the public domain.
//
//
// This implementation works on 128 , 192 , 256 bit keys
// and on 128 bit blocks
//
//
// Example of usage:
//
// // Input data
// unsigned char key[32]; // The key
// initializeYour256BitKey(); // Obviously initialized with sth
// const unsigned char * plainText = getYourPlainText(); // Your plain text
// int plainTextLen = strlen(plainText); // Plain text length
//
// // Encrypting
// Rijndael rin;
// unsigned char output[plainTextLen + 16];
//
// rin.init(Rijndael::CBC,Rijndael::Encrypt,key,Rijndael::Key32Bytes);
// // It is a good idea to check the error code
// int len = rin.padEncrypt(plainText,len,output);
// if(len >= 0)useYourEncryptedText();
// else encryptError(len);
//
// // Decrypting: we can reuse the same object
// unsigned char output2[len];
// rin.init(Rijndael::CBC,Rijndael::Decrypt,key,Rijndael::Key32Bytes));
// len = rin.padDecrypt(output,len,output2);
// if(len >= 0)useYourDecryptedText();
// else decryptError(len);
//
#include "stdafx.h"
#define _MAX_KEY_COLUMNS (256 / 32)
#define _MAX_ROUNDS 14
#define MAX_IV_SIZE 16
// We assume that unsigned int is 32 bits long....
// typedef unsigned char uint8_t;
// typedef unsigned int uint32_t;
// typedef unsigned short uint16_t;
// Error codes
#define RIJNDAEL_SUCCESS 0
#define RIJNDAEL_UNSUPPORTED_MODE -1
#define RIJNDAEL_UNSUPPORTED_DIRECTION -2
#define RIJNDAEL_UNSUPPORTED_KEY_LENGTH -3
#define RIJNDAEL_BAD_KEY -4
#define RIJNDAEL_NOT_INITIALIZED -5
#define RIJNDAEL_BAD_DIRECTION -6
#define RIJNDAEL_CORRUPTED_DATA -7
class Rijndael
{
public:
enum Direction
{
Encrypt,
Decrypt
};
enum Mode
{
ECB,
CBC,
CFB1
};
enum KeyLength
{
Key16Bytes,
Key24Bytes,
Key32Bytes
};
//
// Creates a Rijndael cipher object
// You have to call init() before you can encrypt or decrypt stuff
//
Rijndael();
~Rijndael();
protected:
// Internal stuff
enum State
{
Valid,
Invalid
};
State m_state;
Mode m_mode;
Direction m_direction;
uint8_t m_initVector[MAX_IV_SIZE];
uint32_t m_uRounds;
uint8_t m_expandedKey[_MAX_ROUNDS + 1][4][4];
public:
//////////////////////////////////////////////////////////////////////////////////////////
// API
//////////////////////////////////////////////////////////////////////////////////////////
// init(): Initializes the crypt session
// Returns RIJNDAEL_SUCCESS or an error code
// mode : Rijndael::ECB, Rijndael::CBC or Rijndael::CFB1
// You have to use the same mode for encrypting and decrypting
// dir : Rijndael::Encrypt or Rijndael::Decrypt
// A cipher instance works only in one direction
// (Well , it could be easily modified to work in both
// directions with a single init() call, but it looks
// useless to me...anyway , it is a matter of generating
// two expanded keys)
// key : array of unsigned octets , it can be 16 , 24 or 32 bytes long
// this CAN be binary data (it is not expected to be null terminated)
// keyLen : Rijndael::Key16Bytes , Rijndael::Key24Bytes or Rijndael::Key32Bytes
// initVector: initialization vector, you will usually use 0 here
int init(Mode mode, Direction dir, const uint8_t *key, KeyLength keyLen, uint8_t *initVector = 0);
// Encrypts the input array (can be binary data)
// The input array length must be a multiple of 16 bytes, the remaining part
// is DISCARDED.
// so it actually encrypts inputLen / 128 blocks of input and puts it in outBuffer
// Input len is in BITS!
// outBuffer must be at least inputLen / 8 bytes long.
// Returns the encrypted buffer length in BITS or an error code < 0 in case of error
int blockEncrypt(const uint8_t *input, int inputLen, uint8_t *outBuffer);
// Encrypts the input array (can be binary data)
// The input array can be any length , it is automatically padded on a 16 byte boundary.
// Input len is in BYTES!
// outBuffer must be at least (inputLen + 16) bytes long
// Returns the encrypted buffer length in BYTES or an error code < 0 in case of error
int padEncrypt(const uint8_t *input, int inputOctets, uint8_t *outBuffer);
// Decrypts the input vector
// Input len is in BITS!
// outBuffer must be at least inputLen / 8 bytes long
// Returns the decrypted buffer length in BITS and an error code < 0 in case of error
int blockDecrypt(const uint8_t *input, int inputLen, uint8_t *outBuffer);
// Decrypts the input vector
// Input len is in BYTES!
// outBuffer must be at least inputLen bytes long
// Returns the decrypted buffer length in BYTES and an error code < 0 in case of error
int padDecrypt(const uint8_t *input, int inputOctets, uint8_t *outBuffer);
protected:
void keySched(uint8_t key[_MAX_KEY_COLUMNS][4]);
void keyEncToDec();
void encrypt(const uint8_t a[16], uint8_t b[16]);
void decrypt(const uint8_t a[16], uint8_t b[16]);
};
#endif // _RIJNDAEL_H_

View File

@@ -0,0 +1,218 @@
/*
* smart_ptr.h
* elftosb
*
* Created by Chris Reed on 4/18/06.
* Copyright 2006 __MyCompanyName__. All rights reserved.
*
*/
#if !defined(_smart_ptr_h_)
#define _smart_ptr_h_
/*!
* \brief Simple, standard smart pointer class.
*
* This class only supports the single-owner paradigm.
*/
template <typename T>
class smart_ptr
{
public:
typedef T data_type;
typedef T *ptr_type;
typedef const T *const_ptr_type;
typedef T &ref_type;
typedef const T &const_ref_type;
//! Default constuctor. Initialises with no pointer set.
smart_ptr()
: _p(0)
{
}
//! This constructor takes a pointer to the object to be deleted.
smart_ptr(ptr_type p)
: _p(p)
{
}
//! Destructor. If an object (pointer) has been set, it will be deleted.
//! Deletes the object using safe_delete().
virtual ~smart_ptr() { safe_delete(); }
//! Return the current pointer value.
ptr_type get() { return _p; }
//! Return the const form of the current pointer value.
const_ptr_type get() const { return _p; }
//! Change the pointer value, or set if if the default constructor was used.
//! If a pointer had previously been associated with the object, and \a p is
//! different than that previous pointer, it will be deleted before taking
//! ownership of \a p. If this is not desired, call reset() beforehand.
void set(ptr_type p)
{
if (_p && p != _p)
{
safe_delete();
}
_p = p;
}
//! Dissociates any previously set pointer value without deleting it.
void reset() { _p = 0; }
//! Dissociates a previously set pointer value, deleting it at the same time.
void clear() { safe_delete(); }
//! Forces immediate deletion of the object. If you are planning on using
//! this method, think about just using a normal pointer. It probably makes
//! more sense.
virtual void safe_delete()
{
if (_p)
{
delete _p;
_p = 0;
}
}
//! \name Operators
//@{
//! Makes the object transparent as the template type.
operator ptr_type() { return _p; }
//! Const version of the pointer operator.
operator const_ptr_type() const { return _p; }
//! Makes the object transparent as a reference of the template type.
operator ref_type() { return *_p; }
//! Const version of the reference operator.
operator const_ref_type() const { return *_p; }
//! Returns a boolean indicating whether the object has a pointer set or not.
operator bool() const { return _p != 0; }
//! To allow setting the pointer directly. Equivalent to a call to set().
smart_ptr<T> &operator=(const_ptr_type p)
{
set(const_cast<ptr_type>(p));
return *this;
}
//! Another operator to allow you to treat the object just like a pointer.
ptr_type operator->() { return _p; }
//! Another operator to allow you to treat the object just like a pointer.
const_ptr_type operator->() const { return _p; }
// //! Pointer dereferencing operator.
// ref_type operator * () const { return *_p; }
//
// //! Const version of the pointer dereference operator.
// const_ref_type operator * () const { return *_p; }
//@}
protected:
ptr_type _p; //!< The wrapped pointer.
};
/*!
* \brief Simple, standard smart pointer class that uses the array delete operator.
*
* This class only supports the single-owner paradigm.
*
* This is almost entirely a copy of smart_ptr since the final C++ specification
* does not allow template subclass members to access members of the parent that
* do not depend on the template parameter.
*/
template <typename T>
class smart_array_ptr
{
public:
typedef T data_type;
typedef T *ptr_type;
typedef const T *const_ptr_type;
typedef T &ref_type;
typedef const T &const_ref_type;
//! Default constuctor. Initialises with no pointer set.
smart_array_ptr()
: _p(0)
{
}
//! This constructor takes a pointer to the object to be deleted.
smart_array_ptr(ptr_type p)
: _p(p)
{
}
//! Destructor. If an array has been set, it will be deleted.
//! Deletes the array using safe_delete().
virtual ~smart_array_ptr() { safe_delete(); }
//! Return the current pointer value.
ptr_type get() { return _p; }
//! Return the const form of the current pointer value.
const_ptr_type get() const { return _p; }
//! Change the pointer value, or set if if the default constructor was used.
//! If a pointer had previously been associated with the object, and \a p is
//! different than that previous pointer, it will be deleted before taking
//! ownership of \a p. If this is not desired, call reset() beforehand.
void set(ptr_type p)
{
if (_p && p != _p)
{
safe_delete();
}
_p = p;
}
//! Dissociates any previously set pointer value without deleting it.
void reset() { _p = 0; }
//! Dissociates a previously set pointer value, deleting it at the same time.
void clear() { safe_delete(); }
//! Forces immediate deletion of the object. If you are planning on using
//! this method, think about just using a normal pointer. It probably makes
//! more sense.
virtual void safe_delete()
{
if (_p)
{
delete[] _p;
_p = 0;
}
}
//! \name Operators
//@{
//! Makes the object transparent as the template type.
operator ptr_type() { return _p; }
//! Const version of the pointer operator.
operator const_ptr_type() const { return _p; }
//! Makes the object transparent as a reference of the template type.
operator ref_type() { return *_p; }
//! Const version of the reference operator.
operator const_ref_type() const { return *_p; }
//! Returns a boolean indicating whether the object has a pointer set or not.
operator bool() const { return _p != 0; }
//! To allow setting the pointer directly. Equivalent to a call to set().
smart_array_ptr<T> &operator=(const_ptr_type p)
{
set(const_cast<ptr_type>(p));
return *this;
}
//! Another operator to allow you to treat the object just like a pointer.
ptr_type operator->() { return _p; }
//! Another operator to allow you to treat the object just like a pointer.
const_ptr_type operator->() const { return _p; }
//! Indexing operator.
ref_type operator[](unsigned index) { return _p[index]; }
//! Indexing operator.
const_ref_type operator[](unsigned index) const { return _p[index]; }
// //! Pointer dereferencing operator.
// ref_type operator * () const { return *_p; }
//
// //! Const version of the pointer dereference operator.
// const_ref_type operator * () const { return *_p; }
//@}
protected:
ptr_type _p; //!< The wrapped pointer.
};
#endif // _smart_ptr_h_

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// stdafx.cpp : source file that includes just the standard includes
// elftosb.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

View File

@@ -0,0 +1,100 @@
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef stdafx_h_
#define stdafx_h_
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
// Default to external release.
#ifndef SGTL_INTERNAL
#define SGTL_INTERNAL 0
#endif
#include <iostream>
#include <stdexcept>
#if defined(WIN32)
//#include <tchar.h>
// define this macro for use in VC++
#if !defined(__LITTLE_ENDIAN__)
#define __LITTLE_ENDIAN__ 1
#endif // !defined(__LITTLE_ENDIAN__)
#endif // defined(WIN32)
#if defined(Linux)
// For Linux systems only, types.h only defines the signed
// integer types. This is not professional code.
// Update: They are defined in the header files in the more recent version of redhat enterprise gcc.
//#include "/usr/include/sys/types.h"
#include <stdint.h>
#include <limits.h>
// typedef unsigned long uint32_t;
// typedef unsigned short uint16_t;
// typedef unsigned char uint8_t;
//#define TCHAR char
//#define _tmain main
// give a default endian in case one is not defined on Linux (it should be, though)
#if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
#define __LITTLE_ENDIAN__ 1
#endif // !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
#endif // defined(Linux)
// gcc on Mac OS X
#if defined(__GNUC__) && (defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__MACOS_CLASSIC__))
#include <TargetConditionals.h>
#if defined(TARGET_RT_LITTLE_ENDIAN) && TARGET_RT_LITTLE_ENDIAN
#if !defined(__LITTLE_ENDIAN__)
#define __LITTLE_ENDIAN__
#endif
#elif defined(TARGET_RT_BIG_ENDIAN) && TARGET_RT_BIG_ENDIAN
#if !defined(__BIG_ENDIAN__)
#define __BIG_ENDIAN__
#endif
#endif
#endif
#if !defined(TRUE)
#define TRUE 1
#endif // !defined(TRUE)
#if !defined(FALSE)
#define FALSE 0
#endif // !defined(FALSE)
#endif // stdafx_h_

21
apps/elftosb/elftosb.sln Normal file
View File

@@ -0,0 +1,21 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "elftosb2", "elftosb2\elftosb2.vcxproj", "{ACBF9A30-8865-4DAA-B686-D8DC823CBF5C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{ACBF9A30-8865-4DAA-B686-D8DC823CBF5C}.Debug|Win32.ActiveCfg = Debug|Win32
{ACBF9A30-8865-4DAA-B686-D8DC823CBF5C}.Debug|Win32.Build.0 = Debug|Win32
{ACBF9A30-8865-4DAA-B686-D8DC823CBF5C}.Release|Win32.ActiveCfg = Release|Win32
{ACBF9A30-8865-4DAA-B686-D8DC823CBF5C}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:elftosb.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,79 @@
/*
* BootImageGenerator.cpp
* elftosb
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "BootImageGenerator.h"
#include "Logging.h"
//! Name of product version option.
#define kProductVersionOption "productVersion"
//! Name of component version option.
#define kComponentVersionOption "componentVersion"
//! Name of option that specifies the drive tag for this .sb file.
#define kDriveTagOption "driveTag"
using namespace elftosb;
void BootImageGenerator::processVersionOptions(BootImage *image)
{
// bail if no option context was set
if (!m_options)
{
return;
}
const StringValue *stringValue;
version_t version;
// productVersion
if (m_options->hasOption(kProductVersionOption))
{
stringValue = dynamic_cast<const StringValue *>(m_options->getOption(kProductVersionOption));
if (stringValue)
{
version.set(*stringValue);
image->setProductVersion(version);
}
else
{
Log::log(Logger::WARNING, "warning: productVersion option is an unexpected type\n");
}
}
// componentVersion
if (m_options->hasOption(kComponentVersionOption))
{
stringValue = dynamic_cast<const StringValue *>(m_options->getOption(kComponentVersionOption));
if (stringValue)
{
version.set(*stringValue);
image->setComponentVersion(version);
}
else
{
Log::log(Logger::WARNING, "warning: componentVersion option is an unexpected type\n");
}
}
}
void BootImageGenerator::processDriveTagOption(BootImage *image)
{
if (m_options->hasOption(kDriveTagOption))
{
const IntegerValue *intValue = dynamic_cast<const IntegerValue *>(m_options->getOption(kDriveTagOption));
if (intValue)
{
image->setDriveTag(static_cast<uint16_t>(intValue->getValue()));
}
else
{
Log::log(Logger::WARNING, "warning: driveTag option is an unexpected type\n");
}
}
}

View File

@@ -0,0 +1,63 @@
/*
* File: BootImageGenerator.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_BootImageGenerator_h_)
#define _BootImageGenerator_h_
#include "OutputSection.h"
#include "BootImage.h"
#include "OptionContext.h"
namespace elftosb
{
/*!
* \brief Abstract base class for generators of specific boot image formats.
*
* Subclasses implement a concrete generator for a certain boot image format, but
* they all have the same interface.
*
* After creating an instance of a subclass the user adds OutputSection objects
* to the generator. These objects describe discrete sections within the resulting
* boot image file. If the format does not support multiple sections then only
* the first will be used.
*
* Options that are common to all boot image formats are handled by methods
* defined in this class. These are the current common options:
* - productVersion
* - componentVersion
* - driveTag
*/
class BootImageGenerator
{
public:
//! \brief Constructor.
BootImageGenerator() {}
//! \brief Destructor.
virtual ~BootImageGenerator() {}
//! \brief Add another section to the output.
void addOutputSection(OutputSection *section) { m_sections.push_back(section); }
//! \brief Set the global option context.
void setOptionContext(OptionContext *context) { m_options = context; }
//! \brief Pure virtual method to generate the output BootImage from input sections.
virtual BootImage *generate() = 0;
protected:
//! Type for a list of model output sections.
typedef std::vector<OutputSection *> section_vector_t;
section_vector_t m_sections; //!< Requested output sections.
OptionContext *m_options; //!< Global option context.
//! \brief Handle common product and component version options.
void processVersionOptions(BootImage *image);
//! \brief Handle the common option which sets the system drive tag.
void processDriveTagOption(BootImage *image);
};
}; // namespace elftosb
#endif // _BootImageGenerator_h_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,164 @@
/*
* File: ConversionController.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_ConversionController_h_)
#define _ConversionController_h_
#include <iostream>
#include <fstream>
#include <string>
#include <stdexcept>
#include "smart_ptr.h"
#include "ElftosbLexer.h"
#include "ElftosbAST.h"
#include "EvalContext.h"
#include "Value.h"
#include "SourceFile.h"
#include "Operation.h"
#include "DataSource.h"
#include "DataTarget.h"
#include "OutputSection.h"
#include "BootImage.h"
#include "OptionDictionary.h"
#include "BootImageGenerator.h"
#include "Keyblob.h"
namespace elftosb
{
/*!
* \brief Manages the entire elftosb file conversion process.
*
* Instances of this class are intended to be used only once. There is no
* way to reset an instance once it has started or completed a conversion.
* Thus the run() method is not reentrant. State information is stored in
* the object during the conversion process.
*
* Two things need to be done before the conversion can be started. The
* command file path has to be set with the setCommandFilePath() method,
* and the paths of any externally provided (i.e., from the command line)
* files need to be added with addExternalFilePath(). Once these tasks
* are completed, the run() method can be called to parse and execute the
* command file. After run() returns, pass an instance of
* BootImageGenerator to the generateOutput() method in order to get
* an instance of BootImage that can be written to the output file.
*/
class ConversionController : public OptionDictionary, public EvalContext::SourceFileManager
{
public:
//! \brief Default constructor.
ConversionController();
//! \brief Destructor.
virtual ~ConversionController();
//! \name Paths
//@{
//! \brief Specify the command file that controls the conversion process.
void setCommandFilePath(const std::string &path);
//! \brief Specify the path of a file provided by the user from outside the command file.
void addExternalFilePath(const std::string &path);
//@}
//! \name Conversion
//@{
//! \brief Process input files.
void run();
//! \brief Uses a BootImageGenerator object to create the final output boot image.
BootImage *generateOutput(BootImageGenerator *generator);
//@}
//! \name SourceFileManager interface
//@{
//! \brief Returns true if a source file with the name \a name exists.
virtual bool hasSourceFile(const std::string &name);
//! \brief Gets the requested source file.
virtual SourceFile *getSourceFile(const std::string &name);
//! \brief Returns the default source file, or NULL if none is set.
virtual SourceFile *getDefaultSourceFile();
//@}
//! \brief Returns a reference to the context used for expression evaluation.
inline EvalContext &getEvalContext() { return m_context; }
protected:
//! \name AST processing
//@{
void parseCommandFile();
void processOptions(ListASTNode *options);
void processConstants(ListASTNode *constants);
void processSources(ListASTNode *sources);
void processKeyblob(ExprASTNode *idExpr, ListASTNode *entires);
void processSections(ListASTNode *sections);
OutputSection *convertDataSection(DataSectionContentsASTNode *dataSection,
uint32_t sectionID,
OptionDictionary *optionsDict);
//@}
//! \name Statement conversion
//@{
OperationSequence *convertStatementList(ListASTNode *statements);
OperationSequence *convertOneStatement(StatementASTNode *statement);
OperationSequence *convertLoadStatement(LoadStatementASTNode *statement);
OperationSequence *convertCallStatement(CallStatementASTNode *statement);
OperationSequence *convertFromStatement(FromStatementASTNode *statement);
OperationSequence *convertModeStatement(ModeStatementASTNode *statement);
OperationSequence *convertResetStatement(ResetStatementASTNode *statement);
OperationSequence *convertIfStatement(IfStatementASTNode *statement);
OperationSequence *convertEraseStatement(EraseStatementASTNode *statement);
OperationSequence *convertMemEnableStatement(MemEnableStatementASTNode *statement);
OperationSequence *convertKeywrapStatement(KeywrapStatementASTNode *statement);
OperationSequence *convertEncryptStatement(EncryptStatementASTNode *statement);
void handleMessageStatement(MessageStatementASTNode *statement);
//@}
//! \name Utilities
//@{
Value *convertAssignmentNodeToValue(ASTNode *node, std::string &ident);
SourceFile *getSourceFromName(std::string *sourceName, int line);
DataSource *createSourceFromNode(ASTNode *dataNode);
DataTarget *createTargetFromNode(ASTNode *targetNode);
std::string *substituteVariables(const std::string *message);
DataSource *createIVTDataSource(IVTConstASTNode *ivtNode);
//@}
//! \name Debugging
//@{
void testLexer(ElftosbLexer &lexer);
void printIntConstExpr(const std::string &ident, IntConstExprASTNode *expr);
//@}
protected:
typedef std::map<std::string, SourceFile *> source_map_t; //!< Map from source name to object.
typedef std::vector<std::string> path_vector_t; //!< List of file paths.
typedef std::vector<OutputSection *> section_vector_t; //!< List of output sections.
typedef std::vector<std::string> source_name_vector_t; //!< List of source names.
typedef std::vector<Keyblob *> keyblob_vector_t; //!< List of keyblobs.
smart_ptr<std::string> m_commandFilePath; //!< Path to command file.
smart_ptr<CommandFileASTNode> m_ast; //!< Root of the abstract syntax tree.
EvalContext m_context; //!< Evaluation context for expressions.
source_map_t m_sources; //!< Map of source names to file objects.
path_vector_t m_externPaths; //!< Paths provided on the command line by the user.
SourceFile *m_defaultSource; //!< Source to use when one isn't provided.
section_vector_t m_outputSections; //!< List of output sections the user wants.
source_name_vector_t m_failedSources; //!< List of sources that failed to open successfully.
keyblob_vector_t m_keyblobs; //!< List of keyblobs the user defines.
Keyblob *m_keywrapKeyblob; //!< Keyblob used for keywrapping
Keyblob *m_encryptKeyblob; //!< Keyblob used for OTFAD encryption
};
//! \brief Whether to support HAB keywords during parsing.
//!
//! This is a standalone global solely so that the bison-generated parser code can get to it
//! as simply as possible.
extern bool g_enableHABSupport;
}; // namespace elftosb
#endif // _ConversionController_h_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
/*
* File: ConversionController.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_ElftosbErrors_h_)
#define _ElftosbErrors_h_
#include <string>
#include <stdexcept>
namespace elftosb
{
/*!
* \brief A semantic error discovered while processing the command file AST.
*/
class semantic_error : public std::runtime_error
{
public:
explicit semantic_error(const std::string &msg)
: std::runtime_error(msg)
{
}
};
}; // namespace elftosb
#endif // _ElftosbErrors_h_

View File

@@ -0,0 +1,152 @@
/*
* File: ElftosbLexer.cpp
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#include "ElftosbLexer.h"
#include <algorithm>
#include "HexValues.h"
using namespace elftosb;
ElftosbLexer::ElftosbLexer(istream &inputStream)
: yyFlexLexer(&inputStream)
, m_line(1)
, m_blob(0)
, m_blobFirstLine(0)
{
}
void ElftosbLexer::getSymbolValue(YYSTYPE *value)
{
if (!value)
{
return;
}
*value = m_symbolValue;
}
void ElftosbLexer::addSourceName(std::string *ident)
{
m_sources.push_back(*ident);
}
bool ElftosbLexer::isSourceName(std::string *ident)
{
string_vector_t::iterator it = find(m_sources.begin(), m_sources.end(), *ident);
return it != m_sources.end();
}
void ElftosbLexer::LexerError(const char *msg)
{
throw elftosb::lexical_error(msg);
}
//! Reads the \a in string and writes to the \a out string. These strings can be the same
//! string since the read head is always in front of the write head.
//!
//! \param[in] in Input string containing C-style escape sequences.
//! \param[out] out Output string. All escape sequences in the input string have been converted
//! to the actual characters. May point to the same string as \a in.
//! \return The length of the resulting \a out string. This length is necessary because
//! the string may have contained escape sequences that inserted null characters.
int ElftosbLexer::processStringEscapes(const char *in, char *out)
{
int count = 0;
while (*in)
{
switch (*in)
{
case '\\':
{
// start of an escape sequence
char c = *++in;
switch (c)
{
case 0: // end of the string, bail
break;
case 'x':
{
// start of a hex char escape sequence
// read high and low nibbles, checking for end of string
char hi = *++in;
if (hi == 0)
break;
char lo = *++in;
if (lo == 0)
break;
if (isHexDigit(hi) && isHexDigit(lo))
{
if (hi >= '0' && hi <= '9')
c = (hi - '0') << 4;
else if (hi >= 'A' && hi <= 'F')
c = (hi - 'A' + 10) << 4;
else if (hi >= 'a' && hi <= 'f')
c = (hi - 'a' + 10) << 4;
if (lo >= '0' && lo <= '9')
c |= lo - '0';
else if (lo >= 'A' && lo <= 'F')
c |= lo - 'A' + 10;
else if (lo >= 'a' && lo <= 'f')
c |= lo - 'a' + 10;
*out++ = c;
count++;
}
else
{
// not hex digits, the \x must have wanted an 'x' char
*out++ = 'x';
*out++ = hi;
*out++ = lo;
count += 3;
}
break;
}
case 'n':
*out++ = '\n';
count++;
break;
case 't':
*out++ = '\t';
count++;
break;
case 'r':
*out++ = '\r';
count++;
break;
case 'b':
*out++ = '\b';
count++;
break;
case 'f':
*out++ = '\f';
count++;
break;
case '0':
*out++ = '\0';
count++;
break;
default:
*out++ = c;
count++;
break;
}
break;
}
default:
// copy all other chars directly
*out++ = *in++;
count++;
}
}
// place terminating null char on output
*out = 0;
return count;
}

View File

@@ -0,0 +1,101 @@
/*
* File: ElftosbLexer.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
// This header just wraps the standard flex C++ header to make it easier to include
// without having to worry about redefinitions of the class name every time.
#if !defined(_ElftosbLexer_h_)
#define _ElftosbLexer_h_
#include "ElftosbAST.h"
#include "FlexLexer.h"
#include "elftosb_parser.tab.hpp"
#include <vector>
#include <string>
#include <stdexcept>
#include "Blob.h"
using namespace std;
namespace elftosb
{
/*!
* \brief Exception class for syntax errors.
*/
class syntax_error : public std::runtime_error
{
public:
explicit syntax_error(const std::string &__arg)
: std::runtime_error(__arg)
{
}
};
/*!
* \brief Exception class for lexical errors.
*/
class lexical_error : public std::runtime_error
{
public:
explicit lexical_error(const std::string &__arg)
: std::runtime_error(__arg)
{
}
};
/*!
* \brief Lexical scanner class for elftosb command files.
*
* This class is a subclass of the standard C++ lexer class produced by
* Flex. It's primary purpose is to provide a clean way to report values
* for symbols, without using the yylval global. This is necessary because
* the parser produced by Bison is a "pure" parser.
*
* In addition, this class manages a list of source names generated by
* parsing. The lexer uses this list to determine if an identifier is
* a source name or a constant identifier.
*/
class ElftosbLexer : public yyFlexLexer
{
public:
//! \brief Constructor.
ElftosbLexer(istream &inputStream);
//! \brief Lexer interface. Returns one token.
virtual int yylex();
//! \brief Returns the value for the most recently produced token in \a value.
virtual void getSymbolValue(YYSTYPE *value);
//! \brief Returns the current token's location in \a loc.
inline token_loc_t &getLocation() { return m_location; }
//! \name Source names
//@{
void addSourceName(std::string *ident);
bool isSourceName(std::string *ident);
//@}
protected:
YYSTYPE m_symbolValue; //!< Value for the current token.
int m_line; //!< Current line number.
token_loc_t m_location; //!< Location for the current token.
Blob *m_blob; //!< The binary object value as its being constructed.
int m_blobFirstLine; //!< Line number for the first character of a blob.
typedef std::vector<std::string> string_vector_t;
string_vector_t m_sources; //!< Vector of source identifiers;
//! \brief Throw an elftosb::lexical_error exception.
virtual void LexerError(const char *msg);
//! \brief Process a string containing escape sequences.
int processStringEscapes(const char *in, char *out);
};
}; // namespace elftosb
#endif // _ElftosbLexer_h_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
/*
* File: EncoreBootImageGenerator.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_EncoreBootImageGenerator_h_)
#define _EncoreBootImageGenerator_h_
#include "BootImageGenerator.h"
#include "EncoreBootImage.h"
#include "Keyblob.h"
namespace elftosb
{
/*!
* \brief Generator for Encore boot images.
*
* Takes the abstract model of the output file and processes it into a
* concrete boot image for the STMP37xx.
*
* In order to enable full i.mx28 support, you must call the setSupportHAB() method and
* pass true.
*/
class EncoreBootImageGenerator : public BootImageGenerator
{
public:
//! \brief Default constructor.
EncoreBootImageGenerator()
: BootImageGenerator()
, m_encryptKeyBlob(NULL)
{
}
//! \brief Builds the resulting boot image from previously added output sections.
virtual BootImage *generate();
//! \brief Enable or disable HAB support.
void setSupportHAB(bool supportHAB) { m_supportHAB = supportHAB; }
protected:
bool m_supportHAB; //!< True if HAB features are enabled.
Keyblob *m_encryptKeyBlob; //!< Keyblob to use during load if encrypting for OTFAD.
void processOptions(EncoreBootImage *image);
void processSectionOptions(EncoreBootImage::Section *imageSection, OutputSection *modelSection);
void processOperationSection(OperationSequenceSection *section, EncoreBootImage *image);
void processDataSection(BinaryDataSection *section, EncoreBootImage *image);
void processLoadOperation(LoadOperation *op, EncoreBootImage::BootSection *section);
void processExecuteOperation(ExecuteOperation *op, EncoreBootImage::BootSection *section);
void processBootModeOperation(BootModeOperation *op, EncoreBootImage::BootSection *section);
void processFlashEraseOperation(FlashEraseOperation *op, EncoreBootImage::BootSection *section);
void processResetOperation(ResetOperation *op, EncoreBootImage::BootSection *section);
void processMemEnableOperation(MemEnableOperation *op, EncoreBootImage::BootSection *section);
void processProgramOperation(ProgramOperation *op, EncoreBootImage::BootSection *section);
void processKeywrapOperation(KeywrapOperation *op, EncoreBootImage::BootSection *section);
void processEncryptOperation(EncryptOperation *op, EncoreBootImage::BootSection *section);
void setFillPatternFromValue(EncoreBootImage::FillCommand &command, SizedIntegerValue &pattern);
};
}; // namespace elftosb
#endif // _EncoreBootImageGenerator_h_

View File

@@ -0,0 +1,199 @@
// -*-C++-*-
// FlexLexer.h -- define interfaces for lexical analyzer classes generated
// by flex
// Copyright (c) 1993 The Regents of the University of California.
// All rights reserved.
//
// This code is derived from software contributed to Berkeley by
// Kent Williams and Tom Epperly.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// Neither the name of the University nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE.
// This file defines FlexLexer, an abstract class which specifies the
// external interface provided to flex C++ lexer objects, and yyFlexLexer,
// which defines a particular lexer class.
//
// If you want to create multiple lexer classes, you use the -P flag
// to rename each yyFlexLexer to some other xxFlexLexer. You then
// include <FlexLexer.h> in your other sources once per lexer class:
//
// #undef yyFlexLexer
// #define yyFlexLexer xxFlexLexer
// #include <FlexLexer.h>
//
// #undef yyFlexLexer
// #define yyFlexLexer zzFlexLexer
// #include <FlexLexer.h>
// ...
#ifndef __FLEX_LEXER_H
// Never included before - need to define base class.
#define __FLEX_LEXER_H
#include <iostream>
#ifndef FLEX_STD
#define FLEX_STD std::
#endif
extern "C++" {
struct yy_buffer_state;
typedef int yy_state_type;
class FlexLexer
{
public:
virtual ~FlexLexer() {}
const char *YYText() const { return yytext; }
int YYLeng() const { return yyleng; }
virtual void yy_switch_to_buffer(struct yy_buffer_state *new_buffer) = 0;
virtual struct yy_buffer_state *yy_create_buffer(FLEX_STD istream *s, int size) = 0;
virtual void yy_delete_buffer(struct yy_buffer_state *b) = 0;
virtual void yyrestart(FLEX_STD istream *s) = 0;
virtual int yylex() = 0;
// Call yylex with new input/output sources.
int yylex(FLEX_STD istream *new_in, FLEX_STD ostream *new_out = 0)
{
switch_streams(new_in, new_out);
return yylex();
}
// Switch to new input/output streams. A nil stream pointer
// indicates "keep the current one".
virtual void switch_streams(FLEX_STD istream *new_in = 0, FLEX_STD ostream *new_out = 0) = 0;
int lineno() const { return yylineno; }
int debug() const { return yy_flex_debug; }
void set_debug(int flag) { yy_flex_debug = flag; }
protected:
char *yytext;
int yyleng;
int yylineno; // only maintained if you use %option yylineno
int yy_flex_debug; // only has effect with -d or "%option debug"
};
}
#endif // FLEXLEXER_H
//#if defined(yyFlexLexer) || ! defined(yyFlexLexerOnce)
// had to disable the 'defined(yyFlexLexer)' part because it was causing duplicate class defs
#if !defined(yyFlexLexerOnce)
// Either this is the first time through (yyFlexLexerOnce not defined),
// or this is a repeated include to define a different flavor of
// yyFlexLexer, as discussed in the flex manual.
#define yyFlexLexerOnce
extern "C++" {
class yyFlexLexer : public FlexLexer
{
public:
// arg_yyin and arg_yyout default to the cin and cout, but we
// only make that assignment when initializing in yylex().
yyFlexLexer(FLEX_STD istream *arg_yyin = 0, FLEX_STD ostream *arg_yyout = 0);
virtual ~yyFlexLexer();
void yy_switch_to_buffer(struct yy_buffer_state *new_buffer);
struct yy_buffer_state *yy_create_buffer(FLEX_STD istream *s, int size);
void yy_delete_buffer(struct yy_buffer_state *b);
void yyrestart(FLEX_STD istream *s);
void yypush_buffer_state(struct yy_buffer_state *new_buffer);
void yypop_buffer_state();
virtual int yylex();
virtual void switch_streams(FLEX_STD istream *new_in, FLEX_STD ostream *new_out = 0);
virtual int yywrap();
protected:
virtual size_t LexerInput(char *buf, size_t max_size);
virtual void LexerOutput(const char *buf, size_t size);
virtual void LexerError(const char *msg);
void yyunput(int c, char *buf_ptr);
int yyinput();
void yy_load_buffer_state();
void yy_init_buffer(struct yy_buffer_state *b, FLEX_STD istream *s);
void yy_flush_buffer(struct yy_buffer_state *b);
int yy_start_stack_ptr;
int yy_start_stack_depth;
int *yy_start_stack;
void yy_push_state(int new_state);
void yy_pop_state();
int yy_top_state();
yy_state_type yy_get_previous_state();
yy_state_type yy_try_NUL_trans(yy_state_type current_state);
int yy_get_next_buffer();
FLEX_STD istream *yyin; // input source for default LexerInput
FLEX_STD ostream *yyout; // output sink for default LexerOutput
// yy_hold_char holds the character lost when yytext is formed.
char yy_hold_char;
// Number of characters read into yy_ch_buf.
int yy_n_chars;
// Points to current character in buffer.
char *yy_c_buf_p;
int yy_init; // whether we need to initialize
int yy_start; // start state number
// Flag which is used to allow yywrap()'s to do buffer switches
// instead of setting up a fresh yyin. A bit of a hack ...
int yy_did_buffer_switch_on_eof;
size_t yy_buffer_stack_top; /**< index of top of stack. */
size_t yy_buffer_stack_max; /**< capacity of stack. */
struct yy_buffer_state **yy_buffer_stack; /**< Stack as an array. */
void yyensure_buffer_stack(void);
// The following are not always needed, but may be depending
// on use of certain flex features (like REJECT or yymore()).
yy_state_type yy_last_accepting_state;
char *yy_last_accepting_cpos;
yy_state_type *yy_state_buf;
yy_state_type *yy_state_ptr;
char *yy_full_match;
int *yy_full_state;
int yy_full_lp;
int yy_lp;
int yy_looking_for_trail_begin;
int yy_more_flag;
int yy_more_len;
int yy_more_offset;
int yy_prev_more_offset;
};
}
#endif // yyFlexLexer || ! yyFlexLexerOnce

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More