認証,アクセス制御

ここでは,Java APIで標準技術を使ったセキュリティについて 述べます.1つは,署名を用いた認証技術, もう1つは,ポリシーファイルとPermissionを用いたアクセス制御です. また,これらに必要なツール,keytool,jarsigner,policytoolの 3つを紹介します.
暗号・復号,認証
他人には知られたくないデータをやりとりする場合があります. これらをネットワーク上でデータのやりとりを実施するとき, そのデータは,ネットワーク上で意味がないデータにする必要があります. それが暗号・復号技術です. また,他人から送られてきたデータが誰から送られてきたものかを 知るための技術が認証です. この認証技術は暗号,復号技術を応用して行われます.

暗号・復号の種類として,3種類あります.
  • 共通鍵暗号方式
  • 暗号化する鍵と復号化する鍵が同じであるという特徴を持ちます. ただし,鍵をあらかじめ配布しておかなくてはいけないことや 鍵の管理が煩雑になるといった問題点もあります.

  • 公開鍵暗号方式
  • 暗号化する鍵と復号化する鍵が異なります. 2つの鍵のうち,片方を公開(公開鍵)し, もう片方を秘密(秘密鍵)にします. 片方の鍵で暗号化すると, そのデータはもう片方の鍵でしか復号できません. しかし,実行速度が遅いと行った問題点があります.

  • ハイブリット方式
  • 上記の2つの特徴を生かした方式です. まず,共通鍵を公開鍵暗号方式で交換し, その後のデータのやりとりを共通鍵暗号方式で 行います.

認証方式は,公開鍵暗号方式の逆を取った方式になっています.
  • 公開鍵暗号方式
  • Bの公開鍵で暗号化する. つまり,そのデータはBの秘密鍵しか復号化できない. したがって,Bしか閲覧できない.

  • 認証技術
  • Aの秘密鍵で暗号化する. Aの公開鍵で復号化できるものは,Aしかつくれない. つまり,Aがこのデータを送ってきたことになる.

公開鍵による署名の生成,検証
まずは,公開鍵,秘密鍵のペアを作成する方法です. 今回は,DSA暗号,SHA1PRNG乱数を用います.
import java.security.*;

public class SigTest{
 public static void main(String[] args){
  //データの設定
  byte[] data = "Hello".getBytes();
  if(args.length > 0){
   data = args[0].getBytes();
  }

  //DHAという公開鍵暗号方式を生成するKeyPairGeneratorを作成
  KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
  //SHA1PRNGという乱数を生成するSecureRandomを作成
  SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
  //現在時刻で乱数を初期化
  random.setSeed(System.currentTimeMillis());
  //Generatorを乱数で初期化し,1024bitの鍵生成に設定
  keyGen.initialize(1024, random);
  //KeyPairGeneratorからKeyPairを作成
  KeyPair pair = keyGen.generateKeyPair();
  //SHA1withDSAという署名方式を利用
  Signature dsa = Signature.getInstance("SHA1withDSA");
  //KeyPairから秘密鍵(PrivateKey)を獲得
  PrivateKey priv = pair.getPrivate();
  //Signatureを獲得した秘密鍵で初期化
  dsa.initSign(priv);
  //Signatureに署名したいデータを入力
  dsa.update(data);
  //署名を獲得
  byte[] sig = dsa.sign();

  //KeyPairから公開鍵(PubicKey)を獲得
  PublicKey pub = pair.getPublic();
  //公開鍵でSignatureを初期化
  dsa.initVerify(pub);
  //Signatureに検証したいデータを入力
  dsa.update(data);
  //Signatureに対して,署名を入力し検証
  boolean verifies = dsa.verify(sig);
  //成功するとtrue,失敗するとfalse
  System.out.println("signature verifies: " + verifies);
 }
}
    
本来であれば,同じところで署名作成&検証を行うことは おかしなことです.ここでは,署名の作成法と署名の検証法を 覚えてもらえばよいです. 本来の姿である署名作成と署名検証の分離には, 以下で述べるkeytoolを用いる必要があります.
メッセージダイジェスト
先ほどは,データ全体に対して署名を施しました. しかし,データが大きくなってしまうと, それだけ処理時間がかかってしまいます. そこで,データの要約を生成するメッセージダイジェストを 用いる方法があります. メッセージダイジェストとは,一方向関数なので, メッセージダイジェストからもともとのデータはわかりません. また,異なるデータから作成されるメッセージダイジェストは 必ず違うという特徴があります.

それでは,メッセージダイジェストを作成する例をだします. 今回は,SHAをメッセージダイジェストのアルゴリズムとして用います.
public class MDTest{
 public static void main(String[] args){
  byte[] data = "Hello".getByte();
  if(args.length > 0){
   data = args[0].getByte();
  }
  //SHAのMessageDigestを作成
  MessageDigest md = MessageDigest.getInstance("SHA");
  //与えられたデータでMessageDigestを更新
  md.update(data);
  //MessageDigestからダイジェスト値を獲得
  byte[] digest = md.digest();
  //ダイジェスト値の出力
  for(int i = 0; i < digest.length; i++){
   System.out.print(digest[i]);
  }
  System.out.println("");
}
    
実際の流れとしては,以下のようになります.
  1. 送るデータからダイジェスト値を作成
  2. ダイジェスト値から署名を作成
  3. データ+ダイジェスト値の署名を送る
  4. 受けとったデータからダイジェスト値を作成
  5. ダイジェスト値から署名を検証
ツールの紹介(keytool, jarsigner, policytool)
Javaで鍵の作成やクラスファイルに証明書をつけたりするために, ツールを利用します.
  • keytool:鍵管理ツール
    • 鍵の作成

      ただし,鍵管理ファイルを独自に作るときは, 「-keystore (鍵管理ファイル名)」 を最後につけます.
      keytool -genkey -alias (エイリアス名) -keyalg (アルゴリズム名)
      		
    • 鍵の取り出し
      keytool -export -alias (エイリアス名) -file (取り出し先のファイル名)
      		
    • 鍵の取り込み
      keytool -import -alias (エイリアス名) -file (取り込み先のファイル名)
      		
    • 鍵の削除
      keytool -delete -alias (エイリアス名)
      		
    現在のJavaで扱えるProviderとアルゴリズムについては, 以下のプログラムを実行することにより知ることができます.
    import java.security.*;
    import java.util.*;
    
    public class CheckProvider{
        public static void main(String[] args){
    	Provider[] prov = Security.getProviders();
    	for(int i = 0; i < prov.length; i++){
    	    System.out.println("Provider:"+prov[i]);
    	    Enumeration e1 = prov[i].keys();
    	    Enumeration e2 = prov[i].elements();
    	    System.out.println("------------------------");
    	    while(e1.hasMoreElements()){
    		System.out.println(e1.nextElement()+":"+e2.nextElement());
    	    }
    	    System.out.println("------------------------");
    	}
        }
    }
    	  
  • jarsigner:Jarファイルに証明書,署名を添付する
    jarsigner (Jarファイル名) (エイリアス名)
    	  
  • policytool:与えるPermissionを規定する

    GUIツールです.Javaアプリケーションをこのpolicytoolで 決めたPermission内で行うとき,多くのPermissionを 与えないとプログラムは動かないことに注意!
    また,ここで作成したPolicyにしたがってプログラムを動かすためには, 以下のように実行する必要があります.

    java -Djava.security.manager (AppName)
    	  

独自のPermissionを作る
FilePermission等のあらかじめ与えられたPermissionではなく, 自分で独自のpermissionを作成する方法を簡単に述べます. Permissionを独自で作成する時に注意することは以下の通りです.
  • java.security.Permissionを継承すること
  • equals,impliesメソッドをオーバライドして独自のメソッドを書くこと
  • ファイル内にPermissionCollectionクラスを書くこと
    • java.securityPermissionCollectionクラスを継承すること
    • add,impliesメソッドを実装すること
ここで,重要なことは,impliesメソッドをどのように実装するかです. 実装したいときは,JDKのソースを見ることをお勧めします.
SecurityManager関連
独自Permissionをチェックするためには,以下のコードをチェックしたい ところで,挿入します.
try{
   //Permissionの作成
   Permission p = new Permission(String name, String action);
   //Permissionのチェック
   AccessController.checkPermission(Permision p);
}catch(SecurityException ex){
   System.err.println(ex);
}
    
Permissionをチェックするときは, checkPermissionを呼び出したクラスだけでなく, そのクラスの呼び出し先のクラスまで, クラスがPermissionを保持しているかどうかをチェックします. チェックに失敗すると,SecurityExceptionをthrowします.

Copyright (C)1997-2001 h-haruki
Last modified: Sun Sep 23 19:35:18 LMT 2001


counter