/*
* Copyright 2011 Licel LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.licel.jcardsim.crypto;
import java.math.BigInteger;
import javacard.framework.JCSystem;
import javacard.framework.Util;
import javacard.security.CryptoException;
/**
* This class contains byte array, initialization flag of this
* array and memory type.
*/
public final class ByteContainer {
private byte[] data;
private byte memoryType;
private short length = 0;
/**
* Construct <code>ByteContainer</code>
* with memory type <code>JCSystem.MEMORY_TYPE_PERSISTENT</code>
*/
public ByteContainer() {
this(JCSystem.MEMORY_TYPE_PERSISTENT);
}
/**
* Construct <code>ByteContainer</code>
* with defined memory type
* @param memoryType memoryType from JCSystem.MEMORY_..
*/
public ByteContainer(byte memoryType) {
this.memoryType = memoryType;
}
/**
* Construct <code>ByteContainer</code>
* with memory type <code>JCSystem.MEMORY_TYPE_PERSISTENT</code>
* and fills it by byte representation of <code>BigInteger</code>
* @param bInteger <code>BigInteger</code> object
* @throws java.lang.IllegalArgumentException if bInteger is negative
*/
public ByteContainer(BigInteger bInteger) {
setBigInteger(bInteger);
}
/**
* Construct <code>ByteContainer</code>
* with memory type <code>JCSystem.MEMORY_TYPE_PERSISTENT</code>
* and fills it by defined byte array
* @param buff byte array
* @param offset offset in byte array
* @param length length of data in byte array
*/
public ByteContainer(byte[] buff, short offset, short length) {
setBytes(buff, offset, length);
}
/**
* Fills <code>ByteContainer</code>by byte representation of <code>BigInteger</code>
* @param bInteger <code>BigInteger</code> object
* @throws java.lang.IllegalArgumentException if bInteger is negative
*/
public void setBigInteger(BigInteger bInteger) {
if (bInteger.signum() < 0) {
throw new IllegalArgumentException("Negative bInteger");
}
byte[] array = bInteger.toByteArray();
if (array[0] == 0 && array.length > 1) {
byte[] trimmedArray = new byte[array.length - 1];
System.arraycopy(array, 1, trimmedArray, 0, trimmedArray.length);
setBytes(trimmedArray);
}
else {
setBytes(array);
}
}
/**
* Fills <code>ByteContainer</code>by defined byte array
* @param buff byte array
*/
public void setBytes(byte[] buff) {
setBytes(buff, (short) 0, (short) buff.length);
}
/**
* Fills <code>ByteContainer</code>by defined byte array
* @param buff byte array
* @param offset offset in byte array
* @param length length of data in byte array
*/
public void setBytes(byte[] buff, short offset, short length) {
if (data == null) {
switch (memoryType) {
case JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT:
data = JCSystem.makeTransientByteArray(length, JCSystem.CLEAR_ON_DESELECT);
break;
case JCSystem.MEMORY_TYPE_TRANSIENT_RESET:
data = JCSystem.makeTransientByteArray(length, JCSystem.CLEAR_ON_DESELECT);
break;
default:
data = new byte[length];
break;
}
}
Util.arrayCopy(buff, offset, data, (short) 0, length);
// current length
this.length = length;
}
/**
* Return <code>BigInteger</code> representation of the <code>ByteContainer</code>
* @return BigInteger
*/
public BigInteger getBigInteger() {
if (length == 0) {
CryptoException.throwIt(CryptoException.UNINITIALIZED_KEY);
}
return new BigInteger(1, data);
}
/**
* Return transient plain byte array representation of the <code>ByteContainer</code>
* @param event type of transient byte array
* @return plain byte array
*/
public byte[] getBytes(byte event) {
if (length == 0) {
CryptoException.throwIt(CryptoException.UNINITIALIZED_KEY);
}
byte[] result = JCSystem.makeTransientByteArray(length, event);
getBytes(result, (short) 0);
return result;
}
/**
* Copy byte array representation of the <code>ByteContainer</code>
* @param dest destination byte array
* @param offset destination byte array offset
* @return bytes copied
*/
public short getBytes(byte[] dest, short offset) {
if (length == 0) {
CryptoException.throwIt(CryptoException.UNINITIALIZED_KEY);
}
if (dest.length - offset < length) {
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
}
Util.arrayCopy(data, (short) 0, dest, offset, length);
// https://code.google.com/p/jcardsim/issues/detail?id=14
return length;
}
/**
* Clear internal structure of the <code>ByteContainer</code>
*/
public void clear() {
if (data != null) {
Util.arrayFillNonAtomic(data, (short) 0, (short) data.length, (byte) 0);
}
length = 0;
}
/**
* Reports the initialized state of the container.
* @return <code>true</code> if the container has been initialized
*/
public boolean isInitialized() {
return length > 0;
}
}