plugins/checkpoint: add checkpoint plugin
The checkpoint plugin watches for writes on the given symbol and logs the written value and the simulation time to a given output file. Additionally, a SHA1 hash is computed over all memory locations between given start and stop symbols. On x86, virtual memory is disabled while computing the checkpoint hash. This means the checkpoint plugin in checksumming over physical, not virtual, address ranges! This can result to unexpected behaviour if virtual memory is not used for identity paging. To save checkpoint information to a file, use the Checkpoint constructor with a given checkpoint symbol and add the plugin to the experiment (flow). To check checkpoints against an existing file, use the constructor without memory symbol and do not add the plugin to the experiment. Instead, define a memory listener "manually" and call the check() function. This approach was taken as the simplest form of cooperation between experiment and plugins. For SHA1 calculation, C code from RFC 3174 is used to prevent depending on another external library. However, this may not be the fastest or best code for the task. TEMPORARY HACK/WORKAROUND: Since dOSEK uses the highest bit (31) of some pointers for parity and the checksum plugin reads these (stack) pointers to determine checksum regions, the plugin currently DISCARDS BIT 31 of pointers used as dynamic region limits. This will be replaced in the future by a callback mechanism, which lets the experiment specify the regions to checksum (called at each checkpoint). Change-Id: I176eccc34b582bbf13e52b6943191dd20258acc5
This commit is contained in:
committed by
Christian Dietrich
parent
0426970dff
commit
bdfacbe605
11
src/plugins/checkpoint/CMakeLists.txt
Normal file
11
src/plugins/checkpoint/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
set(PLUGIN_NAME checkpoint)
|
||||
|
||||
set(MY_PLUGIN_SRCS
|
||||
Checkpoint.cc
|
||||
Checkpoint.hpp
|
||||
sha1.c
|
||||
)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
## Build library
|
||||
add_library(fail-${PLUGIN_NAME} ${MY_PLUGIN_SRCS})
|
||||
230
src/plugins/checkpoint/Checkpoint.cc
Normal file
230
src/plugins/checkpoint/Checkpoint.cc
Normal file
@ -0,0 +1,230 @@
|
||||
#include "Checkpoint.hpp"
|
||||
#include "sal/Listener.hpp"
|
||||
#include "sal/Memory.hpp"
|
||||
#include "sha1.h"
|
||||
#include <cstring>
|
||||
#include "sal/bochs/BochsCPU.hpp"
|
||||
#include "sal/SALConfig.hpp"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace fail;
|
||||
|
||||
bool Checkpoint::run()
|
||||
{
|
||||
assert(!m_checking && "FATAL: Checkpoint plugin must not be added to simulation in checking mode");
|
||||
|
||||
// log information
|
||||
m_log << "Checkpoint Logger started." << std::endl;
|
||||
m_log << "Triggering on: " << m_symbol << std::endl;
|
||||
m_log << "Writing output to: " << m_file << std::endl;
|
||||
|
||||
/*
|
||||
std::vector<address_range>::const_iterator it = m_check_ranges.begin();
|
||||
for( ; it != m_check_ranges.end(); ++it) {
|
||||
m_log << "Checksumming: " <<
|
||||
<< ((it->first.second) ? "*" : "")
|
||||
<< "0x" << std::hex << it->first.first
|
||||
<< " - " <<
|
||||
<< (it->second.second) ? "*" : ""
|
||||
<< "0x" << std::hex << it->second.first
|
||||
<< std::endl;
|
||||
}
|
||||
*/
|
||||
|
||||
if (!m_ostream.is_open()) {
|
||||
m_log << "No output file." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// listen for memory writes and save checkpoints
|
||||
MemWriteListener ev_mem(m_symbol.getAddress());
|
||||
while (true) {
|
||||
simulator.addListenerAndResume(&ev_mem);
|
||||
|
||||
save_checkpoint(ev_mem.getTriggerInstructionPointer());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
address_t Checkpoint::resolve_address(const indirectable_address_t &addr) {
|
||||
if(addr.second) {
|
||||
const address_t paddr = addr.first;
|
||||
address_t value = 0;
|
||||
|
||||
MemoryManager& mm = simulator.getMemoryManager();
|
||||
|
||||
if(mm.isMapped(paddr) && mm.isMapped(paddr+1) && mm.isMapped(paddr+2) && mm.isMapped(paddr+3)) {
|
||||
simulator.getMemoryManager().getBytes(paddr, 4, &value);
|
||||
}
|
||||
|
||||
// HACK/WORKAROUND for dOSEK, which uses bit 31 for parity!
|
||||
// This fixes checkpoint ranges for dOSEK, but breaks other systems *if*
|
||||
// addresses with bit 31 set are used as the limit for checkpoint regions
|
||||
return value & ~(1<<31);
|
||||
} else {
|
||||
return addr.first;
|
||||
}
|
||||
}
|
||||
|
||||
void Checkpoint::checksum(uint8_t (&Message_Digest)[20])
|
||||
{
|
||||
SHA1Context sha;
|
||||
int err;
|
||||
|
||||
// prepare SHA1 hash
|
||||
err = SHA1Reset(&sha);
|
||||
assert(err == 0);
|
||||
|
||||
MemoryManager& mm = simulator.getMemoryManager();
|
||||
|
||||
// disable paging on x86
|
||||
#ifdef BUILD_X86
|
||||
const Register *reg_cr0 = simulator.getCPU(0).getRegister(RID_CR0);
|
||||
uint32_t cr0 = simulator.getCPU(0).getRegisterContent(reg_cr0);
|
||||
simulator.getCPU(0).setRegisterContent(reg_cr0, cr0 & ~(1<<31));
|
||||
#endif
|
||||
|
||||
// iterate memory regions
|
||||
std::vector<address_range>::const_iterator it = m_check_ranges.begin();
|
||||
for( ; it != m_check_ranges.end(); ++it) {
|
||||
fail::address_t start = resolve_address(it->first);
|
||||
fail::address_t end = resolve_address(it->second);
|
||||
|
||||
if((start == 0) || (end == 0)) {
|
||||
m_log << std::hex << "invalid checksum range pointer" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
//m_log << std::hex << "checksumming 0x" << start << " - 0x" << end << std::endl;
|
||||
|
||||
for(fail::address_t addr = start; addr < end; addr++) {
|
||||
if(mm.isMapped(addr)) {
|
||||
// read byte
|
||||
uint8_t data = mm.getByte(addr);
|
||||
// add to hash
|
||||
err = SHA1Input(&sha, &data, 1);
|
||||
} else {
|
||||
err = SHA1Input(&sha, (uint8_t*) &addr, 4);
|
||||
}
|
||||
|
||||
assert(err == 0);
|
||||
}
|
||||
}
|
||||
|
||||
// restore paging on x86
|
||||
#ifdef BUILD_X86
|
||||
simulator.getCPU(0).setRegisterContent(reg_cr0, cr0);
|
||||
#endif
|
||||
|
||||
// complete hash
|
||||
err = SHA1Result(&sha, Message_Digest);
|
||||
assert(err == 0);
|
||||
}
|
||||
|
||||
void Checkpoint::checkpoint(const fail::ElfSymbol symbol,
|
||||
uint32_t &value,
|
||||
fail::simtime_t &simtime,
|
||||
std::string &digest_str)
|
||||
{
|
||||
// increment checkpoint count
|
||||
m_count++;
|
||||
|
||||
// timestamp
|
||||
simtime = simulator.getTimerTicks();
|
||||
|
||||
// written value
|
||||
address_t addr = symbol.getAddress();
|
||||
MemoryManager& mm = simulator.getMemoryManager();
|
||||
if(mm.isMapped(addr) && mm.isMapped(addr+1) && mm.isMapped(addr+2) && mm.isMapped(addr+3)) {
|
||||
mm.getBytes(symbol.getAddress(), symbol.getSize(), &value);
|
||||
} else {
|
||||
value = 0xDEADBEEF; // TODO: invalid value?
|
||||
}
|
||||
|
||||
// checksum
|
||||
uint8_t digest[20];
|
||||
checksum(digest);
|
||||
|
||||
// checksum to string
|
||||
std::stringstream s;
|
||||
s.fill('0');
|
||||
for ( size_t i = 0 ; i < 20 ; ++i )
|
||||
s << std::setw(2) << std::hex <<(unsigned short)digest[i];
|
||||
digest_str = s.str();
|
||||
}
|
||||
|
||||
void Checkpoint::save_checkpoint(fail::address_t ip)
|
||||
{
|
||||
uint32_t value;
|
||||
fail::simtime_t simtime;
|
||||
std::string digest;
|
||||
|
||||
// get checkpoint info
|
||||
checkpoint(m_symbol, value, simtime, digest);
|
||||
|
||||
// log checkpoint
|
||||
m_log << std::dec << "Checkpoint " << m_count << " @ " << simtime << std::endl;
|
||||
|
||||
// write checkpoint
|
||||
if (m_ostream.is_open()) {
|
||||
m_ostream << std::hex << ip << "\t" << std::dec << simtime << "\t" << value << "\t" << digest << std::endl;
|
||||
} else {
|
||||
m_log << "Output error" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Checkpoint::check_result Checkpoint::check(const fail::ElfSymbol symbol, fail::address_t ip)
|
||||
{
|
||||
uint32_t value;
|
||||
fail::simtime_t simtime;
|
||||
std::string digest;
|
||||
|
||||
address_t golden_ip;
|
||||
uint32_t golden_timestamp;
|
||||
uint32_t golden_value;
|
||||
char golden_digest_hex[41];
|
||||
|
||||
assert(m_checking && "FATAL: Checkpoint plugin cannot check in tracing mode");
|
||||
|
||||
// get checkpoint info
|
||||
checkpoint(symbol, value, simtime, digest);
|
||||
|
||||
// check with log
|
||||
if (!m_istream.is_open()) {
|
||||
m_log << "Input file not open!" << std::endl;
|
||||
return INVALID;
|
||||
}
|
||||
if (m_istream.eof()) {
|
||||
m_log << "Checkpoint after last golden checkpoint!" << std::endl;
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
// read golden values
|
||||
m_istream >> std::hex >> golden_ip;
|
||||
m_istream >> std::dec >> golden_timestamp;
|
||||
m_istream >> std::dec >> golden_value;
|
||||
m_istream.width(41);
|
||||
m_istream >> golden_digest_hex;
|
||||
std::string golden_digest = golden_digest_hex;
|
||||
|
||||
|
||||
//bool same_timestamp = simtime == golden_timestamp);
|
||||
bool same_ip = ip == golden_ip;
|
||||
bool same_value = value == golden_value;
|
||||
bool same_digest = digest == golden_digest;
|
||||
|
||||
if (!same_ip || !same_value || !same_digest) {
|
||||
// log
|
||||
m_log << "GOLDEN:" << std::hex << golden_ip << "\t" << std::dec << golden_timestamp << "\t" << golden_value << "\t" << golden_digest << std::endl;
|
||||
m_log << "TEST: " << std::hex << ip << "\t" << std::dec << simtime << "\t" << value << "\t" << digest << std::endl;
|
||||
}
|
||||
|
||||
|
||||
if(!same_value) return DIFFERENT_VALUE;
|
||||
if(!same_ip) return DIFFERENT_IP;
|
||||
if(!same_digest) return DIFFERENT_DIGEST;
|
||||
|
||||
return IDENTICAL;
|
||||
}
|
||||
117
src/plugins/checkpoint/Checkpoint.hpp
Normal file
117
src/plugins/checkpoint/Checkpoint.hpp
Normal file
@ -0,0 +1,117 @@
|
||||
#ifndef __Checkpoint_HPP__
|
||||
#define __Checkpoint_HPP__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <unistd.h>
|
||||
#include "efw/ExperimentFlow.hpp"
|
||||
#include "config/FailConfig.hpp"
|
||||
#include "util/Logger.hpp"
|
||||
#include <fstream>
|
||||
#include "util/ElfReader.hpp"
|
||||
|
||||
/**
|
||||
* @class Checkpoint
|
||||
* @brief Listens to a memory location and outputs instruction pointer, written value,
|
||||
* timestamp and SHA1 hash of memory regions to file on each write access from SUT
|
||||
*/
|
||||
class Checkpoint : public fail::ExperimentFlow
|
||||
{
|
||||
public:
|
||||
typedef std::pair<fail::address_t,bool> indirectable_address_t; //!< fixed address or pointer to address
|
||||
typedef std::pair<indirectable_address_t,indirectable_address_t> address_range; //!< contiguous memory region
|
||||
typedef std::vector<address_range> range_vector; //!< vector of memory regions
|
||||
|
||||
enum check_result {
|
||||
IDENTICAL,
|
||||
DIFFERENT_IP,
|
||||
DIFFERENT_VALUE,
|
||||
DIFFERENT_DIGEST,
|
||||
INVALID
|
||||
};
|
||||
|
||||
private:
|
||||
const fail::ElfSymbol m_symbol; //!< target memory symbol triggering checkpoints
|
||||
const range_vector m_check_ranges; //!< address ranges to checksum
|
||||
const bool m_checking; //!< checking mode (when false: tracing mode)
|
||||
std::string m_file; //!< the input/output filename
|
||||
fail::Logger m_log; //!< debug output
|
||||
std::ofstream m_ostream; //!< outputfile stream
|
||||
std::ifstream m_istream; //!< inputfile stream
|
||||
unsigned m_count;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct Checkpoint Logger in tracing (output) mode.
|
||||
*
|
||||
* @param symbol The global memory address the plugin listens to
|
||||
* @param check_ranges Address ranges which are included in the saved checksum
|
||||
* @param outputfile The path to the file to write the checkpoints
|
||||
*/
|
||||
Checkpoint(const fail::ElfSymbol & symbol,
|
||||
const std::vector<address_range> check_ranges,
|
||||
const std::string& outputfile) :
|
||||
m_symbol(symbol), m_check_ranges(check_ranges), m_checking(false),
|
||||
m_file(outputfile) , m_log("CPLogger", false), m_count(0)
|
||||
{
|
||||
m_ostream.open(m_file.c_str() );
|
||||
if (!m_ostream.is_open()) {
|
||||
m_log << "Could not open " << m_file.c_str() << " for writing." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct Checkpoint Logger in checking (input) mode.
|
||||
*
|
||||
* @param symbol The global memory address the plugin listens to
|
||||
* @param check_ranges Address ranges which are compared to the saved checksum
|
||||
* @param inputfile The path to the file to read in checkpoints
|
||||
*/
|
||||
Checkpoint(const std::vector<address_range> check_ranges,
|
||||
const std::string& inputfile) :
|
||||
m_check_ranges(check_ranges), m_checking(true), m_file(inputfile),
|
||||
m_log("CPLogger", false), m_count(0)
|
||||
{
|
||||
m_istream.open(m_file.c_str() );
|
||||
if (!m_istream.is_open()) {
|
||||
m_log << "Could not open " << m_file.c_str() << " for reading." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//! How many checkpoints have been triggered so far
|
||||
unsigned getCount() const {
|
||||
return m_count;
|
||||
}
|
||||
|
||||
//! Start plugin control flow for tracing mode. Do not call in checking mode!
|
||||
bool run();
|
||||
|
||||
/**
|
||||
* Perform a check against saved checkpoints. Call this method in experiment when
|
||||
* a MemWriteBreakpoint on symbol triggers.
|
||||
*
|
||||
* @param symbol (memory) symbol which triggered checkpoint
|
||||
* @param ip instruction pointer which triggered checkpoint
|
||||
* @return check result
|
||||
*/
|
||||
check_result check(const fail::ElfSymbol symbol, fail::address_t ip);
|
||||
|
||||
private:
|
||||
//! calulate checksum over memory regions
|
||||
void checksum(uint8_t (&Message_Digest)[20]);
|
||||
|
||||
//! extract checkpoint information from simulation
|
||||
void checkpoint(const fail::ElfSymbol symbol,
|
||||
uint32_t &value,
|
||||
fail::simtime_t &simtime,
|
||||
std::string &digest_str);
|
||||
|
||||
//! save checkpoint to file
|
||||
void save_checkpoint(fail::address_t ip);
|
||||
|
||||
//! get value of indirectable_address_t
|
||||
fail::address_t resolve_address(const indirectable_address_t &addr);
|
||||
};
|
||||
|
||||
#endif // __Checkpoint_HPP__
|
||||
392
src/plugins/checkpoint/sha1.c
Normal file
392
src/plugins/checkpoint/sha1.c
Normal file
@ -0,0 +1,392 @@
|
||||
/*
|
||||
* sha1.c
|
||||
*
|
||||
* Copyright (C) The Internet Society (2001). All Rights Reserved.
|
||||
* This file is taken from RFC3174.
|
||||
*
|
||||
* Description:
|
||||
* This file implements the Secure Hashing Algorithm 1 as
|
||||
* defined in FIPS PUB 180-1 published April 17, 1995.
|
||||
*
|
||||
* The SHA-1, produces a 160-bit message digest for a given
|
||||
* data stream. It should take about 2**n steps to find a
|
||||
* message with the same digest as a given message and
|
||||
* 2**(n/2) to find any two messages with the same digest,
|
||||
* when n is the digest size in bits. Therefore, this
|
||||
* algorithm can serve as a means of providing a
|
||||
* "fingerprint" for a message.
|
||||
*
|
||||
* Portability Issues:
|
||||
* SHA-1 is defined in terms of 32-bit "words". This code
|
||||
* uses <stdint.h> (included via "sha1.h" to define 32 and 8
|
||||
* bit unsigned integer types. If your C compiler does not
|
||||
* support 32 bit unsigned integers, this code is not
|
||||
* appropriate.
|
||||
*
|
||||
* Caveats:
|
||||
* SHA-1 is designed to work with messages less than 2^64 bits
|
||||
* long. Although SHA-1 allows a message digest to be generated
|
||||
* for messages of any number of bits less than 2^64, this
|
||||
* implementation only works with messages with a length that is
|
||||
* a multiple of the size of an 8-bit character.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
/*
|
||||
* Define the SHA1 circular left shift macro
|
||||
*/
|
||||
#define SHA1CircularShift(bits,word) \
|
||||
(((word) << (bits)) | ((word) >> (32-(bits))))
|
||||
|
||||
/* Local Function Prototyptes */
|
||||
void SHA1PadMessage(SHA1Context *);
|
||||
void SHA1ProcessMessageBlock(SHA1Context *);
|
||||
|
||||
/*
|
||||
* SHA1Reset
|
||||
*
|
||||
* Description:
|
||||
* This function will initialize the SHA1Context in preparation
|
||||
* for computing a new SHA1 message digest.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to reset.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int SHA1Reset(SHA1Context *context)
|
||||
{
|
||||
if (!context)
|
||||
{
|
||||
return shaNull;
|
||||
}
|
||||
|
||||
context->Length_Low = 0;
|
||||
context->Length_High = 0;
|
||||
context->Message_Block_Index = 0;
|
||||
|
||||
context->Intermediate_Hash[0] = 0x67452301;
|
||||
context->Intermediate_Hash[1] = 0xEFCDAB89;
|
||||
context->Intermediate_Hash[2] = 0x98BADCFE;
|
||||
context->Intermediate_Hash[3] = 0x10325476;
|
||||
context->Intermediate_Hash[4] = 0xC3D2E1F0;
|
||||
|
||||
context->Computed = 0;
|
||||
context->Corrupted = 0;
|
||||
|
||||
return shaSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1Result
|
||||
*
|
||||
* Description:
|
||||
* This function will return the 160-bit message digest into the
|
||||
* Message_Digest array provided by the caller.
|
||||
* NOTE: The first octet of hash is stored in the 0th element,
|
||||
* the last octet of hash in the 19th element.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to use to calculate the SHA-1 hash.
|
||||
* Message_Digest: [out]
|
||||
* Where the digest is returned.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int SHA1Result( SHA1Context *context,
|
||||
uint8_t Message_Digest[SHA1HashSize])
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!context || !Message_Digest)
|
||||
{
|
||||
return shaNull;
|
||||
}
|
||||
|
||||
if (context->Corrupted)
|
||||
{
|
||||
return context->Corrupted;
|
||||
}
|
||||
|
||||
if (!context->Computed)
|
||||
{
|
||||
SHA1PadMessage(context);
|
||||
for(i=0; i<64; ++i)
|
||||
{
|
||||
/* message may be sensitive, clear it out */
|
||||
context->Message_Block[i] = 0;
|
||||
}
|
||||
context->Length_Low = 0; /* and clear length */
|
||||
context->Length_High = 0;
|
||||
context->Computed = 1;
|
||||
|
||||
}
|
||||
|
||||
for(i = 0; i < SHA1HashSize; ++i)
|
||||
{
|
||||
Message_Digest[i] = context->Intermediate_Hash[i>>2]
|
||||
>> 8 * ( 3 - ( i & 0x03 ) );
|
||||
}
|
||||
|
||||
return shaSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1Input
|
||||
*
|
||||
* Description:
|
||||
* This function accepts an array of octets as the next portion
|
||||
* of the message.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The SHA context to update
|
||||
* message_array: [in]
|
||||
* An array of characters representing the next portion of
|
||||
* the message.
|
||||
* length: [in]
|
||||
* The length of the message in message_array
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int SHA1Input( SHA1Context *context,
|
||||
const uint8_t *message_array,
|
||||
unsigned length)
|
||||
{
|
||||
if (!length)
|
||||
{
|
||||
return shaSuccess;
|
||||
}
|
||||
|
||||
if (!context || !message_array)
|
||||
{
|
||||
return shaNull;
|
||||
}
|
||||
|
||||
if (context->Computed)
|
||||
{
|
||||
context->Corrupted = shaStateError;
|
||||
|
||||
return shaStateError;
|
||||
}
|
||||
|
||||
if (context->Corrupted)
|
||||
{
|
||||
return context->Corrupted;
|
||||
}
|
||||
while(length-- && !context->Corrupted)
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] =
|
||||
(*message_array & 0xFF);
|
||||
|
||||
context->Length_Low += 8;
|
||||
if (context->Length_Low == 0)
|
||||
{
|
||||
context->Length_High++;
|
||||
if (context->Length_High == 0)
|
||||
{
|
||||
/* Message is too long */
|
||||
context->Corrupted = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->Message_Block_Index == 64)
|
||||
{
|
||||
SHA1ProcessMessageBlock(context);
|
||||
}
|
||||
|
||||
message_array++;
|
||||
}
|
||||
|
||||
return shaSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1ProcessMessageBlock
|
||||
*
|
||||
* Description:
|
||||
* This function will process the next 512 bits of the message
|
||||
* stored in the Message_Block array.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
|
||||
* Many of the variable names in this code, especially the
|
||||
* single character names, were used because those were the
|
||||
* names used in the publication.
|
||||
*
|
||||
*
|
||||
*/
|
||||
void SHA1ProcessMessageBlock(SHA1Context *context)
|
||||
{
|
||||
const uint32_t K[] = { /* Constants defined in SHA-1 */
|
||||
0x5A827999,
|
||||
0x6ED9EBA1,
|
||||
0x8F1BBCDC,
|
||||
0xCA62C1D6
|
||||
};
|
||||
int t; /* Loop counter */
|
||||
uint32_t temp; /* Temporary word value */
|
||||
uint32_t W[80]; /* Word sequence */
|
||||
uint32_t A, B, C, D, E; /* Word buffers */
|
||||
|
||||
/*
|
||||
* Initialize the first 16 words in the array W
|
||||
*/
|
||||
for(t = 0; t < 16; t++)
|
||||
{
|
||||
W[t] = context->Message_Block[t * 4] << 24;
|
||||
W[t] |= context->Message_Block[t * 4 + 1] << 16;
|
||||
W[t] |= context->Message_Block[t * 4 + 2] << 8;
|
||||
W[t] |= context->Message_Block[t * 4 + 3];
|
||||
}
|
||||
|
||||
for(t = 16; t < 80; t++)
|
||||
{
|
||||
W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
|
||||
}
|
||||
|
||||
A = context->Intermediate_Hash[0];
|
||||
B = context->Intermediate_Hash[1];
|
||||
C = context->Intermediate_Hash[2];
|
||||
D = context->Intermediate_Hash[3];
|
||||
E = context->Intermediate_Hash[4];
|
||||
|
||||
for(t = 0; t < 20; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) +
|
||||
((B & C) | ((~B) & D)) + E + W[t] + K[0];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for(t = 20; t < 40; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for(t = 40; t < 60; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) +
|
||||
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for(t = 60; t < 80; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
context->Intermediate_Hash[0] += A;
|
||||
context->Intermediate_Hash[1] += B;
|
||||
context->Intermediate_Hash[2] += C;
|
||||
context->Intermediate_Hash[3] += D;
|
||||
context->Intermediate_Hash[4] += E;
|
||||
|
||||
context->Message_Block_Index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1PadMessage
|
||||
*
|
||||
|
||||
* Description:
|
||||
* According to the standard, the message must be padded to an even
|
||||
* 512 bits. The first padding bit must be a '1'. The last 64
|
||||
* bits represent the length of the original message. All bits in
|
||||
* between should be 0. This function will pad the message
|
||||
* according to those rules by filling the Message_Block array
|
||||
* accordingly. It will also call the ProcessMessageBlock function
|
||||
* provided appropriately. When it returns, it can be assumed that
|
||||
* the message digest has been computed.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to pad
|
||||
* ProcessMessageBlock: [in]
|
||||
* The appropriate SHA*ProcessMessageBlock function
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
*/
|
||||
|
||||
void SHA1PadMessage(SHA1Context *context)
|
||||
{
|
||||
/*
|
||||
* Check to see if the current message block is too small to hold
|
||||
* the initial padding bits and length. If so, we will pad the
|
||||
* block, process it, and then continue padding into a second
|
||||
* block.
|
||||
*/
|
||||
if (context->Message_Block_Index > 55)
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] = 0x80;
|
||||
while(context->Message_Block_Index < 64)
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] = 0;
|
||||
}
|
||||
|
||||
SHA1ProcessMessageBlock(context);
|
||||
|
||||
while(context->Message_Block_Index < 56)
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] = 0x80;
|
||||
while(context->Message_Block_Index < 56)
|
||||
{
|
||||
|
||||
context->Message_Block[context->Message_Block_Index++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the message length as the last 8 octets
|
||||
*/
|
||||
context->Message_Block[56] = context->Length_High >> 24;
|
||||
context->Message_Block[57] = context->Length_High >> 16;
|
||||
context->Message_Block[58] = context->Length_High >> 8;
|
||||
context->Message_Block[59] = context->Length_High;
|
||||
context->Message_Block[60] = context->Length_Low >> 24;
|
||||
context->Message_Block[61] = context->Length_Low >> 16;
|
||||
context->Message_Block[62] = context->Length_Low >> 8;
|
||||
context->Message_Block[63] = context->Length_Low;
|
||||
|
||||
SHA1ProcessMessageBlock(context);
|
||||
}
|
||||
72
src/plugins/checkpoint/sha1.h
Normal file
72
src/plugins/checkpoint/sha1.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* sha1.h
|
||||
*
|
||||
* Description:
|
||||
* This is the header file for code which implements the Secure
|
||||
* Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
|
||||
* April 17, 1995.
|
||||
*
|
||||
* Many of the variable names in this code, especially the
|
||||
* single character names, were used because those were the names
|
||||
* used in the publication.
|
||||
*
|
||||
* Please read the file sha1.c for more information.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SHA1_H_
|
||||
#define _SHA1_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef _SHA_enum_
|
||||
#define _SHA_enum_
|
||||
enum
|
||||
{
|
||||
shaSuccess = 0,
|
||||
shaNull, /* Null pointer parameter */
|
||||
shaInputTooLong, /* input data too long */
|
||||
shaStateError /* called Input after Result */
|
||||
};
|
||||
#endif
|
||||
#define SHA1HashSize 20
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-1
|
||||
* hashing operation
|
||||
*/
|
||||
typedef struct SHA1Context
|
||||
{
|
||||
uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
|
||||
|
||||
uint32_t Length_Low; /* Message length in bits */
|
||||
uint32_t Length_High; /* Message length in bits */
|
||||
|
||||
/* Index into message block array */
|
||||
int_least16_t Message_Block_Index;
|
||||
uint8_t Message_Block[64]; /* 512-bit message blocks */
|
||||
|
||||
int Computed; /* Is the digest computed? */
|
||||
int Corrupted; /* Is the message digest corrupted? */
|
||||
} SHA1Context;
|
||||
|
||||
/*
|
||||
* Function Prototypes
|
||||
*/
|
||||
|
||||
int SHA1Reset( SHA1Context *);
|
||||
int SHA1Input( SHA1Context *,
|
||||
const uint8_t *,
|
||||
unsigned int);
|
||||
int SHA1Result( SHA1Context *,
|
||||
uint8_t Message_Digest[SHA1HashSize]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user