//////////////////////////////////////////////////////////////////////////// 
// 
// 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.provider;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.AlgorithmParameters;
import javax.crypto.Cipher;
import javax.crypto.spec.PBEParameterSpec;
import com.dstc.security.asn1.*;
import com.dstc.security.x509.AlgorithmId;
import com.dstc.security.pkcs8.PrivateKeyInfo;
import com.dstc.security.pkcs8.EncryptedPrivateKeyInfo;

/**
 * <p>Implements a private key for use with the RSA-based signature algorithms.
 * 
 * @see java.security.PublicKey
 * @see java.security.RSAwithAnyMD
 * @see com.dstc.security.provider.RSAParameters
 * @see com.dstc.security.provider.RSAPublicKey
 *
 * @version 0.98, 98/07/01
 * @author Ming Yung
 */
public class RSAPrivateKey extends Sequence
  implements PrivateKey, java.security.interfaces.RSAPrivateKey
{
  private BigInteger modulus, publicExponent, privateExponent, p, q;
  private static BigInteger one = BigInteger.valueOf (1);

  //Constructs a key from key data
  protected RSAPrivateKey (BigInteger modulus, BigInteger privateExponent) 
  {
    this.modulus = modulus;
    this.privateExponent = privateExponent;
  }

  //Constructs a key from key data
  protected RSAPrivateKey (BigInteger modulus, BigInteger publicExponent,
                        BigInteger privateExponent, BigInteger p,
                        BigInteger q) 
  {
    this.addComponent(new com.dstc.security.asn1.Integer(
      BigInteger.valueOf(0)));

    this.modulus = modulus;
    this.addComponent(new com.dstc.security.asn1.Integer(modulus));

    this.publicExponent = publicExponent;
    this.addComponent(new com.dstc.security.asn1.Integer(publicExponent));

    this.privateExponent = privateExponent;
    this.addComponent(new com.dstc.security.asn1.Integer(privateExponent));

    this.p = p;
    this.addComponent(new com.dstc.security.asn1.Integer(p));

    this.q = q;
    this.addComponent(new com.dstc.security.asn1.Integer(q));

    this.addComponent(new com.dstc.security.asn1.Integer(privateExponent.mod
                                          (p.subtract(one))));

    this.addComponent(new com.dstc.security.asn1.Integer(privateExponent.mod
                                          (q.subtract(one))));

    this.addComponent(new com.dstc.security.asn1.Integer(q.modInverse(p)));
  }

  ///Returns the algorithm "RSA"
  public String getAlgorithm () 
  {
    return "RSA";
  }

  ///Returns the format "PKCS#8"
  public String getFormat () 
  {
    return "PKCS#8";
  }

  ///Returns the modulus for this key
  public BigInteger getModulus () 
  {
    return modulus;
  }

  ///Returns the private exponent for this key
  public BigInteger getPrivateExponent () 
  {
    return privateExponent;
  }

  ///Returns a PKCS8 encoding for this key
  public byte[] getEncoded () 
  {
    try
    {
      //Get Encoded private key
      byte priv[] = (new PrivateKeyInfo(new AlgorithmId(OID.rsaEncryption,
        null), super.encode())).encode();

      return priv;
    }
    catch (Exception e)
    {
      System.out.println(e.toString());
      return null;
    }
  }

  /**
   * Constructs a private key from a DER encoding
   *       RSAPrivateKey ::= SEQUENCE {
   *         version Version,
   *         modulus INTEGER, -- n
   *         publicExponent INTEGER, -- e
   *         privateExponent INTEGER, -- d
   *         prime1 INTEGER, -- p
   *         prime2 INTEGER, -- q
   *         exponent1 INTEGER, -- d mod (p-1)
   *         exponent2 INTEGER, -- d mod (q-1)
   *         coefficient INTEGER -- (inverse of q) mod p }
   *  for this key
   */
  protected RSAPrivateKey(byte encoded[]) throws Asn1Exception
  {
    doDecode(encoded);
    this.modulus = ((com.dstc.security.asn1.Integer)components.
                     elementAt(1)).getBigInteger();
    this.publicExponent = ((com.dstc.security.asn1.Integer)components.
                     elementAt(2)).getBigInteger();
    this.privateExponent = ((com.dstc.security.asn1.Integer)components.
                     elementAt(3)).getBigInteger();
    this.p = ((com.dstc.security.asn1.Integer)components.
               elementAt(4)).getBigInteger();
    this.q = ((com.dstc.security.asn1.Integer)components.
               elementAt(5)).getBigInteger();
  }
}
