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

org.bouncycastle.crypto.kems.ECIESKeyEncapsulation 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.4.

There is a newer version: 1.79
Show newest version
package org.bouncycastle.crypto.kems;

import java.math.BigInteger;
import java.security.SecureRandom;

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DerivationFunction;
import org.bouncycastle.crypto.KeyEncapsulation;
import org.bouncycastle.crypto.params.ECKeyParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.KDFParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.BigIntegers;

/**
 * The ECIES Key Encapsulation Mechanism (ECIES-KEM) from ISO 18033-2.
 */
public class ECIESKeyEncapsulation
    implements KeyEncapsulation
{
    private static final BigInteger ONE = BigInteger.valueOf(1);

    private DerivationFunction kdf;
    private SecureRandom rnd;
    private ECKeyParameters key;
    private boolean CofactorMode;
    private boolean OldCofactorMode;
    private boolean SingleHashMode;

    /**
     * Set up the ECIES-KEM.
     *
     * @param kdf the key derivation function to be used.
     * @param rnd the random source for the session key.
     */
    public ECIESKeyEncapsulation(
        DerivationFunction kdf,
        SecureRandom rnd)
    {
        this.kdf = kdf;
        this.rnd = rnd;
        this.CofactorMode = false;
        this.OldCofactorMode = false;
        this.SingleHashMode = false;
    }

    /**
     * Set up the ECIES-KEM.
     *
     * @param kdf             the key derivation function to be used.
     * @param rnd             the random source for the session key.
     * @param cofactorMode    true to use the new cofactor ECDH.
     * @param oldCofactorMode true to use the old cofactor ECDH.
     * @param singleHashMode  true to use single hash mode.
     */
    public ECIESKeyEncapsulation(
        DerivationFunction kdf,
        SecureRandom rnd,
        boolean cofactorMode,
        boolean oldCofactorMode,
        boolean singleHashMode)
    {
        this.kdf = kdf;
        this.rnd = rnd;

        // If both cofactorMode and oldCofactorMode are set to true
        // then the implementation will use the new cofactor ECDH 
        this.CofactorMode = cofactorMode;
        this.OldCofactorMode = oldCofactorMode;
        this.SingleHashMode = singleHashMode;
    }

    /**
     * Initialise the ECIES-KEM.
     *
     * @param key the recipient's public (for encryption) or private (for decryption) key.
     */
    public void init(CipherParameters key)
        throws IllegalArgumentException
    {
        if (!(key instanceof ECKeyParameters))
        {
            throw new IllegalArgumentException("EC key required");
        }
        else
        {
            this.key = (ECKeyParameters)key;
        }
    }

    /**
     * Generate and encapsulate a random session key.
     *
     * @param out    the output buffer for the encapsulated key.
     * @param outOff the offset for the output buffer.
     * @param keyLen the length of the session key.
     * @return the random session key.
     */
    public CipherParameters encrypt(byte[] out, int outOff, int keyLen)
        throws IllegalArgumentException
    {
        if (!(key instanceof ECPublicKeyParameters))
        {
            throw new IllegalArgumentException("Public key required for encryption");
        }

        BigInteger n = key.getParameters().getN();
        BigInteger h = key.getParameters().getH();

        // Generate the ephemeral key pair    
        BigInteger r = BigIntegers.createRandomInRange(ONE, n, rnd);
        ECPoint gTilde = key.getParameters().getG().multiply(r);

        // Encode the ephemeral public key
        byte[] C = gTilde.getEncoded();
        System.arraycopy(C, 0, out, outOff, C.length);

        // Compute the static-ephemeral key agreement
        BigInteger rPrime;
        if (CofactorMode)
        {
            rPrime = r.multiply(h).mod(n);
        }
        else
        {
            rPrime = r;
        }

        ECPoint hTilde = ((ECPublicKeyParameters)key).getQ().multiply(rPrime);

        // Encode the shared secret value
        int PEHlen = (key.getParameters().getCurve().getFieldSize() + 7) / 8;
        byte[] PEH = BigIntegers.asUnsignedByteArray(PEHlen, hTilde.getX().toBigInteger());

        // Initialise the KDF
        byte[] kdfInput;
        if (SingleHashMode)
        {
            kdfInput = new byte[C.length + PEH.length];
            System.arraycopy(C, 0, kdfInput, 0, C.length);
            System.arraycopy(PEH, 0, kdfInput, C.length, PEH.length);
        }
        else
        {
            kdfInput = PEH;
        }

        kdf.init(new KDFParameters(kdfInput, null));

        // Generate the secret key
        byte[] K = new byte[keyLen];
        kdf.generateBytes(K, 0, K.length);

        // Return the ciphertext
        return new KeyParameter(K);
    }

    /**
     * Generate and encapsulate a random session key.
     *
     * @param out    the output buffer for the encapsulated key.
     * @param keyLen the length of the session key.
     * @return the random session key.
     */
    public CipherParameters encrypt(byte[] out, int keyLen)
    {
        return encrypt(out, 0, keyLen);
    }

    /**
     * Decrypt an encapsulated session key.
     *
     * @param in     the input buffer for the encapsulated key.
     * @param inOff  the offset for the input buffer.
     * @param inLen  the length of the encapsulated key.
     * @param keyLen the length of the session key.
     * @return the session key.
     */
    public CipherParameters decrypt(byte[] in, int inOff, int inLen, int keyLen)
        throws IllegalArgumentException
    {
        if (!(key instanceof ECPrivateKeyParameters))
        {
            throw new IllegalArgumentException("Private key required for encryption");
        }

        BigInteger n = key.getParameters().getN();
        BigInteger h = key.getParameters().getH();

        // Decode the ephemeral public key
        byte[] C = new byte[inLen];
        System.arraycopy(in, inOff, C, 0, inLen);
        ECPoint gTilde = key.getParameters().getCurve().decodePoint(C);

        // Compute the static-ephemeral key agreement
        ECPoint gHat;
        if ((CofactorMode) || (OldCofactorMode))
        {
            gHat = gTilde.multiply(h);
        }
        else
        {
            gHat = gTilde;
        }

        BigInteger xHat;
        if (CofactorMode)
        {
            xHat = ((ECPrivateKeyParameters)key).getD().multiply(h.modInverse(n)).mod(n);
        }
        else
        {
            xHat = ((ECPrivateKeyParameters)key).getD();
        }

        ECPoint hTilde = gHat.multiply(xHat);

        // Encode the shared secret value
        int PEHlen = (key.getParameters().getCurve().getFieldSize() + 7) / 8;
        byte[] PEH = BigIntegers.asUnsignedByteArray(PEHlen, hTilde.getX().toBigInteger());

        // Initialise the KDF
        byte[] kdfInput;
        if (SingleHashMode)
        {
            kdfInput = new byte[C.length + PEH.length];
            System.arraycopy(C, 0, kdfInput, 0, C.length);
            System.arraycopy(PEH, 0, kdfInput, C.length, PEH.length);
        }
        else
        {
            kdfInput = PEH;
        }
        kdf.init(new KDFParameters(kdfInput, null));

        // Generate the secret key
        byte[] K = new byte[keyLen];
        kdf.generateBytes(K, 0, K.length);

        return new KeyParameter(K);
    }

    /**
     * Decrypt an encapsulated session key.
     *
     * @param in     the input buffer for the encapsulated key.
     * @param keyLen the length of the session key.
     * @return the session key.
     */
    public CipherParameters decrypt(byte[] in, int keyLen)
    {
        return decrypt(in, 0, in.length, keyLen);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy