From: Ian Clysdale <iclysdal@calum.csclub.uwaterloo.ca>
Message-Id: <199709181454.KAA28256@calum.csclub.uwaterloo.ca>
Subject: Behaviour of Cipher class in JCE
To: java-security@web2.javasoft.com
Date: Thu, 18 Sep 1997 10:54:53 -0400 (EDT)
Dear Sir/Madam:
I've been working at implementing a simple cipher algorithm following
the CAST-128 protocol (RFC 2144). My algorithm implements (or perhaps I
should say attempts to implement) its own buffering and padding. However,
although I pass up messages to the Cipher super-class during construction of
my Cipher, the Cipher class does not seem to receive them. When I pass in
block-aligned data, the engineCrypt() method is not called at all. When I pass
in non-block-aligned data, outBufferSize() raises an exception since the
data is not block-aligned.
Is it actually possible to implement buffering and padding in the current
version of the JCE (May 1, 1997 release)? If so, what am I doing wrong? I have
included sample code for a very simple minimalist cipher which attempts to
perform its own padding and buffering:
Thanks a lot,
ian
-------------------------
/* Cipher Code : Conforms to JCE. */
package provider.test;
import java.security.*;
public class CipherTest
extends Cipher
implements SymmetricCipher
{
final int BLOCK_SIZE=8;
/* Constructor: */
public CipherTest() {
// Implement padding and buffering. Security provider is Provider.
super(true,true,"ProviderTest");
}
/* SPI Requirements: */
protected int engineBlockSize() {
return BLOCK_SIZE;
}
protected int engineOutBufferSize(int inLen, boolean isFinal) {
// In a theoretical world, return the size of the buffer based
// on the length of the input, and whether or not it is the final
// data.
// Return something just for the sake of it.
return BLOCK_SIZE;
}
protected void engineInitEncrypt(Key key) throws InvalidKeyException {
System.out.println("Performing key scheduling, setting state value to ENCRYPT.");
}
protected void engineInitDecrypt(Key key) throws InvalidKeyException {
System.out.println("Performing key scheduling, setting state value to DECRYPT.");
}
protected int engineUpdate(byte in[],int inOff,int inLen,byte out[],int outOff) {
System.out.println("Performing actual encryption/decryption.");
// Since we didn't actually do anything, say so.
return 0;
}
protected int engineCrypt(byte out[], int offset) {
// Since we are over-riding the buffering, as we told the super-class
// at time of construction, this should always be run.
System.out.println("Cleaning up, flushing the buffer.");
// Since we didn't actually do anything...
return 0;
}
}
-------------------------
/* Provider Code. Conforms to JCE 1.1. */
package provider.test;
public final class ProviderTest extends java.security.Provider {
public ProviderTest() {
super("ProviderTest",0.1,"Ian's Test of JCE Cipher behaviour.");
put("Cipher.CipherTest","provider.test.CipherTest");
}
}
-------------------------
package provider.test;
import java.security.Cipher;
import sun.security.provider.SecretKey;
class Driver {
Driver() {
byte[] FortyBitKey = new byte[] { 1, 2, 3, 4, 5 };
byte[] BlockAligned = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
byte[] NotAligned = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
byte[] Storage;
try {
// Get the cipher.
Cipher c=Cipher.getInstance("CipherTest","ProviderTest");
// Create the Key
SecretKey testKey=new SecretKey(FortyBitKey, "TestCipher");
// Perform a test encryption on both the block-aligned and the
// non-block-aligned data.
c.initEncrypt(testKey);
Storage=c.crypt(BlockAligned);
Storage=c.crypt(NotAligned);
// Perform a test decryption on the block-aligned data.
// (Since we perform padding, all data to be decrypted should
// be block-aligned.)
c.initDecrypt(testKey);
Storage=c.crypt(BlockAligned);
Storage=c.crypt(NotAligned);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ProviderTest pt=new ProviderTest();
java.security.Security.addProvider(pt);
Driver x=new Driver();
}
}
-----------------------------------------
As output from executing Driver(), I receive :
-----------------------------------------
Performing key scheduling, setting state value to ENCRYPT.
Performing actual encryption/decryption.
java.security.IllegalBlockSizeException: Input data length not a multiple of blocksize.
at java.security.Cipher.outBufferSize(Cipher.java:417)
at java.security.Cipher.outBufferSize(Cipher.java:392)
at java.security.Cipher.crypt(Cipher.java:520)
at java.security.Cipher.crypt(Cipher.java:497)
at provider.test.Driver.<init>(Driver.java:26)
at provider.test.Driver.main(Driver.java:42)
-----------------------------------------
Note the lack of a message from engineCrypt() and the exception.