org.bouncycastle.openpgp.PGPPBEEncryptedData Maven / Gradle / Ivy
package org.bouncycastle.openpgp;
import org.bouncycastle.bcpg.BCPGInputStream;
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.InputStreamPacket;
import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket;
import org.bouncycastle.bcpg.SymmetricKeyEncSessionPacket;
import java.io.EOFException;
import java.io.InputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Provider;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* A password based encryption object.
*/
public class PGPPBEEncryptedData
extends PGPEncryptedData
{
SymmetricKeyEncSessionPacket keyData;
PGPPBEEncryptedData(
SymmetricKeyEncSessionPacket keyData,
InputStreamPacket encData)
{
super(encData);
this.keyData = keyData;
}
/**
* Return the raw input stream for the data stream.
*
* @return InputStream
*/
public InputStream getInputStream()
{
return encData.getInputStream();
}
/**
* Return the decrypted input stream, using the passed in passPhrase.
*
* @param passPhrase
* @param provider
* @return InputStream
* @throws PGPException
* @throws NoSuchProviderException
*/
public InputStream getDataStream(
char[] passPhrase,
String provider)
throws PGPException, NoSuchProviderException
{
return getDataStream(passPhrase, PGPUtil.getProvider(provider));
}
/**
* Return the decrypted input stream, using the passed in passPhrase.
*
* @param passPhrase
* @param provider
* @return InputStream
* @throws PGPException
*/
public InputStream getDataStream(
char[] passPhrase,
Provider provider)
throws PGPException
{
try
{
int keyAlgorithm = keyData.getEncAlgorithm();
SecretKey key = PGPUtil.makeKeyFromPassPhrase(keyAlgorithm, keyData.getS2K(), passPhrase, provider);
byte[] secKeyData = keyData.getSecKeyData();
if (secKeyData != null && secKeyData.length > 0)
{
Cipher keyCipher = Cipher.getInstance(
PGPUtil.getSymmetricCipherName(keyAlgorithm) + "/CFB/NoPadding",
provider);
keyCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(new byte[keyCipher.getBlockSize()]));
byte[] keyBytes = keyCipher.doFinal(secKeyData);
keyAlgorithm = keyBytes[0];
key = new SecretKeySpec(keyBytes, 1, keyBytes.length - 1, PGPUtil.getSymmetricCipherName(keyAlgorithm));
}
Cipher c = createStreamCipher(keyAlgorithm, provider);
byte[] iv = new byte[c.getBlockSize()];
c.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
encStream = new BCPGInputStream(new CipherInputStream(encData.getInputStream(), c));
if (encData instanceof SymmetricEncIntegrityPacket)
{
truncStream = new TruncatedStream(encStream);
String digestName = PGPUtil.getDigestName(HashAlgorithmTags.SHA1);
MessageDigest digest = MessageDigest.getInstance(digestName, provider);
encStream = new DigestInputStream(truncStream, digest);
}
for (int i = 0; i != iv.length; i++)
{
int ch = encStream.read();
if (ch < 0)
{
throw new EOFException("unexpected end of stream.");
}
iv[i] = (byte)ch;
}
int v1 = encStream.read();
int v2 = encStream.read();
if (v1 < 0 || v2 < 0)
{
throw new EOFException("unexpected end of stream.");
}
// Note: the oracle attack on "quick check" bytes is not deemed
// a security risk for PBE (see PGPPublicKeyEncryptedData)
boolean repeatCheckPassed = iv[iv.length - 2] == (byte) v1
&& iv[iv.length - 1] == (byte) v2;
// Note: some versions of PGP appear to produce 0 for the extra
// bytes rather than repeating the two previous bytes
boolean zeroesCheckPassed = v1 == 0 && v2 == 0;
if (!repeatCheckPassed && !zeroesCheckPassed)
{
throw new PGPDataValidationException("data check failed.");
}
return encStream;
}
catch (PGPException e)
{
throw e;
}
catch (Exception e)
{
throw new PGPException("Exception creating cipher", e);
}
}
private Cipher createStreamCipher(int keyAlgorithm, Provider provider)
throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException,
PGPException
{
String mode = (encData instanceof SymmetricEncIntegrityPacket)
? "CFB"
: "OpenPGPCFB";
String cName = PGPUtil.getSymmetricCipherName(keyAlgorithm)
+ "/" + mode + "/NoPadding";
return Cipher.getInstance(cName, provider);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy