All Downloads are FREE. Search and download functionalities are using the official Maven repository.

COSE.EncryptCommon Maven / Gradle / Ivy

/*
 * 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 COSE;

import com.upokecenter.cbor.CBORObject;
import com.upokecenter.cbor.CBORType;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 *
 * @author jimsch
 */
public abstract class EncryptCommon extends Message {
    private final String    AES_SPEC = "AES";
    
    private final String    AES_CCM_SPEC = AES_SPEC + "/CCM/NoPadding";
    private final int       AES_CCM_16_IV_LENGTH = 13;
    private final int       AES_CCM_64_IV_LENGTH = 7;
    
    private final String    AES_GCM_SPEC = AES_SPEC + "/GCM/NoPadding";
    private final int       AES_GCM_IV_LENGTH = 96;
    
    protected String context;
    protected byte[] rgbEncrypt;
    SecureRandom random = new SecureRandom();
    
    protected byte[] decryptWithKey(byte[] rgbKey) throws CoseException {
        CBORObject algX = findAttribute(HeaderKeys.Algorithm);
        AlgorithmID alg = AlgorithmID.FromCBOR(algX);
                
        if (rgbEncrypt == null) throw new CoseException("No Encrypted Content Specified");
 
        switch (alg) {
            case AES_GCM_128:
            case AES_GCM_192:
            case AES_GCM_256:
                AES_GCM_Decrypt(alg, rgbKey);
                break;
                
            case AES_CCM_16_64_128:
            case AES_CCM_16_64_256:
            case AES_CCM_64_64_128:
            case AES_CCM_64_64_256:
            case AES_CCM_16_128_128:
            case AES_CCM_16_128_256:
            case AES_CCM_64_128_128:
            case AES_CCM_64_128_256:
                AES_CCM_Decrypt(alg, rgbKey);
                break;
                
            default:
                throw new CoseException("Unsupported Algorithm Specified");
        }
        
        return rgbContent;
    }
    
    void encryptWithKey(byte[] rgbKey) throws CoseException, IllegalStateException {
        CBORObject algX = findAttribute(HeaderKeys.Algorithm);
        AlgorithmID alg = AlgorithmID.FromCBOR(algX);
                
        if (rgbContent == null) throw new CoseException("No Content Specified");

        switch (alg) {
            case AES_GCM_128:
            case AES_GCM_192:
            case AES_GCM_256:
                AES_GCM_Encrypt(alg, rgbKey);
                break;

            case AES_CCM_16_64_128:
            case AES_CCM_16_64_256:
            case AES_CCM_64_64_128:
            case AES_CCM_64_64_256:
            case AES_CCM_16_128_128:
            case AES_CCM_16_128_256:
            case AES_CCM_64_128_128:
            case AES_CCM_64_128_256:
                AES_CCM_Encrypt(alg, rgbKey);
                break;

            default:
                throw new CoseException("Unsupported Algorithm Specified");
        }
        
        ProcessCounterSignatures();
    }
    
    private int getAES_CCM_IVSize(AlgorithmID alg) throws CoseException {
        switch (alg) {
            case AES_CCM_16_64_128:
            case AES_CCM_16_64_256:
            case AES_CCM_16_128_128:
            case AES_CCM_16_128_256:
                return AES_CCM_16_IV_LENGTH;
            case AES_CCM_64_64_128:
            case AES_CCM_64_64_256:
            case AES_CCM_64_128_256:
            case AES_CCM_64_128_128:
                return AES_CCM_64_IV_LENGTH;
        }
        throw new CoseException("Unsupported algorithm: " + alg);
    }
    
    private void AES_CCM_Decrypt(AlgorithmID alg, byte[] rgbKey) throws CoseException, IllegalStateException {
        // validate key
        if (rgbKey.length != alg.getKeySize()/8) {
            throw new CoseException("Key Size is incorrect");
        }

        // obtain and validate IV
        final int ivLen = getAES_CCM_IVSize(alg);
        CBORObject  iv = findAttribute(HeaderKeys.IV);
        if (iv == null) {
            throw new CoseException("Missing IV during decryption");
        }
        if (iv.getType() != CBORType.ByteString) {
            throw new CoseException("IV is incorrectly formed");
        }
        if (iv.GetByteString().length != ivLen) {
            throw new CoseException("IV size is incorrect");
        }
        
        try {
            Cipher      cipher = Cipher.getInstance(AES_CCM_SPEC);
            cipher.init(Cipher.DECRYPT_MODE,
                        new SecretKeySpec(rgbKey, AES_SPEC),
                        new GCMParameterSpec(alg.getTagSize(), iv.GetByteString()));
            cipher.updateAAD(getAADBytes());
            
            rgbContent = new byte[cipher.getOutputSize(rgbEncrypt.length)];
            ByteBuffer  input = ByteBuffer.wrap(rgbEncrypt);
            ByteBuffer  output = ByteBuffer.wrap(rgbContent);
            cipher.doFinal(input, output);
        } 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("Decryption failure", ex);
        } catch (Exception ex) {
            throw new CoseException("Decryption failure", ex);
        }
    }
    
 
    private void AES_CCM_Encrypt(AlgorithmID alg, byte[] rgbKey) throws CoseException, IllegalStateException {
        // validate key
        if (rgbKey.length != alg.getKeySize()/8) {
            throw new CoseException("Key Size is incorrect");
        }
        
        // obtain and validate iv
        CBORObject  iv = findAttribute(HeaderKeys.IV);
        int         ivLen = getAES_CCM_IVSize(alg);
        if (iv == null) {
            byte[] tmp = new byte[ivLen];
            random.nextBytes(tmp);
            iv = CBORObject.FromObject(tmp);
            addAttribute(HeaderKeys.IV, iv, Attribute.UNPROTECTED);
        } else {
            if (iv.getType() != CBORType.ByteString) {
                throw new CoseException("IV is incorreclty formed.");
            }
            if (iv.GetByteString().length > ivLen) {
                throw new CoseException("IV is too long.");
            }
        }
        
        try {
            Cipher      cipher = Cipher.getInstance(AES_CCM_SPEC);
            cipher.init(Cipher.ENCRYPT_MODE,
                        new SecretKeySpec(rgbKey, AES_SPEC),
                        new GCMParameterSpec(alg.getTagSize(), iv.GetByteString()));
            cipher.updateAAD(getAADBytes());

            rgbEncrypt = new byte[cipher.getOutputSize(rgbContent.length)];
            ByteBuffer  input = ByteBuffer.wrap(rgbContent);
            ByteBuffer  output = ByteBuffer.wrap(rgbEncrypt);
            cipher.doFinal(input, output);
        } catch (NoSuchAlgorithmException ex) {
            throw new CoseException("Algorithm not supported", ex);
        } catch (Exception ex) {
            throw new CoseException("Encryption failure", ex);
        }
    }

    private void AES_GCM_Decrypt(AlgorithmID alg, byte[] rgbKey) throws CoseException {
        CBORObject      iv = findAttribute(HeaderKeys.IV);

        // validate key
        if (rgbKey.length != alg.getKeySize()/8) {
            throw new CoseException("Key Size is incorrect");
        }

        // get and validate iv
        if (iv == null) {
            throw new CoseException("Missing IV during decryption");
        }
        if (iv.getType() != CBORType.ByteString) {
            throw new CoseException("IV is incorrectly formed");
        }
        if (iv.GetByteString().length != AES_GCM_IV_LENGTH/8) {
            throw new CoseException("IV size is incorrect");
        }

        try {
            // create and prepare cipher
            Cipher          cipher;
            cipher = Cipher.getInstance(AES_GCM_SPEC);
            cipher.init(Cipher.DECRYPT_MODE,
                        new SecretKeySpec(rgbKey, "AES"),
                        new GCMParameterSpec(alg.getTagSize(), iv.GetByteString()));
            cipher.updateAAD(getAADBytes());

            // setup plaintext output
            rgbContent = new byte[cipher.getOutputSize(rgbEncrypt.length)];

            // decryptit!
            ByteBuffer  input = ByteBuffer.wrap(rgbEncrypt);
            ByteBuffer  output = ByteBuffer.wrap(rgbContent);
            cipher.doFinal(input, output);
        } 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("Decryption failure", ex);
        } catch (Exception ex) {
            throw new CoseException("Decryption failure", ex);
        }
    }

    private void AES_GCM_Encrypt(AlgorithmID alg, byte[] rgbKey) throws CoseException, IllegalStateException {
        // validate key
        if (rgbKey.length != alg.getKeySize()/8) {
            throw new CoseException("Key Size is incorrect");
        }
        
        // obtain and validate iv
        CBORObject  iv = findAttribute(HeaderKeys.IV);
        if (iv == null) {
            // generate IV
            byte[] tmp = new byte[AES_GCM_IV_LENGTH/8];
            random.nextBytes(tmp);
            iv = CBORObject.FromObject(tmp);
            addAttribute(HeaderKeys.IV, iv, PROTECTED);
        } else {
            if (iv.getType() != CBORType.ByteString) {
                throw new CoseException("IV is incorrectly formed");
            }
            if (iv.GetByteString().length != AES_GCM_IV_LENGTH/8) {
                throw new CoseException("IV size is incorrect");
            }
        }
        
        try {
            Cipher      cipher = Cipher.getInstance(AES_GCM_SPEC);
            cipher.init(Cipher.ENCRYPT_MODE,
                        new SecretKeySpec(rgbKey, AES_SPEC),
                        new GCMParameterSpec(alg.getTagSize(), iv.GetByteString()));
            cipher.updateAAD(getAADBytes());

            rgbEncrypt = new byte[cipher.getOutputSize(rgbContent.length)];
            ByteBuffer  input = ByteBuffer.wrap(rgbContent);
            ByteBuffer  output = ByteBuffer.wrap(rgbEncrypt);
            cipher.doFinal(input, output);
        } catch (NoSuchAlgorithmException ex) {
            throw new CoseException("Algorithm not supported", ex);
        } catch (Exception ex) {
            throw new CoseException("Encryption failure", ex);
        }
    }
    
    private byte[] getAADBytes() {
        CBORObject obj = CBORObject.NewArray();
        
        obj.Add(context);
        if (objProtected.size() == 0) rgbProtected = new byte[0];
        else rgbProtected = objProtected.EncodeToBytes();
        obj.Add(rgbProtected);
        obj.Add(CBORObject.FromObject(externalData));
        return obj.EncodeToBytes();
    }
    
    /**
     * Used to obtain the encrypted content for the cases where detached content
     * is requested.
     * 
     * @return bytes of the encrypted content
     * @throws CoseException if content has not been encrypted
     */
    public byte[] getEncryptedContent() throws CoseException{
        if (rgbEncrypt == null) throw new CoseException("No Encrypted Content Specified");
        
        return rgbEncrypt;
    }
    
    /**
     * Set the encrypted content for detached content cases.
     * 
     * @param rgb encrypted content to be used
     */
    public void setEncryptedContent(byte[] rgb) {
        rgbEncrypt = rgb;
    }

    protected void ProcessCounterSignatures() throws CoseException {
        if (!counterSignList.isEmpty()) {
            if (counterSignList.size() == 1) {
                counterSignList.get(0).sign(rgbProtected, rgbEncrypt);
                addAttribute(HeaderKeys.CounterSignature, counterSignList.get(0).EncodeToCBORObject(), Attribute.UNPROTECTED);
            }
            else {
                CBORObject list = CBORObject.NewArray();
                for (CounterSign sig : counterSignList) {
                    sig.sign(rgbProtected, rgbEncrypt);
                    list.Add(sig.EncodeToCBORObject());
                }
                addAttribute(HeaderKeys.CounterSignature, list, Attribute.UNPROTECTED);
            }
        }
        
        if (counterSign1 != null) {
            counterSign1.sign(rgbProtected, rgbEncrypt);
            addAttribute(HeaderKeys.CounterSignature0, counterSign1.EncodeToCBORObject(), Attribute.UNPROTECTED);
        }
    }

    public boolean validate(CounterSign1 countersignature) throws CoseException {
        return countersignature.validate(rgbProtected, rgbEncrypt);
    }
    
    public boolean validate(CounterSign countersignature) throws CoseException {
        return countersignature.validate(rgbProtected, rgbEncrypt);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy