PKCS#12简单介绍
最新版本的PKCS#12标准文档出版在2012年,由RSA实验室制定。由于PKCS#12是个人信息交换结构,其中包含有个人安全的关键信息,其组织的ASN.1结构较为复杂,所以在了解PKCS#12之前首先要知道ASN.1结构、BER\DER、X.509证书、CRL列表等等知识。
首先我们来简单认识一下PKCS#12。PKCS#12证书结构的后缀名一般为.pfx和.p12,使用EJBCA或者OpenSSL都可以产生PKCS#12,一般是基于1024bit RSA算法的。产生后的PKCS#12结构可以导入到系统中,用于邮件的签名和加密(需要使用到邮件客户端,如OutLook Express、OutLook等)。需要用到加密,所以PKCS#12中必须包含用户的私钥。而保护结构中私钥的一般方式是设置口令。将PKCS#12导入到容器中、并且提取其中的私钥是需要验证用户设置的口令是否正确。
PKCS#12的ASN.1结构
PKCS#12整体结构:
PFX ::= SEQUENCE {
version INTEGER {v3(3)}(v3,...), //版本号,默认为v3
authSafe ContentInfo, //PKCS#7结构消息
macData MacData OPTIONAL //mac数据,可选
}
其中version默认为v3,对应代码结构:
BC库中定义的Pfx结构: public class Pfx extends ASN1Object implements PKCSObjectIdentifiers { private ContentInfo contentInfo; private MacData macData = null; //其他代码省略 }
Mac数据段结构(可选):
MacData ::= SEQUENCE {
mac DigestInfo,
macSalt OCTET STRING,
iterations INTEGER DEFAULT 1
-- Note: The default is for historical reasons and its use is deprecated.
}
MacData是一个Sequence,因此在改结构段中可能存在多个该类型的数据结构。
public class MacData extends ASN1Object
{
private static final BigInteger ONE = BigInteger.valueOf(1);
DigestInfo digInfo;
byte[] salt;
BigInteger iterationCount;
//其他代码省略
}
*首先*我们来看看 mac DigestInfo这个对象
DigestInfo的ASN.1结构:
DigestInfo::=SEQUENCE{
digestAlgorithm AlgorithmIdentifier,
digest OCTET STRING
}
在BC库中的定义结构为:
package org.bouncycastle.asn1.x509;
public class DigestInfo extends ASN1Object
{
private byte[] digest;
private AlgorithmIdentifier algId;
//其余代码省略
}
然后再来看看剩下的macSalt及 iterations两个对象。 macSalt 被定义为ASN.1的OCTET STRING结构,为基本的结构类型。其与iterations一起被包装成PKCS12PBEParam类,参看下面代码:
public class PKCS12PBEParams extends ASN1Object
{
ASN1Integer iterations;
ASN1OctetString iv;
public PKCS12PBEParams(byte[] salt,int iterations)
{
this.iv = new DEROctetString(salt);
this.iterations = new ASN1Integer(iterations);
}
//省略其他代码
}
在下面的代码中我们将看到建造者模式在代码的实例应用,正好应对上篇博文中的知识点。
public interface PKCS12MacCalculatorBuilder
{
MacCalculator build(char[] password);
AlgorithmIdentifier getDigestAlgorithmIdentifier();
}
public class BcPKCS12MacCalculatorBuilder implements PKCS12MacCalculatorBuilder
{
private ExtendedDigest digest;
private AlgorithmIdentifier algorithmIdentifier;
private SecureRandom random;
private int saltLength;
private int iterationCount = 1024;
public BcPKCS12MacCalculatorBuilder()
{
this(new SHA1Digest(), new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE));
}
public BcPKCS12MacCalculatorBuilder(ExtendedDigest digest, AlgorithmIdentifier algorithmIdentifier)
{
this.digest = digest;
this.algorithmIdentifier = algorithmIdentifier;
this.saltLength = digest.getDigestSize();
}
//实现接口中的方法getDigestAlgorithmIdentifier
public AlgorithmIdentifier getDigestAlgorithmIdentifier()
{
return algorithmIdentifier;
}
public MacCalculator build(final char[] password) //实现接口中的方法build
{
if (random == null)
{
random = new SecureRandom();
}
byte[] salt = new byte[saltLength];
random.nextBytes(salt);
return PKCS12PBEUtils.createMacCalculator(algorithmIdentifier.getAlgorithm(), digest, new PKCS12PBEParams(salt, iterationCount), password);
}
及其对应的Provider,实现代码结构如下:
public interface PKCS12MacCalculatorBuilderProvider
{
PKCS12MacCalculatorBuilder get(AlgorithmIdentifier algorithmIdentifier);
}
public class BcPKCS12MacCalculatorBuilderProviderBuilder implements PKCS12MacCalculatorBuilderProvider
{
private ExtendedDigest digest;
private AlgorithmIdentifier digestAlgorithmIdentifier;
public PKCS12MacCalculatorBuilder get(final AlgorithmIdentifier algorithmIdentifier)
{ //实现接口中的方法
return new PKCS12MacCalculatorBuilder()
{
public MacCalculator build(final char[] password)
{
PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algorithmIdentifier.getParameters());
return PKCS12PBEUtils.createMacCalculator(digestAlgorithmIdentifier.getAlgorithm(), digest, pbeParams, password);
}
public AlgorithmIdentifier getDigestAlgorithmIdentifier()
{
return digestAlgorithmIdentifier;
}
};
}
}
由下面代码生成MacData结构:
class MacDataGenerator
{
private PKCS12MacCalculatorBuilder builder; //私有builder属性
MacDataGenerator(PKCS12MacCalculatorBuilder builder)
{
this.builder = builder;
}
public MacData build(char[] password, byte[] data) throws PKCSException
{
MacCalculator macCalculator = builder.build(password);
AlgorithmIdentifier algId = macCalculator.getAlgorithmIdentifier();
OutputStream out = macCalculator.getOutputStream();
try
{
out.write(data);
out.close();
}
catch (IOException e)
{
throw new PKCSException("unable to process data: " + e.getMessage(), e);
}
DigestInfo dInfo = new DigestInfo(builder.getDigestAlgorithmIdentifier(), macCalculator.getMac());
PKCS12PBEParams params = PKCS12PBEParams.getInstance(algId.getParameters());
return new MacData(dInfo, params.getIV(), params.getIterations().intValue());
}
}
其中要返回关键的MacCalculator的代码都集中由PKCS12PBEUtils.createMacCalculator(digestAlgorithmIdentifier.getAlgorithm(), digest, pbeParams, password)来处理。