Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/main/java/COSE/CryptoContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package COSE;


import java.security.Provider;

/**
* Specify which JCA Provider to use for signing and verifying messages
*/
public class CryptoContext {

private Provider provider;

public CryptoContext(Provider provider) {
this.provider = provider;
}

public Provider getProvider() {
return provider;
}

public void setProvider(Provider provider) {
this.provider = provider;
}

}
45 changes: 26 additions & 19 deletions src/main/java/COSE/Encrypt0Message.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ public class Encrypt0Message extends EncryptCommon {
public Encrypt0Message() {
this(true, true);
}

/**
* Create a Encrypt0Message object. This object corresponds to the encrypt
message format in COSE.
*
*
* @param emitTag is the leading CBOR tag emitted
* @param emitContent is the content emitted
*/
Expand All @@ -38,11 +38,18 @@ public Encrypt0Message(boolean emitTag, boolean emitContent) {
this.emitTag = emitTag;
this.emitContent = emitContent;
}


/**
* Gets the {@link CryptoContext} to set a different JCA Provider
*/
public CryptoContext getCryptoContext() {
return cryptoContext;
}

@Override
public void DecodeFromCBORObject(CBORObject obj) throws CoseException {
if (obj.size() != 3) throw new CoseException("Invalid Encrypt0 structure");

if (obj.get(0).getType() == CBORType.ByteString) {
if (obj.get(0).GetByteString().length == 0) {
rgbProtected = new byte[0];
Expand All @@ -53,54 +60,54 @@ public void DecodeFromCBORObject(CBORObject obj) throws CoseException {
objProtected = CBORObject.DecodeFromBytes(rgbProtected);
if (objProtected.getType() != CBORType.Map) throw new CoseException("Invalid Encrypt0 structure");
}

}
else throw new CoseException("Invalid Encrypt0 structure");

if(obj.get(1).getType() == CBORType.Map) objUnprotected = obj.get(1);
else throw new CoseException("Invalid Encrypt0 structure");

if (obj.get(2).getType() == CBORType.ByteString) rgbEncrypt = obj.get(2).GetByteString();
else if (!obj.get(2).isNull()) throw new CoseException("Invalid Encrypt0 structure");


}

/**
* Internal function used to construct the CBORObject
* Internal function used to construct the CBORObject
* @return the constructed CBORObject
* @throws CoseException if the content has not yet been encrypted
*/
@Override
protected CBORObject EncodeCBORObject() throws CoseException {
if (rgbEncrypt == null) throw new CoseException("Encrypt function not called");

CBORObject obj = CBORObject.NewArray();
if (objProtected.size() > 0) obj.Add(objProtected.EncodeToBytes());
else obj.Add(CBORObject.FromObject(new byte[0]));

obj.Add(objUnprotected);

if (emitContent) obj.Add(rgbEncrypt);
else obj.Add(CBORObject.Null);

return obj;
}

/**
* Decrypt the message using the passed in key.
*
*
* @param rgbKey key for decryption
* @return the decrypted content
* @throws CoseException - Error during decryption
*/
public byte[] decrypt(byte[] rgbKey) throws CoseException {
return super.decryptWithKey(rgbKey);
}

/**
* Encrypt the message using the passed in key.
*
*
* @param rgbKey key used for encryption
* @throws CoseException - Error during decryption
* @throws IllegalStateException - Error during decryption
Expand Down
82 changes: 46 additions & 36 deletions src/main/java/COSE/EncryptCommon.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,35 @@
* @author jimsch
*/
public abstract class EncryptCommon extends Message {

protected CryptoContext cryptoContext = new CryptoContext(null);

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:
Expand All @@ -56,18 +59,18 @@ protected byte[] decryptWithKey(byte[] rgbKey) throws CoseException {
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) {
Expand All @@ -91,10 +94,10 @@ void encryptWithKey(byte[] rgbKey) throws CoseException, IllegalStateException {
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:
Expand All @@ -110,7 +113,7 @@ private int getAES_CCM_IVSize(AlgorithmID alg) throws CoseException {
}
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) {
Expand All @@ -129,14 +132,16 @@ private void AES_CCM_Decrypt(AlgorithmID alg, byte[] rgbKey) throws CoseExceptio
if (iv.GetByteString().length != ivLen) {
throw new CoseException("IV size is incorrect");
}

try {
Cipher cipher = Cipher.getInstance(AES_CCM_SPEC);
Cipher cipher = cryptoContext.getProvider() != null ?
Cipher.getInstance(AES_CCM_SPEC, cryptoContext.getProvider()) :
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);
Expand All @@ -153,14 +158,14 @@ private void AES_CCM_Decrypt(AlgorithmID alg, byte[] rgbKey) throws CoseExceptio
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);
Expand All @@ -177,9 +182,11 @@ private void AES_CCM_Encrypt(AlgorithmID alg, byte[] rgbKey) throws CoseExceptio
throw new CoseException("IV is too long.");
}
}

try {
Cipher cipher = Cipher.getInstance(AES_CCM_SPEC);
Cipher cipher = cryptoContext.getProvider() != null ?
Cipher.getInstance(AES_CCM_SPEC, cryptoContext.getProvider()) :
Cipher.getInstance(AES_CCM_SPEC);
cipher.init(Cipher.ENCRYPT_MODE,
new SecretKeySpec(rgbKey, AES_SPEC),
new GCMParameterSpec(alg.getTagSize(), iv.GetByteString()));
Expand Down Expand Up @@ -217,8 +224,9 @@ private void AES_GCM_Decrypt(AlgorithmID alg, byte[] rgbKey) throws CoseExceptio

try {
// create and prepare cipher
Cipher cipher;
cipher = Cipher.getInstance(AES_GCM_SPEC);
Cipher cipher = cryptoContext.getProvider() != null ?
Cipher.getInstance(AES_GCM_SPEC, cryptoContext.getProvider()) :
Cipher.getInstance(AES_GCM_SPEC);
cipher.init(Cipher.DECRYPT_MODE,
new SecretKeySpec(rgbKey, "AES"),
new GCMParameterSpec(alg.getTagSize(), iv.GetByteString()));
Expand Down Expand Up @@ -249,7 +257,7 @@ private void AES_GCM_Encrypt(AlgorithmID alg, byte[] rgbKey) throws CoseExceptio
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) {
Expand All @@ -266,9 +274,11 @@ private void AES_GCM_Encrypt(AlgorithmID alg, byte[] rgbKey) throws CoseExceptio
throw new CoseException("IV size is incorrect");
}
}

try {
Cipher cipher = Cipher.getInstance(AES_GCM_SPEC);
Cipher cipher = cryptoContext.getProvider() != null ?
Cipher.getInstance(AES_GCM_SPEC, cryptoContext.getProvider()) :
Cipher.getInstance(AES_GCM_SPEC);
cipher.init(Cipher.ENCRYPT_MODE,
new SecretKeySpec(rgbKey, AES_SPEC),
new GCMParameterSpec(alg.getTagSize(), iv.GetByteString()));
Expand All @@ -284,34 +294,34 @@ private void AES_GCM_Encrypt(AlgorithmID alg, byte[] rgbKey) throws CoseExceptio
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) {
Expand All @@ -333,7 +343,7 @@ protected void ProcessCounterSignatures() throws CoseException {
addAttribute(HeaderKeys.CounterSignature, list, Attribute.UNPROTECTED);
}
}

if (counterSign1 != null) {
counterSign1.sign(rgbProtected, rgbEncrypt);
addAttribute(HeaderKeys.CounterSignature0, counterSign1.EncodeToCBORObject(), Attribute.UNPROTECTED);
Expand All @@ -343,7 +353,7 @@ protected void ProcessCounterSignatures() throws CoseException {
public boolean validate(CounterSign1 countersignature) throws CoseException {
return countersignature.validate(rgbProtected, rgbEncrypt);
}

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