mangle.cc #1

  • //
  • guest/
  • perforce_software/
  • p4/
  • 2014-1/
  • support/
  • mangle.cc
  • View
  • Commits
  • Open Download .zip Download (8 KB)
/*
 * This code implements the lucifer encryption/decryption
 * code but has been modified to work just on small strings.
 *
 * Originally written by Arthur Sorkin in 1984 in FORTRAN
 *
 * Rewritten in 1991 by Jonathan M. Smith
 *
 * This code is in the public domain.  Patents have expired.
 *
 * To encrypt a string (must be 16 bytes or less) instantiate
 * a Mangle object, call In() passing the string, key and an
 * output buffer to store the result.  To decrypt the string
 * instantiate a Mangle object, call Out() passing in the 32
 * character (hex) string and the originally key, string will
 * be returned in the output buffer in the same way as In().
 * 
 * Notes:
 *
 * data must be 16 bytes or less (except see below).
 * key will be truncated to a maximum of 16 characters.
 *
 * As part of the security improvements the digest stored in the
 * server is no longer usable on the client, in order to mangle
 * the 32 character digest (data > 16 characters) alternative
 * interfaces InMD5() and OutMD5() handle the "raw" digest.
 */
#include <stdhdrs.h>
#include <error.h>
#include <strbuf.h>
#include <strops.h>
#include <msgsupp.h>
#include "mangle.h"

#define BPB 8   

Mangle::Mangle()
{
	// diffusion pattern 

	o[0] = 7; o[1] = 6; o[2] = 2; o[3] = 1; 
	o[4] = 5; o[5] = 0; o[6] = 3; o[7] = 4;

	// inverse of fixed permutation

	pr[0] = 2; pr[1] = 5; pr[2] = 4; pr[3] = 0;
	pr[4] = 3; pr[5] = 1; pr[6] = 7; pr[7] = 6;

	// S-box permutations

	s0[0] = 12;  s0[1] = 15;  s0[2] = 7;   s0[3] = 10; 
        s0[4] = 14;  s0[5] = 13;  s0[6] = 11;  s0[7] = 0;  
	s0[8] = 2;   s0[9] = 6;   s0[10] = 3;  s0[11] = 1;
	s0[12] = 9;  s0[13] = 4;  s0[14] = 5;  s0[15] = 8;

	s1[0] = 7;   s1[1] = 2;   s1[2] = 14;  s1[3] = 9;  
	s1[4] = 3;   s1[5] = 11;  s1[6] = 0;   s1[7] = 4;  
	s1[8] = 12;  s1[9] = 13;  s1[10] = 1;  s1[11] = 10;
	s1[12] = 6;  s1[13] = 15; s1[14] = 8;  s1[15] = 5;

	// S-box mix
	s2[0] = 10; s2[1] = 1; s2[2] = 13; s2[3] = 12;
	s2[4] = 4;  s2[5] = 0; s2[6] = 11; s2[7] = 3;
}

void
Mangle::DoIt( 
	const StrPtr &data, 
	const StrPtr &key, 
	StrBuf &result,
	int decipher, 
	int digest,
	Error *e )
{
	int m[128];					
	int k[128];					
	char *p, *q;
	char src[17];
	char enc[17];
	char buf[17];
	int counter;
	int output;
	int c, i, j;

	if( ( decipher && data.Length() != 32 && data.Length() != 0 ) ||
	    ( !decipher && data.Length() > 16 && !digest ) ||
	    ( !decipher && data.Length() != 32 && digest ) )
	{
	    e->Set( MsgSupp::BadMangleParams );
	}

	if( e->Test() )
	    return;

	memset( src, 0, 17 );
	memset( enc, 0, 17 );
	memset( buf, 0, 17 );

	// truncate key to 16 character max

	memcpy( buf, key.Text(), key.Length() > 16 ? 16 : key.Length() );

	if( decipher || digest )
	    StrOps::XtoO( data.Text(), (unsigned char *)src, 16 );
	else
	    memcpy( src, data.Text(), data.Length() );

	p = src;
	q = enc;

	for( counter = 0; counter < 16; counter += 1 )
	{
	    c = buf[counter] & 0xFF;
	    for( i = 0; i < BPB; i += 1 )
	    {
	        k[(BPB*counter)+i] = c & 0x1;
	        c = c>>1;
	    }
	}

	counter = 0;

	/* Mix it up a bit
	 */
	if( decipher )
	{ 
	    s1[4] = s2[0]; s1[5] = s2[1]; s1[6] = s2[2];  s1[7] = s2[3]; 
	}

	/* Lose check for NULL, since its a valid character, assume its a 
	 * 16 byte cipher block (thats all it ever should be, lose the
	 * while( (c=*p++) != '\0' )
	 */

	for( j = 0; j < 16; ++j )
        {
	    c = *p++;
	    if( counter == 16 )
	    {
	        Getdval( decipher, m, k );

	        for( counter = 0; counter < 16; counter += 1 )
	        {
	            output = 0;
	            for( i = BPB-1; i >= 0; i -= 1 )
	                output = (output<<1) + m[(BPB*counter)+i];
	            *q++ = output;
	        }
	        counter = 0;
	    }
	    for( i = 0; i < BPB; i += 1 )
	    {
	        m[(BPB*counter)+i] = c & 0x1;
	        c = c>>1;
	    }
	    counter += 1;
	}

	for( ;counter < 16; counter += 1 )
	    for( i = 0; i < BPB; i += 1 )
                m[(BPB*counter)+i] = 0;

	Getdval( decipher, m, k );

	for( counter = 0; counter < 16; counter += 1 )
	{
	    output = 0;
            for( i = BPB-1; i >= 0; i -= 1 )
                output = (output<<1) + m[(BPB*counter)+i];
            *q++ = output;
	}

	*q = '\0';        

	result.Clear();
    
	if( decipher && !digest )
	    result.Set( enc );
	else
	    StrOps::OtoX( (const unsigned char *)enc, 16, result );
}

void	
Mangle::In( const StrPtr &in, const StrPtr &key, StrBuf &result, Error *e ) 
{ 
	StrBuf mangledValue;
	StrBuf inputSegment;
	int    inputLen = in.Length();
	int    offset = 0;

	while( offset < inputLen )
	{
	    StrBuf data, mangledChunk;
	    int chunkSize = inputLen - offset;
	    if( chunkSize > 16 ) chunkSize = 16;
	    data.Extend( &in.Text()[offset], chunkSize );
	    data.Terminate();
	    DoIt( data, key, mangledChunk, 0, 0, e );     

	    if( e->Test() )
	        return;
	    mangledValue.Append( &mangledChunk );
	    offset += chunkSize;
	}

	result = mangledValue;
}

void	
Mangle::Out( const StrPtr &out, const StrPtr  &key, StrBuf &result, Error *e ) 
{ 
	// Extract the password (cleartext) using the key
	StrBuf extractedValue;
	StrBuf inputSegment;
	int    inputLen = out.Length();
	int    offset = 0;

	while( offset < inputLen )
	{
	    StrBuf data, extractedChunk;
	    int chunkSize = inputLen - offset;
	    if( chunkSize > 32 ) chunkSize = 32;
	    data.Extend( &out.Text()[offset], chunkSize );
	    data.Terminate();
	    DoIt( data, key, extractedChunk, 1, 0, e ); 
	    if( e->Test() )
	        return;
	    extractedValue.Append( &extractedChunk );
	    offset += chunkSize;
	}
	result = extractedValue;
}

void
Mangle::Getdval( int decipher, int m[], int k[] )
{
	int tcbindex, tcbcontrol; /* transfer control byte indices */
	int round, hi, lo, h_0, h_1;
	int bit, temp1;
	int byte, index, v, tr[BPB];

	h_0 = 0;
	h_1 = 1;

	tcbcontrol = decipher  ? 8 : 0;

	/* mix it up a bit
	 */
	if( decipher )
	{ 
	    s1[8] = s2[4]; s1[9] = s2[5]; s1[10] = s2[6]; s1[11] = s2[7]; 
	}

	for( round=0; round<16; round += 1 )
	{
	    if( decipher )
	        tcbcontrol = (tcbcontrol+1) & 0xF;
	    tcbindex = tcbcontrol;
	    for( byte = 0; byte < 8; byte +=1 )
	    {
	        lo = (m[(h_1*64)+(BPB*byte)+7])*8
	            +(m[(h_1*64)+(BPB*byte)+6])*4
	            +(m[(h_1*64)+(BPB*byte)+5])*2
	            +(m[(h_1*64)+(BPB*byte)+4]);
	        hi = (m[(h_1*64)+(BPB*byte)+3])*8
	            +(m[(h_1*64)+(BPB*byte)+2])*4
	            +(m[(h_1*64)+(BPB*byte)+1])*2
	            +(m[(h_1*64)+(BPB*byte)+0]);

	        v = (s0[lo]+16*s1[hi])*(1-k[(BPB*tcbindex)+byte])
	            +(s0[hi]+16*s1[lo])*k[(BPB*tcbindex)+byte];

	        for( temp1 = 0; temp1 < BPB; temp1 += 1 )
	        {
	            tr[temp1] = v & 0x1;
	            v = v>>1;
	        }

	        for( bit = 0; bit < BPB; bit += 1 )
	        {
	            index = (o[bit]+byte) & 0x7;
	            temp1 = m[(h_0*64)+(BPB*index)+bit]
	            	+k[(BPB*tcbcontrol)+pr[bit]]
	            	+tr[pr[bit]];
	            m[(h_0*64)+(BPB*index)+bit] = temp1 & 0x1;
	        }
	    
	        if( byte<7 || decipher )
	            tcbcontrol = (tcbcontrol+1) & 0xF;
	    }

	    temp1 = h_0;
	    h_0 = h_1;
	    h_1 = temp1;
	}

	/* final swap */
	for( byte = 0; byte < 8; byte += 1 )
	{
	    for( bit = 0; bit < BPB; bit += 1 )
	    {
	        temp1 = m[(BPB*byte)+bit];
	        m[(BPB*byte)+bit] = m[64+(BPB*byte)+bit];
	        m[64+(BPB*byte)+bit] = temp1;
	    }
	}
}

void
Mangle::XOR( 
	StrBuf &data, 
	const StrPtr &key, 
	Error *e )
{
	if( data.Length() != 32 && key.Length() != 32 ) 
	    e->Set( MsgSupp::BadMangleParams );

	if( e->Test() )
	    return;

	char src[17];
	char enc[17];
	char buf[17];

	StrOps::XtoO( data.Text(), (unsigned char *)src, 16 );
	StrOps::XtoO( key.Text(), (unsigned char *)enc, 16 );

	for( int i = 0; i < 16; ++i )
	    buf[i] = src[i] ^ enc[i];

	data.Clear();
	StrOps::OtoX( (const unsigned char *)buf, 16, data );
}
# Change User Description Committed
#1 15902 Matt Attaway A second renaming that I will not obliterate as a badge of shame
//guest/perforce_software/p4/2014_1/support/mangle.cc
#1 15901 Matt Attaway Clean up code to fit modern Workshop naming standards
//guest/perforce_software/p4/2014.1/support/mangle.cc
#1 12188 Matt Attaway Move 'main' p4 into a release specific directory in prep for new releases
//guest/perforce_software/p4/support/mangle.cc
#1 9129 Matt Attaway Initial commit of the 2014.1 p4/p4api source code