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:
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:
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:
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; } }