36
36
37
37
38
38
/**
39
- * This class extends your basic Merkle tree to
40
- * incorporate the block name at each node, so that
39
+ * This class extends the basic MerkleTree for use in CCN.
40
+ * It incorporates the CCN ContentName for an object at each node, so that
41
41
* names are authenticated as well as content in a
42
42
* way that intermediary CCN nodes can verify.
43
43
*
44
- * For each content node in the CCNMerkleTree, we compute its
45
- * digest in the same way we would compute the digest of a leaf
46
- * node for signing (incorporating the name, authentication metadata,
47
- * and content). We then combine all these together into a MerkleTree,
44
+ * For each leaf node in the CCNMerkleTree, we compute its
45
+ * digest in exactly the same way we would compute the digest of a ContentObject
46
+ * node for signing on its own (incorporating the name, authentication metadata,
47
+ * and content). We then combine all these leaf digests together into a MerkleTree,
48
48
* and sign the root node.
49
49
*
50
50
* To generate a leaf block digest, therefore, we need to know
51
51
* - the content of the block
52
- * - the name for the block (which, for fragmented content, includes the fragment
52
+ * - the name for the block (which, for segmented content, includes the segmented
53
53
* number. If we're buffering content and building trees per buffer, the
54
54
* fragment numbers may carry across buffers (e.g. leaf 0 of this tree might
55
- * be fragment 37 of the content as a whole)
55
+ * be fragment 37 of the content as a whole)
56
+ *
56
57
* - the authentication metadata. In the case of fragmented content, this is
57
58
* likely to be the same for all blocks. In the case of other content, the
58
59
* publisher is likely to be the same, but the timestamp and even maybe the
59
60
* type could be different -- i.e. you could use a CCNMerkleTree to amortize
60
61
* signature costs over any collection of data, not just a set of fragments.
61
62
*
62
- * So, we either need to hand in all the names, or a function to call to get
63
- * the name for each block.
63
+ * So, we either need to hand in all the names, or have a function to call to get
64
+ * the name for each block.
65
+ *
66
+ * Note: There is no requirement that a CCNMerkleTree be built only from the segments
67
+ * of a single piece of content, although that is the most common use. One
68
+ * can build and verify a CCNMerkleTree built out of an arbitrary set of
69
+ * ContentObjects; this may be a useful way of limiting the number of
70
+ * signatures generated on constrained platforms. Eventually the CCNSegmenter
71
+ * will be extended to handle such collections of arbitrary objects.
72
+ *
64
73
*/
65
74
public class CCNMerkleTree extends MerkleTree {
66
75
@@ -70,15 +79,15 @@ public class CCNMerkleTree extends MerkleTree {
70
79
ContentObject [] _segmentObjects = null ;
71
80
72
81
/**
73
- * Build a CCNMerkleTree from a set of leaf content objects .
82
+ * Build a CCNMerkleTree from a set of leaf ContentObjects .
74
83
* @param contentObjects must be at least 2 blocks, or will throw IllegalArgumentException.
75
- * @param signingKey key to sign root with
84
+ * @param signingKey key to sign the root with
76
85
* @throws NoSuchAlgorithmException if key or DEFAULT_DIGEST_ALGORITHM are unknown
77
86
* @throws InvalidKeyException if signingKey is invalid
78
87
* @throws SignatureException if we cannot sign
79
88
*/
80
89
public CCNMerkleTree (ContentObject [] contentObjects ,
81
- PrivateKey signingKey ) throws NoSuchAlgorithmException , InvalidKeyException , SignatureException {
90
+ PrivateKey signingKey ) throws NoSuchAlgorithmException , InvalidKeyException , SignatureException {
82
91
83
92
super (CCNDigestHelper .DEFAULT_DIGEST_ALGORITHM , ((null != contentObjects ) ? contentObjects .length : 0 ));
84
93
_segmentObjects = contentObjects ;
@@ -115,7 +124,12 @@ public ContentName segmentName(int leafIndex) {
115
124
return _segmentObjects [leafIndex ].name ();
116
125
return null ;
117
126
}
118
-
127
+
128
+ /**
129
+ * Return the SignedInfo for a given segment.
130
+ * @param leafIndex the index of the leaf whose SignedInfo we want
131
+ * @return the SignedInfo
132
+ */
119
133
public SignedInfo segmentSignedInfo (int leafIndex ) {
120
134
if ((leafIndex < 0 ) || (leafIndex > _segmentObjects .length ))
121
135
throw new IllegalArgumentException ("Index out of range!" );
@@ -125,7 +139,12 @@ public SignedInfo segmentSignedInfo(int leafIndex) {
125
139
}
126
140
return null ;
127
141
}
128
-
142
+
143
+ /**
144
+ * Set the signature for a particular segment.
145
+ * @param leafIndex the leaf segment to set the signature for
146
+ * @return the Signature
147
+ */
129
148
public Signature segmentSignature (int leafIndex ) {
130
149
if ((leafIndex < 0 ) || (leafIndex > _segmentObjects .length ))
131
150
throw new IllegalArgumentException ("Index out of range!" );
@@ -141,36 +160,74 @@ public Signature segmentSignature(int leafIndex) {
141
160
}
142
161
143
162
/**
144
- * Sets the signatures of all the blockObjects.
145
- * TODO DKS refactor this class to remove unused stuff.
163
+ * Sets the signatures of all the contained ContentObjects.
146
164
*/
147
165
public void setSignatures () {
148
166
for (int i =0 ; i < numLeaves (); ++i ) {
149
167
segmentSignature (i ); // DKS TODO refactor, sets signature as a side effect
150
168
}
151
169
}
152
-
170
+
171
+ /**
172
+ * A version of initializeTree to go with the CCNMerkleTree(ContentObject []) constructor.
173
+ * @param contentObjects objects to build into the tree
174
+ * @throws NoSuchAlgorithmException if the default digest algorithm unknown
175
+ */
153
176
protected void initializeTree (ContentObject [] contentObjects ) throws NoSuchAlgorithmException {
154
177
if (contentObjects .length < numLeaves ())
155
178
throw new IllegalArgumentException ("MerkleTree: cannot build tree from more blocks than given! Have " + contentObjects .length + " blocks, asked to use: " + (numLeaves ()));
156
179
157
180
computeLeafValues (contentObjects );
158
181
computeNodeValues ();
159
182
}
160
-
183
+
184
+ /**
185
+ * Construct the Signature for a given leaf. This is composed of the rootSignature(),
186
+ * which is the same for all nodes, and the DER encoded MerklePath for this leaf as the
187
+ * witness.
188
+ * @param leafIndex the leaf to compute the signature for
189
+ * @return the signature
190
+ */
161
191
protected Signature computeSignature (int leafIndex ) {
162
192
MerklePath path = path (leafIndex );
163
193
return new Signature (path .derEncodedPath (), rootSignature ());
164
194
}
165
-
195
+
196
+ /**
197
+ * Compute the signature on the root node. It's already a digest, so in
198
+ * theory we could just wrap it up in some PKCS#1 padding, encrypt it
199
+ * with our private key, and voila! A signature. But there are basically
200
+ * know crypto software packages that provide signature primitives that take
201
+ * already-digested data and just do the padding and encryption, and so we'd
202
+ * be asking anyone attepmpting to implement CCN MHT signing (including ourselves)
203
+ * to re-implement a very complicated wheel, across a number of signature algorithms.
204
+ * We might also want to sign with a key that does not support the digest algorithm
205
+ * we used to compute the root (for example, DSA).
206
+ * So take the computationally very slightly more expensive, but vastly simpler
207
+ * (implementation-wise) approach of taking our digest and signing it with
208
+ * a standard signing API -- which means digesting it one more time for the
209
+ * signature. So we sign (digest + encrypt) the root digest.
210
+ *
211
+ * @param root the root digest to sign
212
+ * @param signingKey the key to sign with
213
+ * @return the bytes of the signature
214
+ * @throws InvalidKeyException
215
+ * @throws SignatureException
216
+ * @throws NoSuchAlgorithmException
217
+ */
166
218
protected static byte [] computeRootSignature (byte [] root , PrivateKey signingKey ) throws InvalidKeyException , SignatureException , NoSuchAlgorithmException {
167
219
// Given the root of the authentication tree, compute a signature over it
168
220
// Right now, this will digest again. It's actually quite hard to get at the raw
169
221
// signature guts for various platforms to avoid re-digesting; too dependent on
170
222
// the sig alg used.
171
223
return CCNSignatureHelper .sign (null , root , signingKey );
172
224
}
173
-
225
+
226
+ /**
227
+ * Compute the leaf values of the ContentObjects in this tree
228
+ * @param contentObjects the content
229
+ * @throws NoSuchAlgorithmException if the digestAlgorithm unknown
230
+ */
174
231
protected void computeLeafValues (ContentObject [] contentObjects ) throws NoSuchAlgorithmException {
175
232
// Hash the leaves
176
233
for (int i =0 ; i < numLeaves (); ++i ) {
@@ -185,11 +242,12 @@ protected void computeLeafValues(ContentObject [] contentObjects) throws NoSuchA
185
242
* We need to incorporate the name of the content block
186
243
* and the signedInfo into the leaf digest of the tree.
187
244
* Essentially, we want the leaf digest to be the same thing
188
- * we would use for signing a stand-alone leaf.
189
- * @param leafIndex
190
- * @param contentBlocks
191
- * @return
192
- * @throws
245
+ * we would use for signing a stand-alone ContentObject.
246
+ * @param leafIndex the index of the leaf to sign
247
+ * @param content the content array containing the leaf content
248
+ * @param offset the offset into content where the leaf start
249
+ * @param length the length of content for this leaf
250
+ * @return the block digest
193
251
*/
194
252
@ Override
195
253
protected byte [] computeBlockDigest (int leafIndex , byte [] content , int offset , int length ) {
0 commit comments