package iaik.pkcs.pkcs11;

import iaik.pkcs.pkcs11.objects.Key;
import iaik.pkcs.pkcs11.objects.KeyPair;
import iaik.pkcs.pkcs11.objects.Object;
import iaik.pkcs.pkcs11.objects.PrivateKey;
import iaik.pkcs.pkcs11.objects.PublicKey;
import iaik.pkcs.pkcs11.objects.SecretKey;
import iaik.pkcs.pkcs11.parameters.Parameters;
import iaik.pkcs.pkcs11.parameters.SSL3KeyMaterialParameters;
import iaik.pkcs.pkcs11.parameters.SSL3MasterKeyDeriveParameters;
import iaik.pkcs.pkcs11.wrapper.CK_ATTRIBUTE;
import iaik.pkcs.pkcs11.wrapper.CK_MECHANISM;
import iaik.pkcs.pkcs11.wrapper.CK_SESSION_INFO;
import iaik.pkcs.pkcs11.wrapper.CK_SSL3_KEY_MAT_PARAMS;
import iaik.pkcs.pkcs11.wrapper.CK_SSL3_MASTER_KEY_DERIVE_PARAMS;
import iaik.pkcs.pkcs11.wrapper.Constants;
import iaik.pkcs.pkcs11.wrapper.Functions;
import iaik.pkcs.pkcs11.wrapper.PKCS11;
import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;

import java.util.Vector;

/**
 * Session objects are used to perform cryptographic operations on a token. The
 * application gets a Session object by calling openSession on a certain Token
 * object. Having the session object, the application may log-in the user, if
 * required.
 * 
 * <pre>
 * <code>
 *   TokenInfo tokenInfo = token.getTokenInfo();
 *   // check, if log-in of the user is required at all
 *   if (tokenInfo.isLoginRequired()) {
 *     // check, if the token has own means to authenticate the user; e.g. a PIN-pad on the reader
 *     if (tokenInfo.isProtectedAuthenticationPath()) {
 *       System.out.println("Please enter the user PIN at the PIN-pad of your reader.");
 *       session.login(Session.UserType.USER, null); // the token prompts the PIN by other means; e.g. PIN-pad
 *     } else {
 *       System.out.print("Enter user-PIN and press [return key]: ");
 *       System.out.flush();
 *       BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
 *       String userPINString = input.readLine();
 *       session.login(Session.UserType.USER, userPINString.toCharArray());
 *     }
 *   }
 * </code>
 * </pre>
 * 
 * With this session object the application can search for token objects and
 * perform a cryptographic operation. For example, to find private RSA keys that
 * the application can use for signing, you can write:
 * 
 * <pre>
 * <code>
 *   RSAPrivateKey privateSignatureKeyTemplate = new RSAPrivateKey();
 *   privateSignatureKeyTemplate.getSign().setBooleanValue(Boolean.TRUE);
 * 
 *   session.findObjectsInit(privateSignatureKeyTemplate);
 *   Object[] privateSignatureKeys;
 * 
 *   List signatureKeyList = new Vector(4);
 *   while ((privateSignatureKeys = session.findObjects(1)).length > 0) {
 *     signatureKeyList.add(privateSignatureKeys[0]);
 *   }
 *   session.findObjectsFinal();
 * </code>
 * </pre>
 * 
 * Having chosen one of this keys, the application can create a signature value
 * using it.
 * 
 * <pre>
 * <code>
 *   // e.g. the encoded digest info object that contains an identifier of the
 *   // hash algorithm and the hash value
 *   byte[] toBeSigned;
 * 
 *   // toBeSigned = ... assign value
 * 
 *   RSAPrivateKey selectedSignatureKey;
 * 
 *   // selectedSignatureKey = ... assign one of the available signature keys
 * 
 *   // initialize for signing
 *   session.signInit(Mechanism.RSA_PKCS, selectedSignatureKey);
 * 
 *   // sign the data to be signed
 *   byte[] signatureValue = session.sign(toBeSigned);
 * </code>
 * </pre>
 * 
 * If the application does not need the session any longer, it should close the
 * session.
 * 
 * <pre>
 * <code>
 *   session.closeSession();
 * </code>
 * </pre>
 * 
 * @see iaik.pkcs.pkcs11.objects.Object
 * @see iaik.pkcs.pkcs11.parameters.Parameters
 * @see iaik.pkcs.pkcs11.Session
 * @see iaik.pkcs.pkcs11.SessionInfo
 * @author <a href="mailto:Karl.Scheibelhofer@iaik.at"> Karl Scheibelhofer </a>
 * @version 1.0
 * @invariants (pkcs11Module_ <> null)
 */
public class Session {

	/**
	 * This interface defines the different user tpyes of PKCS#11.
	 * 
	 * @author <a href="mailto:Karl.Scheibelhofer@iaik.at"> Karl Scheibelhofer
	 *         </a>
	 * @version 1.0
	 * @invariants
	 */
	public interface UserType {

		/**
		 * This constant stands for the security officer.
		 */
		public static boolean SO = false;

		/**
		 * Thsi constant stands for the user (token owner).
		 */
		public static boolean USER = true;

	}

	/**
	 * A reference to the underlying PKCS#11 module to perform the operations.
	 */
	protected Module module_;

	/**
	 * A reference to the underlying PKCS#11 module to perform the operations.
	 */
	protected PKCS11 pkcs11Module_;

	/**
	 * The session handle to perform the operations with.
	 */
	protected long sessionHandle_;

	/**
	 * The token to perform the operations on.
	 */
	protected Token token_;

	/**
	 * Constructor taking the token and the sesion handle.
	 * 
	 * @param token
	 *          The token this session operates with.
	 * @param sessionHandle
	 *          The session handle to perform the operations with.
	 * @preconditions (token <> null)
	 * @postconditions
	 */
	protected Session(Token token, long sessionHandle) {
		if (token == null) {
			throw new NullPointerException("Argument \"token\" must not be null.");
		}
		token_ = token;
		module_ = token_.getSlot().getModule();
		pkcs11Module_ = module_.getPKCS11Module();
		sessionHandle_ = sessionHandle;
	}

	/**
	 * Initializes the user-PIN. Can only be called from a read-write security
	 * officer session. May be used to set a new user-PIN if the user-PIN is
	 * locked.
	 * 
	 * @param pin
	 *          The new user-PIN. This parameter may be null, if the token has a
	 *          protected authentication path. Refer to the PKCS#11 standard for
	 *          details.
	 * @exception TokenException
	 *              If the session has not the right to set the PIN of if the
	 *              operation fails for some other reason.
	 * @preconditions
	 * @postconditions
	 */
	public void initPIN(char[] pin)
	    throws TokenException
	{
		pkcs11Module_.C_InitPIN(sessionHandle_, pin);
	}

	/**
	 * Set the user-PIN to a new value. Can only be called from a read-write
	 * sessions.
	 * 
	 * @param oldPin
	 *          The old (current) user-PIN.
	 * @param newPin
	 *          The new value for the user-PIN.
	 * @exception TokenException
	 *              If setting the new PIN fails.
	 * @preconditions
	 * @postconditions
	 */
	public void setPIN(char[] oldPin, char[] newPin)
	    throws TokenException
	{
		pkcs11Module_.C_SetPIN(sessionHandle_, oldPin, newPin);
	}

	/**
	 * Closes this session.
	 * 
	 * @exception TokenException
	 *              If closing the session failed.
	 * @preconditions
	 * @postconditions
	 */
	public void closeSession()
	    throws TokenException
	{
		pkcs11Module_.C_CloseSession(sessionHandle_);
	}

	/**
	 * Compares the sessionHandle and token_ of this object with the other object.
	 * Returns only true, if those are equal in both objects.
	 * 
	 * @param otherObject
	 *          The other Session object.
	 * @return True, if other is an instance of Token and the session handles and
	 *         tokens of both objects are equal. False, otherwise.
	 * @preconditions
	 * @postconditions
	 */
	public boolean equals(java.lang.Object otherObject) {
		boolean equal = false;

		if (otherObject instanceof Session) {
			Session other = (Session) otherObject;
			equal = (this == other)
			    || ((this.sessionHandle_ == other.sessionHandle_) && this.token_
			        .equals(other.token_));
		}

		return equal;
	}

	/**
	 * The overriding of this method should ensure that the objects of this class
	 * work correctly in a hashtable.
	 * 
	 * @return The hash code of this object. Gained from the sessionHandle.
	 * @preconditions
	 * @postconditions
	 */
	public int hashCode() {
		return (int) sessionHandle_;
	}

	/**
	 * Get the handle of this session.
	 * 
	 * @return The handle of this session.
	 * @preconditions
	 * @postconditions
	 */
	public long getSessionHandle() {
		return sessionHandle_;
	}

	/**
	 * Get information about this session.
	 * 
	 * @return An object providing information about this session.
	 * @exception TokenException
	 *              If getting the information failed.
	 * @preconditions
	 * @postconditions (result <> null)
	 */
	public SessionInfo getSessionInfo()
	    throws TokenException
	{
		CK_SESSION_INFO ckSessionInfo = pkcs11Module_.C_GetSessionInfo(sessionHandle_);

		return new SessionInfo(ckSessionInfo);
	}

	/**
	 * Get the Module which this Session object operates with.
	 * 
	 * @return The module of this session.
	 * @preconditions
	 * @postconditions
	 */
	public Module getModule() {
		return module_;
	}

	/**
	 * Get the token that created this Session object.
	 * 
	 * @return The token of this session.
	 * @preconditions
	 * @postconditions
	 */
	public Token getToken() {
		return token_;
	}

	/**
	 * Get the current operation state. This state can be used later to restore
	 * the operation to exactly this state.
	 * 
	 * @return The current operation state as a byte array.
	 * @exception TokenException
	 *              If saving the state fails or is not possible.
	 * @see #setOperationState(byte[],Key,Key)
	 * @preconditions
	 * @postconditions (result <> null)
	 */
	public byte[] getOperationState()
	    throws TokenException
	{
		return pkcs11Module_.C_GetOperationState(sessionHandle_);
	}

	/**
	 * Sets the operation state of this session to a previously saved one. This
	 * method may need the key used during the saved operation to continue,
	 * because it may not be possible to save a key into the state's byte array.
	 * Refer to the PKCS#11 standard for details on this function.
	 * 
	 * @param operationState
	 *          The previously saved state as returned by getOperationState().
	 * @param encryptionKey
	 *          A encryption or decryption key, if a encryption or decryption
	 *          operation was saved which should be continued, but the keys could
	 *          not be saved.
	 * @param authenticationKey
	 *          A signing, verification of MAC key, if a signing, verification or
	 *          MAC operation needs to be restored that could not save the key.
	 * @exception TokenException
	 *              If restoring the state fails.
	 * @see #getOperationState()
	 * @preconditions
	 * @postconditions
	 */
	public void setOperationState(byte[] operationState,
	                              Key encryptionKey,
	                              Key authenticationKey)
	    throws TokenException
	{
		pkcs11Module_.C_SetOperationState(sessionHandle_, operationState,
		    encryptionKey.getObjectHandle(), authenticationKey.getObjectHandle());
	}

	/**
	 * Logs in the user or the security officer to the session. Notice that all
	 * sessions of a token have the same login state; i.e. if you login the user
	 * to one session all other open sessions of this token get user rights.
	 * 
	 * @param userType
	 *          UserType.SO for the security officer or UserType.USER to login the
	 *          user.
	 * @param pin
	 *          The PIN. The security officer-PIN or the user-PIN depending on the
	 *          userType parameter.
	 * @exception TokenException
	 *              If login fails.
	 * @preconditions
	 * @postconditions
	 */
	public void login(boolean userType, char[] pin)
	    throws TokenException
	{
		long lUserType = (userType == UserType.SO) ? PKCS11Constants.CKU_SO
		    : PKCS11Constants.CKU_USER;
		pkcs11Module_.C_Login(sessionHandle_, lUserType, pin);
	}

	/**
	 * Logs out this session.
	 * 
	 * @exception TokenException
	 *              If logging out the session fails.
	 * @preconditions
	 * @postconditions
	 */
	public void logout()
	    throws TokenException
	{
		pkcs11Module_.C_Logout(sessionHandle_);
	}

	/**
	 * Create a new object on the token (or in the session). The application must
	 * provide a template that holds enough information to create a certain
	 * object. For instance, if the application wants to create a new DES key
	 * object it creates a new instance of the DESSecretKey class to serve as a
	 * template. The application must set all attributes of this new object which
	 * are required for the creation of such an object on the token. Then it
	 * passes this DESSecretKey object to this method to create the object on the
	 * token. Example: <code>
	 *   DESSecretKey desKeyTemplate = new DESSecretKey();
	 *   // the key type is set by the DESSecretKey's constructor, so you need not do it
	 *   desKeyTemplate.setValue(myDesKeyValueAs8BytesLongByteArray);
	 *   desKeyTemplate.setToken(Boolean.TRUE);
	 *   desKeyTemplate.setPrivate(Boolean.TRUE);
	 *   desKeyTemplate.setEncrypt(Boolean.TRUE);
	 *   desKeyTemplate.setDecrypt(Boolean.TRUE);
	 *   ...
	 *   DESSecretKey theCreatedDESKeyObject = (DESSecretKey) userSession.createObject(desKeyTemplate);
	 * </code> Refer to the PKCS#11 standard to find out what attributes must be
	 * set for certain types of objects to create them on the token.
	 * 
	 * @param templateObject
	 *          The template object that holds all values that the new object on
	 *          the token should contain. (this is not a java.lang.Object!)
	 * @return A new PKCS#11 Object (this is not a java.lang.Object!) that serves
	 *         holds all the (readable) attributes of the object on the token. In
	 *         contrast to the templateObject, this object might have certain
	 *         attributes set to token-dependent default-values.
	 * @exception TokenException
	 *              If the creation of the new object fails. If it fails, the no
	 *              new object was created on the token.
	 * @preconditions (templateObject <> null)
	 * @postconditions (result <> null)
	 */
	public Object createObject(Object templateObject)
	    throws TokenException
	{
		CK_ATTRIBUTE[] ckAttributes = Object.getSetAttributes(templateObject);
		long objectHandle = pkcs11Module_.C_CreateObject(sessionHandle_, ckAttributes);

		return Object.getInstance(this, objectHandle);
	}

	/**
	 * Copy an existing object. The source object and a template object are given.
	 * Any value set in the template object will override the corresponding value
	 * from the source object, when the new object ist created. See the PKCS#11
	 * standard for details.
	 * 
	 * @param sourceObject
	 *          The source object of the copy operation.
	 * @param templateObject
	 *          A template object which's attribute values are used for the new
	 *          object; i.e. they have higher priority than the attribute values
	 *          from the source object. May be null; in that case the new object
	 *          is just a one-to-one copy of the sourceObject.
	 * @return The new object that is created by copying the source object and
	 *         setting attributes to the values given by the templateObject.
	 * @exception TokenException
	 *              If copying the object fails for some reason.
	 * @preconditions (sourceObject <> null)
	 * @postconditions
	 */
	public Object copyObject(Object sourceObject, Object templateObject)
	    throws TokenException
	{
		long sourceObjectHandle = sourceObject.getObjectHandle();
		CK_ATTRIBUTE[] ckAttributes = Object.getSetAttributes(templateObject);
		long newObjectHandle = pkcs11Module_.C_CopyObject(sessionHandle_, sourceObjectHandle,
		    ckAttributes);

		return Object.getInstance(this, newObjectHandle);
	}

	/**
	 * Gets all present attributes of the given template object an writes them to
	 * the object to update on the token (or in the session). Both parameters may
	 * refer to the same Java object. This is possible, because this method only
	 * needs the object handle of the objectToUpdate, and gets the attributes to
	 * set from the template. This means, an application can get the object using
	 * createObject of findObject, then modify attributes of this Java object and
	 * then call this method passing this object as both parameters. This will
	 * update the object on the token to the values as modified in the Java
	 * object.
	 * 
	 * @param objectToUpdate
	 *          The attributes of this object get updated.
	 * @param templateObject
	 *          This methods gets all present attributes of this template object
	 *          and set this attributes at the objectToUpdate.
	 * @exception TokenException
	 *              If updateing the attributes fails. All or no attributes are
	 *              updated.
	 * @preconditions (objectToUpdate <> null) and (template <> null)
	 * @postconditions
	 */
	public void setAttributeValues(Object objectToUpdate, Object templateObject)
	    throws TokenException
	{
		long objectToUpdateHandle = objectToUpdate.getObjectHandle();
		CK_ATTRIBUTE[] ckAttributesTemplates = Object.getSetAttributes(templateObject);
		pkcs11Module_.C_SetAttributeValue(sessionHandle_, objectToUpdateHandle,
		    ckAttributesTemplates);
	}

	/**
	 * Reads all the attributes of the given Object from the token and returns a
	 * new Object that contains all these attributes. The given objectToRead and
	 * the returned Object are different Java objects. This method just uses the
	 * object handle of the given object, it does not modify anything in this
	 * object.
	 * 
	 * @param objectToRead
	 *          The object to newly read from the token.
	 * @return A new Object holding all attributes that this method just read from
	 *         the token.
	 * @exception TokenException
	 *              If reading the attributes fails.
	 * @preconditions (objectToRead <> null)
	 * @postconditions (result <> null)
	 */
	public Object getAttributeValues(Object objectToRead)
	    throws TokenException
	{
		long objectHandle = objectToRead.getObjectHandle();

		return Object.getInstance(this, objectHandle);
	}

	/**
	 * Destroy a certain object on the token (or in the session). Give the object
	 * that you want to destroy. This method uses only the internal object handle
	 * of the given object to identify the object.
	 * 
	 * @param object
	 *          The object that should be destroyed.
	 * @exception TokenException
	 *              If the object could not be destroyed.
	 * @preconditions (object <> null)
	 * @postconditions
	 */
	public void destroyObject(Object object)
	    throws TokenException
	{
		long objectHandle = object.getObjectHandle();
		pkcs11Module_.C_DestroyObject(sessionHandle_, objectHandle);
	}

	/**
	 * Get the size of the specified object in bytes. This size specifies how much
	 * memory the object takes up on the token.
	 * 
	 * @param object
	 *          The object to get the size for.
	 * @return The object's size bytes.
	 * @exception TokenException
	 *              If determining the size fails.
	 * @preconditions (object <> null)
	 * @postconditions
	 */
	public long getObjectSize(Object object)
	    throws TokenException
	{
		long objectHandle = object.getObjectHandle();
		return pkcs11Module_.C_GetObjectSize(sessionHandle_, objectHandle);
	}

	/**
	 * Initializes a find operations that provides means to find objects by
	 * passing a template object. This method get all set attributes of the
	 * template object ans searches for all objects on the token that match with
	 * these attributes.
	 * 
	 * @param templateObject
	 *          The object that serves as a template for searching. If this object
	 *          is null, the find operation will find all objects that this
	 *          session can see. Notice, that only a user session will see private
	 *          objects.
	 * @exception TokenException
	 *              If initializing the find operation fails.
	 * @preconditions
	 * @postconditions
	 */
	public void findObjectsInit(Object templateObject)
	    throws TokenException
	{
		CK_ATTRIBUTE[] ckAttributes = Object.getSetAttributes(templateObject);
		pkcs11Module_.C_FindObjectsInit(sessionHandle_, ckAttributes);
	}

	/**
	 * Finds objects that match the template object passed to findObjectsInit. The
	 * application must call findObjectsInit before calling this method. With
	 * maxObjectCount the application can specifay how many objects to return at
	 * once; i.e. the application can get all found objects by susequent calls to
	 * this method like maxObjectCount(1) until it receives an empty array (this
	 * method never returns null!).
	 * 
	 * @param maxObjectCount
	 *          Specifies how many objects to return with this call.
	 * @return An array of found objects. The maximum size of this array is
	 *         maxObjectCount, the minimum length is 0. Never returns null.
	 * @exception TokenException
	 *              A plain TokenException if something during PKCS11 FindObject 
	 *              went wrong, a TokenException with a nested TokenException if 
	 *              the Exception is raised during object parsing.
	 * @preconditions
	 * @postconditions (result <> null)
	 */
	public Object[] findObjects(int maxObjectCount)
	    throws TokenException
	{
		Vector foundObjects = new Vector();
		long[] objectHandles = pkcs11Module_.C_FindObjects(sessionHandle_, maxObjectCount);

		try {
			for (int i = 0; i < objectHandles.length; i++) {
				Object object = Object.getInstance(this, objectHandles[i]);
				foundObjects.addElement(object);
			}
			Object[] objectArray = new Object[foundObjects.size()];
			foundObjects.copyInto(objectArray);

			return objectArray;
		} catch (TokenException e) {
			// encapsulate exception to signal a cause other than C_FindObjects
			throw new TokenException(e);
		}
	}

	/**
	 * Finalizes a find operation. The application must call this method to
	 * finalize a find operation before attempting to start any other operation.
	 * 
	 * @exception TokenException
	 *              If finalizing the current find operation was not possible.
	 * @preconditions
	 * @postconditions
	 */
	public void findObjectsFinal()
	    throws TokenException
	{
		pkcs11Module_.C_FindObjectsFinal(sessionHandle_);
	}

