Skip to content

Commit

Permalink
Fix decryption of SEIPD2 packets using PKESK6
Browse files Browse the repository at this point in the history
  • Loading branch information
vanitasvitae committed Aug 7, 2024
1 parent c46bd49 commit f5691b6
Show file tree
Hide file tree
Showing 4 changed files with 366 additions and 179 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ public class PGPPublicKeyEncryptedData
}

private boolean confirmCheckSum(
byte[] sessionInfo)
byte[] sessionInfo)
{
int check = 0;

for (int i = 1; i != sessionInfo.length - 2; i++)
{
check += sessionInfo[i] & 0xff;
Expand Down Expand Up @@ -72,7 +71,7 @@ public int getSymmetricAlgorithm(
{
if (keyData.getVersion() == PublicKeyEncSessionPacket.VERSION_3)
{
byte[] plain = dataDecryptorFactory.recoverSessionData(keyData.getAlgorithm(), keyData.getEncSessionKey());
byte[] plain = dataDecryptorFactory.recoverSessionData(keyData, encData);
// symmetric cipher algorithm is stored in first octet of session data
return plain[0];
}
Expand All @@ -98,16 +97,60 @@ public PGPSessionKey getSessionKey(
PublicKeyDataDecryptorFactory dataDecryptorFactory)
throws PGPException
{
byte[] sessionData = dataDecryptorFactory.recoverSessionData(keyData.getAlgorithm(), keyData.getEncSessionKey());
if (keyData.getAlgorithm() == PublicKeyAlgorithmTags.X25519 || keyData.getAlgorithm() == PublicKeyAlgorithmTags.X448)
byte[] sessionInfo = dataDecryptorFactory.recoverSessionData(keyData, encData);
if (containsChecksum(keyData.getAlgorithm()))
{
if (!confirmCheckSum(sessionInfo))
{
throw new PGPException("Key checksum failed.");
}
sessionInfo = Arrays.copyOf(sessionInfo, sessionInfo.length - 2);
}


byte[] sessionKey;
int algorithm;

// OCB (LibrePGP v5 style AEAD)
if (encData instanceof AEADEncDataPacket)
{
return new PGPSessionKey(sessionData[0] & 0xff, Arrays.copyOfRange(sessionData, 1, sessionData.length));
algorithm = ((AEADEncDataPacket) encData).getAlgorithm();
sessionKey = Arrays.copyOfRange(sessionInfo, 1, sessionInfo.length);
}
if (!confirmCheckSum(sessionData))

// SEIPD (OpenPGP v4 / OpenPGP v6)
else if (encData instanceof SymmetricEncIntegrityPacket)
{
throw new PGPKeyValidationException("key checksum failed");
SymmetricEncIntegrityPacket seipd = (SymmetricEncIntegrityPacket) encData;
if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_1)
{
algorithm = sessionInfo[0];
sessionKey = Arrays.copyOfRange(sessionInfo, 1, sessionInfo.length);
}
else if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_2)
{
algorithm = seipd.getCipherAlgorithm();
sessionKey = Arrays.copyOfRange(sessionInfo, 1, sessionInfo.length);
}
else
{
throw new UnsupportedPacketVersionException("Unsupported SEIPD packet version: " + seipd.getVersion());
}
}
return new PGPSessionKey(sessionData[0] & 0xff, Arrays.copyOfRange(sessionData, 1, sessionData.length - 2));
// SED (Legacy, no integrity protection!)
else
{
algorithm = sessionInfo[0];
sessionKey = Arrays.copyOfRange(sessionInfo, 1, sessionInfo.length);
}

return new PGPSessionKey(algorithm & 0xff, sessionKey);
}

private boolean containsChecksum(int algorithm)
{
return algorithm != PublicKeyAlgorithmTags.X25519 &&
algorithm != PublicKeyAlgorithmTags.X448;
}

/**
Expand Down Expand Up @@ -169,13 +212,38 @@ private InputStream getDataStream(
}
else
{
boolean withIntegrityPacket = encData instanceof SymmetricEncIntegrityPacket;

PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(withIntegrityPacket, sessionKey.getAlgorithm(), sessionKey.getKey());
if (encData instanceof SymmetricEncIntegrityPacket)
{
SymmetricEncIntegrityPacket seipd = (SymmetricEncIntegrityPacket) encData;
// SEIPD v1 (OpenPGP v4)
if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_1)
{
PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(true, sessionKey.getAlgorithm(), sessionKey.getKey());

BCPGInputStream encIn = encData.getInputStream();
BCPGInputStream encIn = encData.getInputStream();

processSymmetricEncIntegrityPacketDataStream(withIntegrityPacket, dataDecryptor, encIn);
processSymmetricEncIntegrityPacketDataStream(true, dataDecryptor, encIn);
}
// SEIPD v2 (OpenPGP v6 AEAD)
else
{
PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(seipd, sessionKey);

BCPGInputStream encIn = encData.getInputStream();

encStream = new BCPGInputStream(dataDecryptor.getInputStream(encIn));
}
}
// SED (Symmetrically Encrypted Data without Integrity Protection; Deprecated)
else
{
PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(false, sessionKey.getAlgorithm(), sessionKey.getKey());

BCPGInputStream encIn = encData.getInputStream();

processSymmetricEncIntegrityPacketDataStream(false, dataDecryptor, encIn);
}

//
// some versions of PGP appear to produce 0 for the extra
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
package org.bouncycastle.openpgp.operator;

import org.bouncycastle.bcpg.InputStreamPacket;
import org.bouncycastle.bcpg.PublicKeyEncSessionPacket;
import org.bouncycastle.openpgp.PGPException;

public interface PublicKeyDataDecryptorFactory
extends PGPDataDecryptorFactory
{
byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
byte[] recoverSessionData(PublicKeyEncSessionPacket pkesk, InputStreamPacket encData)
throws PGPException;

/**
* @deprecated use {@link #recoverSessionData(PublicKeyEncSessionPacket, InputStreamPacket)} (PublicKeyEncSessionPacket, InputStreamPacket)} instead.
* @param keyAlgorithm public key algorithm
* @param secKeyData encrypted session key data
* @param pkeskVersion version of the PKESK packet
* @return
* @throws PGPException
*/
byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData, int pkeskVersion)
throws PGPException;

}
Loading

0 comments on commit f5691b6

Please sign in to comment.