/*{ ** Name: scu_xencode - encrypt a character string ** ** Description: ** This function uses CI routines to encrypt a character string. ** Since the character string is used to generate the key schedule, ** the encryption is essentially one-way (you'd need to know the ** password to decode the password....) This routine was designed ** to encrypt application_id passwords. ** ** Inputs: ** SCU_XENCODE the opcode to scf_call() ** scf_cb control block in which is specified ** .scf_ptr_union.scf_xpassword ** pointer to buffer to be encrypted ** .scf_nbr_union.scf_xpasskey ** pointer to seed for key schedule ** .scf_len_union.scf_xpwdlen ** length of password and key seed ** ** Outputs: ** scf_cb the same control block ** .error the error control area ** .err_code E_SC_OK or ... ** E_SC0261_XENCODE_BAD_PARM ** E_SC0262_XENCODE_BAD_RESULT ** Returns: ** E_DB_{OK, WARNING, ERROR, FATAL} ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 24-mar-89 (ralph) ** Written for terminator ** 20-may-89 (ralph) ** Changed encryption to use separate key ** 06-jun-89 (ralph) ** Fixed unix compile problems ** 06-may-1993 (ralph) ** DELIM_IDENT: ** Translate key seed to lower case prior to encryption. ** 2-Jul-1993 (daveb) ** prototyped. ** 14-jul-93 (ed) ** replacing <dbms.h> by <gl.h> <sl.h> <iicommon.h> <dbdbms.h> ** 12-Sep-2007 (drivi01) ** Modified scu_xencode function to fix numerous bugs. ** The buffers for password manipulation shouldn't exceed ** the size of scb_xpassword field in SCF control block, ** otherwise the data will be truncated. */ DB_STATUS scu_xencode(SCF_CB *scf_cb, SCD_SCB *scb ) { STATUS status; CI_KS KS; char inbuffer[DB_PASSWORD_LENGTH+1]; char outbuffer[DB_PASSWORD_LENGTH+1]; char keybuffer[DB_PASSWORD_LENGTH]; u_i2 i2_size; i4 longnat_size; i4 nat_size; char *char_ptr; #define PASSINIT "hjodvwHOJHOJhodh498032&*&*#)$&*jpkshghjlg58925fjkdjkpg" status = E_DB_OK; CLRDBERR(&scf_cb->scf_error); /* Ensure input parameter is okay */ if ((scf_cb->scf_len_union.scf_xpwdlen <= 0) || (scf_cb->scf_len_union.scf_xpwdlen >= sizeof(inbuffer)) || (scf_cb->scf_nbr_union.scf_xpasskey == NULL) || (scf_cb->scf_ptr_union.scf_xpassword == NULL)) { sc0ePut(NULL, E_SC0261_XENCODE_BAD_PARM, NULL, 0); SETDBERR(&scf_cb->scf_error, 0, E_SC0261_XENCODE_BAD_PARM); return(E_DB_ERROR); } /* Copy string to input buffer */ MEmove(scf_cb->scf_len_union.scf_xpwdlen, (PTR)scf_cb->scf_ptr_union.scf_xpassword, (char)'\0', sizeof(inbuffer), (PTR)inbuffer); /* Copy key to key buffer */ MEmove(scf_cb->scf_len_union.scf_xpwdlen, (PTR)scf_cb->scf_nbr_union.scf_xpasskey, (char)'?', sizeof(keybuffer), (PTR)keybuffer); /* Fold the key to lower case */ for (nat_size = sizeof(keybuffer), char_ptr = keybuffer; nat_size > 0; nat_size = CMbytedec(nat_size, char_ptr), char_ptr = CMnext(char_ptr)) { CMtolower(char_ptr, char_ptr); } /* Remove white space from input string */ nat_size = STzapblank(inbuffer, outbuffer); /* Check size */ if ((nat_size <= 0) || (nat_size > sizeof(outbuffer)-1)) { sc0ePut(NULL, E_SC0261_XENCODE_BAD_PARM, NULL, 0); SETDBERR(&scf_cb->scf_error, 0, E_SC0261_XENCODE_BAD_PARM); return(E_DB_ERROR); } /* Initialize input buffer to "garbage" */ MEmove(sizeof(PASSINIT), (PTR)PASSINIT, (char)'?', sizeof(inbuffer), (PTR)inbuffer); /* Normalize the string back into input buffer */ MEcopy((PTR)outbuffer, nat_size, (PTR)inbuffer); /* Reset output buffer to blanks */ MEfill(sizeof(outbuffer), (u_char)' ', (PTR)outbuffer); /* ** First, encrypt the key seed using the string to encode. ** Then, encrypt the string using the encrypted seed. ** This is done to prevent two roles with the same password ** from having the same encrypted value. ** Note that this makes the encryption one-way, since ** the password must be provided to decrypt the password! */ /* Generate the key schedule to encrypt the key seed */ (VOID)CIsetkey((PTR)inbuffer, KS); /* Encrypt the key seed */ longnat_size = DB_PASSWORD_LENGTH; (VOID)CIencode((PTR)keybuffer, longnat_size, KS, (PTR)outbuffer); /* Generate the second key schedule */ (VOID)CIsetkey((PTR)keybuffer, KS); /* Encode the string */ longnat_size = DB_PASSWORD_LENGTH; (VOID)CIencode((PTR)inbuffer, longnat_size, KS, (PTR)outbuffer); /* Make sure it was really encoded */ if ((char *)STskipblank(outbuffer, (i4)sizeof(outbuffer)) != NULL) { /* It was; copy result to caller's area */ i2_size = scf_cb->scf_len_union.scf_xpwdlen; MEmove(sizeof(outbuffer), (PTR)outbuffer, (char)' ', i2_size, (PTR)scf_cb->scf_ptr_union.scf_xpassword); } else { /* The encryption did not work; return an error */ sc0ePut(NULL, E_SC0262_XENCODE_BAD_RESULT, NULL, 0); SETDBERR(&scf_cb->scf_error, 0, E_SC0262_XENCODE_BAD_RESULT); status = E_DB_ERROR; } return(status); }
static STATUS gcn_encode( char *key, u_i1 *mask, char *ipb, char *opb ) { CI_KS ksch; char kbuff[ CRYPT_SIZE + 1 ]; char tbuff[ 128 ]; char *ptr, *tmp = tbuff; i4 tsize = sizeof( tbuff ); i4 len; bool done; /* ** Validate input. */ if ( key == NULL || opb == NULL ) return( FAIL ); if ( ipb == NULL || *ipb == EOS ) { *opb = EOS; return( OK ); } if ( mask == NULL ) mask = zeros; /* ** Ensure temp buffer is large enoush. */ len = ((STlength(ipb) + (CRYPT_SIZE - 1)) / (CRYPT_SIZE - 1)) * CRYPT_SIZE; if ( len >= tsize ) { tsize = len + 1; tmp = (char *)MEreqmem( 0, tsize, FALSE, NULL ); if ( ! tmp ) return( FAIL ); } /* ** Adjust key to CRYPT_SIZE by duplication/truncation. */ for( ptr = key, len = 0; len < CRYPT_SIZE; len++ ) { if ( ! *ptr ) ptr = key; kbuff[ len ] = *ptr++ ^ mask[ len ]; } kbuff[ len ] = EOS; CIsetkey( kbuff, ksch ); /* ** The string to be encrypted must be a multiple of ** CRYPT_SIZE in length for the block encryption ** algorithm used by CIencode(). To provide some ** randomness in the output, the first character ** or each CRYPT_SIZE block is assigned a random ** value. The remainder of the block is filled ** from the string to be encrypted. If the final ** block is not filled, random values are used as ** padding. A fixed delimiter separates the ** original string and the padding (the delimiter ** must always be present). */ for( done = FALSE, len = 0; ! done && (len + CRYPT_SIZE) < tsize; ) { /* ** First character in each encryption block is random. */ tmp[ len++ ] = (i4)(CSET_RANGE * MHrand()) + CSET_BASE; /* ** Load string into remainder of encryption block. */ while( *ipb && len % CRYPT_SIZE ) tmp[ len++ ] = *ipb++; /* ** If encryption block not filled, fill with random padding. */ if ( len % CRYPT_SIZE ) { /* ** Padding begins with fixed delimiter. */ tmp[ len++ ] = CRYPT_DELIM; done = TRUE; /* Only done when delimiter appended */ /* ** Fill encryption block with random padding. */ while( len % CRYPT_SIZE ) tmp[ len++ ] = (i4)(CSET_RANGE * MHrand()) + CSET_BASE; } } /* ** Encrypt the password and convert to text. */ tmp[ len ] = EOS; CIencode( tmp, len, ksch, (PTR)tmp ); CItotext( (u_char *)tmp, len, opb ); if ( tmp != tbuff ) MEfree( (PTR)tmp ); return( OK ); }