	/**
	 * Initializes a new encryption operation. The application must call this
	 * method before calling any other encrypt* operation. Before initializing a
	 * new operation, any currently pending operation must be finalized using the
	 * appropriate *Final method (e.g. digestFinal()). There are exceptions for
	 * dual-function operations. This method requires the mechansim to use for
	 * encrpytion and the key for this oepration. The key must have set its
	 * encryption flag. For the mechanism the application may use a constant
	 * defined in the Mechanism class. Notice that the key and the mechanism must
	 * be compatible; i.e. you cannot use a DES key with the RSA mechanism.
	 * 
	 * @param mechanism
	 *          The mechanism to use; e.g. Mechanism.DES_CBC.
	 * @param key
	 *          The decryption key to use.
	 * @exception TokenException
	 *              If initializing this operation failed.
	 * @preconditions (mechansim <> null) and (key <> null)
	 * @postconditions
	 */
	public void encryptInit(Mechanism mechanism, Key key)
	    throws TokenException
	{
		CK_MECHANISM ckMechanism = new CK_MECHANISM();
		ckMechanism.mechanism = mechanism.getMechanismCode();
		Parameters parameters = mechanism.getParameters();
		ckMechanism.pParameter = (parameters != null) ? parameters.getPKCS11ParamsObject()
		    : null;

		pkcs11Module_.C_EncryptInit(sessionHandle_, ckMechanism, key.getObjectHandle());
	}

	/**
	 * Encrypts the given data with the key and mechansim given to the encryptInit
	 * method. This method finalizes the current encryption operation; i.e. the
	 * application need (and should) not call encryptFinal() after this call. For
	 * encrypting multiple pices of data use encryptUpdate and encryptFinal.
	 * 
	 * @param data
	 *          The data to encrpyt.
	 * @return The encrpyted data.
	 * @exception TokenException
	 *              If encrypting failed.
	 * @preconditions (data <> null)
	 * @postconditions (result <> null)
	 */
	public byte[] encrypt(byte[] data)
	    throws TokenException
	{
		return pkcs11Module_.C_Encrypt(sessionHandle_, data);
	}

	/**
	 * This method can be used to encrypt multiple pieces of data; e.g.
	 * buffer-size pieces when reading the data from a stream. Encrypts the given
	 * data with the key and mechansim given to the encryptInit method. The
	 * application must call encryptFinal to get the final result of the
	 * encryption after feeding in all data using this method.
	 * 
	 * @param part
	 *          The piece of data to encrpt.
	 * @return The intermediate encryption result. May not be available. To get
	 *         the final result call encryptFinal.
	 * @exception TokenException
	 *              If encrypting the data failed.
	 * @preconditions (part <> null)
	 * @postconditions
	 */
	public byte[] encryptUpdate(byte[] part)
	    throws TokenException
	{
		return pkcs11Module_.C_EncryptUpdate(sessionHandle_, part);
	}

	/**
	 * This method finalizes an encrpytion operation and returns the final result.
	 * Use this method, if you fed in the data using encryptUpdate. If you used
	 * the encrypt(byte[]) method, you need not (and shall not) call this method,
	 * because encrypt(byte[]) finalizes the encryption itself.
	 * 
	 * @return The final result of the encryption; i.e. the encrypted data.
	 * @exception TokenException
	 *              If calculating the final result failed.
	 * @preconditions
	 * @postconditions (result <> null)
	 */
	public byte[] encryptFinal()
	    throws TokenException
	{
		return pkcs11Module_.C_EncryptFinal(sessionHandle_);
	}

	/**
	 * Initializes a new decryption operation. The application must call this
	 * method before calling any other decrypt* operation. Before initializing a
	 * new operation, any currently pending operation must be finalized using the
	 * appropriate *Final method (e.g. digestFinal()). There are exceptions for
	 * dual-function operations. This method requires the mechansim to use for
	 * decrpytion and the key for this oepration. The key must have set its
	 * decryption flag. For the mechanism the application may use a constant
	 * defined in the Mechanism class. Notice that the key and the mechanism must
	 * be compatible; i.e. you cannot use a DES key with the RSA mechanism.
	 * 
	 * @param mechanism
	 *          The mechanism to use; e.g. Mechanism.DES_CBC.
	 * @param key
	 *          The decryption key to use.
	 * @exception TokenException
	 *              If initializing this operation failed.
	 * @preconditions (mechansim <> null) and (key <> null)
	 * @postconditions
	 */
	public void decryptInit(Mechanism mechanism, Key key)
	    throws TokenException
	{
		CK_MECHANISM ckMechanism = new CK_MECHANISM();
		ckMechanism.mechanism = mechanism.getMechanismCode();
		Parameters parameters = mechanism.getParameters();
		ckMechanism.pParameter = (parameters != null) ? parameters.getPKCS11ParamsObject()
		    : null;

		pkcs11Module_.C_DecryptInit(sessionHandle_, ckMechanism, key.getObjectHandle());
	}

	/**
	 * Decrypts the given data with the key and mechansim given to the decryptInit
	 * method. This method finalizes the current decryption operation; i.e. the
	 * application need (and should) not call decryptFinal() after this call. For
	 * decrypting multiple pices of data use decryptUpdate and decryptFinal.
	 * 
	 * @param data
	 *          The data to decrpyt.
	 * @return The decrpyted data.
	 * @exception TokenException
	 *              If decrypting failed.
	 * @preconditions (data <> null)
	 * @postconditions (result <> null)
	 */
	public byte[] decrypt(byte[] data)
	    throws TokenException
	{
		return pkcs11Module_.C_Decrypt(sessionHandle_, data);
	}

	/**
	 * This method can be used to decrypt multiple pieces of data; e.g.
	 * buffer-size pieces when reading the data from a stream. Decrypts the given
	 * data with the key and mechansim given to the decryptInit method. The
	 * application must call decryptFinal to get the final result of the
	 * encryption after feeding in all data using this method.
	 * 
	 * @param encryptedPart
	 *          The piece of data to decrpt.
	 * @return The intermediate decryption result. May not be available. To get
	 *         the final result call decryptFinal.
	 * @exception TokenException
	 *              If decrypting the data failed.
	 * @preconditions (encryptedPart <> null)
	 * @postconditions
	 */
	public byte[] decryptUpdate(byte[] encryptedPart)
	    throws TokenException
	{
		return pkcs11Module_.C_DecryptUpdate(sessionHandle_, encryptedPart);
	}

	/**
	 * This method finalizes a decrpytion operation and returns the final result.
	 * Use this method, if you fed in the data using decryptUpdate. If you used
	 * the decrypt(byte[]) method, you need not (and shall not) call this method,
	 * because decrypt(byte[]) finalizes the decryption itself.
	 * 
	 * @return The final result of the decryption; i.e. the decrypted data.
	 * @exception TokenException
	 *              If calculating the final result failed.
	 * @preconditions
	 * @postconditions (result <> null)
	 */
	public byte[] decryptFinal()
	    throws TokenException
	{
		return pkcs11Module_.C_DecryptFinal(sessionHandle_);
	}

	/**
	 * Initializes a new digesting operation. The application must call this
	 * method before calling any other digest* operation. Before initializing a
	 * new operation, any currently pending operation must be finalized using the
	 * appropriate *Final method (e.g. digestFinal()). There are exceptions for
	 * dual-function operations. This method requires the mechansim to use for
	 * digesting for this oepration. For the mechanism the application may use a
	 * constant defined in the Mechanism class.
	 * 
	 * @param mechanism
	 *          The mechanism to use; e.g. Mechanism.SHA_1.
	 * @exception TokenException
	 *              If initializing this operation failed.
	 * @preconditions (mechansim <> null)
	 * @postconditions
	 */
	public void digestInit(Mechanism mechanism)
	    throws TokenException
	{
		CK_MECHANISM ckMechanism = new CK_MECHANISM();
		ckMechanism.mechanism = mechanism.getMechanismCode();
		Parameters parameters = mechanism.getParameters();
		ckMechanism.pParameter = (parameters != null) ? parameters.getPKCS11ParamsObject()
		    : null;

		pkcs11Module_.C_DigestInit(sessionHandle_, ckMechanism);
	}

	/**
	 * Digests the given data with the mechansim given to the digestInit method.
	 * This method finalizes the current digesting operation; i.e. the application
	 * need (and should) not call digestFinal() after this call. For digesting
	 * multiple pices of data use digestUpdate and digestFinal.
	 * 
	 * @param data
	 *          The data to digest.
	 * @return The digested data.
	 * @exception TokenException
	 *              If digesting the data failed.
	 * @preconditions (data <> null)
	 * @postconditions (result <> null)
	 */
	public byte[] digest(byte[] data)
	    throws TokenException
	{
		return pkcs11Module_.C_Digest(sessionHandle_, data);
	}

	/**
	 * This method can be used to digest multiple pieces of data; e.g. buffer-size
	 * pieces when reading the data from a stream. Digests the given data with the
	 * mechansim given to the digestInit method. The application must call
	 * digestFinal to get the final result of the digesting after feeding in all
	 * data using this method.
	 * 
	 * @param part
	 *          The piece of data to digest.
	 * @exception TokenException
	 *              If digesting the data failed.
	 * @preconditions (part <> null)
	 * @postconditions
	 */
	public void digestUpdate(byte[] part)
	    throws TokenException
	{
		pkcs11Module_.C_DigestUpdate(sessionHandle_, part);
	}

	/**
	 * This method is similar to digestUpdate and can be combined with it during
	 * one digesting operation. This method digests the value of the given secret
	 * key.
	 * 
	 * @param key
	 *          The key to digest the value of.
	 * @exception TokenException
	 *              If digesting the key failed.
	 * @preconditions (key <> null)
	 * @postconditions
	 */
	public void digestKey(SecretKey key)
	    throws TokenException
	{
		pkcs11Module_.C_DigestKey(sessionHandle_, key.getObjectHandle());
	}

	/**
	 * This method finalizes a digesting operation and returns the final result.
	 * Use this method, if you fed in the data using digestUpdate and/or
	 * digestKey. If you used the digest(byte[]) method, you need not (and shall
	 * not) call this method, because digest(byte[]) finalizes the digesting
	 * itself.
	 * 
	 * @return The final result of the digesting; i.e. the message digest.
	 * @exception TokenException
	 *              If calculating the final message digest failed.
	 * @preconditions
	 * @postconditions (result <> null)
	 */
	public byte[] digestFinal()
	    throws TokenException
	{
		return pkcs11Module_.C_DigestFinal(sessionHandle_);
	}

	/**
	 * Initializes a new signing operation. Use it for signatures and MACs. The
	 * application must call this method before calling any other sign* operation.
	 * Before initializing a new operation, any currently pending operation must
	 * be finalized using the appropriate *Final method (e.g. digestFinal()).
	 * There are exceptions for dual-function operations. This method requires the
	 * mechansim to use for signing and the key for this oepration. The key must
	 * have set its sign flag. For the mechanism the application may use a
	 * constant defined in the Mechanism class. Notice that the key and the
	 * mechanism must be compatible; i.e. you cannot use a DES key with the RSA
	 * mechanism.
	 * 
	 * @param mechanism
	 *          The mechanism to use; e.g. Mechanism.RSA_PKCS.
	 * @param key
	 *          The signing key to use.
	 * @exception TokenException
	 *              If initializing this operation failed.
	 * @preconditions (mechansim <> null) and (key <> null)
	 * @postconditions
	 */
	public void signInit(Mechanism mechanism, Key key)
	    throws TokenException
	{
		CK_MECHANISM ckMechanism = new CK_MECHANISM();
		ckMechanism.mechanism = mechanism.getMechanismCode();
		Parameters parameters = mechanism.getParameters();
		ckMechanism.pParameter = (parameters != null) ? parameters.getPKCS11ParamsObject()
		    : null;

		pkcs11Module_.C_SignInit(sessionHandle_, ckMechanism, key.getObjectHandle());
	}

	/**
	 * Signs the given data with the key and mechansim given to the signInit
	 * method. This method finalizes the current signing operation; i.e. the
	 * application need (and should) not call signFinal() after this call. For
	 * signing multiple pices of data use signUpdate and signFinal.
	 * 
	 * @param data
	 *          The data to sign.
	 * @return The signed data.
	 * @exception TokenException
	 *              If signing the data failed.
	 * @preconditions (data <> null)
	 * @postconditions (result <> null)
	 */
	public byte[] sign(byte[] data)
	    throws TokenException
	{
		return pkcs11Module_.C_Sign(sessionHandle_, data);
	}

	/**
	 * This method can be used to sign multiple pieces of data; e.g. buffer-size
	 * pieces when reading the data from a stream. Signs the given data with the
	 * mechansim given to the signInit method. The application must call signFinal
	 * to get the final result of the signing after feeding in all data using this
	 * method.
	 * 
	 * @param part
	 *          The piece of data to sign.
	 * @exception TokenException
	 *              If signing the data failed.
	 * @preconditions (part <> null)
	 * @postconditions
	 */
	public void signUpdate(byte[] part)
	    throws TokenException
	{
		pkcs11Module_.C_SignUpdate(sessionHandle_, part);
	}

	/**
	 * This method finalizes a signing operation and returns the final result. Use
	 * this method, if you fed in the data using signUpdate. If you used the
	 * sign(byte[]) method, you need not (and shall not) call this method, because
	 * sign(byte[]) finalizes the signing operation itself.
	 * 
	 * @return The final result of the signing operation; i.e. the signature
	 *         value.
	 * @exception TokenException
	 *              If calculating the final signature value failed.
	 * @preconditions
	 * @postconditions (result <> null)
	 */
	public byte[] signFinal()
	    throws TokenException
	{
		return pkcs11Module_.C_SignFinal(sessionHandle_);
	}

	/**
	 * Initializes a new signing operation for signing with recovery. The
	 * application must call this method before calling signRecover. Before
	 * initializing a new operation, any currently pending operation must be
	 * finalized using the appropriate *Final method (e.g. digestFinal()). There
	 * are exceptions for dual-function operations. This method requires the
	 * mechansim to use for signing and the key for this oepration. The key must
	 * have set its sign-recover flag. For the mechanism the application may use a
	 * constant defined in the Mechanism class. Notice that the key and the
	 * mechanism must be compatible; i.e. you cannot use a DES key with the RSA
	 * mechanism.
	 * 
	 * @param mechanism
	 *          The mechanism to use; e.g. Mechanism.RSA_9796.
	 * @param key
	 *          The signing key to use.
	 * @exception TokenException
	 *              If initializing this operation failed.
	 * @preconditions (mechansim <> null) and (key <> null)
	 * @postconditions
	 */
	public void signRecoverInit(Mechanism mechanism, Key key)
	    throws TokenException
	{
		CK_MECHANISM ckMechanism = new CK_MECHANISM();
		ckMechanism.mechanism = mechanism.getMechanismCode();
		Parameters parameters = mechanism.getParameters();
		ckMechanism.pParameter = (parameters != null) ? parameters.getPKCS11ParamsObject()
		    : null;

		pkcs11Module_.C_SignRecoverInit(sessionHandle_, ckMechanism, key.getObjectHandle());
	}

	/**
	 * Signs the given data with the key and mechansim given to the
	 * signRecoverInit method. This method finalizes the current sign-recover
	 * operation; there is no equivalent method to signUpdate for signing with
	 * recovery.
	 * 
	 * @param data
	 *          The data to sign.
	 * @return The signed data.
	 * @exception TokenException
	 *              If signing the data failed.
	 * @preconditions (data <> null)
	 * @postconditions (result <> null)
	 */
	public byte[] signRecover(byte[] data)
	    throws TokenException
	{
		return pkcs11Module_.C_SignRecover(sessionHandle_, data);
	}

	/**
	 * Initializes a new verification operation. You can use it for verifying
	 * signatures and MACs. The application must call this method before calling
	 * any other verify* operation. Before initializing a new operation, any
	 * currently pending operation must be finalized using the appropriate *Final
	 * method (e.g. digestFinal()). There are exceptions for dual-function
	 * operations. This method requires the mechansim to use for verification and
	 * the key for this oepration. The key must have set its verify flag. For the
	 * mechanism the application may use a constant defined in the Mechanism
	 * class. Notice that the key and the mechanism must be compatible; i.e. you
	 * cannot use a DES key with the RSA mechanism.
	 * 
	 * @param mechanism
	 *          The mechanism to use; e.g. Mechanism.RSA_PKCS.
	 * @param key
	 *          The verification key to use.
	 * @exception TokenException
	 *              If initializing this operation failed.
	 * @preconditions (mechansim <> null) and (key <> null)
	 * @postconditions
	 */
	public void verifyInit(Mechanism mechanism, Key key)
	    throws TokenException
	{
		CK_MECHANISM ckMechanism = new CK_MECHANISM();
		ckMechanism.mechanism = mechanism.getMechanismCode();
		Parameters parameters = mechanism.getParameters();
		ckMechanism.pParameter = (parameters != null) ? parameters.getPKCS11ParamsObject()
		    : null;

		pkcs11Module_.C_VerifyInit(sessionHandle_, ckMechanism, key.getObjectHandle());
	}

	/**
	 * Verifies the given signature against the given data with the key and
	 * mechansim given to the verifyInit method. This method finalizes the current
	 * verification operation; i.e. the application need (and should) not call
	 * verifyFinal() after this call. For verifying with multiple pices of data
	 * use verifyUpdate and verifyFinal. This method throws an exception, if the
	 * verification of the signature fails.
	 * 
	 * @param data
	 *          The data that was signed.
	 * @param signature
	 *          The signature or MAC to verify.
	 * @exception TokenException
	 *              If verifying the signature fails. This is also the case, if
	 *              the signature is forged.
	 * @preconditions (data <> null) and (signature <> null)
	 * @postconditions
	 */
	public void verify(byte[] data, byte[] signature)
	    throws TokenException
	{
		pkcs11Module_.C_Verify(sessionHandle_, data, signature);
	}

	/**
	 * This method can be used to verify a signature with multiple pieces of data;
	 * e.g. buffer-size pieces when reading the data from a stream. To verify the
	 * signature or MAC call verifyFinal after feeding in all data using this
	 * method.
	 * 
	 * @param part
	 *          The piece of data to verify against.
	 * @exception TokenException
	 *              If verifying (e.g. digesting) the data failed.
	 * @preconditions (part <> null)
	 * @postconditions
	 */
	public void verifyUpdate(byte[] part)
	    throws TokenException
	{
		pkcs11Module_.C_VerifyUpdate(sessionHandle_, part);
	}

	/**
	 * This method finalizes a verification operation. Use this method, if you fed
	 * in the data using verifyUpdate. If you used the verify(byte[]) method, you
	 * need not (and shall not) call this method, because verify(byte[]) finalizes
	 * the verification operation itself. If this method verified the signature
	 * successfully, it returns normally. If the verification of the signature
	 * fails, e.g. if the signature was forged or the data was modified, this
	 * method throws an exception.
	 * 
	 * @param signature
	 *          The signature value.
	 * @exception TokenException
	 *              If verifying the signature fails. This is also the case, if
	 *              the signature is forged.
	 * @preconditions
	 * @postconditions (result <> null)
	 */
	public void verifyFinal(byte[] signature)
	    throws TokenException
	{
		pkcs11Module_.C_VerifyFinal(sessionHandle_, signature);
	}

	/**
	 * Initializes a new verification operation for verification with data
	 * recovery. The application must call this method before calling
	 * verifyRecover. Before initializing a new operation, any currently pending
	 * operation must be finalized using the appropriate *Final method (e.g.
	 * digestFinal()). This method requires the mechansim to use for verification
	 * and the key for this oepration. The key must have set its verify-recover
	 * flag. For the mechanism the application may use a constant defined in the
	 * Mechanism class. Notice that the key and the mechanism must be compatible;
	 * i.e. you cannot use a DES key with the RSA mechanism.
	 * 
	 * @param mechanism
	 *          The mechanism to use; e.g. Mechanism.RSA_9796.
	 * @param key
	 *          The verification key to use.
	 * @exception TokenException
	 *              If initializing this operation failed.
	 * @preconditions (mechansim <> null) and (key <> null)
	 * @postconditions
	 */
	public void verifyRecoverInit(Mechanism mechanism, Key key)
	    throws TokenException
	{
		CK_MECHANISM ckMechanism = new CK_MECHANISM();
		ckMechanism.mechanism = mechanism.getMechanismCode();
		Parameters parameters = mechanism.getParameters();
		ckMechanism.pParameter = (parameters != null) ? parameters.getPKCS11ParamsObject()
		    : null;

		pkcs11Module_.C_VerifyRecoverInit(sessionHandle_, ckMechanism, key.getObjectHandle());
	}

	/**
	 * Signs the given data with the key and mechansim given to the
	 * signRecoverInit method. This method finalizes the current sign-recover
	 * operation; there is no equivalent method to signUpdate for signing with
	 * recovery.
	 * 
	 * @param signature
	 *          The data to sign.
	 * @return The signed data.
	 * @exception TokenException
	 *              If signing the data failed.
	 * @preconditions (data <> null)
	 * @postconditions (result <> null)
	 */
	public byte[] verifyRecover(byte[] signature)
	    throws TokenException
	{
		return pkcs11Module_.C_VerifyRecover(sessionHandle_, signature);
	}

	/**
	 * Dual-function. Continues a multipart dual digest and encryption operation.
	 * This method call can also be combined with calls to digestUpdate, digestKey
	 * and encryptUpdate. Call digestFinal and encryptFinal to get the final
	 * results.
	 * 
	 * @param part
	 *          The piece of data to digest and encrypt.
	 * @return The intermediate result of the encryption.
	 * @exception TokenException
	 *              If digesting or encrypting the data failed.
	 * @preconditions (part <> null)
	 * @postconditions
	 */
	public byte[] digestEncryptedUpdate(byte[] part)
	    throws TokenException
	{
		return pkcs11Module_.C_DigestEncryptUpdate(sessionHandle_, part);
	}

	/**
	 * Dual-function. Continues a multipart dual decrypt and digest operation.
	 * This method call can also be combined with calls to digestUpdate, digestKey
	 * and decryptUpdate. It is the recovered plaintext that gets digested in this
	 * method call, not the given encryptedPart. Call digestFinal and decryptFinal
	 * to get the final results.
	 * 
	 * @param part
	 *          The piece of data to decrypt and digest.
	 * @return The intermediate result of the decryption; the decrypted data.
	 * @exception TokenException
	 *              If decrypting or digesting the data failed.
	 * @preconditions (part <> null)
	 * @postconditions
	 */
	public byte[] decryptDigestUpdate(byte[] part)
	    throws TokenException
	{
		return pkcs11Module_.C_DecryptDigestUpdate(sessionHandle_, part);
	}

	/**
	 * Dual-function. Continues a multipart dual sign and encrypt operation. Calls
	 * to this method can also be combined with calls to signUpdate and
	 * encryptUpdate. Call signFinal and encryptFinal to get the final results.
	 * 
	 * @param part
	 *          The piece of data to sign and encrypt.
	 * @return The intermediate result of the encryption; the encrypted data.
	 * @exception TokenException
	 *              If signing or encrypting the data failed.
	 * @preconditions (part <> null)
	 * @postconditions
	 */
	public byte[] signEncryptUpdate(byte[] part)
	    throws TokenException
	{
		return pkcs11Module_.C_SignEncryptUpdate(sessionHandle_, part);
	}

	/**
	 * Dual-function. Continues a multipart dual decrypt and verify operation.
	 * This method call can also be combined with calls to decryptUpdate and
	 * verifyUpdate. It is the recovered plaintext that gets verified in this
	 * method call, not the given encryptedPart. Call decryptFinal and verifyFinal
	 * to get the final results.
	 * 
	 * @param encryptedPart
	 *          The piece of data to decrypt and verify.
	 * @return The intermediate result of the decryption; the decrypted data.
	 * @exception TokenException
	 *              If decrypting or verifying the data failed.
	 * @preconditions (encryptedPart <> null)
	 * @postconditions
	 */
	public byte[] decryptVerifyUpdate(byte[] encryptedPart)
	    throws TokenException
	{
		return pkcs11Module_.C_DecryptVerifyUpdate(sessionHandle_, encryptedPart);
	}

	/**
	 * Generate a new secret key or a set of domain parameters. It uses the set
	 * attributes of the template for setting the attributes of the new key
	 * object. As mechanism the application can use a constant of the Mechanism
	 * class.
	 * 
	 * @param mechanism
	 *          The mechanism to generate a key for; e.g. Mechanism.DES to
	 *          generate a DES key.
	 * @param template
	 *          The template for the new key or domain parameters; e.g. a
	 *          DESSecretKey object which has set certain attributes.
	 * @return The newly generated secret key or domain parameters.
	 * @exception TokenException
	 *              If generating a new secert key or domain parameters failed.
	 * @preconditions
	 * @postconditions (result instanceof SecretKey) or (result instanceof
	 *                 DomainParameters)
	 */
	public Object generateKey(Mechanism mechanism, Object template)
	    throws TokenException
	{
		CK_MECHANISM ckMechanism = new CK_MECHANISM();
		ckMechanism.mechanism = mechanism.getMechanismCode();
		Parameters parameters = mechanism.getParameters();
		ckMechanism.pParameter = (parameters != null) ? parameters.getPKCS11ParamsObject()
		    : null;
		CK_ATTRIBUTE[] ckAttributes = Object.getSetAttributes(template);

		long objectHandle = pkcs11Module_.C_GenerateKey(sessionHandle_, ckMechanism,
		    ckAttributes);

		return Object.getInstance(this, objectHandle);
	}

	/**
	 * Generate a new public key - private key key-pair and use the set attributes
	 * of the template objects for setting the attributes of the new public key
	 * and private key objects. As mechanism the application can use a constant of
	 * the Mechanism class.
	 * 
	 * @param mechanism
	 *          The mechanism to generate a key for; e.g. Mechanism.RSA to
	 *          generate a new RSA key-pair.
	 * @param publicKeyTemplate
	 *          The template for the new public key part; e.g. a RSAPublicKey
	 *          object which has set certain attributes (e.g. public exponent and
	 *          verify).
	 * @param privateKeyTemplate
	 *          The template for the new private key part; e.g. a RSAPrivateKey
	 *          object which has set certain attributes (e.g. sign and decrypt).
	 * @return The newly generated key-pair.
	 * @exception TokenException
	 *              If generating a new key-pair failed.
	 * @preconditions
	 * @postconditions
	 */
	public KeyPair generateKeyPair(Mechanism mechanism,
	                               Object publicKeyTemplate,
	                               Object privateKeyTemplate)
	    throws TokenException
	{
		CK_MECHANISM ckMechanism = new CK_MECHANISM();
		ckMechanism.mechanism = mechanism.getMechanismCode();
		Parameters parameters = mechanism.getParameters();
		ckMechanism.pParameter = (parameters != null) ? parameters.getPKCS11ParamsObject()
		    : null;
		CK_ATTRIBUTE[] ckPublicKeyAttributes = Object.getSetAttributes(publicKeyTemplate);
		CK_ATTRIBUTE[] ckPrivateKeyAttributes = Object.getSetAttributes(privateKeyTemplate);

		long[] objectHandles = pkcs11Module_.C_GenerateKeyPair(sessionHandle_, ckMechanism,
		    ckPublicKeyAttributes, ckPrivateKeyAttributes);

		PublicKey publicKey = (PublicKey) Object.getInstance(this, objectHandles[0]);
		PrivateKey privateKey = (PrivateKey) Object.getInstance(this, objectHandles[1]);

		return new KeyPair(publicKey, privateKey);
	}

	/**
	 * Wraps (encrypts) the given key with the wrapping key using the given
	 * mechanism.
	 * 
	 * @param mechanism
	 *          The mechanism to use for wrapping the key.
	 * @param wrappingKey
	 *          The key to use for wrapping (encrypting).
	 * @param key
	 *          The key to wrap (encrypt).
	 * @return The wrapped key as byte array.
	 * @exception TokenException
	 *              If wrapping the key failed.
	 * @preconditions (mechanism <> null) and (wrappingKey <> null) and (key <>
	 *                null)
	 * @postconditions (result <> null)
	 */
	public byte[] wrapKey(Mechanism mechanism, Key wrappingKey, Key key)
	    throws TokenException
	{
		CK_MECHANISM ckMechanism = new CK_MECHANISM();
		ckMechanism.mechanism = mechanism.getMechanismCode();
		Parameters parameters = mechanism.getParameters();
		ckMechanism.pParameter = (parameters != null) ? parameters.getPKCS11ParamsObject()
		    : null;

		return pkcs11Module_.C_WrapKey(sessionHandle_, ckMechanism,
		    wrappingKey.getObjectHandle(), key.getObjectHandle());
	}

	/**
	 * Unwraps (decrypts) the given encrypted key with the unwrapping key using
	 * the given mechanism. The application can also pass a template key to set
	 * certain attributes of the unwrapped key. This creates a key object after
	 * unwrapping the key and returns an object representing this key.
	 * 
	 * @param mechanism
	 *          The mechanism to use for unwrapping the key.
	 * @param unwrappingKey
	 *          The key to use for unwrapping (decrypting).
	 * @param wrappedKey
	 *          The encrypted key to unwrap (decrypt).
	 * @param keyTemplate
	 *          The template for creating the new key object.
	 * @return A key object representing the newly created key object.
	 * @exception TokenException
	 *              If unwrapping the key or creating a new key object failed.
	 * @preconditions (mechanism <> null) and (unwrappingKey <> null) and
	 *                (wrappedKey <> null)
	 * @postconditions (result <> null)
	 */
	public Key unwrapKey(Mechanism mechanism,
	                     Key unwrappingKey,
	                     byte[] wrappedKey,
	                     Object keyTemplate)
	    throws TokenException
	{
		CK_MECHANISM ckMechanism = new CK_MECHANISM();
		ckMechanism.mechanism = mechanism.getMechanismCode();
		Parameters parameters = mechanism.getParameters();
		ckMechanism.pParameter = (parameters != null) ? parameters.getPKCS11ParamsObject()
		    : null;
		CK_ATTRIBUTE[] ckAttributes = Object.getSetAttributes(keyTemplate);

		long objectHandle = pkcs11Module_.C_UnwrapKey(sessionHandle_, ckMechanism,
		    unwrappingKey.getObjectHandle(), wrappedKey, ckAttributes);

		return (Key) Object.getInstance(this, objectHandle);
	}

	/**
	 * Derives a new key from a specified base key unsing the given mechanism.
	 * After deriving a new key from the base key, a new key object is created and
	 * a representation of it is returned. The application can provide a template
	 * key to set certain attributes of the new key object.
	 * 
	 * @param mechanism
	 *          The mechanism to use for deriving the new key from the base key.
	 * @param baseKey
	 *          The key to use as base for derivation.
	 * @param template
	 *          The template for creating the new key object.
	 * @return A key object representing the newly derived (created) key object or
	 *         null, if the used mechanism uses other means to return its values;
	 *         e.g. the CKM_SSL3_KEY_AND_MAC_DERIVE mechanism.
	 * @exception TokenException
	 *              If deriving the key or creating a new key object failed.
	 * @preconditions (mechanism <> null) and (baseKey <> null)
	 * @postconditions
	 */
	public Key deriveKey(Mechanism mechanism, Key baseKey, Key template)
	    throws TokenException
	{
		Key derivedKey = null;

		CK_MECHANISM ckMechanism = new CK_MECHANISM();
		ckMechanism.mechanism = mechanism.getMechanismCode();
		Parameters parameters = mechanism.getParameters();
		ckMechanism.pParameter = (parameters != null) ? parameters.getPKCS11ParamsObject()
		    : null;
		CK_ATTRIBUTE[] ckAttributes = Object.getSetAttributes(template);

		long objectHandle = pkcs11Module_.C_DeriveKey(sessionHandle_, ckMechanism,
		    baseKey.getObjectHandle(), ckAttributes);

		/*
		 * for certain mechanisms we must copy back the returned values the the
		 * parameters object of the given mechanism
		 */
		if ((ckMechanism.mechanism == PKCS11Constants.CKM_SSL3_MASTER_KEY_DERIVE || ckMechanism.mechanism == PKCS11Constants.CKM_TLS_MASTER_KEY_DERIVE)
		    && (parameters instanceof SSL3MasterKeyDeriveParameters)) {
			/*
			 * The SSL3MasterKeyDeriveParameters object need special handling due to
			 * their deeper nesting of their data structure, which needs to be copied
			 * back to get all the results.
			 */
			// set the returned client version
			((SSL3MasterKeyDeriveParameters) parameters).getVersion().setPKCS11ParamsObject(
			    ((CK_SSL3_MASTER_KEY_DERIVE_PARAMS) (ckMechanism.pParameter)).pVersion);
			derivedKey = (Key) Object.getInstance(this, objectHandle);
		} else if ((ckMechanism.mechanism == PKCS11Constants.CKM_SSL3_KEY_AND_MAC_DERIVE || ckMechanism.mechanism == PKCS11Constants.CKM_TLS_KEY_AND_MAC_DERIVE)
		    && (parameters instanceof SSL3KeyMaterialParameters)) {
			/*
			 * The SSL3KeyMaterialParameters object need special handling due to their
			 * deeper nesting of their data structure, which needs to be copied back
			 * to get all the results.
			 */
			// set the returned secret keys and IVs
			((SSL3KeyMaterialParameters) parameters).getReturnedKeyMaterial()
			    .setPKCS11ParamsObject(
			        ((CK_SSL3_KEY_MAT_PARAMS) (ckMechanism.pParameter)).pReturnedKeyMaterial,
			        this);
			/*
			 * this mechanism returns its keys and values through the parameters
			 * object of the mechanism, but it does not return a key
			 */
			derivedKey = null;
		} else {
			derivedKey = (Key) Object.getInstance(this, objectHandle);
		}

		return derivedKey;
	}

	/**
	 * Mixes additional seeding material into the random number generator.
	 * 
	 * @param seed
	 *          The seed bytes to mix in.
	 * @exception TokenException
	 *              If mixing in the seed failed.
	 * @preconditions (seed <> null)
	 * @postconditions
	 */
	public void seedRandom(byte[] seed)
	    throws TokenException
	{
		pkcs11Module_.C_SeedRandom(sessionHandle_, seed);
	}

	/**
	 * Generates a certain number of random bytes.
	 * 
	 * @param numberOfBytesToGenerate
	 *          The number of random bytes to generate.
	 * @return An array of random bytes with length numberOfBytesToGenerate.
	 * @exception TokenException
	 *              If generating random bytes failed.
	 * @preconditions (numberOfBytesToGenerate >= 0)
	 * @postconditions (result <> null) and (result.length ==
	 *                 numberOfBytesToGenerate)
	 */
	public byte[] generateRandom(int numberOfBytesToGenerate)
	    throws TokenException
	{
		byte[] randomBytesBuffer = new byte[numberOfBytesToGenerate];
		pkcs11Module_.C_GenerateRandom(sessionHandle_, randomBytesBuffer); // fill
		                                                                   // the
		                                                                   // buffer
		                                                                   // with
		                                                                   // random
		                                                                   // bytes

		return randomBytesBuffer;
	}

	/**
	 * Legacy function that will normally throw an PKCS11Exception with the
	 * error-code PKCS11Constants.CKR_FUNCTION_NOT_PARALLEL.
	 * 
	 * @exception TokenException
	 *              Throws always an PKCS11Excption.
	 * @preconditions
	 * @postconditions
	 */
	public void getFunctionStatus()
	    throws TokenException
	{
		pkcs11Module_.C_GetFunctionStatus(sessionHandle_);
	}

	/**
	 * Legacy function that will normally throw an PKCS11Exception with the
	 * error-code PKCS11Constants.CKR_FUNCTION_NOT_PARALLEL.
	 * 
	 * @exception TokenException
	 *              Throws always an PKCS11Excption.
	 * @preconditions
	 * @postconditions
	 */
	public void cancelFunction()
	    throws TokenException
	{
		pkcs11Module_.C_CancelFunction(sessionHandle_);
	}

	/**
	 * Returns the string representation of this object.
	 * 
	 * @return the string representation of this object
	 */
	public String toString() {
		StringBuffer buffer = new StringBuffer();

		buffer.append("Session Handle: ");
		buffer.append("0x");
		buffer.append(Functions.toHexString(sessionHandle_));
		buffer.append(Constants.NEWLINE);

		buffer.append("Token: ");
		buffer.append(token_.toString());

		return buffer.toString();
	}

}
