//////////////////////////////////////////////////////////////////////////// 
// 
// Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1993, 1994, 1995.
// Unpublished work.  All Rights Reserved.
// 
// The software contained on this media is the property of the
// DSTC Pty Ltd.  Use of this software is strictly in accordance
// with the license agreement in the accompanying LICENSE.DOC 
// file. If your distribution of this software does not contain 
// a LICENSE.DOC file then you have no rights to use this 
// software in any manner and should contact DSTC at the address 
// below to determine an appropriate licensing arrangement.
// 
//      DSTC Pty Ltd
//      Level 7, GP South
//      University of Queensland
//      St Lucia, 4072
//      Australia
//      Tel: +61 7 3365 4310
//      Fax: +61 7 3365 4311
//      Email: jcsi@dstc.qut.edu.au
// 
// This software is being provided "AS IS" without warranty of
// any kind.  In no event shall DSTC Pty Ltd be liable for
// damage of any kind arising out of or in connection with
// the use or performance of this software.
// 
//////////////////////////////////////////////////////////////////////////// 

package com.dstc.security.pkcs8;

import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.security.AlgorithmParameters;
import javax.crypto.Cipher;
import javax.crypto.spec.PBEParameterSpec;

import com.dstc.security.asn1.Sequence;
import com.dstc.security.asn1.OctetString;
import com.dstc.security.asn1.Asn1Exception;
import com.dstc.security.x509.AlgorithmId;

import com.dstc.security.provider.PBEKey;
import com.dstc.security.provider.OID;

/**
 * <p>A class representing the PKCS#8 ASN.1 structure PrivateKeyInfo.
 *
 * <pre>
 * PrivateKeyInfo ::= SEQUENCE {
 *                        version             Version,
 *                        privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
 *                        privateKey          PrivateKey,
 *                        attributes [0] IMPLICIT Attributes OPTIONAL }
 *
 * Version ::= INTEGER -- equals to 0
 *
 * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
 *
 * PrivateKey ::= OCTET STRING
 *
 * Attributes ::= SET OF Attribute
 * </pre>
 *
 * @see com.dstc.security.x509.AlgorithmId
 * @see com.dstc.security.x509.Attribute
 *
 * @version 0.98, 98/07/01
 * @author Ming Yung
 */
public class PrivateKeyInfo extends Sequence
{
  //Private Key
  private byte encodedKey[];

  //Private Key Algorithm
  private AlgorithmId privAlgo;

  /**
   * Constructs a PrivateKeyInfo from an AlgorithmId and encoded key
   */
  public PrivateKeyInfo(AlgorithmId algo, byte encodedKey[])
  {
    this.addComponent(new com.dstc.security.asn1.Integer(0));

    this.privAlgo = algo;
    this.addComponent(algo);

    this.encodedKey = encodedKey;
    this.addComponent(new OctetString(encodedKey));
  }

  /**
   * Constructs a PrivateKeyInfo from a DER encoding
   */
  public PrivateKeyInfo(byte encoded[]) throws Asn1Exception
  {
    doDecode(encoded);
    this.privAlgo = new AlgorithmId(
                    ((Sequence)components.elementAt(1)).encode());
    this.encodedKey = ((OctetString)components.elementAt(2)).getBytes();
  }

  /**
   * Returns the AlgorithmId
   */
  public AlgorithmId getAlgorithmId()
  {
    return this.privAlgo;
  }

  /**
   * Returns the encoded key
   */
  public byte[] getEncodedKey()
  {
    return this.encodedKey;
  }


  /**
   * Encrypts and returns the key
   */
  public byte[] encrypt()
  {
    try
    {
      //Encrypt it with a PBECipher
      //Generate salt;
      byte preSalt[] = "Hello there!".getBytes();
      byte salt[] = new byte[8];
      System.arraycopy (preSalt, 0, salt, 0, 8);
      PBEParameterSpec paramsSpec = new PBEParameterSpec (salt, 5);
      AlgorithmParameters algParams =
        AlgorithmParameters.getInstance("PBEwithMD5andDES");
      algParams.init(paramsSpec);

      //Prompt for password and generate PBEKey
      System.err.print("Enter password: ");
      InputStreamReader isr = new InputStreamReader(System.in);
      BufferedReader in = new BufferedReader(isr);
      PBEKey pbeKey = new PBEKey(in.readLine());

      //Get Cipher object and encrypt encoded private key
      Cipher cipher = Cipher.getInstance("PBEwithMD5andDES");
      cipher.init (Cipher.ENCRYPT_MODE, pbeKey, paramsSpec);
      byte encrypted[] = cipher.doFinal(this.encode());

      //Construct an EncryptedPrivateKeyInfo object and return its encoding
      return new EncryptedPrivateKeyInfo(new AlgorithmId(
        OID.pbeWithMD5AndDES_CBC, algParams),
        encrypted).encode();
    }
    catch (Exception e)
    {
      e.printStackTrace();
      return null;
    }
  }
}
