| 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()); |
| } |
| } |