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

ru.i_novus.common.sign.util.CryptoIO Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
package ru.i_novus.common.sign.util;

/*-
 * -----------------------------------------------------------------
 * common-sign-gost
 * -----------------------------------------------------------------
 * Copyright (C) 2018 - 2019 I-Novus LLC
 * -----------------------------------------------------------------
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * -----------------------------------------------------------------
 */

import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.crypto.engines.DESedeEngine;
import org.bouncycastle.crypto.engines.RC2Engine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.pkcs.*;
import org.bouncycastle.pkcs.bc.BcPKCS12MacCalculatorBuilder;
import org.bouncycastle.pkcs.bc.BcPKCS12PBEOutputEncryptorBuilder;
import org.bouncycastle.pkcs.jcajce.JcaPKCS12SafeBagBuilder;
import ru.i_novus.common.sign.api.SignAlgorithmType;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;

@Slf4j
public class CryptoIO {
    private static final int BUFFER_SIZE = 1024;

    private CryptoIO() {
        // don't instantiate
    }

    public static CryptoIO getInstance() {
        return new CryptoIO();
    }

    public PKCS8EncodedKeySpec readPkFromPKCS8(final String keyPath) {
        try {
            byte[] data = Files.readAllBytes(Paths.get(keyPath));
            return new PKCS8EncodedKeySpec(data);
        } catch (IOException e) {
            throw new UncheckedIOException("Cannot read PK from PKCS8", e);
        }
    }

    public PrivateKey readPrivateKey(InputStream input) throws IOException, GeneralSecurityException {
        PEMParser pemReader = new PEMParser(new InputStreamReader(input));

        /*
         * Now it's in a PKCS#8 PrivateKeyInfo structure. Read its Algorithm
         * OID and use that to construct a KeyFactory.
         */
        PrivateKeyInfo pki = (PrivateKeyInfo) pemReader.readObject();
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(pki.getEncoded());

        String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
        return KeyFactory.getInstance(algOid).generatePrivate(spec);
    }

    public PrivateKey readPkFromPEM(final Path keyPath, SignAlgorithmType algorithmType) {
        try {
            byte[] data = Files.readAllBytes(keyPath);
            return CryptoFormatConverter.getInstance().getPKFromPEMEncoded(algorithmType, new String(data));
        } catch (IOException e) {
            throw new UncheckedIOException("Cannot read key from path '" + keyPath + "'", e);
        }
    }

    public X509CertificateHolder readCertFromDER(final String crtPath) {
        try {
            byte[] data = Files.readAllBytes(Paths.get(crtPath));
            return new X509CertificateHolder(data);
        } catch (IOException e) {
            throw new UncheckedIOException("Cannot read certificate from path '" + crtPath + "'", e);
        }
    }

    public X509Certificate readCertFromPEM(final Path crtPath) {
        try {
            byte[] data = Files.readAllBytes(crtPath);
            return CryptoFormatConverter.getInstance().getCertificateFromPEMEncoded(new String(data));
        } catch (IOException e) {
            throw new UncheckedIOException("Cannot read certificate from path '" + crtPath + "'", e);
        }
    }

    public String writeCertToDERFile(final X509CertificateHolder certificateHolder, final Path path) {
        try {
            if (path.toFile().exists()) {
                Files.delete(path);
            }
            try (OutputStream fos = Files.newOutputStream(path, StandardOpenOption.CREATE)) {
                fos.write(certificateHolder.getEncoded());
            }
            return path.toString();
        } catch (IOException e) {
            throw new UncheckedIOException("Cannot write certificate to path '" + path + "' in DER", e);
        }
    }

    public byte[] writeCertToByteArray(final X509CertificateHolder certificateHolder) {
        try {
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            stream.write(certificateHolder.getEncoded());
            return stream.toByteArray();
        } catch (IOException e) {
            throw new UncheckedIOException("Cannot convert certificate to byte array", e);
        }
    }

