/* * UNDES V1.1.0 - reconstructed from undes.exe * Original executable: (C) 1998 H.N.M. Dijkema, GPL * * IMPORTANT: despite the program name, the executable selects * CRYPT_ALGO_3DES + CRYPT_MODE_CBC, i.e. two-key triple DES in CBC mode. * * This is reconstructed source, not the original source text. Control flow, * constants, CRYPTLIB calls and file-format behaviour are derived from the * 16-bit Turbo C executable and verified against CRYPTLIB 0.99 source. */ #include #include #include #include #include "crypt.h" #include "des_common.h" int main( int argc, char **argv ) { char *password; char *inputName; char *outputName; FILE *input; FILE *output; unsigned char *buffer; unsigned char *payload; BYTE key[ CRYPT_MAX_KEYSIZE ]; BYTE iv[ CRYPT_MAX_IVSIZE ]; BYTE passwordBlock[ CRYPT_MAX_KEYSIZE ]; CRYPT_INFO cryptInfo; CRYPT_QUERY_INFO queryInfo; CRYPT_ALGO algorithm = CRYPT_ALGO_3DES; CRYPT_MODE mode = CRYPT_MODE_CBC; DES_INT32 fileVersion; DES_INT32 plainLength; int keySize; int ivSize; int bytesRead; int firstTime; int inputFd; int i; if( argc == 2 ) { if( strcmp( argv[ 1 ], "--copyright" ) == 0 ) { printf( "%s\n\n", desProgramVersion ); printf( "%s", desCopyrightText ); exit( 0 ); } if( strcmp( argv[ 1 ], "--version" ) == 0 ) { printf( "%s\n", desProgramVersion ); exit( 0 ); } } if( argc != 4 ) { fprintf( stderr, "usage: undes \n" " undes --copyright\n" " undes --version\n" " '-' for file --> stdin/stdout\n" ); exit( argc == 1 ? 0 : 2 ); } password = argv[ 1 ]; inputName = argv[ 2 ]; outputName = argv[ 3 ]; if( strcmp( inputName, "-" ) != 0 && strcmp( inputName, outputName ) == 0 ) { fprintf( stderr, " and cannot be the same\n" ); exit( 1 ); } input = ( strcmp( inputName, "-" ) == 0 ) ? stdin : fopen( inputName, "rb" ); output = ( strcmp( outputName, "-" ) == 0 ) ? stdout : fopen( outputName, "wb" ); checkOpen( input, inputName ); checkOpen( output, outputName ); algorithm = CRYPT_ALGO_3DES; mode = CRYPT_MODE_CBC; firstTime = TRUE; buffer = (unsigned char *) malloc( DES_BUFFER_SIZE ); if( buffer == NULL ) { fprintf( stderr, "Can't allocate buffer\n" ); exit( 1 ); } payload = buffer + DES_PREFIX_SIZE; initLibrary(); queryAlgoModeInformation( algorithm, mode, &queryInfo ); keySize = queryInfo.keySize; /* 14 bytes */ ivSize = queryInfo.ivSize; /* 4 bytes */ i = 0; while( i < keySize && password[ i ] != '\0' ) { key[ i ] = (BYTE) password[ i ]; i++; } while( i < keySize ) key[ i++ ] = 0; fileVersion = (DES_INT32) -1; inputFd = fileno( input ); bytesRead = read( inputFd, &fileVersion, 4 ); checkRead( bytesRead ); checkVersion( fileVersion ); initCryptContext( &cryptInfo, algorithm, mode ); loadCryptContext( &cryptInfo, key, keySize ); queryContextInformation( &cryptInfo, &queryInfo ); ivSize = queryInfo.ivSize; bytesRead = read( inputFd, iv, ivSize ); checkRead( bytesRead ); loadIV( &cryptInfo, iv, ivSize ); bytesRead = read( inputFd, passwordBlock, CRYPT_MAX_KEYSIZE ); checkRead( bytesRead ); bytesRead = read( inputFd, buffer, DES_BUFFER_SIZE ); checkRead( bytesRead ); while( bytesRead != 0 ) { /* * This ordering is intentional. DES encrypts the first data block * before passwordBlock, although passwordBlock is stored first in the * file. Decrypting in the same crypto order preserves CBC state. */ decryptBuffer( &cryptInfo, buffer, DES_BUFFER_SIZE ); memcpy( &plainLength, buffer, 4 ); if( plainLength < 0 ) plainLength = DES_PAYLOAD_SIZE; if( firstTime ) { decryptBuffer( &cryptInfo, passwordBlock, CRYPT_MAX_KEYSIZE ); i = 0; while( i < keySize && passwordBlock[ i ] == key[ i ] ) i++; if( i != keySize ) { fprintf( stderr, "Password is not correct, no decryption possible\n" ); exit( 1 ); } firstTime = FALSE; } fwrite( payload, (DES_UINT16) plainLength, 1, output ); checkWrite( output ); fflush( output ); bytesRead = read( inputFd, buffer, DES_BUFFER_SIZE ); checkRead( bytesRead ); } decryptBuffer( &cryptInfo, buffer, 0 ); destroyCryptContext( &cryptInfo ); endLibrary(); free( buffer ); if( input != stdin ) fclose( input ); if( output != stdout ) fclose( output ); return( 0 ); }