5
5
import java .math .BigInteger ;
6
6
import java .util .Date ;
7
7
8
+ import org .bouncycastle .bcpg .HashUtils ;
8
9
import org .bouncycastle .bcpg .MPInteger ;
9
10
import org .bouncycastle .bcpg .OnePassSignaturePacket ;
10
11
import org .bouncycastle .bcpg .PublicKeyAlgorithmTags ;
11
12
import org .bouncycastle .bcpg .SignaturePacket ;
12
13
import org .bouncycastle .bcpg .SignatureSubpacket ;
13
14
import org .bouncycastle .bcpg .SignatureSubpacketTags ;
15
+ import org .bouncycastle .bcpg .sig .IssuerFingerprint ;
14
16
import org .bouncycastle .bcpg .sig .IssuerKeyID ;
15
17
import org .bouncycastle .bcpg .sig .SignatureCreationTime ;
18
+ import org .bouncycastle .crypto .CryptoServicesRegistrar ;
16
19
import org .bouncycastle .openpgp .operator .PGPContentSigner ;
17
20
import org .bouncycastle .openpgp .operator .PGPContentSignerBuilder ;
18
21
import org .bouncycastle .util .Arrays ;
@@ -31,6 +34,7 @@ public class PGPSignatureGenerator
31
34
//private int providedKeyAlgorithm = -1;
32
35
private int providedKeyAlgorithm = -1 ;
33
36
private PGPPublicKey signingPubKey ;
37
+ private byte [] salt ;
34
38
35
39
/**
36
40
* Create a version 4 signature generator built on the passed in contentSignerBuilder.
@@ -88,8 +92,8 @@ public PGPSignatureGenerator(
88
92
/**
89
93
* Initialise the generator for signing.
90
94
*
91
- * @param signatureType
92
- * @param key
95
+ * @param signatureType type of signature
96
+ * @param key private signing key
93
97
* @throws PGPException
94
98
*/
95
99
public void init (
@@ -106,12 +110,37 @@ public void init(
106
110
sigType = contentSigner .getType ();
107
111
lastb = 0 ;
108
112
109
- // if (providedKeyAlgorithm >= 0 && providedKeyAlgorithm != contentSigner.getKeyAlgorithm())
110
- // {
111
- // throw new PGPException("key algorithm mismatch");
112
- // }
113
+ if (providedKeyAlgorithm >= 0 && providedKeyAlgorithm != contentSigner .getKeyAlgorithm ())
114
+ {
115
+ throw new PGPException ("key algorithm mismatch" );
116
+ }
117
+
118
+ if (key .getPublicKeyPacket ().getVersion () != version )
119
+ {
120
+ throw new PGPException ("Key version mismatch." );
121
+ }
122
+
123
+ if (version == SignaturePacket .VERSION_6 )
124
+ {
125
+ int saltSize = HashUtils .getV6SignatureSaltSizeInBytes (contentSigner .getHashAlgorithm ());
126
+ salt = new byte [saltSize ];
127
+ CryptoServicesRegistrar .getSecureRandom ().nextBytes (salt );
128
+ try
129
+ {
130
+ sigOut .write (salt );
131
+ }
132
+ catch (IOException e )
133
+ {
134
+ throw new PGPException ("Cannot update signature with salt." );
135
+ }
136
+ }
113
137
}
114
138
139
+ /**
140
+ * Set the hashed signature subpackets.
141
+ * Hashed signature subpackets are covered by the signature.
142
+ * @param hashedPcks hashed signature subpackets
143
+ */
115
144
public void setHashedSubpackets (
116
145
PGPSignatureSubpacketVector hashedPcks )
117
146
{
@@ -124,6 +153,11 @@ public void setHashedSubpackets(
124
153
hashed = hashedPcks .toSubpacketArray ();
125
154
}
126
155
156
+ /**
157
+ * Set the unhashed signature subpackets.
158
+ * Unhashed signature subpackets are not covered by the signature.
159
+ * @param unhashedPcks unhashed signature subpackets
160
+ */
127
161
public void setUnhashedSubpackets (
128
162
PGPSignatureSubpacketVector unhashedPcks )
129
163
{
@@ -147,7 +181,26 @@ public PGPOnePassSignature generateOnePassVersion(
147
181
boolean isNested )
148
182
throws PGPException
149
183
{
150
- return new PGPOnePassSignature (new OnePassSignaturePacket (sigType , contentSigner .getHashAlgorithm (), contentSigner .getKeyAlgorithm (), contentSigner .getKeyID (), isNested ));
184
+ if (version == SignaturePacket .VERSION_6 )
185
+ {
186
+ return new PGPOnePassSignature (v6OPSPacket (isNested ));
187
+ }
188
+ else
189
+ {
190
+ return new PGPOnePassSignature (v3OPSPacket (isNested ));
191
+ }
192
+ }
193
+
194
+ private OnePassSignaturePacket v3OPSPacket (boolean isNested )
195
+ {
196
+ return new OnePassSignaturePacket (sigType , contentSigner .getHashAlgorithm (), contentSigner .getKeyAlgorithm (),
197
+ contentSigner .getKeyID (), isNested );
198
+ }
199
+
200
+ private OnePassSignaturePacket v6OPSPacket (boolean isNested )
201
+ {
202
+ return new OnePassSignaturePacket (sigType , contentSigner .getHashAlgorithm (), contentSigner .getKeyAlgorithm (),
203
+ salt , signingPubKey .getFingerprint (), isNested );
151
204
}
152
205
153
206
/**
@@ -159,66 +212,51 @@ public PGPOnePassSignature generateOnePassVersion(
159
212
public PGPSignature generate ()
160
213
throws PGPException
161
214
{
162
- MPInteger [] sigValues ;
163
- int version = 4 ;
164
- ByteArrayOutputStream sOut = new ByteArrayOutputStream ();
165
- SignatureSubpacket [] hPkts , unhPkts ;
166
-
167
- if (packetNotPresent (hashed , SignatureSubpacketTags .CREATION_TIME ))
168
- {
169
- hPkts = insertSubpacket (hashed , new SignatureCreationTime (false , new Date ()));
170
- }
171
- else
172
- {
173
- hPkts = hashed ;
174
- }
175
-
176
- if (packetNotPresent (hashed , SignatureSubpacketTags .ISSUER_KEY_ID ) && packetNotPresent (unhashed , SignatureSubpacketTags .ISSUER_KEY_ID ))
177
- {
178
- unhPkts = insertSubpacket (unhashed , new IssuerKeyID (false , contentSigner .getKeyID ()));
179
- }
180
- else
181
- {
182
- unhPkts = unhashed ;
183
- }
215
+ prepareSignatureSubpackets ();
184
216
217
+ ByteArrayOutputStream sOut = new ByteArrayOutputStream ();
185
218
try
186
219
{
220
+ // hash the "header"
187
221
sOut .write ((byte )version );
188
222
sOut .write ((byte )sigType );
189
223
sOut .write ((byte )contentSigner .getKeyAlgorithm ());
190
224
sOut .write ((byte )contentSigner .getHashAlgorithm ());
191
225
226
+ // hash signature subpackets
192
227
ByteArrayOutputStream hOut = new ByteArrayOutputStream ();
193
-
194
- for (int i = 0 ; i != hPkts .length ; i ++)
228
+ for (int i = 0 ; i != hashed .length ; i ++)
195
229
{
196
- hPkts [i ].encode (hOut );
230
+ hashed [i ].encode (hOut );
197
231
}
198
-
199
232
byte [] data = hOut .toByteArray ();
200
233
234
+ if (version == SignaturePacket .VERSION_6 )
235
+ {
236
+ sOut .write ((byte ) (data .length >> 24 ));
237
+ sOut .write ((byte ) (data .length >> 16 ));
238
+ }
201
239
sOut .write ((byte )(data .length >> 8 ));
202
240
sOut .write ((byte )data .length );
203
241
sOut .write (data );
204
- byte [] hData = sOut .toByteArray ();
205
242
243
+ // hash the "footer"
244
+ int dataLen = sOut .toByteArray ().length ;
206
245
sOut .write ((byte )version );
207
246
sOut .write ((byte )0xff );
208
- sOut .write ((byte )(hData . length >> 24 ));
209
- sOut .write ((byte )(hData . length >> 16 ));
210
- sOut .write ((byte )(hData . length >> 8 ));
211
- sOut .write ((byte )(hData . length ));
247
+ sOut .write ((byte )(dataLen >> 24 ));
248
+ sOut .write ((byte )(dataLen >> 16 ));
249
+ sOut .write ((byte )(dataLen >> 8 ));
250
+ sOut .write ((byte )(dataLen ));
212
251
}
213
252
catch (IOException e )
214
253
{
215
254
throw new PGPException ("exception encoding hashed data." , e );
216
255
}
217
256
218
-
219
257
byte [] trailer = sOut .toByteArray ();
220
-
221
258
blockUpdate (trailer , 0 , trailer .length );
259
+ MPInteger [] sigValues ;
222
260
switch (contentSigner .getKeyAlgorithm ())
223
261
{
224
262
case PublicKeyAlgorithmTags .RSA_SIGN :
@@ -253,16 +291,63 @@ public PGPSignature generate()
253
291
fingerPrint [0 ] = digest [0 ];
254
292
fingerPrint [1 ] = digest [1 ];
255
293
256
- if (sigValues != null )
294
+ SignaturePacket sigPckt ;
295
+ if (sigValues != null ) // MPI encoding
257
296
{
258
- return new PGPSignature ( new SignaturePacket (sigType , contentSigner .getKeyID (), contentSigner .getKeyAlgorithm (),
259
- contentSigner .getHashAlgorithm (), hPkts , unhPkts , fingerPrint , sigValues ) );
297
+ sigPckt = new SignaturePacket (version , sigType , contentSigner .getKeyID (), contentSigner .getKeyAlgorithm (),
298
+ contentSigner .getHashAlgorithm (), hashed , unhashed , fingerPrint , sigValues , salt );
260
299
}
261
- else
300
+ else // native encoding
262
301
{
263
302
// Ed25519, Ed448 use raw encoding instead of MPI
264
- return new PGPSignature (new SignaturePacket (4 , sigType , contentSigner .getKeyID (), contentSigner .getKeyAlgorithm (),
265
- contentSigner .getHashAlgorithm (), hPkts , unhPkts , fingerPrint , contentSigner .getSignature (), null ));
303
+
304
+ sigPckt = new SignaturePacket (version , sigType , contentSigner .getKeyID (), contentSigner .getKeyAlgorithm (),
305
+ contentSigner .getHashAlgorithm (), hashed , unhashed , fingerPrint , contentSigner .getSignature (), salt );
306
+ }
307
+ return new PGPSignature (sigPckt );
308
+ }
309
+
310
+ protected void prepareSignatureSubpackets ()
311
+ throws PGPException
312
+ {
313
+ switch (version )
314
+ {
315
+ case SignaturePacket .VERSION_4 :
316
+ case SignaturePacket .VERSION_5 :
317
+ {
318
+ // Insert hashed signature creation time if missing
319
+ if (packetNotPresent (hashed , SignatureSubpacketTags .CREATION_TIME ))
320
+ {
321
+ hashed = insertSubpacket (hashed , new SignatureCreationTime (true , new Date ()));
322
+ }
323
+
324
+ // Insert unhashed issuer key-ID if missing
325
+ if (packetNotPresent (hashed , SignatureSubpacketTags .ISSUER_KEY_ID ) && packetNotPresent (unhashed , SignatureSubpacketTags .ISSUER_KEY_ID ))
326
+ {
327
+ unhashed = insertSubpacket (unhashed , new IssuerKeyID (false , contentSigner .getKeyID ()));
328
+ }
329
+
330
+ break ;
331
+ }
332
+
333
+ case SignaturePacket .VERSION_6 :
334
+ {
335
+ // Insert hashed signature creation time if missing
336
+ if (packetNotPresent (hashed , SignatureSubpacketTags .CREATION_TIME ))
337
+ {
338
+ hashed = insertSubpacket (hashed , new SignatureCreationTime (true , new Date ()));
339
+ }
340
+
341
+ // Insert hashed issuer fingerprint subpacket if missing
342
+ if (packetNotPresent (hashed , SignatureSubpacketTags .ISSUER_FINGERPRINT ) &&
343
+ packetNotPresent (unhashed , SignatureSubpacketTags .ISSUER_FINGERPRINT ) &&
344
+ signingPubKey != null )
345
+ {
346
+ hashed = insertSubpacket (hashed , new IssuerFingerprint (true , version , signingPubKey .getFingerprint ()));
347
+ }
348
+
349
+ break ;
350
+ }
266
351
}
267
352
}
268
353
0 commit comments