package org.spongycastle.openpgp.operator.jcajce;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.Signature;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
import org.spongycastle.jcajce.JcaJceHelper;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.operator.PGPDataDecryptor;
import org.spongycastle.openpgp.operator.PGPDigestCalculator;
class OperatorHelper
{
private JcaJceHelper helper;
OperatorHelper(JcaJceHelper helper)
{
this.helper = helper;
}
MessageDigest createDigest(int algorithm)
throws GeneralSecurityException, PGPException
{
MessageDigest dig;
dig = helper.createDigest(PGPUtil.getDigestName(algorithm));
return dig;
}
KeyFactory createKeyFactory(String algorithm)
throws GeneralSecurityException, PGPException
{
return helper.createKeyFactory(algorithm);
}
PGPDataDecryptor createDataDecryptor(boolean withIntegrityPacket, int encAlgorithm, byte[] key)
throws PGPException
{
try
{
SecretKey secretKey = new SecretKeySpec(key, PGPUtil.getSymmetricCipherName(encAlgorithm));
final Cipher c = createStreamCipher(encAlgorithm, withIntegrityPacket);
byte[] iv = new byte[c.getBlockSize()];
c.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
return new PGPDataDecryptor()
{
public InputStream getInputStream(InputStream in)
{
return new CipherInputStream(in, c);
}
public int getBlockSize()
{
return c.getBlockSize();
}
public PGPDigestCalculator getIntegrityCalculator()
{
return new SHA1PGPDigestCalculator();
}
};
}
catch (PGPException e)
{
throw e;
}
catch (Exception e)
{
throw new PGPException("Exception creating cipher", e);
}
}
Cipher createStreamCipher(int encAlgorithm, boolean withIntegrityPacket)
throws PGPException
{
String mode = (withIntegrityPacket)
? "CFB"
: "OpenPGPCFB";
String cName = PGPUtil.getSymmetricCipherName(encAlgorithm)
+ "/" + mode + "/NoPadding";
return createCipher(cName);
}
Cipher createCipher(String cipherName)
throws PGPException
{
try
{
return helper.createCipher(cipherName);
}
catch (GeneralSecurityException e)
{
throw new PGPException("cannot create cipher: " + e.getMessage(), e);
}
}
Cipher createPublicKeyCipher(int encAlgorithm)
throws PGPException
{
switch (encAlgorithm)
{
case PGPPublicKey.RSA_ENCRYPT:
case PGPPublicKey.RSA_GENERAL:
return createCipher("RSA/ECB/PKCS1Padding");
case PGPPublicKey.ELGAMAL_ENCRYPT:
case PGPPublicKey.ELGAMAL_GENERAL:
return createCipher("ElGamal/ECB/PKCS1Padding");
case PGPPublicKey.DSA:
throw new PGPException("Can't use DSA for encryption.");
case PGPPublicKey.ECDSA:
throw new PGPException("Can't use ECDSA for encryption.");
default:
throw new PGPException("unknown asymmetric algorithm: " + encAlgorithm);
}
}
private Signature createSignature(String cipherName)
throws PGPException
{
try
{
return helper.createSignature(cipherName);
}
catch (GeneralSecurityException e)
{
throw new PGPException("cannot create signature: " + e.getMessage(), e);
}
}
public Signature createSignature(int keyAlgorithm, int hashAlgorithm)
throws PGPException
{
String encAlg;
switch (keyAlgorithm)
{
case PublicKeyAlgorithmTags.RSA_GENERAL:
case PublicKeyAlgorithmTags.RSA_SIGN:
encAlg = "RSA";
break;
case PublicKeyAlgorithmTags.DSA:
encAlg = "DSA";
break;
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: // in some malformed cases.
case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
encAlg = "ElGamal";
break;
default:
throw new PGPException("unknown algorithm tag in signature:" + keyAlgorithm);
}
return createSignature(PGPUtil.getDigestName(hashAlgorithm) + "with" + encAlg);
}
}