| runHost.java |
|---|
import java.io.*;
import java.net.*;
import java.util.*;
import com.dalsemi.onewire.adapter.*;
import com.dalsemi.onewire.container.*;
import com.dalsemi.onewire.OneWireAccessProvider;
import com.dalsemi.onewire.application.sha.*;
import com.dalsemi.onewire.*;
import com.dalsemi.onewire.utils.*;
/**
* Starts the host component for NetAdapter clients on the local machine.
* If no options are specified, the default adapter for this machine is used
* and the host is launched as a multi-threaded server using the defaults.
*
*/
public class runHost
{
static final String strUsage =
"Starts the host component for NetAdapter clients on the local machine.\n" +
"If no options are specified, the default adapter for this machine is used\n" +
"and the host is launched as a multi-threaded server using the defaults:\n" +
"\n" +
" Host Listen Port: " + AuthenticationConstants.DEFAULT_PORT + "\n" +
"\n" +
"syntax: java AuthHost <options>\n" +
"\n" +
"Options:\n" +
" -props Pulls all defaults from the onewire.properties\n" +
" file rather than using the defaults set in\n" +
" com.dalsemi.onewire.adapter.NetAdapterConstants.\n" +
" -p PATH This is the path to the SHA properties file.\n" +
" -listenPort NUM Sets the host's listening port for incoming\n" +
" socket connections.\n" +
" -secret STRING Sets the shared secret for authenticating incoming\n" +
" client connections.\n";
public static void usage()
{
System.out.println();
System.out.println(strUsage);
System.exit(1);
}
public static void main(String[] args)
throws Exception
{
String adapterName = null, adapterPort = null;
int listenPort = AuthenticationConstants.DEFAULT_PORT;
boolean multithread = true;
String secret = AuthenticationConstants.DEFAULT_SECRET;
byte[] SNum = new byte[8];
byte[] data = new byte[7];
// コプロセッサ
long coprID = 0;
SHAiButtonCopr copr = null;
boolean useProperties = false;
// ------------------------------------------------------------
// コマンドラインでsha.propertiesファイルのパスをチェックする
// ------------------------------------------------------------
for(int i=0; i<args.length; i++)
{
char c = args[0].charAt(1);
String arg = args[i].toUpperCase();
if(arg.indexOf("-P")==0)
{
String sha_props_path;
if(arg.length()==2)
sha_props_path = args[++i];
else
sha_props_path = arg.substring(2);
// sha.propertiesファイルを開く
try
{
FileInputStream prop_file
= new FileInputStream(sha_props_path
+ "sha.properties");
sha_properties = new Properties();
sha_properties.load(prop_file);
}
catch(Exception e)
{
sha_properties = null;
}
}
else if(arg.equalsIgnoreCase("-listenPort"))
{
listenPort = Integer.parseInt(args[++i]);
}
else if(arg.equalsIgnoreCase("-secret"))
{
secret = args[++i];
}
else if(args[0].charAt(0)!='-' || c=='h' || c=='H' || c=='?')
{
System.out.println("Invalid option: " + arg);
usage();
}
}
// ------------------------------------------------------------
// コプロセッサを見つける
// ------------------------------------------------------------
if(getPropertyBoolean("copr.simulated.isSimulated", false))
{
String coprVMfilename = getProperty("copr.simulated.filename");
// ---------------------------------------------------------
// Load emulated coprocessor
// ---------------------------------------------------------
try
{
copr = new SHAiButtonCoprVM(coprVMfilename);
}
catch(Exception e)
{
IOHelper.writeLine("Invalid Coprocessor Data File");
e.printStackTrace();
System.exit(1);
}
}
if(copr==null)
{
IOHelper.writeLine("No Coprocessor found!");
System.exit(1);
}
IOHelper.writeLine(copr);
IOHelper.writeLine();
AuthenticationHost sh = new AuthenticationHost(copr,listenPort,
secret);
sh.run();
}
static Properties sha_properties = null;
/**
* 指定されたプロパティを得る。
* 以下の場所からプロパティを探す。
* 1. System.propertiesの中
* 2. カレントディレクトリにあるonewire.propertiesファイルの中あるいは
* TINIの /etc/ の中
*
* 引数: propName : 読まれるプロパティの文字列名
*
* 戻り値: String : プロパティの値、見つからなかった場合はnull
*/
public static String getProperty (String propName)
{
// 始めにシステムプロパティを試みる
try
{
String ret_str = System.getProperty(propName, null);
if(ret_str!=null)
return ret_str;
}
catch (Exception e)
{ ; }
// 見つからなかった場合はsha.propertiesファイルを試みる
if(sha_properties==null)
{
//try to load sha_propreties file
FileInputStream prop_file = null;
// ある可能性のある二つの場所で探す
// (1).\sha.properties (2)<java.home>\lib\sha.properties
String path = "";
for (int i = 0; i <= 1; i++)
{
// sha.propertiesファイルを開く
try
{
prop_file = new FileInputStream(path + "sha.properties");
// onewire.propertiesを読む
try
{
sha_properties = new Properties();
sha_properties.load(prop_file);
}
catch (Exception e)
{
// 失敗
sha_properties = null;
}
}
catch (IOException e)
{
prop_file = null;
}
// プロパティが読み込まれたかどうかをチェックする
if (sha_properties != null)
break;
// 二番目のパスを試みる
path = System.getProperty("java.home") + File.separator + "lib"
+ File.separator;
}
}
if(sha_properties==null)
{
IOHelper.writeLine("Can't find sha.properties file");
return null;
}
else
{
Object ret = sha_properties.get(propName);
if(ret==null)
return null;
else
return ret.toString();
}
}
public static String getProperty (String propName, String defValue)
{
String ret = getProperty(propName);
return (ret==null) ? defValue : ret;
}
public static boolean getPropertyBoolean(String propName, boolean defValue)
{
String strValue = getProperty(propName);
if(strValue!=null)
defValue = Boolean.valueOf(strValue).booleanValue();
return defValue;
}
public static byte[] getPropertyBytes(String propName, byte[] defValue)
{
String strValue = getProperty(propName);
if(strValue!=null)
{
//only supports up to 128 bytes of data
byte[] tmp = new byte[128];
//split the string on commas and spaces
StringTokenizer strtok = new StringTokenizer(strValue,", ");
//how many bytes we got
int i = 0;
while(strtok.hasMoreElements())
{
//this string could have more than one byte in it
String multiByteStr = strtok.nextToken();
int strLen = multiByteStr.length();
for(int j=0; j<strLen; j+=2)
{
//get just two nibbles at a time
String byteStr
= multiByteStr.substring(j, Math.min(j+2, strLen));
long lng = 0;
try
{
//parse the two nibbles into a byte
lng = Long.parseLong(byteStr, 16);
}
catch(NumberFormatException nfe)
{
nfe.printStackTrace();
//no mercy!
return defValue;
}
//store the byte and increment the counter
if(i<tmp.length)
tmp[i++] = (byte)(lng&0x0FF);
}
}
if(i>0)
{
byte[] retVal = new byte[i];
System.arraycopy(tmp, 0, retVal, 0, i);
return retVal;
}
}
return defValue;
}
}
|
| AuthenticationHost.java |
|---|
import java.io.*;
import java.net.*;
import java.util.*;
import com.dalsemi.onewire.*;
import com.dalsemi.onewire.adapter.*;
import com.dalsemi.onewire.container.*;
import com.dalsemi.onewire.utils.*;
import com.dalsemi.onewire.application.sha.*;
/**
* 新しい接続サービスを行うクラス
* 同一スレッド上で動作する
*/
public class AuthenticationHost implements Runnable
{
/**
* バイト配列に0xFFを入れる
*/
private static final byte[] ffBlock
= new byte[] {
(byte)0x0FF,(byte)0x0FF,(byte)0x0FF,(byte)0x0FF,
(byte)0x0FF,(byte)0x0FF,(byte)0x0FF,(byte)0x0FF,
(byte)0x0FF,(byte)0x0FF,(byte)0x0FF,(byte)0x0FF,
(byte)0x0FF,(byte)0x0FF,(byte)0x0FF,(byte)0x0FF,
(byte)0x0FF,(byte)0x0FF,(byte)0x0FF,(byte)0x0FF,
(byte)0x0FF,(byte)0x0FF,(byte)0x0FF,(byte)0x0FF,
(byte)0x0FF,(byte)0x0FF,(byte)0x0FF,(byte)0x0FF,
(byte)0x0FF,(byte)0x0FF,(byte)0x0FF,(byte)0x0FF
};
/**
* サービスをしている接続
*/
private AuthenticationConstants.Connection conn;
/**
* 接続確認のための乱数
*/
Random rand;
/**
* 接続に対する暗号
*/
String secret;
/**
* リモート認証のためのコプロセッサ情報
*/
SHAiButtonCopr copr;
/**
* 接続のためのサーバーソケット
*/
ServerSocket serverSock;
/**
* ソケットサービスに対するコンストラクタ
* 入出力ストリームを作り、クライアントにこのホストの
* バージョンを送る
*/
public AuthenticationHost(SHAiButtonCopr copr, int listenPort, String secret)
throws IOException
{
// チャレンジに対する乱数オブジェクト
rand = new Random();
// 接続に対して暗号を設定する
this.secret = secret;
// 認証に対するコプロセッサのデータ
this.copr = copr;
// 接続のためのソケット
serverSock = new ServerSocket(listenPort);
}
public void run()
{
byte[] SNum = new byte[8];
byte[] data = new byte[7];
try
{
for(;;)
{
Socket sock = null;
sock = serverSock.accept();
// ソケットのtimeoutを10秒に設定する
sock.setSoTimeout(10000);
// 接続オブジェクトを作る
conn = new AuthenticationConstants.Connection();
conn.sock = sock;
conn.input = new DataInputStream(conn.sock.getInputStream());
conn.output = new DataOutputStream(new BufferedOutputStream(
conn.sock.getOutputStream()));
// クライアントを認証する
byte[] chlg = new byte[8];
rand.nextBytes(chlg);
conn.output.write(chlg);
conn.output.flush();
// 暗号とチャレンジのcrcを計算する
int crc = CRC16.compute(secret.getBytes(), 0);
crc = CRC16.compute(chlg, crc);
int answer = conn.input.readInt();
if(answer!=crc)
{
conn.output.writeByte(AuthenticationConstants.RET_FAILURE);
conn.output.writeUTF("Client Authentication Failed");
conn.output.flush();
throw new IOException("authentication failed");
}
else
{
conn.output.writeByte(AuthenticationConstants.RET_SUCCESS);
conn.output.flush();
}
if(authenticate(SNum,data))
{
System.out.println();
System.out.println("Remote Authentication Successful for part: ");
IOHelper.writeBytesHex(SNum,0,8);
System.out.println("With the following verification data:");
IOHelper.writeBytes(data);
System.out.println();
}
else
{
System.out.println("Remote Authentication was " +
"unseccessful for part: ");
IOHelper.writeBytesHex(SNum,0,8);
}
}
}
catch(Exception ioe)
{
if(AuthenticationConstants.DEBUG)
ioe.printStackTrace();
}
}
/**
* Run method for socket Servicer.
*/
public boolean authenticate(byte[] SNum, byte[] data)
throws OneWireException, OneWireIOException, IOException
{
byte[] accountData = new byte[32];
byte[] fullBindCode = new byte[15];
byte[] ver_data = new byte[7];
byte[] mac = new byte[20];
byte[] coprBindCode = new byte[7];
byte[] coprBindData = new byte[32];
byte lastError = 0x00;
byte authCmd = 0x00;
boolean authenticated = false;
try
{
while(conn.sock!=null)
{
byte cmd = 0x00;
cmd = conn.input.readByte();
if(cmd == AuthenticationConstants.START_OF_AUTH)
{
// get the bytes to block
conn.input.read(SNum, 0, 8);
// send the bind code
coprBindCode = copr.getBindCode();
conn.output.write(coprBindCode);
conn.output.flush();
coprBindData = copr.getBindData();
conn.output.write(coprBindData);
conn.output.flush();
// Send the file name and file name extension of the file
byte[] fileName = new byte[4];
byte fileNameExt;
copr.getFilename(fileName,0);
fileNameExt = copr.getFilenameExt();
conn.output.write(fileName);
conn.output.flush();
conn.output.write(fileNameExt);
conn.output.flush();
if(SNum[0] == 0x18)
{
authCmd = OneWireContainer18.VALIDATE_DATA_PAGE;
}
else if((SNum[0] == 0x33) || (SNum[0] == 0xB3))
{
authCmd = OneWireContainer18.AUTH_HOST;
}
// Verifing the User
lastError = verifyUserNet(copr, authCmd);
// verify Transaction Data
if((verifyTransactionDataNet(copr, data, SNum)
== 0x00) && (lastError == 0x00))
{
authenticated = true;
}
conn.output.writeByte(AuthenticationConstants.END_OF_AUTH);
conn.output.flush();
conn.sock.close();
}
}
}
catch(IOException ioe)
{
if(AuthenticationConstants.DEBUG)
ioe.printStackTrace();
conn.sock.close();
}
return authenticated;
}
private byte verifyUserNet(SHAiButtonCopr copr, byte authCmd)
throws OneWireException, OneWireIOException, IOException
{
byte lastError = 0x00;
int wcc = 0;
byte[] chlg = new byte[3];
byte[] accountData = new byte[32];
byte[] mac = new byte[20];
byte[] fullBindCode = new byte[15];
byte[] coprBindCode = new byte[7];
byte[] coprBindData = new byte[32];
byte[] scratchpad = new byte[32];
if(!copr.generateChallenge(0, chlg, 0))
{
lastError = AuthenticationConstants.COPR_COMPUTE_CHALLENGE_FAILED;
}
conn.output.writeByte(AuthenticationConstants.CHALLENGE_FOR_VERIFICATION);
conn.output.flush();
conn.output.write(chlg,0,chlg.length);
conn.output.flush();
conn.output.writeByte(AuthenticationConstants.VERIFY_USER_DATA);
conn.output.flush();
wcc = conn.input.readInt();
conn.input.read(accountData,0,accountData.length);
conn.input.read(mac,0,mac.length);
conn.input.read(fullBindCode,0,fullBindCode.length);
if(wcc<0)
{
System.arraycopy(ffBlock, 0, scratchpad, 8, 4);
}
else
{
//スクラッチパッドにwrite cycleカウンターをコピーする
Convert.toByteArray(wcc, scratchpad, 8, 4);
}
//fullBindCodeからユーザアドレスとpage numを得る
System.arraycopy(fullBindCode, 4, scratchpad, 12, 8);
// 同じチャレンジバイトをセットする
System.arraycopy(chlg, 0, scratchpad, 20, 3);
if(!copr.verifyAuthentication(fullBindCode,
accountData,
scratchpad, mac,
authCmd))
{
lastError = AuthenticationConstants.COPROCESSOR_FAILURE;
}
return lastError;
}
private byte verifyTransactionDataNet(SHAiButtonCopr copr, byte[] ver_data,
byte[] SNum)
throws OneWireException, OneWireIOException, IOException
{
byte lastError = 0x00;
int wcc = 0;
byte[] accountData = new byte[32];
byte[] ver_mac = new byte[20];
byte[] scratchpad = new byte[32];
conn.output.writeByte(AuthenticationConstants.VERIFY_TRANSACTION_DATA);
conn.output.flush();
conn.input.read(accountData,0,accountData.length);
wcc = conn.input.readInt();
// ユーザの検証データを得る
System.arraycopy(accountData,22,ver_data,0,7);
// account data pageからmacを得る
System.arraycopy(accountData, 2,
ver_mac, 0, 20);
// macをリセットする
copr.getInitialSignature(accountData, 2);
// CRCをリセットする
accountData[30] = (byte)0;
accountData[31] = (byte)0;
// now we also need to get things like wcc,
//user_page_number, user ID
if(wcc<0)
{
// write cycleカウンターを持っていない
System.arraycopy(ffBlock, 0, scratchpad, 8, 4);
}
else
{
// write cycleカウンターをスクラッチパッドにコピーする
Convert.toByteArray(wcc, scratchpad, 8, 4);
}
scratchpad[12] = (byte)conn.input.readInt();
System.arraycopy(SNum,0,scratchpad,13,7);
copr.getSigningChallenge(scratchpad, 20);
if(!copr.verifySignature(accountData, scratchpad,
ver_mac))
{
lastError = AuthenticationConstants.COPROCESSOR_FAILURE;
}
return lastError;
}
}
|
| AuthenticationConstants.java |
|---|
public interface AuthenticationConstants
{
/** Debug メッセージ・フラグ */
static final boolean DEBUG = false;
/** TCP/IP接続のデフォールトのポート */
static final int DEFAULT_PORT = 6161;
/** サーバーでの認証に対するデフォールトの暗証 */
static final String DEFAULT_SECRET = "Adapter Secret Default";
/*--------------------------------*/
/*----- メソッドが返すコード -----*/
/*--------------------------------*/
static final byte RET_SUCCESS = (byte)0xFF;
static final byte RET_FAILURE = (byte)0xF0;
/** ネットワークを通って送られるコマンド */
static final byte NO_ACTION = 0x00;
static final byte START_OF_AUTH = (byte) 0xAA;
static final byte END_OF_AUTH = (byte) 0xA0;
static final byte CHALLENGE_FOR_VERIFICATION = (byte) 0xA1;
static final byte VERIFY_USER_DATA = (byte) 0xA2;
static final byte VERIFY_TRANSACTION_DATA = (byte) 0xA3;
/** 失敗 */
static final byte COPROCESSOR_FAILURE = (byte) 0xC0;
static final byte COPR_COMPUTE_CHALLENGE_FAILED = (byte) 0xC1;
/** I/O streamでソケット接続する場合の内部ユーティリティ */
public static final class Connection
{
/** socket to host */
public java.net.Socket sock = null;
/** input stream from socket */
public java.io.DataInputStream input = null;
/** output stream from socket */
public java.io.DataOutputStream output = null;
}
/** 基本的にNULLオブジェクトである空の接続のインスタンス */
public static final Connection EMPTY_CONNECTION = new Connection();
}
|