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

org.bouncycastle.crypto.asymmetric.AsymmetricLMSPrivateKey Maven / Gradle / Ivy

Go to download

The FIPS 140-2 Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms certified to FIPS 140-2 level 1. This jar contains the debug version JCE provider and low-level API for the BC-FJA version 1.0.2.3, FIPS Certificate #3514. Please note the debug jar is not certified.

There is a newer version: 2.0.0
Show newest version
package org.bouncycastle.crypto.asymmetric;

import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.atomic.AtomicBoolean;

import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.AsymmetricPrivateKey;
import org.bouncycastle.crypto.internal.Permissions;
import org.bouncycastle.crypto.internal.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.internal.pqc.lms.Composer;
import org.bouncycastle.crypto.internal.pqc.lms.HSSPrivateKeyParameters;
import org.bouncycastle.crypto.internal.pqc.lms.LMSContextBasedSigner;
import org.bouncycastle.crypto.internal.pqc.lms.LMSPrivateKeyParameters;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Pack;
import org.bouncycastle.util.Properties;

/**
 * Leighton-Micali Hash-Based Signatures (LMS) private keys.
 */
public final class AsymmetricLMSPrivateKey
    extends AsymmetricLMSKey
    implements AsymmetricPrivateKey
{
    private final AtomicBoolean hasBeenDestroyed = new AtomicBoolean(false);

    private final byte[] keyData;

    private byte[] publicData;
    private ASN1Set attributes;
    private int hashCode;
    private AsymmetricKeyParameter lwKey;

    public AsymmetricLMSPrivateKey(int levels, byte[] keyData, byte[] publicData)
    {
        super(levels);

        this.keyData = Arrays.clone(keyData);
        this.publicData = Arrays.clone(publicData);
        this.hashCode = calculateHashCode();
        this.lwKey = getLwKey(this);
    }

    /**
     * Construct a key from an encoding of a PrivateKeyInfo.
     *
     * @param encoding the DER encoding of the key.
     */
    public AsymmetricLMSPrivateKey(byte[] encoding)
        throws IOException
    {
        this(PrivateKeyInfo.getInstance(encoding));
    }

    /**
     * Construct a key from a PrivateKeyInfo.
     *
     * @param keyInfo the PrivateKeyInfo containing the key.
     */
    public AsymmetricLMSPrivateKey(PrivateKeyInfo keyInfo)
        throws IOException
    {
        this(ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets(), keyInfo.getPublicKeyData(), keyInfo.getAttributes());
    }

    private AsymmetricLMSPrivateKey(byte[]  keyEnc, ASN1BitString pubKey, ASN1Set attributes)
    {
        this(Pack.bigEndianToInt(keyEnc, 0), keyEnc, pubKey, attributes);
    }

    private AsymmetricLMSPrivateKey(int L, byte[]  keyEnc, ASN1BitString pubKey, ASN1Set attributes)
    {
        super(L);

        this.keyData = Arrays.copyOfRange(keyEnc, 4, keyEnc.length);

        this.attributes = attributes;
        this.hashCode = calculateHashCode();
        this.lwKey = getLwKey(this);

        if (pubKey != null)
        {
            byte[] pubEnc = pubKey.getOctets();

            publicData = Arrays.copyOfRange(pubEnc, 4, pubEnc.length);
        }
        else
        {
            if (this.lwKey instanceof LMSPrivateKeyParameters)
            {
                publicData = ((LMSPrivateKeyParameters)lwKey).getPublicKey().getEncoded();
            }
            else
            {
                publicData = ((HSSPrivateKeyParameters)lwKey).getPublicKey().getLMSPublicKey().getEncoded();
            }
        }
    }

    public long getUsagesRemaining()
    {
        if (lwKey instanceof LMSPrivateKeyParameters)
        {
            return ((LMSPrivateKeyParameters)lwKey).getUsagesRemaining();
        }
        else
        {
            return ((HSSPrivateKeyParameters)lwKey).getUsagesRemaining();
        }
    }

    public long getIndex()
    {
        if (lwKey instanceof LMSPrivateKeyParameters)
        {
            return ((LMSPrivateKeyParameters)lwKey).getIndex();
        }
        else
        {
            return ((HSSPrivateKeyParameters)lwKey).getIndex();
        }
    }

    public byte[] getSecret()
    {
        checkApprovedOnlyModeStatus();

        KeyUtils.checkPermission(Permissions.CanOutputPrivateKey);

        byte[] kd = Arrays.clone(keyData);

        KeyUtils.checkDestroyed(this);

        return kd;
    }

    public byte[] getPublicData()
    {
        KeyUtils.checkDestroyed(this);

        return Arrays.clone(publicData);
    }

    public AsymmetricLMSPrivateKey extractKeyShard(int usageCount)
    {
        if (lwKey instanceof LMSPrivateKeyParameters)
        {
            LMSPrivateKeyParameters shard = ((LMSPrivateKeyParameters)lwKey).extractKeyShard(usageCount);

            return new AsymmetricLMSPrivateKey(1, shard.getEncoded(), publicData);
        }
        else
        {
            HSSPrivateKeyParameters shard = ((HSSPrivateKeyParameters)lwKey).extractKeyShard(usageCount);

            return new AsymmetricLMSPrivateKey(getL(), shard.getEncoded(), publicData);
        }
    }

    public byte[] getEncoded()
    {
        checkApprovedOnlyModeStatus();

        KeyUtils.checkPermission(Permissions.CanOutputPrivateKey);

        KeyUtils.checkDestroyed(this);

        byte[] encoding = Composer.compose().u32str(L).bytes(keyData).build();
        byte[] pubEncoding = Composer.compose().u32str(L).bytes(publicData).build();

        AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_alg_hss_lms_hashsig);
        if (Properties.isOverrideSet("org.bouncycastle.pkcs8.v1_info_only"))
        {
            return KeyUtils.getEncodedPrivateKeyInfo(algorithmIdentifier, new DEROctetString(encoding), attributes, null);
        }
        else
        {
            return KeyUtils.getEncodedPrivateKeyInfo(algorithmIdentifier, new DEROctetString(encoding), attributes, pubEncoding);
        }
    }

    public void destroy()
    {
        checkApprovedOnlyModeStatus();

        if (!hasBeenDestroyed.getAndSet(true))
        {
            Arrays.clear(keyData);
            if (publicData != null)
            {
                Arrays.clear(publicData);
            }
            this.publicData = null;
            this.attributes = null;
            this.lwKey = null;
            this.hashCode = -1;
            super.zeroize();
        }
    }

    public boolean isDestroyed()
    {
        checkApprovedOnlyModeStatus();

        return hasBeenDestroyed.get();
    }

    @Override
    public boolean equals(Object o)
    {
        checkApprovedOnlyModeStatus();

        if (this == o)
        {
            return true;
        }

        if (!(o instanceof AsymmetricLMSPrivateKey))
        {
            return false;
        }

        AsymmetricLMSPrivateKey other = (AsymmetricLMSPrivateKey)o;

        other.checkApprovedOnlyModeStatus();

        if (this.isDestroyed() || other.isDestroyed())
        {
            return false;
        }

        if (!Arrays.constantTimeAreEqual(getSecret(), other.getSecret()))
        {
            return false;
        }

        return this.getAlgorithm().equals(other.getAlgorithm());
    }

    @Override
    public int hashCode()
    {
        checkApprovedOnlyModeStatus();

        return hashCode;
    }

    private int calculateHashCode()
    {
        int result = getAlgorithm().hashCode();
        result = 31 * result + Arrays.hashCode(keyData);
        return result;
    }

    public LMSContextBasedSigner getContextBasedSigner()
    {
        return (LMSContextBasedSigner)lwKey;
    }

    private static AsymmetricKeyParameter getLwKey(final AsymmetricLMSPrivateKey privKey)
    {
        return AccessController.doPrivileged(new PrivilegedAction()
        {
            public AsymmetricKeyParameter run()
            {
                try
                {
                    if (privKey.getL() == 1)
                    {
                        return LMSPrivateKeyParameters.getInstance(privKey.getSecret());
                    }
                    else
                    {
                        return HSSPrivateKeyParameters.getInstance(privKey.getSecret());
                    }
                }
                catch (IOException e)
                {
                    throw new IllegalStateException(e);
                }
            }
        });
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy