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

com.mastercard.developer.utils.EncryptionUtils Maven / Gradle / Ivy

The newest version!
package com.mastercard.developer.utils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;

import static com.mastercard.developer.utils.ByteUtils.concat;
import static com.mastercard.developer.utils.EncodingUtils.base64Decode;

/**
 * Utility class for loading certificates and keys.
 */
public final class EncryptionUtils {

    private static final String PKCS_1_PEM_HEADER = "-----BEGIN RSA PRIVATE KEY-----";
    private static final String PKCS_1_PEM_FOOTER = "-----END RSA PRIVATE KEY-----";
    private static final String PKCS_8_PEM_HEADER = "-----BEGIN PRIVATE KEY-----";
    private static final String PKCS_8_PEM_FOOTER = "-----END PRIVATE KEY-----";

    private EncryptionUtils() {
    }

    /**
     * Populate a X509 encryption certificate object with the certificate data at the given file path.
     */
    public static Certificate loadEncryptionCertificate(String certificatePath) throws CertificateException, IOException {
        return loadEncryptionCertificate(Files.newInputStream(Paths.get(certificatePath)));
    }

    /**
     * Populate a X509 encryption certificate object with the certificate data at the given certificate data in bytes.
     */
    public static Certificate loadEncryptionCertificate(InputStream certificateStream) throws CertificateException {
        CertificateFactory factory = CertificateFactory.getInstance("X.509");
        return factory.generateCertificate(certificateStream);
    }

    /**
     * Load a RSA decryption key from a file (PEM or DER).
     */
    public static PrivateKey loadDecryptionKey(String keyFilePath) throws GeneralSecurityException, IOException {
        InputStream keyStream = new ByteArrayInputStream(Files.readAllBytes(Paths.get(keyFilePath)));
        return loadDecryptionKey(keyStream);
    }

    /**
     * Load a RSA decryption key from key data in bytes.
     */
    public static PrivateKey loadDecryptionKey(InputStream keyDataStream) throws GeneralSecurityException, IOException {
        byte[] keyBytes = keyDataStream.readAllBytes();
        String keyDataString = new String(keyBytes, StandardCharsets.UTF_8);

        if (keyDataString.contains(PKCS_1_PEM_HEADER)) {
            // OpenSSL / PKCS#1 Base64 PEM encoded file
            keyDataString = keyDataString.replace(PKCS_1_PEM_HEADER, "");
            keyDataString = keyDataString.replace(PKCS_1_PEM_FOOTER, "");
            keyDataString = keyDataString.replace("\n", "");
            keyDataString = keyDataString.replace("\r\n", "");
            return readPkcs1PrivateKey(base64Decode(keyDataString));
        }

        if (keyDataString.contains(PKCS_8_PEM_HEADER)) {
            // PKCS#8 Base64 PEM encoded file
            keyDataString = keyDataString.replace(PKCS_8_PEM_HEADER, "");
            keyDataString = keyDataString.replace(PKCS_8_PEM_FOOTER, "");
            keyDataString = keyDataString.replace("\n", "");
            keyDataString = keyDataString.replace("\r\n", "");
            return readPkcs8PrivateKey(base64Decode(keyDataString));
        }

        // We assume it's a PKCS#8 DER encoded binary file
        return readPkcs8PrivateKey(keyBytes);
    }

    /**
     * Load a RSA decryption key out of a PKCS#12 container.
     */
    public static PrivateKey loadDecryptionKey(String pkcs12KeyFilePath,
                                               String decryptionKeyAlias,
                                               String decryptionKeyPassword) throws GeneralSecurityException, IOException {
        KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12");
        pkcs12KeyStore.load(Files.newInputStream(Paths.get(pkcs12KeyFilePath)), decryptionKeyPassword.toCharArray());
        return (PrivateKey) pkcs12KeyStore.getKey(decryptionKeyAlias, decryptionKeyPassword.toCharArray());
    }

    /**
     * Create a PrivateKey instance from raw PKCS#8 bytes.
     */
    private static PrivateKey readPkcs8PrivateKey(byte[] pkcs8Bytes) throws GeneralSecurityException {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8Bytes);
        try {
            return keyFactory.generatePrivate(keySpec);
        } catch (InvalidKeySpecException e) {
            throw new IllegalArgumentException("Unexpected key format!", e);
        }
    }

    /**
     * Create a PrivateKey instance from raw PKCS#1 bytes.
     */
    private static PrivateKey readPkcs1PrivateKey(byte[] pkcs1Bytes) throws GeneralSecurityException {
        // We can't use Java internal APIs to parse ASN.1 structures, so we build a PKCS#8 key Java can understand
        int pkcs1Length = pkcs1Bytes.length;
        int totalLength = pkcs1Length + 22;
        byte[] pkcs8Header = new byte[] {
                0x30, (byte) 0x82, (byte) ((totalLength >> 8) & 0xff), (byte) (totalLength & 0xff), // Sequence + total length
                0x2, 0x1, 0x0, // Integer (0)
                0x30, 0xD, 0x6, 0x9, 0x2A, (byte) 0x86, 0x48, (byte) 0x86, (byte) 0xF7, 0xD, 0x1, 0x1, 0x1, 0x5, 0x0, // Sequence: 1.2.840.113549.1.1.1, NULL
                0x4, (byte) 0x82, (byte) ((pkcs1Length >> 8) & 0xff), (byte) (pkcs1Length & 0xff) // Octet string + length
        };
        byte[] pkcs8bytes = concat(pkcs8Header, pkcs1Bytes);
        return readPkcs8PrivateKey(pkcs8bytes);
    }

    public static String sanitizeJson(String json) {
        return json.replace("\n", "")
                .replace("\r", "")
                .replace("\t", "");
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy