Skip to content

Commit 7794342

Browse files
committed
Fix decryption of SEIPD2 packets using PKESK6
1 parent bb19781 commit 7794342

File tree

6 files changed

+371
-188
lines changed

6 files changed

+371
-188
lines changed

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

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,9 @@ public class PGPPublicKeyEncryptedData
3535
}
3636

3737
private boolean confirmCheckSum(
38-
byte[] sessionInfo)
38+
byte[] sessionInfo)
3939
{
4040
int check = 0;
41-
4241
for (int i = 1; i != sessionInfo.length - 2; i++)
4342
{
4443
check += sessionInfo[i] & 0xff;
@@ -72,7 +71,7 @@ public int getSymmetricAlgorithm(
7271
{
7372
if (keyData.getVersion() == PublicKeyEncSessionPacket.VERSION_3)
7473
{
75-
byte[] plain = dataDecryptorFactory.recoverSessionData(keyData.getAlgorithm(), keyData.getEncSessionKey());
74+
byte[] plain = dataDecryptorFactory.recoverSessionData(keyData, encData);
7675
// symmetric cipher algorithm is stored in first octet of session data
7776
return plain[0];
7877
}
@@ -98,16 +97,60 @@ public PGPSessionKey getSessionKey(
9897
PublicKeyDataDecryptorFactory dataDecryptorFactory)
9998
throws PGPException
10099
{
101-
byte[] sessionData = dataDecryptorFactory.recoverSessionData(keyData.getAlgorithm(), keyData.getEncSessionKey());
102-
if (keyData.getAlgorithm() == PublicKeyAlgorithmTags.X25519 || keyData.getAlgorithm() == PublicKeyAlgorithmTags.X448)
100+
byte[] sessionInfo = dataDecryptorFactory.recoverSessionData(keyData, encData);
101+
if (containsChecksum(keyData.getAlgorithm()))
102+
{
103+
if (!confirmCheckSum(sessionInfo))
104+
{
105+
throw new PGPException("Key checksum failed.");
106+
}
107+
sessionInfo = Arrays.copyOf(sessionInfo, sessionInfo.length - 2);
108+
}
109+
110+
111+
byte[] sessionKey;
112+
int algorithm;
113+
114+
// OCB (LibrePGP v5 style AEAD)
115+
if (encData instanceof AEADEncDataPacket)
103116
{
104-
return new PGPSessionKey(sessionData[0] & 0xff, Arrays.copyOfRange(sessionData, 1, sessionData.length));
117+
algorithm = ((AEADEncDataPacket) encData).getAlgorithm();
118+
sessionKey = Arrays.copyOfRange(sessionInfo, 1, sessionInfo.length);
105119
}
106-
if (!confirmCheckSum(sessionData))
120+
121+
// SEIPD (OpenPGP v4 / OpenPGP v6)
122+
else if (encData instanceof SymmetricEncIntegrityPacket)
107123
{
108-
throw new PGPKeyValidationException("key checksum failed");
124+
SymmetricEncIntegrityPacket seipd = (SymmetricEncIntegrityPacket) encData;
125+
if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_1)
126+
{
127+
algorithm = sessionInfo[0];
128+
sessionKey = Arrays.copyOfRange(sessionInfo, 1, sessionInfo.length);
129+
}
130+
else if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_2)
131+
{
132+
algorithm = seipd.getCipherAlgorithm();
133+
sessionKey = Arrays.copyOfRange(sessionInfo, 1, sessionInfo.length);
134+
}
135+
else
136+
{
137+
throw new UnsupportedPacketVersionException("Unsupported SEIPD packet version: " + seipd.getVersion());
138+
}
109139
}
110-
return new PGPSessionKey(sessionData[0] & 0xff, Arrays.copyOfRange(sessionData, 1, sessionData.length - 2));
140+
// SED (Legacy, no integrity protection!)
141+
else
142+
{
143+
algorithm = sessionInfo[0];
144+
sessionKey = Arrays.copyOfRange(sessionInfo, 1, sessionInfo.length);
145+
}
146+
147+
return new PGPSessionKey(algorithm & 0xff, sessionKey);
148+
}
149+
150+
private boolean containsChecksum(int algorithm)
151+
{
152+
return algorithm != PublicKeyAlgorithmTags.X25519 &&
153+
algorithm != PublicKeyAlgorithmTags.X448;
111154
}
112155

113156
/**
@@ -169,13 +212,38 @@ private InputStream getDataStream(
169212
}
170213
else
171214
{
172-
boolean withIntegrityPacket = encData instanceof SymmetricEncIntegrityPacket;
173215

174-
PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(withIntegrityPacket, sessionKey.getAlgorithm(), sessionKey.getKey());
216+
if (encData instanceof SymmetricEncIntegrityPacket)
217+
{
218+
SymmetricEncIntegrityPacket seipd = (SymmetricEncIntegrityPacket) encData;
219+
// SEIPD v1 (OpenPGP v4)
220+
if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_1)
221+
{
222+
PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(true, sessionKey.getAlgorithm(), sessionKey.getKey());
175223

176-
BCPGInputStream encIn = encData.getInputStream();
224+
BCPGInputStream encIn = encData.getInputStream();
177225

178-
processSymmetricEncIntegrityPacketDataStream(withIntegrityPacket, dataDecryptor, encIn);
226+
processSymmetricEncIntegrityPacketDataStream(true, dataDecryptor, encIn);
227+
}
228+
// SEIPD v2 (OpenPGP v6 AEAD)
229+
else
230+
{
231+
PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(seipd, sessionKey);
232+
233+
BCPGInputStream encIn = encData.getInputStream();
234+
235+
encStream = new BCPGInputStream(dataDecryptor.getInputStream(encIn));
236+
}
237+
}
238+
// SED (Symmetrically Encrypted Data without Integrity Protection; Deprecated)
239+
else
240+
{
241+
PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(false, sessionKey.getAlgorithm(), sessionKey.getKey());
242+
243+
BCPGInputStream encIn = encData.getInputStream();
244+
245+
processSymmetricEncIntegrityPacketDataStream(false, dataDecryptor, encIn);
246+
}
179247

180248
//
181249
// some versions of PGP appear to produce 0 for the extra
Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
11
package org.bouncycastle.openpgp.operator;
22

3+
import org.bouncycastle.bcpg.InputStreamPacket;
4+
import org.bouncycastle.bcpg.PublicKeyEncSessionPacket;
35
import org.bouncycastle.openpgp.PGPException;
46

57
public interface PublicKeyDataDecryptorFactory
68
extends PGPDataDecryptorFactory
79
{
8-
byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
10+
byte[] recoverSessionData(PublicKeyEncSessionPacket pkesk, InputStreamPacket encData)
911
throws PGPException;
12+
13+
/**
14+
* @deprecated use {@link #recoverSessionData(PublicKeyEncSessionPacket, InputStreamPacket)} (PublicKeyEncSessionPacket, InputStreamPacket)} instead.
15+
* @param keyAlgorithm public key algorithm
16+
* @param secKeyData encrypted session key data
17+
* @param pkeskVersion version of the PKESK packet
18+
* @return
19+
* @throws PGPException
20+
*/
21+
byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData, int pkeskVersion)
22+
throws PGPException;
23+
1024
}

0 commit comments

Comments
 (0)