| package org.bouncycastle.pqc.jcajce.provider.mceliece; |
| |
| 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.pqc.asn1.McElieceCCA2PrivateKey; |
| import org.bouncycastle.pqc.asn1.McElieceCCA2PublicKey; |
| import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; |
| import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters; |
| import org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters; |
| |
| /** |
| * This class is used to translate between McEliece CCA2 keys and key |
| * specifications. |
| * |
| * @see BCMcElieceCCA2PrivateKey |
| * @see BCMcElieceCCA2PublicKey |
| */ |
| public class McElieceCCA2KeyFactorySpi |
| extends KeyFactorySpi |
| { |
| |
| /** |
| * The OID of the algorithm. |
| */ |
| public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2"; |
| |
| /** |
| * Converts, if possible, a key specification into a |
| * {@link BCMcElieceCCA2PublicKey}. Currently, the following key |
| * specifications are supported: |
| * {@link X509EncodedKeySpec}. |
| * |
| * @param keySpec the key specification |
| * @return the McEliece CCA2 public key |
| * @throws InvalidKeySpecException if the key specification is not supported. |
| */ |
| protected PublicKey engineGeneratePublic(KeySpec keySpec) |
| throws InvalidKeySpecException |
| { |
| 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 |
| SubjectPublicKeyInfo pki; |
| try |
| { |
| pki = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)); |
| } |
| catch (IOException e) |
| { |
| throw new InvalidKeySpecException(e.toString()); |
| } |
| |
| |
| try |
| { |
| if (PQCObjectIdentifiers.mcElieceCca2.equals(pki.getAlgorithm().getAlgorithm())) |
| { |
| McElieceCCA2PublicKey key = McElieceCCA2PublicKey.getInstance(pki.parsePublicKey()); |
| |
| return new BCMcElieceCCA2PublicKey(new McElieceCCA2PublicKeyParameters(key.getN(), key.getT(), key.getG(), Utils.getDigest(key.getDigest()).getAlgorithmName())); |
| } |
| else |
| { |
| throw new InvalidKeySpecException("Unable to recognise OID in McEliece private key"); |
| } |
| } |
| catch (IOException cce) |
| { |
| throw new InvalidKeySpecException( |
| "Unable to decode X509EncodedKeySpec: " |
| + cce.getMessage()); |
| } |
| } |
| |
| throw new InvalidKeySpecException("Unsupported key specification: " |
| + keySpec.getClass() + "."); |
| } |
| |
| /** |
| * Converts, if possible, a key specification into a |
| * {@link BCMcElieceCCA2PrivateKey}. Currently, the following key |
| * specifications are supported: |
| * {@link PKCS8EncodedKeySpec}. |
| * |
| * @param keySpec the key specification |
| * @return the McEliece CCA2 private key |
| * @throws InvalidKeySpecException if the KeySpec is not supported. |
| */ |
| protected PrivateKey engineGeneratePrivate(KeySpec keySpec) |
| throws InvalidKeySpecException |
| { |
| if (keySpec instanceof PKCS8EncodedKeySpec) |
| { |
| // get the DER-encoded Key according to PKCS#8 from the spec |
| byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded(); |
| |
| // decode the PKCS#8 data structure to the pki object |
| PrivateKeyInfo pki; |
| |
| try |
| { |
| pki = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)); |
| } |
| catch (IOException e) |
| { |
| throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec: " + e); |
| } |
| |
| try |
| { |
| if (PQCObjectIdentifiers.mcElieceCca2.equals(pki.getPrivateKeyAlgorithm().getAlgorithm())) |
| { |
| McElieceCCA2PrivateKey key = McElieceCCA2PrivateKey.getInstance(pki.parsePrivateKey()); |
| |
| return new BCMcElieceCCA2PrivateKey(new McElieceCCA2PrivateKeyParameters(key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getP(), Utils.getDigest(key.getDigest()).getAlgorithmName())); |
| } |
| else |
| { |
| throw new InvalidKeySpecException("Unable to recognise OID in McEliece public key"); |
| } |
| } |
| catch (IOException cce) |
| { |
| throw new InvalidKeySpecException( |
| "Unable to decode PKCS8EncodedKeySpec."); |
| } |
| } |
| |
| throw new InvalidKeySpecException("Unsupported key specification: " + keySpec.getClass() + "."); |
| } |
| |
| /** |
| * Converts, if possible, a given key into a key specification. Currently, |
| * the following key specifications are supported: |
| * |
| * @param key the key |
| * @param keySpec the key specification |
| * @return the specification of the McEliece CCA2 key |
| * @throws InvalidKeySpecException if the key type or the key specification is not |
| * supported. |
| * @see BCMcElieceCCA2PrivateKey |
| * @see BCMcElieceCCA2PublicKey |
| */ |
| public KeySpec getKeySpec(Key key, Class keySpec) |
| throws InvalidKeySpecException |
| { |
| if (key instanceof BCMcElieceCCA2PrivateKey) |
| { |
| if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) |
| { |
| return new PKCS8EncodedKeySpec(key.getEncoded()); |
| } |
| } |
| else if (key instanceof BCMcElieceCCA2PublicKey) |
| { |
| if (X509EncodedKeySpec.class.isAssignableFrom(keySpec)) |
| { |
| return new X509EncodedKeySpec(key.getEncoded()); |
| } |
| } |
| 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, only |
| * the following "source" keys are supported: {@link BCMcElieceCCA2PrivateKey}, |
| * {@link BCMcElieceCCA2PublicKey}. |
| * |
| * @param key the key |
| * @return a key of a known key type |
| * @throws InvalidKeyException if the key type is not supported. |
| */ |
| public Key translateKey(Key key) |
| throws InvalidKeyException |
| { |
| if ((key instanceof BCMcElieceCCA2PrivateKey) |
| || (key instanceof BCMcElieceCCA2PublicKey)) |
| { |
| return key; |
| } |
| throw new InvalidKeyException("Unsupported key type."); |
| |
| } |
| |
| |
| public PublicKey generatePublic(SubjectPublicKeyInfo pki) |
| throws InvalidKeySpecException |
| { |
| // get the inner type inside the BIT STRING |
| try |
| { |
| ASN1Primitive innerType = pki.parsePublicKey(); |
| McElieceCCA2PublicKey key = McElieceCCA2PublicKey.getInstance(innerType); |
| return new BCMcElieceCCA2PublicKey(new McElieceCCA2PublicKeyParameters(key.getN(), key.getT(), key.getG(), Utils.getDigest(key.getDigest()).getAlgorithmName())); |
| } |
| catch (IOException cce) |
| { |
| throw new InvalidKeySpecException("Unable to decode X509EncodedKeySpec"); |
| } |
| } |
| |
| |
| public PrivateKey generatePrivate(PrivateKeyInfo pki) |
| throws InvalidKeySpecException |
| { |
| // get the inner type inside the BIT STRING |
| try |
| { |
| ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive(); |
| McElieceCCA2PrivateKey key = McElieceCCA2PrivateKey.getInstance(innerType); |
| return new BCMcElieceCCA2PrivateKey(new McElieceCCA2PrivateKeyParameters(key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getP(), null)); |
| } |
| catch (IOException cce) |
| { |
| throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec"); |
| } |
| } |
| |
| protected KeySpec engineGetKeySpec(Key key, Class tClass) |
| throws InvalidKeySpecException |
| { |
| return null; //To change body of implemented methods use File | Settings | File Templates. |
| } |
| |
| protected Key engineTranslateKey(Key key) |
| throws InvalidKeyException |
| { |
| return null; //To change body of implemented methods use File | Settings | File Templates. |
| } |
| } |