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.
426 lines
11 KiB
426 lines
11 KiB
/*
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
*/
|
|
|
|
/*
|
|
Blowfish algorythms: Bruce Schneier and Jim Conger
|
|
Bruce Schneier, 1996, Applied Cryptography, 2nd ed., John Wiley & Sons
|
|
Blowfish Eggdrop algorythms: Robey Pointer
|
|
|
|
Copyright (C) 1994 Bruce Schneier <schneier@counterpane.com>
|
|
Copyright (C) 1996 Jim Conger <jconger@cox.net>
|
|
Copyright (C) Robey Pointer <robey@lag.net>
|
|
*/
|
|
|
|
//---------------------------------------------------------------------------
|
|
#include <string.h>
|
|
#include "oldblowfish1.h"
|
|
#include "oldblowfish2.h"
|
|
//---------------------------------------------------------------------------
|
|
|
|
//---------------------------------------------------------------------------
|
|
#define S(x,i) (SBoxes[i][x.w.byte##i])
|
|
#define bf_F(x) (((S(x,0) + S(x,1)) ^ S(x,2)) + S(x,3))
|
|
#define ROUND(a,b,n) (a.dword ^= bf_F(b) ^ PArray[n])
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
oldCBlowFish::oldCBlowFish ()
|
|
{
|
|
PArray = new DWORD [18] ;
|
|
SBoxes = new DWORD [4][256] ;
|
|
}
|
|
|
|
oldCBlowFish::~oldCBlowFish ()
|
|
{
|
|
delete PArray ;
|
|
delete [] SBoxes ;
|
|
}
|
|
|
|
// the low level (private) encryption function
|
|
void oldCBlowFish::Blowfish_encipher (DWORD *xl, DWORD *xr)
|
|
{
|
|
union aword Xl, Xr ;
|
|
|
|
Xl.dword = *xl ;
|
|
Xr.dword = *xr ;
|
|
|
|
Xl.dword ^= PArray [0];
|
|
ROUND (Xr, Xl, 1) ; ROUND (Xl, Xr, 2) ;
|
|
ROUND (Xr, Xl, 3) ; ROUND (Xl, Xr, 4) ;
|
|
ROUND (Xr, Xl, 5) ; ROUND (Xl, Xr, 6) ;
|
|
ROUND (Xr, Xl, 7) ; ROUND (Xl, Xr, 8) ;
|
|
ROUND (Xr, Xl, 9) ; ROUND (Xl, Xr, 10) ;
|
|
ROUND (Xr, Xl, 11) ; ROUND (Xl, Xr, 12) ;
|
|
ROUND (Xr, Xl, 13) ; ROUND (Xl, Xr, 14) ;
|
|
ROUND (Xr, Xl, 15) ; ROUND (Xl, Xr, 16) ;
|
|
Xr.dword ^= PArray [17] ;
|
|
|
|
*xr = Xl.dword ;
|
|
*xl = Xr.dword ;
|
|
}
|
|
|
|
// the low level (private) decryption function
|
|
void oldCBlowFish::Blowfish_decipher (DWORD *xl, DWORD *xr)
|
|
{
|
|
union aword Xl ;
|
|
union aword Xr ;
|
|
|
|
Xl.dword = *xl ;
|
|
Xr.dword = *xr ;
|
|
|
|
Xl.dword ^= PArray [17] ;
|
|
ROUND (Xr, Xl, 16) ; ROUND (Xl, Xr, 15) ;
|
|
ROUND (Xr, Xl, 14) ; ROUND (Xl, Xr, 13) ;
|
|
ROUND (Xr, Xl, 12) ; ROUND (Xl, Xr, 11) ;
|
|
ROUND (Xr, Xl, 10) ; ROUND (Xl, Xr, 9) ;
|
|
ROUND (Xr, Xl, 8) ; ROUND (Xl, Xr, 7) ;
|
|
ROUND (Xr, Xl, 6) ; ROUND (Xl, Xr, 5) ;
|
|
ROUND (Xr, Xl, 4) ; ROUND (Xl, Xr, 3) ;
|
|
ROUND (Xr, Xl, 2) ; ROUND (Xl, Xr, 1) ;
|
|
Xr.dword ^= PArray[0];
|
|
|
|
*xl = Xr.dword;
|
|
*xr = Xl.dword;
|
|
}
|
|
|
|
|
|
// constructs the enctryption sieve
|
|
void oldCBlowFish::Initialize (BYTE key[], int keybytes)
|
|
{
|
|
int i, j ;
|
|
DWORD data, datal, datar ;
|
|
union aword temp ;
|
|
|
|
|
|
// ATTN: new fix for keys > 56, should make it more compatible with FISH
|
|
// but fish uses 80 ???
|
|
if (keybytes>MAXKEYBYTES_COMPATMODE)
|
|
keybytes=MAXKEYBYTES_COMPATMODE;
|
|
|
|
// first fill arrays from data tables
|
|
for (i = 0 ; i < 18 ; i++)
|
|
PArray [i] = bf_P [i] ;
|
|
|
|
for (i = 0 ; i < 4 ; i++)
|
|
{
|
|
for (j = 0 ; j < 256 ; j++)
|
|
SBoxes [i][j] = bf_S [i][j] ;
|
|
}
|
|
|
|
|
|
j = 0 ;
|
|
for (i = 0 ; i < NPASS + 2 ; ++i)
|
|
{
|
|
temp.dword = 0 ;
|
|
temp.w.byte0 = key[j];
|
|
temp.w.byte1 = key[(j+1) % keybytes] ;
|
|
temp.w.byte2 = key[(j+2) % keybytes] ;
|
|
temp.w.byte3 = key[(j+3) % keybytes] ;
|
|
data = temp.dword ;
|
|
PArray [i] ^= data ;
|
|
j = (j + 4) % keybytes ;
|
|
}
|
|
|
|
datal = 0 ;
|
|
datar = 0 ;
|
|
|
|
for (i = 0 ; i < NPASS + 2 ; i += 2)
|
|
{
|
|
Blowfish_encipher (&datal, &datar) ;
|
|
PArray [i] = datal ;
|
|
PArray [i + 1] = datar ;
|
|
}
|
|
|
|
for (i = 0 ; i < 4 ; ++i)
|
|
{
|
|
for (j = 0 ; j < 256 ; j += 2)
|
|
{
|
|
Blowfish_encipher (&datal, &datar) ;
|
|
SBoxes [i][j] = datal ;
|
|
SBoxes [i][j + 1] = datar ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// get output length, which must be even MOD 8
|
|
DWORD oldCBlowFish::GetOutputLength (DWORD lInputLong)
|
|
{
|
|
DWORD lVal ;
|
|
|
|
lVal = lInputLong % 8 ; // find out if uneven number of bytes at the end
|
|
if (lVal != 0)
|
|
return lInputLong + 8 - lVal ;
|
|
else
|
|
return lInputLong ;
|
|
}
|
|
|
|
|
|
// Encode pIntput into pOutput. Input length in lSize. Returned value
|
|
// is length of output which will be even MOD 8 bytes. Input buffer and
|
|
// output buffer can be the same, but be sure buffer length is even MOD 8.
|
|
DWORD oldCBlowFish::Encode (BYTE * pInput, BYTE * pOutput, DWORD lSize)
|
|
{
|
|
DWORD lCount, lOutSize, lGoodBytes ;
|
|
BYTE *pi, *po ;
|
|
int i, j ;
|
|
int SameDest = (pInput == pOutput ? 1 : 0) ;
|
|
|
|
lOutSize = GetOutputLength (lSize) ;
|
|
for (lCount = 0 ; lCount < lOutSize ; lCount += 8)
|
|
{
|
|
if (SameDest) // if encoded data is being written into input buffer
|
|
{
|
|
if (lCount < lSize - 7) // if not dealing with uneven bytes at end
|
|
{
|
|
Blowfish_encipher ((DWORD *) pInput,
|
|
(DWORD *) (pInput + 4)) ;
|
|
}
|
|
else // pad end of data with null bytes to complete encryption
|
|
{
|
|
po = pInput + lSize ; // point at byte past the end of actual data
|
|
j = (int) (lOutSize - lSize) ; // number of bytes to set to null
|
|
for (i = 0 ; i < j ; i++)
|
|
*po++ = 0 ;
|
|
Blowfish_encipher ((DWORD *) pInput,
|
|
(DWORD *) (pInput + 4)) ;
|
|
}
|
|
pInput += 8 ;
|
|
}
|
|
else // output buffer not equal to input buffer, so must copy
|
|
{ // input to output buffer prior to encrypting
|
|
if (lCount < lSize - 7) // if not dealing with uneven bytes at end
|
|
{
|
|
pi = pInput ;
|
|
po = pOutput ;
|
|
for (i = 0 ; i < 8 ; i++) // copy bytes to output
|
|
*po++ = *pi++ ;
|
|
Blowfish_encipher ((DWORD *) pOutput, // now encrypt them
|
|
(DWORD *) (pOutput + 4)) ;
|
|
}
|
|
else // pad end of data with null bytes to complete encryption
|
|
{
|
|
lGoodBytes = lSize - lCount ; // number of remaining data bytes
|
|
po = pOutput ;
|
|
for (i = 0 ; i < (int) lGoodBytes ; i++)
|
|
*po++ = *pInput++ ;
|
|
for (j = i ; j < 8 ; j++)
|
|
*po++ = 0 ;
|
|
Blowfish_encipher ((DWORD *) pOutput,
|
|
(DWORD *) (pOutput + 4)) ;
|
|
}
|
|
pInput += 8 ;
|
|
pOutput += 8 ;
|
|
}
|
|
}
|
|
return lOutSize ;
|
|
}
|
|
|
|
// Decode pIntput into pOutput. Input length in lSize. Input buffer and
|
|
// output buffer can be the same, but be sure buffer length is even MOD 8.
|
|
void oldCBlowFish::Decode (BYTE * pInput, BYTE * pOutput, DWORD lSize)
|
|
{
|
|
DWORD lCount ;
|
|
BYTE *pi, *po ;
|
|
int i ;
|
|
int SameDest = (pInput == pOutput ? 1 : 0) ;
|
|
|
|
for (lCount = 0 ; lCount < lSize ; lCount += 8)
|
|
{
|
|
if (SameDest) // if encoded data is being written into input buffer
|
|
{
|
|
Blowfish_decipher ((DWORD *) pInput,
|
|
(DWORD *) (pInput + 4)) ;
|
|
pInput += 8 ;
|
|
}
|
|
else // output buffer not equal to input buffer
|
|
{ // so copy input to output before decoding
|
|
pi = pInput ;
|
|
po = pOutput ;
|
|
for (i = 0 ; i < 8 ; i++)
|
|
*po++ = *pi++ ;
|
|
Blowfish_decipher ((DWORD *) pOutput,
|
|
(DWORD *) (pOutput + 4)) ;
|
|
pInput += 8 ;
|
|
pOutput += 8 ;
|
|
}
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// The following code is adapted from the eggdrop bot source:
|
|
// by Robey Pointer
|
|
// DR - as i understand this, what we have here is a function where you pass
|
|
// it a string(passphrase), and it convolutes it into an encrypted version
|
|
// (witout using a separate key). and you use this one-way encrypted
|
|
// string later, when you ask person for their passphrase. when they give
|
|
// you there passphrase, you call this again, and compare the two outputs.
|
|
// if the outputs are the same, then the inputs presumably were, and so
|
|
// passphrase is judged to match. In this way you can store one-way encrypted
|
|
// passphrases in plain files.
|
|
//
|
|
|
|
#define SALT1 0xdeadd061
|
|
#define SALT2 0x23f6b095
|
|
|
|
// Convert 64-bit encrypted passphrase to text for userfile
|
|
char base64[] = "./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
|
|
int base64dec(char c)
|
|
{
|
|
// updated 1/20/03 for speed improvement
|
|
static char base64unmap[255];
|
|
static bool didinit=false;
|
|
int i;
|
|
|
|
if (!didinit)
|
|
{
|
|
// initialize base64unmap
|
|
for (i=0;i<255;++i)
|
|
base64unmap[i]=0;
|
|
for (i=0;i<64;++i)
|
|
base64unmap[(int)base64[i]]=i;
|
|
didinit=true;
|
|
}
|
|
|
|
return base64unmap[(int)c];
|
|
}
|
|
|
|
void blowfish_encrypt_pass(char *text, char *str)
|
|
{
|
|
DWORD left,right;
|
|
int n;
|
|
char *p;
|
|
oldCBlowFish caca;
|
|
caca.Initialize((unsigned char*)text,strlen(text));
|
|
left = SALT1;
|
|
right = SALT2;
|
|
caca.Blowfish_encipher(&left, &right);
|
|
p = str;
|
|
*p++ = '+'; // + means encrypted pass
|
|
n = 32;
|
|
while (n > 0) {
|
|
*p++ = base64[right & 0x3f];
|
|
right = (right >> 6);
|
|
n -= 6;
|
|
}
|
|
n = 32;
|
|
while (n > 0) {
|
|
*p++ = base64[left & 0x3f];
|
|
left = (left >> 6);
|
|
n -= 6;
|
|
}
|
|
*p = 0;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// ORIGINAL COMPATIBLE (ECB) METHODS
|
|
|
|
char *encrypt_string_oldecb(char *key, char *str)
|
|
{
|
|
DWORD left, right;
|
|
unsigned char *p;
|
|
char *s, *dest, *d;
|
|
int i;
|
|
|
|
// Pad fake string with 8 bytes to make sure there's enough
|
|
s = new char[strlen(str) + 9];
|
|
strcpy(s, str);
|
|
if ((!key) || (!key[0]))
|
|
return s;
|
|
p = (unsigned char*)s;
|
|
dest = new char[(strlen(str) + 9) * 2];
|
|
while (*p)
|
|
p++;
|
|
for (i = 0; i < 8; i++)
|
|
*p++ = 0;
|
|
|
|
oldCBlowFish caca;
|
|
caca.Initialize((unsigned char*)key,strlen(key));
|
|
p = (unsigned char*)s;
|
|
d = dest;
|
|
while (*p) {
|
|
left = ((*p++) << 24);
|
|
left += ((*p++) << 16);
|
|
left += ((*p++) << 8);
|
|
left += (*p++);
|
|
right = ((*p++) << 24);
|
|
right += ((*p++) << 16);
|
|
right += ((*p++) << 8);
|
|
right += (*p++);
|
|
caca.Blowfish_encipher(&left, &right);
|
|
for (i = 0; i < 6; i++) {
|
|
*d++ = base64[right & 0x3f];
|
|
right = (right >> 6);
|
|
}
|
|
for (i = 0; i < 6; i++) {
|
|
*d++ = base64[left & 0x3f];
|
|
left = (left >> 6);
|
|
}
|
|
}
|
|
*d = 0;
|
|
delete s;
|
|
return dest;
|
|
}
|
|
|
|
|
|
// Returned string must be freed when done with it!
|
|
char *decrypt_string_oldecb(char *key, char *str)
|
|
{
|
|
DWORD left, right;
|
|
char *p, *s, *dest, *d;
|
|
int i;
|
|
|
|
// Pad encoded string with 0 bits in case it's bogus
|
|
s = new char[strlen(str) + 12];
|
|
strcpy(s, str);
|
|
if ((!key) || (!key[0]))
|
|
return s;
|
|
p = s;
|
|
dest = new char[strlen(str) + 12];
|
|
while (*p)
|
|
p++;
|
|
for (i = 0; i < 12; i++)
|
|
*p++ = 0;
|
|
oldCBlowFish caca;
|
|
caca.Initialize((unsigned char*)key,strlen(key));
|
|
p = s;
|
|
d = dest;
|
|
while (*p) {
|
|
right = 0L;
|
|
left = 0L;
|
|
for (i = 0; i < 6; i++)
|
|
right |= (base64dec(*p++)) << (i * 6);
|
|
for (i = 0; i < 6; i++)
|
|
left |= (base64dec(*p++)) << (i * 6);
|
|
caca.Blowfish_decipher(&left, &right);
|
|
for (i = 0; i < 4; i++)
|
|
*d++ = (char) ((left & (0xff << ((3 - i) * 8))) >> ((3 - i) * 8));
|
|
for (i = 0; i < 4; i++)
|
|
*d++ = (char) ((right & (0xff << ((3 - i) * 8))) >> ((3 - i) * 8));
|
|
}
|
|
*d = 0;
|
|
delete s;
|
|
return dest;
|
|
}
|
|
//---------------------------------------------------------------------------
|