* Merge libwiisave with libzelda

This commit is contained in:
Antidote 2013-02-15 20:22:16 -08:00
parent 1e2065b352
commit 24f6a1715a
26 changed files with 3608 additions and 5 deletions

View File

@ -132,7 +132,7 @@ public:
* \param str The string to write to the buffer
*/
void writeUnicode(const std::string& str);
private:
protected:
Int8 readByte();
Int8* readBytes(Int64);
bool isOpenForReading();

82
include/WiiBanner.h Normal file
View File

@ -0,0 +1,82 @@
#ifndef WIIBANNER_H
#define WIIBANNER_H
#include <vector>
#include <string>
#include <Types.hpp>
class WiiImage
{
public:
WiiImage();
WiiImage(Uint32 width, Uint32 height, Uint8* data);
~WiiImage();
void setWidth(const Uint32 width);
Uint32 width() const;
void setHeight(const Uint32 height);
Uint32 height() const;
void setData(const Uint8* data);
Uint8* data();
Uint8* toRGBA32();
private:
Uint32 m_width;
Uint32 m_height;
Uint8* m_data;
};
class WiiBanner
{
public:
enum { NoCopy = 0x00000001, Bounce = 0x00000010, NoCopyBounce = NoCopy | Bounce };
WiiBanner();
WiiBanner(Uint32 gameId, const std::string& title, const std::string& subtitle, WiiImage* m_banner, std::vector<WiiImage*> icons);
virtual ~WiiBanner();
void setGameID(Uint64 id);
Uint64 gameID() const;
void setBannerImage(WiiImage* banner);
WiiImage* bannerImage() const;
void setBannerSize(Uint32 size);
Uint32 bannerSize() const;
void setTitle(const std::string& title);
std::string title() const;
void setSubtitle(const std::string& subtitle);
std::string subtitle() const;
void addIcon(WiiImage* icon);
void setIcon(Uint32 id, WiiImage* icon);
WiiImage* getIcon(Uint32 id) const;
std::vector<WiiImage*> icons() const;
void setAnimationSpeed(Uint16 animSpeed);
Uint16 animationSpeed() const;
void setPermissions(Uint8 permissions);
Uint8 permissions() const;
void setFlags(Uint32 flags);
Uint32 flags() const;
protected:
private:
Uint64 m_gameId;
WiiImage* m_banner;
Uint32 m_animSpeed;
Uint8 m_permissions;
Uint32 m_flags;
Uint32 m_bannerSize;
std::vector<WiiImage*> m_icons;
std::string m_title;
std::string m_subtitle;
};
#endif // WIIBANNER_H

82
include/WiiBanner.hpp Normal file
View File

@ -0,0 +1,82 @@
#ifndef WIIBANNER_H
#define WIIBANNER_H
#include <vector>
#include <string>
#include <Types.hpp>
class WiiImage
{
public:
WiiImage();
WiiImage(Uint32 width, Uint32 height, Uint8* data);
~WiiImage();
void setWidth(const Uint32 width);
Uint32 width() const;
void setHeight(const Uint32 height);
Uint32 height() const;
void setData(const Uint8* data);
Uint8* data();
Uint8* toRGBA32();
private:
Uint32 m_width;
Uint32 m_height;
Uint8* m_data;
};
class WiiBanner
{
public:
enum { NoCopy = 0x00000001, Bounce = 0x00000010, NoCopyBounce = NoCopy | Bounce };
WiiBanner();
WiiBanner(Uint32 gameId, const std::string& title, const std::string& subtitle, WiiImage* m_banner, std::vector<WiiImage*> icons);
virtual ~WiiBanner();
void setGameID(Uint64 id);
Uint64 gameID() const;
void setBannerImage(WiiImage* banner);
WiiImage* bannerImage() const;
void setBannerSize(Uint32 size);
Uint32 bannerSize() const;
void setTitle(const std::string& title);
std::string title() const;
void setSubtitle(const std::string& subtitle);
std::string subtitle() const;
void addIcon(WiiImage* icon);
void setIcon(Uint32 id, WiiImage* icon);
WiiImage* getIcon(Uint32 id) const;
std::vector<WiiImage*> icons() const;
void setAnimationSpeed(Uint16 animSpeed);
Uint16 animationSpeed() const;
void setPermissions(Uint8 permissions);
Uint8 permissions() const;
void setFlags(Uint32 flags);
Uint32 flags() const;
protected:
private:
Uint64 m_gameId;
WiiImage* m_banner;
Uint32 m_animSpeed;
Uint8 m_permissions;
Uint32 m_flags;
Uint32 m_bannerSize;
std::vector<WiiImage*> m_icons;
std::string m_title;
std::string m_subtitle;
};
#endif // WIIBANNER_H

68
include/WiiFile.h Normal file
View File

@ -0,0 +1,68 @@
#ifndef WIIFILE_H
#define WIIFILE_H
#include <string>
#include <map>
#include <Types.hpp>
class WiiFile
{
public:
enum Permission
{
OtherRead = 0x01,
OtherWrite = 0x02,
GroupRead = 0x04,
GroupWrite = 0x08,
OwnerRead = 0x10,
OwnerWrite = 0x20,
// Mask values;
OtherRW = (OtherRead|OtherWrite),
GroupRW = (GroupRead|GroupWrite),
OwnerRW = (OwnerRead|OwnerWrite)
};
enum Type
{
File = 0x01,
Directory = 0x02
};
WiiFile();
WiiFile(const std::string& filename);
WiiFile(const std::string& filename, Uint8 permissions, const Uint8* data, Uint32 length);
virtual ~WiiFile();
void setFilename(const std::string& filename);
std::string filename() const;
void setData(const Uint8* data);
Uint8* data() const;
void setLength(const int len);
int length() const;
void setPermissions(const Uint8 permissions);
Uint8 permissions() const;
void setAttributes(const Uint8 attr);
Uint8 attributes() const;
void setType(Type type);
Type type() const;
bool isDirectory() const;
bool isFile() const;
protected:
private:
Uint8 m_permissions;
Uint8 m_attributes;
Type m_type;
std::string m_filename;
int m_fileLen;
Uint8* m_fileData;
};
#endif // WIIFILE_H

68
include/WiiFile.hpp Normal file
View File

@ -0,0 +1,68 @@
#ifndef WIIFILE_H
#define WIIFILE_H
#include <string>
#include <map>
#include <Types.hpp>
class WiiFile
{
public:
enum Permission
{
OtherRead = 0x01,
OtherWrite = 0x02,
GroupRead = 0x04,
GroupWrite = 0x08,
OwnerRead = 0x10,
OwnerWrite = 0x20,
// Mask values;
OtherRW = (OtherRead|OtherWrite),
GroupRW = (GroupRead|GroupWrite),
OwnerRW = (OwnerRead|OwnerWrite)
};
enum Type
{
File = 0x01,
Directory = 0x02
};
WiiFile();
WiiFile(const std::string& filename);
WiiFile(const std::string& filename, Uint8 permissions, const Uint8* data, Uint32 length);
virtual ~WiiFile();
void setFilename(const std::string& filename);
std::string filename() const;
void setData(const Uint8* data);
Uint8* data() const;
void setLength(const int len);
int length() const;
void setPermissions(const Uint8 permissions);
Uint8 permissions() const;
void setAttributes(const Uint8 attr);
Uint8 attributes() const;
void setType(Type type);
Type type() const;
bool isDirectory() const;
bool isFile() const;
protected:
private:
Uint8 m_permissions;
Uint8 m_attributes;
Type m_type;
std::string m_filename;
int m_fileLen;
Uint8* m_fileData;
};
#endif // WIIFILE_H

47
include/WiiSave.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef WIISAVE_H
#define WIISAVE_H
#include <unordered_map>
#include <string>
#include <Types.hpp>
class WiiFile;
class WiiBanner;
class WiiImage;
class BinaryReader;
class BinaryWriter;
class WiiSave
{
public:
typedef std::unordered_map<std::string, WiiFile*>::const_iterator FileIterator;
WiiSave();
virtual ~WiiSave();
bool saveToFile(const std::string& filepath, Uint8* macAddress, Uint32 ngId, Uint8* ngPriv, Uint8* ngSig, Uint32 ngKeyId);
void addFile(const std::string& filename, WiiFile* file);
WiiFile* getFile(const std::string& filename) const;
std::unordered_map<std::string, WiiFile*>& getFileList();
void setBanner(WiiBanner* banner);
WiiBanner* banner() const;
protected:
private:
void writeBanner();
Uint32 writeFile(WiiFile* file);
void writeImage(WiiImage* image);
void writeCerts(Uint32 filesSize, Uint32 ngId, Uint8* ngPriv, Uint8* ngSig, Uint32 ngKeyId);
std::string readNullTermString();
std::unordered_map<std::string, WiiFile*> m_files;
WiiBanner* m_banner;
BinaryReader* m_reader;
BinaryWriter* m_writer;
};
#endif // WIISAVE_H

37
include/WiiSave.hpp Normal file
View File

@ -0,0 +1,37 @@
#ifndef WIISAVE_H
#define WIISAVE_H
#include <unordered_map>
#include <string>
#include <Types.hpp>
class WiiFile;
class WiiBanner;
class WiiImage;
class BinaryReader;
class BinaryWriter;
class WiiSave
{
public:
typedef std::unordered_map<std::string, WiiFile*>::const_iterator FileIterator;
WiiSave();
virtual ~WiiSave();
void addFile(const std::string& filename, WiiFile* file);
WiiFile* file(const std::string& filename) const;
std::unordered_map<std::string, WiiFile*>& fileList();
void setBanner(WiiBanner* banner);
WiiBanner* banner() const;
protected:
private:
std::unordered_map<std::string, WiiFile*> m_files;
WiiBanner* m_banner;
};
#endif // WIISAVE_H

26
include/WiiSaveReader.hpp Normal file
View File

@ -0,0 +1,26 @@
#ifndef __WII_SAVE_READER_HPP__
#define __WII_SAVE_READER_HPP__
#include <Types.hpp>
#include <utility.hpp>
#include <BinaryReader.hpp>
class WiiSave;
class WiiBanner;
class WiiFile;
class WiiImage;
class WiiSaveReader : public BinaryReader
{
public:
WiiSaveReader(const Uint8*, Uint64);
WiiSaveReader(const std::string&);
WiiSave* readSave();
private:
WiiBanner* readBanner();
WiiFile* readFile();
WiiImage* readImage(Uint32 width, Uint32 height);
void readCerts(Uint32 totalSize);
};
#endif // __WII_SAVE_READER_HPP__

27
include/WiiSaveWriter.hpp Normal file
View File

@ -0,0 +1,27 @@
#ifndef __WII_SAVE_WRITER_HPP__
#define __WII_SAVE_WRITER_HPP__
#include <Types.hpp>
#include <utility.hpp>
#include <BinaryWriter.hpp>
class WiiSave;
class WiiBanner;
class WiiFile;
class WiiImage;
class WiiSaveWriter : public BinaryWriter
{
public:
WiiSaveWriter(const std::string&);
bool writeSave(WiiSave* save, Uint8* macAddress, Uint32 ngId, Uint8* ngPriv, Uint8* ngSig, Uint32 ngKeyId, const std::string& filepath = "");
private:
void writeBanner(WiiBanner* banner);
Uint32 writeFile(WiiFile* file);
void writeImage(WiiImage* image);
void writeCerts(Uint32 filesSize, Uint32 ngId, Uint8* ngPriv, Uint8* ngSig, Uint32 ngKeyId);
};
#endif // __WII_SAVE_WRITER_HPP__

20
include/aes.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef __AES_H_
#define __AES_H_
#include <Types.hpp>
#ifdef __cplusplus
extern "C" {
#endif
void aes_encrypt(Uint8 *iv, const Uint8 *inbuf, Uint8 *outbuf, Uint64 len);
void aes_decrypt(Uint8 *iv, const Uint8 *inbuf, Uint8 *outbuf, Uint64 len);
void aes_set_key(const Uint8 *key );
#ifdef __cplusplus
}
#endif
#endif //__AES_H_

13
include/bn.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef BN_H
#define BN_H
#include <Types.hpp>
int bn_compare(Uint8 *a, Uint8 *b, Uint32 n);
void bn_sub_modulus(Uint8 *a, Uint8 *N, Uint32 n);
void bn_add(Uint8 *d, Uint8 *a, Uint8 *b, Uint8 *N, Uint32 n);
void bn_mul(Uint8 *d, Uint8 *a, Uint8 *b, Uint8 *N, Uint32 n);
void bn_exp(Uint8 *d, Uint8 *a, Uint8 *N, Uint32 n, Uint8 *e, Uint32 en);
void bn_inv(Uint8 *d, Uint8 *a, Uint8 *N, Uint32 n);
#endif // BN_H

