/* Encrypt an unsigned byte array using a symmetric algorithm.
Copyright (c) 2003-2006 The Regents of the University of California.
All rights reserved.
Permission is hereby granted, without written agreement and without
license or royalty fees, to use, copy, modify, and distribute this
software and its documentation for any purpose, provided that the above
copyright notice and the following two paragraphs appear in all copies
of this software.
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
ENHANCEMENTS, OR MODIFICATIONS.
PT_COPYRIGHT_VERSION_2
COPYRIGHTENDKEY
*/
package ptolemy.actor.lib.security;
import java.io.ByteArrayOutputStream;
import javax.crypto.Cipher;
import ptolemy.actor.TypedIOPort;
import ptolemy.kernel.CompositeEntity;
import ptolemy.kernel.util.IllegalActionException;
import ptolemy.kernel.util.NameDuplicationException;
import ptolemy.kernel.util.Settable;
//////////////////////////////////////////////////////////////////////////
//// SymmetricEncryption
/**
Encrypt an unsigned byte array using a symmetric algorithm.
<p>In cryptography, a symmetric algorithm is an algorithm that uses
the same key for encryption and decryption. An asymmetric algorithm uses
two different keys: a public key and a private key. Sun's documentation
says that asymmetric algorithms are usually much slower than
symmetric algorithms. The initial default set of algorithms that
comes with the Sun JDK does not include an asymmetric encryption algorithm,
though other algorithms may be installed by the system administrator.
<p>This actor reads an unsigned byte array at the <i>input</i> port,
encrypts the data using the data from the <i>key</i> port and then
writes the unsigned byte array results to the <i>output</i> port.
<p>The <i>key</i> should be the same for both the
SymmetricDecryption actor and this actor. The <i>key</i> should not
be visible to users as the security of the encrypted message relies on
the secrecy of this key.
<p>The <i>algorithm</i> parameter determines which algorithm is used.
The algorithm specified must be symmetric. The mode and padding can also
be specified in the <i>mode</i> and <i>padding</i> parameters. In
case a provider specific instance of an algorithm is needed the
provider may also be specified in the <i>provider</i> parameter.
<p>Note that for simplicity, this actor does not support the
notion of algorithm parameters, so the algorithm must not require
that algorithm parameters be transmitted separately from the key.
If the user selects an algorithm that uses algorithm parameters, then
an exception will likely be thrown.
<p>This actor relies on the Java Cryptography Architecture (JCA) and Java
Cryptography Extension (JCE). See the
{@link ptolemy.actor.lib.security.CryptographyActor} documentation for
resources about the JCE.
@author Christopher Hylands Brooks, Contributor: Rakesh Reddy
@version $Id: SymmetricEncryption.java,v 1.49 2006/08/21 23:12:00 cxh Exp $
@since Ptolemy II 4.0
@Pt.ProposedRating Green (cxh)
@Pt.AcceptedRating Yellow (cxh)
*/
public class SymmetricEncryption extends CipherActor {
/** Construct an actor with the given container and name.
* @param container The container.
* @param name The name of this actor.
* @exception IllegalActionException If the actor cannot be contained
* by the proposed container.
* @exception NameDuplicationException If the container already has an
* actor with this name.
*/
public SymmetricEncryption(CompositeEntity container, String name)
throws NameDuplicationException, IllegalActionException {
super(container, name);
algorithm.setVisibility(Settable.NOT_EDITABLE);
algorithm.setPersistent(false);
// Hide the algorithm parameter.
algorithm.setVisibility(Settable.EXPERT);
key = new TypedIOPort(this, "key", true, false);
key.setTypeEquals(KeyToken.KEY);
// Hide the keySize parameter, it is not used.
keySize.setVisibility(Settable.EXPERT);
}
///////////////////////////////////////////////////////////////////
//// ports and parameters ////
/** The key to be used by this actor to encrypt the data.
* The type is an KeyToken containing a java.security.Key.
* Usually the output of the {@link ptolemy.actor.lib.security.SecretKey}
* actor is connected to this port
*/
public TypedIOPort key;
///////////////////////////////////////////////////////////////////
//// public methods ////
/** If there is a token on the <i>input</i> port, this method takes the
* data from the <i>input</i> and encrypts the data based on the
* <i>algorithm</i>, <i>provider</i>, <i>mode</i> and <i>padding</i>
* using the key read in from the <i>key</i> port.
* This processed data is then sent on the <i>output</i> port.
* All parameters should be the same as the corresponding
* decryption actor. This method calls javax.crypto.Cipher.init()
* with the value of the <i>key</i>.
*
* @exception IllegalActionException If thrown by base class.
*/
public void fire() throws IllegalActionException {
if (key.hasToken(0)) {
try {
KeyToken keyToken = (KeyToken) key.get(0);
// FIXME: do we really want to initialize the key each time?
java.security.Key securityKey = keyToken.getValue();
if (!_algorithm.equals(securityKey.getAlgorithm())) {
// We have the name of the algorithm from the Key,
// so we reinitialize the cipher
_algorithm = securityKey.getAlgorithm();
algorithm.setExpression(_algorithm);
_updateCipherNeeded = true;
_updateCipher();
}
_cipher.init(Cipher.ENCRYPT_MODE, securityKey);
} catch (Exception ex) {
throw new IllegalActionException(this, ex,
"Failed to initialize Cipher with " + "algorithm: '"
+ _algorithm + "', padding: '" + _padding
+ "', provider: '" + _provider + "'");
}
}
super.fire();
}
/** Encrypt the data using the javax.crypto.Cipher.
*
* @param dataBytes the data to be encrypted.
* @return byte[] the encrypted data.
* @exception IllegalActionException If error occurs in
* ByteArrayOutputStream, if the key is invalid, if the padding is bad
* or if the block size is illegal.
*/
protected byte[] _process(byte[] dataBytes) throws IllegalActionException {
// FIXME: should this method try to stream the data and
// have a wrapup method that calls _cipher.doFinal() instead?
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
byteArrayOutputStream.write(_cipher.doFinal(dataBytes));
} catch (Exception ex) {
throw new IllegalActionException(this, ex, "Problem processing "
+ dataBytes.length + " bytes.");
}
return byteArrayOutputStream.toByteArray();
}
}