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

com.weavechain.core.encrypt.ECIESKeys Maven / Gradle / Ivy

There is a newer version: 1.3
Show newest version
package com.weavechain.core.encrypt;

import net.thiim.dilithium.interfaces.DilithiumPublicKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.bitcoinj.base.Base58;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;

public class ECIESKeys implements KeyExchange {

    static final Logger logger = LoggerFactory.getLogger(ECIESKeys.class);

    private static final String CIPHER = "AES/CBC/PKCS5Padding";

    private static final String ALGORITHM = "ECDH";

    private static final String CURVE_TYPE = "secp256k1"; //secp256r1

    private static final String PROVIDER = BouncyCastleProvider.PROVIDER_NAME;

    @Override
    public KeyPair readKeys(String encodedPrivateKey, String encodedPublicKey) {
        try {
            PublicKey publicKey = readPublicKey(encodedPublicKey);
            PrivateKey privateKey = readPrivateKey(encodedPrivateKey);

            return new KeyPair(publicKey, privateKey);
        } catch (Exception e) {
            logger.error("Failed decoding keys", e);
            return null;
        }
    }

    static byte[] uncompress(byte[] compKey) throws IOException {
        ECParameterSpec spec = ECNamedCurveTable.getParameterSpec(CURVE_TYPE);
        ECPoint point = spec.getCurve().decodePoint(compKey);
        byte[] x = point.getXCoord().getEncoded();
        byte[] y = point.getYCoord().getEncoded();

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        outputStream.write(0x04);
        outputStream.write(x);
        outputStream.write(y);
        return outputStream.toByteArray();
    }

    private PublicKey readPublicKey(String encodedPublicKey) throws InvalidKeySpecException, NoSuchAlgorithmException {
        PublicKey publicKey = null;

        if (encodedPublicKey != null) {
            encodedPublicKey = encodedPublicKey.replace("\r", "").replace("\n", "").replace("\t", "").replace(" ", "");
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
            try {
                if (encodedPublicKey.length() < KeysProvider.MAX_B58_LEN) {
                    byte[] key = Base58.decode(encodedPublicKey.startsWith(KeysProvider.PREFIX) ? encodedPublicKey.substring(KeysProvider.PREFIX.length()) : encodedPublicKey);

                    ECParameterSpec spec = ECNamedCurveTable.getParameterSpec(CURVE_TYPE);
                    ECPoint pubPoint = spec.getCurve().decodePoint(key);
                    ECPublicKeySpec keySpec = new ECPublicKeySpec(pubPoint, spec);

                    publicKey = keyFactory.generatePublic(keySpec);
                } else {
                    byte[] key = Hex.decode(encodedPublicKey);
                    if (key.length > 0) {
                        publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(key));
                    }
                }
            } catch (Exception e) {
                try {
                    byte[] key = Base58.decode(encodedPublicKey);
                    publicKey = decodeKey(keyFactory, key);
                } catch (Exception ex) {
                    byte[] key = Base64.decodeBase64(encodedPublicKey);
                    publicKey = decodeKey(keyFactory, key);
                }
            }
        }
        return publicKey;
    }

    private PublicKey decodeKey(KeyFactory keyFactory, byte[] key) throws NoSuchAlgorithmException, InvalidKeySpecException {
        PublicKey publicKey;
        try {
            publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(key));
        } catch (InvalidKeySpecException e) {
            try {
                KeyFactory kf = KeyFactory.getInstance("EdDSA");
                publicKey = kf.generatePublic(new X509EncodedKeySpec(key));
            } catch (InvalidKeySpecException ex) {
                KeyFactory kf = KeyFactory.getInstance("Dilithium");
                publicKey = kf.generatePublic(new DilithiumPublicKeySpec(KeysProvider.DILITHIUM_PARAM_SPEC, key));
            }
        }
        return publicKey;
    }

    private PrivateKey readPrivateKey(String encodedPrivateKey) throws InvalidKeySpecException, NoSuchAlgorithmException {
        PrivateKey privateKey = null;

        if (encodedPrivateKey != null) {
            encodedPrivateKey = encodedPrivateKey.replace("\r", "").replace("\n", "").replace("\t", "").replace(" ", "");
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
            try {
                if (encodedPrivateKey.length() < KeysProvider.MAX_B58_LEN) {
                    byte[] key = Base58.decode(encodedPrivateKey);

                    BigInteger d = new BigInteger(1, key.length == 33 ? Arrays.copyOfRange(key, 1, key.length) : key);
                    ECNamedCurveParameterSpec params = ECNamedCurveTable.getParameterSpec(CURVE_TYPE);
                    ECPrivateKeySpec keySpec = new ECPrivateKeySpec(d, params);

                    return keyFactory.generatePrivate(keySpec);
                } else {
                    byte[] key = Hex.decode(encodedPrivateKey);
                    if (key.length > 0) {
                        privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(key));
                    }
                }
            } catch (Exception e) {
                byte[] key = Base64.decodeBase64(encodedPrivateKey);
                try {
                    privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(key));
                } catch (InvalidKeySpecException ex) {
                    KeyFactory kf = KeyFactory.getInstance("EdDSA");
                    privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(key));
                }
            }
        }
        return privateKey;
    }

    @Override
    public KeyPair generateKeys() {
        try {
            KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM, PROVIDER);
            kpg.initialize(new ECGenParameterSpec(CURVE_TYPE));
            return kpg.generateKeyPair();
        } catch (Exception e) {
            logger.error("Failed generating keys", e);
            return null;
        }
    }

    @Override
    public SecretKey sharedSecret(PrivateKey privateKey, PublicKey publicKey, byte[] message) {
        try {
            KeyAgreement keyAgreement = KeyAgreement.getInstance(ALGORITHM, PROVIDER);
            keyAgreement.init(privateKey);
            keyAgreement.doPhase(publicKey, true);
            return keyAgreement.generateSecret("AES");
        } catch (Exception e) {
            logger.error("Failed generating keys", e);
            return null;
        }
    }

    private byte[] getIV(byte[] seed, byte[] iv) {
        byte[] s = new byte[iv.length];
        for (int i = 0; i < iv.length; i++) {
            s[i] = iv[i];
            s[i] ^= seed[i % seed.length];
        }
        return s;
    }

    @Override
    public byte[] encrypt(SecretKey key, byte[] data, byte[] seed, byte[] iv) {
        try {
            IvParameterSpec ivSpec = new IvParameterSpec(getIV(seed, iv));
            Cipher cipher = Cipher.getInstance(CIPHER, PROVIDER);
            cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
            byte[] encrypted = new byte[cipher.getOutputSize(data.length)];
            int len = cipher.update(data, 0, data.length, encrypted, 0);
            cipher.doFinal(encrypted, len);
            return encrypted;
        } catch (Exception e) {
            logger.error("Failed encrypt", e);
            return null;
        }
    }

    @Override
    public byte[] decrypt(SecretKey key, byte[] data, byte[] seed, byte[] iv) {
        try {
            Key decryptionKey = new SecretKeySpec(key.getEncoded(), key.getAlgorithm());
            IvParameterSpec ivSpec = new IvParameterSpec(getIV(seed, iv));
            Cipher cipher = Cipher.getInstance(CIPHER, PROVIDER);
            cipher.init(Cipher.DECRYPT_MODE, decryptionKey, ivSpec);
            byte[] decrypted = new byte[cipher.getOutputSize(data.length)];
            int len = cipher.update(data, 0, data.length, decrypted, 0);
            cipher.doFinal(decrypted, len);
            return decrypted;
        } catch (Exception e) {
            logger.error("Failed decrypt", e);
            return null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy