mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-24 05:40:39 +00:00
4898461: Support for ECB and CBC/PKCS5Padding
Add support for ECB mode and PKCS5Padding Reviewed-by: andreas
This commit is contained in:
parent
99370e418f
commit
83d7d2cdfb
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -22,10 +22,10 @@
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package sun.security.pkcs11;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.spec.*;
|
||||
@ -34,7 +34,6 @@ import javax.crypto.*;
|
||||
import javax.crypto.spec.*;
|
||||
|
||||
import sun.nio.ch.DirectBuffer;
|
||||
|
||||
import sun.security.pkcs11.wrapper.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
|
||||
@ -43,8 +42,8 @@ import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
* DES, DESede, AES, ARCFOUR, and Blowfish.
|
||||
*
|
||||
* This class is designed to support ECB and CBC with NoPadding and
|
||||
* PKCS5Padding for both. However, currently only CBC/NoPadding (and
|
||||
* ECB/NoPadding for stream ciphers) is functional.
|
||||
* PKCS5Padding for both. It will use its own padding impl if the
|
||||
* native mechanism does not support padding.
|
||||
*
|
||||
* Note that PKCS#11 current only supports ECB and CBC. There are no
|
||||
* provisions for other modes such as CFB, OFB, PCBC, or CTR mode.
|
||||
@ -62,10 +61,56 @@ final class P11Cipher extends CipherSpi {
|
||||
private final static int MODE_CBC = 4;
|
||||
|
||||
// padding constant for NoPadding
|
||||
private final static int PAD_NONE = 5;
|
||||
private final static int PAD_NONE = 5;
|
||||
// padding constant for PKCS5Padding
|
||||
private final static int PAD_PKCS5 = 6;
|
||||
|
||||
private static interface Padding {
|
||||
// ENC: format the specified buffer with padding bytes and return the
|
||||
// actual padding length
|
||||
int setPaddingBytes(byte[] paddingBuffer, int padLen);
|
||||
|
||||
// DEC: return the length of trailing padding bytes given the specified
|
||||
// padded data
|
||||
int unpad(byte[] paddedData, int ofs, int len)
|
||||
throws BadPaddingException;
|
||||
}
|
||||
|
||||
private static class PKCS5Padding implements Padding {
|
||||
|
||||
private final int blockSize;
|
||||
|
||||
PKCS5Padding(int blockSize)
|
||||
throws NoSuchPaddingException {
|
||||
if (blockSize == 0) {
|
||||
throw new NoSuchPaddingException
|
||||
("PKCS#5 padding not supported with stream ciphers");
|
||||
}
|
||||
this.blockSize = blockSize;
|
||||
}
|
||||
|
||||
public int setPaddingBytes(byte[] paddingBuffer, int padLen) {
|
||||
Arrays.fill(paddingBuffer, 0, padLen, (byte) (padLen & 0x007f));
|
||||
return padLen;
|
||||
}
|
||||
|
||||
public int unpad(byte[] paddedData, int ofs, int len)
|
||||
throws BadPaddingException {
|
||||
byte padValue = paddedData[ofs + len - 1];
|
||||
if (padValue < 1 || padValue > blockSize) {
|
||||
throw new BadPaddingException("Invalid pad value!");
|
||||
}
|
||||
// sanity check padding bytes
|
||||
int padStartIndex = ofs + len - padValue;
|
||||
for (int i = padStartIndex; i < len; i++) {
|
||||
if (paddedData[i] != padValue) {
|
||||
throw new BadPaddingException("Invalid pad bytes!");
|
||||
}
|
||||
}
|
||||
return padValue;
|
||||
}
|
||||
}
|
||||
|
||||
// token instance
|
||||
private final Token token;
|
||||
|
||||
@ -99,65 +144,93 @@ final class P11Cipher extends CipherSpi {
|
||||
// padding type, on of PAD_* above (PAD_NONE for stream ciphers)
|
||||
private int paddingType;
|
||||
|
||||
// when the padding is requested but unsupported by the native mechanism,
|
||||
// we use the following to do padding and necessary data buffering.
|
||||
// padding object which generate padding and unpad the decrypted data
|
||||
private Padding paddingObj;
|
||||
// buffer for holding back the block which contains padding bytes
|
||||
private byte[] padBuffer;
|
||||
private int padBufferLen;
|
||||
|
||||
// original IV, if in MODE_CBC
|
||||
private byte[] iv;
|
||||
|
||||
// total number of bytes processed
|
||||
private int bytesProcessed;
|
||||
// number of bytes buffered internally by the native mechanism and padBuffer
|
||||
// if we do the padding
|
||||
private int bytesBuffered;
|
||||
|
||||
P11Cipher(Token token, String algorithm, long mechanism)
|
||||
throws PKCS11Exception {
|
||||
throws PKCS11Exception, NoSuchAlgorithmException {
|
||||
super();
|
||||
this.token = token;
|
||||
this.algorithm = algorithm;
|
||||
this.mechanism = mechanism;
|
||||
keyAlgorithm = algorithm.split("/")[0];
|
||||
|
||||
String algoParts[] = algorithm.split("/");
|
||||
keyAlgorithm = algoParts[0];
|
||||
|
||||
if (keyAlgorithm.equals("AES")) {
|
||||
blockSize = 16;
|
||||
blockMode = MODE_CBC;
|
||||
// XXX change default to PKCS5Padding
|
||||
paddingType = PAD_NONE;
|
||||
} else if (keyAlgorithm.equals("RC4") || keyAlgorithm.equals("ARCFOUR")) {
|
||||
} else if (keyAlgorithm.equals("RC4") ||
|
||||
keyAlgorithm.equals("ARCFOUR")) {
|
||||
blockSize = 0;
|
||||
blockMode = MODE_ECB;
|
||||
paddingType = PAD_NONE;
|
||||
} else { // DES, DESede, Blowfish
|
||||
blockSize = 8;
|
||||
blockMode = MODE_CBC;
|
||||
// XXX change default to PKCS5Padding
|
||||
paddingType = PAD_NONE;
|
||||
}
|
||||
this.blockMode =
|
||||
(algoParts.length > 1 ? parseMode(algoParts[1]) : MODE_ECB);
|
||||
|
||||
String defPadding = (blockSize == 0 ? "NoPadding" : "PKCS5Padding");
|
||||
String paddingStr =
|
||||
(algoParts.length > 2 ? algoParts[2] : defPadding);
|
||||
try {
|
||||
engineSetPadding(paddingStr);
|
||||
} catch (NoSuchPaddingException nspe) {
|
||||
// should not happen
|
||||
throw new ProviderException(nspe);
|
||||
}
|
||||
session = token.getOpSession();
|
||||
}
|
||||
|
||||
protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
|
||||
// Disallow change of mode for now since currently it's explicitly
|
||||
// defined in transformation strings
|
||||
throw new NoSuchAlgorithmException("Unsupported mode " + mode);
|
||||
}
|
||||
|
||||
private int parseMode(String mode) throws NoSuchAlgorithmException {
|
||||
mode = mode.toUpperCase();
|
||||
int result;
|
||||
if (mode.equals("ECB")) {
|
||||
this.blockMode = MODE_ECB;
|
||||
result = MODE_ECB;
|
||||
} else if (mode.equals("CBC")) {
|
||||
if (blockSize == 0) {
|
||||
throw new NoSuchAlgorithmException
|
||||
("CBC mode not supported with stream ciphers");
|
||||
}
|
||||
this.blockMode = MODE_CBC;
|
||||
result = MODE_CBC;
|
||||
} else {
|
||||
throw new NoSuchAlgorithmException("Unsupported mode " + mode);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected void engineSetPadding(String padding)
|
||||
throws NoSuchPaddingException {
|
||||
if (padding.equalsIgnoreCase("NoPadding")) {
|
||||
paddingObj = null;
|
||||
padBuffer = null;
|
||||
padding = padding.toUpperCase();
|
||||
if (padding.equals("NOPADDING")) {
|
||||
paddingType = PAD_NONE;
|
||||
} else if (padding.equalsIgnoreCase("PKCS5Padding")) {
|
||||
if (blockSize == 0) {
|
||||
throw new NoSuchPaddingException
|
||||
("PKCS#5 padding not supported with stream ciphers");
|
||||
}
|
||||
} else if (padding.equals("PKCS5PADDING")) {
|
||||
paddingType = PAD_PKCS5;
|
||||
// XXX PKCS#5 not yet implemented
|
||||
throw new NoSuchPaddingException("pkcs5");
|
||||
if (mechanism != CKM_DES_CBC_PAD && mechanism != CKM_DES3_CBC_PAD &&
|
||||
mechanism != CKM_AES_CBC_PAD) {
|
||||
// no native padding support; use our own padding impl
|
||||
paddingObj = new PKCS5Padding(blockSize);
|
||||
padBuffer = new byte[blockSize];
|
||||
}
|
||||
} else {
|
||||
throw new NoSuchPaddingException("Unsupported padding " + padding);
|
||||
}
|
||||
@ -175,7 +248,7 @@ final class P11Cipher extends CipherSpi {
|
||||
|
||||
// see JCE spec
|
||||
protected byte[] engineGetIV() {
|
||||
return (iv == null) ? null : (byte[])iv.clone();
|
||||
return (iv == null) ? null : (byte[]) iv.clone();
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@ -185,8 +258,9 @@ final class P11Cipher extends CipherSpi {
|
||||
}
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||
try {
|
||||
AlgorithmParameters params = AlgorithmParameters.getInstance
|
||||
(keyAlgorithm, P11Util.getSunJceProvider());
|
||||
AlgorithmParameters params =
|
||||
AlgorithmParameters.getInstance(keyAlgorithm,
|
||||
P11Util.getSunJceProvider());
|
||||
params.init(ivSpec);
|
||||
return params;
|
||||
} catch (GeneralSecurityException e) {
|
||||
@ -210,38 +284,38 @@ final class P11Cipher extends CipherSpi {
|
||||
protected void engineInit(int opmode, Key key,
|
||||
AlgorithmParameterSpec params, SecureRandom random)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
byte[] iv;
|
||||
byte[] ivValue;
|
||||
if (params != null) {
|
||||
if (params instanceof IvParameterSpec == false) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Only IvParameterSpec supported");
|
||||
}
|
||||
IvParameterSpec ivSpec = (IvParameterSpec)params;
|
||||
iv = ivSpec.getIV();
|
||||
IvParameterSpec ivSpec = (IvParameterSpec) params;
|
||||
ivValue = ivSpec.getIV();
|
||||
} else {
|
||||
iv = null;
|
||||
ivValue = null;
|
||||
}
|
||||
implInit(opmode, key, iv, random);
|
||||
implInit(opmode, key, ivValue, random);
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected void engineInit(int opmode, Key key, AlgorithmParameters params,
|
||||
SecureRandom random)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
byte[] iv;
|
||||
byte[] ivValue;
|
||||
if (params != null) {
|
||||
try {
|
||||
IvParameterSpec ivSpec = (IvParameterSpec)
|
||||
params.getParameterSpec(IvParameterSpec.class);
|
||||
iv = ivSpec.getIV();
|
||||
ivValue = ivSpec.getIV();
|
||||
} catch (InvalidParameterSpecException e) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Could not decode IV", e);
|
||||
}
|
||||
} else {
|
||||
iv = null;
|
||||
ivValue = null;
|
||||
}
|
||||
implInit(opmode, key, iv, random);
|
||||
implInit(opmode, key, ivValue, random);
|
||||
}
|
||||
|
||||
// actual init() implementation
|
||||
@ -250,31 +324,31 @@ final class P11Cipher extends CipherSpi {
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
cancelOperation();
|
||||
switch (opmode) {
|
||||
case Cipher.ENCRYPT_MODE:
|
||||
encrypt = true;
|
||||
break;
|
||||
case Cipher.DECRYPT_MODE:
|
||||
encrypt = false;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Unsupported mode: " + opmode);
|
||||
case Cipher.ENCRYPT_MODE:
|
||||
encrypt = true;
|
||||
break;
|
||||
case Cipher.DECRYPT_MODE:
|
||||
encrypt = false;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Unsupported mode: " + opmode);
|
||||
}
|
||||
if (blockMode == MODE_ECB) { // ECB or stream cipher
|
||||
if (iv != null) {
|
||||
if (blockSize == 0) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("IV not used with stream ciphers");
|
||||
("IV not used with stream ciphers");
|
||||
} else {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("IV not used in ECB mode");
|
||||
("IV not used in ECB mode");
|
||||
}
|
||||
}
|
||||
} else { // MODE_CBC
|
||||
if (iv == null) {
|
||||
if (encrypt == false) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("IV must be specified for decryption in CBC mode");
|
||||
("IV must be specified for decryption in CBC mode");
|
||||
}
|
||||
// generate random IV
|
||||
if (random == null) {
|
||||
@ -285,7 +359,7 @@ final class P11Cipher extends CipherSpi {
|
||||
} else {
|
||||
if (iv.length != blockSize) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("IV length must match block size");
|
||||
("IV length must match block size");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -331,63 +405,43 @@ final class P11Cipher extends CipherSpi {
|
||||
session = token.getOpSession();
|
||||
}
|
||||
if (encrypt) {
|
||||
token.p11.C_EncryptInit
|
||||
(session.id(), new CK_MECHANISM(mechanism, iv), p11Key.keyID);
|
||||
token.p11.C_EncryptInit(session.id(),
|
||||
new CK_MECHANISM(mechanism, iv), p11Key.keyID);
|
||||
} else {
|
||||
token.p11.C_DecryptInit
|
||||
(session.id(), new CK_MECHANISM(mechanism, iv), p11Key.keyID);
|
||||
token.p11.C_DecryptInit(session.id(),
|
||||
new CK_MECHANISM(mechanism, iv), p11Key.keyID);
|
||||
}
|
||||
bytesProcessed = 0;
|
||||
bytesBuffered = 0;
|
||||
padBufferLen = 0;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
// XXX the calculations below assume the PKCS#11 implementation is smart.
|
||||
// conceivably, not all implementations are and we may need to estimate
|
||||
// more conservatively
|
||||
|
||||
private int bytesBuffered(int totalLen) {
|
||||
if (paddingType == PAD_NONE) {
|
||||
// with NoPadding, buffer only the current unfinished block
|
||||
return totalLen & (blockSize - 1);
|
||||
} else { // PKCS5
|
||||
// with PKCS5Padding in decrypt mode, the buffer must never
|
||||
// be empty. Buffer a full block instead of nothing.
|
||||
int buffered = totalLen & (blockSize - 1);
|
||||
if ((buffered == 0) && (encrypt == false)) {
|
||||
buffered = blockSize;
|
||||
}
|
||||
return buffered;
|
||||
}
|
||||
}
|
||||
|
||||
// if update(inLen) is called, how big does the output buffer have to be?
|
||||
private int updateLength(int inLen) {
|
||||
if (inLen <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if (blockSize == 0) {
|
||||
return inLen;
|
||||
} else {
|
||||
// bytes that need to be buffered now
|
||||
int buffered = bytesBuffered(bytesProcessed);
|
||||
// bytes that need to be buffered after this update
|
||||
int newBuffered = bytesBuffered(bytesProcessed + inLen);
|
||||
return inLen + buffered - newBuffered;
|
||||
|
||||
int result = inLen + bytesBuffered;
|
||||
if (blockSize != 0) {
|
||||
// minus the number of bytes in the last incomplete block.
|
||||
result -= (result & (blockSize - 1));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// if doFinal(inLen) is called, how big does the output buffer have to be?
|
||||
private int doFinalLength(int inLen) {
|
||||
if (paddingType == PAD_NONE) {
|
||||
return updateLength(inLen);
|
||||
}
|
||||
if (inLen < 0) {
|
||||
return 0;
|
||||
}
|
||||
int buffered = bytesBuffered(bytesProcessed);
|
||||
int newProcessed = bytesProcessed + inLen;
|
||||
int paddedProcessed = (newProcessed + blockSize) & ~(blockSize - 1);
|
||||
return paddedProcessed - bytesProcessed + buffered;
|
||||
|
||||
int result = inLen + bytesBuffered;
|
||||
if (blockSize != 0 && encrypt && paddingType != PAD_NONE) {
|
||||
// add the number of bytes to make the last block complete.
|
||||
result += (blockSize - (result & (blockSize - 1)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@ -397,6 +451,7 @@ final class P11Cipher extends CipherSpi {
|
||||
int n = engineUpdate(in, inOfs, inLen, out, 0);
|
||||
return P11Util.convert(out, 0, n);
|
||||
} catch (ShortBufferException e) {
|
||||
// convert since the output length is calculated by updateLength()
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
}
|
||||
@ -409,6 +464,7 @@ final class P11Cipher extends CipherSpi {
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected int engineUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)
|
||||
throws ShortBufferException {
|
||||
return implUpdate(inBuffer, outBuffer);
|
||||
@ -422,14 +478,15 @@ final class P11Cipher extends CipherSpi {
|
||||
int n = engineDoFinal(in, inOfs, inLen, out, 0);
|
||||
return P11Util.convert(out, 0, n);
|
||||
} catch (ShortBufferException e) {
|
||||
// convert since the output length is calculated by doFinalLength()
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
|
||||
int outOfs) throws ShortBufferException, IllegalBlockSizeException {
|
||||
// BadPaddingException {
|
||||
int outOfs) throws ShortBufferException, IllegalBlockSizeException,
|
||||
BadPaddingException {
|
||||
int n = 0;
|
||||
if ((inLen != 0) && (in != null)) {
|
||||
n = engineUpdate(in, inOfs, inLen, out, outOfs);
|
||||
@ -440,8 +497,10 @@ final class P11Cipher extends CipherSpi {
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected int engineDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)
|
||||
throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
|
||||
throws ShortBufferException, IllegalBlockSizeException,
|
||||
BadPaddingException {
|
||||
int n = engineUpdate(inBuffer, outBuffer);
|
||||
n += implDoFinal(outBuffer);
|
||||
return n;
|
||||
@ -454,18 +513,55 @@ final class P11Cipher extends CipherSpi {
|
||||
}
|
||||
try {
|
||||
ensureInitialized();
|
||||
int k;
|
||||
int k = 0;
|
||||
if (encrypt) {
|
||||
k = token.p11.C_EncryptUpdate
|
||||
(session.id(), 0, in, inOfs, inLen, 0, out, outOfs, outLen);
|
||||
k = token.p11.C_EncryptUpdate(session.id(), 0, in, inOfs, inLen,
|
||||
0, out, outOfs, outLen);
|
||||
} else {
|
||||
k = token.p11.C_DecryptUpdate
|
||||
(session.id(), 0, in, inOfs, inLen, 0, out, outOfs, outLen);
|
||||
int newPadBufferLen = 0;
|
||||
if (paddingObj != null) {
|
||||
if (padBufferLen != 0) {
|
||||
// NSS throws up when called with data not in multiple
|
||||
// of blocks. Try to work around this by holding the
|
||||
// extra data in padBuffer.
|
||||
if (padBufferLen != padBuffer.length) {
|
||||
int bufCapacity = padBuffer.length - padBufferLen;
|
||||
if (inLen > bufCapacity) {
|
||||
bufferInputBytes(in, inOfs, bufCapacity);
|
||||
inOfs += bufCapacity;
|
||||
inLen -= bufCapacity;
|
||||
} else {
|
||||
bufferInputBytes(in, inOfs, inLen);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
k = token.p11.C_DecryptUpdate(session.id(),
|
||||
0, padBuffer, 0, padBufferLen,
|
||||
0, out, outOfs, outLen);
|
||||
padBufferLen = 0;
|
||||
}
|
||||
newPadBufferLen = inLen & (blockSize - 1);
|
||||
if (newPadBufferLen == 0) {
|
||||
newPadBufferLen = padBuffer.length;
|
||||
}
|
||||
inLen -= newPadBufferLen;
|
||||
}
|
||||
if (inLen > 0) {
|
||||
k += token.p11.C_DecryptUpdate(session.id(), 0, in, inOfs,
|
||||
inLen, 0, out, (outOfs + k), (outLen - k));
|
||||
}
|
||||
// update 'padBuffer' if using our own padding impl.
|
||||
if (paddingObj != null) {
|
||||
bufferInputBytes(in, inOfs + inLen, newPadBufferLen);
|
||||
}
|
||||
}
|
||||
bytesProcessed += inLen;
|
||||
bytesBuffered += (inLen - k);
|
||||
return k;
|
||||
} catch (PKCS11Exception e) {
|
||||
// XXX throw correct exception
|
||||
if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {
|
||||
throw (ShortBufferException)
|
||||
(new ShortBufferException().initCause(e));
|
||||
}
|
||||
throw new ProviderException("update() failed", e);
|
||||
}
|
||||
}
|
||||
@ -481,101 +577,167 @@ final class P11Cipher extends CipherSpi {
|
||||
if (outLen < updateLength(inLen)) {
|
||||
throw new ShortBufferException();
|
||||
}
|
||||
boolean inPosChanged = false;
|
||||
int origPos = inBuffer.position();
|
||||
try {
|
||||
ensureInitialized();
|
||||
|
||||
long inAddr = 0;
|
||||
int inOfs = inBuffer.position();
|
||||
int inOfs = 0;
|
||||
byte[] inArray = null;
|
||||
|
||||
if (inBuffer instanceof DirectBuffer) {
|
||||
inAddr = ((DirectBuffer)inBuffer).address();
|
||||
} else {
|
||||
if (inBuffer.hasArray()) {
|
||||
inArray = inBuffer.array();
|
||||
inOfs += inBuffer.arrayOffset();
|
||||
} else {
|
||||
inArray = new byte[inLen];
|
||||
inBuffer.get(inArray);
|
||||
inOfs = 0;
|
||||
inPosChanged = true;
|
||||
}
|
||||
inAddr = ((DirectBuffer) inBuffer).address();
|
||||
inOfs = origPos;
|
||||
} else if (inBuffer.hasArray()) {
|
||||
inArray = inBuffer.array();
|
||||
inOfs = (origPos + inBuffer.arrayOffset());
|
||||
}
|
||||
|
||||
long outAddr = 0;
|
||||
int outOfs = outBuffer.position();
|
||||
int outOfs = 0;
|
||||
byte[] outArray = null;
|
||||
if (outBuffer instanceof DirectBuffer) {
|
||||
outAddr = ((DirectBuffer)outBuffer).address();
|
||||
outAddr = ((DirectBuffer) outBuffer).address();
|
||||
outOfs = outBuffer.position();
|
||||
} else {
|
||||
if (outBuffer.hasArray()) {
|
||||
outArray = outBuffer.array();
|
||||
outOfs += outBuffer.arrayOffset();
|
||||
outOfs = (outBuffer.position() + outBuffer.arrayOffset());
|
||||
} else {
|
||||
outArray = new byte[outLen];
|
||||
outOfs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int k;
|
||||
int k = 0;
|
||||
if (encrypt) {
|
||||
k = token.p11.C_EncryptUpdate
|
||||
(session.id(), inAddr, inArray, inOfs, inLen,
|
||||
outAddr, outArray, outOfs, outLen);
|
||||
if (inAddr == 0 && inArray == null) {
|
||||
inArray = new byte[inLen];
|
||||
inBuffer.get(inArray);
|
||||
} else {
|
||||
inBuffer.position(origPos + inLen);
|
||||
}
|
||||
k = token.p11.C_EncryptUpdate(session.id(),
|
||||
inAddr, inArray, inOfs, inLen,
|
||||
outAddr, outArray, outOfs, outLen);
|
||||
} else {
|
||||
k = token.p11.C_DecryptUpdate
|
||||
(session.id(), inAddr, inArray, inOfs, inLen,
|
||||
outAddr, outArray, outOfs, outLen);
|
||||
}
|
||||
bytesProcessed += inLen;
|
||||
if (!inPosChanged) {
|
||||
inBuffer.position(inBuffer.position() + inLen);
|
||||
int newPadBufferLen = 0;
|
||||
if (paddingObj != null) {
|
||||
if (padBufferLen != 0) {
|
||||
// NSS throws up when called with data not in multiple
|
||||
// of blocks. Try to work around this by holding the
|
||||
// extra data in padBuffer.
|
||||
if (padBufferLen != padBuffer.length) {
|
||||
int bufCapacity = padBuffer.length - padBufferLen;
|
||||
if (inLen > bufCapacity) {
|
||||
bufferInputBytes(inBuffer, bufCapacity);
|
||||
inOfs += bufCapacity;
|
||||
inLen -= bufCapacity;
|
||||
} else {
|
||||
bufferInputBytes(inBuffer, inLen);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
k = token.p11.C_DecryptUpdate(session.id(), 0,
|
||||
padBuffer, 0, padBufferLen, outAddr, outArray,
|
||||
outOfs, outLen);
|
||||
padBufferLen = 0;
|
||||
}
|
||||
newPadBufferLen = inLen & (blockSize - 1);
|
||||
if (newPadBufferLen == 0) {
|
||||
newPadBufferLen = padBuffer.length;
|
||||
}
|
||||
inLen -= newPadBufferLen;
|
||||
}
|
||||
if (inLen > 0) {
|
||||
if (inAddr == 0 && inArray == null) {
|
||||
inArray = new byte[inLen];
|
||||
inBuffer.get(inArray);
|
||||
} else {
|
||||
inBuffer.position(inBuffer.position() + inLen);
|
||||
}
|
||||
k += token.p11.C_DecryptUpdate(session.id(), inAddr,
|
||||
inArray, inOfs, inLen, outAddr, outArray,
|
||||
(outOfs + k), (outLen - k));
|
||||
}
|
||||
// update 'padBuffer' if using our own padding impl.
|
||||
if (paddingObj != null && newPadBufferLen != 0) {
|
||||
bufferInputBytes(inBuffer, newPadBufferLen);
|
||||
}
|
||||
}
|
||||
bytesBuffered += (inLen - k);
|
||||
if (!(outBuffer instanceof DirectBuffer) &&
|
||||
!outBuffer.hasArray()) {
|
||||
!outBuffer.hasArray()) {
|
||||
outBuffer.put(outArray, outOfs, k);
|
||||
} else {
|
||||
outBuffer.position(outBuffer.position() + k);
|
||||
}
|
||||
return k;
|
||||
} catch (PKCS11Exception e) {
|
||||
// Un-read the bytes back to input buffer
|
||||
if (inPosChanged) {
|
||||
inBuffer.position(inBuffer.position() - inLen);
|
||||
// Reset input buffer to its original position for
|
||||
inBuffer.position(origPos);
|
||||
if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {
|
||||
throw (ShortBufferException)
|
||||
(new ShortBufferException().initCause(e));
|
||||
}
|
||||
// XXX throw correct exception
|
||||
throw new ProviderException("update() failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
private int implDoFinal(byte[] out, int outOfs, int outLen)
|
||||
throws ShortBufferException, IllegalBlockSizeException {
|
||||
if (outLen < doFinalLength(0)) {
|
||||
throws ShortBufferException, IllegalBlockSizeException,
|
||||
BadPaddingException {
|
||||
int requiredOutLen = doFinalLength(0);
|
||||
if (outLen < requiredOutLen) {
|
||||
throw new ShortBufferException();
|
||||
}
|
||||
try {
|
||||
ensureInitialized();
|
||||
int k = 0;
|
||||
if (encrypt) {
|
||||
return token.p11.C_EncryptFinal
|
||||
(session.id(), 0, out, outOfs, outLen);
|
||||
if (paddingObj != null) {
|
||||
int actualPadLen = paddingObj.setPaddingBytes(padBuffer,
|
||||
requiredOutLen - bytesBuffered);
|
||||
k = token.p11.C_EncryptUpdate(session.id(),
|
||||
0, padBuffer, 0, actualPadLen,
|
||||
0, out, outOfs, outLen);
|
||||
}
|
||||
k += token.p11.C_EncryptFinal(session.id(),
|
||||
0, out, (outOfs + k), (outLen - k));
|
||||
} else {
|
||||
return token.p11.C_DecryptFinal
|
||||
(session.id(), 0, out, outOfs, outLen);
|
||||
if (paddingObj != null) {
|
||||
if (padBufferLen != 0) {
|
||||
k = token.p11.C_DecryptUpdate(session.id(), 0,
|
||||
padBuffer, 0, padBufferLen, 0, padBuffer, 0,
|
||||
padBuffer.length);
|
||||
}
|
||||
k += token.p11.C_DecryptFinal(session.id(), 0, padBuffer, k,
|
||||
padBuffer.length - k);
|
||||
int actualPadLen = paddingObj.unpad(padBuffer, 0, k);
|
||||
k -= actualPadLen;
|
||||
System.arraycopy(padBuffer, 0, out, outOfs, k);
|
||||
} else {
|
||||
k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs,
|
||||
outLen);
|
||||
}
|
||||
}
|
||||
return k;
|
||||
} catch (PKCS11Exception e) {
|
||||
handleException(e);
|
||||
throw new ProviderException("doFinal() failed", e);
|
||||
} finally {
|
||||
initialized = false;
|
||||
bytesProcessed = 0;
|
||||
bytesBuffered = 0;
|
||||
padBufferLen = 0;
|
||||
session = token.releaseSession(session);
|
||||
}
|
||||
}
|
||||
|
||||
private int implDoFinal(ByteBuffer outBuffer)
|
||||
throws ShortBufferException, IllegalBlockSizeException {
|
||||
throws ShortBufferException, IllegalBlockSizeException,
|
||||
BadPaddingException {
|
||||
int outLen = outBuffer.remaining();
|
||||
if (outLen < doFinalLength(0)) {
|
||||
int requiredOutLen = doFinalLength(0);
|
||||
if (outLen < requiredOutLen) {
|
||||
throw new ShortBufferException();
|
||||
}
|
||||
|
||||
@ -583,30 +745,54 @@ final class P11Cipher extends CipherSpi {
|
||||
ensureInitialized();
|
||||
|
||||
long outAddr = 0;
|
||||
int outOfs = outBuffer.position();
|
||||
byte[] outArray = null;
|
||||
int outOfs = 0;
|
||||
if (outBuffer instanceof DirectBuffer) {
|
||||
outAddr = ((DirectBuffer)outBuffer).address();
|
||||
outAddr = ((DirectBuffer) outBuffer).address();
|
||||
outOfs = outBuffer.position();
|
||||
} else {
|
||||
if (outBuffer.hasArray()) {
|
||||
outArray = outBuffer.array();
|
||||
outOfs += outBuffer.arrayOffset();
|
||||
outOfs = outBuffer.position() + outBuffer.arrayOffset();
|
||||
} else {
|
||||
outArray = new byte[outLen];
|
||||
outOfs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int k;
|
||||
int k = 0;
|
||||
|
||||
if (encrypt) {
|
||||
k = token.p11.C_EncryptFinal
|
||||
(session.id(), outAddr, outArray, outOfs, outLen);
|
||||
if (paddingObj != null) {
|
||||
int actualPadLen = paddingObj.setPaddingBytes(padBuffer,
|
||||
requiredOutLen - bytesBuffered);
|
||||
k = token.p11.C_EncryptUpdate(session.id(),
|
||||
0, padBuffer, 0, actualPadLen,
|
||||
outAddr, outArray, outOfs, outLen);
|
||||
}
|
||||
k += token.p11.C_EncryptFinal(session.id(),
|
||||
outAddr, outArray, (outOfs + k), (outLen - k));
|
||||
} else {
|
||||
k = token.p11.C_DecryptFinal
|
||||
(session.id(), outAddr, outArray, outOfs, outLen);
|
||||
if (paddingObj != null) {
|
||||
if (padBufferLen != 0) {
|
||||
k = token.p11.C_DecryptUpdate(session.id(),
|
||||
0, padBuffer, 0, padBufferLen,
|
||||
0, padBuffer, 0, padBuffer.length);
|
||||
padBufferLen = 0;
|
||||
}
|
||||
k += token.p11.C_DecryptFinal(session.id(),
|
||||
0, padBuffer, k, padBuffer.length - k);
|
||||
int actualPadLen = paddingObj.unpad(padBuffer, 0, k);
|
||||
k -= actualPadLen;
|
||||
outArray = padBuffer;
|
||||
outOfs = 0;
|
||||
} else {
|
||||
k = token.p11.C_DecryptFinal(session.id(),
|
||||
outAddr, outArray, outOfs, outLen);
|
||||
}
|
||||
}
|
||||
if (!(outBuffer instanceof DirectBuffer) &&
|
||||
!outBuffer.hasArray()) {
|
||||
if ((!encrypt && paddingObj != null) ||
|
||||
(!(outBuffer instanceof DirectBuffer) &&
|
||||
!outBuffer.hasArray())) {
|
||||
outBuffer.put(outArray, outOfs, k);
|
||||
} else {
|
||||
outBuffer.position(outBuffer.position() + k);
|
||||
@ -617,20 +803,21 @@ final class P11Cipher extends CipherSpi {
|
||||
throw new ProviderException("doFinal() failed", e);
|
||||
} finally {
|
||||
initialized = false;
|
||||
bytesProcessed = 0;
|
||||
bytesBuffered = 0;
|
||||
session = token.releaseSession(session);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleException(PKCS11Exception e)
|
||||
throws IllegalBlockSizeException {
|
||||
throws ShortBufferException, IllegalBlockSizeException {
|
||||
long errorCode = e.getErrorCode();
|
||||
// XXX better check
|
||||
if (errorCode == CKR_DATA_LEN_RANGE) {
|
||||
throw (IllegalBlockSizeException)new
|
||||
IllegalBlockSizeException(e.toString()).initCause(e);
|
||||
if (errorCode == CKR_BUFFER_TOO_SMALL) {
|
||||
throw (ShortBufferException)
|
||||
(new ShortBufferException().initCause(e));
|
||||
} else if (errorCode == CKR_DATA_LEN_RANGE) {
|
||||
throw (IllegalBlockSizeException)
|
||||
(new IllegalBlockSizeException(e.toString()).initCause(e));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@ -649,12 +836,14 @@ final class P11Cipher extends CipherSpi {
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected int engineGetKeySize(Key key) throws InvalidKeyException {
|
||||
int n = P11SecretKeyFactory.convertKey
|
||||
(token, key, keyAlgorithm).keyLength();
|
||||
(token, key, keyAlgorithm).keyLength();
|
||||
return n;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
if ((session != null) && token.isValid()) {
|
||||
@ -666,4 +855,15 @@ final class P11Cipher extends CipherSpi {
|
||||
}
|
||||
}
|
||||
|
||||
private final void bufferInputBytes(byte[] in, int inOfs, int len) {
|
||||
System.arraycopy(in, inOfs, padBuffer, padBufferLen, len);
|
||||
padBufferLen += len;
|
||||
bytesBuffered += len;
|
||||
}
|
||||
|
||||
private final void bufferInputBytes(ByteBuffer inBuffer, int len) {
|
||||
inBuffer.get(padBuffer, padBufferLen, len);
|
||||
padBufferLen += len;
|
||||
bytesBuffered += len;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -601,14 +601,26 @@ public final class SunPKCS11 extends AuthProvider {
|
||||
// XXX attributes for Ciphers (supported modes, padding)
|
||||
d(CIP, "ARCFOUR", P11Cipher, s("RC4"),
|
||||
m(CKM_RC4));
|
||||
// XXX only CBC/NoPadding for block ciphers
|
||||
d(CIP, "DES/CBC/NoPadding", P11Cipher,
|
||||
m(CKM_DES_CBC));
|
||||
d(CIP, "DES/CBC/PKCS5Padding", P11Cipher,
|
||||
m(CKM_DES_CBC_PAD, CKM_DES_CBC));
|
||||
d(CIP, "DES/ECB", P11Cipher, s("DES"),
|
||||
m(CKM_DES_ECB));
|
||||
|
||||
d(CIP, "DESede/CBC/NoPadding", P11Cipher,
|
||||
m(CKM_DES3_CBC));
|
||||
d(CIP, "DESede/CBC/PKCS5Padding", P11Cipher,
|
||||
m(CKM_DES3_CBC_PAD, CKM_DES3_CBC));
|
||||
d(CIP, "DESede/ECB", P11Cipher, s("DESede"),
|
||||
m(CKM_DES3_ECB));
|
||||
d(CIP, "AES/CBC/NoPadding", P11Cipher,
|
||||
m(CKM_AES_CBC));
|
||||
d(CIP, "Blowfish/CBC/NoPadding", P11Cipher,
|
||||
d(CIP, "AES/CBC/PKCS5Padding", P11Cipher,
|
||||
m(CKM_AES_CBC_PAD, CKM_AES_CBC));
|
||||
d(CIP, "AES/ECB", P11Cipher, s("AES"),
|
||||
m(CKM_AES_ECB));
|
||||
d(CIP, "Blowfish/CBC", P11Cipher,
|
||||
m(CKM_BLOWFISH_CBC));
|
||||
|
||||
// XXX RSA_X_509, RSA_OAEP not yet supported
|
||||
|
||||
282
jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphers.java
Normal file
282
jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphers.java
Normal file
@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modi
|
||||
fy it
|
||||
* under the terms of the GNU General Public License version 2 onl
|
||||
y, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, bu
|
||||
t WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABIL
|
||||
ITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public L
|
||||
icense
|
||||
* version 2 for more details (a copy is included in the LICENSE f
|
||||
ile that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public Licen
|
||||
se version
|
||||
* 2 along with this work; if not, write to the Free Software Foun
|
||||
dation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, San
|
||||
ta Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional inform
|
||||
ation or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test %I% %E%
|
||||
* @bug 4898461
|
||||
* @summary basic test for symmetric ciphers with padding
|
||||
* @author Valerie Peng
|
||||
* @library ..
|
||||
*/
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
|
||||
public class TestSymmCiphers extends PKCS11Test {
|
||||
|
||||
private static class CI { // class for holding Cipher Information
|
||||
|
||||
String transformation;
|
||||
String keyAlgo;
|
||||
int dataSize;
|
||||
|
||||
CI(String transformation, String keyAlgo, int dataSize) {
|
||||
this.transformation = transformation;
|
||||
this.keyAlgo = keyAlgo;
|
||||
this.dataSize = dataSize;
|
||||
}
|
||||
}
|
||||
private static final CI[] TEST_LIST = {
|
||||
new CI("ARCFOUR", "ARCFOUR", 400),
|
||||
new CI("RC4", "RC4", 401),
|
||||
new CI("DES/CBC/NoPadding", "DES", 400),
|
||||
new CI("DESede/CBC/NoPadding", "DESede", 160),
|
||||
new CI("AES/CBC/NoPadding", "AES", 4800),
|
||||
new CI("Blowfish/CBC/NoPadding", "Blowfish", 24),
|
||||
new CI("DES/cbc/PKCS5Padding", "DES", 6401),
|
||||
new CI("DESede/CBC/PKCS5Padding", "DESede", 402),
|
||||
new CI("AES/CBC/PKCS5Padding", "AES", 30),
|
||||
new CI("Blowfish/CBC/PKCS5Padding", "Blowfish", 19),
|
||||
new CI("DES/ECB/NoPadding", "DES", 400),
|
||||
new CI("DESede/ECB/NoPadding", "DESede", 160),
|
||||
new CI("AES/ECB/NoPadding", "AES", 4800),
|
||||
new CI("DES/ECB/PKCS5Padding", "DES", 32),
|
||||
new CI("DES/ECB/PKCS5Padding", "DES", 6400),
|
||||
new CI("DESede/ECB/PKCS5Padding", "DESede", 400),
|
||||
new CI("AES/ECB/PKCS5Padding", "AES", 64),
|
||||
new CI("DES", "DES", 6400),
|
||||
new CI("DESede", "DESede", 408),
|
||||
new CI("AES", "AES", 128)
|
||||
};
|
||||
private static StringBuffer debugBuf = new StringBuffer();
|
||||
|
||||
public void main(Provider p) throws Exception {
|
||||
// NSS reports CKR_DEVICE_ERROR when the data passed to
|
||||
// its EncryptUpdate/DecryptUpdate is not multiple of blocks
|
||||
int firstBlkSize = 16;
|
||||
boolean status = true;
|
||||
Random random = new Random();
|
||||
try {
|
||||
for (int i = 0; i < TEST_LIST.length; i++) {
|
||||
CI currTest = TEST_LIST[i];
|
||||
System.out.println("===" + currTest.transformation + "===");
|
||||
try {
|
||||
KeyGenerator kg =
|
||||
KeyGenerator.getInstance(currTest.keyAlgo, p);
|
||||
SecretKey key = kg.generateKey();
|
||||
Cipher c1 = Cipher.getInstance(currTest.transformation, p);
|
||||
Cipher c2 = Cipher.getInstance(currTest.transformation,
|
||||
"SunJCE");
|
||||
|
||||
byte[] plainTxt = new byte[currTest.dataSize];
|
||||
random.nextBytes(plainTxt);
|
||||
System.out.println("Testing inLen = " + plainTxt.length);
|
||||
|
||||
c2.init(Cipher.ENCRYPT_MODE, key);
|
||||
AlgorithmParameters params = c2.getParameters();
|
||||
byte[] answer = c2.doFinal(plainTxt);
|
||||
System.out.println("Encryption tests: START");
|
||||
test(c1, Cipher.ENCRYPT_MODE, key, params, firstBlkSize,
|
||||
plainTxt, answer);
|
||||
System.out.println("Encryption tests: DONE");
|
||||
c2.init(Cipher.DECRYPT_MODE, key, params);
|
||||
byte[] answer2 = c2.doFinal(answer);
|
||||
System.out.println("Decryption tests: START");
|
||||
test(c1, Cipher.DECRYPT_MODE, key, params, firstBlkSize,
|
||||
answer, answer2);
|
||||
System.out.println("Decryption tests: DONE");
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
System.out.println("Skipping unsupported algorithm: " +
|
||||
nsae);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// print out debug info when exception is encountered
|
||||
if (debugBuf != null) {
|
||||
System.out.println(debugBuf.toString());
|
||||
debugBuf = new StringBuffer();
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
private static void test(Cipher cipher, int mode, SecretKey key,
|
||||
AlgorithmParameters params, int firstBlkSize,
|
||||
byte[] in, byte[] answer) throws Exception {
|
||||
// test setup
|
||||
long startTime, endTime;
|
||||
cipher.init(mode, key, params);
|
||||
int outLen = cipher.getOutputSize(in.length);
|
||||
//debugOut("Estimated output size = " + outLen + "\n");
|
||||
|
||||
// test data preparation
|
||||
ByteBuffer inBuf = ByteBuffer.allocate(in.length);
|
||||
inBuf.put(in);
|
||||
inBuf.position(0);
|
||||
ByteBuffer inDirectBuf = ByteBuffer.allocateDirect(in.length);
|
||||
inDirectBuf.put(in);
|
||||
inDirectBuf.position(0);
|
||||
ByteBuffer outBuf = ByteBuffer.allocate(outLen);
|
||||
ByteBuffer outDirectBuf = ByteBuffer.allocateDirect(outLen);
|
||||
|
||||
// test#1: byte[] in + byte[] out
|
||||
//debugOut("Test#1:\n");
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
startTime = System.nanoTime();
|
||||
byte[] temp = cipher.update(in, 0, firstBlkSize);
|
||||
if (temp != null && temp.length > 0) {
|
||||
baos.write(temp, 0, temp.length);
|
||||
}
|
||||
temp = cipher.doFinal(in, firstBlkSize, in.length - firstBlkSize);
|
||||
if (temp != null && temp.length > 0) {
|
||||
baos.write(temp, 0, temp.length);
|
||||
}
|
||||
byte[] testOut1 = baos.toByteArray();
|
||||
endTime = System.nanoTime();
|
||||
perfOut("stream InBuf + stream OutBuf: " +
|
||||
(endTime - startTime));
|
||||
match(testOut1, answer);
|
||||
|
||||
// test#2: Non-direct Buffer in + non-direct Buffer out
|
||||
//debugOut("Test#2:\n");
|
||||
//debugOut("inputBuf: " + inBuf + "\n");
|
||||
//debugOut("outputBuf: " + outBuf + "\n");
|
||||
|
||||
startTime = System.nanoTime();
|
||||
cipher.update(inBuf, outBuf);
|
||||
cipher.doFinal(inBuf, outBuf);
|
||||
endTime = System.nanoTime();
|
||||
perfOut("non-direct InBuf + non-direct OutBuf: " +
|
||||
(endTime - startTime));
|
||||
match(outBuf, answer);
|
||||
|
||||
// test#3: Direct Buffer in + direc Buffer out
|
||||
//debugOut("Test#3:\n");
|
||||
//debugOut("(pre) inputBuf: " + inDirectBuf + "\n");
|
||||
//debugOut("(pre) outputBuf: " + outDirectBuf + "\n");
|
||||
|
||||
startTime = System.nanoTime();
|
||||
cipher.update(inDirectBuf, outDirectBuf);
|
||||
cipher.doFinal(inDirectBuf, outDirectBuf);
|
||||
endTime = System.nanoTime();
|
||||
perfOut("direct InBuf + direct OutBuf: " +
|
||||
(endTime - startTime));
|
||||
|
||||
//debugOut("(post) inputBuf: " + inDirectBuf + "\n");
|
||||
//debugOut("(post) outputBuf: " + outDirectBuf + "\n");
|
||||
match(outDirectBuf, answer);
|
||||
|
||||
// test#4: Direct Buffer in + non-direct Buffer out
|
||||
//debugOut("Test#4:\n");
|
||||
inDirectBuf.position(0);
|
||||
outBuf.position(0);
|
||||
//debugOut("inputBuf: " + inDirectBuf + "\n");
|
||||
//debugOut("outputBuf: " + outBuf + "\n");
|
||||
|
||||
startTime = System.nanoTime();
|
||||
cipher.update(inDirectBuf, outBuf);
|
||||
cipher.doFinal(inDirectBuf, outBuf);
|
||||
endTime = System.nanoTime();
|
||||
perfOut("direct InBuf + non-direct OutBuf: " +
|
||||
(endTime - startTime));
|
||||
match(outBuf, answer);
|
||||
|
||||
// test#5: Non-direct Buffer in + direct Buffer out
|
||||
//debugOut("Test#5:\n");
|
||||
inBuf.position(0);
|
||||
outDirectBuf.position(0);
|
||||
|
||||
//debugOut("(pre) inputBuf: " + inBuf + "\n");
|
||||
//debugOut("(pre) outputBuf: " + outDirectBuf + "\n");
|
||||
|
||||
startTime = System.nanoTime();
|
||||
cipher.update(inBuf, outDirectBuf);
|
||||
cipher.doFinal(inBuf, outDirectBuf);
|
||||
endTime = System.nanoTime();
|
||||
perfOut("non-direct InBuf + direct OutBuf: " +
|
||||
(endTime - startTime));
|
||||
|
||||
//debugOut("(post) inputBuf: " + inBuf + "\n");
|
||||
//debugOut("(post) outputBuf: " + outDirectBuf + "\n");
|
||||
match(outDirectBuf, answer);
|
||||
|
||||
debugBuf = null;
|
||||
}
|
||||
|
||||
private static void perfOut(String msg) {
|
||||
if (debugBuf != null) {
|
||||
debugBuf.append("PERF>" + msg);
|
||||
}
|
||||
}
|
||||
|
||||
private static void debugOut(String msg) {
|
||||
if (debugBuf != null) {
|
||||
debugBuf.append(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private static void match(byte[] b1, byte[] b2) throws Exception {
|
||||
if (b1.length != b2.length) {
|
||||
debugOut("got len : " + b1.length + "\n");
|
||||
debugOut("expect len: " + b2.length + "\n");
|
||||
throw new Exception("mismatch - different length! got: " + b1.length + ", expect: " + b2.length + "\n");
|
||||
} else {
|
||||
for (int i = 0; i < b1.length; i++) {
|
||||
if (b1[i] != b2[i]) {
|
||||
debugOut("got : " + toString(b1) + "\n");
|
||||
debugOut("expect: " + toString(b2) + "\n");
|
||||
throw new Exception("mismatch");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void match(ByteBuffer bb, byte[] answer) throws Exception {
|
||||
byte[] bbTemp = new byte[bb.position()];
|
||||
bb.position(0);
|
||||
bb.get(bbTemp, 0, bbTemp.length);
|
||||
match(bbTemp, answer);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
main(new TestSymmCiphers());
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user