All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.SignatureSpi Maven / Gradle / Ivy

Go to download

The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for JDK 1.5 to JDK 1.8.

The newest version!
package org.bouncycastle.jcajce.provider.asymmetric.compositesignatures;

import java.io.IOException;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.InvalidParameterException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.AlgorithmParameterSpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.jcajce.CompositePrivateKey;
import org.bouncycastle.jcajce.CompositePublicKey;
import org.bouncycastle.jcajce.spec.CompositeAlgorithmSpec;
import org.bouncycastle.util.Exceptions;

/**
 * Signature class for composite signatures. Selected algorithm is set by the "subclasses" at the end of this file.
 */
public class SignatureSpi
    extends java.security.SignatureSpi
{
    private static final Map canonicalNames = new HashMap();

    private static final String ML_DSA_44 = "ML-DSA-44";
    private static final String ML_DSA_65 = "ML-DSA-65";
    private static final String ML_DSA_87 = "ML-DSA-87";

    static
    {
        canonicalNames.put("MLDSA44", ML_DSA_44);
        canonicalNames.put("MLDSA65", ML_DSA_65);
        canonicalNames.put("MLDSA87", ML_DSA_87);
        canonicalNames.put(NISTObjectIdentifiers.id_ml_dsa_44.getId(), ML_DSA_44);
        canonicalNames.put(NISTObjectIdentifiers.id_ml_dsa_65.getId(), ML_DSA_65);
        canonicalNames.put(NISTObjectIdentifiers.id_ml_dsa_87.getId(), ML_DSA_87);
    }

    //Enum value of the selected composite signature algorithm.
    private final CompositeSignaturesConstants.CompositeName algorithmIdentifier;
    //ASN1 OI value of the selected composite signature algorithm.
    private final ASN1ObjectIdentifier algorithmIdentifierASN1;

    //List of Signatures. Each entry corresponds to a component signature from the composite definition.
    private final List componentSignatures;

    //Hash function that is used to pre-hash the input message before it is fed into the component Signature.
    //Each composite signature has a specific hash function https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html
    private final Digest digest;
    private byte[] OIDBytes;


    SignatureSpi(CompositeSignaturesConstants.CompositeName algorithmIdentifier)
    {
        this.algorithmIdentifier = algorithmIdentifier;
        this.algorithmIdentifierASN1 = CompositeSignaturesConstants.compositeNameASN1IdentifierMap.get(this.algorithmIdentifier);
        List componentSignatures = new ArrayList();
        try
        {
            switch (this.algorithmIdentifier)
            {
            case MLDSA44_Ed25519_SHA512:
                componentSignatures.add(Signature.getInstance(ML_DSA_44, "BC"));
                componentSignatures.add(Signature.getInstance("Ed25519", "BC"));
                this.digest = DigestFactory.createSHA512();
                break;
            case MLDSA65_Ed25519_SHA512:
                componentSignatures.add(Signature.getInstance(ML_DSA_65, "BC"));
                componentSignatures.add(Signature.getInstance("Ed25519", "BC"));
                this.digest = DigestFactory.createSHA512();
                break;
            case MLDSA87_Ed448_SHA512:
                componentSignatures.add(Signature.getInstance(ML_DSA_87, "BC"));
                componentSignatures.add(Signature.getInstance("Ed448", "BC"));
                this.digest = DigestFactory.createSHA512();
                break;
            case MLDSA44_RSA2048_PSS_SHA256:
                componentSignatures.add(Signature.getInstance(ML_DSA_44, "BC"));
                componentSignatures.add(Signature.getInstance("SHA256withRSA/PSS", "BC")); //PSS with SHA-256 as digest algo and MGF.
                this.digest = DigestFactory.createSHA256();
                break;
            case MLDSA65_RSA3072_PSS_SHA512:
                componentSignatures.add(Signature.getInstance(ML_DSA_65, "BC"));
                componentSignatures.add(Signature.getInstance("SHA512withRSA/PSS", "BC")); //PSS with SHA-512 as digest algo and MGF.
                this.digest = DigestFactory.createSHA512();
                break;
            case MLDSA44_RSA2048_PKCS15_SHA256:
                componentSignatures.add(Signature.getInstance(ML_DSA_44, "BC"));
                componentSignatures.add(Signature.getInstance("SHA256withRSA", "BC")); //PKCS15
                this.digest = DigestFactory.createSHA256();
                break;
            case MLDSA65_RSA3072_PKCS15_SHA512:
                componentSignatures.add(Signature.getInstance(ML_DSA_65, "BC"));
                componentSignatures.add(Signature.getInstance("SHA512withRSA", "BC")); //PKCS15
                this.digest = DigestFactory.createSHA512();
                break;
            case MLDSA44_ECDSA_P256_SHA256:
            case MLDSA44_ECDSA_brainpoolP256r1_SHA256:
                componentSignatures.add(Signature.getInstance(ML_DSA_44, "BC"));
                componentSignatures.add(Signature.getInstance("SHA256withECDSA", "BC"));
                this.digest = DigestFactory.createSHA256();
                break;
            case MLDSA65_ECDSA_P256_SHA512:
            case MLDSA65_ECDSA_brainpoolP256r1_SHA512:
                componentSignatures.add(Signature.getInstance(ML_DSA_65, "BC"));
                componentSignatures.add(Signature.getInstance("SHA512withECDSA", "BC"));
                this.digest = DigestFactory.createSHA512();
                break;
            case MLDSA87_ECDSA_P384_SHA512:
            case MLDSA87_ECDSA_brainpoolP384r1_SHA512:
                componentSignatures.add(Signature.getInstance(ML_DSA_87, "BC"));
                componentSignatures.add(Signature.getInstance("SHA512withECDSA", "BC"));
                this.digest = DigestFactory.createSHA512();
                break;
            case Falcon512_ECDSA_P256_SHA256:
            case Falcon512_ECDSA_brainpoolP256r1_SHA256:
                componentSignatures.add(Signature.getInstance("Falcon", "BC"));
                componentSignatures.add(Signature.getInstance("SHA256withECDSA", "BC"));
                this.digest = DigestFactory.createSHA256();
                break;
            case Falcon512_Ed25519_SHA512:
                componentSignatures.add(Signature.getInstance("Falcon", "BC"));
                componentSignatures.add(Signature.getInstance("Ed25519", "BC"));
                this.digest = DigestFactory.createSHA512();
                break;
            default:
                throw new IllegalArgumentException("unknown composite algorithm");
            }

            //get bytes of composite signature algorithm OID in DER
            //these bytes are used a prefix to the message digest https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html#name-composite-sign
            OIDBytes = this.algorithmIdentifierASN1.getEncoded(ASN1Encoding.DER);
        }
        catch (GeneralSecurityException e)
        {
            throw Exceptions.illegalStateException(e.getMessage(), e);
        }
        catch (IOException e)
        {
            throw Exceptions.illegalStateException(e.getMessage(), e);
        }
        this.componentSignatures = Collections.unmodifiableList(componentSignatures);
    }

    protected void engineInitVerify(PublicKey publicKey)
        throws InvalidKeyException
    {

        if (!(publicKey instanceof CompositePublicKey))
        {
            throw new InvalidKeyException("Public key is not composite.");
        }

        CompositePublicKey compositePublicKey = (CompositePublicKey)publicKey;

        if (!compositePublicKey.getAlgorithmIdentifier().equals(this.algorithmIdentifierASN1))
        {
            throw new InvalidKeyException("Provided composite public key cannot be used with the composite signature algorithm.");
        }

        //for each component signature run initVerify with the corresponding public key.
        for (int i = 0; i < this.componentSignatures.size(); i++)
        {
            this.componentSignatures.get(i).initVerify(compositePublicKey.getPublicKeys().get(i));
        }
    }

    protected void engineInitSign(PrivateKey privateKey)
        throws InvalidKeyException
    {
        if (!(privateKey instanceof CompositePrivateKey))
        {
            throw new InvalidKeyException("Private key is not composite.");
        }

        CompositePrivateKey compositePrivateKey = (CompositePrivateKey)privateKey;

        if (!compositePrivateKey.getAlgorithmIdentifier().equals(this.algorithmIdentifierASN1))
        {
            throw new InvalidKeyException("Provided composite private key cannot be used with the composite signature algorithm.");
        }

        //for each component signature run initVerify with the corresponding private key.
        for (int i = 0; i < this.componentSignatures.size(); i++)
        {
            this.componentSignatures.get(i).initSign(compositePrivateKey.getPrivateKeys().get(i));
        }
    }


    protected void engineUpdate(byte b)
        throws SignatureException
    {
        digest.update(b);
    }

    protected void engineUpdate(byte[] bytes, int off, int len)
        throws SignatureException
    {
        digest.update(bytes, off, len);
    }

    /**
     * Method which calculates each component signature and constructs a composite signature
     * which is a sequence of BIT STRINGs https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html#name-compositesignaturevalue
     *
     * @return composite signature bytes
     * @throws SignatureException
     */
    protected byte[] engineSign()
        throws SignatureException
    {
        ASN1EncodableVector signatureSequence = new ASN1EncodableVector();
        try
        {
            //calculate message digest (pre-hashing of the message)
            byte[] digestResult = new byte[digest.getDigestSize()];
            digest.doFinal(digestResult, 0);

            for (int i = 0; i < this.componentSignatures.size(); i++)
            {
                this.componentSignatures.get(i).update(this.OIDBytes);
                this.componentSignatures.get(i).update(digestResult); //in total, "OID || digest(message)" is the message fed into each component signature
                byte[] signatureValue = this.componentSignatures.get(i).sign();
                signatureSequence.add(new DERBitString(signatureValue));
            }

            return new DERSequence(signatureSequence).getEncoded(ASN1Encoding.DER);
        }
        catch (IOException e)
        {
            throw new SignatureException(e.getMessage());
        }

    }

    /**
     * Corresponding verification method to the engineSign method.
     * The composite signature is valid if and only if all component signatures are valid.
     * The method verifies all component signatures even if it is already known that the composite signature is invalid.
     *
     * @param signature the signature bytes to be verified.
     * @return
     * @throws SignatureException
     */
    protected boolean engineVerify(byte[] signature)
        throws SignatureException
    {

        ASN1Sequence signatureSequence = DERSequence.getInstance(signature);
        //Check if the decoded sequence of component signatures has the expected size.
        if (signatureSequence.size() != this.componentSignatures.size())
        {
            return false;
        }

        //calculate message digest (pre-hashing of the message)
        byte[] digestResult = new byte[digest.getDigestSize()];
        digest.doFinal(digestResult, 0);

        // Currently all signatures try to verify even if, e.g., the first is invalid.
        // If each component verify() is constant time, then this is also, otherwise it does not make sense to iterate over all if one of them already fails.
        // However, it is important that we do not provide specific error messages, e.g., "only the 2nd component failed to verify".
        boolean fail = false;

        for (int i = 0; i < this.componentSignatures.size(); i++)
        {
            this.componentSignatures.get(i).update(this.OIDBytes);
            this.componentSignatures.get(i).update(digestResult); //in total, "OID || digest(message)" is the message fed into each component signature
            if (!this.componentSignatures.get(i).verify(ASN1BitString.getInstance(signatureSequence.getObjectAt(i)).getOctets()))
            {
                fail = true;
            }
        }

        return !fail;
    }

    protected void engineSetParameter(AlgorithmParameterSpec algorithmParameterSpec)
        throws InvalidAlgorithmParameterException
    {
        if (algorithmParameterSpec instanceof CompositeAlgorithmSpec)
        {
            CompositeAlgorithmSpec compAlgSpec = (CompositeAlgorithmSpec)algorithmParameterSpec;

            List specs = compAlgSpec.getParameterSpecs();
            List names = compAlgSpec.getAlgorithmNames();

            switch (this.algorithmIdentifier)
            {
            case MLDSA44_Ed25519_SHA512:
                setSigParameter(componentSignatures.get(0), ML_DSA_44, names, specs);
                break;
            case MLDSA65_Ed25519_SHA512:
                setSigParameter(componentSignatures.get(0), ML_DSA_65, names, specs);
                break;
            case MLDSA87_Ed448_SHA512:
                setSigParameter(componentSignatures.get(0), ML_DSA_87, names, specs);
                break;
            case MLDSA44_RSA2048_PSS_SHA256:
                setSigParameter(componentSignatures.get(0), ML_DSA_44, names, specs);
                break;
            case MLDSA65_RSA3072_PSS_SHA512:
                setSigParameter(componentSignatures.get(0), ML_DSA_65, names, specs);
                break;
            case MLDSA44_RSA2048_PKCS15_SHA256:
                setSigParameter(componentSignatures.get(0), ML_DSA_44, names, specs);
                break;
            case MLDSA65_RSA3072_PKCS15_SHA512:
                setSigParameter(componentSignatures.get(0), ML_DSA_65, names, specs);
                break;
            case MLDSA44_ECDSA_P256_SHA256:
            case MLDSA44_ECDSA_brainpoolP256r1_SHA256:
                setSigParameter(componentSignatures.get(0), ML_DSA_44, names, specs);
                break;
            case MLDSA65_ECDSA_P256_SHA512:
            case MLDSA65_ECDSA_brainpoolP256r1_SHA512:
                setSigParameter(componentSignatures.get(0), ML_DSA_65, names, specs);
                break;
            case MLDSA87_ECDSA_P384_SHA512:
            case MLDSA87_ECDSA_brainpoolP384r1_SHA512:
                setSigParameter(componentSignatures.get(0), ML_DSA_87, names, specs);
                break;
            default:
                throw new InvalidAlgorithmParameterException("unknown composite algorithm");
            }
        }
        else
        {
            throw new InvalidAlgorithmParameterException("unknown parameterSpec passed to composite signature");
        }
    }

    private void setSigParameter(Signature targetSig, String targetSigName, List names, List specs)
        throws InvalidAlgorithmParameterException
    {
        for (int i = 0; i != names.size(); i++)
        {
            String canonicalName = getCanonicalName(names.get(i));

            if (names.get(i).equals(targetSigName))
            {
                targetSig.setParameter(specs.get(i));
            }
        }
    }

    private String getCanonicalName(String baseName)
    {
        String name = canonicalNames.get(baseName);

        if (name != null)
        {
            return name;
        }

        return baseName;
    }

    protected void engineSetParameter(String s, Object o)
        throws InvalidParameterException
    {
        throw new UnsupportedOperationException("engineSetParameter unsupported");
    }

    protected Object engineGetParameter(String s)
        throws InvalidParameterException
    {
        throw new UnsupportedOperationException("engineGetParameter unsupported");
    }

    protected AlgorithmParameters engineGetParameters()
    {
        return null;
    }

    public final static class MLDSA44_Ed25519_SHA512
        extends SignatureSpi
    {
        public MLDSA44_Ed25519_SHA512()
        {
            super(CompositeSignaturesConstants.CompositeName.MLDSA44_Ed25519_SHA512);
        }
    }

    public final static class MLDSA65_Ed25519_SHA512
        extends SignatureSpi
    {
        public MLDSA65_Ed25519_SHA512()
        {
            super(CompositeSignaturesConstants.CompositeName.MLDSA65_Ed25519_SHA512);
        }
    }

    public final static class MLDSA87_Ed448_SHA512
        extends SignatureSpi
    {
        public MLDSA87_Ed448_SHA512()
        {
            super(CompositeSignaturesConstants.CompositeName.MLDSA87_Ed448_SHA512);
        }
    }

    public final static class MLDSA44_RSA2048_PSS_SHA256
        extends SignatureSpi
    {
        public MLDSA44_RSA2048_PSS_SHA256()
        {
            super(CompositeSignaturesConstants.CompositeName.MLDSA44_RSA2048_PSS_SHA256);
        }
    }

    public final static class MLDSA44_RSA2048_PKCS15_SHA256
        extends SignatureSpi
    {
        public MLDSA44_RSA2048_PKCS15_SHA256()
        {
            super(CompositeSignaturesConstants.CompositeName.MLDSA44_RSA2048_PKCS15_SHA256);
        }
    }

    public final static class MLDSA65_RSA3072_PSS_SHA512
        extends SignatureSpi
    {
        public MLDSA65_RSA3072_PSS_SHA512()
        {
            super(CompositeSignaturesConstants.CompositeName.MLDSA65_RSA3072_PSS_SHA512);
        }
    }

    public final static class MLDSA65_RSA3072_PKCS15_SHA512
        extends SignatureSpi
    {
        public MLDSA65_RSA3072_PKCS15_SHA512()
        {
            super(CompositeSignaturesConstants.CompositeName.MLDSA65_RSA3072_PKCS15_SHA512);
        }
    }

    public final static class MLDSA44_ECDSA_P256_SHA256
        extends SignatureSpi
    {
        public MLDSA44_ECDSA_P256_SHA256()
        {
            super(CompositeSignaturesConstants.CompositeName.MLDSA44_ECDSA_P256_SHA256);
        }
    }

    public final static class MLDSA44_ECDSA_brainpoolP256r1_SHA256
        extends SignatureSpi
    {
        public MLDSA44_ECDSA_brainpoolP256r1_SHA256()
        {
            super(CompositeSignaturesConstants.CompositeName.MLDSA44_ECDSA_brainpoolP256r1_SHA256);
        }
    }

    public final static class MLDSA65_ECDSA_P256_SHA512
        extends SignatureSpi
    {
        public MLDSA65_ECDSA_P256_SHA512()
        {
            super(CompositeSignaturesConstants.CompositeName.MLDSA65_ECDSA_P256_SHA512);
        }
    }

    public final static class MLDSA65_ECDSA_brainpoolP256r1_SHA512
        extends SignatureSpi
    {
        public MLDSA65_ECDSA_brainpoolP256r1_SHA512()
        {
            super(CompositeSignaturesConstants.CompositeName.MLDSA65_ECDSA_brainpoolP256r1_SHA512);
        }
    }

    public final static class MLDSA87_ECDSA_P384_SHA512
        extends SignatureSpi
    {
        public MLDSA87_ECDSA_P384_SHA512()
        {
            super(CompositeSignaturesConstants.CompositeName.MLDSA87_ECDSA_P384_SHA512);
        }
    }

    public final static class MLDSA87_ECDSA_brainpoolP384r1_SHA512
        extends SignatureSpi
    {
        public MLDSA87_ECDSA_brainpoolP384r1_SHA512()
        {
            super(CompositeSignaturesConstants.CompositeName.MLDSA87_ECDSA_brainpoolP384r1_SHA512);
        }
    }

    public final static class Falcon512_Ed25519_SHA512
        extends SignatureSpi
    {
        public Falcon512_Ed25519_SHA512()
        {
            super(CompositeSignaturesConstants.CompositeName.Falcon512_Ed25519_SHA512);
        }
    }

    public final static class Falcon512_ECDSA_P256_SHA256
        extends SignatureSpi
    {
        public Falcon512_ECDSA_P256_SHA256()
        {
            super(CompositeSignaturesConstants.CompositeName.Falcon512_ECDSA_P256_SHA256);
        }
    }

    public final static class Falcon512_ECDSA_brainpoolP256r1_SHA256
        extends SignatureSpi
    {
        public Falcon512_ECDSA_brainpoolP256r1_SHA256()
        {
            super(CompositeSignaturesConstants.CompositeName.Falcon512_ECDSA_brainpoolP256r1_SHA256);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy