/* Fail: Krypto.java
 * Jaanus Poial
 */

import java.io.*;
import java.security.*;
import java.security.cert.*;
import javax.crypto.*;

/**
 * Kryptoklasside elemente.
 * @author Jaanus Poial
 * @version 0.3
 * @since 1.4
 */
public class Krypto {

   /**
    * peameetod.
    * @param p k2surida
    */
   public static void main (String[] p) {
      try {

	 // asymmeetrilise algoritmi jaoks v6tmepaari genereerimine
	 // RSA - Rivest, Shamir, Adleman 1978
         KeyPairGenerator pgen = KeyPairGenerator.getInstance ("RSA");
         pgen.initialize (1024); // 2048 on lubatud
         KeyPair paar = pgen.generateKeyPair();
         PublicKey avavoti = paar.getPublic();        // avalik v6ti
         PrivateKey privavoti = paar.getPrivate();    // privaatne v6ti

	 // symmeetrilise algoritmi jaoks v6tme genereerimine
	 // "Triple-DES"
	 KeyGenerator vgen = KeyGenerator.getInstance ("DESede");
         vgen.init (112); // 168 lubatud
         SecretKey salavoti = vgen.generateKey();     // salajane v6ti

         // v6tmehoidla, v6tmete salvestamine ja lugemine
         KeyStore hoidla = KeyStore.getInstance ("JCEKS");
         hoidla.load (null, "parool".toCharArray());
         hoidla.setKeyEntry ("avalik", avavoti, "parool2".toCharArray(), null);
	 hoidla.setKeyEntry ("sala", salavoti, "parool3".toCharArray(), null);
	 // privaatv6tit saab salvestada ainult sertifikaadiga
	 // lugemine algab tegelikult load-st, mis praegu on tehtud
	 Key voti = hoidla.getKey ("avalik", "parool2".toCharArray());
         FileOutputStream fos = new FileOutputStream ("votmed");
         hoidla.store (fos, "parool".toCharArray());
         fos.close();

	 // allkirjastamine privaatv6tmega
         Signature sgn = Signature.getInstance ("MD5withRSA");
         sgn.initSign (privavoti);
         byte[] teade = "Sellele lausele annan allkirja".getBytes();
         sgn.update (teade);
         byte[] tulemus = sgn.sign(); // allkirjastatud baitmassiiv

	 // allkirja kontrollimine avaliku v6tmega
         sgn.initVerify ((PublicKey)voti);
         sgn.update (teade);
         if (sgn.verify (tulemus)) 
	    System.out.println ("Qige allkiri: " + sgn.toString());
	 else System.out.println ("Vale allkiri: " + sgn.toString());

         // allkirjastatud objekt
         Serializable objekt = "See on yks v2ga t2htis objekt";
         SignedObject aobjekt = new SignedObject (objekt, privavoti, sgn);
         String tmp = (String)aobjekt.getObject();
         System.out.println (tmp);
         if (aobjekt.verify (avavoti, sgn)) System.out.println ("OK");
         else System.out.println ("Ei klapi");

	 // r2simine
         MessageDigest md5 = MessageDigest.getInstance ("MD5");
	 md5.reset(); // praegusel hetkel saab ka ilma selleta
	 byte[] sonum = "arvutatakse r2si (128 bitti)".getBytes();
	 md5.update (sonum);
	 byte[] rasi = md5.digest();        // s6numilyhend
	 System.out.print ("S6numilyhend: ");
	 for (int i=0; i<rasi.length; i++) {
            System.out.print (Integer.toHexString (rasi [i]&0xff) + " ");
	 }
	 System.out.println();
	 
	 // kryptimine symmeetrilise algoritmiga
	 Cipher shiffer = Cipher.getInstance ("DESede");
         shiffer.init (Cipher.ENCRYPT_MODE, salavoti);
	 byte[] avatekst = "See on suur saladus".getBytes();
	 // pikema teate korral osamassiivid saadakse update abil
         byte[] shiffertekst = shiffer.doFinal (avatekst); // shifreeritud

	 // dekryptimine
	 shiffer.init (Cipher.DECRYPT_MODE, salavoti);
	 byte[] tagasi = shiffer.doFinal (shiffertekst);
	 System.out.println (new String (tagasi));

	 // kryptitud voog - kirjutamine
         FileInputStream avavoog1 = new FileInputStream ("andmed");
	 FileOutputStream krvoog1 = new FileOutputStream ("krandmed");
	 shiffer.init (Cipher.ENCRYPT_MODE, salavoti);
	 CipherOutputStream cout = new CipherOutputStream (krvoog1, shiffer);
	 int b;
	 while ((b = avavoog1.read()) != -1) {
            cout.write (b);
	 }
	 cout.close();

	 // kryptitud voog - lugemine
	 FileInputStream krvoog2 = new FileInputStream ("krandmed");
	 FileOutputStream avavoog2 = new FileOutputStream ("andmed2");
	 shiffer.init (Cipher.DECRYPT_MODE, salavoti);
	 CipherInputStream cin = new CipherInputStream (krvoog2, shiffer);
	 while ((b = cin.read()) != -1) {
            avavoog2.write (b);
         }
         avavoog2.close();
	 
	 // X509 sertifikaadi lugemine failist
	 // vaata keytool-programmi sertifikaatide jaoks
         CertificateFactory cfac = CertificateFactory.getInstance ("X.509");
	 InputStream svoog = new FileInputStream ("sertifikaat");
         X509Certificate cert = 
	    (X509Certificate)cfac.generateCertificate (svoog);
	 svoog.close();
      } 
      catch (Exception e) {
	 System.out.println ("Jama " + e.toString());
      }
   } // main lopp

} // Krypto lopp

