Di Jawa kita percaya

Percaya pada semua orang? Jangan percaya pada sesiapa? Kedengarannya seperti X-Files, tetapi ketika menyangkut maklumat sulit, mengetahui siapa yang anda percayai sama pentingnya dengan mengetahui apa yang anda percayai. Konsep ini sama pentingnya untuk aplikasi seperti untuk orang. Bagaimanapun, kami telah menjadikan aplikasi sebagai penjaga maklumat kami dan pengawal sumber kami. Ini benar di seluruh perusahaan - aplikasi menyimpan maklumat penting mengenai perniagaan dan pelanggan kami - dan itu benar di desktop. Saya tidak dapat memberitahu anda berapa kali saya ditanya bagaimana menulis applet yang mengimbas pemacu pengguna sehingga satu pengguna dapat menguasai penyemak imbas pengguna lain atau menangkap maklumat peribadi.

Java, sebagai platform pengembangan jaringan seperti itu, harus mengatasi masalah kepercayaan. Hasilnya adalah Java Security API dan Java Cryptography Architecture.

Sekilas pandangan ke belakang

Sebelum saya menyelidiki API, kod, dan komen secara mendalam, saya ingin melihat semula perbincangan bulan lalu secara ringkas. Sekiranya anda menyertai kami untuk pertama kalinya, anda mungkin mahu membuat sandaran sebulan dan membaca "Tanda tangan dan dihantar: Pengenalan keselamatan dan pengesahan." Lajur ini memberikan pengenalan menyeluruh untuk semua istilah dan konsep yang akan saya gunakan bulan ini.

Keselamatan dan pengesahan menangani dua masalah penting: iaitu membuktikan mesej dibuat oleh entiti tertentu, dan membuktikan bahawa mesej tidak dirusak setelah ia dibuat. Salah satu cara untuk memenuhi kedua-dua tujuan ini adalah dengan menggunakan tandatangan digital.

Tanda tangan digital sangat bergantung pada cabang kriptografi yang dikenali sebagai kriptografi kunci awam. Algoritma kunci awam dicirikan oleh fakta bahawa ia bergantung pada sepasang kekunci yang dipadankan (satu peribadi dan satu awam) dan bukannya satu kekunci. Entiti merahsiakan kunci peribadinya, tetapi menyediakan kunci awamnya.

Algoritma tandatangan digital mengambil input mesej dan kunci peribadi entiti, dan menghasilkan tandatangan digital. Tandatangan digital dibuat sedemikian rupa sehingga sesiapa sahaja dapat mengambil kunci awam entiti dan menggunakannya untuk mengesahkan bahawa entiti itu sebenarnya menandatangani mesej yang dimaksudkan. Tambahan pula, jika mesej asal telah diubah, tandatangannya tidak dapat disahkan lagi. Tanda tangan digital memberikan satu faedah tambahan: setelah entiti menandatangani dan menyebarkan mesej, mustahil bagi penciptanya untuk menafikan telah menandatangani mesej (tanpa mendakwa kunci peribadinya dicuri)

Enjin dan pembekal

Java Cryptography API mendefinisikan toolkit Java untuk keselamatan dan pengesahan. Java Cryptography Architecture (JCA) menerangkan cara menggunakan API. Untuk memastikan tahap fleksibiliti tertinggi bagi pemaju dan pengguna akhir, JCA menerapkan dua prinsip panduan:

  1. Senibina harus menyokong kebebasan dan kebolehpanjangan algoritma. Pembangun mesti dapat menulis aplikasi tanpa mengikatnya terlalu dekat dengan algoritma tertentu. Sebagai tambahan, ketika algoritma baru dikembangkan, algoritma tersebut mesti disatukan dengan mudah dengan algoritma yang ada.

  2. Senibina harus menyokong kebebasan pelaksanaan dan interoperabiliti. Pembangun mesti dapat menulis aplikasi tanpa mengaitkannya dengan pelaksanaan algoritma vendor tertentu. Di samping itu, pelaksanaan algoritma yang disediakan oleh pelbagai vendor mesti beroperasi.

Untuk memenuhi dua syarat ini, para pengembang API Kriptografi Java mendasarkan reka bentuk mereka pada sistem enjin dan penyedia.

Enjin menghasilkan contoh penjana pencernaan mesej, penjana tanda digital dan penjana pasangan kunci. Setiap contoh digunakan untuk menjalankan fungsi yang sesuai.

Enjin kanonik dalam JCA adalah kelas yang menyediakan kaedah statik (atau kaedah) bernama getInstance(), yang mengembalikan contoh kelas yang menerapkan algoritma signifikan secara kriptografi. The getInstance()kaedah datang dalam kedua-dua satu hujah dan satu bentuk dua hujah. Dalam kedua kes tersebut, argumen pertama adalah nama algoritma. JCA memberikan senarai nama standard, walaupun tidak semua akan diberikan dalam siaran tertentu. Argumen kedua memilih pembekal.

Pembekal SUN

Hanya satu pembekal - SUN - yang dibekalkan dalam JDK 1.1. SUN menyediakan pelaksanaan algoritma NIST Digital Signature (DSA), dan pelaksanaan algoritma pencernaan mesej MD5 dan NIST SHA-1.

Mesej KelasDigest

Kita akan bermula dengan melihat kod yang menghasilkan intisari mesej dari mesej.

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

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

Seperti yang saya sebutkan sebentar tadi, getInstance()kaedah ini terdapat dalam dua rasa. Yang pertama hanya memerlukan algoritma yang ditentukan. Yang kedua memerlukan algoritma dan penyedia ditentukan. Kedua-duanya mengembalikan contoh kelas yang menerapkan algoritma SHA.

Seterusnya, kami menyampaikan mesej melalui penjana pencernaan mesej.

int n = 0; bait [] rgb = bait baru [1000]; manakala ((n = inputstreamMessage.read (rgb))> -1) {messagedigest.update (rgb, 0, n); }

Di sini, kami menganggap mesej itu tersedia sebagai aliran input. Kod ini berfungsi dengan baik untuk pesanan besar dengan panjang yang tidak diketahui. The update()kaedah juga menerima satu bait tunggal sebagai hujah untuk mesej daripada beberapa bait panjang, dan pelbagai bait untuk mesej saiz yang tetap atau boleh diramal.

rgb = messagedigest.digest ();

Langkah terakhir melibatkan penghasilan intisari mesej itu sendiri. Ringkasan yang dihasilkan dikodkan dalam pelbagai bait.

Seperti yang anda lihat, JCA dengan mudah menyembunyikan semua perincian tahap rendah dan perincian khusus algoritma, yang membolehkan anda bekerja pada tahap yang lebih tinggi dan lebih abstrak.

Sudah tentu, salah satu risiko pendekatan abstrak adalah peningkatan kemungkinan bahawa kita tidak akan mengenali output yang salah akibat pepijat. Memandangkan peranan kriptografi, ini boleh menjadi masalah yang ketara.

Pertimbangkan bug "off-by-one" di baris kemas kini di bawah:

int n = 0; bait [] rgb = bait baru [1000]; manakala ((n = inputstreamMessage.read (rgb))> -1) {messagedigest.update (rgb, 0, n - 1); }

Pengaturcara C, C ++, dan Java menggunakan idio had-minus-one dengan kerap sehingga menaip menjadi hampir automatik - walaupun tidak sesuai. Kod di atas akan dikompilasi, dan yang dapat dijalankan akan dijalankan tanpa ralat atau amaran, tetapi intisari mesej yang dihasilkan akan salah.

Nasib baik, JCA dipikirkan dengan baik dan dirancang dengan baik, menjadikan perangkap yang berpotensi seperti yang di atas agak jarang berlaku.

Sebelum kita beralih ke penjana pasangan kunci, lihatlah

MessageDigestGenerator, kod sumber lengkap untuk program yang menghasilkan intisari mesej.

KeyPairGenerator Kelas

Untuk menghasilkan tandatangan digital (dan menyulitkan data), kami memerlukan kunci.

Key generation, in its algorithm-independent form, is not substantially more difficult than creating and using a message digest.

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

As in the message digest example above, this code creates an instance of a class that generates DSA-compatible keys. A second (if necessary) argument specifies the provider.

After a key-pair generator instance is created, it must be initialized. We can initialize key-pair generators in one of two ways: algorithm-independent or algorithm-dependent. Which method you use depends on the amount of control you want over the final result.

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

Keys based on different algorithms differ in how they're generated, but they have one parameter in common -- the key's strength. Strength is a relative term that corresponds roughly to how hard the key will be to "break." If you use the algorithm-independent initializer, you can specify only the strength -- any algorithm-dependent values assume reasonable defaults.

DSAKeyPairGenerator dsakeypairgenerator = (DSAKeyPairGenerator) keypairgenerator; DSAParams dsaparams = new DSAParams() { private BigInteger p = BigInteger(...); private BigInteger q = BigInteger(...); private BigInteger g = BigInteger(...); public BigInteger getP() { return p; } public BigInteger getQ() { return q; } public BigInteger getG() { return g; } }; dsakeypairgenerator.initialize(dsaparams, new SecureRandom());

While the defaults are usually good enough, if you need more control, it is available. Let's assume you used the engine to create a generator of DSA-compatible keys, as in the code above. Behind the scenes, the engine loaded and instantiated an instance of a class that implements the DSAKeyPairGenerator interface. If we cast the generic key-pair generator we received to DSAKeyPairGenerator, we then gain access to the algorithm-dependent method of initialization.

To initialize a DSA key-pair generator, we need three values: the prime P, the subprime Q, and the base G. These values are captured in an inner class instance that is passed to the initialize() method.

The SecureRandom class provides a secure source of random numbers used in the key-pair generation.

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.

Bulan depan saya akan kembali ke wilayah middleware. Saya akan mengambil sedikit RMI, beberapa threading, dan sebilangan besar kod, dan menunjukkan kepada anda cara membina middleware berorientasikan mesej anda sendiri.

Todd Sundsted telah menulis program sejak komputer tersedia dalam model desktop yang mudah digunakan. Walaupun pada awalnya berminat untuk membangun aplikasi objek terdistribusi dalam C ++, Todd beralih ke bahasa pengaturcaraan Java ketika menjadi pilihan yang jelas untuk hal semacam itu. Selain menulis, Todd adalah presiden Etcee yang menawarkan perkhidmatan latihan, bimbingan, perundingan, dan pengembangan perisian.

Ketahui lebih lanjut mengenai topik ini

  • Muat turun kod sumber lengkap //www.javaworld.com/jw-01-1999/howto/jw-01-howto.zip
  • Gambaran Keseluruhan API Keselamatan Java //www.javasoft.com/products/jdk/1.1/docs/guide/security/JavaSecurityOverview.html
  • Senibina Kriptografi Java //www.javasoft.com/products/jdk/1.1/docs/guide/security/CryptoSpec.html
  • Halaman Keselamatan Java Sun //java.sun.com/security/index.html
  • Soalan Lazim RSA mengenai Kriptografi //www.rsa.com/rsalabs/faq/
  • Dasar dan Maklumat Kriptografi //www.crypto.com/
  • Baca lajur Howd To Java sebelumnya //www.javaworld.com/topicalindex/jw-ti-howto.html

Kisah ini, "Di Jawa yang kami percayai" pada awalnya diterbitkan oleh JavaWorld.