10
include/ec.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef EC_H
#define EC_H
#include <Types.hpp>
bool check_ec ( Uint8 *ng, Uint8 *ap, Uint8 *sig, Uint8 *sig_hash );
void make_ec_cert ( Uint8 *cert, Uint8 *sig, char *signer, char *name, Uint8 *priv, Uint32 key_id );
void generate_ecdsa( Uint8 *R, Uint8 *S, Uint8 *k, Uint8 *hash );
#endif // EC_H

241
include/md5.h Normal file
View File

@ -0,0 +1,241 @@
#ifndef MD5_H
#define MD5_H
#ifdef __cplusplus
extern "C"
{
#endif
/* ========================================================================== **
*
* MD5.h
*
* Copyright:
* Copyright (C) 2003-2005 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
*
* $Id: MD5.h,v 0.6 2005/06/08 18:35:59 crh Exp $
*
* Modifications and additions by dimok
*
* -------------------------------------------------------------------------- **
*
* Description:
* Implements the MD5 hash algorithm, as described in RFC 1321.
*
* -------------------------------------------------------------------------- **
*
* License:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* -------------------------------------------------------------------------- **
*
* Notes:
*
* None of this will make any sense unless you're studying RFC 1321 as you
* read the code.
*
* MD5 is described in RFC 1321.
* The MD*4* algorithm is described in RFC 1320 (that's 1321 - 1).
* MD5 is very similar to MD4, but not quite similar enough to justify
* putting the two into a single module. Besides, I wanted to add a few
* extra functions to this one to expand its usability.
*
* There are three primary motivations for this particular implementation.
* 1) Programmer's pride. I wanted to be able to say I'd done it, and I
* wanted to learn from the experience.
* 2) Portability. I wanted an implementation that I knew to be portable
* to a reasonable number of platforms. In particular, the algorithm is
* designed with little-endian platforms in mind, but I wanted an
* endian-agnostic implementation.
* 3) Compactness. While not an overriding goal, I thought it worth-while
* to see if I could reduce the overall size of the result. This is in
* keeping with my hopes that this library will be suitable for use in
* some embedded environments.
* Beyond that, cleanliness and clarity are always worth pursuing.
*
* As mentioned above, the code really only makes sense if you are familiar
* with the MD5 algorithm or are using RFC 1321 as a guide. This code is
* quirky, however, so you'll want to be reading carefully.
*
* Yeah...most of the comments are cut-and-paste from my MD4 implementation.
*
* -------------------------------------------------------------------------- **
*
* References:
* IETF RFC 1321: The MD5 Message-Digest Algorithm
* Ron Rivest. IETF, April, 1992
*
* ========================================================================== **
*/
/* -------------------------------------------------------------------------- **
* Typedefs:
*/
typedef struct
{
unsigned int len;
unsigned int ABCD[4];
int b_used;
unsigned char block[64];
} auth_md5Ctx;
/* -------------------------------------------------------------------------- **
* Functions:
*/
auth_md5Ctx *auth_md5InitCtx(auth_md5Ctx *ctx);
/* ------------------------------------------------------------------------ **
* Initialize an MD5 context.
*
* Input: ctx - A pointer to the MD5 context structure to be initialized.
* Contexts are typically created thusly:
* ctx = (auth_md5Ctx *)malloc( sizeof(auth_md5Ctx) );
*
* Output: A pointer to the initialized context (same as <ctx>).
*
* Notes: The purpose of the context is to make it possible to generate
* an MD5 Message Digest in stages, rather than having to pass a
* single large block to a single MD5 function. The context
* structure keeps track of various bits of state information.
*
* Once the context is initialized, the blocks of message data
* are passed to the <auth_md5SumCtx()> function. Once the
* final bit of data has been handed to <auth_md5SumCtx()> the
* context can be closed out by calling <auth_md5CloseCtx()>,
* which also calculates the final MD5 result.
*
* Don't forget to free an allocated context structure when
* you've finished using it.
*
* See Also: <auth_md5SumCtx()>, <auth_md5CloseCtx()>
*
* ------------------------------------------------------------------------ **
*/
auth_md5Ctx *auth_md5SumCtx(auth_md5Ctx *ctx, const unsigned char *src, const int len);
/* ------------------------------------------------------------------------ **
* Build an MD5 Message Digest within the given context.
*
* Input: ctx - Pointer to the context in which the MD5 sum is being
* built.
* src - A chunk of source data. This will be used to drive
* the MD5 algorithm.
* len - The number of bytes in <src>.
*
* Output: A pointer to the updated context (same as <ctx>).
*
* See Also: <auth_md5InitCtx()>, <auth_md5CloseCtx()>, <auth_md5Sum()>
*
* ------------------------------------------------------------------------ **
*/
auth_md5Ctx *auth_md5CloseCtx(auth_md5Ctx *ctx, unsigned char *dst);
/* ------------------------------------------------------------------------ **
* Close an MD5 Message Digest context and generate the final MD5 sum.
*
* Input: ctx - Pointer to the context in which the MD5 sum is being
* built.
* dst - A pointer to at least 16 bytes of memory, which will
* receive the finished MD5 sum.
*
* Output: A pointer to the closed context (same as <ctx>).
* You might use this to free a malloc'd context structure. :)
*
* Notes: The context (<ctx>) is returned in an undefined state.
* It must be re-initialized before re-use.
*
* See Also: <auth_md5InitCtx()>, <auth_md5SumCtx()>
*
* ------------------------------------------------------------------------ **
*/
unsigned char * MD5(unsigned char * hash, const unsigned char *src, const int len);
/* ------------------------------------------------------------------------ **
* Compute an MD5 message digest.
*
* Input: dst - Destination buffer into which the result will be written.
* Must be 16 bytes, minimum.
* src - Source data block to be MD5'd.
* len - The length, in bytes, of the source block.
* (Note that the length is given in bytes, not bits.)
*
* Output: A pointer to <dst>, which will contain the calculated 16-byte
* MD5 message digest.
*
* Notes: This function is a shortcut. It takes a single input block.
* For more drawn-out operations, see <auth_md5InitCtx()>.
*
* This function is interface-compatible with the
* <auth_md4Sum()> function in the MD4 module.
*
* The MD5 algorithm is designed to work on data with an
* arbitrary *bit* length. Most implementations, this one
* included, handle the input data in byte-sized chunks.
*
* The MD5 algorithm does much of its work using four-byte
* words, and so can be tuned for speed based on the endian-ness
* of the host. This implementation is intended to be
* endian-neutral, which may make it a teeny bit slower than
* others. ...maybe.
*
* See Also: <auth_md5InitCtx()>
*
* ------------------------------------------------------------------------ **
*/
unsigned char * MD5fromFile(unsigned char *dst, const char *src);
/* ------------------------------------------------------------------------ **
* Compute an MD5 message digest.
*
* Input: dst - Destination buffer into which the result will be written.
* Must be 16 bytes, minimum.
* src - filepath to the file to be MD5'd.
*
* Output: A pointer to <dst>, which will contain the calculated 16-byte
* MD5 message digest.
*
* Notes: This function is a shortcut. It takes a single input block.
* For more drawn-out operations, see <auth_md5InitCtx()>.
*
* This function is interface-compatible with the
* <auth_md4Sum()> function in the MD4 module.
*
* The MD5 algorithm is designed to work on data with an
* arbitrary *bit* length. Most implementations, this one
* included, handle the input data in byte-sized chunks.
*
* The MD5 algorithm does much of its work using four-byte
* words, and so can be tuned for speed based on the endian-ness
* of the host. This implementation is intended to be
* endian-neutral, which may make it a teeny bit slower than
* others. ...maybe.
*
* See Also: <auth_md5InitCtx()>
*
* ------------------------------------------------------------------------ **
*/
const char * MD5ToString(const unsigned char *hash, char *dst);
unsigned char * StringToMD5(const char * hash, unsigned char * dst);
/* ========================================================================== */
#ifdef __cplusplus
}
#endif
#endif /* AUTH_MD5_H */

46
include/sha1.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef _SHA1_H_
#define _SHA1_H_
#include <Types.hpp>
#ifdef __cplusplus
extern "C" {
#endif
/*
* This structure will hold context information for the hashing
* operation
*/
typedef struct SHA1Context
{
unsigned Message_Digest[5]; /* Message Digest (output) */
unsigned Length_Low; /* Message length in bits */
unsigned Length_High; /* Message length in bits */
unsigned char Message_Block[64]; /* 512-bit message blocks */
int Message_Block_Index; /* Index into message block array */
int Computed; /* Is the digest computed? */
int Corrupted; /* Is the message digest corruped? */
} SHA1Context;
/*
* Function Prototypes
*/
void SHA1Reset(SHA1Context *);
int SHA1Result(SHA1Context *);
void SHA1Input( SHA1Context *,
const unsigned char *,
unsigned);
Uint8* getSha1( Uint8 * stuff, Uint32 stuff_size );
#ifdef __cplusplus
}
#endif
#endif

14
libzelda.layout Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_layout_file>
<ActiveTarget name="Release Linux" />
<File name="include/BinaryReader.hpp" open="1" top="0" tabpos="1" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="115" />
</Cursor>
</File>
<File name="include/BinaryWriter.hpp" open="1" top="1" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="4709" topLine="96" />
</Cursor>
</File>
</CodeBlocks_layout_file>

View File

@ -7,6 +7,9 @@ INCLUDEPATH += include
HEADERS += \
include/utility.hpp \
include/utf8.h \
include/utf8/unchecked.h \
include/utf8/core.h \
include/utf8/checked.h \
include/Types.hpp \
include/TextStream.hpp \
include/Stream.hpp \
@ -17,16 +20,36 @@ HEADERS += \
include/Exception.hpp \
include/BinaryWriter.hpp \
include/BinaryReader.hpp \
include/utf8/unchecked.h \
include/utf8/core.h \
include/utf8/checked.h
include/WiiBanner.h \
include/WiiBanner.hpp \
include/WiiFile.h \
include/WiiFile.hpp \
include/WiiSave.h \
include/WiiSave.hpp \
include/WiiSaveReader.hpp \
include/WiiSaveWriter.hpp \
include/aes.h \
include/bn.h \
include/ec.h \
include/md5.h \
include/sha1.h
SOURCES += \
src/utility.cpp \
src/TextStream.cpp \
src/Stream.cpp \
src/BinaryWriter.cpp \
src/BinaryReader.cpp
src/BinaryReader.cpp \
src/WiiBanner.cpp \
src/WiiFile.cpp \
src/WiiSave.cpp \
src/WiiSaveReader.cpp \
src/WiiSaveWriter.cpp \
src/aes.c \
src/bn.cpp \
src/ec.cpp \
src/md5.c \
src/sha1.cpp
system("exec doxygen libzelda.conf")
system("cd doc/latex && make")

165
src/WiiBanner.cpp Normal file
View File

@ -0,0 +1,165 @@
#include "WiiBanner.h"
#include <utility.hpp>
#include <string.h>
WiiImage::WiiImage(Uint32 width, Uint32 height, Uint8* data) :
m_width(width),
m_height(height),
m_data(data)
{
}
WiiImage::~WiiImage()
{
if (m_data)
delete[] m_data;
m_data = NULL;
}
Uint8* WiiImage::data()
{
return m_data;
}
Uint32 WiiImage::width() const
{
return m_width;
}
Uint32 WiiImage::height() const
{
return m_height;
}
WiiBanner::WiiBanner() :
m_gameId(0),
m_banner(NULL),
m_flags(0),
m_bannerSize(0),
m_title(""),
m_subtitle("")
{
}
WiiBanner::WiiBanner(Uint32 gameId, const std::string& title,
const std::string& subtitle, WiiImage* banner, std::vector<WiiImage*> icons) :
m_gameId(gameId),
m_banner(banner),
m_flags(0),
m_bannerSize(0),
m_icons(icons),
m_title(title),
m_subtitle(subtitle)
{
}
WiiBanner::~WiiBanner()
{
delete m_banner;
m_icons.clear();
}
void WiiBanner::setGameID(Uint64 id)
{
m_gameId = id;
}
Uint64 WiiBanner::gameID() const
{
return m_gameId;
}
void WiiBanner::setTitle(const std::string& title)
{
m_title = title;
}
std::string WiiBanner::title() const
{
return m_title;
}
void WiiBanner::setSubtitle(const std::string& subtitle)
{
m_subtitle = subtitle;
}
std::string WiiBanner::subtitle() const
{
return m_subtitle;
}
void WiiBanner::addIcon(WiiImage* icon)
{
m_icons.push_back(icon);
}
void WiiBanner::setIcon(Uint32 id, WiiImage* icon)
{
if (m_icons[id] != NULL)
{
delete m_icons[id];
m_icons[id] = icon;
}
}
WiiImage* WiiBanner::getIcon(Uint32 id) const
{
if (!m_icons[id])
return NULL;
return m_icons[id];
}
std::vector<WiiImage*> WiiBanner::icons() const
{
return m_icons;
}
void WiiBanner::setBannerImage(WiiImage* banner)
{
m_banner = banner;
}
WiiImage* WiiBanner::bannerImage() const
{
return m_banner;
}
void WiiBanner::setAnimationSpeed(Uint16 animSpeed)
{
m_animSpeed = animSpeed;
}
Uint16 WiiBanner::animationSpeed() const
{
return m_animSpeed;
}
void WiiBanner::setPermissions(Uint8 permissions)
{
m_permissions = permissions;
}
Uint8 WiiBanner::permissions() const
{
return m_permissions;
}
void WiiBanner::setBannerSize(Uint32 size)
{
m_bannerSize = size;
}
Uint32 WiiBanner::bannerSize() const
{
return m_bannerSize;
}
void WiiBanner::setFlags(Uint32 flags)
{
m_flags = flags;
}
Uint32 WiiBanner::flags() const
{
return m_flags;
}

115
src/WiiFile.cpp Normal file
View File

@ -0,0 +1,115 @@
#include "WiiFile.h"
WiiFile::WiiFile() :
m_permissions(WiiFile::GroupRW|WiiFile::OtherRW|WiiFile::OwnerRW),
m_attributes(0),
m_type(WiiFile::File),
m_filename(""),
m_fileLen(0),
m_fileData(NULL)
{
//ctor
}
WiiFile::WiiFile(const std::string& filename) :
m_permissions(WiiFile::GroupRW|WiiFile::OtherRW|WiiFile::OwnerRW),
m_attributes(0),
m_type(WiiFile::File),
m_filename(filename),
m_fileLen(0),
m_fileData(NULL)
{
}
WiiFile::WiiFile(const std::string& filename, Uint8 permissions, const Uint8* data, Uint32 length) :
m_permissions(permissions),
m_attributes(0),
m_type(WiiFile::File),
m_filename(filename),
m_fileLen(length),
m_fileData((Uint8*)data)
{
}
WiiFile::~WiiFile()
{
if (m_fileData)
delete[] m_fileData;
}
void WiiFile::setFilename(const std::string& filename)
{
m_filename = filename;
}
std::string WiiFile::filename() const
{
return m_filename;
}
void WiiFile::setPermissions(const Uint8 permissions)
{
m_permissions = (Uint8)permissions;
}
Uint8 WiiFile::permissions() const
{
return m_permissions;
}
void WiiFile::setData(const Uint8* data)
{
if (m_fileData)
{
delete[] m_fileData;
m_fileData = NULL;
}
m_fileData = (Uint8*)data;
}
Uint8* WiiFile::data() const
{
return m_fileData;
}
void WiiFile::setLength(const int len)
{
m_fileLen = (int)len;
}
int WiiFile::length() const
{
return m_fileLen;
}
void WiiFile::setAttributes(const Uint8 attr)
{
m_attributes = attr;
}
Uint8 WiiFile::attributes() const
{
return m_attributes;
}
void WiiFile::setType(WiiFile::Type type)
{
m_type = type;
}
WiiFile::Type WiiFile::type() const
{
return m_type;
}
bool WiiFile::isDirectory() const
{
return (m_type == WiiFile::Directory);
}
bool WiiFile::isFile() const
{
return (m_type == WiiFile::File);
}

66
src/WiiSave.cpp Normal file
View File

@ -0,0 +1,66 @@
#include "WiiSave.h"
#include "WiiFile.h"
#include "WiiBanner.h"
#include "BinaryReader.hpp"
#include "BinaryWriter.hpp"
#include "IOException.hpp"
#include "aes.h"
#include "ec.h"
#include <utility.hpp>
#include "md5.h"
#include "sha1.h"
#include <stdio.h>
#include <vector>
#include <string.h>
#include <sys/stat.h>
#include <iostream>
#include <iomanip>
WiiSave::WiiSave()
: m_banner(NULL)
{
}
WiiSave::~WiiSave()
{
m_files.clear();
delete m_banner;
m_banner = NULL;
}
void WiiSave::addFile(const std::string& filepath, WiiFile* file)
{
m_files[filepath] = file;
}
WiiFile* WiiSave::file(const std::string& filepath) const
{
std::unordered_map<std::string, WiiFile*>::const_iterator iter = m_files.begin();
for (;iter != m_files.end(); ++iter)
{
if (iter->first == filepath)
return (WiiFile*)iter->second;
}
return NULL;
}
std::unordered_map<std::string, WiiFile*>& WiiSave::fileList()
{
return m_files;
}
void WiiSave::setBanner(WiiBanner* banner)
{
m_banner = banner;
}
WiiBanner* WiiSave::banner() const
{
return m_banner;
}

276
src/WiiSaveReader.cpp Normal file
View File

@ -0,0 +1,276 @@
#include "WiiSaveReader.hpp"
#include "WiiSave.h"
#include "WiiFile.h"
#include "WiiBanner.h"
#include "md5.h"
#include "aes.h"
#include "ec.h"
#include "sha1.h"
#include <iostream>
#include <iomanip>
#include <utility.hpp>
#include <IOException.hpp>
#include <string.h>
const Uint8 SD_KEY[16] = {0xab, 0x01, 0xb9, 0xd8, 0xe1, 0x62, 0x2b, 0x08, 0xaf, 0xba, 0xd8, 0x4d, 0xbf, 0xc2, 0xa5, 0x5d};
const Uint8 SD_IV[16] = {0x21, 0x67, 0x12, 0xe6, 0xaa, 0x1f, 0x68, 0x9f, 0x95, 0xc5, 0xa2, 0x23, 0x24, 0xdc, 0x6a, 0x98};
const Uint8 MD5_BLANKER[16] = {0x0e, 0x65, 0x37, 0x81, 0x99, 0xbe, 0x45, 0x17, 0xab, 0x06, 0xec, 0x22, 0x45, 0x1a, 0x57, 0x93};
WiiSaveReader::WiiSaveReader(const Uint8* data, Uint64 length)
: BinaryReader(data, length)
{
setEndianess(BigEndian);
}
WiiSaveReader::WiiSaveReader(const std::string& filename)
: BinaryReader(filename)
{
std::cout << filename << std::endl;
setEndianess(BigEndian);
}
WiiSave* WiiSaveReader::readSave()
{
WiiSave* ret = new WiiSave;
if (length() < 0xF0C0)
throw IOException("Not a valid WiiSave");
WiiBanner* banner = this->readBanner();
if (!banner)
throw IOException("Invalid banner");
ret->setBanner(banner);
Uint32 bkVer = this->readUInt32();
if (bkVer != 0x00000070)
throw IOException("Invalid BacKup header size");
Uint32 bkMagic = this->readUInt32();
bkMagic = bkMagic;
if (bkMagic != 0x426B0001)
throw IOException("Invalid BacKup header magic");
Uint32 ngId = this->readUInt32();
ngId = ngId;
Uint32 numFiles = this->readUInt32();
/*int fileSize =*/ this->readUInt32();
seek(8); // skip unknown data;
Uint32 totalSize = this->readUInt32();
this->seek(64); // Unknown (Most likely padding)
this->seek(8);
this->seek(6);
this->seek(2);
this->seek(0x10);
WiiFile* file;
for (Uint32 i = 0; i < numFiles; ++i)
{
file = readFile();
if (file)
ret->addFile("/" + file->filename(), file);
}
readCerts(totalSize);
return ret;
}
WiiBanner* WiiSaveReader::readBanner()
{
Uint8* dec = new Uint8[0xf0c0];
memset(dec, 0, 0xF0C0);
Uint8* data = (Uint8*)this->readBytes(0xF0C0);
Uint8* oldData = this->data();
Uint64 oldPos = this->position();
Uint64 oldLen = this->length();
Uint64 gameId;
Uint32 bannerSize;
Uint8 permissions;
Uint8 md5[16];
Uint8 md5Calc[16];
Uint8 tmpIV[26];
memcpy(tmpIV, SD_IV, 16);
aes_set_key(SD_KEY);
aes_decrypt(tmpIV, data, dec, 0xF0C0);
memset(md5, 0, 16);
memset(md5Calc, 0, 16);
// Read in the MD5 sum
memcpy(md5, (dec + 0x0E), 0x10);
// Write the blanker to the buffer
memcpy((dec + 0x0E), MD5_BLANKER, 0x10);
MD5(md5Calc, dec, 0xF0C0);
// Compare the Calculated MD5 to the one from the file.
// This needs to be done incase the file is corrupted.
if (memcmp(md5, md5Calc, 0x10))
{
std::cerr << "MD5 Mismatch" << std::endl;
// Make sure to reset m_reader values back to the old ones.
std::cerr << "MD5 provided: ";
for (int i = 0; i < 16; ++i)
std::cerr << std::setw(2) << std::setfill('0') << std::hex << (int)(md5[i]);
std::cerr << std::endl;
std::cerr << "MD5 Calculated: ";
for (int i = 0; i < 16; ++i)
std::cerr << std::hex << (int)(md5Calc[i]);
std::cerr << std::endl;
this->setData(oldData, oldLen);
this->seek(oldPos, Stream::Beginning);
throw IOException("MD5 Mismatch");
}
// Set the binary reader buffer;
this->setData(dec, 0xF0C0);
// Start reading the header
gameId = this->readUInt64();
bannerSize = this->readUInt32();
permissions = this->readByte();
/* unk =*/ this->readByte();
this->seek(0x10);
// skip padding
this->seek(2);
int magic;
int flags;
short animSpeed;
std::string gameTitle;
std::string subTitle;
magic = this->readUInt32();
// Ensure that the header magic is valid.
if (magic != 0x5749424E)
{
// Make sure to reset m_reader values back to the old ones.
this->setData(oldData, oldLen);
this->seek(oldPos, Stream::Beginning);
throw IOException("Invalid Header Magic");
}
flags = this->readUInt32();
animSpeed = this->readUInt16();
this->seek(22);
gameTitle = this->readUnicode();
if (this->position() != 0x0080)
this->seek(0x0080, Stream::Beginning);
subTitle = this->readUnicode();
if (this->position() != 0x00C0)
this->seek(0x00C0, Stream::Beginning);
WiiBanner* banner = new WiiBanner;
banner->setGameID(gameId);
banner->setTitle(gameTitle);
banner->setSubtitle(subTitle);
banner->setBannerSize(bannerSize);
WiiImage* bannerImage = readImage(192, 64);
banner->setBannerImage(bannerImage);
banner->setAnimationSpeed(animSpeed);
banner->setPermissions(permissions);
banner->setFlags(flags);
if (banner->bannerSize() == 0x72a0)
{
WiiImage* icon = readImage(48, 48);
if (icon)
banner->addIcon(icon);
else
std::cerr << "Warning: Icon empty, skipping" << std::endl;
}
else
{
for(int i = 0; i < 8; i++)
{
WiiImage* icon = readImage(48, 48);
if (icon)
banner->addIcon(icon);
else
std::cerr << "Warning: Icon empty, skipping" << std::endl;
}
}
this->setData(oldData, oldLen);
this->seek(oldPos, Stream::Beginning);
return banner;
}
WiiImage* WiiSaveReader::readImage(Uint32 width, Uint32 height)
{
Uint8* image = (Uint8*)this->readBytes(width*height*2);
if (!isEmpty((Int8*)image, width*height*2))
return new WiiImage(width, height, image);
return NULL;
}
WiiFile* WiiSaveReader::readFile()
{
Uint32 fileLen;
Uint8 permissions;
Uint8 attributes;
Uint8 type;
std::string name;
Uint8* filedata;
WiiFile* ret;
Uint32 magic = this->readUInt32();
if (magic != 0x03adf17e)
{
std::cerr << "Not a valid File entry header: 0x" << std::hex << magic << std::endl;
return NULL;
}
fileLen = this->readUInt32();
permissions = this->readByte();
attributes = this->readByte();
type = (WiiFile::Type)this->readByte();
name = std::string((const char*)this->readBytes(0x45));
ret = new WiiFile(std::string(name));
ret->setPermissions(permissions);
ret->setAttributes(attributes);
ret->setType((WiiFile::Type)type);
Uint8* iv = (Uint8*)this->readBytes(0x10);
this->seek(0x20);
if (type == WiiFile::File)
{
// Read file data
int roundedLen = (fileLen + 63) & ~63;
filedata = (Uint8*)this->readBytes(roundedLen);
// Decrypt file
Uint8* decData = new Uint8[roundedLen];
aes_set_key(SD_KEY);
aes_decrypt(iv, filedata, decData, roundedLen);
delete filedata;
ret->setData(decData);
ret->setLength(fileLen);
}
return ret;
}
void WiiSaveReader::readCerts(Uint32 totalSize)
{
Uint32 dataSize = totalSize - 0x340;
Uint8* sig = (Uint8*)this->readBytes(0x40);
Uint8* ngCert = (Uint8*)this->readBytes(0x180);
Uint8* apCert = (Uint8*)this->readBytes(0x180);
this->seek(0xF0C0, Stream::Beginning);
Uint8* data = (Uint8*)this->readBytes(dataSize);
Uint8* hash;
hash = getSha1(data, dataSize);
Uint8* hash2 = getSha1(hash, 20);
check_ec(ngCert, apCert, sig, hash2);
}

238
src/WiiSaveWriter.cpp Normal file
View File

@ -0,0 +1,238 @@
#include "WiiSaveWriter.hpp"
#include "WiiSave.h"
#include "WiiFile.h"
#include "WiiBanner.h"
#include "WiiSave.h"
#include "WiiFile.h"
#include "WiiBanner.h"
#include "BinaryWriter.hpp"
#include "IOException.hpp"
#include "aes.h"
#include "ec.h"
#include <utility.hpp>
#include "md5.h"
#include "sha1.h"
#include <stdio.h>
#include <vector>
#include <string.h>
#include <sys/stat.h>
#include <iostream>
#include <iomanip>
const Uint8 SD_KEY[16] = {0xab, 0x01, 0xb9, 0xd8, 0xe1, 0x62, 0x2b, 0x08, 0xaf, 0xba, 0xd8, 0x4d, 0xbf, 0xc2, 0xa5, 0x5d};
const Uint8 SD_IV[16] = {0x21, 0x67, 0x12, 0xe6, 0xaa, 0x1f, 0x68, 0x9f, 0x95, 0xc5, 0xa2, 0x23, 0x24, 0xdc, 0x6a, 0x98};
const Uint8 MD5_BLANKER[16] = {0x0e, 0x65, 0x37, 0x81, 0x99, 0xbe, 0x45, 0x17, 0xab, 0x06, 0xec, 0x22, 0x45, 0x1a, 0x57, 0x93};
WiiSaveWriter::WiiSaveWriter(const std::string &filename)
: BinaryWriter(filename)
{
this->setAutoResizing(true);
this->setEndianess(Stream::BigEndian);
}
bool WiiSaveWriter::writeSave(WiiSave *save, Uint8 *macAddress, Uint32 ngId, Uint8 *ngPriv, Uint8 *ngSig, Uint32 ngKeyId,const std::string &filepath)
{
if (filepath != "")
m_filepath = filepath;
writeBanner(save->banner());
this->writeUInt32(0x70);
this->writeUInt32(0x426B0001);
this->writeUInt32(ngId); // NG-ID
this->writeUInt32(save->fileList().size());
this->writeUInt32(0); // Size of files;
this->seek(8);
this->writeUInt32(0); // totalSize
this->seek(64);
this->writeUInt64(save->banner()->gameID());
this->writeBytes((Int8*)macAddress, 6);
this->seek(2); // unknown;
this->seek(0x10); // padding;
Uint32 totalSize = 0;
for (std::unordered_map<std::string, WiiFile*>::const_iterator iter = save->fileList().begin(); iter != save->fileList().end(); ++iter)
{
totalSize += writeFile(iter->second);
}
int pos = this->position();
// Write size data
this->seek(0xF0C0 + 0x10, Stream::Beginning);
this->writeUInt32(totalSize);
this->seek(0xF0C0 + 0x1C, Stream::Beginning);
this->writeUInt32(totalSize + 0x3c0);
this->seek(pos, Stream::Beginning);
writeCerts(totalSize, ngId, ngPriv, ngSig, ngKeyId);
this->save();
return true;
}
void WiiSaveWriter::writeBanner(WiiBanner *banner)
{
this->setEndianess(Stream::BigEndian);
this->setAutoResizing(true);
this->writeInt64(banner->gameID());
this->writeInt32((0x60a0+0x1200)*banner->icons().size());
this->writeByte((Int8)banner->permissions());
this->seek(1);
this->writeBytes((Int8*)MD5_BLANKER, 16);
this->seek(2);
this->writeInt32(0x5749424E); // WIBN
this->writeInt32(banner->flags());
this->writeInt16(banner->animationSpeed());
this->seek(22);
this->writeUnicode(banner->title());
if (this->position() != 0x0080)
this->seek(0x0080, Stream::Beginning);
this->writeUnicode(banner->subtitle());
if (this->position() != 0x00C0)
this->seek(0x00C0, Stream::Beginning);
WiiImage* bannerImage = banner->bannerImage();
this->writeBytes((Int8*)bannerImage->data(), bannerImage->width()*bannerImage->height()*2);
// For empty icons
Uint8* tmpIcon = new Uint8[48*48*2];
memset(tmpIcon, 0, 48*48*2);
for (Uint32 i = 0; i < 8; ++i)
{
if (i < banner->icons().size())
{
writeImage(banner->icons()[i]);
}
else
{
this->writeBytes((Int8*)tmpIcon, 48*48*2);
}
}
delete[] tmpIcon; // delete tmp buffer;
Uint8* hash = new Uint8[0x10];
MD5(hash, (Uint8*)this->data(), 0xF0C0);
this->seek(0x0E, Stream::Beginning);
this->writeBytes((Int8*)hash, 0x10);
aes_set_key(SD_KEY);
Uint8 data[0xF0C0];
memcpy(data, this->data(), 0xF0C0);
Uint8 tmpIV[26];
memcpy(tmpIV, SD_IV, 16);
aes_encrypt(tmpIV, data, data, 0xF0C0);
this->seek(0, Stream::Beginning);
this->writeBytes((Int8*)data, 0xF0C0);
this->seek(0xF0C0, Stream::Beginning);
}
Uint32 WiiSaveWriter::writeFile(WiiFile *file)
{
Uint32 ret = 0x80;
// Write the File magic
this->writeUInt32(0x03ADF17E);
this->writeUInt32(file->length());
this->writeByte(file->permissions());
this->writeByte(file->attributes());
this->writeByte(file->type());
Uint8 name[0x45];
fillRandom(name, 0x45);
memcpy(name, file->filename().c_str(), file->filename().size());
name[file->filename().size()] = '\0';
this->writeBytes((Int8*)name, 0x45);
Uint8 iv[16];
fillRandom(iv, 0x10);
this->writeBytes((Int8*)iv, 0x10);
Uint8 crap[0x20];
fillRandom(crap, 0x20);
this->writeBytes((Int8*)crap, 0x20);
if (file->type() == WiiFile::File)
{
int roundedSize = (file->length() + 63) & ~63;
Uint8* data = new Uint8[roundedSize];
memset(data, 0, roundedSize);
aes_set_key(SD_KEY);
aes_encrypt(iv, file->data(), data, roundedSize);
this->writeBytes((Int8*)data, roundedSize);
ret += roundedSize;
delete[] data;
}
return ret;
}
void WiiSaveWriter::writeImage(WiiImage* image)
{
Int8* data = (Int8*)image->data();
this->writeBytes(data, image->width() * image->height() * 2);
}
void WiiSaveWriter::writeCerts(Uint32 filesSize, Uint32 ngId, Uint8 *ngPriv, Uint8 *ngSig, Uint32 ngKeyId)
{
Uint8 sig[0x40];
Uint8 ngCert[0x180];
Uint8 apCert[0x180];
Uint8* hash;
Uint8 apPriv[30];
Uint8 apSig[60];
char signer[64];
char name[64];
Uint8* data;
Uint32 dataSize;
sprintf(signer, "Root-CA00000001-MS00000002");
sprintf(name, "NG%08x", ngId);
make_ec_cert(ngCert, ngSig, signer, name, ngPriv, ngKeyId);
memset(apPriv, 0, 30);
apPriv[10] = 1;
memset(apSig, 81, 30);
sprintf(signer, "Root-CA00000001-MS00000002-NG%08x", ngId);
sprintf(name, "AP%08x%08x", 1, 2);
make_ec_cert(apCert, apSig, signer, name, apPriv, 0);
hash = getSha1(apCert + 0x80, 0x100);
generate_ecdsa(apSig, apSig+30, ngPriv, hash);
make_ec_cert(apCert, apSig, signer, name, apPriv, 0);
delete[] hash;
dataSize = filesSize + 0x80;
data = new Uint8[dataSize];
Uint8* rawData = this->data();
memcpy(data, rawData + 0xF0C0, dataSize);
hash = getSha1(data, dataSize);
Uint8* hash2 = getSha1(hash, 20);
delete[] hash;
delete[] data;
generate_ecdsa(sig, sig+30, apPriv, hash2);
int stuff = 0x2f536969;
if (!isSystemBigEndian())
stuff = swap32(stuff);
*(Uint32*)(sig+60) = stuff;
delete[] hash2;
this->writeBytes((Int8*)sig, 0x40);
this->writeBytes((Int8*)ngCert, 0x180);
this->writeBytes((Int8*)apCert, 0x180);
}

403
src/aes.c Normal file
View File