    public String writePKToPKCS8File(final KeyPair keyPair, final Path path) {
        try (OutputStream fos = Files.newOutputStream(path, StandardOpenOption.CREATE,
                StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)) {
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyPair.getPrivate().getEncoded());
            fos.write(pkcs8EncodedKeySpec.getEncoded());
        } catch (IOException e) {
            throw new UncheckedIOException("Cannot write PK to file '" + path + "'", e);
        }
        return path.toString();
    }

    public byte[] writePKToByteArray(PrivateKey privateKey) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
        try {
            stream.write(pkcs8EncodedKeySpec.getEncoded());
        } catch (IOException e) {
            throw new UncheckedIOException("Cannot write PKCS8 encoded key to byte array", e);
        }
        return stream.toByteArray();
    }

    public PrivateKey readPrivateKeyFromPKCS12(Path filePath, String keystorePass) {
        try {
            return readPrivateKeyFromPKCS12(Files.newInputStream(filePath), keystorePass);
        } catch (IOException e) {
            throw new UncheckedIOException("Cannot read file '" + filePath + "'", e);
        }
    }

    public KeyStore getPkcs12KeyStore(InputStream inputStream, String keystorePass) {
        try {
            KeyStore keyStore = KeyStore.getInstance("pkcs12", BouncyCastleProvider.PROVIDER_NAME);
            keyStore.load(inputStream, keystorePass == null ? null : keystorePass.toCharArray());
            return keyStore;
        } catch (KeyStoreException | IOException | CertificateException | NoSuchProviderException | NoSuchAlgorithmException e) {
            throw new IllegalArgumentException("Cannot read private key from keystore", e);
        }
    }

    public PrivateKey readPrivateKeyFromPKCS12(KeyStore keyStore, String keystorePass) {
        String alias;
        try {
             alias = keyStore.aliases().nextElement();
        } catch (KeyStoreException e) {
            throw new IllegalArgumentException("Keystore is invalid. Cannot read certificate chain", e);
        }
        try {
            return (PrivateKey) keyStore.getKey(alias, keystorePass == null ? null : keystorePass.toCharArray());
        } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
            throw new IllegalArgumentException("Cannot read private key from keystore", e);
        }
    }

    public X509Certificate readCertificateFromPKCS12(InputStream inputStream, String keystorePass) {
        KeyStore keyStore = getPkcs12KeyStore(inputStream, keystorePass);
        return readCertificateFromPKCS12(keyStore);
    }

    public X509Certificate readCertificateFromPKCS12(KeyStore keyStore) {
        try {
            String alias = keyStore.aliases().nextElement();
            Certificate[] chain = keyStore.getCertificateChain(alias);
            return (X509Certificate) chain[chain.length - 1];
        } catch (KeyStoreException e) {
            throw new IllegalArgumentException("Keystore is invalid. Cannot read certificate chain", e);
        }
    }

    public PrivateKey readPrivateKeyFromPKCS12(InputStream inputStream, String keystorePass) {
        KeyStore keyStore = getPkcs12KeyStore(inputStream, keystorePass);
        return readPrivateKeyFromPKCS12(keyStore, keystorePass);
    }

    public X509Certificate readCertificateFromPKCS12(Path filePath, String keystorePass) {
        try {
            return readCertificateFromPKCS12(Files.newInputStream(filePath), keystorePass);
        } catch (IOException e) {
            throw new UncheckedIOException("Cannot read file '" + filePath + "'", e);
        }
    }

    public void createPkcs12File(Path filePath, String password, PrivateKey privateKey, X509Certificate[] chain) {

        PKCS12PfxPdu pfx = createPkcs12PfxPdu(password, privateKey, chain);

        try (OutputStream stream = Files.newOutputStream(filePath,
                StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)) {
            stream.write(pfx.getEncoded());
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public String createPkcs12FileEncoded(String password, PrivateKey privateKey, X509Certificate[] chain) {
        try {
            PKCS12PfxPdu pfx = createPkcs12PfxPdu(password, privateKey, chain);
            return Base64Util.getBase64EncodedString(pfx.getEncoded());
        } catch (IOException e) {
            throw new UncheckedIOException("Cannot create Pkcs12File", e);
        }
    }

    public PKCS12PfxPdu createPkcs12PfxPdu(String password, PrivateKey privateKey, X509Certificate[] chain) {
        if (chain.length == 0) {
            throw new IllegalArgumentException("Cannot build PKCS12 without certificates");
        }

        PublicKey publicKey = chain[0].getPublicKey();
        JcaX509ExtensionUtils extUtils = null;
        try {
            extUtils = new JcaX509ExtensionUtils();
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("Cannot find algorithm 'SHA1'", e);
        }

        PKCS12SafeBag[] safeBags = new PKCS12SafeBag[chain.length];
        for (int i = chain.length - 1; i >= 0; i--) {
            PKCS12SafeBagBuilder certBagBuilder = null;
            try {
                certBagBuilder = new JcaPKCS12SafeBagBuilder(chain[i]);
            } catch (IOException e) {
                throw new UncheckedIOException("Cannot init certificate chain entry", e);
            }
            if (i == 0) {
                certBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extUtils.createSubjectKeyIdentifier(publicKey));
            }
            safeBags[i] = certBagBuilder.build();
        }

        PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privateKey,
                new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC,
                        new CBCBlockCipher(new DESedeEngine())).build(password.toCharArray()));
        keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extUtils.createSubjectKeyIdentifier(publicKey));

        PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder();

        try {
            pfxPduBuilder.addEncryptedData(
                    new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC,
                            new CBCBlockCipher(new RC2Engine())).build(password.toCharArray()), safeBags);

            pfxPduBuilder.addData(keyBagBuilder.build());
        } catch (IOException e) {
            throw new UncheckedIOException("Cannot build PFX", e);
        }

        try {
            return pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), password.toCharArray());
        } catch (PKCSException e) {
            throw new RuntimeException("Cannot build PFX container", e);
        }
    }

    /**
     * Convert input stream to byte array using default buffer size
     *
     * @param inputStream input stream
     * @return byte array
     */
    public byte[] inputStreamToByteArray(InputStream inputStream) {
        try {
            return inputStreamToByteArray(inputStream, BUFFER_SIZE);
        } catch (IOException e) {
            throw new UncheckedIOException("Cannot read input stream", e);
        }
    }

    /**
     * Convert input stream to byte array
     *
     * @param inputStream input stream
     * @param bufferSize  buffer size to process data
     * @return byte array
     */
    public byte[] inputStreamToByteArray(InputStream inputStream, int bufferSize) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        int nRead;
        byte[] data = new byte[bufferSize];
        while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, nRead);
        }
        buffer.flush();
        return buffer.toByteArray();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy