Skip to content

Commit a2ff7ab

Browse files
authored
Merge pull request #30 from jimsch/master
Check point
2 parents e24e6df + 35adff8 commit a2ff7ab

File tree

10 files changed

+336
-31
lines changed

10 files changed

+336
-31
lines changed

pom.xml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,28 @@
6161
<configuration>
6262
<source>1.7</source>
6363
<target>1.7</target>
64+
<showDeprecation>true</showDeprecation>
6465
</configuration>
6566
</plugin>
67+
<plugin>
68+
<groupId>org.jacoco</groupId>
69+
<artifactId>jacoco-maven-plugin</artifactId>
70+
<version>0.7.7.201606060606</version>
71+
<executions>
72+
<execution>
73+
<goals>
74+
<goal>prepare-agent</goal>
75+
</goals>
76+
</execution>
77+
<execution>
78+
<id>report</id>
79+
<phase>prepare-package</phase>
80+
<goals>
81+
<goal>report</goal>
82+
</goals>
83+
</execution>
84+
</executions>
85+
</plugin>
6686
</plugins>
6787
</build>
6888

src/main/java/COSE/Attribute.java

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,32 @@
2222
*/
2323

2424
class Attribute {
25+
/**
26+
* Internal map of protected attributes
27+
*/
2528
protected CBORObject objProtected = CBORObject.NewMap();
29+
30+
/**
31+
* Internal map of unprotected attributes
32+
*/
2633
protected CBORObject objUnprotected = CBORObject.NewMap();
34+
35+
/**
36+
* Internal map of attributes which are not a part of the encoded message.
37+
*/
2738
protected CBORObject objDontSend = CBORObject.NewMap();
39+
40+
/**
41+
* The encoded byte string for the protected attributes. If this variable is
42+
* set then the message was either decoded or as been cryptographically signed/encrypted/maced.
43+
* If it is set, then do not allow objProtected to be modified.
44+
*/
2845
protected byte[] rgbProtected;
46+
47+
/**
48+
* Holder for the external data object that is authenticated as part of the
49+
* message
50+
*/
2951
protected byte[] externalData = new byte[0];
3052

3153
/**
@@ -276,13 +298,40 @@ public CBORObject findAttribute(HeaderKeys label, int where) {
276298
return findAttribute(label.AsCBOR(), where);
277299
}
278300

301+
/**
302+
* Return the entire map of protected attributes
303+
*
304+
* @return the protected attribute map
305+
*/
306+
public CBORObject getProtectedAttributes() {
307+
return objProtected;
308+
}
309+
310+
/**
311+
* Return the entire map of unprotected attributes
312+
*
313+
* @return the unprotected attribute map
314+
*/
315+
public CBORObject getUnprotectedAttributes() {
316+
return objUnprotected;
317+
}
318+
319+
/**
320+
* Return the entire map of do not send attributes
321+
*
322+
* @return the do not send attribute map
323+
*/
324+
public CBORObject getDoNotSendAttributes() {
325+
return objDontSend;
326+
}
327+
279328
/**
280329
* Remove an attribute from the set of all attribute maps.
281330
*
282-
* @param label
331+
* @param label attribute to be removed
283332
* @exception CoseException if integrity protection would be modified.
284333
*/
285-
private void removeAttribute(CBORObject label) throws CoseException {
334+
public void removeAttribute(CBORObject label) throws CoseException {
286335
if (objProtected.ContainsKey(label)) {
287336
if (rgbProtected != null) throw new CoseException("Operation would modify integrity protected attributes");
288337
objProtected.Remove(label);
@@ -291,6 +340,25 @@ private void removeAttribute(CBORObject label) throws CoseException {
291340
if (objDontSend.ContainsKey(label)) objDontSend.Remove(label);
292341
}
293342

343+
/**
344+
* Remove an attribute from the set of all attribute maps.
345+
*
346+
* @param label attribute to be removed
347+
* @throws CoseException
348+
*/
349+
public void removeAttribute(HeaderKeys label) throws CoseException {
350+
removeAttribute(label.AsCBOR());
351+
}
352+
353+
/**
354+
* Get the optional external data field to be authenticated
355+
*
356+
* * @return external authenticated data
357+
*/
358+
public byte[] getExternal() {
359+
return externalData;
360+
}
361+
294362
/**
295363
* Set the optional external data field to be authenticated
296364
*

src/main/java/COSE/EncryptCommon.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import com.upokecenter.cbor.CBORObject;
99
import com.upokecenter.cbor.CBORType;
10-
import java.nio.charset.StandardCharsets;
1110
import java.security.SecureRandom;
1211
import org.bouncycastle.crypto.InvalidCipherTextException;
1312
import org.bouncycastle.crypto.engines.AESFastEngine;
@@ -27,7 +26,7 @@ public abstract class EncryptCommon extends Message {
2726
SecureRandom random = new SecureRandom();
2827

2928
protected byte[] decryptWithKey(byte[] rgbKey) throws CoseException, InvalidCipherTextException {
30-
CBORObject algX = findAttribute(HeaderKeys.Algorithm.AsCBOR());
29+
CBORObject algX = findAttribute(HeaderKeys.Algorithm);
3130
AlgorithmID alg = AlgorithmID.FromCBOR(algX);
3231

3332
if (rgbEncrypt == null) throw new CoseException("No Encrypted Content Specified");
@@ -58,7 +57,7 @@ protected byte[] decryptWithKey(byte[] rgbKey) throws CoseException, InvalidCiph
5857
}
5958

6059
void encryptWithKey(byte[] rgbKey) throws CoseException, IllegalStateException, InvalidCipherTextException {
61-
CBORObject algX = findAttribute(HeaderKeys.Algorithm.AsCBOR());
60+
CBORObject algX = findAttribute(HeaderKeys.Algorithm);
6261
AlgorithmID alg = AlgorithmID.FromCBOR(algX);
6362

6463
if (rgbContent == null) throw new CoseException("No Content Specified");
@@ -172,7 +171,7 @@ private void AES_CCM_Encrypt(AlgorithmID alg, byte[] rgbKey) throws CoseExceptio
172171
}
173172
else {
174173
random.nextBytes(IV);
175-
AddUnprotected(HeaderKeys.IV, CBORObject.FromObject(IV));
174+
addAttribute(HeaderKeys.IV, CBORObject.FromObject(IV), Attribute.UNPROTECTED);
176175
}
177176

178177
if (rgbKey.length != alg.getKeySize()/8) throw new CoseException("Key Size is incorrect");
@@ -223,7 +222,7 @@ private void AES_GCM_Encrypt(AlgorithmID alg, byte[] rgbKey) throws CoseExceptio
223222
if (cn == null) {
224223
IV = new byte[96/8];
225224
random.nextBytes(IV);
226-
AddUnprotected(HeaderKeys.IV, CBORObject.FromObject(IV));
225+
addAttribute(HeaderKeys.IV, CBORObject.FromObject(IV), Attribute.UNPROTECTED);
227226
}
228227
else {
229228
if (cn.getType() != CBORType.ByteString) throw new CoseException("IV is incorrectly formed");

src/main/java/COSE/Message.java

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,33 @@
1010
import java.nio.charset.StandardCharsets;
1111

1212
/**
13+
* The Message class provides a common class that all of the COSE message classes
14+
* inherit from. It provides the function used for decoding all of the known
15+
* messages.
1316
*
1417
* @author jimsch
1518
*/
19+
1620
public abstract class Message extends Attribute {
21+
/**
22+
* Is the tag identifying the message emitted?
23+
*/
1724
protected boolean emitTag = true;
25+
26+
/**
27+
* Is the content emitted as part of the message?
28+
*/
1829
protected boolean emitContent = true;
19-
protected MessageTag messageTag;
20-
protected byte[] rgbContent;
30+
31+
/**
32+
* What message tag identifies this message?
33+
*/
34+
protected MessageTag messageTag = MessageTag.Unknown;
35+
36+
/**
37+
* What is the plain text content of the message.
38+
*/
39+
protected byte[] rgbContent = null;
2140

2241
/**
2342
* Decode a COSE message object. This function assumes that the message
@@ -51,9 +70,9 @@ public static Message DecodeFromBytes(byte[] rgbData, MessageTag defaultTag) thr
5170
if (messageObject.GetTags().length != 1) throw new CoseException("Malformed message - too many tags");
5271

5372
if (defaultTag == MessageTag.Unknown) {
54-
defaultTag = MessageTag.FromInt(messageObject.getOutermostTag().intValue());
73+
defaultTag = MessageTag.FromInt(messageObject.getInnermostTag().intValue());
5574
}
56-
else if (defaultTag != MessageTag.FromInt(messageObject.getOutermostTag().intValue())) {
75+
else if (defaultTag != MessageTag.FromInt(messageObject.getInnermostTag().intValue())) {
5776
throw new CoseException("Passed in tag does not match actual tag");
5877
}
5978
}
@@ -96,13 +115,41 @@ else if (defaultTag != MessageTag.FromInt(messageObject.getOutermostTag().intVal
96115
return msg;
97116

98117
}
99-
118+
119+
/**
120+
* Encode the message to a byte array. This function will force cryptographic operations to be executed as needed.
121+
*
122+
* @return byte encoded object
123+
* @throws CoseException Internal COSE Exception
124+
*/
100125
public byte[] EncodeToBytes() throws CoseException {
101126
return EncodeToCBORObject().EncodeToBytes();
102127
}
103128

129+
/**
130+
* Given a CBOR tree, parse the message. This is an abstract function that is implemented for each different supported COSE message.
131+
*
132+
* @param messageObject CBORObject to be converted to a message.
133+
* @throws CoseException
134+
*/
135+
104136
protected abstract void DecodeFromCBORObject(CBORObject messageObject) throws CoseException;
137+
138+
/**
139+
* Encode the COSE message object to a CBORObject tree. This function call will force cryptographic operations to be executed as needed.
140+
* This is an internal function, as such it does not add the tag on the front and is implemented on a per message object.
141+
*
142+
* @return CBORObject representing the message.
143+
* @throws CoseException
144+
*/
105145
protected abstract CBORObject EncodeCBORObject() throws CoseException;
146+
147+
/**
148+
* Encode the COSE message object to a CBORObject tree. This function call will force cryptographic operations to be executed as needed.
149+
*
150+
* @return CBORObject representing the message.
151+
* @throws CoseException
152+
*/
106153
public CBORObject EncodeToCBORObject() throws CoseException {
107154
CBORObject obj;
108155

@@ -115,17 +162,40 @@ public CBORObject EncodeToCBORObject() throws CoseException {
115162
return obj;
116163
}
117164

165+
/**
166+
* Return the content bytes of the message
167+
*
168+
* @return bytes of the content
169+
*/
118170
public byte[] GetContent() {
119171
return rgbContent;
120172
}
121173

174+
/**
175+
* Does the message current have content?
176+
*
177+
* @return true if it has content
178+
*/
179+
public boolean HasContent() {
180+
return rgbContent != null;
181+
}
182+
183+
/**
184+
* Set the content bytes of the message. If the message was transmitted with
185+
* detached content, this must be called before doing cryptographic processing on the message.
186+
*
187+
* @param rgbData bytes to set as the content
188+
*/
122189
public void SetContent(byte[] rgbData) {
123190
rgbContent = rgbData;
124191
}
125192

193+
/**
194+
* Set the content bytes as a text string. The string will be encoded using UTF8 into a byte string.
195+
*
196+
* @param strData string to set as the content
197+
*/
126198
public void SetContent(String strData) {
127199
rgbContent = strData.getBytes(StandardCharsets.UTF_8);
128200
}
129-
130-
131201
}

src/main/java/COSE/Recipient.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ public void encrypt() throws CoseException, Exception {
234234
byte[] rgbAPU = new byte[256/8];
235235
random = new SecureRandom();
236236
random.nextBytes(rgbAPU);
237-
addAttribute(HeaderKeys.HKDF_Context_PartyU_nonce.AsCBOR(), CBORObject.FromObject(rgbAPU), Attribute.UnprotectedAttributes);
237+
addAttribute(HeaderKeys.HKDF_Context_PartyU_nonce.AsCBOR(), CBORObject.FromObject(rgbAPU), Attribute.UNPROTECTED);
238238
}
239239
rgbKey = ECDH_GenerateSecret(privateKey);
240240
rgbKey = HKDF(rgbKey, 128, AlgorithmID.AES_KW_128, new SHA256Digest());
@@ -255,7 +255,7 @@ public void encrypt() throws CoseException, Exception {
255255
byte[] rgbAPU = new byte[256/8];
256256
random = new SecureRandom();
257257
random.nextBytes(rgbAPU);
258-
addAttribute(HeaderKeys.HKDF_Context_PartyU_nonce.AsCBOR(), CBORObject.FromObject(rgbAPU), Attribute.UnprotectedAttributes);
258+
addAttribute(HeaderKeys.HKDF_Context_PartyU_nonce.AsCBOR(), CBORObject.FromObject(rgbAPU), Attribute.UNPROTECTED);
259259
}
260260
rgbKey = ECDH_GenerateSecret(privateKey);
261261
rgbKey = HKDF(rgbKey, 192, AlgorithmID.AES_KW_192, new SHA256Digest());
@@ -276,7 +276,7 @@ public void encrypt() throws CoseException, Exception {
276276
byte[] rgbAPU = new byte[256/8];
277277
random = new SecureRandom();
278278
random.nextBytes(rgbAPU);
279-
addAttribute(HeaderKeys.HKDF_Context_PartyU_nonce.AsCBOR(), CBORObject.FromObject(rgbAPU), Attribute.UnprotectedAttributes);
279+
addAttribute(HeaderKeys.HKDF_Context_PartyU_nonce.AsCBOR(), CBORObject.FromObject(rgbAPU), Attribute.UNPROTECTED);
280280
}
281281
rgbKey = ECDH_GenerateSecret(privateKey);
282282
rgbKey = HKDF(rgbKey, 256, AlgorithmID.AES_KW_256, new SHA256Digest());
@@ -365,7 +365,7 @@ public byte[] getKey(AlgorithmID algCEK) throws CoseException, Exception {
365365
byte[] rgbAPU = new byte[256/8];
366366
random = new SecureRandom();
367367
random.nextBytes(rgbAPU);
368-
addAttribute(HeaderKeys.HKDF_Context_PartyU_nonce.AsCBOR(), CBORObject.FromObject(rgbAPU), Attribute.UnprotectedAttributes);
368+
addAttribute(HeaderKeys.HKDF_Context_PartyU_nonce.AsCBOR(), CBORObject.FromObject(rgbAPU), Attribute.UNPROTECTED);
369369
}
370370
rgbSecret = ECDH_GenerateSecret(privateKey);
371371
return HKDF(rgbSecret, algCEK.getKeySize(), algCEK, new SHA256Digest());
@@ -376,7 +376,7 @@ public byte[] getKey(AlgorithmID algCEK) throws CoseException, Exception {
376376
byte[] rgbAPU = new byte[512/8];
377377
random = new SecureRandom();
378378
random.nextBytes(rgbAPU);
379-
addAttribute(HeaderKeys.HKDF_Context_PartyU_nonce.AsCBOR(), CBORObject.FromObject(rgbAPU), Attribute.UnprotectedAttributes);
379+
addAttribute(HeaderKeys.HKDF_Context_PartyU_nonce.AsCBOR(), CBORObject.FromObject(rgbAPU), Attribute.UNPROTECTED);
380380
}
381381
rgbSecret = ECDH_GenerateSecret(privateKey);
382382
return HKDF(rgbSecret, algCEK.getKeySize(), algCEK, new SHA512Digest());
@@ -466,7 +466,7 @@ private void ECDH_GenerateEphemeral() throws CoseException
466466
System.arraycopy(rgbEncoded, 1, X, 0, X.length);
467467
epk.Add(KeyKeys.EC2_X.AsCBOR(), CBORObject.FromObject(X));
468468
epk.Add(KeyKeys.EC2_Y.AsCBOR(), CBORObject.FromObject((rgbEncoded[0] & 1) == 1));
469-
AddUnprotected(HeaderKeys.ECDH_EPK, epk);
469+
addAttribute(HeaderKeys.ECDH_EPK, epk, Attribute.UNPROTECTED);
470470

471471
OneKey secretKey = new OneKey();
472472
secretKey.add(KeyKeys.KeyType, KeyKeys.KeyType_EC2);

src/main/java/COSE/SignCommon.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
2020
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
2121
import org.bouncycastle.crypto.signers.ECDSASigner;
22+
import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
2223
import org.bouncycastle.math.ec.ECPoint;
2324

2425
/**
@@ -58,7 +59,7 @@ byte[] computeSignature(byte[] rgbToBeSigned, CipherParameters key) throws CoseE
5859
byte[] rgbDigest = new byte[digest.getDigestSize()];
5960
digest.doFinal(rgbDigest, 0);
6061

61-
ECDSASigner ecdsa = new ECDSASigner();
62+
ECDSASigner ecdsa = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));
6263
ecdsa.init(true, key);
6364
BigInteger[] sig = ecdsa.generateSignature(rgbDigest);
6465

@@ -186,7 +187,7 @@ boolean validateSignature(byte[] rgbToBeSigned, byte[] rgbSignature, CipherParam
186187
}
187188

188189
default:
189-
throw new CoseException("Inernal error");
190+
throw new CoseException("Internal error");
190191
}
191192
}
192193

0 commit comments

Comments
 (0)