package de.persosim.simulator.crypto; import java.math.BigInteger; import de.persosim.simulator.utils.HexString; import de.persosim.simulator.utils.Utils; /** * This class represents a counter to be used in the context of sequence numbers * in secure messaging. The counter is limited to positive numbers including 0. * The default value is 0, the default increment is 1. When exceeding the * maximum value the counter is reset to 0. * * @author slutters * */ public class SendSequenceCounter { // the current value // 0 <= current value <= maxValue protected BigInteger value; // maximum achievable value private BigInteger maxValue; /*--------------------------------------------------------------------------------*/ /** * This constructor constructs a {@link SendSequenceCounter} object * @param value the value to start counting from * @param maxValue the maximum possible value */ public SendSequenceCounter(BigInteger value, BigInteger maxValue) { if(maxValue.compareTo(BigInteger.ZERO) <= 0) {throw new IllegalArgumentException("max value must not be smaller than 1");} this.maxValue = maxValue; if(value.compareTo(BigInteger.ZERO) < 0) {throw new IllegalArgumentException("ssc must not be smaller than 0");} if(value.compareTo(this.maxValue) > 0) {throw new IllegalArgumentException("ssc must not be larger than max value");} this.value = value; } /** * This constructor constructs a {@link SendSequenceCounter} object * @param maxValue the maximum possible value */ public SendSequenceCounter(BigInteger maxValue) { this(BigInteger.ZERO, maxValue); } /** * This constructor constructs a {@link SendSequenceCounter} object * @param value the value to start counting from * @param maxByteLength the maximum byte length representation of the value */ public SendSequenceCounter(BigInteger value, int maxByteLength) { this(value, ((new BigInteger("2")).pow(maxByteLength * 8)).subtract(BigInteger.ONE)); } /** * This constructor constructs a {@link SendSequenceCounter} object * @param maxByteLength the maximum byte length representation of the value */ public SendSequenceCounter(int maxByteLength) { this(BigInteger.ZERO, maxByteLength); } /*--------------------------------------------------------------------------------*/ /** * @return the maxValue */ public BigInteger getMaxValue() { return maxValue; } /** * @return the value */ public BigInteger getValue() { return value; } /** * @return the byteLength */ public int getMaxByteLength() { return (int) (Math.ceil(maxValue.bitLength()/8.0)); } /** * This method increments the current value by 1 */ public void increment() { this.value = this.value.add(BigInteger.ONE); if(this.value.compareTo(this.maxValue) > 0) { this.reset(); } } /** * This method resets the current value to 0 */ public void reset() { this.value = BigInteger.ZERO; } /** * This method returns a byte[] representation of the current value padded * to the length of the byte[] representation of the maximum value. * * @return a byte[] representation of the current value */ public byte[] toByteArray() { byte[] out = Utils.toUnsignedByteArray(this.value); return Utils.padWithLeadingZeroes(out, getMaxByteLength()); } @Override public String toString() { return this.value.toString() + " [" + HexString.encode(toByteArray()) + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((maxValue == null) ? 0 : maxValue.hashCode()); result = prime * result + ((value == null) ? 0 : value.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; SendSequenceCounter other = (SendSequenceCounter) obj; if (maxValue == null) { if (other.maxValue != null) return false; } else if (!maxValue.equals(other.maxValue)) return false; if (value == null) { if (other.value != null) return false; } else if (!value.equals(other.value)) return false; return true; } }