package org.bouncycastle.pqc.crypto.util;
import java.io.IOException;
import java.io.InputStream;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams;
import org.bouncycastle.pqc.asn1.XMSSKeyParams;
import org.bouncycastle.pqc.asn1.XMSSMTKeyParams;
import org.bouncycastle.pqc.asn1.XMSSPrivateKey;
import org.bouncycastle.pqc.crypto.newhope.NHPrivateKeyParameters;
import org.bouncycastle.pqc.crypto.qtesla.QTESLAPrivateKeyParameters;
import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPrivateKeyParameters;
import org.bouncycastle.pqc.crypto.xmss.BDS;
import org.bouncycastle.pqc.crypto.xmss.BDSStateMap;
import org.bouncycastle.pqc.crypto.xmss.XMSSMTParameters;
import org.bouncycastle.pqc.crypto.xmss.XMSSMTPrivateKeyParameters;
import org.bouncycastle.pqc.crypto.xmss.XMSSParameters;
import org.bouncycastle.pqc.crypto.xmss.XMSSPrivateKeyParameters;
import org.bouncycastle.pqc.crypto.xmss.XMSSUtil;
import org.bouncycastle.util.Pack;
Factory for creating private key objects from PKCS8 PrivateKeyInfo objects.
/**
* Factory for creating private key objects from PKCS8 PrivateKeyInfo objects.
*/
public class PrivateKeyFactory
{
Create a private key parameter from a PKCS8 PrivateKeyInfo encoding.
Params: - privateKeyInfoData – the PrivateKeyInfo encoding
Throws: - IOException – on an error decoding the key
Returns: a suitable private key parameter
/**
* Create a private key parameter from a PKCS8 PrivateKeyInfo encoding.
*
* @param privateKeyInfoData the PrivateKeyInfo encoding
* @return a suitable private key parameter
* @throws IOException on an error decoding the key
*/
public static AsymmetricKeyParameter createKey(byte[] privateKeyInfoData) throws IOException
{
return createKey(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(privateKeyInfoData)));
}
Create a private key parameter from a PKCS8 PrivateKeyInfo encoding read from a
stream.
Params: - inStr – the stream to read the PrivateKeyInfo encoding from
Throws: - IOException – on an error decoding the key
Returns: a suitable private key parameter
/**
* Create a private key parameter from a PKCS8 PrivateKeyInfo encoding read from a
* stream.
*
* @param inStr the stream to read the PrivateKeyInfo encoding from
* @return a suitable private key parameter
* @throws IOException on an error decoding the key
*/
public static AsymmetricKeyParameter createKey(InputStream inStr) throws IOException
{
return createKey(PrivateKeyInfo.getInstance(new ASN1InputStream(inStr).readObject()));
}
Create a private key parameter from the passed in PKCS8 PrivateKeyInfo object.
Params: - keyInfo – the PrivateKeyInfo object containing the key material
Throws: - IOException – on an error decoding the key
Returns: a suitable private key parameter
/**
* Create a private key parameter from the passed in PKCS8 PrivateKeyInfo object.
*
* @param keyInfo the PrivateKeyInfo object containing the key material
* @return a suitable private key parameter
* @throws IOException on an error decoding the key
*/
public static AsymmetricKeyParameter createKey(PrivateKeyInfo keyInfo) throws IOException
{
AlgorithmIdentifier algId = keyInfo.getPrivateKeyAlgorithm();
ASN1ObjectIdentifier algOID = algId.getAlgorithm();
if (algOID.on(BCObjectIdentifiers.qTESLA))
{
ASN1OctetString qTESLAPriv = ASN1OctetString.getInstance(keyInfo.parsePrivateKey());
return new QTESLAPrivateKeyParameters(Utils.qTeslaLookupSecurityCategory(keyInfo.getPrivateKeyAlgorithm()), qTESLAPriv.getOctets());
}
else if (algOID.equals(BCObjectIdentifiers.sphincs256))
{
return new SPHINCSPrivateKeyParameters(ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets(),
Utils.sphincs256LookupTreeAlgName(SPHINCS256KeyParams.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters())));
}
else if (algOID.equals(BCObjectIdentifiers.newHope))
{
return new NHPrivateKeyParameters(convert(ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets()));
}
else if (algOID.equals(BCObjectIdentifiers.xmss))
{
XMSSKeyParams keyParams = XMSSKeyParams.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters());
ASN1ObjectIdentifier treeDigest = keyParams.getTreeDigest().getAlgorithm();
XMSSPrivateKey xmssPrivateKey = XMSSPrivateKey.getInstance(keyInfo.parsePrivateKey());
try
{
XMSSPrivateKeyParameters.Builder keyBuilder = new XMSSPrivateKeyParameters
.Builder(new XMSSParameters(keyParams.getHeight(), Utils.getDigest(treeDigest)))
.withIndex(xmssPrivateKey.getIndex())
.withSecretKeySeed(xmssPrivateKey.getSecretKeySeed())
.withSecretKeyPRF(xmssPrivateKey.getSecretKeyPRF())
.withPublicSeed(xmssPrivateKey.getPublicSeed())
.withRoot(xmssPrivateKey.getRoot());
if (xmssPrivateKey.getBdsState() != null)
{
BDS bds = (BDS)XMSSUtil.deserialize(xmssPrivateKey.getBdsState(), BDS.class);
keyBuilder.withBDSState(bds.withWOTSDigest(treeDigest));
}
return keyBuilder.build();
}
catch (ClassNotFoundException e)
{
throw new IOException("ClassNotFoundException processing BDS state: " + e.getMessage());
}
}
else if (algOID.equals(PQCObjectIdentifiers.xmss_mt))
{
XMSSMTKeyParams keyParams = XMSSMTKeyParams.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters());
ASN1ObjectIdentifier treeDigest = keyParams.getTreeDigest().getAlgorithm();
try
{
XMSSPrivateKey xmssMtPrivateKey = XMSSPrivateKey.getInstance(keyInfo.parsePrivateKey());
XMSSMTPrivateKeyParameters.Builder keyBuilder = new XMSSMTPrivateKeyParameters
.Builder(new XMSSMTParameters(keyParams.getHeight(), keyParams.getLayers(), Utils.getDigest(treeDigest)))
.withIndex(xmssMtPrivateKey.getIndex())
.withSecretKeySeed(xmssMtPrivateKey.getSecretKeySeed())
.withSecretKeyPRF(xmssMtPrivateKey.getSecretKeyPRF())
.withPublicSeed(xmssMtPrivateKey.getPublicSeed())
.withRoot(xmssMtPrivateKey.getRoot());
if (xmssMtPrivateKey.getBdsState() != null)
{
BDSStateMap bdsState = (BDSStateMap)XMSSUtil.deserialize(xmssMtPrivateKey.getBdsState(), BDSStateMap.class);
keyBuilder.withBDSState(bdsState.withWOTSDigest(treeDigest));
}
return keyBuilder.build();
}
catch (ClassNotFoundException e)
{
throw new IOException("ClassNotFoundException processing BDS state: " + e.getMessage());
}
}
else
{
throw new RuntimeException("algorithm identifier in private key not recognised");
}
}
private static short[] convert(byte[] octets)
{
short[] rv = new short[octets.length / 2];
for (int i = 0; i != rv.length; i++)
{
rv[i] = Pack.littleEndianToShort(octets, i * 2);
}
return rv;
}
}