|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: INNER | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object | +--com.dalsemi.onewire.container.SHAiButton
High level class implementing transactions and authentications for a DS1963S, Sha iButton.
This class makes use of several performance enhancements for TINI.
For instance, most methods are synchronized
to access instance variable
byte arrays rather than creating new byte arrays every time a transaction
is performed. This could hurt performance in multi-threaded
applications, but the usefulness of having several threads contending
to talk to a single iButton is questionable since the methods in com.dalsemi.onewire.adapter.DSPortAdapter
beginExclusive(boolean)
and endExclusive()
should be used.
A DS1963S SHA iButton can be a Coprocessor or a User. A Coprocessor iButton verifies signatures and signs data for User iButtons. A Coprocessor might be located inside a vending machine, where a person would bring their User iButton. When the User iButton is pressed to the Blue Dot to perform a transaction, the Coprocessor would first verify that this button belongs to the system, i.e. that it knows the same authentication secret (example: a Visa terminal making sure the iButton had a Visa account installed). Then the Coprocessor would verify the signed data, probably money, to make sure it was valid. If someone tried to overwrite the money file, even with a previously valid money file (an attempt to 'restore' a previous amount of money), the signed file would be invalid because the signature includes the write cycle counter, which is incremented every time a page is written to. The write cycle counter is read-only and does not roll over, so the previous amount of money could not be restored by rolling the write counter. The Coprocessor verifies the money, then signs a new data file that contains the new amount of money.
There are two secrets involved with the transaction process. The first secret is the authentication secret. It is used to validate a User iButton to a system. The Coprocessor iButton has the system authentication secret installed. On User iButtons, the system authentication secret is merged with binding data and the unique address of the User iButton to create a unique device authentication secret. The second secret is a signing secret. This secret only exists on the Coprocessor iButton, and is used to sign and verify data such as money. These secrets are inaccessible outside the iButton. Once they are installed, they cannot be retrieved.
There are two main operations involved in initializing a DS1963S to be a Coprocessor iButton for transactions. First, it must have a Coprocessor file that defines parameters for the system. Second, it must install a master authentication secret and a signing secret.
Dallas Semiconductor has created a suggested format for Coprocessor files to help developers implement systems for authentication and transactions. The structure is as follows:
|
# bytes | |
Name of user account data file | |
|
Signing page number | |
|
Authentication page number | |
|
Workspace page number | |
|
Version number | |
|
Installation data code | |
|
Binding data | |
|
Binding code | |
|
Signing challenge | |
|
Provider name length (LN) | |
|
Initial Signature length (LS) | |
|
Extra data length (LE) | |
|
Service provider name | |
|
Initial signature | |
|
Extra data | |
|
Encryption algorithm code | |
|
This class assumes the use of TMEX files. The code below shows how to set up a Coprocessor iButton using the TMEX file format and the service file format discussed above.
//preformatted root directory page for TMEX
byte[] page0 =
{
(byte)0x0F, (byte)0xAA, (byte)0x00, (byte)0x80, (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x43, (byte)0x4F, (byte)0x50, (byte)0x52, (byte)0x00, (byte)0x01, (byte)0x01, (byte)0x00,
(byte)0x74, (byte)0x9C, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF
};
. . .
//adapter is a DSPortAdapter that has just found a DS1963S
OneWireContainer18 owc18 = new OneWireContainer18();
owc18.setupContainer(adapter,adapter.getAddressAsLong());
//we will control the speed of the 1-Wire bus, don't do speed check
owc18.setSpeedCheck(false);
SHAiButton sha = new SHAiButton(owc18);
//first we need to accumulate data for our service file
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write("DLSM".getBytes()); //coprocessor service file name
baos.write(102); //coprocessor service file extension
baos.write(8); //signing page
baos.write(7); //authentication page
baos.write(9); //workspace page
baos.write(1); //version number
baos.write(10); //date stamp: month
baos.write(18); //date stamp: date
baos.write(20); //date stamp: year / 100
baos.write(0); //date stamp: year % 100
//32 bytes of bind data
baos.write("01234567890123456789012345678901".getBytes());
baos.write("binding".getBytes()); //bind code, 7 bytes
baos.write(new byte[3]); //signing challenge, 3 bytes
baos.write("Dallas Semiconductor".length()); //provider of the service
baos.write(20); //initial signature length (20)
baos.write(0); //extra data length
baos.write("Dallas Semiconductor".getBytes()); //provider of the service
baos.write(new byte[20]); //initial signature
baos.write("".getBytes()); //any extra data
baos.write(0); //an encryption code
byte[] data = baos.toByteArray();
//start writing the page at page 1 of the Coprocessor,
//since page 0 will be taken by the TMEX root directory file
int page = 1;
byte[] this_page = new byte[32];
int index = 0;
int length;
while (index < data.length)
{
//this loop handles breaking the data into
//TMEX file structure compatible pages
if (data.length - index > 28)
length = 28;
else
length = data.length - index;
this_page[0] = (byte)(length + 1);
System.arraycopy(data,index,this_page,1,length);
index += length;
if (index//make sure this is an inverted CRC
crc = (~crc) & 0x0ffff;
this_page[length+2] = (byte) crc;
this_page[length+3] = (byte) (crc >> 8);
owc18.writeDataPage(page,this_page);
page++;
}
//now we have written the entire COPR.0 file, now we
//need to fix up page 0, the root directory
//make a bitmask of which pages we have used. since we
//have used all pages from 0 to (page-1), this trick will work
int mask = (0x01 << (page)) - 1;
//now put that int (LSB first) in page0[4..7]
page0[4] = (byte)(mask);
page0[5] = (byte)(mask >> 8);
page0[6] = (byte)(mask >> 16);
page0[7] = (byte)(mask >> 24 );
//now how many pages were used for file COPR.000?
//if we used (page) pages, and page 0 is the root, then there are page-1 pages in the file
//stick it in the file at position 14
page0[14] = (byte)(page-1);
//now recalculate the CRC for the root directory
int CRC = ~CRC16.compute(page0,0,page0[0]+1);
page0[page0[0]+1] = (byte)CRC;
page0[page0[0]+2] = (byte)(CRC >> 8);
//now we have to fix page 0
if ((!owc18.eraseScratchPad(0)) || (!owc18.writeDataPage(0,page0)))
{
System.out.println("Failed to write page 0");
return;
}
//done with root directory, now install signing secret and an authentication secret
byte[] sign_secret = "this is my signing secret".getBytes();
byte[] auth_secret = "this is my authentication secret".getBytes();
if (!owc18.installMasterSecret(8,sign_secret,0))
System.out.println("Could not install master signing secret!");
else
System.out.println("Signing secret installed.");
if (!owc18.installMasterSecret(7,auth_secret,7))
System.out.println("Could not install master authentication secret!");
else
System.out.println("Authentication secret installed.");
In order to initialize a SHAiButton
object to be used as
a Coprocessor iButton, read the "COPR.0" file from the DS1963S using
the readFile(int)
command. Use the file data to make calls to
setup this iButton as a Coprocessor. See isCoprocessor()
for which parameters must be set to act as a Coprocessor. The next section
also describes setting up a SHAiButton
object to act as a Coprocessor.
Initializing a User iButton also requires two steps. The first is finding and gathering information from a Coprocessor iButton. The second is installing an authentication secret and an initial money page on the User iButton.
I. The following code shows how gather data from a Coprocessor iButton
and setup a SHAiButton
object to act as a Coprocessor.
//adapter is a DSPortAdapter, ID is the byte[] address of the DS1963S
// that has already been found
SHAiButton copr = null;
OneWireContainer18 ds1963S = (OneWireContainer18) adapter.getDeviceContainer(ID);
ds1963S.setupContainer(adapter,ID);
ds1963S.setSpeedCheck(false);
SHAiButton sha = new SHAiButton(ds1963S);
byte[] filebuffer = new byte[400];
filelength = sha.readFile(0, filebuffer);
//look for the file "COPR.000"
byte[] file = "COPR".getBytes();
int filepage = -1;
for (i=0;i < filelength;i++)
{
if (filebuffer[i]==file[0])
if (filebuffer[i+1]==file[1])
if (filebuffer[i+2]==file[2])
if (filebuffer[i+3]==file[3])
if (filebuffer[i+4]==(byte)0) //000 is the extension
filepage = filebuffer[i+5];
}
if (filepage==-1)
{
System.out.println("Could not find the file page!!!");
}
else
{
filelength = sha.readFile(filepage, filebuffer);
sha.setFilename(filebuffer,0);
sha.setSigningPageNumber(filebuffer[5]);
sha.setAuthenticationPageNumber(filebuffer[6]);
sha.setWorkspacePageNumber(filebuffer[7]);
//note: not all Dallas Semiconductor demo's include the bind
// data and bind code in the COPR.000 file, which is why
// we check the file length here
if (filelength >= 45)
sha.setBindData(filebuffer,13);
if (filelength >= 52)
sha.setBindCode(filebuffer,45);
if (sha.isCoprocessor())
{
copr = sha;
System.out.println("Found a coprocessor for service \""+sha.getUserFileName()+"\"");
}
}
II. Once the Coprocessor iButton has been set, any other DS1963S can be set as a User iButton. The following code shows how to create a User iButton that would be compatible with the Coprocessor iButton created in the section above.
//byte[] page0 should be the same as in the Coprocessor initialization section
//owc18 has already been set up to talk to a new DS1963S
owc18.setSpeedCheck(false);
SHAiButton sha = new SHAiButton(owc18);
int auth_page = 13; //put the money page and authentication data on page 13
int tid = 0x1234; //transaction ID, defined by credit/debit authority
int fact = 0x8b48; //ISO4217 monetary unit code and multiplier
int data_type = 0; //certificate type, defined by credit/debit authority
byte[] auth_secret = "this is my authentication secret".getBytes();
if (!owc18.installMasterSecret(auth_page,auth_secret,auth_page&7))
System.out.println("Could not install master authentication secret!");
else
System.out.println("Authentication secret installed.");
//now we need to bind this data to the user iButton
if (!owc18.bindSecretToiButton(auth_page,copr.getBindData(), copr.getBindCode(), auth_page & 7))
{
System.out.println("Failed to bind the secret to the iButton");
}
else
System.out.println("Authentication secret bound to iButton");
//now the authentication secret has been installed,
//we need to put some initial money on the page
byte[] default_page = new byte[32];
default_page[1] = (byte)0x34;
default_page[2] = (byte)0x12;
default_page[3] = (byte)0x48;
default_page[4] = (byte)0x8b;
sha.setUser(auth_page);
//this puts $100.00 on the iButton (10000 pennies)
//copr is defined in part I of this User initialization example
if (copr.signDataFile(sha,10000,-1, default_page))
System.out.println("Successfully set up user iButton");
else
System.out.println("Failed to set up user iButton");
//we've put money on the iButton, now we need a root directory
char[] name = copr.getUserFileName().toCharArray();
int ext = copr.getUserFileExtension();
page0[8] = (byte)name[0];
page0[9] = (byte)name[1];
page0[10] = (byte)name[2];
page0[11] = (byte)name[3];
page0[12] = (byte)ext;
page0[13] = (byte)auth_page;
page0[14] = (byte)1;
//the mask should represent that we are using page 0 and page auth_page
int mask = 0x01 | (0x01 << auth_page);
//now put that int (LSB first) in page0[4..7]
page0[4] = (byte)(mask);
page0[5] = (byte)(mask >> 8);
page0[6] = (byte)(mask >> 16);
page0[7] = (byte)(mask >> 24);
//now redo the CRC and write it
int CRC = ~CRC16.compute(page0,0,page0[0]+1);
page0[page0[0]+1] = (byte)CRC;
page0[page0[0]+2] = (byte)(CRC >> 8);
//now put this new page 0 on the iButton as a root directory
if ((!owc18.eraseScratchPad(0)) || (!owc18.writeDataPage(0,page0)))
{
System.out.println("Failed to write page 0");
return;
}
Performing an Authentication and a Transaction
The code in OneWireContainer18
and this class has been written to
make transactions fast in Java. While the example code for initializing
Coprocessors and Users is not extremely fast, the code in the critical path
of a transaction is fast. The critical path of a transaction can be defined as everything
that happens from the time an iButton is inserted for a transaction until
a new data file has been signed and installed on the User iButton. This means
that code to find a Coprocessor and initialize a SHAiButton
object to
act as a Coprocessor is not in the critical path. The code below uses a
SHAiButton
object copr
. It can be set up in the same
manner as described in section I of "Initializing a User iButton".
OneWireContainer18 owc = new OneWireContainer18();
owc.setSpeedCheck(false);
SHAiButton user = new SHAiButton();
byte[] file = copr.getUserFileName().getBytes();
byte ext = ( byte ) copr.getUserFileExtension();
//adapter is our DSPortAdapter object, it has just found
// a DS1963S to transact with
//CRITICAL PATH BEGINS HERE, let's time it
long t1 = System.currentTimeMillis();
//first let's start talking in overdrive
adapter.reset();
adapter.putByte(0x3c);
adapter.setSpeed(DSPortAdapter.SPEED_OVERDRIVE);
adapter.reset();
adapter.getAddress(ID);
owc.setupContainer(adapter, ID);
user.setiButton(owc);
//now we need to find the file installed!
//filebuffer is a previously defined, large byte array (~400 bytes)
filelength = user.readFile(0, filebuffer);
int filepage = -1;
for (i = 0; i < filelength-5; i++)
{
if (filebuffer [i] == file [0])
if (filebuffer [i + 1] == file [1])
if (filebuffer [i + 2] == file [2])
if (filebuffer [i + 3] == file [3])
if (filebuffer [i + 4] == ext)
{
//we have found the service file on this iButton
filepage = filebuffer [i + 5];
i = filelength;
}
}
if (filepage == -1)
{
System.out.println("No service installed!");
}
else
{
//set up this iButton as a User iButton
user.setUser(filepage);
int wcc = copr.verifyAuthentication(user, pagedata);
if (wcc > 0)
{
//verify that our money is valid
if (copr.verifyUserMoney(pagedata, user,wcc))
{
//this is how the cash is stored in our money page
int cash = (pagedata [5] & 0x0ff) | ((pagedata [6] & 0x0ff) << 8)
| ((pagedata [7] & 0x0ff) << 16);
//amount is the amount to be deducted or added
if (cash + amount >= 0)
{
//put the new amount of money onto the iButton
if (copr.signDataFile(user, cash + amount, wcc, pagedata))
{
//CRITICAL PATH IS OVER, stop timing
long t2 = System.currentTimeMillis();
int newcash = cash + amount;
//now report our transaction
System.out.println("-----------------------");
System.out.println("| Device : "+ Long.toHexString(t));
//note that I am assuming the money is stored as US $0.01
//rather than reading the monetary unit code and multiplier from
//the iButton
System.out.println("| Balance : $ " + (newcash / 100)+ "." + (newcash % 100) + " US");
System.out.println("| Transaction time : " + (t2 - t1) + " ms");
System.out.println("-----------------------\r\n");
}
}
}
}
}
//put the 1-Wire bus back at normal speed
adapter.setSpeed(DSPortAdapter.SPEED_REGULAR);
adapter.reset();
This class makes no calls to the adapter level, i.e. it does no direct talking to
the device. It uses the methods in OneWireContainer18
to implement
transactions.
OneWireContainer18
Field Summary | |
static int |
AUTHENTICATION_FAILED_ERROR
Useful constant for getLastError() . |
static int |
BIND_SECRET_ERROR
Useful constant for getLastError() . |
static int |
CRC_ERROR
Useful constant for getLastError() . |
static int |
ERASE_SCRATCHPAD_ERROR
Useful constant for getLastError() . |
static int |
NO_COPROCESSOR_ERROR
Useful constant for getLastError() . |
static int |
NO_ERROR
Useful constant for getLastError() . |
static int |
NO_USER_ERROR
Useful constant for getLastError() . |
static int |
READ_AUTHENTICATED_ERROR
Useful constant for getLastError() . |
static int |
READ_MEMORY_PAGE_ERROR
Useful constant for getLastError() . |
static int |
READ_SCRATCHPAD_ERROR
Useful constant for getLastError() . |
static int |
SHA_FUNCTION_ERROR
Useful constant for getLastError() . |
static int |
VERIFICATION_FAILED_ERROR
Useful constant for getLastError() . |
static int |
WRITE_MEMORY_PAGE_ERROR
Useful constant for getLastError() . |
static int |
WRITE_SCRATCHPAD_ERROR
Useful constant for getLastError() . |
Constructor Summary | |
SHAiButton()
Creates a new object to handle authentications and transactions with a DS1963S SHA iButton. |
|
SHAiButton(OneWireContainer18 ibc)
Creates a new object to handle authentications and transactions with a DS1963S SHA iButton. |
Method Summary | |
int |
answerChallenge(byte[] challenge,
byte[] mac,
byte[] pagedata)
Answers a challenge from the Coprocessor iButton by signing a data page. |
boolean |
generateChallenge(int page_number,
int offset,
byte[] ch)
Generates a 3 byte random challenge in the iButton, sufficient to be used as a challenge to be answered by a User iButton. |
byte[] |
getBindCode()
Get the 7-byte binding code. |
byte[] |
getBindData()
Gets the 32-byte binding data. |
int |
getLastError()
Returns the last error that occurred. |
int |
getUserFileExtension()
Returns the extension of the Coprocessor Service File. |
String |
getUserFileName()
Returns the name of the Coprocessor Service File. |
boolean |
isCoprocessor()
Determines if this SHAiButton has enough of its parameters
set to act as a Coprocessor iButton. |
int |
readFile(int start_page,
byte[] page)
Reads a TMEX file starting at the specified page. |
void |
setAuthenticationPageNumber(int pg)
Sets the page that the authentication secret is installed on in this Coprocessor iButton. |
void |
setBindCode(byte[] buf,
int offset)
Sets the binding code for this SHA iButton. |
void |
setBindData(byte[] buf,
int offset)
Sets the binding data for this SHA iButton. |
void |
setFilename(byte[] buf,
int start)
Sets the file name and extension for the Coprocessor Service File. |
void |
setiButton(OneWireContainer18 ibc)
Sets the OneWireContainer18 object that this SHAiButton
will use to communicate with a DS1963S. |
void |
setInitialSignature(byte[] sig_ini,
int start)
Sets the optional initial signature for a Coprocessor iButton. |
void |
setSigningChallenge(byte[] ch,
int start)
Sets the optional signing challenge for a Coprocessor iButton. |
void |
setSigningPageNumber(int pg)
Sets the page used to generate signatures on the Coprocessor iButton. |
boolean |
setUser(int file_page_number)
Sets up this SHAiButton as a User iButton. |
void |
setWorkspacePageNumber(int pg)
Sets the page this Coprocessor iButton will use to recreate User iButton specific secrets. |
boolean |
signDataFile(SHAiButton user,
int newbalance,
int write_cycle_counter,
byte[] pagedata)
Makes this Coprocessor iButton produce a signature for a new amount of money for the User iButton, then places the new money file on user . |
String |
toString()
Returns a java.lang.String with the unique
address of the SHA iButton in hex. |
int |
verifyAuthentication(SHAiButton user,
byte[] pagedata)
Determines if the SHAiButton user belongs to the system
defined by this Coprocessor iButton. |
boolean |
verifyUserMoney(byte[] userpage,
SHAiButton user,
int wcc)
Verifies a User iButton's signed data on this Coprocessor iButton. |
Methods inherited from class java.lang.Object |
equals, getClass, hashCode, notify, notifyAll, wait, wait, wait |
Field Detail |
public static final int NO_ERROR
getLastError()
. Means no error occurred.getLastError()
public static final int ERASE_SCRATCHPAD_ERROR
getLastError()
. Means an
error occurred during an Erase Scratch Pad activity with the DS1963S.
Probably due to a communication error, meaning a retry might succeed.getLastError()
public static final int WRITE_SCRATCHPAD_ERROR
getLastError()
. Means an
error occurred during an Erase Scratch Pad activity with the DS1963S.
Probably due to a communication error, meaning a retry might succeed.getLastError()
public static final int READ_SCRATCHPAD_ERROR
getLastError()
. Means an
error occurred during a Read Scratch Pad activity with the DS1963S.
Probably due to a communication error, meaning a retry might succeed.getLastError()
public static final int READ_MEMORY_PAGE_ERROR
getLastError()
. Means an
error occurred during a Read Memory Page activity with the DS1963S.
Probably due to a communication error, meaning a retry might succeed.getLastError()
public static final int READ_AUTHENTICATED_ERROR
getLastError()
. Means an
error occurred during a Read Authenticated Memory Page activity with the DS1963S.
Probably due to a communication error, meaning a retry might succeed.getLastError()
public static final int BIND_SECRET_ERROR
getLastError()
. Means an
error occurred during a Secret Binding activity with the DS1963S.
Probably due to a communication error, meaning a retry might succeed.getLastError()
public static final int WRITE_MEMORY_PAGE_ERROR
getLastError()
. Means an
error occurred during a Write Memory Page activity with the DS1963S.
Probably due to a communication error, meaning a retry might succeed.getLastError()
public static final int SHA_FUNCTION_ERROR
getLastError()
. Means an
error occurred during a cryptographic activity with the DS1963S.
Probably due to a communication error, meaning a retry might succeed.getLastError()
public static final int CRC_ERROR
getLastError()
. Means a
CRC from the DS1963S was invalid. Probably due to a communication
error, meaning a retry might succeed.getLastError()
public static final int NO_COPROCESSOR_ERROR
getLastError()
. Means
that the coprocessor SHAiButton
object has not
been successfully setup.getLastError()
public static final int NO_USER_ERROR
getLastError()
. Means
that the user SHAiButton
object has not been
successfully setup.getLastError()
public static final int AUTHENTICATION_FAILED_ERROR
getLastError()
. It is possible this error
is due to a communication error, and that a retry will be
successful. However, it can also mean that the user SHAiButton
does not belong to the system (could not authenticate).getLastError()
public static final int VERIFICATION_FAILED_ERROR
getLastError()
. It is possible this error
is due to a communication error, and that a retry will be
successful. However, it can also mean that the user SHAiButton
's
money data file is invalid (has been tampered with).getLastError()
Constructor Detail |
public SHAiButton()
Creates a new object to handle authentications and transactions
with a DS1963S SHA iButton. This constructor does not initialize
any parameters, but only creates allocation for several instance
variables. Before doing any processing using this SHAiButton
,
call setiButton(OneWireContainer18)
to initialize this
object. This method is meant to be used outside of the 'critical path'
of a transaction:
This is less expensive than creating a new
//initialize variables to use in the transaction loop here
. . .
SHAiButton user = new SHAiButton();
OneWireContainer18 owc18 = new OneWireContainer18();
. . .
while (allowingTransactions)
{
//here begins the 'critical path' of the transaction
. . .
//find a new DS1963S iButton inserted
// 'ID' is the 8 byte address of the device
// 'adapter' is the DSPortAdapter object to talk to the device
owc18.setupContainer(adapter, ID);
user.setiButton(owc18);
. . .
//now perform transaction
}
SHAiButton
in every instance of the loop.
SHAiButton(OneWireContainer18)
,
setiButton(OneWireContainer18)
public SHAiButton(OneWireContainer18 ibc)
the default constructor
for speed considerations when creating a new SHAiButton
object
for a User iButton.ibc
- the initialized OneWireContainer
object for the DS1963S
that will belong to this SHAiButton
SHAiButton()
Method Detail |
public void setiButton(OneWireContainer18 ibc)
Sets the OneWireContainer18
object that this SHAiButton
will use to communicate with a DS1963S. This method should be used in conjunction
with the constructor SHAiButton()
. Note that the following two code
snippets are functionally equivalent:
is functionally equivalent to
. . .
//owc18 is a OneWireContainer18 already initialized
SHAiButton sha = new SHAiButton(owc18);
. . .
The reasons for using the latter code are discussed in the
. . .
//owc18 is a OneWireContainer18 already initialized
SHAiButton sha = new SHAiButton();
sha.setiButton(owc18);
. . .
SHAiButton()
documentation.
SHAiButton()
,
SHAiButton(OneWireContainer18)
public void setBindData(byte[] buf, int offset)
java.lang.ArrayIndexOutOfBoundsException
.
Data beyond the first 32 bytes will be ignored. This data is used to bind secrets
to User iButtons and also to re-create user signatures in
Coprocessor iButtons.buf
- buffer with the binding dataoffset
- offset to start reading from the buffer (32 bytes
will be read from offset
)getBindData()
,
setBindCode(byte[],int)
public void setBindCode(byte[] buf, int offset)
java.lang.ArrayIndexOutOfBoundsException
.
Data beyond the first 7 bytes will be ignored. This data is written to
the scratchpad for binding secrets to User iButtons and also to recreate
User iButton signatures on Coprocessor iButtons.buf
- buffer with the binding dataoffset
- offset to start reading from the buffer (7 bytes
will be read from offset
)getBindCode()
,
setBindData(byte[],int)
public byte[] getBindData()
getBindCode()
,
setBindData(byte[],int)
public byte[] getBindCode()
getBindData()
,
setBindCode(byte[],int)
public int answerChallenge(byte[] challenge, byte[] mac, byte[] pagedata) throws OneWireIOException, OneWireException
Answers a challenge from the Coprocessor iButton by signing a data page. This method is used by the User iButton.
To authenticate a User iButton to a system, the Coprocessor iButton generates a random challenge. This way, an attacker cannot simply memorize one successful response and fake its way into the system. The User iButton signs a data page with its system authentication secret. The random number generated by the Coprocessor and the write cycle counter of the user's data page are also part of the signature. If the Coprocessor can verify this signature, then the User iButton belongs to the system.
Note that authentication does not guarantee the validity of the data
in the page. It must be verified using verifyUserMoney()
.
The only true input to this method is the random byte array
challenge
. The other byte arrays are used to return
information that the Coprocessor iButton needs to verify the signature.
challenge
- a 3 byte random challenge (generated by the Coprocessor DS1963S)mac
- buffer for the returned signature generated by the
User DS1963S (must be at least 20 bytes long)pagedata
- buffer for the page data the User DS1963S signed
(must be at least 32 bytes long)pagedata
,
of -1 if an error occurred (use getLastError()
for more
information on the type of error)OneWireIOException
- on a 1-Wire communication error such as
reading an incorrect CRC from a 1-Wire device. This could be
caused by a physical interruption in the 1-Wire Network due to
shorts or a newly arriving 1-Wire device issuing a 'presence pulse'.OneWireException
- on a communication or setup error with the 1-Wire
adapterverifyUserMoney(byte[],SHAiButton,int)
,
generateChallenge(int,int,byte[])
,
getLastError()
public boolean generateChallenge(int page_number, int offset, byte[] ch) throws OneWireIOException, OneWireException
Generates a 3 byte random challenge in the iButton, sufficient to be used as a challenge to be answered by a User iButton. This method will normally be called by a Coprocessor iButton.
The DS1963S will generate 20 bytes of pseudo random data, though only
3 bytes are needed for the challenge. Programs can add more 'randomness'
by selecting different bytes from the 20 bytes of random data using the
offset
parameter.
The random number generator is actually the DS1963S's SHA engine, which requires
page data to compute a hash. Select a page number with the page_number
parameter.
page_number
- page number that the random number generation will be based on
(cannot be 0 or 8)offset
- offset into the 20 random bytes to draw random data from
(must be in range 0-16)ch
- buffer for the challenge to be returned (must be of length 3 or more)true
if successful, false
if an error
occurred (use getLastError()
for more
information on the type of error)OneWireIOException
- on a 1-Wire communication error such as
reading an incorrect CRC from a 1-Wire device. This could be
caused by a physical interruption in the 1-Wire Network due to
shorts or a newly arriving 1-Wire device issuing a 'presence pulse'.OneWireException
- on a communication or setup error with the 1-Wire
adapteranswerChallenge(byte[],byte[],byte[])
,
getLastError()
public int verifyAuthentication(SHAiButton user, byte[] pagedata) throws OneWireException, OneWireIOException
Determines if the SHAiButton
user
belongs to the system
defined by this Coprocessor iButton. This method can only be called by a
Coprocessor iButton. See the usage example in this class for initializing up
a Coprocessor iButton.
The SHAiButton
user
must have previously been
initialized with the setUser()
method.
The TMEX formatted page with the money signature is returned in
the parameter pagedata
. pagedata
must be
at least 32 bytes long to hold this data. If the verification
is successful, verify that the data in the returned page is valid
with the verifyUserMoney()
method.
Failure of this method does not necessarily mean that the User iButton does not belong to the system. It is possible that a communication disruption here could cause a CRC error that would be indistinguishable from a failed authentication. However, repeated attempts should reveal whether it was truly a communication problem or a User iButton that does not belong to the system.
This method starts by generating a random challenge on the Coprocessor iButton. The User iButton then answers that challenge by signing a specified data page. The Coprocessor then recreates the User iButton's secret, and signs the same data that the User signed. If the signatures match, the authentication succeeded.
user
- the SHAiButton
that will answer the
challenge and be authenticated, previously setup with setUser()
pagedata
- buffer for the data page that will be used by user
to generate the authentication signaturegetLastError()
for more
information on the type of error)OneWireIOException
- on a 1-Wire communication error such as
reading an incorrect CRC from a 1-Wire device. This could be
caused by a physical interruption in the 1-Wire Network due to
shorts or a newly arriving 1-Wire device issuing a 'presence pulse'.OneWireException
- on a communication or setup error with the 1-Wire
adaptergenerateChallenge(int,int,byte[])
,
answerChallenge(byte[],byte[],byte[])
,
OneWireContainer18.bindSecretToiButton(int,byte[],byte[],int)
,
OneWireContainer18.SHAFunction(byte,int)
,
OneWireContainer18.matchScratchPad(byte[])
,
verifyUserMoney(byte[],SHAiButton,int)
,
getLastError()
,
setUser(int)
public boolean isCoprocessor()
Determines if this SHAiButton
has enough of its parameters
set to act as a Coprocessor iButton. To be a Coprocessor, the
following must be set:
The Coprocessor uses other parameters, but these have default and do not need to be set unless required by the system. These parameters are:
byte
sbyte
strue
if this iButton can act as a CoprocessorsetFilename(byte[],int)
,
setSigningPageNumber(int)
,
setAuthenticationPageNumber(int)
,
setWorkspacePageNumber(int)
,
setBindCode(byte[],int)
,
setBindData(byte[],int)
,
setSigningChallenge(byte[],int)
,
setInitialSignature(byte[],int)
public String toString()
java.lang.String
with the unique
address of the SHA iButton in hex. This is only a convenience
method that calls OneWireContainer.getAddressAsString()
on the OneWireContainer18
object this SHAiButton
uses.toString
in class Object
OneWireContainer.getAddressAsString()
public boolean setUser(int file_page_number)
Sets up this SHAiButton
as a User iButton.
To act as a User iButton, this object only needs to
know what page number its service file is located in.
This is the page that contains signed data and/or
is used for authentication. Methods that take a User
SHAiButton
as a parameter check to make sure
that the User has been set up using this method.
See the usage section for an example on how to discover the page number where the service file is located on a User iButton.
file_page_number
- page number that contains signed datatrue
if successfulpublic void setInitialSignature(byte[] sig_ini, int start)
Sets the optional initial signature for a Coprocessor iButton. When a data page is signed, the place in the page where the signature will be stored is initialized to this value.
Up to 20 bytes will be copied from sig_ini
if
its length permits. The initial signature defaults to
all 0's. If sig_ini
is not long enough
to copy 20 bytes, the excess in the initial signature will
remain at all 0's.
sig_ini
- new initial signaturestart
- offset to start reading the new initial signature from sig_ini
public void setSigningChallenge(byte[] ch, int start)
Sets the optional signing challenge for a Coprocessor iButton. All signatures on the Coprocessor have a location for challenges. This may optionally be set. Note that this is not the same as the challenge in the authentication sequence. This is data that will be included with the Coprocessor's signature of a data (money) file.
Up to 3 bytes will be copied from ch
if
its length permits. The signing challenge defaults to
all 0's. If ch
is not long enough
to copy 3 bytes, the excess in the signing challenge will
remain at all 0's.
ch
- Byte new random challengestart
- offset to start reading the new signing challenge from ch
public void setFilename(byte[] buf, int start)
Sets the file name and extension for the Coprocessor Service File. This file will appear on User iButtons and will contain data signed by the Coprocessor.
The parameter buf
should have 5 bytes
to represent the Coprocessor Service File name and
extension. For example, if the service file is named
"DLSM.102" (extension = 102), buf
should look
like:
buf[start + 0] = (byte)'D';
buf[start + 1] = (byte)'L';
buf[start + 2] = (byte)'S';
buf[start + 3] = (byte)'M';
buf[start + 4] = (byte)102;
This function must be called to initialize a Coprocessor iButton.
buf
- the file name and extensionstart
- index to start copying from buf
isCoprocessor()
,
getUserFileName()
,
getUserFileExtension()
public void setSigningPageNumber(int pg)
Sets the page used to generate signatures on the Coprocessor iButton. The hardware of the DS1963S allows only page 0 or page 8 to be used for this function. Since this class assumes the TMEX file structure (requiring page 0 to be a directory page), this method should be called setting the signing page to page 8.
This function must be called to initialize a Coprocessor iButton.
pg
- page number for generating signaturesisCoprocessor()
public void setAuthenticationPageNumber(int pg)
Sets the page that the authentication secret is installed on in this Coprocessor iButton. This secret will be used to recreate User iButton specific authentication secrets during the authentication process.
This function must be called to initialize a Coprocessor iButton.
pg
- page the installation secret is installed onisCoprocessor()
public void setWorkspacePageNumber(int pg)
Sets the page this Coprocessor iButton will use to recreate User iButton specific secrets. No data should be stored here, as it will be overridden when the system tries to perform an authentication.
This function must be called to initialize a Coprocessor iButton.
pg
- free page that can be used as workspaceisCoprocessor()
public String getUserFileName()
java.lang.NullPointerException
if the file name has not been set. If the file name
is 'DLSM.102', this returns the java.lang.String
"DLSM".setFilename(byte[],int)
public int getUserFileExtension()
java.lang.NullPointerException
if the file name has not been set. If the file name
is 'DLSM.102', this returns the int
102.setFilename(byte[],int)
public boolean signDataFile(SHAiButton user, int newbalance, int write_cycle_counter, byte[] pagedata) throws OneWireIOException, OneWireException
Makes this Coprocessor iButton produce a signature
for a new amount of money for the User iButton, then places
the new money file on user
.
The write cycle counter is part of a valid signature.
The Coprocessor iButton uses it to verify a signature
of a signed data file. It should be returned in a normal
transaction from the method verifyAuthentication()
.
However, if this method fails or if this is the
initialization of a User iButton, use -1 for the write cycle counter.
Then, the code will determine the correct write cycle counter
value directly from the User iButton. However, do not do this
in a normal transaction sequence as it takes longer.
Note that this method specifically handles TMEX file formats.
user
- SHAiButton
object that has been initialized as a user
with setUser(int)
newbalance
- new balance to be stored on the User iButtonwrite_cycle_counter
- the current write cycle counter of the User iButton's
money pagepagedata
- the money data page (from verifyAuthentication()
)true
if successful, false
if an error occurred (use getLastError()
for more
information on the type of error)OneWireIOException
- on a 1-Wire communication error such as
reading an incorrect CRC from a 1-Wire device. This could be
caused by a physical interruption in the 1-Wire Network due to
shorts or a newly arriving 1-Wire device issuing a 'presence pulse'.OneWireException
- on a communication or setup error with the 1-Wire
adapterverifyUserMoney(byte[],SHAiButton,int)
,
getLastError()
,
verifyAuthentication(SHAiButton,byte[])
public boolean verifyUserMoney(byte[] userpage, SHAiButton user, int wcc) throws OneWireIOException, OneWireException
userpage
- the full 32 byte TMEX file from the User iButton
(from verifyAuthentication()
)user
- SHAiButton
object that has been initialized as a user
with setUser(int)
wcc
- write cycle counter of the user's money page
(from verifyAuthentication()
)true if the data file is valid, false
if an error occurred (use getLastError()
for more
information on the type of error)- Throws:
OneWireIOException
- on a 1-Wire communication error such as
reading an incorrect CRC from a 1-Wire device. This could be
caused by a physical interruption in the 1-Wire Network due to
shorts or a newly arriving 1-Wire device issuing a 'presence pulse'.OneWireException
- on a communication or setup error with the 1-Wire
adapter- See Also:
verifyAuthentication(SHAiButton,byte[])
,
getLastError()
public int readFile(int start_page, byte[] page) throws OneWireIOException, OneWireException
Reads a TMEX file starting at the specified page. The parameter
page
will store the file, or up to page.length
bytes of the file. This method performs CRC checks to ensure
the validity of the file.
Call readFile(0)
to read the root directory.
start_page
- page of the DS1963S to start reading frompage
- buffer for the file dataOneWireIOException
- on a 1-Wire communication error such as
reading an incorrect CRC from a 1-Wire device. This could be
caused by a physical interruption in the 1-Wire Network due to
shorts or a newly arriving 1-Wire device issuing a 'presence pulse'.OneWireException
- on a communication or setup error with the 1-Wire
adapterpublic int getLastError()
NO_ERROR
,
ERASE_SCRATCHPAD_ERROR
,
WRITE_SCRATCHPAD_ERROR
,
READ_SCRATCHPAD_ERROR
,
READ_MEMORY_PAGE_ERROR
,
READ_AUTHENTICATED_ERROR
,
BIND_SECRET_ERROR
,
WRITE_MEMORY_PAGE_ERROR
,
SHA_FUNCTION_ERROR
,
CRC_ERROR
,
NO_COPROCESSOR_ERROR
,
NO_USER_ERROR
,
AUTHENTICATION_FAILED_ERROR
,
VERIFICATION_FAILED_ERROR
|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: INNER | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |