Javaでは信頼しています

みんなを信頼しますか?誰も信じない?X-ファイルに少し似ているように聞こえますが、機密情報に関しては、誰を信頼しているかを知ることは、何を信頼しているかを知ることと同じくらい重要です。この概念は、アプリケーションにとっても人にとっても重要です。結局のところ、私たちはアプリケーションを私たちの情報の管理者と私たちのリソースの管理者にしました。これは企業全体に当てはまります。アプリケーションは私たちのビジネスと顧客に関する重要な情報を保持します。そしてそれはデスクトップにも当てはまります。あるユーザーが別のユーザーのブラウザを操作したり、個人情報を取得したりできるように、ユーザーのドライブをスキャンするアプレットの作成方法を尋ねられた回数はわかりません。

Javaは、それ自体がネットワーク開発プラットフォームであるため、信頼の問題に正面から取り組む必要がありました。その結果が、Java SecurityAPIとJavaCryptographyArchitectureです。

後ろ向きに一瞥

API、コード、解説に真っ向から飛び込む前に、先月の議論を簡単に振り返りたいと思います。初めて参加する場合は、1か月バックアップして、「署名と配信:セキュリティと認証の概要」を読むことをお勧めします。このコラムでは、今月使用するすべての用語と概念を完全に紹介します。

セキュリティと認証は、メッセージが特定のエンティティによって作成されたことを証明することと、メッセージが作成された後に改ざんされていないことを証明することの2つの重要な懸念に対処します。これらの両方の目標を達成する1つの方法は、デジタル署名を使用することです。

デジタル署名は、公開鍵暗号化として知られる暗号化の分野に大きく依存しています。公開鍵アルゴリズムは、単一の鍵ではなく、一致する鍵のペア(1つは秘密鍵と1つは公開鍵)に依存しているという特徴があります。エンティティは秘密鍵を秘密に保ちますが、公開鍵を利用できるようにします。

デジタル署名アルゴリズムは、メッセージとエンティティの秘密鍵を入力として受け取り、デジタル署名を生成します。デジタル署名は、誰でもエンティティの公開鍵を取得し、それを使用して、エンティティが問題のメッセージに実際に署名したことを確認できるように作成されます。さらに、元のメッセージが改ざんされていると、署名を検証できなくなります。デジタル署名には、もう1つの利点があります。エンティティがメッセージに署名して配布すると、発信者がメッセージに署名したことを否定することはできません(とにかく、秘密鍵が盗まれたと主張することなく)。

エンジンとプロバイダーの

Java Cryptography APIは、セキュリティと認証のためのJavaツールキットを定義します。Java暗号化アーキテクチャ(JCA)は、APIの使用方法を説明しています。開発者とエンドユーザーの両方に最高の柔軟性を保証するために、JCAは2つの指針を採用しています。

  1. アーキテクチャは、アルゴリズムの独立性と拡張性をサポートする必要があります。開発者は、特定のアルゴリズムにあまり密接に結び付けずにアプリケーションを作成できなければなりません。さらに、新しいアルゴリズムが開発されると、それらは既存のアルゴリズムと簡単に統合される必要があります。

  2. アーキテクチャは、実装の独立性と相互運用性をサポートする必要があります。開発者は、特定のベンダーのアルゴリズムの実装に縛られることなく、アプリケーションを作成できなければなりません。さらに、さまざまなベンダーが提供するアルゴリズムの実装は相互運用する必要があります。

これらの2つの要件を満たすために、Java Cryptography APIの開発者は、エンジンとプロバイダーのシステムに基づいて設計を行いました。

エンジンは、メッセージダイジェストジェネレーター、デジタル署名ジェネレーター、およびキーペアジェネレーターのインスタンスを生成します。各インスタンスは、対応する機能を実行するために使用されます。

JCAの正規エンジンは、という名前の静的メソッドを提供getInstance()するクラスであり、暗号的に重要なアルゴリズムを実装するクラスのインスタンスを返します。このgetInstance()方法には、1つの引数と2つの引数の両方の形式があります。どちらの場合も、最初の引数はアルゴリズムの名前です。JCAは標準名のリストを提供しますが、特定のリリースですべてが提供されるわけではありません。2番目の引数はプロバイダーを選択します。

SUNプロバイダー

JDK 1.1では、1つのプロバイダー(SUN)のみが提供されます。SUNは、NISTデジタル署名アルゴリズム(DSA)の実装と、MD5およびNISTSHA-1メッセージダイジェストアルゴリズムの実装の両方を提供します。

クラスMessageDigest

まず、メッセージからメッセージダイジェストを生成するコードを見ていきます。

MessageDigest messagedigest = MessageDigest.getInstance( "SHA");

MessageDigest messagedigest = MessageDigest.getInstance( "SHA"、 "SUN");

少し前に述べたように、このgetInstance()方法には2つの種類があります。1つ目は、アルゴリズムのみを指定する必要があります。2つ目は、アルゴリズムとプロバイダーの両方を指定する必要があります。どちらも、SHAアルゴリズムを実装するクラスのインスタンスを返します。

次に、メッセージをメッセージダイジェストジェネレータに渡します。

int n = 0; バイト[] rgb =新しいバイト[1000]; while((n = inputstreamMessage.read(rgb))> -1){messagedigest.update(rgb、0、n); }

ここでは、メッセージが入力ストリームとして利用可能であると想定しています。このコードは、長さが不明な大きなメッセージに適しています。このupdate()メソッドは、長さが数バイトのメッセージの引数として1バイトを受け入れ、固定または予測可能なサイズのメッセージのバイト配列も受け入れます。

rgb = messagedigest.digest();

最後のステップでは、メッセージダイジェスト自体を生成します。結果のダイジェストは、バイトの配列にエンコードされます。

ご覧のとおり、JCAは、すべての低レベルの実装とアルゴリズム固有の詳細を便利に非表示にして、より高い、より抽象的なレベルで作業できるようにします。

もちろん、このような抽象的なアプローチのリスクの1つは、バグに起因する誤った出力を認識できない可能性が高くなることです。暗号化の役割を考えると、これは重大な問題になる可能性があります。

以下の更新行の「オフバイワン」バグについて考えてみます。

int n = 0; バイト[] rgb =新しいバイト[1000]; while((n = inputstreamMessage.read(rgb))> -1){messagedigest.update(rgb、0、n-1); }

C、C ++、およびJavaプログラマーは、制限マイナス1のイディオムを頻繁に使用するため、適切でない場合でも、入力はほぼ自動的になります。上記のコードはコンパイルされ、実行可能ファイルはエラーや警告なしで実行されますが、結果のメッセージダイジェストは正しくありません。

幸いなことに、JCAはよく考えられ、よく設計されているため、上記のような潜在的な落とし穴は比較的まれです。

キーペアジェネレータに移る前に、

MessageDigestGenerator、メッセージダイジェストを生成するプログラムの完全なソースコード。

クラスKeyPairGenerator

デジタル署名を生成する(そしてデータを暗号化する)には、キーが必要です。

アルゴリズムに依存しない形式のキー生成は、メッセージダイジェストを作成して使用するよりも実質的に難しくありません。

KeyPairGenerator keypairgenerator = KeyPairGenerator.getInstance( "DSA");

上記のメッセージダイジェストの例のように、このコードはDSA互換のキーを生成するクラスのインスタンスを作成します。2番目の(必要な場合)引数はプロバイダーを指定します。

キーペアジェネレータインスタンスを作成したら、初期化する必要があります。キーペアジェネレーターは、アルゴリズムに依存しない、またはアルゴリズムに依存する2つの方法のいずれかで初期化できます。どちらの方法を使用するかは、最終結果を制御する量によって異なります。

keypairgenerator.initialize(1024、new SecureRandom());

異なるアルゴリズムに基づくキーは、生成方法が異なりますが、共通のパラメーターが1つあります。それは、キーの強度です。強さは、鍵が「壊す」のがどれほど難しいかに大まかに対応する相対的な用語です。アルゴリズムに依存しない初期化子を使用する場合は、強度のみを指定できます。アルゴリズムに依存する値はすべて、適切なデフォルトを想定しています。

DSAKeyPairGenerator dsakeypairgenerator =(DSAKeyPairGenerator)keypairgenerator; DSAParams dsaparams = new DSAParams(){private BigInteger p = BigInteger(...); プライベートBigIntegerq = BigInteger(...); プライベートBigIntegerg = BigInteger(...); public BigInteger getP(){return p; } public BigInteger getQ(){return q; } public BigInteger getG(){return g; }}; dsakeypairgenerator.initialize(dsaparams、new SecureRandom());

通常はデフォルトで十分ですが、さらに制御が必要な場合は、デフォルトを使用できます。上記のコードのように、エンジンを使用してDSA互換キーのジェネレーターを作成したと仮定します。舞台裏では、エンジンはDSAKeyPairGeneratorインターフェースを実装するクラスのインスタンスをロードしてインスタンス化しました。受け取った汎用キーペアジェネレーターをにキャストするDSAKeyPairGeneratorと、アルゴリズムに依存する初期化方法にアクセスできるようになります。

DSAキーペアジェネレータを初期化するには、プライムP、サブプライムQ、およびベースGの3つの値が必要ですこれらの値は、initialize()メソッドに渡される内部クラスインスタンスにキャプチャされます。

このSecureRandomクラスは、キーペアの生成に使用される乱数の安全なソースを提供します。

return keypairgenerator.generateKeyPair();

The final step involves generating the key pair itself.

Before we move on to digital signatures, take a look at KeyTools, the complete source code for a program that generates a key pair.

Class Signature

The creation and use of an instance of the Signature class is not substantially different from either of the two previous examples. The differences lie in how the instance is used -- either to sign or to verify a message.

Signature signature = Signature.getInstance("DSA");

Just as before, we use the engine to get an instance of the appropriate type. What we do next depends on whether or not we are signing or verifying a message.

signature.initSign(privatekey);

In order to sign a message, we must first initialize the signature instance with the private key of the entity that is signing the message.

signature.initVerify(publickey);

In order to verify a message, we must initialize the signature instance with the public key of the entity that claims it signed the message.

int n = 0; byte [] rgb = new byte [1000]; while ((n = inputstreamMessage.read(rgb)) > -1) { signature.update(rgb, 0, n); }

Next, regardless of whether or not we are signing or verifying, we must pass the message through the signature generator. You'll notice how similar the process is to the earlier example of generating a message digest.

The final step consists of generating the signature or verifying a signature.

rgb = signature.sign();

If we are signing a message, the sign() method returns the signature.

signature.verify(rgbSignature);

If we are verifying the signature previously generated from a message, we must use the verify() method. It takes as a parameter the previously generated signature and determines whether or not it is still valid.

Before we wrap things up, take a look at Sign.java, the complete source code for a program that signs a message, and Verify.java, the complete source code for a program that verifies a message.

Conclusion

If you arm yourself with the tools and techniques I've presented this month, you'll be more than ready to secure your applications. The Java Cryptography API makes the process almost effortless. Release 1.2 of the Java Developers Kit promises even more. Stay tuned.

来月はミドルウェアの領域に戻ります。少しのRMI、いくつかのスレッド化、およびコードのヒープを取り上げて、独自のメッセージ指向ミドルウェアを構築する方法を示します。

Todd Sundstedは、コンピューターが便利なデスクトップモデルで利用できるようになって以来、プログラムを作成してきました。Toddは、もともとC ++で分散オブジェクトアプリケーションを構築することに興味を持っていましたが、そのようなことの明白な選択になったときにJavaプログラミング言語に移行しました。Toddは、執筆に加えて、トレーニング、メンタリング、コンサルティング、およびソフトウェア開発サービスを提供するEtceeの社長です。

このトピックの詳細

  • 完全なソースコードをダウンロードする//www.javaworld.com/jw-01-1999/howto/jw-01-howto.zip
  • Java SecurityAPIの概要//www.javasoft.com/products/jdk/1.1/docs/guide/security/JavaSecurityOverview.html
  • Java暗号化アーキテクチャ//www.javasoft.com/products/jdk/1.1/docs/guide/security/CryptoSpec.html
  • SunのJavaセキュリティページ//java.sun.com/security/index.html
  • 暗号化に関するRSAのFAQ // www.rsa.com / rsalabs / faq /
  • 暗号化ポリシーと情報//www.crypto.com/
  • Toddの以前のハウツーJavaコラムを読む//www.javaworld.com/topicalindex/jw-ti-howto.html

この物語、「私たちが信頼するJavaで」は、もともとJavaWorldによって発行されました。