using System;
using System.IO;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.BC;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Pqc.Asn1;
using Org.BouncyCastle.Pqc.Crypto.Bike;
using Org.BouncyCastle.Pqc.Crypto.Cmce;
using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium;
using Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber;
using Org.BouncyCastle.Pqc.Crypto.Falcon;
using Org.BouncyCastle.Pqc.Crypto.Frodo;
using Org.BouncyCastle.Pqc.Crypto.Hqc;
using Org.BouncyCastle.Pqc.Crypto.Lms;
using Org.BouncyCastle.Pqc.Crypto.Picnic;
using Org.BouncyCastle.Pqc.Crypto.Saber;
using Org.BouncyCastle.Pqc.Crypto.Sike;
using Org.BouncyCastle.Pqc.Crypto.SphincsPlus;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Pqc.Crypto.Utilities
{
public static class PqcPrivateKeyFactory
{
/// Create a private key parameter from a PKCS8 PrivateKeyInfo encoding.
/// the PrivateKeyInfo encoding
/// a suitable private key parameter
/// on an error decoding the key
public static AsymmetricKeyParameter CreateKey(byte[] privateKeyInfoData)
{
return CreateKey(PrivateKeyInfo.GetInstance(Asn1Object.FromByteArray(privateKeyInfoData)));
}
/// Create a private key parameter from a PKCS8 PrivateKeyInfo encoding read from a stream
/// the stream to read the PrivateKeyInfo encoding from
/// a suitable private key parameter
/// on an error decoding the key
public static AsymmetricKeyParameter CreateKey(Stream inStr)
{
return CreateKey(PrivateKeyInfo.GetInstance(new Asn1InputStream(inStr).ReadObject()));
}
/// Create a private key parameter from the passed in PKCS8 PrivateKeyInfo object.
/// the PrivateKeyInfo object containing the key material
/// a suitable private key parameter
/// on an error decoding the key
public static AsymmetricKeyParameter CreateKey(PrivateKeyInfo keyInfo)
{
AlgorithmIdentifier algID = keyInfo.PrivateKeyAlgorithm;
DerObjectIdentifier algOid = algID.Algorithm;
if (algOid.Equals(PkcsObjectIdentifiers.IdAlgHssLmsHashsig))
{
byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets();
DerBitString pubKey = keyInfo.PublicKey;
if (Pack.BE_To_UInt32(keyEnc, 0) == 1)
{
if (pubKey != null)
{
byte[] pubEnc = pubKey.GetOctets();
return LmsPrivateKeyParameters.GetInstance(Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length),
Arrays.CopyOfRange(pubEnc, 4, pubEnc.Length));
}
return LmsPrivateKeyParameters.GetInstance(Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length));
}
}
if (algOid.On(BCObjectIdentifiers.pqc_kem_mceliece))
{
CmcePrivateKey cmceKey = CmcePrivateKey.GetInstance(keyInfo.ParsePrivateKey());
CmceParameters spParams = PqcUtilities.McElieceParamsLookup(algOid);
return new CmcePrivateKeyParameters(spParams, cmceKey.Delta, cmceKey.C, cmceKey.G, cmceKey.Alpha, cmceKey.S);
}
if (algOid.On(BCObjectIdentifiers.pqc_kem_frodo))
{
byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets();
FrodoParameters spParams = PqcUtilities.FrodoParamsLookup(algOid);
return new FrodoPrivateKeyParameters(spParams, keyEnc);
}
if (algOid.On(BCObjectIdentifiers.sphincsPlus))
{
SphincsPlusPrivateKey spKey = SphincsPlusPrivateKey.GetInstance(keyInfo.ParsePrivateKey());
SphincsPlusParameters spParams = PqcUtilities.SphincsPlusParamsLookup(algOid);
SphincsPlusPublicKey publicKey = spKey.PublicKey;
return new SphincsPlusPrivateKeyParameters(spParams, spKey.GetSkseed(), spKey.GetSkprf(),
publicKey.GetPkseed(), publicKey.GetPkroot());
}
if (algOid.On(BCObjectIdentifiers.pqc_kem_saber))
{
byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets();
SaberParameters spParams = PqcUtilities.SaberParamsLookup(algOid);
return new SaberPrivateKeyParameters(spParams, keyEnc);
}
if (algOid.On(BCObjectIdentifiers.picnic))
{
byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets();
PicnicParameters picnicParams = PqcUtilities.PicnicParamsLookup(algOid);
return new PicnicPrivateKeyParameters(picnicParams, keyEnc);
}
#pragma warning disable CS0618 // Type or member is obsolete
if (algOid.On(BCObjectIdentifiers.pqc_kem_sike))
{
byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets();
SikeParameters sikeParams = PqcUtilities.SikeParamsLookup(algOid);
return new SikePrivateKeyParameters(sikeParams, keyEnc);
}
#pragma warning restore CS0618 // Type or member is obsolete
if (algOid.On(BCObjectIdentifiers.pqc_kem_bike))
{
byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets();
BikeParameters bikeParams = PqcUtilities.BikeParamsLookup(algOid);
byte[] h0 = Arrays.CopyOfRange(keyEnc, 0, bikeParams.RByte);
byte[] h1 = Arrays.CopyOfRange(keyEnc, bikeParams.RByte, 2 * bikeParams.RByte);
byte[] sigma = Arrays.CopyOfRange(keyEnc, 2 * bikeParams.RByte, keyEnc.Length);
return new BikePrivateKeyParameters(bikeParams, h0, h1, sigma);
}
if (algOid.On(BCObjectIdentifiers.pqc_kem_hqc))
{
byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets();
HqcParameters hqcParams = PqcUtilities.HqcParamsLookup(algOid);
return new HqcPrivateKeyParameters(hqcParams, keyEnc);
}
if (algOid.On(BCObjectIdentifiers.pqc_kem_kyber))
{
KyberPrivateKey kyberKey = KyberPrivateKey.GetInstance(keyInfo.ParsePrivateKey());
KyberParameters kyberParams = PqcUtilities.KyberParamsLookup(algOid);
#pragma warning disable CS0618 // Type or member is obsolete
KyberPublicKey pubKey = kyberKey.PublicKey;
#pragma warning restore CS0618 // Type or member is obsolete
if (pubKey != null)
{
return new KyberPrivateKeyParameters(kyberParams, kyberKey.GetS(), kyberKey.GetHpk(),
kyberKey.GetNonce(), pubKey.T, pubKey.Rho);
}
return new KyberPrivateKeyParameters(kyberParams, kyberKey.GetS(), kyberKey.GetHpk(),
kyberKey.GetNonce(), null, null);
}
if (algOid.Equals(BCObjectIdentifiers.dilithium2) ||
algOid.Equals(BCObjectIdentifiers.dilithium3) ||
algOid.Equals(BCObjectIdentifiers.dilithium5) ||
algOid.Equals(BCObjectIdentifiers.dilithium2_aes) ||
algOid.Equals(BCObjectIdentifiers.dilithium3_aes) ||
algOid.Equals(BCObjectIdentifiers.dilithium5_aes))
{
Asn1Sequence keyEnc = Asn1Sequence.GetInstance(keyInfo.ParsePrivateKey());
DilithiumParameters spParams = PqcUtilities.DilithiumParamsLookup(algOid);
int version = DerInteger.GetInstance(keyEnc[0]).IntValueExact;
if (version != 0)
throw new IOException("unknown private key version: " + version);
byte[] t1 = null;
DerBitString publicKeyData = keyInfo.PublicKey;
if (publicKeyData != null)
{
var pubParams = PqcPublicKeyFactory.DilithiumConverter.GetPublicKeyParameters(spParams,
publicKeyData);
t1 = pubParams.GetT1();
}
return new DilithiumPrivateKeyParameters(spParams,
DerBitString.GetInstance(keyEnc[1]).GetOctets(),
DerBitString.GetInstance(keyEnc[2]).GetOctets(),
DerBitString.GetInstance(keyEnc[3]).GetOctets(),
DerBitString.GetInstance(keyEnc[4]).GetOctets(),
DerBitString.GetInstance(keyEnc[5]).GetOctets(),
DerBitString.GetInstance(keyEnc[6]).GetOctets(),
t1); // encT1
}
if (algOid.Equals(BCObjectIdentifiers.falcon_512) ||
algOid.Equals(BCObjectIdentifiers.falcon_1024))
{
Asn1Sequence keyEnc = Asn1Sequence.GetInstance(keyInfo.ParsePrivateKey());
FalconParameters spParams = PqcUtilities.FalconParamsLookup(algOid);
int version = DerInteger.GetInstance(keyEnc[0]).IntValueExact;
if (version != 1)
throw new IOException("unknown private key version: " + version);
return new FalconPrivateKeyParameters(spParams,
Asn1OctetString.GetInstance(keyEnc[1]).GetOctets(),
Asn1OctetString.GetInstance(keyEnc[2]).GetOctets(),
Asn1OctetString.GetInstance(keyEnc[3]).GetOctets(),
keyInfo.PublicKey?.GetOctets()); // encT1
}
throw new Exception("algorithm identifier in private key not recognised");
}
}
}