blob: 4874dc9887ba2fe7421560395008b70fcc88268d [file] [log] [blame]
package org.bouncycastle.pqc.jcajce.provider.rainbow;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactorySpi;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
import org.bouncycastle.pqc.asn1.RainbowPrivateKey;
import org.bouncycastle.pqc.asn1.RainbowPublicKey;
import org.bouncycastle.pqc.jcajce.spec.RainbowPrivateKeySpec;
import org.bouncycastle.pqc.jcajce.spec.RainbowPublicKeySpec;
/**
* This class transforms Rainbow keys and Rainbow key specifications.
*
* @see BCRainbowPublicKey
* @see RainbowPublicKeySpec
* @see BCRainbowPrivateKey
* @see RainbowPrivateKeySpec
*/
public class RainbowKeyFactorySpi
extends KeyFactorySpi
implements AsymmetricKeyInfoConverter
{
/**
* Converts, if possible, a key specification into a
* {@link BCRainbowPrivateKey}. Currently, the following key specifications
* are supported: {@link RainbowPrivateKeySpec}, {@link PKCS8EncodedKeySpec}.
* <p>
* The ASN.1 definition of the key structure is
* <pre>
* RainbowPrivateKey ::= SEQUENCE {
* oid OBJECT IDENTIFIER -- OID identifying the algorithm
* A1inv SEQUENCE OF OCTET STRING -- inversed matrix of L1
* b1 OCTET STRING -- translation vector of L1
* A2inv SEQUENCE OF OCTET STRING -- inversed matrix of L2
* b2 OCTET STRING -- translation vector of L2
* vi OCTET STRING -- num of elmts in each Set S
* layers SEQUENCE OF Layer -- layers of F
* }
*
* Layer ::= SEQUENCE OF Poly
* Poly ::= SEQUENCE {
* alpha SEQUENCE OF OCTET STRING
* beta SEQUENCE OF OCTET STRING
* gamma OCTET STRING
* eta OCTET
* }
* </pre>
* </p>
*
* @param keySpec the key specification
* @return the Rainbow private key
* @throws InvalidKeySpecException if the KeySpec is not supported.
*/
public PrivateKey engineGeneratePrivate(KeySpec keySpec)
throws InvalidKeySpecException
{
if (keySpec instanceof RainbowPrivateKeySpec)
{
return new BCRainbowPrivateKey((RainbowPrivateKeySpec)keySpec);
}
else if (keySpec instanceof PKCS8EncodedKeySpec)
{
// get the DER-encoded Key according to PKCS#8 from the spec
byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
try
{
return generatePrivate(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)));
}
catch (Exception e)
{
throw new InvalidKeySpecException(e.toString());
}
}
throw new InvalidKeySpecException("Unsupported key specification: "
+ keySpec.getClass() + ".");
}
/**
* Converts, if possible, a key specification into a
* {@link BCRainbowPublicKey}. Currently, the following key specifications are
* supported:{@link X509EncodedKeySpec}.
* <p>
* The ASN.1 definition of a public key's structure is
* <pre>
* RainbowPublicKey ::= SEQUENCE {
* oid OBJECT IDENTIFIER -- OID identifying the algorithm
* docLength Integer -- length of signable msg
* coeffquadratic SEQUENCE OF OCTET STRING -- quadratic (mixed) coefficients
* coeffsingular SEQUENCE OF OCTET STRING -- singular coefficients
* coeffscalar OCTET STRING -- scalar coefficients
* }
* </pre>
* </p>
*
* @param keySpec the key specification
* @return the Rainbow public key
* @throws InvalidKeySpecException if the KeySpec is not supported.
*/
public PublicKey engineGeneratePublic(KeySpec keySpec)
throws InvalidKeySpecException
{
if (keySpec instanceof RainbowPublicKeySpec)
{
return new BCRainbowPublicKey((RainbowPublicKeySpec)keySpec);
}
else if (keySpec instanceof X509EncodedKeySpec)
{
// get the DER-encoded Key according to X.509 from the spec
byte[] encKey = ((X509EncodedKeySpec)keySpec).getEncoded();
// decode the SubjectPublicKeyInfo data structure to the pki object
try
{
return generatePublic(SubjectPublicKeyInfo.getInstance(encKey));
}
catch (Exception e)
{
throw new InvalidKeySpecException(e.toString());
}
}
throw new InvalidKeySpecException("Unknown key specification: " + keySpec + ".");
}
/**
* Converts a given key into a key specification, if possible. Currently the
* following specs are supported:
* <ul>
* <li>for RainbowPublicKey: X509EncodedKeySpec, RainbowPublicKeySpec
* <li>for RainbowPrivateKey: PKCS8EncodedKeySpec, RainbowPrivateKeySpec
* </ul>
*
* @param key the key
* @param keySpec the key specification
* @return the specification of the CMSS key
* @throws InvalidKeySpecException if the key type or key specification is not supported.
*/
public final KeySpec engineGetKeySpec(Key key, Class keySpec)
throws InvalidKeySpecException
{
if (key instanceof BCRainbowPrivateKey)
{
if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec))
{
return new PKCS8EncodedKeySpec(key.getEncoded());
}
else if (RainbowPrivateKeySpec.class.isAssignableFrom(keySpec))
{
BCRainbowPrivateKey privKey = (BCRainbowPrivateKey)key;
return new RainbowPrivateKeySpec(privKey.getInvA1(), privKey
.getB1(), privKey.getInvA2(), privKey.getB2(), privKey
.getVi(), privKey.getLayers());
}
}
else if (key instanceof BCRainbowPublicKey)
{
if (X509EncodedKeySpec.class.isAssignableFrom(keySpec))
{
return new X509EncodedKeySpec(key.getEncoded());
}
else if (RainbowPublicKeySpec.class.isAssignableFrom(keySpec))
{
BCRainbowPublicKey pubKey = (BCRainbowPublicKey)key;
return new RainbowPublicKeySpec(pubKey.getDocLength(), pubKey
.getCoeffQuadratic(), pubKey.getCoeffSingular(), pubKey
.getCoeffScalar());
}
}
else
{
throw new InvalidKeySpecException("Unsupported key type: "
+ key.getClass() + ".");
}
throw new InvalidKeySpecException("Unknown key specification: "
+ keySpec + ".");
}
/**
* Translates a key into a form known by the FlexiProvider. Currently the
* following key types are supported: RainbowPrivateKey, RainbowPublicKey.
*
* @param key the key
* @return a key of a known key type
* @throws InvalidKeyException if the key is not supported.
*/
public final Key engineTranslateKey(Key key)
throws InvalidKeyException
{
if (key instanceof BCRainbowPrivateKey || key instanceof BCRainbowPublicKey)
{
return key;
}
throw new InvalidKeyException("Unsupported key type");
}
public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
throws IOException
{
RainbowPrivateKey pKey = RainbowPrivateKey.getInstance(keyInfo.parsePrivateKey());
return new BCRainbowPrivateKey(pKey.getInvA1(), pKey.getB1(), pKey.getInvA2(), pKey.getB2(), pKey.getVi(), pKey.getLayers());
}
public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
throws IOException
{
RainbowPublicKey pKey = RainbowPublicKey.getInstance(keyInfo.parsePublicKey());
return new BCRainbowPublicKey(pKey.getDocLength(), pKey.getCoeffQuadratic(), pKey.getCoeffSingular(), pKey.getCoeffScalar());
}
}