以下の3つのファイルがホスト側で実行されるサーバープログラムです。実行ファイル名はrunHost.tiniになります。

runHost



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



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


interface AuthenticationConstants



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();
}