Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Mailing Lists -> Oracle-L -> C / external procedure puzzle for the C guru's

C / external procedure puzzle for the C guru's

From: Jared Still <jkstill_at_bcbso.com>
Date: Tue, 30 May 2000 12:43:30 -0700 (PDT)
Message-Id: <10513.107166@fatcity.com>


First off let me say 'I am not a C programmer'.

That disclaimer will hopefully insulate me from any flames for doing something stupid in C.

I'm trying to build an encryption routine for use in Oracle, via external procedure calls.

After digging through MetaLink for couple of hours I was able to get tnsnames.ora, sqlnet.ora and listener.ora to work properly for the external callouts.

I dug up some RC4 encryption code in C from the web, and modified it for use in shared library.

The original code always works correctly and as expected for command line use.

When I modify it for use in a shared library, the function has the habit of returning data that is too short. It appears that whenever an encypted character is ascii character 10, the rest of the string is truncated.

Whether this is a problem I built into the C code, or is an anomoly in the library spec, I'm not sure, though it is probably due to me bungling the string handling somehow.

I'm hoping some of you C mavens that may have worked with external procedure callouts can help me out here, and point out any glaring errors I may have made.

Thanks

Jared

PLATFORM:   Sun E4500
  2 Gig RAM
  4 CPU
  Solaris 2.6

Oracle version 8.1.6  

First, here are the additions to the listener.ora and tnsnames.ora files:

LISTENER.ORA the only line that matters here is that added to the listener section:

(address=
(protocol=ipc)
(key=extproc_key)

                        )

added to the SID list:     

   (sid_desc=

      (sid_name=extproc_agent)
      (oracle_home = /obase/product/8.1.6)
      (program=extproc)

   )

TNSNAMES.ORA this is the entire tnsnames.ora. Since
we use oracle names, we don't usually have need for tnsnames

  extproc_connection_data.bcbso.tbg.org=                  
	  (description=                           
		  (address=(protocol=ipc)(key=extproc_key))                      
		  (connect_data= (sid=extproc_agent)) 
	  ) 



SQLNET.ORA the only line that matters here is that this one, as it says to look in tnsnames.ora before checking with oracle names.

  NAMES.DIRECTORY_PATH = (TNSNAMES, ONAMES) This configuration all works fine.

Below is the code used to build this.

The files are :

  cl.sql which builds the package
  a single sql statement that fails
  rc4p.c which is the code for the shared library   rc4.c which is the original C code
  rc4.h which is a header used by rc4p.c

But first, here are the commands to build the shared library.

  cc -c rc4p.c
  ld -G -o rc4p.so rc4p.o

set echo on   

create or replace library librc4p as '/home/jkstill/articles/encryption/rc4/c/rc4p.so' /

show errors

create or replace package crypt
is

	function rc4( key_in varchar2, data_in varchar2 ) return varchar2;
	--pragma restrict_references( rc4, wnds, rnds, wnps );
end;
/

show errors package crypt

create or replace package body crypt
is

	function rc4p( key_in varchar2, data_in in out varchar2 )
	return pls_integer is external
	library librc4p
	name "rc4p"
	language C;

	function rc4( key_in varchar2, data_in varchar2 ) return varchar2
	is
		dummy pls_integer;

		v_data varchar2(500);
		clear_len integer;
		crypt_len integer;

	begin

		v_data := data_in;
		clear_len := length(v_data);
		dummy := rc4p( key_in, v_data );

		return v_data;

	end;

end;
/

show errors package body crypt

set echo off

select crypt.rc4('cryptkey',(crypt.rc4( 'cryptkey','ALL_ALL_TABLES'))) from dual;

/* rc4.h */
typedef struct rc4_key

{      
	unsigned char state[256];       
	unsigned char x;        
	unsigned char y;

} rc4_key;

void prepare_key(unsigned char *key_data_ptr,int key_data_len, rc4_key *key);

void rc4(unsigned char *buffer_ptr,int buffer_len,rc4_key * key);        

#include <stdio.h>

#define buf_size 1024

   /*rc4.c */
#include "rc4.h"
static void swap_byte(unsigned char *a, unsigned char *b);