@ -0,0 +1,403 @@
/* Rijndael Block Cipher - aes.c
Written by Mike Scott 21st April 1999
mike@compapp.dcu.ie
Permission for free direct or derivative use is granted subject
to compliance with any conditions that the originators of the
algorithm place on its exploitation.
*/
#include <stdio.h>
//#include <stdlib.h>
#include <string.h>
typedef unsigned char u8; /* 8 bits */
typedef unsigned long u32; /* 32 bits */
typedef unsigned long long u64;
/* rotates x one bit to the left */
#define ROTL(x) (((x)>>7)|((x)<<1))
/* Rotates 32-bit word left by 1, 2 or 3 byte */
#define ROTL8(x) (((x)<<8)|((x)>>24))
#define ROTL16(x) (((x)<<16)|((x)>>16))
#define ROTL24(x) (((x)<<24)|((x)>>8))
/* Fixed Data */
static u8 InCo[4]={0xB,0xD,0x9,0xE}; /* Inverse Coefficients */
static u8 fbsub[256];
static u8 rbsub[256];
static u8 ptab[256],ltab[256];
static u32 ftable[256];
static u32 rtable[256];
static u32 rco[30];
/* Parameter-dependent data */
int Nk,Nb,Nr;
u8 fi[24],ri[24];
u32 fkey[120];
u32 rkey[120];
static u32 pack(u8 *b)
{ /* pack bytes into a 32-bit Word */
return ((u32)b[3]<<24)|((u32)b[2]<<16)|((u32)b[1]<<8)|(u32)b[0];
}
static void unpack(u32 a,u8 *b)
{ /* unpack bytes from a word */
b[0]=(u8)a;
b[1]=(u8)(a>>8);
b[2]=(u8)(a>>16);
b[3]=(u8)(a>>24);
}
static u8 xtime(u8 a)
{
u8 b;
if (a&0x80) b=0x1B;
else b=0;
a<<=1;
a^=b;
return a;
}
static u8 bmul(u8 x,u8 y)
{ /* x.y= AntiLog(Log(x) + Log(y)) */
if (x && y) return ptab[(ltab[x]+ltab[y])%255];
else return 0;
}
static u32 SubByte(u32 a)
{
u8 b[4];
unpack(a,b);
b[0]=fbsub[b[0]];
b[1]=fbsub[b[1]];
b[2]=fbsub[b[2]];
b[3]=fbsub[b[3]];
return pack(b);
}
static u8 product(u32 x,u32 y)
{ /* dot product of two 4-byte arrays */
u8 xb[4],yb[4];
unpack(x,xb);
unpack(y,yb);
return bmul(xb[0],yb[0])^bmul(xb[1],yb[1])^bmul(xb[2],yb[2])^bmul(xb[3],yb[3]);
}
static u32 InvMixCol(u32 x)
{ /* matrix Multiplication */
u32 y,m;
u8 b[4];
m=pack(InCo);
b[3]=product(m,x);
m=ROTL24(m);
b[2]=product(m,x);
m=ROTL24(m);
b[1]=product(m,x);
m=ROTL24(m);
b[0]=product(m,x);
y=pack(b);
return y;
}
u8 ByteSub(u8 x)
{
u8 y=ptab[255-ltab[x]]; /* multiplicative inverse */
x=y; x=ROTL(x);
y^=x; x=ROTL(x);
y^=x; x=ROTL(x);
y^=x; x=ROTL(x);
y^=x; y^=0x63;
return y;
}
void gentables(void)
{ /* generate tables */
int i;
u8 y,b[4];
/* use 3 as primitive root to generate power and log tables */
ltab[0]=0;
ptab[0]=1; ltab[1]=0;
ptab[1]=3; ltab[3]=1;
for (i=2;i<256;i++)
{
ptab[i]=ptab[i-1]^xtime(ptab[i-1]);
ltab[ptab[i]]=i;
}
/* affine transformation:- each bit is xored with itself shifted one bit */
fbsub[0]=0x63;
rbsub[0x63]=0;
for (i=1;i<256;i++)
{
y=ByteSub((u8)i);
fbsub[i]=y; rbsub[y]=i;
}
for (i=0,y=1;i<30;i++)
{
rco[i]=y;
y=xtime(y);
}
/* calculate forward and reverse tables */
for (i=0;i<256;i++)
{
y=fbsub[i];
b[3]=y^xtime(y); b[2]=y;
b[1]=y; b[0]=xtime(y);
ftable[i]=pack(b);
y=rbsub[i];
b[3]=bmul(InCo[0],y); b[2]=bmul(InCo[1],y);
b[1]=bmul(InCo[2],y); b[0]=bmul(InCo[3],y);
rtable[i]=pack(b);
}
}
void gkey(int nb,int nk,u8 *key)
{ /* blocksize=32*nb bits. Key=32*nk bits */
/* currently nb,bk = 4, 6 or 8 */
/* key comes as 4*Nk bytes */
/* Key Scheduler. Create expanded encryption key */
int i,j,k,m,N;
int C1,C2,C3;
u32 CipherKey[8];
Nb=nb; Nk=nk;
/* Nr is number of rounds */
if (Nb>=Nk) Nr=6+Nb;
else Nr=6+Nk;
C1=1;
if (Nb<8) { C2=2; C3=3; }
else { C2=3; C3=4; }
/* pre-calculate forward and reverse increments */
for (m=j=0;j<nb;j++,m+=3)
{
fi[m]=(j+C1)%nb;
fi[m+1]=(j+C2)%nb;
fi[m+2]=(j+C3)%nb;
ri[m]=(nb+j-C1)%nb;
ri[m+1]=(nb+j-C2)%nb;
ri[m+2]=(nb+j-C3)%nb;
}
N=Nb*(Nr+1);
for (i=j=0;i<Nk;i++,j+=4)
{
CipherKey[i]=pack(key+j);
}
for (i=0;i<Nk;i++) fkey[i]=CipherKey[i];
for (j=Nk,k=0;j<N;j+=Nk,k++)
{
fkey[j]=fkey[j-Nk]^SubByte(ROTL24(fkey[j-1]))^rco[k];
if (Nk<=6)
{
for (i=1;i<Nk && (i+j)<N;i++)
fkey[i+j]=fkey[i+j-Nk]^fkey[i+j-1];
}
else
{
for (i=1;i<4 &&(i+j)<N;i++)
fkey[i+j]=fkey[i+j-Nk]^fkey[i+j-1];
if ((j+4)<N) fkey[j+4]=fkey[j+4-Nk]^SubByte(fkey[j+3]);
for (i=5;i<Nk && (i+j)<N;i++)
fkey[i+j]=fkey[i+j-Nk]^fkey[i+j-1];
}
}
/* now for the expanded decrypt key in reverse order */
for (j=0;j<Nb;j++) rkey[j+N-Nb]=fkey[j];
for (i=Nb;i<N-Nb;i+=Nb)
{
k=N-Nb-i;
for (j=0;j<Nb;j++) rkey[k+j]=InvMixCol(fkey[i+j]);
}
for (j=N-Nb;j<N;j++) rkey[j-N+Nb]=fkey[j];
}
/* There is an obvious time/space trade-off possible here. *
* Instead of just one ftable[], I could have 4, the other *
* 3 pre-rotated to save the ROTL8, ROTL16 and ROTL24 overhead */
void encrypt(u8 *buff)
{
int i,j,k,m;
u32 a[8],b[8],*x,*y,*t;
for (i=j=0;i<Nb;i++,j+=4)
{
a[i]=pack(buff+j);
a[i]^=fkey[i];
}
k=Nb;
x=a; y=b;
/* State alternates between a and b */
for (i=1;i<Nr;i++)
{ /* Nr is number of rounds. May be odd. */
/* if Nb is fixed - unroll this next
loop and hard-code in the values of fi[] */
for (m=j=0;j<Nb;j++,m+=3)
{ /* deal with each 32-bit element of the State */
/* This is the time-critical bit */
y[j]=fkey[k++]^ftable[(u8)x[j]]^
ROTL8(ftable[(u8)(x[fi[m]]>>8)])^
ROTL16(ftable[(u8)(x[fi[m+1]]>>16)])^
ROTL24(ftable[(u8)(x[fi[m+2]]>>24)]);
}
t=x; x=y; y=t; /* swap pointers */
}
/* Last Round - unroll if possible */
for (m=j=0;j<Nb;j++,m+=3)
{
y[j]=fkey[k++]^(u32)fbsub[(u8)x[j]]^
ROTL8((u32)fbsub[(u8)(x[fi[m]]>>8)])^
ROTL16((u32)fbsub[(u8)(x[fi[m+1]]>>16)])^
ROTL24((u32)fbsub[(u8)(x[fi[m+2]]>>24)]);
}
for (i=j=0;i<Nb;i++,j+=4)
{
unpack(y[i],(u8 *)&buff[j]);
x[i]=y[i]=0; /* clean up stack */
}
return;
}
void decrypt(u8 *buff)
{
int i,j,k,m;
u32 a[8],b[8],*x,*y,*t;
for (i=j=0;i<Nb;i++,j+=4)
{
a[i]=pack(buff+j);
a[i]^=rkey[i];
}
k=Nb;
x=a; y=b;
/* State alternates between a and b */
for (i=1;i<Nr;i++)
{ /* Nr is number of rounds. May be odd. */
/* if Nb is fixed - unroll this next
loop and hard-code in the values of ri[] */
for (m=j=0;j<Nb;j++,m+=3)
{ /* This is the time-critical bit */
y[j]=rkey[k++]^rtable[(u8)x[j]]^
ROTL8(rtable[(u8)(x[ri[m]]>>8)])^
ROTL16(rtable[(u8)(x[ri[m+1]]>>16)])^
ROTL24(rtable[(u8)(x[ri[m+2]]>>24)]);
}
t=x; x=y; y=t; /* swap pointers */
}
/* Last Round - unroll if possible */
for (m=j=0;j<Nb;j++,m+=3)
{
y[j]=rkey[k++]^(u32)rbsub[(u8)x[j]]^
ROTL8((u32)rbsub[(u8)(x[ri[m]]>>8)])^
ROTL16((u32)rbsub[(u8)(x[ri[m+1]]>>16)])^
ROTL24((u32)rbsub[(u8)(x[ri[m+2]]>>24)]);
}
for (i=j=0;i<Nb;i++,j+=4)
{
unpack(y[i],(u8 *)&buff[j]);
x[i]=y[i]=0; /* clean up stack */
}
return;
}
void aes_set_key(u8 *key) {
gentables();
gkey(4, 4, key);
}
// CBC mode decryption
void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len) {
u8 block[16];
u8* ctext_ptr;
unsigned int blockno = 0, i;
//fprintf( stderr,"aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len );
//printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) {
unsigned int fraction;
if (blockno == (len / sizeof(block))) { // last block
fraction = len % sizeof(block);
if (fraction == 0) break;
memset(block, 0, sizeof(block));
} else fraction = 16;
// debug_printf("block %d: fraction = %d\n", blockno, fraction);
memcpy(block, inbuf + blockno * sizeof(block), fraction);
decrypt(block);
if (blockno == 0) ctext_ptr = iv;
else ctext_ptr = inbuf + (blockno-1) * sizeof(block);
for(i=0; i < fraction; i++)
outbuf[blockno * sizeof(block) + i] =
ctext_ptr[i] ^ block[i];
// debug_printf("Block %d output: ", blockno);
// hexdump(outbuf + blockno*sizeof(block), 16);
}
}
// CBC mode encryption
void aes_encrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len) {
u8 block[16];
unsigned int blockno = 0, i;
//printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
//fprintf( stderr,"aes_encrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) {
unsigned int fraction;
if (blockno == (len / sizeof(block))) { // last block
fraction = len % sizeof(block);
if (fraction == 0) break;
memset(block, 0, sizeof(block));
} else fraction = 16;
// debug_printf("block %d: fraction = %d\n", blockno, fraction);
memcpy(block, inbuf + blockno * sizeof(block), fraction);
for(i=0; i < fraction; i++)
block[i] = inbuf[blockno * sizeof(block) + i] ^ iv[i];
encrypt(block);
memcpy(iv, block, sizeof(block));
memcpy(outbuf + blockno * sizeof(block), block, sizeof(block));
// debug_printf("Block %d output: ", blockno);
// hexdump(outbuf + blockno*sizeof(block), 16);
}
}

111
src/bn.cpp Normal file
View File

@ -0,0 +1,111 @@
// Copyright 2007,2008 Segher Boessenkool <segher@kernel.crashing.org>
// Licensed under the terms of the GNU GPL, version 2
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
#include <string.h>
#include <stdio.h>
#include "bn.h"
static void bn_zero(Uint8 *d, Uint32 n)
{
memset(d, 0, n);
}
static void bn_copy(Uint8 *d, Uint8 *a, Uint32 n)
{
memcpy(d, a, n);
}
int bn_compare(Uint8 *a, Uint8 *b, Uint32 n)
{
Uint32 i;
for (i = 0; i < n; i++) {
if (a[i] < b[i])
return -1;
if (a[i] > b[i])
return 1;
}
return 0;
}
void bn_sub_modulus(Uint8 *a, Uint8 *N, Uint32 n)
{
Uint32 i;
Uint32 dig;
Uint8 c;
c = 0;
for (i = n - 1; i < n; i--) {
dig = N[i] + c;
c = (a[i] < dig);
a[i] -= dig;
}
}
void bn_add(Uint8 *d, Uint8 *a, Uint8 *b, Uint8 *N, Uint32 n)
{
Uint32 i;
Uint32 dig;
Uint8 c;
c = 0;
for (i = n - 1; i < n; i--) {
dig = a[i] + b[i] + c;
c = (dig >= 0x100);
d[i] = dig;
}
if (c)
bn_sub_modulus(d, N, n);
if (bn_compare(d, N, n) >= 0)
bn_sub_modulus(d, N, n);
}
void bn_mul(Uint8 *d, Uint8 *a, Uint8 *b, Uint8 *N, Uint32 n)
{
Uint32 i;
Uint8 mask;
bn_zero(d, n);
for (i = 0; i < n; i++)
for (mask = 0x80; mask != 0; mask >>= 1) {
bn_add(d, d, d, N, n);
if ((a[i] & mask) != 0)
bn_add(d, d, b, N, n);
}
}
void bn_exp(Uint8 *d, Uint8 *a, Uint8 *N, Uint32 n, Uint8 *e, Uint32 en)
{
Uint8 t[512];
Uint32 i;
Uint8 mask;
bn_zero(d, n);
d[n-1] = 1;
for (i = 0; i < en; i++)
for (mask = 0x80; mask != 0; mask >>= 1) {
bn_mul(t, d, d, N, n);
if ((e[i] & mask) != 0)
bn_mul(d, t, a, N, n);
else
bn_copy(d, t, n);
}
}
// only for prime N -- stupid but lazy, see if I care
void bn_inv(Uint8 *d, Uint8 *a, Uint8 *N, Uint32 n)
{
Uint8 t[512], s[512];
bn_copy(t, N, n);
bn_zero(s, n);
s[n-1] = 2;
bn_sub_modulus(t, s, n);
bn_exp(d, a, N, n, t, n);
}

