org.spongycastle.jce.PKCS12Util Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scprov-jdk15 Show documentation
Show all versions of scprov-jdk15 Show documentation
Spongy Castle is a package-rename (org.bouncycastle.* to org.spongycastle.*) of Bouncy Castle intended for Android.
Android ships with a stripped-down version of Bouncy Castle - this causes classloader collisions if you try to add
an alternative (updated/complete) Bouncy Castle jar.
This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for JDK 1.5.
package org.spongycastle.jce;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import org.spongycastle.asn1.ASN1InputStream;
import org.spongycastle.asn1.ASN1Object;
import org.spongycastle.asn1.ASN1OctetString;
import org.spongycastle.asn1.ASN1Sequence;
import org.spongycastle.asn1.DERNull;
import org.spongycastle.asn1.DERObject;
import org.spongycastle.asn1.DERObjectIdentifier;
import org.spongycastle.asn1.DEROctetString;
import org.spongycastle.asn1.DEROutputStream;
import org.spongycastle.asn1.pkcs.ContentInfo;
import org.spongycastle.asn1.pkcs.MacData;
import org.spongycastle.asn1.pkcs.Pfx;
import org.spongycastle.asn1.x509.AlgorithmIdentifier;
import org.spongycastle.asn1.x509.DigestInfo;
/**
* Utility class for reencoding PKCS#12 files to definite length.
*/
public class PKCS12Util
{
/**
* Just re-encode the outer layer of the PKCS#12 file to definite length encoding.
*
* @param berPKCS12File - original PKCS#12 file
* @return a byte array representing the DER encoding of the PFX structure
* @throws IOException
*/
public static byte[] convertToDefiniteLength(byte[] berPKCS12File)
throws IOException
{
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
DEROutputStream dOut = new DEROutputStream(bOut);
Pfx pfx = new Pfx(ASN1Sequence.getInstance(ASN1Object.fromByteArray(berPKCS12File)));
bOut.reset();
dOut.writeObject(pfx);
return bOut.toByteArray();
}
/**
* Re-encode the PKCS#12 structure to definite length encoding at the inner layer
* as well, recomputing the MAC accordingly.
*
* @param berPKCS12File - original PKCS12 file.
* @param provider - provider to use for MAC calculation.
* @return a byte array representing the DER encoding of the PFX structure.
* @throws IOException on parsing, encoding errors.
*/
public static byte[] convertToDefiniteLength(byte[] berPKCS12File, char[] passwd, String provider)
throws IOException
{
Pfx pfx = new Pfx(ASN1Sequence.getInstance(ASN1Object.fromByteArray(berPKCS12File)));
ContentInfo info = pfx.getAuthSafe();
ASN1OctetString content = ASN1OctetString.getInstance(info.getContent());
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
DEROutputStream dOut = new DEROutputStream(bOut);
ASN1InputStream contentIn = new ASN1InputStream(content.getOctets());
DERObject obj = contentIn.readObject();
dOut.writeObject(obj);
info = new ContentInfo(info.getContentType(), new DEROctetString(bOut.toByteArray()));
MacData mData = pfx.getMacData();
try
{
int itCount = mData.getIterationCount().intValue();
byte[] data = ASN1OctetString.getInstance(info.getContent()).getOctets();
byte[] res = calculatePbeMac(mData.getMac().getAlgorithmId().getObjectId(), mData.getSalt(), itCount, passwd, data, provider);
AlgorithmIdentifier algId = new AlgorithmIdentifier(mData.getMac().getAlgorithmId().getObjectId(), new DERNull());
DigestInfo dInfo = new DigestInfo(algId, res);
mData = new MacData(dInfo, mData.getSalt(), itCount);
}
catch (Exception e)
{
throw new IOException("error constructing MAC: " + e.toString());
}
pfx = new Pfx(info, mData);
bOut.reset();
dOut.writeObject(pfx);
return bOut.toByteArray();
}
private static byte[] calculatePbeMac(
DERObjectIdentifier oid,
byte[] salt,
int itCount,
char[] password,
byte[] data,
String provider)
throws Exception
{
SecretKeyFactory keyFact = SecretKeyFactory.getInstance(oid.getId(), provider);
PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
PBEKeySpec pbeSpec = new PBEKeySpec(password);
SecretKey key = keyFact.generateSecret(pbeSpec);
Mac mac = Mac.getInstance(oid.getId(), provider);
mac.init(key, defParams);
mac.update(data);
return mac.doFinal();
}
}