package org.bouncycastle.pqc.crypto.util;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
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.XMSSPublicKey;
import org.bouncycastle.pqc.crypto.newhope.NHPublicKeyParameters;
import org.bouncycastle.pqc.crypto.qtesla.QTESLAPublicKeyParameters;
import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPublicKeyParameters;
import org.bouncycastle.pqc.crypto.xmss.XMSSMTParameters;
import org.bouncycastle.pqc.crypto.xmss.XMSSMTPublicKeyParameters;
import org.bouncycastle.pqc.crypto.xmss.XMSSParameters;
import org.bouncycastle.pqc.crypto.xmss.XMSSPublicKeyParameters;
public class PublicKeyFactory
{
private static Map converters = new HashMap();
static
{
converters.put(PQCObjectIdentifiers.qTESLA_I, new QTeslaConverter());
converters.put(PQCObjectIdentifiers.qTESLA_III_size, new QTeslaConverter());
converters.put(PQCObjectIdentifiers.qTESLA_III_speed, new QTeslaConverter());
converters.put(PQCObjectIdentifiers.qTESLA_p_I, new QTeslaConverter());
converters.put(PQCObjectIdentifiers.qTESLA_p_III, new QTeslaConverter());
converters.put(PQCObjectIdentifiers.sphincs256, new SPHINCSConverter());
converters.put(PQCObjectIdentifiers.newHope, new NHConverter());
converters.put(PQCObjectIdentifiers.xmss, new XMSSConverter());
converters.put(PQCObjectIdentifiers.xmss_mt, new XMSSMTConverter());
}
public static AsymmetricKeyParameter createKey(byte[] keyInfoData)
throws IOException
{
return createKey(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(keyInfoData)));
}
public static AsymmetricKeyParameter createKey(InputStream inStr)
throws IOException
{
return createKey(SubjectPublicKeyInfo.getInstance(new ASN1InputStream(inStr).readObject()));
}
public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo)
throws IOException
{
return createKey(keyInfo, null);
}
public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo, Object defaultParams)
throws IOException
{
AlgorithmIdentifier algId = keyInfo.getAlgorithm();
SubjectPublicKeyInfoConverter converter = (SubjectPublicKeyInfoConverter)converters.get(algId.getAlgorithm());
if (converter != null)
{
return converter.getPublicKeyParameters(keyInfo, defaultParams);
}
else
{
throw new IOException("algorithm identifier in public key not recognised: " + algId.getAlgorithm());
}
}
private static abstract class SubjectPublicKeyInfoConverter
{
abstract AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
throws IOException;
}
private static class QTeslaConverter
extends SubjectPublicKeyInfoConverter
{
AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
throws IOException
{
return new QTESLAPublicKeyParameters(Utils.qTeslaLookupSecurityCategory(keyInfo.getAlgorithm()), keyInfo.getPublicKeyData().getOctets());
}
}
private static class SPHINCSConverter
extends SubjectPublicKeyInfoConverter
{
AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
throws IOException
{
return new SPHINCSPublicKeyParameters(keyInfo.getPublicKeyData().getBytes(),
Utils.sphincs256LookupTreeAlgName(SPHINCS256KeyParams.getInstance(keyInfo.getAlgorithm().getParameters())));
}
}
private static class NHConverter
extends SubjectPublicKeyInfoConverter
{
AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
throws IOException
{
return new NHPublicKeyParameters(keyInfo.getPublicKeyData().getBytes());
}
}
private static class XMSSConverter
extends SubjectPublicKeyInfoConverter
{
AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
throws IOException
{
XMSSKeyParams keyParams = XMSSKeyParams.getInstance(keyInfo.getAlgorithm().getParameters());
ASN1ObjectIdentifier treeDigest = keyParams.getTreeDigest().getAlgorithm();
XMSSPublicKey xmssPublicKey = XMSSPublicKey.getInstance(keyInfo.parsePublicKey());
return new XMSSPublicKeyParameters
.Builder(new XMSSParameters(keyParams.getHeight(), Utils.getDigest(treeDigest)))
.withPublicSeed(xmssPublicKey.getPublicSeed())
.withRoot(xmssPublicKey.getRoot()).build();
}
}
private static class XMSSMTConverter
extends SubjectPublicKeyInfoConverter
{
AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
throws IOException
{
XMSSMTKeyParams keyParams = XMSSMTKeyParams.getInstance(keyInfo.getAlgorithm().getParameters());
ASN1ObjectIdentifier treeDigest = keyParams.getTreeDigest().getAlgorithm();
XMSSPublicKey xmssMtPublicKey = XMSSPublicKey.getInstance(keyInfo.parsePublicKey());
return new XMSSMTPublicKeyParameters
.Builder(new XMSSMTParameters(keyParams.getHeight(), keyParams.getLayers(), Utils.getDigest(treeDigest)))
.withPublicSeed(xmssMtPublicKey.getPublicSeed())
.withRoot(xmssMtPublicKey.getRoot()).build();
}
}
}