/*
* oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
*
* Copyright (c) 2014, Gluu
*/
package org.xdi.oxauth.model.jwe;
import org.apache.commons.lang.ArrayUtils;
import org.xdi.oxauth.model.crypto.encryption.BlockEncryptionAlgorithm;
import org.xdi.oxauth.model.exception.InvalidParameterException;
import org.xdi.oxauth.model.util.Base64Util;
import org.xdi.oxauth.model.util.Util;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Arrays;
/**
* @author Javier Rojas Blum
* @version July 31, 2016
*/
public class KeyDerivationFunction {
public static byte[] generateCek(byte[] cmk, BlockEncryptionAlgorithm blockEncryptionAlgorithm)
throws UnsupportedEncodingException, NoSuchProviderException, NoSuchAlgorithmException, InvalidParameterException {
if (cmk == null) {
throw new InvalidParameterException("The content master key (CMK) is null");
}
if (blockEncryptionAlgorithm == null) {
throw new InvalidParameterException("The block encryption algorithm is null");
}
if (blockEncryptionAlgorithm != BlockEncryptionAlgorithm.A128CBC_PLUS_HS256
&& blockEncryptionAlgorithm != BlockEncryptionAlgorithm.A256CBC_PLUS_HS512) {
throw new InvalidParameterException("The block encryption algorithm is not supported");
}
byte[] round1 = Base64Util.unsignedToBytes(new int[]{0, 0, 0, 1});
byte[] outputBitSize = null;
if (blockEncryptionAlgorithm != BlockEncryptionAlgorithm.A128CBC_PLUS_HS256) {
outputBitSize = Base64Util.unsignedToBytes(new int[]{0, 0, 0, 128});
} else { //A256CBC_PLUS_HS512
outputBitSize = Base64Util.unsignedToBytes(new int[]{0, 0, 1, 0});
}
byte[] encValue = blockEncryptionAlgorithm.getName().getBytes(Util.UTF8_STRING_ENCODING);
byte[] epu = Base64Util.unsignedToBytes(new int[]{0, 0, 0, 0});
byte[] epv = Base64Util.unsignedToBytes(new int[]{0, 0, 0, 0});
byte[] label = "Encryption".getBytes(Util.UTF8_STRING_ENCODING);
byte[] round1Input = ArrayUtils.addAll(round1, cmk);
round1Input = ArrayUtils.addAll(round1Input, outputBitSize);
round1Input = ArrayUtils.addAll(round1Input, encValue);
round1Input = ArrayUtils.addAll(round1Input, epu);
round1Input = ArrayUtils.addAll(round1Input, epv);
round1Input = ArrayUtils.addAll(round1Input, label);
MessageDigest mda = MessageDigest.getInstance(blockEncryptionAlgorithm.getMessageDiggestAlgorithm(), "BC");
byte[] round1Hash = mda.digest(round1Input);
byte[] cek = Arrays.copyOf(round1Hash, blockEncryptionAlgorithm.getCekLength() / 8);
return cek;
}
public static byte[] generateCik(byte[] cmk, BlockEncryptionAlgorithm blockEncryptionAlgorithm)
throws UnsupportedEncodingException, NoSuchProviderException, NoSuchAlgorithmException, InvalidParameterException {
if (cmk == null) {
throw new InvalidParameterException("The content master key (CMK) is null");
}
if (blockEncryptionAlgorithm == null) {
throw new InvalidParameterException("The block encryption algorithm is null");
}
if (blockEncryptionAlgorithm != BlockEncryptionAlgorithm.A128CBC_PLUS_HS256
&& blockEncryptionAlgorithm != BlockEncryptionAlgorithm.A256CBC_PLUS_HS512) {
throw new InvalidParameterException("The block encryption algorithm is not supported");
}
byte[] round1 = Base64Util.unsignedToBytes(new int[]{0, 0, 0, 1});
byte[] outputBitSize = null;
if (blockEncryptionAlgorithm != BlockEncryptionAlgorithm.A128CBC_PLUS_HS256) {
outputBitSize = Base64Util.unsignedToBytes(new int[]{0, 0, 1, 0});
} else { //A256CBC_PLUS_HS512
outputBitSize = Base64Util.unsignedToBytes(new int[]{0, 0, 2, 0});
}
byte[] encValue = blockEncryptionAlgorithm.getName().getBytes(Util.UTF8_STRING_ENCODING);
byte[] epu = Base64Util.unsignedToBytes(new int[]{0, 0, 0, 0});
byte[] epv = Base64Util.unsignedToBytes(new int[]{0, 0, 0, 0});
byte[] label = "Integrity".getBytes(Util.UTF8_STRING_ENCODING);
byte[] round1Input = ArrayUtils.addAll(round1, cmk);
round1Input = ArrayUtils.addAll(round1Input, outputBitSize);
round1Input = ArrayUtils.addAll(round1Input, encValue);
round1Input = ArrayUtils.addAll(round1Input, epu);
round1Input = ArrayUtils.addAll(round1Input, epv);
round1Input = ArrayUtils.addAll(round1Input, label);
MessageDigest mda = MessageDigest.getInstance(blockEncryptionAlgorithm.getMessageDiggestAlgorithm(), "BC");
byte[] cik = mda.digest(round1Input);
return cik;
}
}