Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
vanitasvitae committed Jul 28, 2024
1 parent 84536cb commit 592aeaa
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.bouncycastle.bcpg.InputStreamPacket;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyEncSessionPacket;
import org.bouncycastle.bcpg.SymmetricEncDataPacket;
import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.bcpg.UnsupportedPacketVersionException;
Expand Down Expand Up @@ -110,6 +111,18 @@ public PGPSessionKey getSessionKey(
PublicKeyDataDecryptorFactory dataDecryptorFactory)
throws PGPException
{
if (encData instanceof AEADEncDataPacket)
{
return dataDecryptorFactory.recoverSessionKey(keyData, (AEADEncDataPacket) encData);
}

if (encData instanceof SymmetricEncDataPacket)
{
return dataDecryptorFactory.recoverSessionKey(keyData, (SymmetricEncDataPacket) encData);
}

return dataDecryptorFactory.recoverSessionKey(keyData, (SymmetricEncIntegrityPacket) encData);

byte[] sessionData = dataDecryptorFactory.recoverSessionData(keyData.getAlgorithm(), keyData.getEncSessionKey(), getVersion());
if (keyData.getAlgorithm() == PublicKeyAlgorithmTags.X25519 || keyData.getAlgorithm() == PublicKeyAlgorithmTags.X448)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,37 @@
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
{
/**
* Recover the session key.
* The return value is a two-dimensional byte array containing the following information about the session key:
* <ul>
* <li>session-key</li>
* <li>1 or 0 bytes encoding the optionally included symmetric key algorithm</li>
* <li>0 or 2 checksum bytes</li>
* </ul>
* @param pkesk public key encrypted session-key packet
* @param encryptedData SEIPD, SED or OED packet
* @return 2-dimensional byte array.
* @throws PGPException
*/
byte[][] recoverSessionKey(PublicKeyEncSessionPacket pkesk, InputStreamPacket encryptedData)
throws PGPException;

/**
* @deprecated use {@link #recoverSessionKey(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;

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import org.bouncycastle.openpgp.operator.PGPPad;
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
import org.bouncycastle.openpgp.operator.RFC6637Utils;
import org.bouncycastle.pqc.crypto.gemss.GeMSSParameters;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;

Expand All @@ -48,6 +47,98 @@ public BcPublicKeyDataDecryptorFactory(PGPPrivateKey pgpPrivKey)
this.pgpPrivKey = pgpPrivKey;
}

@Override
public byte[][] recoverSessionKey(PublicKeyEncSessionPacket pkesk, InputStreamPacket encData)
throws PGPException
{
if (pkesk.getAlgorithm() != pgpPrivKey.getPublicKeyPacket().getAlgorithm())
{
throw new PGPException("Public-Key algorithm field of the Public-Key Encrypted Session Key Packet" +
" does not match the private keys algorithm.");
}

byte[][] secKeyData = pkesk.getEncSessionKey();

try
{
AsymmetricKeyParameter privKey = KEY_CONVERTER.getPrivateKey(pgpPrivKey);
int keyAlgorithm = pkesk.getAlgorithm();
switch (keyAlgorithm)
{
case PublicKeyAlgorithmTags.X25519:

case PublicKeyAlgorithmTags.X448:
return recoverXSessionData(secKeyData[0], privKey, X448PublicBCPGKey.LENGTH,
HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256, new X448Agreement(),
"X448", new PublicKeyParametersOperation()
{
@Override
public AsymmetricKeyParameter getPublicKeyParameters(byte[] pEnc, int pEncOff)
{
return new X448PublicKeyParameters(pEnc, 0);
}
}, pkesk.getVersion());

case PublicKeyAlgorithmTags.ECDH:
byte[] enc = secKeyData[0];
byte[] pEnc;
byte[] keyEnc;
int pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
assertOutOfRange(2 + pLen + 1, enc);

pEnc = new byte[pLen];
System.arraycopy(enc, 2, pEnc, 0, pLen);

int keyLen = enc[pLen + 2] & 0xff;
assertOutOfRange(2 + pLen + 1 + keyLen, enc);

keyEnc = new byte[keyLen];
System.arraycopy(enc, 2 + pLen + 1, keyEnc, 0, keyLen);

byte[] secret;
RFC6637KDFCalculator rfc6637KDFCalculator;
byte[] userKeyingMaterial;
int symmetricKeyAlgorithm, hashAlgorithm;

ECDHPublicBCPGKey ecPubKey = (ECDHPublicBCPGKey)pgpPrivKey.getPublicKeyPacket().getKey();
// XDH
if (ecPubKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
{
if (pEnc.length != 1 + X25519PublicKeyParameters.KEY_SIZE || 0x40 != pEnc[0])
{
throw new IllegalArgumentException("Invalid Curve25519 public key");
}
// skip the 0x40 header byte.
secret = BcUtil.getSecret(new X25519Agreement(), privKey, new X25519PublicKeyParameters(pEnc, 1));
}
else
{
ECDomainParameters ecParameters = ((ECPrivateKeyParameters)privKey).getParameters();

ECPublicKeyParameters ephPub = new ECPublicKeyParameters(ecParameters.getCurve().decodePoint(pEnc),
ecParameters);

ECDHBasicAgreement agreement = new ECDHBasicAgreement();
agreement.init(privKey);
BigInteger S = agreement.calculateAgreement(ephPub);
secret = BigIntegers.asUnsignedByteArray(agreement.getFieldSize(), S);
}
hashAlgorithm = ecPubKey.getHashAlgorithm();
symmetricKeyAlgorithm = ecPubKey.getSymmetricKeyAlgorithm();
userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pgpPrivKey.getPublicKeyPacket(), new BcKeyFingerprintCalculator());
rfc6637KDFCalculator = new RFC6637KDFCalculator(new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(secret, userKeyingMaterial));

return PGPPad.unpadSessionData(unwrapSessionData(keyEnc, symmetricKeyAlgorithm, key));
}
} catch (InvalidCipherTextException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}


@Override
public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData, int pkeskVersion)
throws PGPException
Expand Down Expand Up @@ -276,7 +367,7 @@ private byte[] recoverXSessionData2(byte[] ephemeralPK,
* @throws PGPException
* @throws InvalidCipherTextException
*/
private byte[] recoverXSessionData(byte[] enc, AsymmetricKeyParameter privKey, int pLen, int hashAlgorithm, int symmetricKeyAlgorithm,
private byte[][] recoverXSessionData(byte[] enc, AsymmetricKeyParameter privKey, int pLen, int hashAlgorithm, int symmetricKeyAlgorithm,
RawAgreement agreement, String algorithmName, PublicKeyParametersOperation pkp, int pkeskVersion)
throws PGPException, InvalidCipherTextException
{
Expand Down Expand Up @@ -311,11 +402,19 @@ private byte[] recoverXSessionData(byte[] enc, AsymmetricKeyParameter privKey, i

if (pkeskVersion == 6)
{
return unwrapped;
return new byte[][] {
unwrapped, // session key
new byte[0], // v6 pkesk does not contain sym-alg (sourced from seipd2 instead)
new byte[0] // X25519, X448 does not include checksum
};
}
else
{
return Arrays.prepend(unwrapped, enc[pLen + 1]);
return new byte[][] {
unwrapped, // session key
new byte[] { enc[pLen + 1] }, // sym alg
new byte[0] // X25519, X448 does not include checksum
};
}
}

Expand Down

0 comments on commit 592aeaa

Please sign in to comment.