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

one.credify.crypto.Encryption Maven / Gradle / Ivy

package one.credify.crypto;

import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.pkcs.PKCSException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.security.*;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.spec.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * RSA 4096 bit encryption
 */
public class Encryption {
    private PublicKey publicKey;
    private PrivateKey privateKey;
    private static int KEY_SIZE = 3072;

    public Encryption() {
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
    }

    public PrivateKey getPrivateKey() {
        return privateKey;
    }

    public PublicKey getPublicKey() {
        return publicKey;
    }

    public byte[] getPublicKeyEncoded() {
        return publicKey.getEncoded();
    }

    public byte[] getPrivateKeyEncoded() {
        return privateKey.getEncoded();
    }

    public String getPublicKeyString() {
        String data = Base64.getEncoder().encodeToString(this.getPublicKeyEncoded());
        return Utils.BEGIN_PUBLIC_KEY + data.replaceAll("(.{64})", "$1\n") + Utils.END_PUBLIC_KEY;
    }

    public String getPublicKeyInBase64Url() {
        return Base64.getUrlEncoder().withoutPadding().encodeToString(this.getPublicKeyEncoded());
    }

    public String getPrivateKeyString() {
        String data = Base64.getEncoder().encodeToString(this.getPrivateKeyEncoded());
        return Utils.BEGIN_PRIVATE_KEY + data.replaceAll("(.{64})", "$1\n") + Utils.END_PRIVATE_KEY;
    }

