| 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. |
| */ |
| public class PrivateKeyFactory |
| { |
| /** |
| * 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. |
| * |
| * @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. |
| * |
| * @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; |
| } |
| } |