//---------------------------------------------------------------------- // 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; }
//---------------------------------------------------------------------- // 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; }
//---------------------------------------------------------------------- // 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; }
//------------------------------------------------------------------------- // 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; }
//------------------------------------------------------------------------- // 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; }