    public void generateKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "BC");
        keyGen.initialize(KEY_SIZE);
        KeyPair keyPair = keyGen.generateKeyPair();
        this.privateKey = keyPair.getPrivate();
        this.publicKey = keyPair.getPublic();
    }

    public void importPrivateKey(String pem) throws InvalidKeySpecException, NoSuchAlgorithmException {
        String privateKeyPEM = pem;
        privateKeyPEM = privateKeyPEM.replace(Utils.BEGIN_PRIVATE_KEY, "");
        privateKeyPEM = privateKeyPEM.replace(Utils.END_PRIVATE_KEY, "");
        privateKeyPEM = privateKeyPEM.replace("\n", "");
        byte[] encoded = Base64.getDecoder().decode(privateKeyPEM);
        PKCS8EncodedKeySpec key = new PKCS8EncodedKeySpec(encoded);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        this.privateKey = keyFactory.generatePrivate(key);
        RSAPrivateCrtKey rsaPrivateCrtKey = (RSAPrivateCrtKey) this.privateKey;
        RSAPublicKeySpec publicKeySpec = new java.security.spec.RSAPublicKeySpec(rsaPrivateCrtKey.getModulus(), rsaPrivateCrtKey.getPublicExponent());
        this.publicKey = keyFactory.generatePublic(publicKeySpec);
    }


    public void importKey(String pem, String password) throws IOException, PKCSException, OperatorCreationException, NoSuchAlgorithmException, InvalidKeySpecException {
        if (!pem.startsWith(Utils.BEGIN_ENCRYPTED_PRIVATE_KEY)) {
            pem = Utils.BEGIN_ENCRYPTED_PRIVATE_KEY + pem + Utils.END_ENCRYPTED_PRIVATE_KEY;
        }
        PEMParser pemParser = new PEMParser(new StringReader(pem));
        Object o = pemParser.readObject();
        KeyPair kp;
        if (o instanceof PKCS8EncryptedPrivateKeyInfo) {
            // Encrypted key - we will use provided password
            PKCS8EncryptedPrivateKeyInfo ckp = (PKCS8EncryptedPrivateKeyInfo) o;
            // uses the password to decrypt the key
            InputDecryptorProvider decProv = new JceOpenSSLPKCS8DecryptorProviderBuilder()
                    .setProvider(BouncyCastleProvider.PROVIDER_NAME).build(password.toCharArray());
            PrivateKeyInfo privateKeyInfo = ckp.decryptPrivateKeyInfo(decProv);
            PKCS8EncodedKeySpec key = new PKCS8EncodedKeySpec(privateKeyInfo.getEncoded());
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            this.privateKey = keyFactory.generatePrivate(key);
            RSAPrivateCrtKey rsaPrivateCrtKey = (RSAPrivateCrtKey) this.privateKey;
            RSAPublicKeySpec publicKeySpec = new java.security.spec.RSAPublicKeySpec(rsaPrivateCrtKey.getModulus(), rsaPrivateCrtKey.getPublicExponent());
            this.publicKey = keyFactory.generatePublic(publicKeySpec);
        } else {
            JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
            // Unencrypted key - no password needed
            PEMKeyPair ukp = (PEMKeyPair) o;
            kp = converter.getKeyPair(ukp);
            this.privateKey = kp.getPrivate();
            this.publicKey = kp.getPublic();
        }
    }

    public void importPublicKey(String pem) throws InvalidKeySpecException, NoSuchAlgorithmException {
        String publicKeyPEM = pem;
        publicKeyPEM = publicKeyPEM.replace(Utils.BEGIN_PUBLIC_KEY, "");
        publicKeyPEM = publicKeyPEM.replace(Utils.END_PUBLIC_KEY, "");
        publicKeyPEM = publicKeyPEM.replace("\n", "");
        byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);
        importPublicKey(encoded);
    }

    public void importPublicKeyInBase64Url(String pem) throws InvalidKeySpecException, NoSuchAlgorithmException {
        String publicKeyPEM = pem;
        publicKeyPEM = publicKeyPEM.replace(Utils.BEGIN_PUBLIC_KEY, "");
        publicKeyPEM = publicKeyPEM.replace(Utils.END_PUBLIC_KEY, "");
        publicKeyPEM = publicKeyPEM.replace("\n", "");
        byte[] encoded = Base64.getUrlDecoder().decode(publicKeyPEM);
        importPublicKey(encoded);
    }

    private void importPublicKey(byte[] encoded) throws NoSuchAlgorithmException, InvalidKeySpecException {
        X509EncodedKeySpec key = new X509EncodedKeySpec(encoded);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        this.publicKey = keyFactory.generatePublic(key);
    }

    public byte[] encrypt(byte[] data) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException, IOException {
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding", new BouncyCastleProvider());
        OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), PSource.PSpecified.DEFAULT);
        cipher.init(Cipher.ENCRYPT_MODE, this.publicKey, oaepParams);
        int blockSize = cipher.getBlockSize();
        int dataLength = data.length;
        int start = 0;
        int end = 0;
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        while (end < dataLength) {
            end = end + blockSize;
            if (end > dataLength) {
                end = dataLength;
            }
            byte[] encryptedSlide = cipher.doFinal(data, start, (end - start));
            stream.write(encryptedSlide);
            start = end;
        }

        return stream.toByteArray();
    }

    public String encryptString(String message) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, IOException {
        byte[] data = this.encrypt(message.getBytes());
        return Base64.getUrlEncoder().withoutPadding().encodeToString(data);
    }

    public String decrypt(byte[] data) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, IOException {
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding", new BouncyCastleProvider());
        OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), PSource.PSpecified.DEFAULT);
        cipher.init(Cipher.DECRYPT_MODE, this.privateKey, oaepParams);
        int blockSize = cipher.getBlockSize();
        int dataLength = data.length;
        int start = 0;
        int end = 0;
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        while (end < dataLength) {
            end = end + blockSize;
            if (end > dataLength) {
                end = dataLength;
            }
            byte[] decryptedBlockData = cipher.doFinal(data, start, (end - start));
            stream.write(decryptedBlockData);
            start = end;
        }

        return stream.toString();
    }

    public String decryptString(String message) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IOException {
        byte[] data = Base64.getUrlDecoder().decode(message);
        return this.decrypt(data);
    }

    public Object decryptObject(Object message) throws InvalidAlgorithmParameterException, IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException, NoSuchAlgorithmException, InvalidKeyException, IOException {
        if (message == null) {
            return null;
        }
        if (message instanceof Map) {
            Map objectMap = (Map) message;
            Map result = new HashMap<>();
            for (Map.Entry entry : objectMap.entrySet()) {
                Object decryptedObj = decryptObject(entry.getValue());
                result.put(entry.getKey(), decryptedObj);
            }
            return result;
        }
        if (message instanceof String) {
            if (((String) message).length() == 0) {
                return message;
            }
            return decryptString((String) message);
        }
        return message;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy