openmohaa/code/gamespy/serverbrowsing/sb_crypt.c
2023-02-04 21:00:01 +01:00

212 lines
6.6 KiB
C

#include <stdlib.h>
#include <string.h>
#include "sb_crypt.h"
static unsigned char keyrand(GOACryptState *state, int limit,
unsigned char *user_key,
unsigned char keysize,
unsigned char *rsum,
unsigned *keypos)
{
unsigned int u, // Value from 0 to limit to return.
retry_limiter, // No infinite loops allowed.
mask; // Select just enough bits.
if (!limit) return 0; // Avoid divide by zero error.
retry_limiter = 0;
mask = 1; // Fill mask with enough bits to cover
while (mask < (unsigned)limit) // the desired range.
mask = (mask << 1) + 1;
do
{
*rsum = (unsigned char)(state->cards[*rsum] + user_key[(*keypos)++]);
if (*keypos >= keysize)
{
*keypos = 0; // Recycle the user key.
*rsum = (unsigned char)(*rsum + keysize); // key "aaaa" != key "aaaaaaaa"
}
u = mask & *rsum;
if (++retry_limiter > 11)
u %= (unsigned int)limit; // Prevent very rare long loops.
}
while (u > (unsigned)limit);
return (unsigned char)(u);
}
void GOAHashInit(GOACryptState *state)
{
// This function is used to initialize non-keyed hash
// computation.
int i, j;
// Initialize the indices and data dependencies.
state->rotor = 1;
state->ratchet = 3;
state->avalanche = 5;
state->last_plain = 7;
state->last_cipher = 11;
// Start with state->cards all in inverse order.
for (i=0, j=255;i<256;i++,j--)
state->cards[i] = (unsigned char) j;
}
void GOACryptInit(GOACryptState *state, unsigned char *key, unsigned char keysize)
{
// Key size may be up to 256 bytes.
// Pass phrases may be used directly, with longer length
// compensating for the low entropy expected in such keys.
// Alternatively, shorter keys hashed from a pass phrase or
// generated randomly may be used. For random keys, lengths
// of from 4 to 16 bytes are recommended, depending on how
// secure you want this to be.
int i;
unsigned char toswap, swaptemp, rsum;
unsigned keypos;
// If we have been given no key, assume the default hash setup.
if (keysize < 1)
{
GOAHashInit(state);
return;
}
// Start with state->cards all in order, one of each.
for (i=0;i<256;i++)
state->cards[i] = (unsigned char)(i);
// Swap the card at each position with some other card.
toswap = 0;
keypos = 0; // Start with first byte of user key.
rsum = 0;
for (i=255;i>=0;i--)
{
toswap = keyrand(state, i, key, keysize, &rsum, &keypos);
swaptemp = state->cards[i];
state->cards[i] = state->cards[toswap];
state->cards[toswap] = swaptemp;
}
// Initialize the indices and data dependencies.
// Indices are set to different values instead of all 0
// to reduce what is known about the state of the state->cards
// when the first byte is emitted.
state->rotor = state->cards[1];
state->ratchet = state->cards[3];
state->avalanche = state->cards[5];
state->last_plain = state->cards[7];
state->last_cipher = state->cards[rsum];
toswap = swaptemp = rsum = 0;
keypos = 0;
}
unsigned char GOAEncryptByte(GOACryptState *state, unsigned char b)
{
// Picture a single enigma state->rotor with 256 positions, rewired
// on the fly by card-shuffling.
// This cipher is a variant of one invented and written
// by Michael Paul Johnson in November, 1993.
unsigned char swaptemp;
// Shuffle the deck a little more.
state->ratchet = (unsigned char)(state->ratchet + state->cards[state->rotor++]);
swaptemp = state->cards[state->last_cipher];
state->cards[state->last_cipher] = state->cards[state->ratchet];
state->cards[state->ratchet] = state->cards[state->last_plain];
state->cards[state->last_plain] = state->cards[state->rotor];
state->cards[state->rotor] = swaptemp;
state->avalanche = (unsigned char)(state->avalanche + state->cards[swaptemp]);
// Output one byte from the state in such a way as to make it
// very hard to figure out which one you are looking at.
/*
state->last_cipher = b^state->cards[(state->cards[state->ratchet] + state->cards[state->rotor]) & 0xFF] ^
state->cards[state->cards[(state->cards[state->last_plain] +
state->cards[state->last_cipher] +
state->cards[state->avalanche])&0xFF]];
*/
state->last_cipher = (unsigned char)(b^state->cards[(state->cards[state->avalanche] + state->cards[state->rotor]) & 0xFF] ^
state->cards[state->cards[(state->cards[state->last_plain] +
state->cards[state->last_cipher] +
state->cards[state->ratchet])&0xFF]]);
state->last_plain = b;
return state->last_cipher;
}
void GOAEncrypt(GOACryptState *state, unsigned char *bp, int len)
{
int i;
for (i = 0 ; i < len ; i++)
{
bp[i] = GOAEncryptByte(state, bp[i]);
}
}
unsigned char GOADecryptByte(GOACryptState *state, unsigned char b)
{
unsigned char swaptemp;
// Shuffle the deck a little more.
state->ratchet = (unsigned char)(state->ratchet + state->cards[state->rotor++]);
swaptemp = state->cards[state->last_cipher];
state->cards[state->last_cipher] = state->cards[state->ratchet];
state->cards[state->ratchet] = state->cards[state->last_plain];
state->cards[state->last_plain] = state->cards[state->rotor];
state->cards[state->rotor] = swaptemp;
state->avalanche = (unsigned char)(state->avalanche + state->cards[swaptemp]);
// Output one byte from the state in such a way as to make it
// very hard to figure out which one you are looking at.
/*
state->last_plain = b^state->cards[(state->cards[state->ratchet] + state->cards[state->rotor]) & 0xFF] ^
state->cards[state->cards[(state->cards[state->last_plain] +
state->cards[state->last_cipher] +
state->cards[state->avalanche])&0xFF]];
*/
//crt - change this around
state->last_plain = (unsigned char)(b^state->cards[(state->cards[state->avalanche] + state->cards[state->rotor]) & 0xFF] ^
state->cards[state->cards[(state->cards[state->last_plain] +
state->cards[state->last_cipher] +
state->cards[state->ratchet])&0xFF]]);
state->last_cipher = b;
return state->last_plain;
}
void GOADecrypt(GOACryptState *state, unsigned char *bp, int len)
{
int i;
for (i = 0 ; i < len ; i++)
{
bp[i] = GOADecryptByte(state, bp[i]);
}
}
void GOAHashFinal(GOACryptState *state, unsigned char *outputhash, // Destination
unsigned char hashlength) // Size of hash.
{
int i;
for (i=255;i>=0;i--)
GOAEncryptByte(state, (unsigned char) i);
for (i=0;i<hashlength;i++)
outputhash[i] = GOAEncryptByte(state, 0);
}