diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java index b5ae1f14e9..4825230d4c 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java @@ -35,9 +35,10 @@ 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; @@ -98,6 +99,8 @@ public PGPSessionKey getSessionKey( throws PGPException { byte[] sessionInfo = dataDecryptorFactory.recoverSessionData(keyData, encData); + + // Confirm and discard checksum if (containsChecksum(keyData.getAlgorithm())) { if (!confirmCheckSum(sessionInfo)) @@ -107,15 +110,13 @@ public PGPSessionKey getSessionKey( sessionInfo = Arrays.copyOf(sessionInfo, sessionInfo.length - 2); } - - byte[] sessionKey; + byte[] sessionKey = Arrays.copyOfRange(sessionInfo, 1, sessionInfo.length); int algorithm; // OCB (LibrePGP v5 style AEAD) if (encData instanceof AEADEncDataPacket) { algorithm = ((AEADEncDataPacket) encData).getAlgorithm(); - sessionKey = Arrays.copyOfRange(sessionInfo, 1, sessionInfo.length); } // SEIPD (OpenPGP v4 / OpenPGP v6) @@ -125,12 +126,10 @@ else if (encData instanceof SymmetricEncIntegrityPacket) 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 { @@ -141,7 +140,6 @@ else if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_2) else { algorithm = sessionInfo[0]; - sessionKey = Arrays.copyOfRange(sessionInfo, 1, sessionInfo.length); } return new PGPSessionKey(algorithm & 0xff, sessionKey); diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/AbstractPublicKeyDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/AbstractPublicKeyDataDecryptorFactory.java index fd61870f8d..6d9136a72f 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/AbstractPublicKeyDataDecryptorFactory.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/AbstractPublicKeyDataDecryptorFactory.java @@ -56,22 +56,12 @@ protected boolean containsSKAlg(int pkeskVersion) return pkeskVersion != PublicKeyEncSessionPacket.VERSION_6; } - protected boolean confirmCheckSum( - byte[] sessionInfo, int algorithm) + protected static void checkRange(int pLen, byte[] enc) + throws PGPException { - // X25519, X448 does not include a checksum - if (algorithm == PublicKeyAlgorithmTags.X25519 || algorithm == PublicKeyAlgorithmTags.X448) + if (pLen > enc.length) { - return true; + throw new PGPException("encoded length out of range"); } - - int check = 0; - for (int i = 1; i != sessionInfo.length - 2; i++) - { - check += sessionInfo[i] & 0xff; - } - - return (sessionInfo[sessionInfo.length - 2] == (byte)(check >> 8)) - && (sessionInfo[sessionInfo.length - 1] == (byte)(check)); } } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyDataDecryptorFactory.java index e19f4734ec..cc5420ddbc 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyDataDecryptorFactory.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyDataDecryptorFactory.java @@ -7,15 +7,30 @@ public interface PublicKeyDataDecryptorFactory extends PGPDataDecryptorFactory { + /** + * Recover the plain session info by decrypting the encrypted session key. + * The session info ALWAYS has the symmetric algorithm ID prefixed, so the return value is: + *
[sym-alg][session-key][checksum]?
+ * + * @param pkesk public-key encrypted session-key packet + * @param encData encrypted data (sed/seipd/oed) packet + * @return decrypted session info + * @throws PGPException + */ byte[] recoverSessionData(PublicKeyEncSessionPacket pkesk, InputStreamPacket encData) throws PGPException; /** - * @deprecated use {@link #recoverSessionData(PublicKeyEncSessionPacket, InputStreamPacket)} (PublicKeyEncSessionPacket, InputStreamPacket)} instead. + * Recover the plain session info by decrypting the encrypted session key. + * This method returns the decrypted session info as-is (without prefixing missing cipher algorithm), + * so the return value is: + *
[sym-alg]?[session-key][checksum]?
+ * + * @deprecated use {@link #recoverSessionData(PublicKeyEncSessionPacket, InputStreamPacket)} instead. * @param keyAlgorithm public key algorithm * @param secKeyData encrypted session key data * @param pkeskVersion version of the PKESK packet - * @return + * @return decrypted session info * @throws PGPException */ byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData, int pkeskVersion) diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java index 53fa3b7559..89554b97d1 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java @@ -297,13 +297,4 @@ private static byte[] unwrapSessionData(byte[] keyEnc, int symmetricKeyAlgorithm c.init(false, key); return c.unwrap(keyEnc, 0, keyEnc.length); } - - private static void checkRange(int pLen, byte[] enc) - throws PGPException - { - if (pLen > enc.length) - { - throw new PGPException("encoded length out of range"); - } - } } \ No newline at end of file diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java index fd1461015c..5acffaa985 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java @@ -147,9 +147,7 @@ public byte[] recoverSessionData(PublicKeyEncSessionPacket pkesk, InputStreamPac public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData, int pkeskVersion) throws PGPException { - if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH || - keyAlgorithm == PublicKeyAlgorithmTags.X25519 || - keyAlgorithm == PublicKeyAlgorithmTags.X448) + if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH || keyAlgorithm == PublicKeyAlgorithmTags.X25519 || keyAlgorithm == PublicKeyAlgorithmTags.X448) { throw new PGPException("ECDH requires use of PGPPrivateKey for decryption"); } @@ -264,18 +262,12 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr byte[] keyEnc; pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8; - if ((2 + pLen + 1) > enc.length) - { - throw new PGPException("encoded length out of range"); - } + checkRange(2 + pLen + 1, enc); pEnc = new byte[pLen]; System.arraycopy(enc, 2, pEnc, 0, pLen); int keyLen = enc[pLen + 2] & 0xff; - if ((2 + pLen + 1 + keyLen) > enc.length) - { - throw new PGPException("encoded length out of range"); - } + checkRange(2 + pLen + 1 + keyLen, enc); keyEnc = new byte[keyLen]; System.arraycopy(enc, 2 + pLen + 1, keyEnc, 0, keyLen); @@ -341,11 +333,8 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr byte[] ephemeralKey = Arrays.copyOf(enc, pLen); int size = enc[pLen] & 0xff; - // checkRange - if ((pLen + 1 + size) > enc.length) - { - throw new PGPException("encoded length out of range"); - } + + checkRange(pLen + 1 + size, enc); // encrypted session key int sesKeyLen = size - (containsSKAlg ? 1 : 0); @@ -363,18 +352,12 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr } } - private Key getSessionKey(JcaPGPKeyConverter converter, - PGPPrivateKey privKey, - String agreementName, - PublicKey publicKey, - int symmetricKeyAlgorithm, - byte[] keyEnc, - AlgorithmParameterSpec ukms) + private Key getSessionKey(JcaPGPKeyConverter converter, PGPPrivateKey privKey, String agreementName, + PublicKey publicKey, int symmetricKeyAlgorithm, byte[] keyEnc, AlgorithmParameterSpec ukms) throws PGPException, GeneralSecurityException { PrivateKey privateKey = converter.getPrivateKey(privKey); - String wrapName = RFC6637Utils.getKeyEncryptionOID(symmetricKeyAlgorithm).getId(); - Key key = JcaJcePGPUtil.getSecret(helper, publicKey, wrapName, agreementName, ukms, privateKey); + Key key = JcaJcePGPUtil.getSecret(helper, publicKey, RFC6637Utils.getKeyEncryptionOID(symmetricKeyAlgorithm).getId(), agreementName, ukms, privateKey); Cipher c = helper.createKeyWrapper(symmetricKeyAlgorithm); c.init(Cipher.UNWRAP_MODE, key); return c.unwrap(keyEnc, "Session", Cipher.SECRET_KEY); @@ -456,4 +439,13 @@ private byte[] decryptSessionData(int keyAlgorithm, PrivateKey privKey, int expe throw new PGPException("exception decrypting session data", e); } } + + private static void checkRange(int pLen, byte[] enc) + throws PGPException + { + if (pLen > enc.length) + { + throw new PGPException("encoded length out of range"); + } + } }