MacCommon.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.eclipse.californium.cose;
import com.upokecenter.cbor.CBORObject;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Formatter;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
*
* @author jimsch
*/
public abstract class MacCommon extends Message {
protected byte[] rgbTag;
protected String strContext;
protected SecureRandom random = new SecureRandom();
protected MacCommon() {
super();
}
protected void CreateWithKey(byte[] rgbKey) throws CoseException {
CBORObject algX = findAttribute(CBORObject.FromObject(1)); //HeaderKeys.Algorithm);
AlgorithmID alg = AlgorithmID.FromCBOR(algX);
if (rgbContent == null) throw new CoseException("No Content Specified");
switch (alg) {
case HMAC_SHA_256_64:
case HMAC_SHA_256:
case HMAC_SHA_384:
case HMAC_SHA_512:
rgbTag = HMAC(alg, rgbKey);
break;
case AES_CBC_MAC_128_64:
case AES_CBC_MAC_256_64:
case AES_CBC_MAC_128_128:
case AES_CBC_MAC_256_128:
rgbTag = AES_CBC_MAC(alg, rgbKey);
break;
default:
throw new CoseException("Unsupported MAC Algorithm");
}
ProcessCounterSignatures();
}
protected boolean Validate(byte[] rgbKey) throws CoseException {
boolean f;
int i;
byte[] rgbTest;
CBORObject algX = findAttribute(CBORObject.FromObject(1)); //HeaderKeys.Algorithm);
AlgorithmID alg = AlgorithmID.FromCBOR(algX);
switch (alg) {
case HMAC_SHA_256_64:
case HMAC_SHA_256:
case HMAC_SHA_384:
case HMAC_SHA_512:
rgbTest = HMAC(alg, rgbKey);
break;
case AES_CBC_MAC_128_64:
case AES_CBC_MAC_256_64:
case AES_CBC_MAC_128_128:
case AES_CBC_MAC_256_128:
rgbTest = AES_CBC_MAC(alg, rgbKey);
break;
default:
throw new CoseException("Unsupported MAC Algorithm");
}
if (rgbTest.length != rgbTag.length) return false;
f = true;
for (i=0; i<rgbTest.length; i++) {
f &= (rgbTest[i] == rgbTag[i]);
}
return f;
}
private byte[] BuildContentBytes() {
CBORObject obj = CBORObject.NewArray();
if (rgbProtected == null) {
if (objProtected.size() == 0) rgbProtected = new byte[0];
else rgbProtected = objProtected.EncodeToBytes();
}
obj.Add(strContext);
obj.Add(rgbProtected);
if (externalData != null) obj.Add(CBORObject.FromObject(externalData));
else obj.Add(CBORObject.FromObject(new byte[0]));
obj.Add(rgbContent);
return obj.EncodeToBytes();
}
protected byte[] AES_CBC_MAC(AlgorithmID alg, byte[] rgbKey) throws CoseException
{
if (rgbKey.length != alg.getKeySize() / 8) throw new CoseException("Key is incorrectly sized");
// The requirements from spec
// IV is 128 bits of zeros
// key sizes are 128, 192 and 256 bits
// Authentication tag sizes are 64 and 128 bits
byte[] IV = new byte[128 / 8];
try {
Cipher cbcmac = Cipher.getInstance("AES/CBC/NoPadding");
cbcmac.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(rgbKey, "AES"),
new IvParameterSpec(IV));
byte[] val = BuildContentBytes();
int blockLen = cbcmac.getBlockSize();
int tagLen = alg.getTagSize() / 8;
int dataLen = val.length,
dataPad = 16 - (val.length % 16);
if (dataPad != 16) {
dataLen += dataPad;
}
ByteBuffer input = ByteBuffer.allocate(dataLen);
input.put(val);
input.put(IV, 0, input.remaining());
input.flip();
ByteBuffer output = ByteBuffer.allocate(dataLen);
cbcmac.doFinal(input, output);
val = new byte[alg.getTagSize() / 8];
output.position(output.limit() - blockLen);
output.get(val);
return val;
} catch (NoSuchAlgorithmException ex) {
throw new CoseException("Algorithm not supported", ex);
}
catch (InvalidKeyException ex) {
if (ex.getMessage() == "Illegal key size") {
throw new CoseException("Unsupported key size", ex);
}
throw new CoseException("Mac failure", ex);
} catch (Exception ex) {
throw new CoseException("Mac failure", ex);
}
}
private byte[] HMAC(AlgorithmID alg, byte[] rgbKey) throws CoseException {
String algStr;
switch (alg) {
case HMAC_SHA_256_64:
case HMAC_SHA_256:
algStr = "HmacSHA256";
break;
case HMAC_SHA_384:
algStr = "HmacSHA384";
break;
case HMAC_SHA_512:
algStr = "HmacSHA512";
break;
default:
throw new CoseException("Internal Error");
}
if (rgbKey.length != alg.getKeySize()/8) throw new CoseException("Key is incorrect size");
try {
Mac hmac = Mac.getInstance(algStr);
hmac.init(new SecretKeySpec(rgbKey, algStr));
byte[] val = BuildContentBytes();
val = hmac.doFinal(val);
val = Arrays.copyOfRange(val, 0, alg.getTagSize() / 8);
return val;
} catch (NoSuchAlgorithmException ex) {
throw new CoseException("Algorithm not supported", ex);
} catch (Exception ex) {
throw new CoseException("Mac failure", ex);
}
}
}