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

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

Go to download

The FIPS 140-3 Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms certified to FIPS 140-3 level 1. This jar contains JCE provider and low-level API for the BC-FJA version 2.0.0, FIPS Certificate #4743. Please see certificate for certified platform details.

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

import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.security.auth.Destroyable;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.Algorithm;
import org.bouncycastle.crypto.AsymmetricPrivateKey;
import org.bouncycastle.crypto.general.EdEC;
import org.bouncycastle.crypto.internal.Permissions;
import org.bouncycastle.util.Arrays;

/**
 * Edwards Curve Diffie-Hellman (XDH) private keys.
 */
public final class AsymmetricXDHPrivateKey
    extends AsymmetricXDHKey
    implements Destroyable, AsymmetricPrivateKey
{
    private final AtomicBoolean hasBeenDestroyed = new AtomicBoolean(false);

    private final byte[] keyData;
    private byte[] publicData;
    private boolean hasPublicKey;

    private ASN1Set attributes;
    private int hashCode;

    public AsymmetricXDHPrivateKey(Algorithm algorithm, byte[] keyData, byte[] publicData)
    {
        super(algorithm);
        this.keyData = Arrays.clone(keyData);
        this.hashCode = calculateHashCode();
        this.attributes = null;
        if (publicData == null)
        {
            this.hasPublicKey = false;
            this.publicData = EdEC.computePublicData(algorithm, keyData);
        }
        else
        {
            this.hasPublicKey = true;
            this.publicData = Arrays.clone(publicData);
        }
    }

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

    /**
     * Construct a key from a PrivateKeyInfo.
     *
     * @param keyInfo the PrivateKeyInfo containing the key.
     */
    public AsymmetricXDHPrivateKey(PrivateKeyInfo keyInfo)
        throws IOException
    {
        super(EdECObjectIdentifiers.id_X448.equals(keyInfo.getPrivateKeyAlgorithm().getAlgorithm())
                    ? EdEC.Algorithm.X448 : EdEC.Algorithm.X25519);

        ASN1Encodable keyOcts = keyInfo.parsePrivateKey();
        keyData = Arrays.clone(ASN1OctetString.getInstance(keyOcts).getOctets());

        if (keyInfo.hasPublicKey())
        {
            hasPublicKey = true;
            publicData = Arrays.clone(keyInfo.getPublicKeyData().getOctets());
        }
        else
        {
            publicData = null;
        }

        if (EdECObjectIdentifiers.id_X448.equals(keyInfo.getPrivateKeyAlgorithm().getAlgorithm()))
        {
            if (keyData.length != EdEC.X448_PRIVATE_KEY_SIZE)
            {
                throw new IllegalArgumentException("raw key data incorrect size");
            }
        }
        else
        {
            if (keyData.length != EdEC.X25519_PRIVATE_KEY_SIZE)
            {
                throw new IllegalArgumentException("raw key data incorrect size");
            }
        }

        this.attributes = keyInfo.getAttributes();
        this.hashCode = calculateHashCode();
    }

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

        KeyUtils.checkPermission(Permissions.CanOutputPrivateKey);

        KeyUtils.checkDestroyed(this);
        
        return Arrays.clone(keyData);
    }

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

        return Arrays.clone(publicData);
    }

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

        KeyUtils.checkPermission(Permissions.CanOutputPrivateKey);

        KeyUtils.checkDestroyed(this);

        byte[] pubData = (hasPublicKey) ? publicData : null;

        if (getAlgorithm().equals(EdEC.Algorithm.X448))
        {
            return KeyUtils.getEncodedPrivateKeyInfo(
                new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448), new DEROctetString(keyData), attributes, pubData);
        }
        else
        {
            return KeyUtils.getEncodedPrivateKeyInfo(
                new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519), new DEROctetString(keyData), attributes, pubData);
        }
    }

    protected void zeroize()
    {
        super.zeroize();
        Arrays.clear(keyData);
    }

    public void destroy()
    {
        checkApprovedOnlyModeStatus();

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

    public boolean isDestroyed()
    {
        checkApprovedOnlyModeStatus();

        return hasBeenDestroyed.get();
    }

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

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

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

        AsymmetricXDHPrivateKey other = (AsymmetricXDHPrivateKey)o;

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

        if (!Arrays.areEqual(keyData, other.keyData))
        {
            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;
    }

    @Override
    protected void finalize()
        throws Throwable
    {
        super.finalize();

        destroy();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy