大宝自习室

道路就在脚下

PKCS12结构-1

| 评论

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)来处理。

评论