Skip to content

Commit 7352222

Browse files
committed
Merge branch 'main' of gitlab.cryptoworkshop.com:root/bc-java
2 parents 5fc61e7 + 58713da commit 7352222

27 files changed

+1511
-221
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,23 @@ else if (version == VERSION_6)
6060
// anon recipient
6161
keyVersion = 0;
6262
keyFingerprint = new byte[0];
63+
keyID = 0L;
6364
}
6465
else
6566
{
6667
keyVersion = in.read();
6768
keyFingerprint = new byte[keyInfoLen - 1];
6869
in.readFully(keyFingerprint);
70+
// Derived key-ID from fingerprint
71+
// TODO: Replace with getKeyIdentifier
72+
if (keyVersion == PublicKeyPacket.VERSION_4)
73+
{
74+
keyID = FingerprintUtil.keyIdFromV4Fingerprint(keyFingerprint);
75+
}
76+
else
77+
{
78+
keyID = FingerprintUtil.keyIdFromV6Fingerprint(keyFingerprint);
79+
}
6980
}
7081
}
7182
else

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

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

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.bouncycastle.bcpg;
22

3-
import java.io.ByteArrayInputStream;
43
import java.io.ByteArrayOutputStream;
54
import java.io.EOFException;
65
import java.io.IOException;
@@ -19,6 +18,7 @@ public class SymmetricKeyEncSessionPacket
1918

2019
/**
2120
* Version 5 SKESK packet.
21+
* LibrePGP only.
2222
* Used only with {@link AEADEncDataPacket AED} packets.
2323
*/
2424
public static final int VERSION_5 = 5;
@@ -40,11 +40,12 @@ public class SymmetricKeyEncSessionPacket
4040
private byte[] authTag; // V5, V6
4141

4242
public SymmetricKeyEncSessionPacket(
43-
BCPGInputStream in)
44-
throws IOException
43+
BCPGInputStream in)
44+
throws IOException
4545
{
4646
this(in, false);
4747
}
48+
4849
public SymmetricKeyEncSessionPacket(
4950
BCPGInputStream in,
5051
boolean newPacketFormat)
@@ -63,30 +64,28 @@ public SymmetricKeyEncSessionPacket(
6364
}
6465
else if (version == VERSION_5 || version == VERSION_6)
6566
{
66-
// https://www.rfc-editor.org/rfc/rfc9580.html#section-5.3.2-3.2.1
67-
// SymAlg + AEADAlg + S2KCount + S2K + IV
68-
int next5Fields5Count = in.read();
67+
int ivLen = 0;
68+
if (version == VERSION_6)
69+
{
70+
// https://www.rfc-editor.org/rfc/rfc9580.html#section-5.3.2-3.2.1
71+
// SymAlg + AEADAlg + S2KCount + S2K + IV
72+
ivLen = in.read(); // next5Fields5Count
73+
}
6974
encAlgorithm = in.read();
7075
aeadAlgorithm = in.read();
76+
if (version == VERSION_6)
77+
{
78+
// https://www.rfc-editor.org/rfc/rfc9580.html#section-5.3.2-3.5.1
79+
int s2kOctetCount = in.read();
80+
ivLen = ivLen - 3 - s2kOctetCount;
81+
}
82+
else
83+
{
84+
ivLen = AEADUtils.getIVLength(aeadAlgorithm);
85+
}
7186

72-
// https://www.rfc-editor.org/rfc/rfc9580.html#section-5.3.2-3.5.1
73-
int s2kOctetCount = in.read();
74-
75-
//TODO: use this line to replace the following code?
7687
s2k = new S2K(in);
77-
// s2kBytes = new byte[s2kOctetCount];
78-
// in.readFully(s2kBytes);
79-
// try
80-
// {
81-
// s2k = new S2K(new ByteArrayInputStream(s2kBytes));
82-
// }
83-
// catch (UnsupportedPacketVersionException e)
84-
// {
85-
//
86-
// // We gracefully catch the error.
87-
// }
88-
89-
int ivLen = next5Fields5Count - 3 - s2kOctetCount;
88+
9089
iv = new byte[ivLen]; // also called nonce
9190
if (in.read(iv) != iv.length)
9291
{
@@ -108,7 +107,6 @@ else if (version == VERSION_5 || version == VERSION_6)
108107
{
109108
throw new UnsupportedPacketVersionException("Unsupported PGP symmetric-key encrypted session key packet version encountered: " + version);
110109
}
111-
112110
}
113111

114112
/**
@@ -361,4 +359,4 @@ else if (version == VERSION_5 || version == VERSION_6)
361359

362360
out.writePacket(hasNewPacketFormat(), SYMMETRIC_KEY_ENC_SESSION, bOut.toByteArray());
363361
}
364-
}
362+
}
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/PGPPublicKey.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ else if (publicPk.getVersion() == PublicKeyPacket.VERSION_4)
7070
{
7171
this.keyID = Pack.bigEndianToLong(fingerprint, fingerprint.length - 8);
7272
}
73-
else if (publicPk.getVersion() == PublicKeyPacket.VERSION_6)
73+
else if (publicPk.getVersion() == PublicKeyPacket.LIBREPGP_5 || publicPk.getVersion() == PublicKeyPacket.VERSION_6)
7474
{
7575
this.keyID = Pack.bigEndianToLong(fingerprint, 0);
7676
}

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

Lines changed: 78 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,13 @@ public int getSymmetricAlgorithm(
8484
{
8585
if (keyData.getVersion() == PublicKeyEncSessionPacket.VERSION_3)
8686
{
87-
byte[] plain = dataDecryptorFactory.recoverSessionData(keyData.getAlgorithm(), keyData.getEncSessionKey());
87+
byte[] plain = dataDecryptorFactory.recoverSessionData(keyData, encData);
8888
// symmetric cipher algorithm is stored in first octet of session data
8989
return plain[0];
9090
}
9191
else if (keyData.getVersion() == PublicKeyEncSessionPacket.VERSION_6)
9292
{
93-
// PKESK v5 stores the cipher algorithm in the SEIPD v2 packet fields.
93+
// PKESK v6 stores the cipher algorithm in the SEIPD v2 packet fields.
9494
return ((SymmetricEncIntegrityPacket)encData).getCipherAlgorithm();
9595
}
9696
else
@@ -110,16 +110,57 @@ public PGPSessionKey getSessionKey(
110110
PublicKeyDataDecryptorFactory dataDecryptorFactory)
111111
throws PGPException
112112
{
113-
byte[] sessionData = dataDecryptorFactory.recoverSessionData(keyData.getAlgorithm(), keyData.getEncSessionKey());
114-
if (keyData.getAlgorithm() == PublicKeyAlgorithmTags.X25519 || keyData.getAlgorithm() == PublicKeyAlgorithmTags.X448)
113+
byte[] sessionInfo = dataDecryptorFactory.recoverSessionData(keyData, encData);
114+
115+
// Confirm and discard checksum
116+
if (containsChecksum(keyData.getAlgorithm()))
117+
{
118+
if (!confirmCheckSum(sessionInfo))
119+
{
120+
throw new PGPException("Key checksum failed.");
121+
}
122+
sessionInfo = Arrays.copyOf(sessionInfo, sessionInfo.length - 2);
123+
}
124+
125+
byte[] sessionKey = Arrays.copyOfRange(sessionInfo, 1, sessionInfo.length);
126+
int algorithm;
127+
128+
// OCB (LibrePGP v5 style AEAD)
129+
if (encData instanceof AEADEncDataPacket)
115130
{
116-
return new PGPSessionKey(sessionData[0] & 0xff, Arrays.copyOfRange(sessionData, 1, sessionData.length));
131+
algorithm = ((AEADEncDataPacket) encData).getAlgorithm();
132+
}
133+
134+
// SEIPD (OpenPGP v4 / OpenPGP v6)
135+
else if (encData instanceof SymmetricEncIntegrityPacket)
136+
{
137+
SymmetricEncIntegrityPacket seipd = (SymmetricEncIntegrityPacket) encData;
138+
if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_1)
139+
{
140+
algorithm = sessionInfo[0];
141+
}
142+
else if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_2)
143+
{
144+
algorithm = seipd.getCipherAlgorithm();
145+
}
146+
else
147+
{
148+
throw new UnsupportedPacketVersionException("Unsupported SEIPD packet version: " + seipd.getVersion());
149+
}
117150
}
118-
if (!confirmCheckSum(sessionData))
151+
// SED (Legacy, no integrity protection!)
152+
else
119153
{
120-
throw new PGPKeyValidationException("key checksum failed");
154+
algorithm = sessionInfo[0];
121155
}
122-
return new PGPSessionKey(sessionData[0] & 0xff, Arrays.copyOfRange(sessionData, 1, sessionData.length - 2));
156+
157+
return new PGPSessionKey(algorithm & 0xff, sessionKey);
158+
}
159+
160+
private boolean containsChecksum(int algorithm)
161+
{
162+
return algorithm != PublicKeyAlgorithmTags.X25519 &&
163+
algorithm != PublicKeyAlgorithmTags.X448;
123164
}
124165

125166
/**
@@ -181,13 +222,38 @@ private InputStream getDataStream(
181222
}
182223
else
183224
{
184-
boolean withIntegrityPacket = encData instanceof SymmetricEncIntegrityPacket;
185225

186-
PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(withIntegrityPacket, sessionKey.getAlgorithm(), sessionKey.getKey());
226+
if (encData instanceof SymmetricEncIntegrityPacket)
227+
{
228+
SymmetricEncIntegrityPacket seipd = (SymmetricEncIntegrityPacket) encData;
229+
// SEIPD v1 (OpenPGP v4)
230+
if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_1)
231+
{
232+
PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(true, sessionKey.getAlgorithm(), sessionKey.getKey());
187233

188-
BCPGInputStream encIn = encData.getInputStream();
234+
BCPGInputStream encIn = encData.getInputStream();
189235

190-
processSymmetricEncIntegrityPacketDataStream(withIntegrityPacket, dataDecryptor, encIn);
236+
processSymmetricEncIntegrityPacketDataStream(true, dataDecryptor, encIn);
237+
}
238+
// SEIPD v2 (OpenPGP v6 AEAD)
239+
else
240+
{
241+
PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(seipd, sessionKey);
242+
243+
BCPGInputStream encIn = encData.getInputStream();
244+
245+
encStream = new BCPGInputStream(dataDecryptor.getInputStream(encIn));
246+
}
247+
}
248+
// SED (Symmetrically Encrypted Data without Integrity Protection; Deprecated)
249+
else
250+
{
251+
PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(false, sessionKey.getAlgorithm(), sessionKey.getKey());
252+
253+
BCPGInputStream encIn = encData.getInputStream();
254+
255+
processSymmetricEncIntegrityPacketDataStream(false, dataDecryptor, encIn);
256+
}
191257

192258
//
193259
// some versions of PGP appear to produce 0 for the extra

0 commit comments

Comments
 (0)