add completed support for new aes encrypted image comments

This commit is contained in:
Hazim Gazov
2010-08-07 23:33:09 +00:00
parent 9ca534338c
commit 631d0ca9d2
3 changed files with 1605 additions and 34 deletions

1381
indra/llimage/aes.cpp Normal file

File diff suppressed because it is too large Load Diff

190
indra/llimage/aes.h Normal file
View File

@@ -0,0 +1,190 @@
//Rijndael.h
#ifndef __RIJNDAEL_H__
#define __RIJNDAEL_H__
#include <exception>
#include <string>
#include <cstring>
using namespace std;
//Rijndael (pronounced Reindaal) is a block cipher, designed by Joan Daemen and Vincent Rijmen as a candidate algorithm for the AES.
//The cipher has a variable block length and key length. The authors currently specify how to use keys with a length
//of 128, 192, or 256 bits to encrypt blocks with al length of 128, 192 or 256 bits (all nine combinations of
//key length and block length are possible). Both block length and key length can be extended very easily to
// multiples of 32 bits.
//Rijndael can be implemented very efficiently on a wide range of processors and in hardware.
//This implementation is based on the Java Implementation used with the Cryptix toolkit found at:
//http://www.esat.kuleuven.ac.be/~rijmen/rijndael/rijndael.zip
//Java code authors: Raif S. Naffah, Paulo S. L. M. Barreto
//This Implementation was tested against KAT test published by the authors of the method and the
//results were identical.
class CRijndael
{
public:
//Operation Modes
//The Electronic Code Book (ECB), Cipher Block Chaining (CBC) and Cipher Feedback Block (CFB) modes
//are implemented.
//In ECB mode if the same block is encrypted twice with the same key, the resulting
//ciphertext blocks are the same.
//In CBC Mode a ciphertext block is obtained by first xoring the
//plaintext block with the previous ciphertext block, and encrypting the resulting value.
//In CFB mode a ciphertext block is obtained by encrypting the previous ciphertext block
//and xoring the resulting value with the plaintext.
enum { ECB=0, CBC=1, CFB=2 };
private:
enum { DEFAULT_BLOCK_SIZE=16 };
enum { MAX_BLOCK_SIZE=32, MAX_ROUNDS=14, MAX_KC=8, MAX_BC=8 };
//Auxiliary Functions
//Multiply two elements of GF(2^m)
static int Mul(int a, int b)
{
return (a != 0 && b != 0) ? sm_alog[(sm_log[a & 0xFF] + sm_log[b & 0xFF]) % 255] : 0;
}
//Convenience method used in generating Transposition Boxes
static int Mul4(int a, char b[])
{
if(a == 0)
return 0;
a = sm_log[a & 0xFF];
int a0 = (b[0] != 0) ? sm_alog[(a + sm_log[b[0] & 0xFF]) % 255] & 0xFF : 0;
int a1 = (b[1] != 0) ? sm_alog[(a + sm_log[b[1] & 0xFF]) % 255] & 0xFF : 0;
int a2 = (b[2] != 0) ? sm_alog[(a + sm_log[b[2] & 0xFF]) % 255] & 0xFF : 0;
int a3 = (b[3] != 0) ? sm_alog[(a + sm_log[b[3] & 0xFF]) % 255] & 0xFF : 0;
return a0 << 24 | a1 << 16 | a2 << 8 | a3;
}
public:
//CONSTRUCTOR
CRijndael();
//DESTRUCTOR
virtual ~CRijndael();
//Expand a user-supplied key material into a session key.
// key - The 128/192/256-bit user-key to use.
// chain - initial chain block for CBC and CFB modes.
// keylength - 16, 24 or 32 bytes
// blockSize - The block size in bytes of this Rijndael (16, 24 or 32 bytes).
void MakeKey(char const* key, char const* chain, int keylength=DEFAULT_BLOCK_SIZE, int blockSize=DEFAULT_BLOCK_SIZE);
private:
//Auxiliary Function
void Xor(char* buff, char const* chain)
{
if(false==m_bKeyInit)
throw std::string(sm_szErrorMsg1);
for(int i=0; i<m_blockSize; i++)
*(buff++) ^= *(chain++);
}
//Convenience method to encrypt exactly one block of plaintext, assuming
//Rijndael's default block size (128-bit).
// in - The plaintext
// result - The ciphertext generated from a plaintext using the key
void DefEncryptBlock(char const* in, char* result);
//Convenience method to decrypt exactly one block of plaintext, assuming
//Rijndael's default block size (128-bit).
// in - The ciphertext.
// result - The plaintext generated from a ciphertext using the session key.
void DefDecryptBlock(char const* in, char* result);
public:
//Encrypt exactly one block of plaintext.
// in - The plaintext.
// result - The ciphertext generated from a plaintext using the key.
void EncryptBlock(char const* in, char* result);
//Decrypt exactly one block of ciphertext.
// in - The ciphertext.
// result - The plaintext generated from a ciphertext using the session key.
void DecryptBlock(char const* in, char* result);
void Encrypt(char const* in, char* result, size_t n, int iMode=ECB);
void Decrypt(char const* in, char* result, size_t n, int iMode=ECB);
//Get Key Length
int GetKeyLength()
{
if(false==m_bKeyInit)
throw std::string(sm_szErrorMsg1);
return m_keylength;
}
//Block Size
int GetBlockSize()
{
if(false==m_bKeyInit)
throw std::string(sm_szErrorMsg1);
return m_blockSize;
}
//Number of Rounds
int GetRounds()
{
if(false==m_bKeyInit)
throw std::string(sm_szErrorMsg1);
return m_iROUNDS;
}
void ResetChain()
{
memcpy(m_chain, m_chain0, m_blockSize);
}
public:
//Null chain
static char const* sm_chain0;
private:
static const int sm_alog[256];
static const int sm_log[256];
static const char sm_S[256];
static const char sm_Si[256];
static const int sm_T1[256];
static const int sm_T2[256];
static const int sm_T3[256];
static const int sm_T4[256];
static const int sm_T5[256];
static const int sm_T6[256];
static const int sm_T7[256];
static const int sm_T8[256];
static const int sm_U1[256];
static const int sm_U2[256];
static const int sm_U3[256];
static const int sm_U4[256];
static const char sm_rcon[30];
static const int sm_shifts[3][4][2];
//Error Messages
static char const* sm_szErrorMsg1;
static char const* sm_szErrorMsg2;
//Key Initialization Flag
bool m_bKeyInit;
//Encryption (m_Ke) round key
int m_Ke[MAX_ROUNDS+1][MAX_BC];
//Decryption (m_Kd) round key
int m_Kd[MAX_ROUNDS+1][MAX_BC];
//Key Length
int m_keylength;
//Block Size
int m_blockSize;
//Number of Rounds
int m_iROUNDS;
//Chain Block
char m_chain0[MAX_BLOCK_SIZE];
char m_chain[MAX_BLOCK_SIZE];
//Auxiliary private use buffers
int tk[MAX_KC];
int a[MAX_BC];
int t[MAX_BC];
};
#endif // __RIJNDAEL_H__

View File

@@ -4,7 +4,7 @@
#include "aes.h"
#include "llapr.h"
#include "llerror.h"
const unsigned char EMKDU_AES_KEY[] = {0x01,0x00,0x81,0x07,0x63,0x78,0xB6,0xFE,0x6E,0x3F,0xB0,0x12,0xCC,0x65,0x66,0xC1,
const char EMKDU_AES_KEY[] = {0x01,0x00,0x81,0x07,0x63,0x78,0xB6,0xFE,0x6E,0x3F,0xB0,0x12,0xCC,0x65,0x66,0xC1,
0x81,0x96,0xAC,0xC1,0x3B,0x66,0x0B,0xF7};
//#define COMMENT_DEBUGG1ING
LLJ2cParser::LLJ2cParser(U8* data,int data_size)
@@ -75,19 +75,33 @@ std::vector<U8> LLJ2cParser::GetNextComment()
return content;
}
//flow of control in this method is shit, gotta fix this... possibly return a vector or map instead of a string -HG
/*
Notes:
For anyone debugging this method, if a comment is not being decoded properly and you know encryption is being used,
the easiest thing to do is to create an LLAPRFile handle inside this method and write the contents of data to a file.
Normally the comment is going to be up near the header, just have a look at it in a hex editor.
It's generally going to be a string of 130 bytes preceeded by a null.
*/
//static
std::string LLImageMetaDataReader::ExtractEncodedComment(U8* data,int data_size)
unsigned int LLImageMetaDataReader::ExtractEncodedComment(U8* data,int data_size, std::string& output)
{
LLJ2cParser parser = LLJ2cParser(data,data_size);
#ifdef COMMENT_DEBUGGING
std::list<S32> lol;
#endif
std::string result;
std::string decodedComment;
//not supported yet, but why the hell not?
unsigned int result = ENC_NONE;
while(1)
{
std::vector<U8> comment = parser.GetNextComment();
if (comment.empty()) break; //exit loop
#ifndef COMMENT_DEBUGGING
if (comment[1] == 0x00 && comment.size() == 130)
{
bool xorComment = true;
@@ -107,6 +121,7 @@ std::string LLImageMetaDataReader::ExtractEncodedComment(U8* data,int data_size)
payload[i + 2] ^= payload[0];
payload[i + 3] ^= payload[2];
}
result = ENC_EMKDU_V1;
}
else if (payload[3] == payload[127])
{
@@ -118,6 +133,7 @@ std::string LLImageMetaDataReader::ExtractEncodedComment(U8* data,int data_size)
payload[i + 2] ^= payload[1];
payload[i + 3] ^= payload[3];
}
result = ENC_ONYXKDU;
}
else
{
@@ -130,7 +146,7 @@ std::string LLImageMetaDataReader::ExtractEncodedComment(U8* data,int data_size)
CRijndael aes;
try
{
aes.MakeKey(reinterpret_cast<const char*>(EMKDU_AES_KEY),"", 24, 16);
aes.MakeKey(EMKDU_AES_KEY,"", 24, 16);
} catch(std::string error)
{
llinfos << error << llendl;
@@ -167,11 +183,13 @@ std::string LLImageMetaDataReader::ExtractEncodedComment(U8* data,int data_size)
if (decrypted[i] == 0) break;
}
if(i == 0) continue;
if(result.length() > 0)
result.append(", ");
if(decodedComment.length() > 0)
decodedComment.append(", ");
result.append("(AES) ");
result.append(decrypted.begin(),decrypted.begin()+i);
//the way it's being done now, you can only specify the encryption type for the last comment.
//need to switch to a map<std::string, unsigned int> or a vector for output.
result = ENC_EMKDU_V2;
decodedComment.append(decrypted.begin(),decrypted.begin()+i);
}
else
{
@@ -180,34 +198,16 @@ std::string LLImageMetaDataReader::ExtractEncodedComment(U8* data,int data_size)
if (payload[i] == 0) break;
}
if(i < 4) continue;
if(result.length() > 0)
result.append(", ");
if(decodedComment.length() > 0)
decodedComment.append(", ");
result.append("(XOR) ");
result.append(payload.begin()+4,payload.begin()+i);
decodedComment.append(payload.begin()+4,payload.begin()+i);
}
//llinfos << "FOUND COMMENT: " << result << llendl;
}
#else
//std::string result(comment.begin(),comment.end());
//return result;
if (comment[1] == 0x00)
lol.push_back(comment.size());
#endif
}
#ifndef COMMENT_DEBUGGING
if(!result.empty())
llwarns << "AES Decryption Debugging: " << result << llendl;
//end of loop
output = decodedComment;
return result;
#else
std::string result;
for(std::list<S32>::iterator itr = lol.begin();itr != lol.end();itr++)
{
result += llformat("%d,",(*itr));
}
result += "end";
return result;
#endif
}
// </edit>