Skip to content

Commit 478f51c

Browse files
committed
Merge branch '1743-librepgp-preferredencryptionmodes-signature-subpacket' into 'main'
1743 librepgp preferredencryptionmodes signature subpacket See merge request root/bc-java!22
2 parents c005424 + 680bb44 commit 478f51c

File tree

10 files changed

+308
-10
lines changed

10 files changed

+308
-10
lines changed

pg/src/main/java/org/bouncycastle/bcpg/SignatureSubpacketInputStream.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.bouncycastle.bcpg.sig.IssuerKeyID;
1313
import org.bouncycastle.bcpg.sig.KeyExpirationTime;
1414
import org.bouncycastle.bcpg.sig.KeyFlags;
15+
import org.bouncycastle.bcpg.sig.LibrePGPPreferredEncryptionModes;
1516
import org.bouncycastle.bcpg.sig.NotationData;
1617
import org.bouncycastle.bcpg.sig.PolicyURI;
1718
import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites;
@@ -151,6 +152,8 @@ else if (flags[StreamUtil.flag_partial])
151152
case PREFERRED_HASH_ALGS:
152153
case PREFERRED_SYM_ALGS:
153154
return new PreferredAlgorithms(type, isCritical, isLongLength, data);
155+
case LIBREPGP_PREFERRED_ENCRYPTION_MODES:
156+
return new LibrePGPPreferredEncryptionModes(isCritical, isLongLength, data);
154157
case PREFERRED_AEAD_ALGORITHMS:
155158
return new PreferredAEADCiphersuites(isCritical, isLongLength, data);
156159
case PREFERRED_KEY_SERV:

pg/src/main/java/org/bouncycastle/bcpg/SignatureSubpacketTags.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ public interface SignatureSubpacketTags
3030
int SIGNATURE_TARGET = 31; // signature target
3131
int EMBEDDED_SIGNATURE = 32; // embedded signature
3232
int ISSUER_FINGERPRINT = 33; // issuer key fingerprint
33-
// public static final int PREFERRED_AEAD_ALGORITHMS = 34; // RESERVED since rfc9580
34-
int INTENDED_RECIPIENT_FINGERPRINT = 35; // intended recipient fingerprint
33+
int LIBREPGP_PREFERRED_ENCRYPTION_MODES = 34;
34+
// public static final int PREFERRED_AEAD_ALGORITHMS = 34;// RESERVED since rfc9580
35+
int INTENDED_RECIPIENT_FINGERPRINT = 35; // intended recipient fingerprint
3536
int ATTESTED_CERTIFICATIONS = 37; // attested certifications (RESERVED)
3637
int KEY_BLOCK = 38; // Key Block (RESERVED)
3738
int PREFERRED_AEAD_ALGORITHMS = 39; // preferred AEAD algorithms
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.bouncycastle.bcpg.sig;
2+
3+
import org.bouncycastle.bcpg.SignatureSubpacketTags;
4+
5+
/**
6+
* This is a deprecated LibrePGP signature subpacket with encryption mode numbers to indicate which modes
7+
* the key holder prefers to use with OCB Encrypted Data Packets ({@link org.bouncycastle.bcpg.AEADEncDataPacket}).
8+
* Implementations SHOULD ignore this subpacket and assume {@link org.bouncycastle.bcpg.AEADAlgorithmTags#OCB}.
9+
*/
10+
public class LibrePGPPreferredEncryptionModes
11+
extends PreferredAlgorithms
12+
{
13+
14+
public LibrePGPPreferredEncryptionModes(boolean isCritical, int[] encryptionModes)
15+
{
16+
this(isCritical, false, intToByteArray(encryptionModes));
17+
}
18+
19+
public LibrePGPPreferredEncryptionModes(boolean critical, boolean isLongLength, byte[] data)
20+
{
21+
super(SignatureSubpacketTags.LIBREPGP_PREFERRED_ENCRYPTION_MODES, critical, isLongLength, data);
22+
}
23+
}

pg/src/main/java/org/bouncycastle/bcpg/sig/PreferredAEADCiphersuites.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import org.bouncycastle.bcpg.SignatureSubpacketTags;
55
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
66

7+
import java.util.ArrayList;
8+
import java.util.List;
9+
710
/**
811
* Signature Subpacket containing the AEAD cipher suites (AEAD algorithm, Symmetric Key Algorithm pairs)
912
* preferred by the key holder's implementation.
@@ -153,6 +156,51 @@ private static byte[] requireEven(byte[] encodedCombinations)
153156
return encodedCombinations;
154157
}
155158

159+
/**
160+
* Return a {@link Builder} for constructing a {@link PreferredAEADCiphersuites} packet.
161+
* @param isCritical true if the packet is considered critical.
162+
* @return builder
163+
*/
164+
public static Builder builder(boolean isCritical)
165+
{
166+
return new Builder(isCritical);
167+
}
168+
169+
public static final class Builder
170+
{
171+
172+
private final List<Combination> combinations = new ArrayList<>();
173+
private final boolean isCritical;
174+
175+
private Builder(boolean isCritical)
176+
{
177+
this.isCritical = isCritical;
178+
}
179+
180+
/**
181+
* Add a combination of cipher- and AEAD algorithm to the list of supported ciphersuites.
182+
* @see SymmetricKeyAlgorithmTags for cipher algorithms
183+
* @see AEADAlgorithmTags for AEAD algorithms
184+
* @param symmetricAlgorithmId symmetric cipher algorithm ID
185+
* @param aeadAlgorithmId AEAD algorithm ID
186+
* @return builder
187+
*/
188+
public Builder addCombination(int symmetricAlgorithmId, int aeadAlgorithmId)
189+
{
190+
combinations.add(new Combination(symmetricAlgorithmId, aeadAlgorithmId));
191+
return this;
192+
}
193+
194+
/**
195+
* Build a {@link PreferredAEADCiphersuites} from this builder.
196+
* @return finished packet
197+
*/
198+
public PreferredAEADCiphersuites build()
199+
{
200+
return new PreferredAEADCiphersuites(isCritical, combinations.toArray(new Combination[0]));
201+
}
202+
}
203+
156204
/**
157205
* Algorithm combination of a {@link SymmetricKeyAlgorithmTags} and a {@link AEADAlgorithmTags}.
158206
*/

pg/src/main/java/org/bouncycastle/bcpg/sig/PreferredAlgorithms.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
public class PreferredAlgorithms
2828
extends SignatureSubpacket
2929
{
30-
private static byte[] intToByteArray(
30+
protected static byte[] intToByteArray(
3131
int[] v)
3232
{
3333
byte[] data = new byte[v.length];

pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketGenerator.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
import org.bouncycastle.bcpg.sig.IssuerKeyID;
1616
import org.bouncycastle.bcpg.sig.KeyExpirationTime;
1717
import org.bouncycastle.bcpg.sig.KeyFlags;
18+
import org.bouncycastle.bcpg.sig.LibrePGPPreferredEncryptionModes;
1819
import org.bouncycastle.bcpg.sig.NotationData;
1920
import org.bouncycastle.bcpg.sig.PolicyURI;
21+
import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites;
2022
import org.bouncycastle.bcpg.sig.PreferredAlgorithms;
2123
import org.bouncycastle.bcpg.sig.PreferredKeyServer;
2224
import org.bouncycastle.bcpg.sig.PrimaryUserID;
@@ -192,17 +194,69 @@ public void setPreferredCompressionAlgorithms(boolean isCritical, int[] algorith
192194
}
193195

194196
/**
197+
* This method is BROKEN!
195198
* Specify the preferred AEAD algorithms of this key.
196199
*
197200
* @param isCritical true if should be treated as critical, false otherwise.
198201
* @param algorithms array of algorithms in descending preference
202+
* @deprecated use {@link #setPreferredAEADCiphersuites(boolean, PreferredAEADCiphersuites.Combination[])}
203+
* or {@link #setPreferredLibrePgpEncryptionModes(boolean, int[])} instead.
199204
*/
205+
@Deprecated
200206
public void setPreferredAEADAlgorithms(boolean isCritical, int[] algorithms)
201207
{
202208
packets.add(new PreferredAlgorithms(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS, isCritical,
203209
algorithms));
204210
}
205211

212+
/**
213+
* Specify the preferred OpenPGP AEAD ciphersuites of this key.
214+
*
215+
* @see <a href="https://www.rfc-editor.org/rfc/rfc9580.html#name-preferred-aead-ciphersuites">
216+
* RFC9580: Preferred AEAD Ciphersuites</a>
217+
*
218+
* @param isCritical true, if this packet should be treated as critical, false otherwise.
219+
* @param algorithms array of algorithms in descending preference
220+
*/
221+
public void setPreferredAEADCiphersuites(boolean isCritical, PreferredAEADCiphersuites.Combination[] algorithms)
222+
{
223+
packets.add(new PreferredAEADCiphersuites(isCritical, algorithms));
224+
}
225+
226+
/**
227+
* Specify the preferred OpenPGP AEAD ciphersuites of this key.
228+
*
229+
* @see <a href="https://www.rfc-editor.org/rfc/rfc9580.html#name-preferred-aead-ciphersuites">
230+
* RFC9580: Preferred AEAD Ciphersuites</a>
231+
*
232+
* @param builder builder to build the ciphersuites packet from
233+
*/
234+
public void setPreferredAEADCiphersuites(PreferredAEADCiphersuites.Builder builder)
235+
{
236+
packets.add(builder.build());
237+
}
238+
239+
/**
240+
* Set the preferred encryption modes for LibrePGP keys.
241+
* Note: LibrePGP is not OpenPGP. An application strictly compliant to only the OpenPGP standard will not
242+
* know how to handle LibrePGP encryption modes.
243+
* The LibrePGP spec states that this subpacket shall be ignored and the application shall instead assume
244+
* {@link org.bouncycastle.bcpg.AEADAlgorithmTags#OCB}.
245+
*
246+
* @see <a href="https://www.ietf.org/archive/id/draft-koch-librepgp-01.html#name-preferred-encryption-modes">
247+
* LibrePGP: Preferred Encryption Modes</a>
248+
* @see org.bouncycastle.bcpg.AEADAlgorithmTags for possible algorithms
249+
*
250+
* @param isCritical whether the packet is critical
251+
* @param algorithms list of algorithms
252+
* @deprecated the use of this subpacket is deprecated in LibrePGP
253+
*/
254+
@Deprecated
255+
public void setPreferredLibrePgpEncryptionModes(boolean isCritical, int[] algorithms)
256+
{
257+
packets.add(new LibrePGPPreferredEncryptionModes(isCritical, algorithms));
258+
}
259+
206260
/**
207261
* Specify the preferred key server for the signed user-id / key.
208262
* Note, that the key server might also be a http/ftp etc. URI pointing to the key itself.

pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketVector.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
import org.bouncycastle.bcpg.sig.IssuerKeyID;
1717
import org.bouncycastle.bcpg.sig.KeyExpirationTime;
1818
import org.bouncycastle.bcpg.sig.KeyFlags;
19+
import org.bouncycastle.bcpg.sig.LibrePGPPreferredEncryptionModes;
1920
import org.bouncycastle.bcpg.sig.NotationData;
2021
import org.bouncycastle.bcpg.sig.PolicyURI;
22+
import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites;
2123
import org.bouncycastle.bcpg.sig.PreferredAlgorithms;
2224
import org.bouncycastle.bcpg.sig.PrimaryUserID;
2325
import org.bouncycastle.bcpg.sig.RegularExpression;
@@ -285,6 +287,13 @@ public int[] getPreferredCompressionAlgorithms()
285287
return ((PreferredAlgorithms)p).getPreferences();
286288
}
287289

290+
/**
291+
* This method is BROKEN!
292+
* @deprecated use {@link #getPreferredAEADCiphersuites()} or {@link #getPreferredLibrePgpEncryptionModes()}
293+
* instead.
294+
* @return preferred AEAD Algorithms
295+
*/
296+
@Deprecated
288297
public int[] getPreferredAEADAlgorithms()
289298
{
290299
SignatureSubpacket p = this.getSubpacket(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS);
@@ -297,6 +306,40 @@ public int[] getPreferredAEADAlgorithms()
297306
return ((PreferredAlgorithms)p).getPreferences();
298307
}
299308

309+
/**
310+
* Return the preferred AEAD ciphersuites denoted in the signature.
311+
*
312+
* @return OpenPGP AEAD ciphersuites
313+
*/
314+
public PreferredAEADCiphersuites getPreferredAEADCiphersuites()
315+
{
316+
SignatureSubpacket p = this.getSubpacket(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS);
317+
318+
if (p == null)
319+
{
320+
return null;
321+
}
322+
return (PreferredAEADCiphersuites) p;
323+
}
324+
325+
/**
326+
* Return the preferred LibrePGP encryption modes denoted in the signature.
327+
* Note: The LibrePGP spec states that this subpacket shall be ignored and the application
328+
* shall instead assume {@link org.bouncycastle.bcpg.AEADAlgorithmTags#OCB}.
329+
*
330+
* @return LibrePGP encryption modes
331+
*/
332+
public int[] getPreferredLibrePgpEncryptionModes()
333+
{
334+
SignatureSubpacket p = this.getSubpacket(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS);
335+
336+
if (p == null)
337+
{
338+
return null;
339+
}
340+
return ((LibrePGPPreferredEncryptionModes) p).getPreferences();
341+
}
342+
300343
public int getKeyFlags()
301344
{
302345
SignatureSubpacket p = this.getSubpacket(SignatureSubpacketTags.KEY_FLAGS);
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package org.bouncycastle.bcpg.test;
2+
3+
import org.bouncycastle.bcpg.AEADAlgorithmTags;
4+
import org.bouncycastle.bcpg.SignatureSubpacketTags;
5+
import org.bouncycastle.bcpg.sig.LibrePGPPreferredEncryptionModes;
6+
import org.bouncycastle.util.Arrays;
7+
8+
import java.io.ByteArrayOutputStream;
9+
import java.io.IOException;
10+
11+
public class SignatureSubpacketsTest
12+
extends AbstractPacketTest
13+
{
14+
@Override
15+
public String getName()
16+
{
17+
return "SignatureSubpacketsTest";
18+
}
19+
20+
@Override
21+
public void performTest()
22+
throws Exception
23+
{
24+
testLibrePGPPreferredEncryptionModesSubpacket();
25+
}
26+
27+
private void testLibrePGPPreferredEncryptionModesSubpacket()
28+
throws IOException
29+
{
30+
int[] algorithms = new int[] {AEADAlgorithmTags.EAX, AEADAlgorithmTags.OCB};
31+
LibrePGPPreferredEncryptionModes encModes = new LibrePGPPreferredEncryptionModes(
32+
false, algorithms);
33+
34+
isTrue("Encryption Modes encoding mismatch",
35+
Arrays.areEqual(algorithms, encModes.getPreferences()));
36+
isFalse("Mismatch in critical flag", encModes.isCritical());
37+
38+
// encode to byte array and check correctness
39+
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
40+
encModes.encode(bOut);
41+
42+
isEncodingEqual("Packet encoding mismatch", new byte[]{
43+
3, // length
44+
SignatureSubpacketTags.LIBREPGP_PREFERRED_ENCRYPTION_MODES,
45+
AEADAlgorithmTags.EAX,
46+
AEADAlgorithmTags.OCB
47+
}, bOut.toByteArray());
48+
}
49+
50+
public static void main(String[] args)
51+
{
52+
runTest(new SignatureSubpacketsTest());
53+
}
54+
}

0 commit comments

Comments
 (0)