419
src/ec.cpp Normal file
View File

@ -0,0 +1,419 @@
// Copyright 2007,2008 Segher Boessenkool <segher@kernel.crashing.org>
// Licensed under the terms of the GNU GPL, version 2
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
#include <string.h>
#include <iostream>
#include <time.h>
#include <stdlib.h>
#include <utility.hpp>
#include "bn.h"
#include "ec.h"
#include "sha1.h"
// y**2 + x*y = x**3 + x + b
/*static u8 ec_b[30] = { 0x00, 0x66, 0x64, 0x7e, 0xde, 0x6c, 0x33, 0x2c, 0x7f, 0x8c, 0x09, 0x23, 0xbb, 0x58, 0x21,
0x3b, 0x33, 0x3b, 0x20, 0xe9, 0xce, 0x42, 0x81, 0xfe, 0x11, 0x5f, 0x7d, 0x8f, 0x90, 0xad };
*/
// order of the addition group of points
static Uint8 ec_N[30] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x13, 0xe9, 0x74, 0xe7, 0x2f, 0x8a, 0x69, 0x22, 0x03, 0x1d, 0x26, 0x03, 0xcf, 0xe0, 0xd7 };
// base point
static Uint8 ec_G[60] = { 0x00, 0xfa, 0xc9, 0xdf, 0xcb, 0xac, 0x83, 0x13, 0xbb, 0x21, 0x39, 0xf1, 0xbb, 0x75, 0x5f,
0xef, 0x65, 0xbc, 0x39, 0x1f, 0x8b, 0x36, 0xf8, 0xf8, 0xeb, 0x73, 0x71, 0xfd, 0x55, 0x8b,
0x01, 0x00, 0x6a, 0x08, 0xa4, 0x19, 0x03, 0x35, 0x06, 0x78, 0xe5, 0x85, 0x28, 0xbe, 0xbf,
0x8a, 0x0b, 0xef, 0xf8, 0x67, 0xa7, 0xca, 0x36, 0x71, 0x6f, 0x7e, 0x01, 0xf8, 0x10, 0x52 };
/*
static void elt_print(char *name, u8 *a)
{
u32 i;
printf("%s = ", name);
for (i = 0; i < 30; i++)
printf("%02x", a[i]);
printf("\n");
}
*/
static void elt_copy(Uint8 *d, Uint8 *a)
{
memcpy(d, a, 30);
}
static void elt_zero(Uint8 *d)
{
memset(d, 0, 30);
}
static int elt_is_zero(Uint8 *d)
{
Uint32 i;
for (i = 0; i < 30; i++)
if (d[i] != 0)
return 0;
return 1;
}
static void elt_add(Uint8 *d, Uint8 *a, Uint8 *b)
{
Uint32 i;
for (i = 0; i < 30; i++)
d[i] = a[i] ^ b[i];
}
static void elt_mul_x(Uint8 *d, Uint8 *a)
{
Uint8 carry, x, y;
Uint32 i;
carry = a[0] & 1;
x = 0;
for (i = 0; i < 29; i++) {
y = a[i + 1];
d[i] = x ^ (y >> 7);
x = y << 1;
}
d[29] = x ^ carry;
d[20] ^= carry << 2;
}
static void elt_mul(Uint8 *d, Uint8 *a, Uint8 *b)
{
Uint32 i, n;
Uint8 mask;
elt_zero(d);
i = 0;
mask = 1;
for (n = 0; n < 233; n++) {
elt_mul_x(d, d);
if ((a[i] & mask) != 0)
elt_add(d, d, b);
mask >>= 1;
if (mask == 0) {
mask = 0x80;
i++;
}
}
}
static const Uint8 square[16] = { 0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15, 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55 };
static void elt_square_to_wide(Uint8 *d, Uint8 *a)
{
Uint32 i;
for (i = 0; i < 30; i++) {
d[2*i] = square[a[i] >> 4];
d[2*i + 1] = square[a[i] & 15];
}
}
static void wide_reduce(Uint8 *d)
{
Uint32 i;
Uint8 x;
for (i = 0; i < 30; i++) {
x = d[i];
d[i + 19] ^= x >> 7;
d[i + 20] ^= x << 1;
d[i + 29] ^= x >> 1;
d[i + 30] ^= x << 7;
}
x = d[30] & ~1;
d[49] ^= x >> 7;
d[50] ^= x << 1;
d[59] ^= x >> 1;
d[30] &= 1;
}
static void elt_square(Uint8 *d, Uint8 *a)
{
Uint8 wide[60];
elt_square_to_wide(wide, a);
wide_reduce(wide);
elt_copy(d, wide + 30);
}
static void itoh_tsujii(Uint8 *d, Uint8 *a, Uint8 *b, Uint32 j)
{
Uint8 t[30];
elt_copy(t, a);
while (j--) {
elt_square(d, t);
elt_copy(t, d);
}
elt_mul(d, t, b);
}
static void elt_inv(Uint8 *d, Uint8 *a)
{
Uint8 t[30];
Uint8 s[30];
itoh_tsujii(t, a, a, 1);
itoh_tsujii(s, t, a, 1);
itoh_tsujii(t, s, s, 3);
itoh_tsujii(s, t, a, 1);
itoh_tsujii(t, s, s, 7);
itoh_tsujii(s, t, t, 14);
itoh_tsujii(t, s, a, 1);
itoh_tsujii(s, t, t, 29);
itoh_tsujii(t, s, s, 58);
itoh_tsujii(s, t, t, 116);
elt_square(d, s);
}
/*
static int point_is_on_curve(u8 *p)
{
u8 s[30], t[30];
u8 *x, *y;
x = p;
y = p + 30;
elt_square(t, x);
elt_mul(s, t, x);
elt_add(s, s, t);
elt_square(t, y);
elt_add(s, s, t);
elt_mul(t, x, y);
elt_add(s, s, t);
elt_add(s, s, ec_b);
return elt_is_zero(s);
}
*/
static int point_is_zero(Uint8 *p)
{
return elt_is_zero(p) && elt_is_zero(p + 30);
}
static void point_double(Uint8 *r, Uint8 *p)
{
Uint8 s[30], t[30];
Uint8 *px, *py, *rx, *ry;
px = p;
py = p + 30;
rx = r;
ry = r + 30;
if (elt_is_zero(px)) {
elt_zero(rx);
elt_zero(ry);
return;
}
elt_inv(t, px);
elt_mul(s, py, t);
elt_add(s, s, px);
elt_square(t, px);
elt_square(rx, s);
elt_add(rx, rx, s);
rx[29] ^= 1;
elt_mul(ry, s, rx);
elt_add(ry, ry, rx);
elt_add(ry, ry, t);
}
static void point_add(Uint8 *r, Uint8 *p, Uint8 *q)
{
Uint8 s[30], t[30], u[30];
Uint8 *px, *py, *qx, *qy, *rx, *ry;
px = p;
py = p + 30;
qx = q;
qy = q + 30;
rx = r;
ry = r + 30;
if (point_is_zero(p)) {
elt_copy(rx, qx);
elt_copy(ry, qy);
return;
}
if (point_is_zero(q)) {
elt_copy(rx, px);
elt_copy(ry, py);
return;
}
elt_add(u, px, qx);
if (elt_is_zero(u)) {
elt_add(u, py, qy);
if (elt_is_zero(u))
point_double(r, p);
else {
elt_zero(rx);
elt_zero(ry);
}
return;
}
elt_inv(t, u);
elt_add(u, py, qy);
elt_mul(s, t, u);
elt_square(t, s);
elt_add(t, t, s);
elt_add(t, t, qx);
t[29] ^= 1;
elt_mul(u, s, t);
elt_add(s, u, py);
elt_add(rx, t, px);
elt_add(ry, s, rx);
}
static void point_mul(Uint8 *d, Uint8 *a, Uint8 *b) // a is bignum
{
Uint32 i;
Uint8 mask;
elt_zero(d);
elt_zero(d + 30);
for (i = 0; i < 30; i++)
for (mask = 0x80; mask != 0; mask >>= 1) {
point_double(d, d);
if ((a[i] & mask) != 0)
point_add(d, d, b);
}
}
void sillyRandom(Uint8 * rndArea, Uint8 count)
{
for(Uint16 i = 0; i < count; i++)
rndArea[i]=rand();
}
void generate_ecdsa(Uint8 *R, Uint8 *S, Uint8 *k, Uint8 *hash)
{
Uint8 e[30];
Uint8 kk[30];
Uint8 m[30];
Uint8 minv[30];
Uint8 mG[60];
//FILE *fp;
elt_zero(e);
memcpy(e + 10, hash, 20);
sillyRandom(m, sizeof(m));
m[0] = 0;
// R = (mG).x
point_mul(mG, m, ec_G);
elt_copy(R, mG);
if (bn_compare(R, ec_N, 30) >= 0)
bn_sub_modulus(R, ec_N, 30);
// S = m**-1*(e + Rk) (mod N)
elt_copy(kk, k);
if (bn_compare(kk, ec_N, 30) >= 0)
bn_sub_modulus(kk, ec_N, 30);
bn_mul(S, R, kk, ec_N, 30);
bn_add(kk, S, e, ec_N, 30);
bn_inv(minv, m, ec_N, 30);
bn_mul(S, minv, kk, ec_N, 30);
}
bool check_ecdsa(Uint8 *Q, Uint8 *R, Uint8 *S, Uint8 *hash)
{
Uint8 Sinv[30];
Uint8 e[30];
Uint8 w1[30], w2[30];
Uint8 r1[60], r2[60];
bn_inv(Sinv, S, ec_N, 30);
elt_zero(e);
memcpy(e + 10, hash, 20);
bn_mul(w1, e, Sinv, ec_N, 30);
bn_mul(w2, R, Sinv, ec_N, 30);
point_mul(r1, w1, ec_G);
point_mul(r2, w2, Q);
point_add(r1, r1, r2);
if (bn_compare(r1, ec_N, 30) >= 0)
bn_sub_modulus(r1, ec_N, 30);
return (bn_compare(r1, R, 30) == 0);
}
void ec_priv_to_pub(Uint8 *k, Uint8 *Q)
{
point_mul(Q, k, ec_G);
}
bool check_ec(Uint8 *ng, Uint8 *ap, Uint8 *sig, Uint8 *sig_hash)
{
Uint8* ap_hash;
Uint8 *ng_Q, *ap_R, *ap_S;
Uint8 *ap_Q, *sig_R, *sig_S;
ng_Q = ng + 0x0108;
ap_R = ap + 0x04;
ap_S = ap + 0x22;
ap_hash = getSha1(ap+0x80, 0x100);
ap_Q = ap + 0x0108;
sig_R = sig;
sig_S = sig + 30;
return check_ecdsa(ng_Q, ap_R, ap_S, ap_hash)
&& check_ecdsa(ap_Q, sig_R, sig_S, sig_hash);
}
void make_ec_cert(Uint8 *cert, Uint8 *sig, char *signer, char *name, Uint8 *priv, Uint32 key_id )
{
memset(cert, 0, 0x180);
*(Uint32*)(cert) = swapU32(0x10002);
memcpy((char*)cert + 4, sig, 60);
strcpy((char*)cert + 0x80, signer);
*(Uint32*)(cert + 0xc0) = swapU32(2);
strcpy((char*)cert + 0xc4, name);
*(Uint32*)(cert + 0x104) = swapU32(key_id);
ec_priv_to_pub(priv, cert + 0x108);
}

610
src/md5.c Normal file
View File

