package at.gv.egiz.smcc.activation; import iaik.utils.CryptoUtils; import java.security.GeneralSecurityException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; public class RetailCBCMac { /** * Calculates a Retail CBC Mac from the given message. *
* The retail CBC Mac is calculated according to the following * algorithm: *
cbcCipherKeyLen
* bytes of the csk
key and use it to calculate a
* CBC Mac value from the first n-1 blocks of the padded message.
* For CBC Mac calculation initialize the CBC Cipher with an
* IV of all zero bytes.
* off
* @param key the Cipher key
* @param cipherAlg the name of the CBC Cipher algorithm to be used
* @param blockSize the block size of the CBC Cipher
*
* @return the CBC Mac value
*
* @throws NoSuchAlgorithmException if the requested Cipher algorithm
* is not available
* @throws NoSuchProviderException if the IAIK provider is not installed
* @throws InvalidKeyException if the key cannot be used with the Ciphers
* @throws GeneralSecurityException if the Cipher operation fails
*/
static byte[] cbcMac(byte[] paddedMsg,
int off,
int len,
SecretKey key,
String cipherAlg,
int blockSize)
throws NoSuchAlgorithmException,
NoSuchProviderException,
InvalidKeyException,
GeneralSecurityException {
if (paddedMsg == null) {
throw new NullPointerException("Message must not be null!");
}
if (key == null) {
throw new NullPointerException("Key csk must not be null!");
}
Cipher cbcCipher = Cipher.getInstance(cipherAlg+"/CBC/NoPadding", "IAIK");
byte[] iv = new byte[blockSize];
cbcCipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
int finOff = off;
if (len > blockSize) {
finOff = len - blockSize;
cbcCipher.update(paddedMsg, 0, finOff);
}
byte[] mac = cbcCipher.doFinal(paddedMsg, finOff, blockSize);
return mac;
}
/**
* Pads the given message to a multiple of the given blocksize with
* a leading one bit followed by as many zero bits as necessary
*
* @param msg the message to be padded
* @param blockSize the block size
*
* @return the padded message
*/
static byte[] pad(byte[] msg, int blockSize) {
int paddingLen;
byte[] paddedMsg;
int msgLen = msg.length;
if (msgLen == 0) {
paddingLen = blockSize;
} else {
paddingLen = blockSize - msgLen % blockSize;
}
if (paddingLen > 0) {
paddedMsg = new byte[msgLen + paddingLen];
System.arraycopy(msg, 0, paddedMsg, 0, msgLen);
paddedMsg[msgLen] = (byte)0x80;
} else {
paddedMsg = msg;
}
return paddedMsg;
}
}