/* * $Id: arjcrypt.c,v 1.5 2003/06/22 11:12:28 andrew_belov Exp $ * --------------------------------------------------------------------------- * This file is a small module that performs stand-alone strong GOST 28147-89 * encryption. * */ #include "arj.h" #if TARGET==DOS #include #include "gost_asm.h" #include "det_x86.h" #elif TARGET==OS2 #endif #include "msg_crp.h" #include "arjcrypt.h" DEBUGHDR(__FILE__) /* Debug information block */ /* OS/2 DLL variable */ #if TARGET==OS2&&COMPILER==MSC int _acrtused=0; #endif /* To identify ourselves, we must have a signature: */ static char id[]="NortheastXXXXXXXX"; /* Currently unused */ #if TARGET==DOS static char signature[]=ARJCRYPT_SIG; static void entry(); static unsigned short entry_point=(unsigned short)&entry; static int use_32=0; /* Allow 32-bit instructions */ #endif /* Local data */ static unsigned long default_key[8]={3, 10, 6, 12, 5, 9, 0, 7}; static int last_bytes=0; /* Number of significant bytes in the last block */ static unsigned long back_code[2]={0L}; /* Recently encrypted data */ static unsigned long ext_code[2]={0L}; /* The code used by gost_cipher() */ static unsigned long gost_key[8]={0L}; /* Encryption key */ static unsigned long gost64_key[16]={0L};/* ARJCRYPT v 2.0 encryption key */ static int flags=0; /* Encryption type */ static int key64_len=0; /* Length of ARJCRYPT v 2 intial encryption password */ #ifdef WORDS_BIGENDIAN static const int ord[8]={3,2,1,0,7,6,5,4}; #define bf(x) ord[x] static void adjust_byte_order(char *p,const int len) { int l4; for (l4=len>>2;l4;l4--) { char tmp,*p1,*p2; p1 = p +1; p2 = p1+1; tmp = *p2; *p2++ = *p1; *p1-- = tmp; tmp = *p1; *p1 = *p2; *p2 = tmp; p = p2+1; } } static void codec(void (*fct)(unsigned char FAR *, unsigned char FAR *, int), unsigned char FAR *buf, int len) { if (!(len&7) && !last_bytes) adjust_byte_order(buf,len); (*fct)(buf,buf,len); if (!(len&7) && !last_bytes) adjust_byte_order(buf,len); } #else #define bf(x) (x) #define codec(fct,buf,len) (fct(buf,buf,len)) #endif /* GOST encoding/decoding loop */ static void gost_loop(unsigned long *src, unsigned long *dest, unsigned long *key) { unsigned long mod1, mod2; int i; #if TARGET==DOS if(use_32) { gost_loop_32(src, dest, key); return; } #endif mod1=src[0]; mod2=src[1]; for(i=0; i<3; i++) { mod2^=gost_term(mod1+key[0]); mod1^=gost_term(mod2+key[1]); mod2^=gost_term(mod1+key[2]); mod1^=gost_term(mod2+key[3]); mod2^=gost_term(mod1+key[4]); mod1^=gost_term(mod2+key[5]); mod2^=gost_term(mod1+key[6]); mod1^=gost_term(mod2+key[7]); } mod2^=gost_term(mod1+key[7]); mod1^=gost_term(mod2+key[6]); mod2^=gost_term(mod1+key[5]); mod1^=gost_term(mod2+key[4]); mod2^=gost_term(mod1+key[3]); mod1^=gost_term(mod2+key[2]); mod2^=gost_term(mod1+key[1]); mod1^=gost_term(mod2+key[0]); dest[0]=mod2; dest[1]=mod1; } /* So-called "gamma"-ciphering that does both encoding and decoding */ static void gost_cipher_proc(unsigned char FAR *src, unsigned char FAR *dest, int len) { unsigned long FAR *tmp_sptr; /* Pointer to source area */ unsigned long FAR *tmp_dptr; /* Pointer to target area */ int remainder; /* Number of bytes in the last block */ remainder=len%8; if(remainder==0&&last_bytes==0) { tmp_sptr=(unsigned long *)src; tmp_dptr=(unsigned long *)dest; len>>=3; while(len--!=0) { back_code[0]+=GOST_I_PAT_LO; if(back_code[0]>=3; while(len--!=0) { gost_loop(back_code, back_code, gost_key); back_code[0]=tmp_dptr[0]=tmp_sptr[0]^back_code[0]; back_code[1]=tmp_dptr[1]=tmp_sptr[1]^back_code[1]; tmp_sptr+=2; tmp_dptr+=2; } } else { bc_offset=(unsigned char *)back_code; while(len--!=0) { if(last_bytes==0) gost_loop(back_code, back_code, gost_key); bc_offset[bf(last_bytes)]=*(dest++)=*(src++)^bc_offset[bf(last_bytes)]; last_bytes++; last_bytes%=8; } } } /* Decoding sequence */ static void gost_decode(unsigned char FAR *src, unsigned char FAR *dest, int len) { unsigned long FAR *tmp_sptr; /* Pointer to source area */ unsigned long FAR *tmp_dptr; /* Pointer to target area */ int remainder; /* Number of bytes in the last block */ unsigned long d_data; /* Decoded data collector */ unsigned char *bc_offset; /* Offset within back_code */ unsigned char dec_sym; /* Currently processed symbol */ remainder=len%8; if(remainder==0&&last_bytes==0) { tmp_sptr=(unsigned long FAR *)src; tmp_dptr=(unsigned long FAR *)dest; len>>=3; while(len--!=0) { gost_loop(back_code, back_code, gost_key); d_data=tmp_sptr[0]; tmp_dptr[0]=d_data^back_code[0]; back_code[0]=d_data; d_data=tmp_sptr[1]; tmp_dptr[1]=d_data^back_code[1]; back_code[1]=d_data; tmp_sptr+=2; tmp_dptr+=2; } } else { bc_offset=(unsigned char *)back_code; while(len--!=0) { if(last_bytes==0) gost_loop(back_code, back_code, gost_key); dec_sym=*(src++); *(dest++)=dec_sym^bc_offset[bf(last_bytes)]; bc_offset[bf(last_bytes++)]=dec_sym; last_bytes%=8; } } } /* Copies characters of a string, appending a null byte to the result */ static int far_strncpy(char FAR *dest, char FAR *src, int limit) { int k; char *d; d=dest; for(k=0; ksizeof(gost_key)) { for(i=0; i<8; i++) gost_key[i]=gost64_key[i+8]; for(i=0; imode) { case ARJCRYPT_INIT: #if TARGET==DOS use_32=detect_x86()==0x386; #endif memset(gost_key, 0, sizeof(gost_key)); far_strncpy((char FAR *)gost_key, exblock_ptr->password, sizeof(gost_key)); modifier[0]=exblock_ptr->l_modifier[0]; modifier[1]=exblock_ptr->l_modifier[1]; flags=ENCRYPT_GOST256; last_bytes=0; calc_gost_pattern(); gost_crtkey(modifier); gost_loop(modifier, back_code, gost_key); exblock_ptr->rc=ARJCRYPT_RC_INITIALIZED; break; case ARJCRYPT_V2_INIT: #if TARGET==DOS use_32=detect_x86()==0x386; #endif memset(gost_key, 0, sizeof(gost_key)); far_strncpy((char FAR *)gost_key, exblock_ptr->password, sizeof(gost_key)); memset(gost64_key, 0, sizeof(gost64_key)); key64_len=far_strncpy((char FAR *)gost64_key, exblock_ptr->password, sizeof(gost64_key)); modifier[0]=exblock_ptr->l_modifier[0]; modifier[1]=exblock_ptr->l_modifier[1]; flags=exblock_ptr->flags; last_bytes=0; calc_gost_pattern(); gost_crtkey(modifier); gost_loop(modifier, back_code, gost_key); exblock_ptr->rc=(flags==ENCRYPT_GOST256||key64_len<=32)?ARJCRYPT_RC_INITIALIZED:ARJCRYPT_RC_INIT_V2; break; case ARJCRYPT_ENCODE: codec(gost_encode, exblock_ptr->data, exblock_ptr->len); exblock_ptr->rc=ARJCRYPT_RC_OK; break; case ARJCRYPT_DECODE: codec(gost_decode, exblock_ptr->data, exblock_ptr->len); exblock_ptr->rc=ARJCRYPT_RC_OK; break; case ARJCRYPT_CIPHER: case ARJCRYPT_DECIPHER: codec(gost_cipher_proc, exblock_ptr->data, exblock_ptr->len); exblock_ptr->rc=ARJCRYPT_RC_OK; break; default: exblock_ptr->rc=ARJCRYPT_RC_ERROR; break; } #if TARGET==DOS exblock_ptr->ret_addr(); #endif }