@ -0,0 +1,610 @@
/* ========================================================================== **
*
* MD5.c
*
* Copyright:
* Copyright (C) 2003-2005 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
*
* $Id: MD5.c,v 0.6 2005/06/08 18:35:59 crh Exp $
*
*
* Modifications and additions by dimok
*
* -------------------------------------------------------------------------- **
*
* Description:
* Implements the MD5 hash algorithm, as described in RFC 1321.
*
* -------------------------------------------------------------------------- **
*
* License:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* -------------------------------------------------------------------------- **
*
* Notes:
*
* None of this will make any sense unless you're studying RFC 1321 as you
* read the code.
*
* MD5 is described in RFC 1321.
* The MD*4* algorithm is described in RFC 1320 (that's 1321 - 1).
* MD5 is very similar to MD4, but not quite similar enough to justify
* putting the two into a single module. Besides, I wanted to add a few
* extra functions to this one to expand its usability.
*
* There are three primary motivations for this particular implementation.
* 1) Programmer's pride. I wanted to be able to say I'd done it, and I
* wanted to learn from the experience.
* 2) Portability. I wanted an implementation that I knew to be portable
* to a reasonable number of platforms. In particular, the algorithm is
* designed with little-endian platforms in mind, but I wanted an
* endian-agnostic implementation.
* 3) Compactness. While not an overriding goal, I thought it worth-while
* to see if I could reduce the overall size of the result. This is in
* keeping with my hopes that this library will be suitable for use in
* some embedded environments.
* Beyond that, cleanliness and clarity are always worth pursuing.
*
* As mentioned above, the code really only makes sense if you are familiar
* with the MD5 algorithm or are using RFC 1321 as a guide. This code is
* quirky, however, so you'll want to be reading carefully.
*
* Yeah...most of the comments are cut-and-paste from my MD4 implementation.
*
* -------------------------------------------------------------------------- **
*
* References:
* IETF RFC 1321: The MD5 Message-Digest Algorithm
* Ron Rivest. IETF, April, 1992
*
* ========================================================================== **
*/
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <ctype.h>
#include "md5.h"
/* -------------------------------------------------------------------------- **
* Static Constants:
*
* K[][] - In round one, the values of k (which are used to index
* particular four-byte sequences in the input) are simply
* sequential. In later rounds, however, they are a bit more
* varied. Rather than calculate the values of k (which may
* or may not be possible--I haven't though about it) the
* values are stored in this array.
*
* S[][] - In each round there is a left rotate operation performed as
* part of the 16 permutations. The number of bits varies in
* a repeating patter. This array keeps track of the patterns
* used in each round.
*
* T[][] - There are four rounds of 16 permutations for a total of 64.
* In each of these 64 permutation operations, a different
* constant value is added to the mix. The constants are
* based on the sine function...read RFC 1321 for more detail.
* In any case, the correct constants are stored in the T[][]
* array. They're divided up into four groups of 16.
*/
static const uint8_t K[3][16] = {
/* Round 1: skipped (since it is simply sequential). */
{ 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12 }, /* R2 */
{ 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2 }, /* R3 */
{ 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 } /* R4 */
};
static const uint8_t S[4][4] = { { 7, 12, 17, 22 }, /* Round 1 */
{ 5, 9, 14, 20 }, /* Round 2 */
{ 4, 11, 16, 23 }, /* Round 3 */
{ 6, 10, 15, 21 } /* Round 4 */
};
static const uint32_t T[4][16] = { { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, /* Round 1 */
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193,
0xa679438e, 0x49b40821 },
{ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, /* Round 2 */
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
0x676f02d9, 0x8d2a4c8a },
{ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, /* Round 3 */
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5,
0x1fa27cf8, 0xc4ac5665 },
{ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, /* Round 4 */
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235,
0x2ad7d2bb, 0xeb86d391 }, };
/* -------------------------------------------------------------------------- **
* Macros:
* md5F(), md5G(), md5H(), and md5I() are described in RFC 1321.
* All of these operations are bitwise, and so not impacted by endian-ness.
*
* GetLongByte()
* Extract one byte from a (32-bit) longword. A value of 0 for <idx>
* indicates the lowest order byte, while 3 indicates the highest order
* byte.
*
*/
#define md5F( X, Y, Z ) ( ((X) & (Y)) | ((~(X)) & (Z)) )
#define md5G( X, Y, Z ) ( ((X) & (Z)) | ((Y) & (~(Z))) )
#define md5H( X, Y, Z ) ( (X) ^ (Y) ^ (Z) )
#define md5I( X, Y, Z ) ( (Y) ^ ((X) | (~(Z))) )
#define GetLongByte( L, idx ) ((unsigned char)(( L >> (((idx) & 0x03) << 3) ) & 0xFF))
#define STR2HEX(x) ((x >= 0x30) && (x <= 0x39)) ? x - 0x30 : toupper((int)x)-0x37
/* -------------------------------------------------------------------------- **
* Static Functions:
*/
static void Permute(uint32_t ABCD[4], const unsigned char block[64])
/* ------------------------------------------------------------------------ **
* Permute the ABCD "registers" using the 64-byte <block> as a driver.
*
* Input: ABCD - Pointer to an array of four unsigned longwords.
* block - An array of bytes, 64 bytes in size.
*
* Output: none.
*
* Notes: The MD5 algorithm operates on a set of four longwords stored
* (conceptually) in four "registers". It is easy to imagine a
* simple MD4/5 chip that would operate this way. In any case,
* the mangling of the contents of those registers is driven by
* the input message. The message is chopped and finally padded
* into 64-byte chunks and each chunk is used to manipulate the
* contents of the registers.
*
* The MD5 Algorithm calls for padding the input to ensure that
* it is a multiple of 64 bytes in length. The last 16 bytes
* of the padding space are used to store the message length
* (the length of the original message, before padding, expressed
* in terms of bits). If there is not enough room for 16 bytes
* worth of bitcount (eg., if the original message was 122 bytes
* long) then the block is padded to the end with zeros and
* passed to this function. Then *another* block is filled with
* zeros except for the last 16 bytes which contain the length.
*
* Oh... and the algorithm requires that there be at least one
* padding byte. The first padding byte has a value of 0x80,
* and any others are 0x00.
*
* ------------------------------------------------------------------------ **
*/
{
int round;
int i, j;
uint8_t s;
uint32_t a, b, c, d;
uint32_t KeepABCD[4];
uint32_t X[16];
/* Store the current ABCD values for later re-use.
*/
for (i = 0; i < 4; i++)
KeepABCD[i] = ABCD[i];
/* Convert the input block into an array of unsigned longs, taking care
* to read the block in Little Endian order (the algorithm assumes this).
* The uint32_t values are then handled in host order.
*/
for (i = 0, j = 0; i < 16; i++)
{
X[i] = (uint32_t) block[j++];
X[i] |= ((uint32_t) block[j++] << 8);
X[i] |= ((uint32_t) block[j++] << 16);
X[i] |= ((uint32_t) block[j++] << 24);
}
/* This loop performs the four rounds of permutations.
* The rounds are each very similar. The differences are in three areas:
* - The function (F, G, H, or I) used to perform bitwise permutations
* on the registers,
* - The order in which values from X[] are chosen.
* - Changes to the number of bits by which the registers are rotated.
* This implementation uses a switch statement to deal with some of the
* differences between rounds. Other differences are handled by storing
* values in arrays and using the round number to select the correct set
* of values.
*
* (My implementation appears to be a poor compromise between speed, size,
* and clarity. Ugh. [crh])
*/
for (round = 0; round < 4; round++)
{
for (i = 0; i < 16; i++)
{
j = (4 - (i % 4)) & 0x3; /* <j> handles the rotation of ABCD. */
s = S[round][i % 4]; /* <s> is the bit shift for this iteration. */
b = ABCD[(j + 1) & 0x3]; /* Copy the b,c,d values per ABCD rotation. */
c = ABCD[(j + 2) & 0x3]; /* This isn't really necessary, it just looks */
d = ABCD[(j + 3) & 0x3]; /* clean & will hopefully be optimized away. */
/* The actual perumation function.
* This is broken out to minimize the code within the switch().
*/
switch (round)
{
case 0:
/* round 1 */
a = md5F( b, c, d ) + X[i];
break;
case 1:
/* round 2 */
a = md5G( b, c, d ) + X[K[0][i]];
break;
case 2:
/* round 3 */
a = md5H( b, c, d ) + X[K[1][i]];
break;
default:
/* round 4 */
a = md5I( b, c, d ) + X[K[2][i]];
break;
}
a = 0xFFFFFFFF & (ABCD[j] + a + T[round][i]);
ABCD[j] = b + (0xFFFFFFFF & ((a << s) | (a >> (32 - s))));
}
}
/* Use the stored original A, B, C, D values to perform
* one last convolution.
*/
for (i = 0; i < 4; i++)
ABCD[i] = 0xFFFFFFFF & (ABCD[i] + KeepABCD[i]);
} /* Permute */
/* -------------------------------------------------------------------------- **
* Functions:
*/
auth_md5Ctx *auth_md5InitCtx(auth_md5Ctx *ctx)
/* ------------------------------------------------------------------------ **
* Initialize an MD5 context.
*
* Input: ctx - A pointer to the MD5 context structure to be initialized.
* Contexts are typically created thusly:
* ctx = (auth_md5Ctx *)malloc( sizeof(auth_md5Ctx) );
*
* Output: A pointer to the initialized context (same as <ctx>).
*
* Notes: The purpose of the context is to make it possible to generate
* an MD5 Message Digest in stages, rather than having to pass a
* single large block to a single MD5 function. The context
* structure keeps track of various bits of state information.
*
* Once the context is initialized, the blocks of message data
* are passed to the <auth_md5SumCtx()> function. Once the
* final bit of data has been handed to <auth_md5SumCtx()> the
* context can be closed out by calling <auth_md5CloseCtx()>,
* which also calculates the final MD5 result.
*
* Don't forget to free an allocated context structure when
* you've finished using it.
*
* See Also: <auth_md5SumCtx()>, <auth_md5CloseCtx()>
*
* ------------------------------------------------------------------------ **
*/
{
ctx->len = 0;
ctx->b_used = 0;
ctx->ABCD[0] = 0x67452301; /* The array ABCD[] contains the four 4-byte */
ctx->ABCD[1] = 0xefcdab89; /* "registers" that are manipulated to */
ctx->ABCD[2] = 0x98badcfe; /* produce the MD5 digest. The input acts */
ctx->ABCD[3] = 0x10325476; /* upon the registers, not the other way */
/* 'round. The initial values are those */
/* given in RFC 1321 (pg. 4). Note, however, that RFC 1321 */
/* provides these values as bytes, not as longwords, and the */
/* bytes are arranged in little-endian order as if they were */
/* the bytes of (little endian) 32-bit ints. That's */
/* confusing as all getout (to me, anyway). The values given */
/* here are provided as 32-bit values in C language format, */
/* so they are endian-agnostic. */
return (ctx);
} /* auth_md5InitCtx */
auth_md5Ctx *auth_md5SumCtx(auth_md5Ctx *ctx, const unsigned char *src, const int len)
/* ------------------------------------------------------------------------ **
* Build an MD5 Message Digest within the given context.
*
* Input: ctx - Pointer to the context in which the MD5 sum is being
* built.
* src - A chunk of source data. This will be used to drive
* the MD5 algorithm.
* len - The number of bytes in <src>.
*
* Output: A pointer to the updated context (same as <ctx>).
*
* See Also: <auth_md5InitCtx()>, <auth_md5CloseCtx()>, <auth_md5Sum()>
*
* ------------------------------------------------------------------------ **
*/
{
int i;
/* Add the new block's length to the total length.
*/
ctx->len += (uint32_t) len;
/* Copy the new block's data into the context block.
* Call the Permute() function whenever the context block is full.
*/
for (i = 0; i < len; i++)
{
ctx->block[ctx->b_used] = src[i];
(ctx->b_used)++;
if (64 == ctx->b_used)
{
Permute(ctx->ABCD, ctx->block);
ctx->b_used = 0;
}
}
/* Return the updated context.
*/
return (ctx);
} /* auth_md5SumCtx */
auth_md5Ctx *auth_md5CloseCtx(auth_md5Ctx *ctx, unsigned char *dst)
/* ------------------------------------------------------------------------ **
* Close an MD5 Message Digest context and generate the final MD5 sum.
*
* Input: ctx - Pointer to the context in which the MD5 sum is being
* built.
* dst - A pointer to at least 16 bytes of memory, which will
* receive the finished MD5 sum.
*
* Output: A pointer to the closed context (same as <ctx>).
* You might use this to free a malloc'd context structure. :)
*
* Notes: The context (<ctx>) is returned in an undefined state.
* It must be re-initialized before re-use.
*
* See Also: <auth_md5InitCtx()>, <auth_md5SumCtx()>
*
* ------------------------------------------------------------------------ **
*/
{
int i;
uint32_t l;
/* Add the required 0x80 padding initiator byte.
* The auth_md5SumCtx() function always permutes and resets the context
* block when it gets full, so we know that there must be at least one
* free byte in the context block.
*/
ctx->block[ctx->b_used] = 0x80;
(ctx->b_used)++;
/* Zero out any remaining free bytes in the context block.
*/
for (i = ctx->b_used; i < 64; i++)
ctx->block[i] = 0;
/* We need 8 bytes to store the length field.
* If we don't have 8, call Permute() and reset the context block.
*/
if (56 < ctx->b_used)
{
Permute(ctx->ABCD, ctx->block);
for (i = 0; i < 64; i++)
ctx->block[i] = 0;
}
/* Add the total length and perform the final perumation.
* Note: The 60'th byte is read from the *original* <ctx->len> value
* and shifted to the correct position. This neatly avoids
* any MAXINT numeric overflow issues.
*/
l = ctx->len << 3;
for (i = 0; i < 4; i++)
ctx->block[56 + i] |= GetLongByte( l, i );
ctx->block[60] = ((GetLongByte( ctx->len, 3 ) & 0xE0) >> 5); /* See Above! */
Permute(ctx->ABCD, ctx->block);
/* Now copy the result into the output buffer and we're done.
*/
for (i = 0; i < 4; i++)
{
dst[0 + i] = GetLongByte( ctx->ABCD[0], i );
dst[4 + i] = GetLongByte( ctx->ABCD[1], i );
dst[8 + i] = GetLongByte( ctx->ABCD[2], i );
dst[12 + i] = GetLongByte( ctx->ABCD[3], i );
}
/* Return the context.
* This is done for compatibility with the other auth_md5*Ctx() functions.
*/
return (ctx);
} /* auth_md5CloseCtx */
unsigned char * MD5(unsigned char *dst, const unsigned char *src, const int len)
/* ------------------------------------------------------------------------ **
* Compute an MD5 message digest.
*
* Input: dst - Destination buffer into which the result will be written.
* Must be 16 bytes, minimum.
* src - Source data block to be MD5'd.
* len - The length, in bytes, of the source block.
* (Note that the length is given in bytes, not bits.)
*
* Output: A pointer to <dst>, which will contain the calculated 16-byte
* MD5 message digest.
*
* Notes: This function is a shortcut. It takes a single input block.
* For more drawn-out operations, see <auth_md5InitCtx()>.
*
* This function is interface-compatible with the
* <auth_md4Sum()> function in the MD4 module.
*
* The MD5 algorithm is designed to work on data with an
* arbitrary *bit* length. Most implementations, this one
* included, handle the input data in byte-sized chunks.
*
* The MD5 algorithm does much of its work using four-byte
* words, and so can be tuned for speed based on the endian-ness
* of the host. This implementation is intended to be
* endian-neutral, which may make it a teeny bit slower than
* others. ...maybe.
*
* See Also: <auth_md5InitCtx()>
*
* ------------------------------------------------------------------------ **
*/
{
auth_md5Ctx ctx[1];
(void) auth_md5InitCtx(ctx); /* Open a context. */
(void) auth_md5SumCtx(ctx, src, len); /* Pass only one block. */
(void) auth_md5CloseCtx(ctx, dst); /* Close the context. */
return (dst); /* Makes life easy. */
} /* auth_md5Sum */
unsigned char * MD5fromFile(unsigned char *dst, const char *src)
/* ------------------------------------------------------------------------ **
* Compute an MD5 message digest.
*
* Input: dst - Destination buffer into which the result will be written.
* Must be 16 bytes, minimum.
* src - filepath of the file to be checked
*
* Output: A pointer to <dst>, which will contain the calculated 16-byte
* MD5 message digest.
*
* Notes: This function is a shortcut. It takes a single input block.
* For more drawn-out operations, see <auth_md5InitCtx()>.
*
* This function is interface-compatible with the
* <auth_md4Sum()> function in the MD4 module.
*
* The MD5 algorithm is designed to work on data with an
* arbitrary *bit* length. Most implementations, this one
* included, handle the input data in byte-sized chunks.
*
* The MD5 algorithm does much of its work using four-byte
* words, and so can be tuned for speed based on the endian-ness
* of the host. This implementation is intended to be
* endian-neutral, which may make it a teeny bit slower than
* others. ...maybe.
*
* See Also: <auth_md5InitCtx()>
*
* ------------------------------------------------------------------------ **
*/
{
auth_md5Ctx ctx[1];
FILE * file;
unsigned int blksize = 0;
unsigned int read = 0;
unsigned int filesize;
unsigned char* buffer;
file = fopen(src, "rb");
if (file == NULL)
{
return NULL;
}
(void) auth_md5InitCtx(ctx); /* Open a context. */
fseek(file, 0, SEEK_END);
filesize = ftell(file);
rewind(file);
if (filesize < 1048576) //1MB cache for files bigger than 1 MB
blksize = filesize;
else blksize = 1048576;
buffer = malloc(blksize);
if (buffer == NULL)
{
//no memory
fclose(file);
return NULL;
}
do
{
read = fread(buffer, 1, blksize, file);
(void) auth_md5SumCtx(ctx, buffer, read); /* Pass only one block. */
} while (read > 0);
fclose(file);
free(buffer);
(void) auth_md5CloseCtx(ctx, dst); /* Close the context. */
return (dst); /* Makes life easy. */
} /* auth_md5Sum */
const char * MD5ToString(const unsigned char * hash, char * dst)
{
char hexchar[3];
short i = 0, n = 0;
for (i = 0; i < 16; i++)
{
sprintf(hexchar, "%02X", hash[i]);
dst[n++] = hexchar[0];
dst[n++] = hexchar[1];
}
dst[n] = 0x00;
return dst;
}
unsigned char * StringToMD5(const char * hash, unsigned char * dst)
{
char hexchar[2];
short i = 0, n = 0;
for (i = 0; i < 16; i++)
{
hexchar[0] = hash[n++];
hexchar[1] = hash[n++];
dst[i] = STR2HEX( hexchar[0] );
dst[i] <<= 4;
dst[i] += STR2HEX( hexchar[1] );
}
return dst;
}
/* ========================================================================== */

396
src/sha1.cpp Normal file
View File

@ -0,0 +1,396 @@
/*
* sha1.c
*
* Copyright (C) 1998, 2009
* Paul E. Jones <paulej@packetizer.com>
* All Rights Reserved
*
*****************************************************************************
* $Id: sha1.c 12 2009-06-22 19:34:25Z paulej $
*****************************************************************************
*
* Description:
* This file implements the Secure Hashing Standard as defined
* in FIPS PUB 180-1 published April 17, 1995.
*
* The Secure Hashing Standard, which uses the Secure Hashing
* Algorithm (SHA), produces a 160-bit message digest for a
* given data stream. In theory, it is highly improbable that
* two messages will produce the same message digest. 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 was
* written with the expectation that the processor has at least
* a 32-bit machine word size. If the machine word size is larger,
* the code should still function properly. One caveat to that
* is that the input functions taking u8acters and u8acter
* arrays assume that only 8 bits of information are stored in each
* u8acter.
*
* 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 u8acter.
*
*/
#include "sha1.h"
#include <string.h>
#include <utility.hpp>
/*
* Define the circular shift macro
*/
#define SHA1CircularShift(bits,word) \
((((word) << (bits)) & 0xFFFFFFFF) | \
((word) >> (32-(bits))))
/* Function prototypes */
void SHA1ProcessMessageBlock(SHA1Context *);
void SHA1PadMessage(SHA1Context *);
/*
* SHA1Reset
*
* Description:
* This function will initialize the SHA1Context in preparation
* for computing a new message digest.
*
* Parameters:
* context: [in/out]
* The context to reset.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1Reset(SHA1Context *context)
{
context->Length_Low = 0;
context->Length_High = 0;
context->Message_Block_Index = 0;
context->Message_Digest[0] = 0x67452301;
context->Message_Digest[1] = 0xEFCDAB89;
context->Message_Digest[2] = 0x98BADCFE;
context->Message_Digest[3] = 0x10325476;
context->Message_Digest[4] = 0xC3D2E1F0;
context->Computed = 0;
context->Corrupted = 0;
}
/*
* SHA1Result
*
* Description:
* This function will return the 160-bit message digest into the
* Message_Digest array within the SHA1Context provided
*
* Parameters:
* context: [in/out]
* The context to use to calculate the SHA-1 hash.
*
* Returns:
* 1 if successful, 0 if it failed.
*
* Comments:
*
*/
int SHA1Result(SHA1Context *context)
{
if (context->Corrupted)
{
return 0;
}
if (!context->Computed)
{
SHA1PadMessage(context);
context->Computed = 1;
}
return 1;
}
/*
* SHA1Input
*
* Description:
* This function accepts an array of octets as the next portion of
* the message.
*
* Parameters:
* context: [in/out]
* The SHA-1 context to update
* message_array: [in]
* An array of u8acters representing the next portion of the
* message.
* length: [in]
* The length of the message in message_array
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1Input( SHA1Context *context,
const unsigned char *message_array,
unsigned length)
{
if (!length)
{
return;
}
if (context->Computed || context->Corrupted)
{
context->Corrupted = 1;
return;
}
while(length-- && !context->Corrupted)
{
context->Message_Block[context->Message_Block_Index++] =
(*message_array & 0xFF);
context->Length_Low += 8;
/* Force it to 32 bits */
context->Length_Low &= 0xFFFFFFFF;
if (context->Length_Low == 0)
{
context->Length_High++;
/* Force it to 32 bits */
context->Length_High &= 0xFFFFFFFF;
if (context->Length_High == 0)
{
/* Message is too long */
context->Corrupted = 1;
}
}
if (context->Message_Block_Index == 64)
{
SHA1ProcessMessageBlock(context);
}
message_array++;
}
}
/*
* 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 the SHAContext, especially the
* single u8acter names, were used because those were the names
* used in the publication.
*
*
*/
void SHA1ProcessMessageBlock(SHA1Context *context)
{
const unsigned K[] = /* Constants defined in SHA-1 */
{
0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6
};
int t; /* Loop counter */
unsigned temp; /* Temporary word value */
unsigned W[80]; /* Word sequence */
unsigned A, B, C, D, E; /* Word buffers */
/*
* Initialize the first 16 words in the array W
*/
for(t = 0; t < 16; t++)
{
W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;
W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;
W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;
W[t] |= ((unsigned) 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->Message_Digest[0];
B = context->Message_Digest[1];
C = context->Message_Digest[2];
D = context->Message_Digest[3];
E = context->Message_Digest[4];
for(t = 0; t < 20; t++)
{
temp = SHA1CircularShift(5,A) +
((B & C) | ((~B) & D)) + E + W[t] + K[0];
temp &= 0xFFFFFFFF;
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];
temp &= 0xFFFFFFFF;
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];
temp &= 0xFFFFFFFF;
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];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
context->Message_Digest[0] =
(context->Message_Digest[0] + A) & 0xFFFFFFFF;
context->Message_Digest[1] =
(context->Message_Digest[1] + B) & 0xFFFFFFFF;
context->Message_Digest[2] =
(context->Message_Digest[2] + C) & 0xFFFFFFFF;
context->Message_Digest[3] =
(context->Message_Digest[3] + D) & 0xFFFFFFFF;
context->Message_Digest[4] =
(context->Message_Digest[4] + E) & 0xFFFFFFFF;
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 SHA1ProcessMessageBlock()
* appropriately. When it returns, it can be assumed that the
* message digest has been computed.
*
* Parameters:
* context: [in/out]
* The context to pad
*
* Returns:
* Nothing.
*
* Comments:
*
*/
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) & 0xFF;
context->Message_Block[57] = (context->Length_High >> 16) & 0xFF;
context->Message_Block[58] = (context->Length_High >> 8) & 0xFF;
context->Message_Block[59] = (context->Length_High) & 0xFF;
context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF;
context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF;
context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF;
context->Message_Block[63] = (context->Length_Low) & 0xFF;
SHA1ProcessMessageBlock(context);
}
Uint8* getSha1( Uint8 * stuff, Uint32 stuff_size )
{
SHA1Context sha;
SHA1Reset( &sha );
SHA1Input( &sha, (const Uint8*)stuff, stuff_size );
if( !SHA1Result( &sha ) )
return 0;
Uint8* ret = new Uint8[20];
memset(ret, 0, 20);
for( int i = 0; i < 5 ; i++ )
{
int val = sha.Message_Digest[ i ];
if (!isSystemBigEndian())
val = swap32(val);
memcpy( (char*)ret + ( i * 4 ), &val, 4 );
}
return ret;
}