void prepare_key(unsigned char *key_data_ptr, int key_data_len, rc4_key *key) {

	unsigned char swapByte;
	unsigned char index1;
	unsigned char index2;
	unsigned char* state;
	short counter;     
 
	state = &key->state[0];         
	for(counter = 0; counter < 256; counter++)              
		state[counter] = counter;               
	key->x = 0;     
	key->y = 0;     
	index1 = 0;     
	index2 = 0;             
	for(counter = 0; counter < 256; counter++)      
	{               
		index2 = (key_data_ptr[index1] + state[counter] +
		index2) % 256;                
		swap_byte(&state[counter], &state[index2]);            
 
		index1 = (index1 + 1) % key_data_len;  
	}       

}     

void rc4(unsigned char *buffer_ptr, int buffer_len, rc4_key *key) {

	unsigned char x;
	unsigned char y;
	unsigned char* state;
	unsigned char xorIndex;
	short counter;              
 
	x = key->x;     
	y = key->y;     
 
	state = &key->state[0];         
	for(counter = 0; counter < buffer_len; counter ++)      
	{               
		x = (x + 1) % 256;                      
		y = (state[x] + y) % 256;               
		swap_byte(&state[x], &state[y]);                        
 
		xorIndex = (state[x] + state[y]) % 256;                 
 
		buffer_ptr[counter] ^= state[xorIndex];         
	}               
	key->x = x;     
	key->y = y;

}     

static void swap_byte(unsigned char *a, unsigned char *b) {

        unsigned char swapByte;  

	swapByte = *a; 
	*a = *b;      
	*b = swapByte;

}    

int rc4p( unsigned char* key_data, unsigned char *clear_text ) {
  unsigned char seed[256];
  char data[512];
  char digit[5];

  int hex,i;
  int n, text_len;
  rc4_key key;

  strcpy(data,key_data);
  n = strlen(data);
  if (n&1)
  {
    strcat(data,"0");
    n++;
  }
  n/=2;
  strcpy(digit,"AA");
  digit[4]='\0';
  for (i=0;i<n;i++)
  {
    digit[2] = data[i*2];
    digit[3] = data[i*2+1];
    sscanf(digit,"%x",&hex);
    seed[i] = hex;
  }

  prepare_key(seed,n,&key);         

  text_len = strlen(clear_text);
  rc4(clear_text,text_len,&key);   

  return strlen(clear_text);

}

#define buf_size 1024

typedef struct rc4_key

{      
   unsigned char state[256];       
   unsigned char x;        

   unsigned char y;
} rc4_key;

#define swap_byte(x,y) t = *(x); *(x) = *(y); *(y) = t

void prepare_key(unsigned char *key_data_ptr, int key_data_len, rc4_key *key) {
  int i;
  unsigned char t;
  unsigned char swapByte;

  unsigned char index1;
  unsigned char index2;
  unsigned char* state;

  short counter;

  state = &key->state[0];
  for(counter = 0; counter < 256; counter++)   state[counter] = counter;

  key->x = 0;
  key->y = 0;
  index1 = 0;
  index2 = 0;

  for(counter = 0; counter < 256; counter++)   {
    index2 = (key_data_ptr[index1] + state[counter] + index2) % 256;
    swap_byte(&state[counter], &state[index2]);
    index1 = (index1 + 1) % key_data_len;
  }
}

void rc4(unsigned char *buffer_ptr, int buffer_len, rc4_key *key) {

  unsigned char t;
  unsigned char x;
  unsigned char y;

  unsigned char* state;
  unsigned char xorIndex;
  short counter;

  x = key->x;
  y = key->y;
  state = &key->state[0];
  for(counter = 0; counter < buffer_len; counter++)   {
    x = (x + 1) % 256;
    y = (state[x] + y) % 256;
    swap_byte(&state[x], &state[y]);
    xorIndex = (state[x] + state[y]) % 256;     buffer_ptr[counter] ^= state[xorIndex];   }
  key->x = x;
  key->y = y;
}

int main(int argc, char* argv[])
{
  unsigned char seed[256];
  char data[512];
  unsigned char buf[buf_size];
  char digit[5];
  int hex, rd,i;
  int n;
  rc4_key key;

  if (argc < 2)
  {
    fprintf(stderr,"%s key <in >out\n",argv[0]);     exit(1);
  }
  strcpy(data,argv[1]);
  n = strlen(data);

  if (n&1)
  {
    strcat(data,"0");
    n++;
  }
  n/=2;
  strcpy(digit,"AA");
  digit[4]='\0'; Received on Tue May 30 2000 - 14:43:30 CDT

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US