static STATUS gcn_decrypt( char *key, char *pbuff, char *passwd ) { CI_KS ksch; char kbuff[ CRYPT_SIZE + 1 ]; i4 len; /* ** Validate input. */ if ( key == NULL || passwd == NULL ) return( FAIL ); if ( pbuff == NULL || *pbuff == EOS ) { *passwd = EOS; return( OK ); } /* ** Adjust key to CRYPT_SIZE by padding/truncation. */ for( len = 0; len < CRYPT_SIZE; len++ ) kbuff[len] = *key ? *key++ : ' '; kbuff[ CRYPT_SIZE ] = EOS; CIsetkey( kbuff, ksch ); /* ** Password is passed as text, convert back to encoded ** binary. Encoded password should be of correct size. ** Decrypt password. */ CItobin( pbuff, &len, (u_char *)passwd ); if ( len % CRYPT_SIZE ) return( FAIL ); CIdecode( passwd, len, ksch, passwd ); /* ** Cleanup password by removing trailing ** spaces and the end marker. */ passwd[ len ] = EOS; len = STtrmwhite( passwd ); if ( passwd[ --len ] != GCN_PASSWD_END ) return( FAIL ); passwd[ len ] = EOS; return( OK ); }
void gcd_decode( char *key, u_i1 *mask, u_i1 *data, u_i2 length, char *buff ) { CI_KS ks; u_i1 kbuff[ CRYPT_SIZE ]; char *ptr; u_i2 i, j; /* ** The key schedule is built from a single CRYPT_SIZE ** byte array. We use the input key to build the byte ** array, truncating or duplicating as necessary. ** The key is also combined with an optional mask. */ for( i = 0, ptr = key; i < CRYPT_SIZE; i++ ) { if ( ! *ptr ) ptr = key; kbuff[ i ] = *ptr++ ^ (mask ? mask[ i ] : 0); } CIsetkey( (PTR)kbuff, ks ); CIdecode( (PTR)data, length, ks, (PTR)buff ); /* ** The encoded data must be padded to a multiple of ** CRYPT_SIZE bytes. Random data is used for the pad, ** so for strings the null terminator is included in ** the data. A random value is added to each block ** so that a given key/data pair does not encode the ** same way twice. */ for( i = 0, ptr = buff; i < length; i += CRYPT_SIZE ) for( j = 1; j < CRYPT_SIZE; j++ ) if ( ! (*ptr++ = buff[ i + j ]) ) /* stop at EOS */ break; return; }
/*{ ** 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_decode( char *key, u_i1 *mask, char *ipb, char *opb ) { CI_KS ksch; char kbuff[ CRYPT_SIZE + 1 ]; char *ptr; i4 len; /* ** Validate input. */ if ( key == NULL || opb == NULL ) return( FAIL ); if ( ipb == NULL || *ipb == EOS ) { *opb = EOS; return( OK ); } if ( mask == NULL ) mask = zeros; /* ** 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 ]; } CIsetkey( kbuff, ksch ); /* ** Password is passed as text, convert back to encoded ** binary. Encoded password should be of correct size. ** Decrypt password. ** ** Decode password will be smaller than input. The ** decoded password also needs to be deformatted, which ** can be done in place, so decode directly into output ** buffer. */ CItobin( ipb, &len, (u_char *)opb ); if ( len % CRYPT_SIZE ) return( FAIL ); CIdecode( (PTR)opb, len, ksch, (PTR)opb ); /* ** Remove padding and delimiter from last encryption block. */ while( len && (u_char)opb[ --len ] != CRYPT_DELIM ); opb[ len ] = EOS; /* ** Extract original password by skipping random salt at ** start of each encryption block. */ for( ptr = opb, len = 0; opb[ len ]; len++ ) if ( len % CRYPT_SIZE ) *ptr++ = opb[ len ]; *ptr = EOS; return( OK ); }
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 ); }