You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1511 lines
40 KiB
1511 lines
40 KiB
/*
|
|
Copyright (C) 2000-2001 Dawit Alemayehu <adawit@kde.org>
|
|
Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License (LGPL)
|
|
version 2 as published by the Free Software Foundation.
|
|
|
|
This program 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
RFC 1321 "MD5 Message-Digest Algorithm" Copyright (C) 1991-1992.
|
|
RSA Data Security, Inc. Created 1991. All rights reserved.
|
|
|
|
The KMD5 class is based on a C++ implementation of
|
|
"RSA Data Security, Inc. MD5 Message-Digest Algorithm" by
|
|
Mordechai T. Abzug, Copyright (c) 1995. This implementation
|
|
passes the test-suite as defined in RFC 1321.
|
|
|
|
The encoding and decoding utilities in KCodecs with the exception of
|
|
quoted-printable are based on the java implementation in HTTPClient
|
|
package by Ronald Tschalär Copyright (C) 1996-1999.
|
|
|
|
The quoted-printable codec as described in RFC 2045, section 6.7. is by
|
|
Rik Hemsley (C) 2001.
|
|
|
|
KMD4 class based on the LGPL code of Copyright (C) 2001 Nikos Mavroyanopoulos
|
|
The algorithm is due to Ron Rivest. This code is based on code
|
|
written by Colin Plumb in 1993.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <kdebug.h>
|
|
#include "kmdcodec.h"
|
|
|
|
#define KMD5_S11 7
|
|
#define KMD5_S12 12
|
|
#define KMD5_S13 17
|
|
#define KMD5_S14 22
|
|
#define KMD5_S21 5
|
|
#define KMD5_S22 9
|
|
#define KMD5_S23 14
|
|
#define KMD5_S24 20
|
|
#define KMD5_S31 4
|
|
#define KMD5_S32 11
|
|
#define KMD5_S33 16
|
|
#define KMD5_S34 23
|
|
#define KMD5_S41 6
|
|
#define KMD5_S42 10
|
|
#define KMD5_S43 15
|
|
#define KMD5_S44 21
|
|
|
|
const char KCodecs::Base64EncMap[64] =
|
|
{
|
|
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
|
|
0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
|
|
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
|
0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
|
|
0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
|
|
0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
|
|
0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33,
|
|
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F
|
|
};
|
|
|
|
const char KCodecs::Base64DecMap[128] =
|
|
{
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3F,
|
|
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
|
|
0x3C, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
|
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
|
|
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
|
0x17, 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
|
|
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
|
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
|
|
0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
const char KCodecs::UUEncMap[64] =
|
|
{
|
|
0x60, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
|
0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
|
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
|
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
|
0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
|
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
|
0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F
|
|
};
|
|
|
|
const char KCodecs::UUDecMap[128] =
|
|
{
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
|
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
|
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
|
0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
|
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
const char KCodecs::hexChars[16] =
|
|
{
|
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
|
};
|
|
|
|
const unsigned int KCodecs::maxQPLineLength = 70;
|
|
|
|
|
|
/******************************** KCodecs ********************************/
|
|
// strchr(3) for broken systems.
|
|
static int rikFindChar(register const char * _s, const char c)
|
|
{
|
|
register const char * s = _s;
|
|
|
|
while (true)
|
|
{
|
|
if ((0 == *s) || (c == *s)) break; ++s;
|
|
if ((0 == *s) || (c == *s)) break; ++s;
|
|
if ((0 == *s) || (c == *s)) break; ++s;
|
|
if ((0 == *s) || (c == *s)) break; ++s;
|
|
}
|
|
|
|
return s - _s;
|
|
}
|
|
|
|
QCString KCodecs::quotedPrintableEncode(const QByteArray& in, bool useCRLF)
|
|
{
|
|
QByteArray out;
|
|
quotedPrintableEncode (in, out, useCRLF);
|
|
return QCString (out.data(), out.size()+1);
|
|
}
|
|
|
|
QCString KCodecs::quotedPrintableEncode(const QCString& str, bool useCRLF)
|
|
{
|
|
if (str.isEmpty())
|
|
return "";
|
|
|
|
QByteArray in (str.length());
|
|
memcpy (in.data(), str.data(), str.length());
|
|
return quotedPrintableEncode(in, useCRLF);
|
|
}
|
|
|
|
void KCodecs::quotedPrintableEncode(const QByteArray& in, QByteArray& out, bool useCRLF)
|
|
{
|
|
out.resize (0);
|
|
if (in.isEmpty())
|
|
return;
|
|
|
|
char *cursor;
|
|
const char *data;
|
|
unsigned int lineLength;
|
|
unsigned int pos;
|
|
|
|
const unsigned int length = in.size();
|
|
const unsigned int end = length - 1;
|
|
|
|
|
|
// Reasonable guess for output size when we're encoding
|
|
// mostly-ASCII data. It doesn't really matter, because
|
|
// the underlying allocation routines are quite efficient,
|
|
// but it's nice to have 0 allocations in many cases.
|
|
out.resize ((length*12)/10);
|
|
cursor = out.data();
|
|
data = in.data();
|
|
lineLength = 0;
|
|
pos = 0;
|
|
|
|
for (unsigned int i = 0; i < length; i++)
|
|
{
|
|
unsigned char c (data[i]);
|
|
|
|
// check if we have to enlarge the output buffer, use
|
|
// a safety margin of 16 byte
|
|
pos = cursor-out.data();
|
|
if (out.size()-pos < 16) {
|
|
out.resize(out.size()+4096);
|
|
cursor = out.data()+pos;
|
|
}
|
|
|
|
// Plain ASCII chars just go straight out.
|
|
|
|
if ((c >= 33) && (c <= 126) && ('=' != c))
|
|
{
|
|
*cursor++ = c;
|
|
++lineLength;
|
|
}
|
|
|
|
// Spaces need some thought. We have to encode them at eol (or eof).
|
|
|
|
else if (' ' == c)
|
|
{
|
|
if
|
|
(
|
|
(i >= length)
|
|
||
|
|
((i < end) && ((useCRLF && ('\r' == data[i + 1]) && ('\n' == data[i + 2]))
|
|
||
|
|
(!useCRLF && ('\n' == data[i + 1]))))
|
|
)
|
|
{
|
|
*cursor++ = '=';
|
|
*cursor++ = '2';
|
|
*cursor++ = '0';
|
|
|
|
lineLength += 3;
|
|
}
|
|
else
|
|
{
|
|
*cursor++ = ' ';
|
|
++lineLength;
|
|
}
|
|
}
|
|
// If we find a line break, just let it through.
|
|
else if ((useCRLF && ('\r' == c) && (i < end) && ('\n' == data[i + 1])) ||
|
|
(!useCRLF && ('\n' == c)))
|
|
{
|
|
lineLength = 0;
|
|
|
|
if (useCRLF) {
|
|
*cursor++ = '\r';
|
|
*cursor++ = '\n';
|
|
++i;
|
|
} else {
|
|
*cursor++ = '\n';
|
|
}
|
|
}
|
|
|
|
// Anything else is converted to =XX.
|
|
|
|
else
|
|
{
|
|
*cursor++ = '=';
|
|
*cursor++ = hexChars[c / 16];
|
|
*cursor++ = hexChars[c % 16];
|
|
|
|
lineLength += 3;
|
|
}
|
|
|
|
// If we're approaching the maximum line length, do a soft line break.
|
|
|
|
if ((lineLength > maxQPLineLength) && (i < end))
|
|
{
|
|
if (useCRLF) {
|
|
*cursor++ = '=';
|
|
*cursor++ = '\r';
|
|
*cursor++ = '\n';
|
|
} else {
|
|
*cursor++ = '=';
|
|
*cursor++ = '\n';
|
|
}
|
|
|
|
lineLength = 0;
|
|
}
|
|
}
|
|
|
|
out.truncate(cursor - out.data());
|
|
}
|
|
|
|
QCString KCodecs::quotedPrintableDecode(const QByteArray & in)
|
|
{
|
|
QByteArray out;
|
|
quotedPrintableDecode (in, out);
|
|
return QCString (out.data(), out.size()+1);
|
|
}
|
|
|
|
QCString KCodecs::quotedPrintableDecode(const QCString & str)
|
|
{
|
|
if (str.isEmpty())
|
|
return "";
|
|
|
|
QByteArray in (str.length());
|
|
memcpy (in.data(), str.data(), str.length());
|
|
return quotedPrintableDecode (in);
|
|
}
|
|
|
|
void KCodecs::quotedPrintableDecode(const QByteArray& in, QByteArray& out)
|
|
{
|
|
// clear out the output buffer
|
|
out.resize (0);
|
|
if (in.isEmpty())
|
|
return;
|
|
|
|
char *cursor;
|
|
const char *data;
|
|
const unsigned int length = in.size();
|
|
|
|
data = in.data();
|
|
out.resize (length);
|
|
cursor = out.data();
|
|
|
|
for (unsigned int i = 0; i < length; i++)
|
|
{
|
|
char c(in[i]);
|
|
|
|
if ('=' == c)
|
|
{
|
|
if (i < length - 2)
|
|
{
|
|
char c1 = in[i + 1];
|
|
char c2 = in[i + 2];
|
|
|
|
if (('\n' == c1) || ('\r' == c1 && '\n' == c2))
|
|
{
|
|
// Soft line break. No output.
|
|
if ('\r' == c1)
|
|
i += 2; // CRLF line breaks
|
|
else
|
|
i += 1;
|
|
}
|
|
else
|
|
{
|
|
// =XX encoded byte.
|
|
|
|
int hexChar0 = rikFindChar(hexChars, c1);
|
|
int hexChar1 = rikFindChar(hexChars, c2);
|
|
|
|
if (hexChar0 < 16 && hexChar1 < 16)
|
|
{
|
|
*cursor++ = char((hexChar0 * 16) | hexChar1);
|
|
i += 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*cursor++ = c;
|
|
}
|
|
}
|
|
|
|
out.truncate(cursor - out.data());
|
|
}
|
|
|
|
QCString KCodecs::base64Encode( const QCString& str, bool insertLFs )
|
|
{
|
|
if ( str.isEmpty() )
|
|
return "";
|
|
|
|
QByteArray in (str.length());
|
|
memcpy( in.data(), str.data(), str.length() );
|
|
return base64Encode( in, insertLFs );
|
|
}
|
|
|
|
QCString KCodecs::base64Encode( const QByteArray& in, bool insertLFs )
|
|
{
|
|
QByteArray out;
|
|
base64Encode( in, out, insertLFs );
|
|
return QCString( out.data(), out.size()+1 );
|
|
}
|
|
|
|
void KCodecs::base64Encode( const QByteArray& in, QByteArray& out,
|
|
bool insertLFs )
|
|
{
|
|
// clear out the output buffer
|
|
out.resize (0);
|
|
if ( in.isEmpty() )
|
|
return;
|
|
|
|
unsigned int sidx = 0;
|
|
unsigned int didx = 0;
|
|
const char* data = in.data();
|
|
const unsigned int len = in.size();
|
|
|
|
unsigned int out_len = ((len+2)/3)*4;
|
|
|
|
// Deal with the 76 characters or less per
|
|
// line limit specified in RFC 2045 on a
|
|
// pre request basis.
|
|
insertLFs = (insertLFs && out_len > 76);
|
|
if ( insertLFs )
|
|
out_len += ((out_len-1)/76);
|
|
|
|
int count = 0;
|
|
out.resize( out_len );
|
|
|
|
// 3-byte to 4-byte conversion + 0-63 to ascii printable conversion
|
|
if ( len > 1 )
|
|
{
|
|
while (sidx < len-2)
|
|
{
|
|
if ( insertLFs )
|
|
{
|
|
if ( count && (count%76) == 0 )
|
|
out[didx++] = '\n';
|
|
count += 4;
|
|
}
|
|
out[didx++] = Base64EncMap[(data[sidx] >> 2) & 077];
|
|
out[didx++] = Base64EncMap[(data[sidx+1] >> 4) & 017 |
|
|
(data[sidx] << 4) & 077];
|
|
out[didx++] = Base64EncMap[(data[sidx+2] >> 6) & 003 |
|
|
(data[sidx+1] << 2) & 077];
|
|
out[didx++] = Base64EncMap[data[sidx+2] & 077];
|
|
sidx += 3;
|
|
}
|
|
}
|
|
|
|
if (sidx < len)
|
|
{
|
|
if ( insertLFs && (count > 0) && (count%76) == 0 )
|
|
out[didx++] = '\n';
|
|
|
|
out[didx++] = Base64EncMap[(data[sidx] >> 2) & 077];
|
|
if (sidx < len-1)
|
|
{
|
|
out[didx++] = Base64EncMap[(data[sidx+1] >> 4) & 017 |
|
|
(data[sidx] << 4) & 077];
|
|
out[didx++] = Base64EncMap[(data[sidx+1] << 2) & 077];
|
|
}
|
|
else
|
|
{
|
|
out[didx++] = Base64EncMap[(data[sidx] << 4) & 077];
|
|
}
|
|
}
|
|
|
|
// Add padding
|
|
while (didx < out.size())
|
|
{
|
|
out[didx] = '=';
|
|
didx++;
|
|
}
|
|
}
|
|
|
|
QCString KCodecs::base64Decode( const QCString& str )
|
|
{
|
|
if ( str.isEmpty() )
|
|
return "";
|
|
|
|
QByteArray in( str.length() );
|
|
memcpy( in.data(), str.data(), str.length() );
|
|
return base64Decode( in );
|
|
}
|
|
|
|
QCString KCodecs::base64Decode( const QByteArray& in )
|
|
{
|
|
QByteArray out;
|
|
base64Decode( in, out );
|
|
return QCString( out.data(), out.size()+1 );
|
|
}
|
|
|
|
void KCodecs::base64Decode( const QByteArray& in, QByteArray& out )
|
|
{
|
|
out.resize(0);
|
|
if ( in.isEmpty() )
|
|
return;
|
|
|
|
unsigned int count = 0;
|
|
unsigned int len = in.size(), tail = len;
|
|
const char* data = in.data();
|
|
|
|
// Deal with possible *nix "BEGIN" marker!!
|
|
while ( count < len && (data[count] == '\n' || data[count] == '\r' ||
|
|
data[count] == '\t' || data[count] == ' ') )
|
|
count++;
|
|
|
|
if ( count == len )
|
|
return;
|
|
|
|
if ( strncasecmp(data+count, "begin", 5) == 0 )
|
|
{
|
|
count += 5;
|
|
while ( count < len && data[count] != '\n' && data[count] != '\r' )
|
|
count++;
|
|
|
|
while ( count < len && (data[count] == '\n' || data[count] == '\r') )
|
|
count ++;
|
|
|
|
data += count;
|
|
tail = (len -= count);
|
|
}
|
|
|
|
// Find the tail end of the actual encoded data even if
|
|
// there is/are trailing CR and/or LF.
|
|
while ( tail > 0
|
|
&& ( data[tail-1] == '=' || data[tail-1] == '\n' || data[tail-1] == '\r' ) )
|
|
if ( data[--tail] != '=' ) len = tail;
|
|
|
|
unsigned int outIdx = 0;
|
|
out.resize( (count=len) );
|
|
for (unsigned int idx = 0; idx < count; idx++)
|
|
{
|
|
// Adhere to RFC 2045 and ignore characters
|
|
// that are not part of the encoding table.
|
|
unsigned char ch = data[idx];
|
|
if ((ch > 47 && ch < 58) || (ch > 64 && ch < 91) ||
|
|
(ch > 96 && ch < 123) || ch == '+' || ch == '/' || ch == '=')
|
|
{
|
|
out[outIdx++] = Base64DecMap[ch];
|
|
}
|
|
else
|
|
{
|
|
len--;
|
|
tail--;
|
|
}
|
|
}
|
|
|
|
// kdDebug() << "Tail size = " << tail << ", Length size = " << len << endl;
|
|
|
|
// 4-byte to 3-byte conversion
|
|
len = (tail>(len/4)) ? tail-(len/4) : 0;
|
|
unsigned int sidx = 0, didx = 0;
|
|
if ( len > 1 )
|
|
{
|
|
while (didx < len-2)
|
|
{
|
|
out[didx] = (((out[sidx] << 2) & 255) | ((out[sidx+1] >> 4) & 003));
|
|
out[didx+1] = (((out[sidx+1] << 4) & 255) | ((out[sidx+2] >> 2) & 017));
|
|
out[didx+2] = (((out[sidx+2] << 6) & 255) | (out[sidx+3] & 077));
|
|
sidx += 4;
|
|
didx += 3;
|
|
}
|
|
}
|
|
|
|
if (didx < len)
|
|
out[didx] = (((out[sidx] << 2) & 255) | ((out[sidx+1] >> 4) & 003));
|
|
|
|
if (++didx < len )
|
|
out[didx] = (((out[sidx+1] << 4) & 255) | ((out[sidx+2] >> 2) & 017));
|
|
|
|
// Resize the output buffer
|
|
if ( len == 0 || len < out.size() )
|
|
out.resize(len);
|
|
}
|
|
|
|
QCString KCodecs::uuencode( const QCString& str )
|
|
{
|
|
if ( str.isEmpty() )
|
|
return "";
|
|
|
|
QByteArray in;
|
|
in.resize( str.length() );
|
|
memcpy( in.data(), str.data(), str.length() );
|
|
return uuencode( in );
|
|
}
|
|
|
|
QCString KCodecs::uuencode( const QByteArray& in )
|
|
{
|
|
QByteArray out;
|
|
uuencode( in, out );
|
|
return QCString( out.data(), out.size()+1 );
|
|
}
|
|
|
|
void KCodecs::uuencode( const QByteArray& in, QByteArray& out )
|
|
{
|
|
out.resize( 0 );
|
|
if( in.isEmpty() )
|
|
return;
|
|
|
|
unsigned int sidx = 0;
|
|
unsigned int didx = 0;
|
|
unsigned int line_len = 45;
|
|
|
|
const char nl[] = "\n";
|
|
const char* data = in.data();
|
|
const unsigned int nl_len = strlen(nl);
|
|
const unsigned int len = in.size();
|
|
|
|
out.resize( (len+2)/3*4 + ((len+line_len-1)/line_len)*(nl_len+1) );
|
|
// split into lines, adding line-length and line terminator
|
|
while (sidx+line_len < len)
|
|
{
|
|
// line length
|
|
out[didx++] = UUEncMap[line_len];
|
|
|
|
// 3-byte to 4-byte conversion + 0-63 to ascii printable conversion
|
|
for (unsigned int end = sidx+line_len; sidx < end; sidx += 3)
|
|
{
|
|
out[didx++] = UUEncMap[(data[sidx] >> 2) & 077];
|
|
out[didx++] = UUEncMap[(data[sidx+1] >> 4) & 017 |
|
|
(data[sidx] << 4) & 077];
|
|
out[didx++] = UUEncMap[(data[sidx+2] >> 6) & 003 |
|
|
(data[sidx+1] << 2) & 077];
|
|
out[didx++] = UUEncMap[data[sidx+2] & 077];
|
|
}
|
|
|
|
// line terminator
|
|
//for (unsigned int idx=0; idx < nl_len; idx++)
|
|
//out[didx++] = nl[idx];
|
|
memcpy(out.data()+didx, nl, nl_len);
|
|
didx += nl_len;
|
|
}
|
|
|
|
// line length
|
|
out[didx++] = UUEncMap[len-sidx];
|
|
// 3-byte to 4-byte conversion + 0-63 to ascii printable conversion
|
|
while (sidx+2 < len)
|
|
{
|
|
out[didx++] = UUEncMap[(data[sidx] >> 2) & 077];
|
|
out[didx++] = UUEncMap[(data[sidx+1] >> 4) & 017 |
|
|
(data[sidx] << 4) & 077];
|
|
out[didx++] = UUEncMap[(data[sidx+2] >> 6) & 003 |
|
|
(data[sidx+1] << 2) & 077];
|
|
out[didx++] = UUEncMap[data[sidx+2] & 077];
|
|
sidx += 3;
|
|
}
|
|
|
|
if (sidx < len-1)
|
|
{
|
|
out[didx++] = UUEncMap[(data[sidx] >> 2) & 077];
|
|
out[didx++] = UUEncMap[(data[sidx+1] >> 4) & 017 |
|
|
(data[sidx] << 4) & 077];
|
|
out[didx++] = UUEncMap[(data[sidx+1] << 2) & 077];
|
|
out[didx++] = UUEncMap[0];
|
|
}
|
|
else if (sidx < len)
|
|
{
|
|
out[didx++] = UUEncMap[(data[sidx] >> 2) & 077];
|
|
out[didx++] = UUEncMap[(data[sidx] << 4) & 077];
|
|
out[didx++] = UUEncMap[0];
|
|
out[didx++] = UUEncMap[0];
|
|
}
|
|
|
|
// line terminator
|
|
memcpy(out.data()+didx, nl, nl_len);
|
|
didx += nl_len;
|
|
|
|
// sanity check
|
|
if ( didx != out.size() )
|
|
out.resize( 0 );
|
|
}
|
|
|
|
QCString KCodecs::uudecode( const QCString& str )
|
|
{
|
|
if ( str.isEmpty() )
|
|
return "";
|
|
|
|
QByteArray in;
|
|
in.resize( str.length() );
|
|
memcpy( in.data(), str.data(), str.length() );
|
|
return uudecode( in );
|
|
}
|
|
|
|
QCString KCodecs::uudecode( const QByteArray& in )
|
|
{
|
|
QByteArray out;
|
|
uudecode( in, out );
|
|
return QCString( out.data(), out.size()+1 );
|
|
}
|
|
|
|
void KCodecs::uudecode( const QByteArray& in, QByteArray& out )
|
|
{
|
|
out.resize( 0 );
|
|
if( in.isEmpty() )
|
|
return;
|
|
|
|
unsigned int sidx = 0;
|
|
unsigned int didx = 0;
|
|
unsigned int len = in.size();
|
|
unsigned int line_len, end;
|
|
const char* data = in.data();
|
|
|
|
// Deal with *nix "BEGIN"/"END" separators!!
|
|
unsigned int count = 0;
|
|
while ( count < len && (data[count] == '\n' || data[count] == '\r' ||
|
|
data[count] == '\t' || data[count] == ' ') )
|
|
count ++;
|
|
|
|
bool hasLF = false;
|
|
if ( strncasecmp( data+count, "begin", 5) == 0 )
|
|
{
|
|
count += 5;
|
|
while ( count < len && data[count] != '\n' && data[count] != '\r' )
|
|
count ++;
|
|
|
|
while ( count < len && (data[count] == '\n' || data[count] == '\r') )
|
|
count ++;
|
|
|
|
data += count;
|
|
len -= count;
|
|
hasLF = true;
|
|
}
|
|
|
|
out.resize( len/4*3 );
|
|
while ( sidx < len )
|
|
{
|
|
// get line length (in number of encoded octets)
|
|
line_len = UUDecMap[ (unsigned char) data[sidx++]];
|
|
// ascii printable to 0-63 and 4-byte to 3-byte conversion
|
|
end = didx+line_len;
|
|
char A, B, C, D;
|
|
if (end > 2) {
|
|
while (didx < end-2)
|
|
{
|
|
A = UUDecMap[(unsigned char) data[sidx]];
|
|
B = UUDecMap[(unsigned char) data[sidx+1]];
|
|
C = UUDecMap[(unsigned char) data[sidx+2]];
|
|
D = UUDecMap[(unsigned char) data[sidx+3]];
|
|
out[didx++] = ( ((A << 2) & 255) | ((B >> 4) & 003) );
|
|
out[didx++] = ( ((B << 4) & 255) | ((C >> 2) & 017) );
|
|
out[didx++] = ( ((C << 6) & 255) | (D & 077) );
|
|
sidx += 4;
|
|
}
|
|
}
|
|
|
|
if (didx < end)
|
|
{
|
|
A = UUDecMap[(unsigned char) data[sidx]];
|
|
B = UUDecMap[(unsigned char) data[sidx+1]];
|
|
out[didx++] = ( ((A << 2) & 255) | ((B >> 4) & 003) );
|
|
}
|
|
|
|
if (didx < end)
|
|
{
|
|
B = UUDecMap[(unsigned char) data[sidx+1]];
|
|
C = UUDecMap[(unsigned char) data[sidx+2]];
|
|
out[didx++] = ( ((B << 4) & 255) | ((C >> 2) & 017) );
|
|
}
|
|
|
|
// skip padding
|
|
while (sidx < len && data[sidx] != '\n' && data[sidx] != '\r')
|
|
sidx++;
|
|
|
|
// skip end of line
|
|
while (sidx < len && (data[sidx] == '\n' || data[sidx] == '\r'))
|
|
sidx++;
|
|
|
|
// skip the "END" separator when present.
|
|
if ( hasLF && strncasecmp( data+sidx, "end", 3) == 0 )
|
|
break;
|
|
}
|
|
|
|
if ( didx < out.size() )
|
|
out.resize( didx );
|
|
}
|
|
|
|
/******************************** KMD5 ********************************/
|
|
KMD5::KMD5()
|
|
{
|
|
init();
|
|
}
|
|
|
|
KMD5::KMD5(const char *in, int len)
|
|
{
|
|
init();
|
|
update(in, len);
|
|
}
|
|
|
|
KMD5::KMD5(const QByteArray& in)
|
|
{
|
|
init();
|
|
update( in );
|
|
}
|
|
|
|
KMD5::KMD5(const QCString& in)
|
|
{
|
|
init();
|
|
update( in );
|
|
}
|
|
|
|
void KMD5::update(const QByteArray& in)
|
|
{
|
|
update(in.data(), int(in.size()));
|
|
}
|
|
|
|
void KMD5::update(const QCString& in)
|
|
{
|
|
update(in.data(), int(in.length()));
|
|
}
|
|
|
|
void KMD5::update(const unsigned char* in, int len)
|
|
{
|
|
if (len < 0)
|
|
len = qstrlen(reinterpret_cast<const char*>(in));
|
|
|
|
if (!len)
|
|
return;
|
|
|
|
if (m_finalized) {
|
|
kdWarning() << "KMD5::update called after state was finalized!" << endl;
|
|
return;
|
|
}
|
|
|
|
Q_UINT32 in_index;
|
|
Q_UINT32 buffer_index;
|
|
Q_UINT32 buffer_space;
|
|
Q_UINT32 in_length = static_cast<Q_UINT32>( len );
|
|
|
|
buffer_index = static_cast<Q_UINT32>((m_count[0] >> 3) & 0x3F);
|
|
|
|
if ( (m_count[0] += (in_length << 3))<(in_length << 3) )
|
|
m_count[1]++;
|
|
|
|
m_count[1] += (in_length >> 29);
|
|
buffer_space = 64 - buffer_index;
|
|
|
|
if (in_length >= buffer_space)
|
|
{
|
|
memcpy (m_buffer + buffer_index, in, buffer_space);
|
|
transform (m_buffer);
|
|
|
|
for (in_index = buffer_space; in_index + 63 < in_length;
|
|
in_index += 64)
|
|
transform (reinterpret_cast<const unsigned char*>(in+in_index));
|
|
|
|
buffer_index = 0;
|
|
}
|
|
else
|
|
in_index=0;
|
|
|
|
memcpy(m_buffer+buffer_index, in+in_index, in_length-in_index);
|
|
}
|
|
|
|
bool KMD5::update(QIODevice& file)
|
|
{
|
|
char buffer[1024];
|
|
int len;
|
|
|
|
while ((len=file.readBlock(reinterpret_cast<char*>(buffer), sizeof(buffer))) > 0)
|
|
update(buffer, len);
|
|
|
|
return file.atEnd();
|
|
}
|
|
|
|
void KMD5::finalize ()
|
|
{
|
|
if (m_finalized) return;
|
|
|
|
Q_UINT8 bits[8];
|
|
Q_UINT32 index, padLen;
|
|
static const unsigned char PADDING[64]=
|
|
{
|
|
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
};
|
|
|
|
encode (bits, m_count, 8);
|
|
//memcpy( bits, m_count, 8 );
|
|
|
|
// Pad out to 56 mod 64.
|
|
index = static_cast<Q_UINT32>((m_count[0] >> 3) & 0x3f);
|
|
padLen = (index < 56) ? (56 - index) : (120 - index);
|
|
update (reinterpret_cast<const char*>(PADDING), padLen);
|
|
|
|
// Append length (before padding)
|
|
update (reinterpret_cast<const char*>(bits), 8);
|
|
|
|
// Store state in digest
|
|
encode (m_digest, m_state, 16);
|
|
//memcpy( m_digest, m_state, 16 );
|
|
|
|
// Fill sensitive information with zero's
|
|
memset ( (void *)m_buffer, 0, sizeof(*m_buffer));
|
|
|
|
m_finalized = true;
|
|
}
|
|
|
|
|
|
bool KMD5::verify( const KMD5::Digest& digest)
|
|
{
|
|
finalize();
|
|
return (0 == memcmp(rawDigest(), digest, sizeof(KMD5::Digest)));
|
|
}
|
|
|
|
bool KMD5::verify( const QCString& hexdigest)
|
|
{
|
|
finalize();
|
|
return (0 == strcmp(hexDigest().data(), hexdigest));
|
|
}
|
|
|
|
const KMD5::Digest& KMD5::rawDigest()
|
|
{
|
|
finalize();
|
|
return m_digest;
|
|
}
|
|
|
|
void KMD5::rawDigest( KMD5::Digest& bin )
|
|
{
|
|
finalize();
|
|
memcpy( bin, m_digest, 16 );
|
|
}
|
|
|
|
|
|
QCString KMD5::hexDigest()
|
|
{
|
|
QCString s(33);
|
|
|
|
finalize();
|
|
sprintf(s.data(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
|
m_digest[0], m_digest[1], m_digest[2], m_digest[3], m_digest[4], m_digest[5],
|
|
m_digest[6], m_digest[7], m_digest[8], m_digest[9], m_digest[10], m_digest[11],
|
|
m_digest[12], m_digest[13], m_digest[14], m_digest[15]);
|
|
|
|
return s;
|
|
}
|
|
|
|
void KMD5::hexDigest(QCString& s)
|
|
{
|
|
finalize();
|
|
s.resize(33);
|
|
sprintf(s.data(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
|
m_digest[0], m_digest[1], m_digest[2], m_digest[3], m_digest[4], m_digest[5],
|
|
m_digest[6], m_digest[7], m_digest[8], m_digest[9], m_digest[10], m_digest[11],
|
|
m_digest[12], m_digest[13], m_digest[14], m_digest[15]);
|
|
}
|
|
|
|
QCString KMD5::base64Digest()
|
|
{
|
|
QByteArray ba(16);
|
|
|
|
finalize();
|
|
memcpy(ba.data(), m_digest, 16);
|
|
return KCodecs::base64Encode(ba);
|
|
}
|
|
|
|
|
|
void KMD5::init()
|
|
{
|
|
d = 0;
|
|
reset();
|
|
}
|
|
|
|
void KMD5::reset()
|
|
{
|
|
m_finalized = false;
|
|
|
|
m_count[0] = 0;
|
|
m_count[1] = 0;
|
|
|
|
m_state[0] = 0x67452301;
|
|
m_state[1] = 0xefcdab89;
|
|
m_state[2] = 0x98badcfe;
|
|
m_state[3] = 0x10325476;
|
|
|
|
memset ( m_buffer, 0, sizeof(*m_buffer));
|
|
memset ( m_digest, 0, sizeof(*m_digest));
|
|
}
|
|
|
|
void KMD5::transform( const unsigned char block[64] )
|
|
{
|
|
|
|
Q_UINT32 a = m_state[0], b = m_state[1], c = m_state[2], d = m_state[3], x[16];
|
|
|
|
decode (x, block, 64);
|
|
//memcpy( x, block, 64 );
|
|
|
|
Q_ASSERT(!m_finalized); // not just a user error, since the method is private
|
|
|
|
/* Round 1 */
|
|
FF (a, b, c, d, x[ 0], KMD5_S11, 0xd76aa478); /* 1 */
|
|
FF (d, a, b, c, x[ 1], KMD5_S12, 0xe8c7b756); /* 2 */
|
|
FF (c, d, a, b, x[ 2], KMD5_S13, 0x242070db); /* 3 */
|
|
FF (b, c, d, a, x[ 3], KMD5_S14, 0xc1bdceee); /* 4 */
|
|
FF (a, b, c, d, x[ 4], KMD5_S11, 0xf57c0faf); /* 5 */
|
|
FF (d, a, b, c, x[ 5], KMD5_S12, 0x4787c62a); /* 6 */
|
|
FF (c, d, a, b, x[ 6], KMD5_S13, 0xa8304613); /* 7 */
|
|
FF (b, c, d, a, x[ 7], KMD5_S14, 0xfd469501); /* 8 */
|
|
FF (a, b, c, d, x[ 8], KMD5_S11, 0x698098d8); /* 9 */
|
|
FF (d, a, b, c, x[ 9], KMD5_S12, 0x8b44f7af); /* 10 */
|
|
FF (c, d, a, b, x[10], KMD5_S13, 0xffff5bb1); /* 11 */
|
|
FF (b, c, d, a, x[11], KMD5_S14, 0x895cd7be); /* 12 */
|
|
FF (a, b, c, d, x[12], KMD5_S11, 0x6b901122); /* 13 */
|
|
FF (d, a, b, c, x[13], KMD5_S12, 0xfd987193); /* 14 */
|
|
FF (c, d, a, b, x[14], KMD5_S13, 0xa679438e); /* 15 */
|
|
FF (b, c, d, a, x[15], KMD5_S14, 0x49b40821); /* 16 */
|
|
|
|
/* Round 2 */
|
|
GG (a, b, c, d, x[ 1], KMD5_S21, 0xf61e2562); /* 17 */
|
|
GG (d, a, b, c, x[ 6], KMD5_S22, 0xc040b340); /* 18 */
|
|
GG (c, d, a, b, x[11], KMD5_S23, 0x265e5a51); /* 19 */
|
|
GG (b, c, d, a, x[ 0], KMD5_S24, 0xe9b6c7aa); /* 20 */
|
|
GG (a, b, c, d, x[ 5], KMD5_S21, 0xd62f105d); /* 21 */
|
|
GG (d, a, b, c, x[10], KMD5_S22, 0x2441453); /* 22 */
|
|
GG (c, d, a, b, x[15], KMD5_S23, 0xd8a1e681); /* 23 */
|
|
GG (b, c, d, a, x[ 4], KMD5_S24, 0xe7d3fbc8); /* 24 */
|
|
GG (a, b, c, d, x[ 9], KMD5_S21, 0x21e1cde6); /* 25 */
|
|
GG (d, a, b, c, x[14], KMD5_S22, 0xc33707d6); /* 26 */
|
|
GG (c, d, a, b, x[ 3], KMD5_S23, 0xf4d50d87); /* 27 */
|
|
GG (b, c, d, a, x[ 8], KMD5_S24, 0x455a14ed); /* 28 */
|
|
GG (a, b, c, d, x[13], KMD5_S21, 0xa9e3e905); /* 29 */
|
|
GG (d, a, b, c, x[ 2], KMD5_S22, 0xfcefa3f8); /* 30 */
|
|
GG (c, d, a, b, x[ 7], KMD5_S23, 0x676f02d9); /* 31 */
|
|
GG (b, c, d, a, x[12], KMD5_S24, 0x8d2a4c8a); /* 32 */
|
|
|
|
/* Round 3 */
|
|
HH (a, b, c, d, x[ 5], KMD5_S31, 0xfffa3942); /* 33 */
|
|
HH (d, a, b, c, x[ 8], KMD5_S32, 0x8771f681); /* 34 */
|
|
HH (c, d, a, b, x[11], KMD5_S33, 0x6d9d6122); /* 35 */
|
|
HH (b, c, d, a, x[14], KMD5_S34, 0xfde5380c); /* 36 */
|
|
HH (a, b, c, d, x[ 1], KMD5_S31, 0xa4beea44); /* 37 */
|
|
HH (d, a, b, c, x[ 4], KMD5_S32, 0x4bdecfa9); /* 38 */
|
|
HH (c, d, a, b, x[ 7], KMD5_S33, 0xf6bb4b60); /* 39 */
|
|
HH (b, c, d, a, x[10], KMD5_S34, 0xbebfbc70); /* 40 */
|
|
HH (a, b, c, d, x[13], KMD5_S31, 0x289b7ec6); /* 41 */
|
|
HH (d, a, b, c, x[ 0], KMD5_S32, 0xeaa127fa); /* 42 */
|
|
HH (c, d, a, b, x[ 3], KMD5_S33, 0xd4ef3085); /* 43 */
|
|
HH (b, c, d, a, x[ 6], KMD5_S34, 0x4881d05); /* 44 */
|
|
HH (a, b, c, d, x[ 9], KMD5_S31, 0xd9d4d039); /* 45 */
|
|
HH (d, a, b, c, x[12], KMD5_S32, 0xe6db99e5); /* 46 */
|
|
HH (c, d, a, b, x[15], KMD5_S33, 0x1fa27cf8); /* 47 */
|
|
HH (b, c, d, a, x[ 2], KMD5_S34, 0xc4ac5665); /* 48 */
|
|
|
|
/* Round 4 */
|
|
II (a, b, c, d, x[ 0], KMD5_S41, 0xf4292244); /* 49 */
|
|
II (d, a, b, c, x[ 7], KMD5_S42, 0x432aff97); /* 50 */
|
|
II (c, d, a, b, x[14], KMD5_S43, 0xab9423a7); /* 51 */
|
|
II (b, c, d, a, x[ 5], KMD5_S44, 0xfc93a039); /* 52 */
|
|
II (a, b, c, d, x[12], KMD5_S41, 0x655b59c3); /* 53 */
|
|
II (d, a, b, c, x[ 3], KMD5_S42, 0x8f0ccc92); /* 54 */
|
|
II (c, d, a, b, x[10], KMD5_S43, 0xffeff47d); /* 55 */
|
|
II (b, c, d, a, x[ 1], KMD5_S44, 0x85845dd1); /* 56 */
|
|
II (a, b, c, d, x[ 8], KMD5_S41, 0x6fa87e4f); /* 57 */
|
|
II (d, a, b, c, x[15], KMD5_S42, 0xfe2ce6e0); /* 58 */
|
|
II (c, d, a, b, x[ 6], KMD5_S43, 0xa3014314); /* 59 */
|
|
II (b, c, d, a, x[13], KMD5_S44, 0x4e0811a1); /* 60 */
|
|
II (a, b, c, d, x[ 4], KMD5_S41, 0xf7537e82); /* 61 */
|
|
II (d, a, b, c, x[11], KMD5_S42, 0xbd3af235); /* 62 */
|
|
II (c, d, a, b, x[ 2], KMD5_S43, 0x2ad7d2bb); /* 63 */
|
|
II (b, c, d, a, x[ 9], KMD5_S44, 0xeb86d391); /* 64 */
|
|
|
|
m_state[0] += a;
|
|
m_state[1] += b;
|
|
m_state[2] += c;
|
|
m_state[3] += d;
|
|
|
|
memset ( static_cast<void *>(x), 0, sizeof(x) );
|
|
}
|
|
|
|
inline Q_UINT32 KMD5::rotate_left (Q_UINT32 x, Q_UINT32 n)
|
|
{
|
|
return (x << n) | (x >> (32-n)) ;
|
|
}
|
|
|
|
inline Q_UINT32 KMD5::F (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z)
|
|
{
|
|
return (x & y) | (~x & z);
|
|
}
|
|
|
|
inline Q_UINT32 KMD5::G (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z)
|
|
{
|
|
return (x & z) | (y & ~z);
|
|
}
|
|
|
|
inline Q_UINT32 KMD5::H (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z)
|
|
{
|
|
return x ^ y ^ z;
|
|
}
|
|
|
|
inline Q_UINT32 KMD5::I (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z)
|
|
{
|
|
return y ^ (x | ~z);
|
|
}
|
|
|
|
void KMD5::FF ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d,
|
|
Q_UINT32 x, Q_UINT32 s, Q_UINT32 ac )
|
|
{
|
|
a += F(b, c, d) + x + ac;
|
|
a = rotate_left (a, s) +b;
|
|
}
|
|
|
|
void KMD5::GG ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d,
|
|
Q_UINT32 x, Q_UINT32 s, Q_UINT32 ac)
|
|
{
|
|
a += G(b, c, d) + x + ac;
|
|
a = rotate_left (a, s) +b;
|
|
}
|
|
|
|
void KMD5::HH ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d,
|
|
Q_UINT32 x, Q_UINT32 s, Q_UINT32 ac )
|
|
{
|
|
a += H(b, c, d) + x + ac;
|
|
a = rotate_left (a, s) +b;
|
|
}
|
|
|
|
void KMD5::II ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d,
|
|
Q_UINT32 x, Q_UINT32 s, Q_UINT32 ac )
|
|
{
|
|
a += I(b, c, d) + x + ac;
|
|
a = rotate_left (a, s) +b;
|
|
}
|
|
|
|
|
|
void KMD5::encode ( unsigned char* output, Q_UINT32 *in, Q_UINT32 len )
|
|
{
|
|
#if !defined(WORDS_BIGENDIAN)
|
|
memcpy(output, in, len);
|
|
|
|
#else
|
|
Q_UINT32 i, j;
|
|
for (i = 0, j = 0; j < len; i++, j += 4)
|
|
{
|
|
output[j] = static_cast<Q_UINT8>((in[i] & 0xff));
|
|
output[j+1] = static_cast<Q_UINT8>(((in[i] >> 8) & 0xff));
|
|
output[j+2] = static_cast<Q_UINT8>(((in[i] >> 16) & 0xff));
|
|
output[j+3] = static_cast<Q_UINT8>(((in[i] >> 24) & 0xff));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Decodes in (Q_UINT8) into output (Q_UINT32). Assumes len is a
|
|
// multiple of 4.
|
|
void KMD5::decode (Q_UINT32 *output, const unsigned char* in, Q_UINT32 len)
|
|
{
|
|
#if !defined(WORDS_BIGENDIAN)
|
|
memcpy(output, in, len);
|
|
|
|
#else
|
|
Q_UINT32 i, j;
|
|
for (i = 0, j = 0; j < len; i++, j += 4)
|
|
output[i] = static_cast<Q_UINT32>(in[j]) |
|
|
(static_cast<Q_UINT32>(in[j+1]) << 8) |
|
|
(static_cast<Q_UINT32>(in[j+2]) << 16) |
|
|
(static_cast<Q_UINT32>(in[j+3]) << 24);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************/
|
|
|
|
|
|
|
|
/***********************************************************/
|
|
|
|
KMD4::KMD4()
|
|
{
|
|
init();
|
|
}
|
|
|
|
KMD4::KMD4(const char *in, int len)
|
|
{
|
|
init();
|
|
update(in, len);
|
|
}
|
|
|
|
KMD4::KMD4(const QByteArray& in)
|
|
{
|
|
init();
|
|
update( in );
|
|
}
|
|
|
|
KMD4::KMD4(const QCString& in)
|
|
{
|
|
init();
|
|
update( in );
|
|
}
|
|
|
|
void KMD4::update(const QByteArray& in)
|
|
{
|
|
update(in.data(), int(in.size()));
|
|
}
|
|
|
|
void KMD4::update(const QCString& in)
|
|
{
|
|
update(in.data(), int(in.length()));
|
|
}
|
|
|
|
/*
|
|
* Update context to reflect the concatenation of another buffer full
|
|
* of bytes.
|
|
*/
|
|
void KMD4::update(const unsigned char *in, int len)
|
|
{
|
|
if (len < 0)
|
|
len = qstrlen(reinterpret_cast<const char*>(in));
|
|
|
|
if (!len)
|
|
return;
|
|
|
|
if (m_finalized) {
|
|
kdWarning() << "KMD4::update called after state was finalized!" << endl;
|
|
return;
|
|
}
|
|
|
|
Q_UINT32 t;
|
|
|
|
/* Update bitcount */
|
|
|
|
t = m_count[0];
|
|
if ((m_count[0] = t + ((Q_UINT32) len << 3)) < t)
|
|
m_count[1]++; /* Carry from low to high */
|
|
m_count[1] += len >> 29;
|
|
|
|
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
|
|
|
/* Handle any leading odd-sized chunks */
|
|
|
|
if (t)
|
|
{
|
|
Q_UINT8 *p = &m_buffer[ t ];
|
|
|
|
t = 64 - t;
|
|
if ((Q_UINT32)len < t)
|
|
{
|
|
memcpy (p, in, len);
|
|
return;
|
|
}
|
|
memcpy (p, in, t);
|
|
byteReverse (m_buffer, 16);
|
|
transform (m_state, (Q_UINT32*) m_buffer);
|
|
in += t;
|
|
len -= t;
|
|
}
|
|
/* Process data in 64-byte chunks */
|
|
|
|
while (len >= 64)
|
|
{
|
|
memcpy (m_buffer, in, 64);
|
|
byteReverse (m_buffer, 16);
|
|
transform (m_state, (Q_UINT32 *) m_buffer);
|
|
in += 64;
|
|
len -= 64;
|
|
}
|
|
|
|
/* Handle any remaining bytes of data. */
|
|
|
|
memcpy (m_buffer, in, len);
|
|
}
|
|
|
|
bool KMD4::update(QIODevice& file)
|
|
{
|
|
char buffer[1024];
|
|
int len;
|
|
|
|
while ((len=file.readBlock(reinterpret_cast<char*>(buffer), sizeof(buffer))) > 0)
|
|
update(buffer, len);
|
|
|
|
return file.atEnd();
|
|
}
|
|
|
|
/*
|
|
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
|
* 1 0* (64-bit count of bits processed, MSB-first)
|
|
*/
|
|
void KMD4::finalize()
|
|
{
|
|
unsigned int count;
|
|
unsigned char *p;
|
|
|
|
/* Compute number of bytes mod 64 */
|
|
count = (m_count[0] >> 3) & 0x3F;
|
|
|
|
/* Set the first char of padding to 0x80. This is safe since there is
|
|
always at least one byte free */
|
|
p = m_buffer + count;
|
|
*p++ = 0x80;
|
|
|
|
/* Bytes of padding needed to make 64 bytes */
|
|
count = 64 - 1 - count;
|
|
|
|
/* Pad out to 56 mod 64 */
|
|
if (count < 8)
|
|
{
|
|
/* Two lots of padding: Pad the first block to 64 bytes */
|
|
memset (p, 0, count);
|
|
byteReverse (m_buffer, 16);
|
|
transform (m_state, (Q_UINT32*) m_buffer);
|
|
|
|
/* Now fill the next block with 56 bytes */
|
|
memset (m_buffer, 0, 56);
|
|
}
|
|
else
|
|
{
|
|
/* Pad block to 56 bytes */
|
|
memset (p, 0, count - 8);
|
|
}
|
|
byteReverse (m_buffer, 14);
|
|
|
|
/* Append length in bits and transform */
|
|
((Q_UINT32 *) m_buffer)[14] = m_count[0];
|
|
((Q_UINT32 *) m_buffer)[15] = m_count[1];
|
|
|
|
transform (m_state, (Q_UINT32 *) m_buffer);
|
|
byteReverse ((unsigned char *) m_state, 4);
|
|
|
|
memcpy (m_digest, m_state, 16);
|
|
memset ( (void *)m_buffer, 0, sizeof(*m_buffer));
|
|
|
|
m_finalized = true;
|
|
}
|
|
|
|
bool KMD4::verify( const KMD4::Digest& digest)
|
|
{
|
|
finalize();
|
|
return (0 == memcmp(rawDigest(), digest, sizeof(KMD4::Digest)));
|
|
}
|
|
|
|
bool KMD4::verify( const QCString& hexdigest)
|
|
{
|
|
finalize();
|
|
return (0 == strcmp(hexDigest().data(), hexdigest));
|
|
}
|
|
|
|
const KMD4::Digest& KMD4::rawDigest()
|
|
{
|
|
finalize();
|
|
return m_digest;
|
|
}
|
|
|
|
void KMD4::rawDigest( KMD4::Digest& bin )
|
|
{
|
|
finalize();
|
|
memcpy( bin, m_digest, 16 );
|
|
}
|
|
|
|
QCString KMD4::hexDigest()
|
|
{
|
|
QCString s(33);
|
|
|
|
finalize();
|
|
sprintf(s.data(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
|
m_digest[0], m_digest[1], m_digest[2], m_digest[3], m_digest[4], m_digest[5],
|
|
m_digest[6], m_digest[7], m_digest[8], m_digest[9], m_digest[10], m_digest[11],
|
|
m_digest[12], m_digest[13], m_digest[14], m_digest[15]);
|
|
// kdDebug() << "KMD4::hexDigest() " << s << endl;
|
|
return s;
|
|
}
|
|
|
|
void KMD4::hexDigest(QCString& s)
|
|
{
|
|
finalize();
|
|
s.resize(33);
|
|
sprintf(s.data(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
|
m_digest[0], m_digest[1], m_digest[2], m_digest[3], m_digest[4], m_digest[5],
|
|
m_digest[6], m_digest[7], m_digest[8], m_digest[9], m_digest[10], m_digest[11],
|
|
m_digest[12], m_digest[13], m_digest[14], m_digest[15]);
|
|
}
|
|
|
|
QCString KMD4::base64Digest()
|
|
{
|
|
QByteArray ba(16);
|
|
|
|
finalize();
|
|
memcpy(ba.data(), m_digest, 16);
|
|
return KCodecs::base64Encode(ba);
|
|
}
|
|
|
|
|
|
void KMD4::init()
|
|
{
|
|
d = 0;
|
|
reset();
|
|
}
|
|
|
|
/*
|
|
* Start MD4 accumulation. Set bit count to 0 and buffer to mysterious
|
|
* initialization constants.
|
|
*/
|
|
void KMD4::reset()
|
|
{
|
|
m_finalized = false;
|
|
|
|
m_state[0] = 0x67452301;
|
|
m_state[1] = 0xefcdab89;
|
|
m_state[2] = 0x98badcfe;
|
|
m_state[3] = 0x10325476;
|
|
|
|
m_count[0] = 0;
|
|
m_count[1] = 0;
|
|
|
|
memset ( m_buffer, 0, sizeof(*m_buffer));
|
|
memset ( m_digest, 0, sizeof(*m_digest));
|
|
}
|
|
|
|
//#define rotl32(x,n) (((x) << ((Q_UINT32)(n))) | ((x) >> (32 - (Q_UINT32)(n))))
|
|
|
|
inline Q_UINT32 KMD4::rotate_left (Q_UINT32 x, Q_UINT32 n)
|
|
{
|
|
return (x << n) | (x >> (32-n)) ;
|
|
}
|
|
|
|
inline Q_UINT32 KMD4::F (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z)
|
|
{
|
|
return (x & y) | (~x & z);
|
|
}
|
|
|
|
inline Q_UINT32 KMD4::G (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z)
|
|
{
|
|
return ((x) & (y)) | ((x) & (z)) | ((y) & (z));
|
|
}
|
|
|
|
inline Q_UINT32 KMD4::H (Q_UINT32 x, Q_UINT32 y, Q_UINT32 z)
|
|
{
|
|
return x ^ y ^ z;
|
|
}
|
|
|
|
inline void KMD4::FF ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d,
|
|
Q_UINT32 x, Q_UINT32 s )
|
|
{
|
|
a += F(b, c, d) + x;
|
|
a = rotate_left (a, s);
|
|
}
|
|
|
|
inline void KMD4::GG ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d,
|
|
Q_UINT32 x, Q_UINT32 s)
|
|
{
|
|
a += G(b, c, d) + x + (Q_UINT32)0x5a827999;
|
|
a = rotate_left (a, s);
|
|
}
|
|
|
|
inline void KMD4::HH ( Q_UINT32& a, Q_UINT32 b, Q_UINT32 c, Q_UINT32 d,
|
|
Q_UINT32 x, Q_UINT32 s )
|
|
{
|
|
a += H(b, c, d) + x + (Q_UINT32)0x6ed9eba1;
|
|
a = rotate_left (a, s);
|
|
}
|
|
|
|
void KMD4::byteReverse( unsigned char *buf, Q_UINT32 len )
|
|
{
|
|
#ifdef WORDS_BIGENDIAN
|
|
Q_UINT32 *b = (Q_UINT32*) buf;
|
|
while ( len > 0 ) {
|
|
*b = ((((*b) & 0xff000000) >> 24) | (((*b) & 0x00ff0000) >> 8) |
|
|
(((*b) & 0x0000ff00) << 8) | (((*b) & 0x000000ff) << 24));
|
|
len--;
|
|
b++;
|
|
}
|
|
#else
|
|
Q_UNUSED(buf)
|
|
Q_UNUSED(len)
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* The core of the MD4 algorithm
|
|
*/
|
|
void KMD4::transform( Q_UINT32 buf[4], Q_UINT32 const in[16] )
|
|
{
|
|
Q_UINT32 a, b, c, d;
|
|
|
|
a = buf[0];
|
|
b = buf[1];
|
|
c = buf[2];
|
|
d = buf[3];
|
|
|
|
FF (a, b, c, d, in[0], 3); /* 1 */
|
|
FF (d, a, b, c, in[1], 7); /* 2 */
|
|
FF (c, d, a, b, in[2], 11); /* 3 */
|
|
FF (b, c, d, a, in[3], 19); /* 4 */
|
|
FF (a, b, c, d, in[4], 3); /* 5 */
|
|
FF (d, a, b, c, in[5], 7); /* 6 */
|
|
FF (c, d, a, b, in[6], 11); /* 7 */
|
|
FF (b, c, d, a, in[7], 19); /* 8 */
|
|
FF (a, b, c, d, in[8], 3); /* 9 */
|
|
FF (d, a, b, c, in[9], 7); /* 10 */
|
|
FF (c, d, a, b, in[10], 11); /* 11 */
|
|
FF (b, c, d, a, in[11], 19); /* 12 */
|
|
FF (a, b, c, d, in[12], 3); /* 13 */
|
|
FF (d, a, b, c, in[13], 7); /* 14 */
|
|
FF (c, d, a, b, in[14], 11); /* 15 */
|
|
FF (b, c, d, a, in[15], 19); /* 16 */
|
|
|
|
GG (a, b, c, d, in[0], 3); /* 17 */
|
|
GG (d, a, b, c, in[4], 5); /* 18 */
|
|
GG (c, d, a, b, in[8], 9); /* 19 */
|
|
GG (b, c, d, a, in[12], 13); /* 20 */
|
|
GG (a, b, c, d, in[1], 3); /* 21 */
|
|
GG (d, a, b, c, in[5], 5); /* 22 */
|
|
GG (c, d, a, b, in[9], 9); /* 23 */
|
|
GG (b, c, d, a, in[13], 13); /* 24 */
|
|
GG (a, b, c, d, in[2], 3); /* 25 */
|
|
GG (d, a, b, c, in[6], 5); /* 26 */
|
|
GG (c, d, a, b, in[10], 9); /* 27 */
|
|
GG (b, c, d, a, in[14], 13); /* 28 */
|
|
GG (a, b, c, d, in[3], 3); /* 29 */
|
|
GG (d, a, b, c, in[7], 5); /* 30 */
|
|
GG (c, d, a, b, in[11], 9); /* 31 */
|
|
GG (b, c, d, a, in[15], 13); /* 32 */
|
|
|
|
HH (a, b, c, d, in[0], 3); /* 33 */
|
|
HH (d, a, b, c, in[8], 9); /* 34 */
|
|
HH (c, d, a, b, in[4], 11); /* 35 */
|
|
HH (b, c, d, a, in[12], 15); /* 36 */
|
|
HH (a, b, c, d, in[2], 3); /* 37 */
|
|
HH (d, a, b, c, in[10], 9); /* 38 */
|
|
HH (c, d, a, b, in[6], 11); /* 39 */
|
|
HH (b, c, d, a, in[14], 15); /* 40 */
|
|
HH (a, b, c, d, in[1], 3); /* 41 */
|
|
HH (d, a, b, c, in[9], 9); /* 42 */
|
|
HH (c, d, a, b, in[5], 11); /* 43 */
|
|
HH (b, c, d, a, in[13], 15); /* 44 */
|
|
HH (a, b, c, d, in[3], 3); /* 45 */
|
|
HH (d, a, b, c, in[11], 9); /* 46 */
|
|
HH (c, d, a, b, in[7], 11); /* 47 */
|
|
HH (b, c, d, a, in[15], 15); /* 48 */
|
|
|
|
|
|
buf[0] += a;
|
|
buf[1] += b;
|
|
buf[2] += c;
|
|
buf[3] += d;
|
|
}
|