mirror of https://github.com/libAthena/athena.git
* Merge libwiisave with libzelda
This commit is contained in:
parent
1e2065b352
commit
24f6a1715a
|
@ -132,7 +132,7 @@ public:
|
||||||
* \param str The string to write to the buffer
|
* \param str The string to write to the buffer
|
||||||
*/
|
*/
|
||||||
void writeUnicode(const std::string& str);
|
void writeUnicode(const std::string& str);
|
||||||
private:
|
protected:
|
||||||
Int8 readByte();
|
Int8 readByte();
|
||||||
Int8* readBytes(Int64);
|
Int8* readBytes(Int64);
|
||||||
bool isOpenForReading();
|
bool isOpenForReading();
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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__
|
|
@ -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__
|
|
@ -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_
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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 */
|
|
@ -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
|
|
@ -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>
|
31
libzelda.pro
31
libzelda.pro
|
@ -7,6 +7,9 @@ INCLUDEPATH += include
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
include/utility.hpp \
|
include/utility.hpp \
|
||||||
include/utf8.h \
|
include/utf8.h \
|
||||||
|
include/utf8/unchecked.h \
|
||||||
|
include/utf8/core.h \
|
||||||
|
include/utf8/checked.h \
|
||||||
include/Types.hpp \
|
include/Types.hpp \
|
||||||
include/TextStream.hpp \
|
include/TextStream.hpp \
|
||||||
include/Stream.hpp \
|
include/Stream.hpp \
|
||||||
|
@ -17,16 +20,36 @@ HEADERS += \
|
||||||
include/Exception.hpp \
|
include/Exception.hpp \
|
||||||
include/BinaryWriter.hpp \
|
include/BinaryWriter.hpp \
|
||||||
include/BinaryReader.hpp \
|
include/BinaryReader.hpp \
|
||||||
include/utf8/unchecked.h \
|
include/WiiBanner.h \
|
||||||
include/utf8/core.h \
|
include/WiiBanner.hpp \
|
||||||
include/utf8/checked.h
|
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 += \
|
SOURCES += \
|
||||||
src/utility.cpp \
|
src/utility.cpp \
|
||||||
src/TextStream.cpp \
|
src/TextStream.cpp \
|
||||||
src/Stream.cpp \
|
src/Stream.cpp \
|
||||||
src/BinaryWriter.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("exec doxygen libzelda.conf")
|
||||||
system("cd doc/latex && make")
|
system("cd doc/latex && make")
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue