Di Jawa kami percaya

Percaya semuanya? Tidak percaya siapapun? Kedengarannya seperti X-Files, tetapi jika menyangkut informasi rahasia, mengetahui siapa yang Anda percayai sama pentingnya dengan mengetahui dengan apa Anda mempercayai mereka. Konsep ini sama pentingnya untuk aplikasi dan juga untuk manusia. Lagi pula, kami telah menjadikan aplikasi sebagai penjaga informasi kami dan pengelola sumber daya kami. Ini benar di seluruh perusahaan - aplikasi menyimpan informasi penting tentang bisnis kita dan pelanggan kita - dan itu benar di desktop. Saya tidak dapat memberi tahu Anda berapa kali saya ditanyai bagaimana menulis applet yang memindai drive pengguna sehingga satu pengguna dapat mengambil alih browser pengguna lain atau menangkap informasi pribadi.

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

Sekilas mundur

Sebelum saya terjun langsung ke API, kode, dan komentar, saya ingin meninjau kembali diskusi bulan lalu secara singkat. Jika Anda bergabung dengan kami untuk pertama kalinya, Anda mungkin ingin mencadangkan sebulan dan membaca "Ditandatangani dan dikirim: Pengantar keamanan dan otentikasi." Kolom ini memberikan pengantar menyeluruh untuk semua istilah dan konsep yang akan saya gunakan bulan ini.

Keamanan dan otentikasi menangani dua masalah penting: yaitu membuktikan pesan dibuat oleh entitas tertentu, dan membuktikan bahwa pesan tidak dirusak setelah dibuat. Salah satu cara untuk memenuhi kedua tujuan tersebut adalah dengan menggunakan tanda tangan digital.

Tanda tangan digital sangat bergantung pada cabang kriptografi yang dikenal sebagai kriptografi kunci publik. Algoritme kunci publik dicirikan oleh fakta bahwa algoritme tersebut mengandalkan pasangan kunci yang cocok (satu pribadi dan satu publik) daripada satu kunci. Entitas menyimpan kunci privatnya, tetapi membuat kunci publiknya tersedia.

Algoritme tanda tangan digital mengambil sebagai masukan pesan dan kunci pribadi entitas, dan menghasilkan tanda tangan digital. Tanda tangan digital dibuat sedemikian rupa sehingga siapa pun dapat mengambil kunci publik entitas dan menggunakannya untuk memverifikasi bahwa entitas tersebut sebenarnya menandatangani pesan yang dipermasalahkan. Selanjutnya, jika pesan asli telah dirusak, tandatangannya tidak dapat lagi diverifikasi. Tanda tangan digital memberikan satu manfaat tambahan: setelah entitas menandatangani dan mendistribusikan pesan, tidak mungkin bagi pencetusnya untuk menyangkal telah menandatangani pesan (tanpa mengklaim kunci pribadinya telah dicuri).

Mesin dan penyedia

Java Cryptography API mendefinisikan toolkit Java untuk keamanan dan otentikasi. Arsitektur Kriptografi Java (JCA) menjelaskan cara menggunakan API. Untuk memastikan tingkat fleksibilitas tertinggi bagi pengembang dan pengguna akhir, JCA menerapkan dua prinsip panduan:

  1. Arsitektur harus mendukung kemandirian dan ekstensibilitas algoritme. Pengembang harus dapat menulis aplikasi tanpa mengikatnya terlalu dekat dengan algoritme tertentu. Selain itu, saat algoritme baru dikembangkan, algoritme tersebut harus mudah diintegrasikan dengan algoritme yang ada.

  2. Arsitektur harus mendukung independensi implementasi dan interoperabilitas. Pengembang harus dapat menulis aplikasi tanpa mengikatnya ke implementasi algoritme vendor tertentu. Selain itu, implementasi algoritme yang disediakan oleh vendor berbeda harus saling beroperasi.

Untuk memenuhi dua persyaratan ini, pengembang Java Cryptography API mendasarkan desain mereka pada sistem mesin dan penyedia.

Mesin menghasilkan contoh generator intisari pesan, generator tanda tangan digital, dan generator pasangan kunci. Setiap instance digunakan untuk menjalankan fungsinya yang sesuai.

Mesin kanonik di JCA adalah kelas yang menyediakan metode statis (atau metode) bernama getInstance(), yang mengembalikan instance kelas yang mengimplementasikan algoritme yang signifikan secara kriptografis. The getInstance()Metode datang di kedua satu-argumen dan bentuk dua argumen. Dalam kedua kasus tersebut, argumen pertama adalah nama algoritme. JCA menyediakan daftar nama standar, meskipun tidak semua akan diberikan dalam rilis tertentu. Argumen kedua memilih penyedia.

Penyedia SUN

Hanya satu provider - SUN - yang tersedia di JDK 1.1. SUN menyediakan implementasi NIST Digital Signature Algorithm (DSA), dan implementasi algoritma intisari pesan MD5 dan NIST SHA-1.

Kelas MessageDigest

Kita akan mulai dengan melihat kode yang menghasilkan intisari pesan dari sebuah pesan.

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

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

Seperti yang saya sebutkan beberapa saat yang lalu, getInstance()metode ini hadir dalam dua rasa. Yang pertama hanya membutuhkan algoritme untuk ditentukan. Yang kedua membutuhkan algoritme dan penyedia untuk ditentukan. Keduanya mengembalikan instance kelas yang mengimplementasikan algoritma SHA.

Selanjutnya, kami meneruskan pesan melalui generator intisari pesan.

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

Di sini, kami menganggap pesan tersedia sebagai aliran input. Kode ini berfungsi dengan baik untuk pesan besar dengan panjang yang tidak diketahui. The update()Metode juga menerima satu byte sebagai argumen untuk pesan dari beberapa byte panjangnya, dan array byte untuk pesan dari ukuran tetap atau diprediksi.

rgb = messagedigest.digest ();

Langkah terakhir melibatkan pembuatan intisari pesan itu sendiri. Intisari yang dihasilkan dikodekan dalam array byte.

Seperti yang Anda lihat, JCA dengan mudah menyembunyikan semua implementasi level rendah dan detail spesifik algoritme, memungkinkan Anda bekerja pada level yang lebih tinggi dan lebih abstrak.

Tentu saja, salah satu risiko dari pendekatan abstrak seperti itu adalah meningkatnya kemungkinan bahwa kita tidak akan mengenali keluaran yang salah akibat bug. Mengingat peran kriptografi, ini bisa menjadi masalah yang signifikan.

Pertimbangkan bug "off-by-one" pada baris pembaruan di bawah ini:

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

Pemrogram C, C ++, dan Java sangat sering menggunakan idiom limit-minus-satu sehingga mengetik menjadi hampir otomatis - bahkan jika tidak sesuai. Kode di atas akan dikompilasi, dan executable akan berjalan tanpa kesalahan atau peringatan, tetapi intisari pesan yang dihasilkan akan salah.

Untungnya, JCA telah dipikirkan dengan matang dan dirancang dengan baik, membuat potensi jebakan seperti di atas relatif jarang.

Sebelum kita beralih ke generator pasangan kunci, lihat dulu

MessageDigestGenerator, kode sumber lengkap untuk program yang menghasilkan intisari pesan.

Class KeyPairGenerator

Untuk menghasilkan tanda tangan digital (dan mengenkripsi data), kita membutuhkan 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 tumpukan kode, dan menunjukkan kepada Anda bagaimana membangun middleware Anda sendiri yang berorientasi pada pesan.

Todd Sundsted telah menulis program sejak komputer tersedia dalam model desktop yang nyaman. Meskipun awalnya tertarik untuk membangun aplikasi objek terdistribusi di C ++, Todd beralih ke bahasa pemrograman Java ketika bahasa itu menjadi pilihan yang jelas untuk hal semacam itu. Selain menulis, Todd adalah presiden Etcee yang menawarkan layanan pelatihan, bimbingan, konsultasi, dan pengembangan perangkat lunak.

Pelajari lebih lanjut tentang topik ini

  • Unduh kode sumber lengkapnya //www.javaworld.com/jw-01-1999/howto/jw-01-howto.zip
  • Ikhtisar Java Security API //www.javasoft.com/products/jdk/1.1/docs/guide/security/JavaSecurityOverview.html
  • Arsitektur Kriptografi Java //www.javasoft.com/products/jdk/1.1/docs/guide/security/CryptoSpec.html
  • Halaman Keamanan Java Sun //java.sun.com/security/index.html
  • FAQ RSA tentang Kriptografi //www.rsa.com/rsalabs/faq/
  • Kebijakan dan Informasi Kriptografi //www.crypto.com/
  • Baca kolom How-To Java Todd sebelumnya //www.javaworld.com/topicalindex/jw-ti-howto.html

Artikel berjudul "Di Jawa Kami Percaya" ini awalnya diterbitkan oleh JavaWorld.