55import java .math .BigInteger ;
66import java .util .Date ;
77
8+ import org .bouncycastle .bcpg .HashUtils ;
89import org .bouncycastle .bcpg .MPInteger ;
910import org .bouncycastle .bcpg .OnePassSignaturePacket ;
1011import org .bouncycastle .bcpg .PublicKeyAlgorithmTags ;
1112import org .bouncycastle .bcpg .SignaturePacket ;
1213import org .bouncycastle .bcpg .SignatureSubpacket ;
1314import org .bouncycastle .bcpg .SignatureSubpacketTags ;
15+ import org .bouncycastle .bcpg .sig .IssuerFingerprint ;
1416import org .bouncycastle .bcpg .sig .IssuerKeyID ;
1517import org .bouncycastle .bcpg .sig .SignatureCreationTime ;
18+ import org .bouncycastle .crypto .CryptoServicesRegistrar ;
1619import org .bouncycastle .openpgp .operator .PGPContentSigner ;
1720import org .bouncycastle .openpgp .operator .PGPContentSignerBuilder ;
1821import org .bouncycastle .util .Arrays ;
@@ -31,6 +34,7 @@ public class PGPSignatureGenerator
3134 //private int providedKeyAlgorithm = -1;
3235 private int providedKeyAlgorithm = -1 ;
3336 private PGPPublicKey signingPubKey ;
37+ private byte [] salt ;
3438
3539 /**
3640 * Create a version 4 signature generator built on the passed in contentSignerBuilder.
@@ -88,8 +92,8 @@ public PGPSignatureGenerator(
8892 /**
8993 * Initialise the generator for signing.
9094 *
91- * @param signatureType
92- * @param key
95+ * @param signatureType type of signature
96+ * @param key private signing key
9397 * @throws PGPException
9498 */
9599 public void init (
@@ -106,12 +110,37 @@ public void init(
106110 sigType = contentSigner .getType ();
107111 lastb = 0 ;
108112
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+ }
113137 }
114138
139+ /**
140+ * Set the hashed signature subpackets.
141+ * Hashed signature subpackets are covered by the signature.
142+ * @param hashedPcks hashed signature subpackets
143+ */
115144 public void setHashedSubpackets (
116145 PGPSignatureSubpacketVector hashedPcks )
117146 {
@@ -124,6 +153,11 @@ public void setHashedSubpackets(
124153 hashed = hashedPcks .toSubpacketArray ();
125154 }
126155
156+ /**
157+ * Set the unhashed signature subpackets.
158+ * Unhashed signature subpackets are not covered by the signature.
159+ * @param unhashedPcks unhashed signature subpackets
160+ */
127161 public void setUnhashedSubpackets (
128162 PGPSignatureSubpacketVector unhashedPcks )
129163 {
@@ -147,7 +181,26 @@ public PGPOnePassSignature generateOnePassVersion(
147181 boolean isNested )
148182 throws PGPException
149183 {
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 );
151204 }
152205
153206 /**
@@ -159,66 +212,51 @@ public PGPOnePassSignature generateOnePassVersion(
159212 public PGPSignature generate ()
160213 throws PGPException
161214 {
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 ();
184216
217+ ByteArrayOutputStream sOut = new ByteArrayOutputStream ();
185218 try
186219 {
220+ // hash the "header"
187221 sOut .write ((byte )version );
188222 sOut .write ((byte )sigType );
189223 sOut .write ((byte )contentSigner .getKeyAlgorithm ());
190224 sOut .write ((byte )contentSigner .getHashAlgorithm ());
191225
226+ // hash signature subpackets
192227 ByteArrayOutputStream hOut = new ByteArrayOutputStream ();
193-
194- for (int i = 0 ; i != hPkts .length ; i ++)
228+ for (int i = 0 ; i != hashed .length ; i ++)
195229 {
196- hPkts [i ].encode (hOut );
230+ hashed [i ].encode (hOut );
197231 }
198-
199232 byte [] data = hOut .toByteArray ();
200233
234+ if (version == SignaturePacket .VERSION_6 )
235+ {
236+ sOut .write ((byte ) (data .length >> 24 ));
237+ sOut .write ((byte ) (data .length >> 16 ));
238+ }
201239 sOut .write ((byte )(data .length >> 8 ));
202240 sOut .write ((byte )data .length );
203241 sOut .write (data );
204- byte [] hData = sOut .toByteArray ();
205242
243+ // hash the "footer"
244+ int dataLen = sOut .toByteArray ().length ;
206245 sOut .write ((byte )version );
207246 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 ));
212251 }
213252 catch (IOException e )
214253 {
215254 throw new PGPException ("exception encoding hashed data." , e );
216255 }
217256
218-
219257 byte [] trailer = sOut .toByteArray ();
220-
221258 blockUpdate (trailer , 0 , trailer .length );
259+ MPInteger [] sigValues ;
222260 switch (contentSigner .getKeyAlgorithm ())
223261 {
224262 case PublicKeyAlgorithmTags .RSA_SIGN :
@@ -253,16 +291,63 @@ public PGPSignature generate()
253291 fingerPrint [0 ] = digest [0 ];
254292 fingerPrint [1 ] = digest [1 ];
255293
256- if (sigValues != null )
294+ SignaturePacket sigPckt ;
295+ if (sigValues != null ) // MPI encoding
257296 {
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 );
260299 }
261- else
300+ else // native encoding
262301 {
263302 // 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+ }
266351 }
267352 }
268353
0 commit comments