//---------------------------------------------------------------------- // Write Data Page for DS1963S. // // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to // indicate the symbolic port number. // 'pagenum' - page number to write to // 'data' - buffer to write into page // 'resume' - if true, device access is resumed using the RESUME // ROM command (0xA5). Otherwise, a a MATCH ROM is // used along with the device's entire address number. // // Return: TRUE - Write successfull // FALSE - error occurred during write. // SMALLINT WriteDataPageSHA18(int portnum, SMALLINT pagenum, uchar* data, SMALLINT resume) { uchar buffer[32]; int addr = pagenum << 5, addr_buff; uchar es = 0; OWASSERT( EraseScratchpadSHA18(portnum, addr, resume), OWERROR_ERASE_SCRATCHPAD_FAILED, FALSE ); OWASSERT( WriteScratchpadSHA18(portnum, addr, data, 32, TRUE), OWERROR_WRITE_SCRATCHPAD_FAILED, FALSE ); OWASSERT( ReadScratchpadSHA18(portnum, &addr_buff, &es, buffer, TRUE), OWERROR_READ_SCRATCHPAD_FAILED, FALSE ); // verify that what we read is exactly what we wrote OWASSERT( (addr == addr_buff) && (es == 0x1F) && (memcmp(buffer, data, 32)==0), OWERROR_READ_SCRATCHPAD_FAILED, FALSE ); OWASSERT( CopyScratchpadSHA18(portnum, addr, 32, TRUE), OWERROR_COPY_SCRATCHPAD_FAILED, FALSE ); return TRUE; }
//------------------------------------------------------------------------- // Creates a random challenge using the SHA engine of the given // coprocessor. // // 'copr' - Structure for holding coprocessor information. // 'pagenum' - pagenumber to use for calculation. // 'chlg' - 3-byte return buffer for challenge. // 'offset' - offset into resulting MAC to pull challenge data from. // // Return: TRUE - create challenge succeeded. // FALSE - an error occurred. // SMALLINT CreateChallenge(SHACopr* copr, SMALLINT pageNum, uchar* chlg, SMALLINT offset) { uchar scratchpad[32]; int addr = pageNum << 5; uchar es = 0x1F; int start = 8; if(offset>0 && offset<17) start += offset; //set the serial number owSerialNum(copr->portnum, copr->devAN, FALSE); OWASSERT( EraseScratchpadSHA18(copr->portnum, addr, FALSE), OWERROR_ERASE_SCRATCHPAD_FAILED, FALSE ); OWASSERT( SHAFunction18(copr->portnum, SHA_COMPUTE_CHALLENGE, addr, TRUE), OWERROR_SHA_FUNCTION_FAILED, FALSE ); OWASSERT( ReadScratchpadSHA18(copr->portnum, &addr, &es, scratchpad, TRUE), OWERROR_READ_SCRATCHPAD_FAILED, FALSE ); memcpy(chlg,&scratchpad[start],3); return TRUE; }
//---------------------------------------------------------------------- // Binds unique secret to DS1963S. bindData must be 32 bytes and // bindCode must be 15 bytes. // // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to // indicate the symbolic port number. // 'pagenum' - page number to do a read authenticate // 'secretnum' - destination secret for computation results // 'bindData' - the input data written to the data page for unique // secret computation. // 'bindCode' - the input data written to the scratchpad for unique // secret computation. // 'resume' - if true, device access is resumed using the RESUME // ROM command (0xA5). Otherwise, a a MATCH ROM is // used along with the device's entire address number. // // Return: TRUE - bind successfull // FALSE - error occurred during secret installation. // SMALLINT BindSecretToiButton18(int portnum, SMALLINT pagenum, SMALLINT secretnum, uchar* bindData, uchar* bindCode, SMALLINT resume) { int addr = pagenum << 5; uchar scratchpad[32]; memset(scratchpad, 0x00, 32); memcpy(&scratchpad[8], bindCode, 15); // write secret data into data page OWASSERT( WriteDataPageSHA18(portnum, pagenum, bindData, resume), OWERROR_WRITE_DATA_PAGE_FAILED, FALSE ); // write secret data into scratchpad OWASSERT( WriteScratchpadSHA18(portnum, addr, scratchpad, 32, TRUE), OWERROR_WRITE_SCRATCHPAD_FAILED, FALSE ); // perform secret computation OWASSERT( SHAFunction18(portnum, (uchar)SHA_COMPUTE_NEXT_SECRET, addr, TRUE), OWERROR_SHA_FUNCTION_FAILED, FALSE ); // copy the resulting secret into secret location OWASSERT( CopySecretSHA18(portnum, secretnum), OWERROR_COPY_SECRET_FAILED, FALSE); return TRUE; }
//---------------------------------------------------------------------- // Perform a scratchpad match using provided data. Fixed data length // of 20 bytes. // // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to // indicate the symbolic port number. // 'data' - data to use in match scratch operation // 'resume' - if true, device access is resumed using the RESUME // ROM command (0xA5). Otherwise, a a MATCH ROM is // used along with the device's entire address number. // // Return: TRUE - valid match // FALSE - no match or device not present // SMALLINT MatchScratchpadSHA18(int portnum, uchar* data, SMALLINT resume) { short send_cnt=0; uchar send_block[50]; int i; ushort lastcrc16; if(!resume) { // access the device OWASSERT( SelectSHA(portnum), OWERROR_ACCESS_FAILED, FALSE ); } else { // transmit RESUME command send_block[send_cnt++] = ROM_CMD_RESUME; } setcrc16(portnum,0); // match scratchpad command send_block[send_cnt] = CMD_MATCH_SCRATCHPAD; lastcrc16 = docrc16(portnum,send_block[send_cnt++]); // send 20 data bytes for (i = 0; i < 20; i++) { send_block[send_cnt] = data[i]; lastcrc16 = docrc16(portnum,send_block[send_cnt++]); } // send two crc bytes and verification byte //for (i = 0; i < 3; i++) // send_block[send_cnt++] = 0xFF; memset(&send_block[send_cnt], 0x0FF, 3); send_cnt += 3; // now send the block OWASSERT( owBlock(portnum,resume,send_block,send_cnt), OWERROR_BLOCK_FAILED, FALSE ); //\\//\\//\\//\\//\\//\\//\\//\\//\\// #ifdef DEBUG_DUMP debugout(send_block,send_cnt); #endif //\\//\\//\\//\\//\\//\\//\\//\\//\\// // check the CRC for (i = (send_cnt - 3); i < (send_cnt - 1); i++) lastcrc16 = docrc16(portnum,send_block[i]); // verify CRC16 is correct OWASSERT( lastcrc16==0xB001, OWERROR_CRC_FAILED, FALSE ); // check verification if(send_block[send_cnt - 1] != (uchar)0xFF) return TRUE; else return FALSE; }
//---------------------------------------------------------------------- // Read the scratchpad with CRC16 verification for DS1963S. // // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to // indicate the symbolic port number. // 'address' - pointer to address that is read from scratchpad // 'es' - pointer to offset byte read from scratchpad // 'data' - pointer data buffer read from scratchpad // 'resume' - if true, device access is resumed using the RESUME // ROM command (0xA5). Otherwise, a a MATCH ROM is // used along with the device's entire address number. // // Return: TRUE - scratch read, address, es, and data returned // FALSE - error reading scratch, device not present // // SMALLINT ReadScratchpadSHA18(int portnum, int* address, uchar* es, uchar* data, SMALLINT resume) { short send_cnt=0; uchar send_block[40]; SMALLINT i; ushort lastcrc16; if(!resume) { // access the device OWASSERT( SelectSHA(portnum), OWERROR_ACCESS_FAILED, FALSE ); } else { // transmit RESUME command send_block[send_cnt++] = ROM_CMD_RESUME; resume = 1; // for addition later } // read scratchpad command send_block[send_cnt++] = CMD_READ_SCRATCHPAD; // now add the read bytes for data bytes and crc16 //for (i = 0; i < 37; i++) // send_block[send_cnt++] = 0xFF; memset(&send_block[send_cnt], 0x0FF, 37); send_cnt += 37; // now send the block OWASSERT( owBlock(portnum,resume,send_block,send_cnt), OWERROR_BLOCK_FAILED, FALSE ); //\\//\\//\\//\\//\\//\\//\\//\\//\\// #ifdef DEBUG_DUMP debugout(send_block,send_cnt); #endif //\\//\\//\\//\\//\\//\\//\\//\\//\\// // calculate CRC16 of result setcrc16(portnum,0); for (i = resume; i < send_cnt ; i++) lastcrc16 = docrc16(portnum,send_block[i]); // verify CRC16 is correct OWASSERT( lastcrc16==0xB001, OWERROR_CRC_FAILED, FALSE ); // copy data to return buffers if(address) *address = (send_block[2+resume] << 8) | send_block[1+resume]; if(es) *es = send_block[3+resume]; memcpy(data, &send_block[4+resume], 32); // success return TRUE; }
//---------------------------------------------------------------------- // Copy the scratchpad with verification for DS1963S. Assume that the // data was padded to get the CRC16 verification on write scratchpad. // This will result in the 'es' byte to be 0x1F. // // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to // indicate the symbolic port number. // 'address' - address of destination // 'len' - length of data // 'resume' - if true, device access is resumed using the RESUME // ROM command (0xA5). Otherwise, a a MATCH ROM is // used along with the device's entire address number. // // Return: TRUE - copy scratch verified // FALSE - error during copy scratch, device not present, or HIDE // flag is in incorrect state for address being written. // SMALLINT CopyScratchpadSHA18(int portnum, int address, SMALLINT len, SMALLINT resume) { short send_cnt=0; uchar send_block[10]; int num_verf; uchar es = (address + len - 1) & 0x1F; if(!resume) { // access the device OWASSERT( SelectSHA(portnum), OWERROR_ACCESS_FAILED, FALSE ); } else { // transmit RESUME command send_block[send_cnt++] = ROM_CMD_RESUME; } // change number of verification bytes if in overdrive num_verf = (in_overdrive[portnum&0x0FF]) ? 4 : 2; // copy scratchpad command send_block[send_cnt++] = CMD_COPY_SCRATCHPAD; // address 1 send_block[send_cnt++] = (uchar)(address & 0xFF); // address 2 send_block[send_cnt++] = (uchar)((address >> 8) & 0xFF); // es send_block[send_cnt++] = es; // verification bytes //for (i = 0; i < num_verf; i++) // send_block[send_cnt++] = 0xFF; memset(&send_block[send_cnt], 0x0FF, num_verf); send_cnt += (short)num_verf; // now send the block OWASSERT( owBlock(portnum,resume,send_block,send_cnt), OWERROR_BLOCK_FAILED, FALSE ); //\\//\\//\\//\\//\\//\\//\\//\\//\\// #ifdef DEBUG_DUMP debugout(send_block,send_cnt); #endif //\\//\\//\\//\\//\\//\\//\\//\\//\\// // check verification OWASSERT( ((send_block[send_cnt-1] & 0xF0) == 0x50) || ((send_block[send_cnt-1] & 0xF0) == 0xA0), OWERROR_NO_COMPLETION_BYTE, FALSE ); return TRUE; }
//---------------------------------------------------------------------- // Installs new system secret for DS1931S. input_secret must be // divisible by 47. Then, each block of 47 is split up with 32 bytes // written to a data page and 15 bytes are written to the scratchpad. // Then, Compute first secret is called (or compute next if the secret // is divisible by 47 more than once). // // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to // indicate the symbolic port number. // 'pagenum' - page number to do a read authenticate // 'secretnum' - destination secret for computation results // 'input_secret' - the input secret buffer used. // 'secret_length' - the length of the input secret buffer, divisibly // by 47. // 'resume' - if true, device access is resumed using the RESUME // ROM command (0xA5). Otherwise, a a MATCH ROM is // used along with the device's entire address number. // // Return: TRUE - Install successfull // FALSE - error occurred during secret installation. // SMALLINT InstallSystemSecret18(int portnum, SMALLINT pagenum, SMALLINT secretnum, uchar* secret, int secret_length, SMALLINT resume) { int addr = pagenum << 5; int offset = 0, bytes_left = 0; uchar data[32],scratchpad[32]; for(offset=0; offset<secret_length; offset+=47) { // clear the buffer memset(data, 0x0FF, 32); memset(scratchpad, 0x0FF, 32); // Determine the amount of bytes remaining to be installed. bytes_left = secret_length - offset; // copy secret data into page buffer and scratchpad buffer memcpy(data, &secret[offset], (bytes_left<32?bytes_left:32)); if(bytes_left>32) { memcpy(&scratchpad[8], &secret[offset+32], (bytes_left<47?bytes_left-32:15)); } // write secret data into data page OWASSERT( WriteDataPageSHA18(portnum, pagenum, data, resume), OWERROR_WRITE_DATA_PAGE_FAILED, FALSE ); // write secret data into scratchpad OWASSERT( WriteScratchpadSHA18(portnum, addr, scratchpad, 32, TRUE), OWERROR_WRITE_SCRATCHPAD_FAILED, FALSE ); // perform secret computation OWASSERT( SHAFunction18(portnum, (uchar)(offset==0 ? SHA_COMPUTE_FIRST_SECRET : SHA_COMPUTE_NEXT_SECRET), addr, TRUE), OWERROR_SHA_FUNCTION_FAILED, FALSE ); // copy the resulting secret into secret location OWASSERT( CopySecretSHA18(portnum, secretnum), OWERROR_COPY_SECRET_FAILED, FALSE); resume = TRUE; } return TRUE; }
//------------------------------------------------------------------------- // Answers a random challenge by performing an authenticated read of the // user's account information. // // 'user' - Structure for holding user token information. // 'chlg' - 3-byte buffer of challenge data. // // Return: the value of the write cycle counter for the account page. // or -1 if there is an error // int AnswerChallenge(SHAUser* user, uchar* chlg) { int addr = user->accountPageNumber << 5; user->writeCycleCounter = -1; memcpy(&user->accountFile[20], chlg, 3); //set the serial number owSerialNum(user->portnum, user->devAN, FALSE); if(user->devAN[0]==0x18) { // for the DS1963S OWASSERT( EraseScratchpadSHA18(user->portnum, addr, FALSE), OWERROR_ERASE_SCRATCHPAD_FAILED, -1 ); OWASSERT( WriteScratchpadSHA18(user->portnum, addr, user->accountFile, 32, TRUE), OWERROR_WRITE_SCRATCHPAD_FAILED, -1 ); user->writeCycleCounter = ReadAuthPageSHA18(user->portnum, user->accountPageNumber, user->accountFile, user->responseMAC, TRUE); } else if(user->devAN[0]==0x33||user->devAN[0]==0xB3) { // for the DS1961S OWASSERT( WriteScratchpadSHA33(user->portnum, addr, &user->accountFile[16], FALSE), OWERROR_WRITE_SCRATCHPAD_FAILED, -1 ); user->writeCycleCounter = ReadAuthPageSHA33(user->portnum, user->accountPageNumber, user->accountFile, user->responseMAC, TRUE); } return user->writeCycleCounter; }
//---------------------------------------------------------------------- // Read Memory Page for DS1963S. // // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to // indicate the symbolic port number. // 'pagenum' - page number to do a read authenticate // 'data' - buffer to read into from page // 'resume' - if true, device access is resumed using the RESUME // ROM command (0xA5). Otherwise, a a MATCH ROM is // used along with the device's entire address number. // // Return: TRUE - Read successfull // FALSE - error occurred during read. // SMALLINT ReadMemoryPageSHA18(int portnum, SMALLINT pagenum, uchar* data, SMALLINT resume) { short send_cnt=0; uchar send_block[36]; int address = pagenum << 5; if(!resume) { // access the device OWASSERT( SelectSHA(portnum), OWERROR_ACCESS_FAILED, -1 ); } else { // transmit RESUME command send_block[send_cnt++] = ROM_CMD_RESUME; } // create the send block // Read Memory command send_block[send_cnt++] = CMD_READ_MEMORY; // TA1 send_block[send_cnt++] = (uchar)(address & 0xFF); // TA2 send_block[send_cnt++] = (uchar)((address >> 8) & 0xFF); // now add the read bytes for data bytes memset(&send_block[send_cnt], 0x0FF, 32); send_cnt += 32; // now send the block OWASSERT( owBlock(portnum,TRUE,send_block,send_cnt), OWERROR_BLOCK_FAILED, FALSE ); // transfer the results memcpy(data, &send_block[send_cnt-32], 32); return TRUE; }
//------------------------------------------------------------------------- // Creates a data signature for the given data buffer using the hardware // coprocessor. // // 'copr' - Structure for holding coprocessor information. // 'data' - data written to the data page to sign // 'scratchpad' - data written to the scratchpad to sign // 'signature' - data buffer which is either holding the signature that // must match exactly what is generated on the coprocessor // -or- will hold the resulting signature created by the // coprocessor. // 'readSignature' - implies whether or not the signature buffer // receives the contents of the scratchpad or is used to // match the contents of the scratchpad. If true, // scratchpad contents are read into the signature buffer. // // Return: If TRUE, the user's authentication response matched exactly the // signature generated by the coprocessor or the signature was // successfully copied into the return buffer. // If FALSE, an error occurred or the signature did not match. // SMALLINT CreateDataSignature(SHACopr* copr, uchar* data, uchar* scratchpad, uchar* signature, SMALLINT readSignature) { int addr = copr->signPageNumber << 5; // set the serial number to that of the coprocessor owSerialNum(copr->portnum, copr->devAN, FALSE); OWASSERT( WriteDataPageSHA18(copr->portnum, copr->signPageNumber, data, FALSE), OWERROR_WRITE_DATA_PAGE_FAILED, FALSE ); OWASSERT( WriteScratchpadSHA18(copr->portnum, addr, scratchpad, 32, TRUE), OWERROR_WRITE_SCRATCHPAD_FAILED, FALSE ); OWASSERT( SHAFunction18(copr->portnum, SHA_SIGN_DATA_PAGE, addr, TRUE), OWERROR_SHA_FUNCTION_FAILED, FALSE ); if(readSignature) { OWASSERT( ReadScratchpadSHA18(copr->portnum, 0, 0, scratchpad, TRUE), OWERROR_READ_SCRATCHPAD_FAILED, FALSE ); } else { OWASSERT( MatchScratchpadSHA18(copr->portnum, signature, TRUE), OWERROR_MATCH_SCRATCHPAD_FAILED, FALSE ); } memcpy(signature, &scratchpad[8], 20); return TRUE; }
//------------------------------------------------------------------------- // Updates service data on a user token. This includes signing the // data if the part is a DS1963S. // // 'copr' - Structure for holding coprocessor information. // 'user' - Structure for holding user token information. // // Return: If TRUE, update succeeded. // If FALSE, an error occurred. // SMALLINT UpdateServiceData(SHACopr* copr, SHAUser* user) { ushort crc16, i; uchar scratchpad[32]; if(user->devAN[0] == 0x18) { DebitFile* accountFile = (DebitFile*)user->accountFile; // make sure length is right. accountFile->fileLength = 29; // update transaction ID // doesn't matter what it is, just needs to change accountFile->transID[0] += 1; if(accountFile->transID[0]==0) accountFile->transID[1] += 1; // conversion factor - 2 data bytes accountFile->convFactor[0] = (uchar)0x8B; accountFile->convFactor[1] = (uchar)0x48; // clear out the old signature and CRC memcpy(accountFile->signature, copr->initSignature, 20); memset(accountFile->crc16, 0x00, 2); // reset data type code accountFile->dataTypeCode = 1; //file doesn't continue on another page accountFile->contPtr = 0; // --- Set up the scratchpad for signing memset(scratchpad, 0x00, 32); // the write cycle counter +1 (since we are about to write this to it) if(user->writeCycleCounter>0) IntToBytes(&scratchpad[8], 4, user->writeCycleCounter+1); else // user doesn't have write cycle counter (DS1961S) memset(&scratchpad[8], 0x0FF, 4); // the pagenumber scratchpad[12] = (uchar)user->accountPageNumber; // and 7 bytes of the address of current device memcpy(&scratchpad[13], user->devAN, 7); // the coprocessor's signing challenge memcpy(&scratchpad[20], copr->signChlg, 3); OWASSERT( CreateDataSignatureVM(copr, sign_secret, user->accountFile, scratchpad, accountFile->signature, TRUE), OWERROR_SIGN_SERVICE_DATA_FAILED, FALSE ); //add the crc at the end of the data. setcrc16(user->portnum, user->accountPageNumber); for (i = 0; i < 30; i++) crc16 = docrc16(user->portnum,user->accountFile[i]); crc16 = ~crc16; accountFile->crc16[0] = (uchar)crc16; accountFile->crc16[1] = (uchar)(crc16>>8); }
//---------------------------------------------------------------------- // Copies hidden scratchpad data into specified secret. Resume command // is used by default. // // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to // indicate the symbolic port number. // 'secretnum' - secret number to replace with scratchpad data. // // Return: TRUE - copy secret succeeded // FALSE - error or device not present // SMALLINT CopySecretSHA18(int portnum, SMALLINT secretnum) { // change number of verification bytes if in overdrive SMALLINT num_verf = (in_overdrive[portnum&0x0FF]) ? 10 : 2; // each page has 4 secrets, so look at 2 LS bits to // determine offset in the page. SMALLINT secret_offset = (secretnum&3) << 3; // secrets 0-3 are stored starting at address 0200h // and 4-7 are stored starting at address 0220h. int address = (secretnum<4 ? 0x0200 : 0x0220) + secret_offset; SMALLINT length = 32 - secret_offset; SMALLINT send_cnt = 0, i; uchar send_block[38]; ushort lastcrc16; //Since other functions must be called before this one //that are communicating with the button, resume is assumed. send_block[send_cnt++] = ROM_CMD_RESUME; send_block[send_cnt++] = CMD_WRITE_SCRATCHPAD; send_block[send_cnt++] = (uchar)address; send_block[send_cnt++] = (uchar)(address>>8); //for(i=0; i<length+2; i++) // send_block[send_cnt++] = (uchar)0x0FF; memset(&send_block[send_cnt], 0x0FF, 2+length); send_cnt += 2+length; // now send the block OWASSERT( owBlock(portnum,TRUE,send_block,send_cnt), OWERROR_BLOCK_FAILED, FALSE ); //\\//\\//\\//\\//\\//\\//\\//\\//\\// #ifdef DEBUG_DUMP debugout(send_block,send_cnt); #endif //\\//\\//\\//\\//\\//\\//\\//\\//\\// // calculate CRC16 of result setcrc16(portnum,0); for (i = 1; i < send_cnt ; i++) lastcrc16 = docrc16(portnum,send_block[i]); // verify CRC16 is correct OWASSERT( lastcrc16==0xB001, OWERROR_CRC_FAILED, FALSE ); // Now read TA1/TA2 and ES, but not rest of data; send_cnt = 1; send_block[send_cnt++] = CMD_READ_SCRATCHPAD; //for(i=0; i<3; i++) // send_block[send_cnt++] = (uchar)0x0FF; memset(&send_block[send_cnt], 0x0FF, 3); send_cnt += 3; // now send the block to get TA1/TA2 and ES OWASSERT( owBlock(portnum,TRUE,send_block,send_cnt), OWERROR_BLOCK_FAILED, FALSE ); //\\//\\//\\//\\//\\//\\//\\//\\//\\// #ifdef DEBUG_DUMP debugout(send_block,send_cnt); #endif //\\//\\//\\//\\//\\//\\//\\//\\//\\// // Use the same buffer to call copyScratchpad with proper // authorization bytes. send_block[1] = CMD_COPY_SCRATCHPAD; //for(i=0; i<num_verf; i++) // send_block[send_cnt++] = (uchar)0x0FF; memset(&send_block[send_cnt], 0x0FF, num_verf); send_cnt += num_verf; // now send the block OWASSERT( owBlock(portnum,TRUE,send_block,send_cnt), OWERROR_BLOCK_FAILED, FALSE ); //\\//\\//\\//\\//\\//\\//\\//\\//\\// #ifdef DEBUG_DUMP debugout(send_block,send_cnt); #endif //\\//\\//\\//\\//\\//\\//\\//\\//\\// // check verification OWASSERT( ((send_block[send_cnt-1] & 0xF0) == 0x50) || ((send_block[send_cnt-1] & 0xF0) == 0xA0), OWERROR_NO_COMPLETION_BYTE, FALSE ); return TRUE; }
//---------------------------------------------------------------------- // Compute sha command based on control_byte and page address. // // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to // indicate the symbolic port number. // 'control_byte' - control byte used in sha operation // 'address' - address used in compute sha operation // 'resume' - if true, device access is resumed using the RESUME // ROM command (0xA5). Otherwise, a a MATCH ROM is // used along with the device's entire address number. // // Return: TRUE - compute sha finished // FALSE - CRC error, device not present // SMALLINT SHAFunction18(int portnum, uchar control_byte, int address, SMALLINT resume) { short send_cnt=0; uchar send_block[18]; int i,num_verf; ushort lastcrc16; if(!resume) { // access the device OWASSERT( SelectSHA(portnum), OWERROR_ACCESS_FAILED, FALSE ); } else { // transmit RESUME command send_block[send_cnt++] = ROM_CMD_RESUME; } setcrc16(portnum,0); // change number of verification bytes if in overdrive num_verf = (in_overdrive[portnum&0x0FF]) ? 10 : 2; // Compute SHA Command send_block[send_cnt] = CMD_COMPUTE_SHA; lastcrc16 = docrc16(portnum,send_block[send_cnt++]); // address 1 send_block[send_cnt] = (uchar)(address & 0xFF); lastcrc16 = docrc16(portnum,send_block[send_cnt++]); // address 2 send_block[send_cnt] = (uchar)((address >> 8) & 0xFF); lastcrc16 = docrc16(portnum,send_block[send_cnt++]); // control byte send_block[send_cnt] = control_byte; lastcrc16 = docrc16(portnum,send_block[send_cnt++]); // now read bytes crc16, and verification //for (i = 0; i < 2 + num_verf; i++) // send_block[send_cnt++] = 0xFF; memset(&send_block[send_cnt], 0x0FF, 2+num_verf); send_cnt += 2+num_verf; // now send the block OWASSERT( owBlock(portnum,resume,send_block,send_cnt), OWERROR_BLOCK_FAILED, FALSE ); //\\//\\//\\//\\//\\//\\//\\//\\//\\// #ifdef DEBUG_DUMP debugout(send_block,send_cnt); #endif //\\//\\//\\//\\//\\//\\//\\//\\//\\// // check the CRC for (i = resume?5:4; i < (send_cnt - num_verf); i++) lastcrc16 = docrc16(portnum,send_block[i]); // verify CRC16 is correct OWASSERT( lastcrc16==0xB001, OWERROR_CRC_FAILED, FALSE ); // check verification OWASSERT( ((send_block[send_cnt-1] & 0xF0) == 0x50) || ((send_block[send_cnt-1] & 0xF0) == 0xA0), OWERROR_NO_COMPLETION_BYTE, FALSE ); return TRUE; }
//---------------------------------------------------------------------- // Read Authenticated Page for DS1963S. // // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to // indicate the symbolic port number. // 'pagenum' - page number to do a read authenticate // 'data' - buffer to read into from page // 'sign' - buffer for storing sha computation // 'resume' - if true, device access is resumed using the RESUME // ROM command (0xA5). Otherwise, a a MATCH ROM is // used along with the device's entire address number. // // Return: Value of write cycle counter for the page // -1 for error // int ReadAuthPageSHA18(int portnum, SMALLINT pagenum, uchar* data, uchar* sign, SMALLINT resume) { short send_cnt=0; uchar send_block[56]; short num_verf; SMALLINT i; ushort lastcrc16; int address = pagenum*32, wcc = -1; if(!resume) { // access the device OWASSERT( SelectSHA(portnum), OWERROR_ACCESS_FAILED, -1 ); } else { // transmit RESUME command send_block[send_cnt++] = ROM_CMD_RESUME; } //seed the crc setcrc16(portnum,0); // change number of verification bytes if in overdrive num_verf = (in_overdrive[portnum&0x0FF]) ? 10 : 2; // create the send block // Read Authenticated Page command send_block[send_cnt] = CMD_READ_AUTH_PAGE; lastcrc16 = docrc16(portnum, send_block[send_cnt++]); // TA1 send_block[send_cnt] = (uchar)(address & 0xFF); lastcrc16 = docrc16(portnum,send_block[send_cnt++]); // TA2 send_block[send_cnt] = (uchar)((address >> 8) & 0xFF); lastcrc16 = docrc16(portnum,send_block[send_cnt++]); // now add the read bytes for data bytes, counter, and crc16, verification //for (i = 0; i < (42 + num_verf); i++) // send_block[send_cnt++] = 0xFF; memset(&send_block[send_cnt], 0x0FF, 42+num_verf); send_cnt += 42+num_verf; // now send the block OWASSERT( owBlock(portnum,resume,send_block,send_cnt), OWERROR_BLOCK_FAILED, -1 ); //\\//\\//\\//\\//\\//\\//\\//\\//\\// #ifdef DEBUG_DUMP debugout(send_block,send_cnt); #endif //\\//\\//\\//\\//\\//\\//\\//\\//\\// // check the CRC for (i = resume?4:3; i < (send_cnt - num_verf); i++) lastcrc16 = docrc16(portnum,send_block[i]); // verify CRC16 is correct OWASSERT( lastcrc16==0xB001, OWERROR_CRC_FAILED, -1); // check verification OWASSERT( ((send_block[send_cnt-1] & 0xF0) == 0x50) || ((send_block[send_cnt-1] & 0xF0) == 0xA0), OWERROR_NO_COMPLETION_BYTE, -1); // transfer results //cnt = 0; //for (i = send_cnt - 42 - num_verf; i < (send_cnt - 10 - num_verf); i++) // data[cnt++] = send_block[i]; memcpy(data, &send_block[send_cnt-42-num_verf], 32); wcc = BytesToInt(&send_block[send_cnt-10-num_verf], 4); if(sign!=NULL) { OWASSERT( ReadScratchpadSHA18(portnum, 0, 0, send_block, TRUE), OWERROR_READ_SCRATCHPAD_FAILED, FALSE ); //for(i=0; i<20; i++) // sign[i] = send_block[i+8]; memcpy(sign, &send_block[8], 20); } return wcc; }
//------------------------------------------------------------------------- // Verifies the authentication response of a user token. // // 'copr' - Structure for holding coprocessor information. // 'user' - Structure for holding user token information. // 'chlg' - 3-byte buffer of challenge data. // 'doBind' - if true, the user's unique secret is recreated on the // coprocessor. If this function is called multiple times, // it is acceptable to skip the bind for all calls after // the first on the same user token. // // Return: If TRUE, the user's authentication response matched exactly the // signature generated by the coprocessor. // If FALSE, an error occurred or the signature did not match. // SMALLINT VerifyAuthResponse(SHACopr* copr, SHAUser* user, uchar* chlg, SMALLINT doBind) { int addr = copr->wspcPageNumber << 5; int wcc = user->writeCycleCounter; uchar sign_cmd; uchar scratchpad[32]; uchar fullBindCode[15]; memset(scratchpad, 0x00, 32); memset(fullBindCode, 0x0FF, 15); // format the bind code properly if(user->devAN[0]==0x18) { // Format for DS1963S memcpy(fullBindCode, copr->bindCode, 4); memcpy(&fullBindCode[12], &(copr->bindCode[4]), 3); // use ValidateDataPage command sign_cmd = SHA_VALIDATE_DATA_PAGE; // copy wcc LSB first if(!IntToBytes(&scratchpad[8], 4, wcc)) OWERROR(OWERROR_NO_ERROR_SET); } else if(user->devAN[0]==0x33||user->devAN[0]==0xB3) { // Leave bindCode FF for DS1961S // Use AuthenticateHost command sign_cmd = SHA_AUTHENTICATE_HOST; // the user doesn't have a write cycle counter memset(&scratchpad[8], 0x0FF, 4); } else { OWERROR(OWERROR_WRONG_TYPE); return FALSE; } // the pagenumber fullBindCode[4] = (uchar)user->accountPageNumber; // and 7 bytes of the address of current device memcpy(&fullBindCode[5], user->devAN, 7); // get the user address and page num from fullBindCode memcpy(&scratchpad[12], &fullBindCode[4], 8); // set the same challenge bytes memcpy(&scratchpad[20], chlg, 3); // set the serial number to that of the coprocessor owSerialNum(copr->portnum, copr->devAN, FALSE); // install user's unique secret on the wspc secret if(doBind) { OWASSERT( BindSecretToiButton18(copr->portnum, copr->authPageNumber, copr->wspcPageNumber&7, copr->bindData, fullBindCode, FALSE), OWERROR_BIND_SECRET_FAILED, FALSE ); if(user->devAN[0]==0x33||user->devAN[0]==0xB3) { // also copy the resulting secret into secret location 0, to // replace the signing secret. Necessary for producing the // DS1961S's write-authorization MAC. OWASSERT( CopySecretSHA18(copr->portnum, 0), OWERROR_COPY_SECRET_FAILED, FALSE); } } // recreate the signature and verify OWASSERT( WriteDataPageSHA18(copr->portnum, copr->wspcPageNumber, user->accountFile, doBind), OWERROR_WRITE_DATA_PAGE_FAILED, FALSE ); OWASSERT( WriteScratchpadSHA18(copr->portnum, addr, scratchpad, 32, TRUE), OWERROR_WRITE_SCRATCHPAD_FAILED, FALSE ); OWASSERT( SHAFunction18(copr->portnum, sign_cmd, addr, TRUE), OWERROR_SHA_FUNCTION_FAILED, FALSE ); OWASSERT( MatchScratchpadSHA18(copr->portnum, user->responseMAC, TRUE), OWERROR_MATCH_SCRATCHPAD_FAILED, FALSE ); return TRUE; }
//------------------------------------------------------------------------- // Installs new service data on a user token. // // 'copr' - Structure for holding coprocessor information. // 'user' - Structure for holding user token information. // 'secret' - the authentication secret to install on user token. // // Return: If TRUE, new service installation succeeded. // If FALSE, an error occurred. // SMALLINT InstallServiceData(SHACopr* copr, SHAUser* user, uchar* secret, int secret_length, int initialBalance) { short handle; int maxwrite; FileEntry fe; uchar fullBindCode[15]; //make sure user has a file directory structure memcpy(fe.Name, copr->serviceFilename, 4); fe.Ext = copr->serviceFilename[4]; // install master authentication secret if(user->devAN[0]==0x18) { //need to format the device if(!owFormat(user->portnum, user->devAN)) return FALSE; //and create an empty stub for his account information if(!owCreateFile(user->portnum, user->devAN, &maxwrite, &handle, &fe)) return FALSE; //need to know what page the stub is on user->accountPageNumber = fe.Spage; // set the serial number to that of the user owSerialNum(user->portnum, user->devAN, FALSE); OWASSERT( InstallSystemSecret18(user->portnum, user->accountPageNumber, user->accountPageNumber&7, secret, secret_length, FALSE), OWERROR_INSTALL_SECRET_FAILED, FALSE ); } else if((user->devAN[0]&0x7F)==0x33) { // set the serial number to that of the user owSerialNum(user->portnum, user->devAN, FALSE); //because of copy-authorization, we need to install the //secret first on the DS1961S and _then_ format the system OWASSERT( InstallSystemSecret33(user->portnum, 0, 0, secret, secret_length, FALSE), OWERROR_INSTALL_SECRET_FAILED, FALSE ); //need to format the device if(!owFormat(user->portnum, user->devAN)) return FALSE; //and create an empty stub for his account information if(!owCreateFile(user->portnum, user->devAN, &maxwrite, &handle, &fe)) return FALSE; //need to know what page the stub is on user->accountPageNumber = fe.Spage; } else { return FALSE; } // format the bind code properly // first four bytes of bind code memcpy(fullBindCode, copr->bindCode, 4); // followed by the pagenumber fullBindCode[4] = (uchar)user->accountPageNumber; // and 7 bytes of the address of current device memcpy(&fullBindCode[5], user->devAN, 7); // followed by the last 3 bytes of bind code memcpy(&fullBindCode[12], &(copr->bindCode[4]), 3); // create a unique secret for iButton if(user->devAN[0]==0x18) { DebitFile* accountFile = (DebitFile*)user->accountFile; OWASSERT( BindSecretToiButton18(user->portnum, user->accountPageNumber, user->accountPageNumber&7, copr->bindData, fullBindCode, TRUE), OWERROR_BIND_SECRET_FAILED, FALSE ); // do a read just to get value of writecycle counter user->writeCycleCounter = ReadAuthPageSHA18(user->portnum, user->accountPageNumber, user->accountFile, NULL, TRUE); //setup user account file with initial balance IntToBytes(accountFile->balanceBytes,3,initialBalance); // set transaction ID accountFile->transID[0] = 0; accountFile->transID[0] = 0; } else if((user->devAN[0]&0x7F)==0x33) { DebitFile33* accountFile33 = (DebitFile33*)user->accountFile; OWASSERT( BindSecretToiButton33(user->portnum, user->accountPageNumber, 0, copr->bindData, fullBindCode, TRUE), OWERROR_BIND_SECRET_FAILED, FALSE ); // Call VerifyUser just to get the user's secret in wspc if(!VerifyUser(copr, user, TRUE)) return FALSE; //Record A //setup user account file with initial balance IntToBytes(accountFile33->balanceBytes_A,3,initialBalance); // set transaction ID accountFile33->transID_A[0] = 0; accountFile33->transID_A[0] = 0; //Record B //setup user account file with initial balance IntToBytes(accountFile33->balanceBytes_B,3,initialBalance); // set transaction ID accountFile33->transID_B[0] = 0; accountFile33->transID_B[0] = 0; } //sign the data with coprocessor and write it out return UpdateServiceData(copr, user); }
//---------------------------------------------------------------------- // Write the scratchpad with CRC16 verification for DS1963S. The data // is padded until the offset is 0x1F so that the CRC16 is retrieved. // // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to // indicate the symbolic port number. // 'address' - address to write data to // 'data' - data to write // 'data_len' - number of bytes of data to write // 'resume' - if true, device access is resumed using the RESUME // ROM command (0xA5). Otherwise, a a MATCH ROM is // used along with the device's entire address number. // // Return: TRUE - write to scratch verified // FALSE - error writing scratch, device not present, or HIDE // flag is in incorrect state for address being written. // SMALLINT WriteScratchpadSHA18(int portnum, int address, uchar *data, SMALLINT data_len, SMALLINT resume) { uchar send_block[50]; short send_cnt=0,i; ushort lastcrc16; if(!resume) { // access the device OWASSERT( SelectSHA(portnum), OWERROR_ACCESS_FAILED, FALSE ); } else { // transmit RESUME command send_block[send_cnt++] = ROM_CMD_RESUME; } setcrc16(portnum,0); // write scratchpad command send_block[send_cnt] = CMD_WRITE_SCRATCHPAD; lastcrc16 = docrc16(portnum,send_block[send_cnt++]); // address 1 send_block[send_cnt] = (uchar)(address & 0xFF); lastcrc16 = docrc16(portnum,send_block[send_cnt++]); // address 2 send_block[send_cnt] = (uchar)((address >> 8) & 0xFF); lastcrc16 = docrc16(portnum,send_block[send_cnt++]); // data for (i = 0; i < data_len; i++) { send_block[send_cnt] = data[i]; lastcrc16 = docrc16(portnum,send_block[send_cnt++]); } // pad if needed for (i = 0; i < (0x1F - ((address + data_len - 1) & 0x1F)); i++) { send_block[send_cnt] = 0xFF; lastcrc16 = docrc16(portnum,send_block[send_cnt++]); } // CRC16 send_block[send_cnt++] = 0xFF; send_block[send_cnt++] = 0xFF; // now send the block OWASSERT( owBlock(portnum,resume,send_block,send_cnt), OWERROR_BLOCK_FAILED, FALSE ); //\\//\\//\\//\\//\\//\\//\\//\\//\\// #ifdef DEBUG_DUMP debugout(send_block,send_cnt); #endif //\\//\\//\\//\\//\\//\\//\\//\\//\\// // perform CRC16 of last 2 byte in packet for (i = send_cnt - 2; i < send_cnt; i++) lastcrc16 = docrc16(portnum,send_block[i]); // verify CRC16 is correct OWASSERT( lastcrc16==0xB001, OWERROR_CRC_FAILED, FALSE ); // success return TRUE; }