net.adamcin.httpsig.testutil.KeyTestUtil.java Source code

Java tutorial

Introduction

Here is the source code for net.adamcin.httpsig.testutil.KeyTestUtil.java

Source

/*
 * This is free and unencumbered software released into the public domain.
 *
 * Anyone is free to copy, modify, publish, use, compile, sell, or
 * distribute this software, either in source code form or as a compiled
 * binary, for any purpose, commercial or non-commercial, and by any
 * means.
 *
 * In jurisdictions that recognize copyright laws, the author or authors
 * of this software dedicate any and all copyright interest in the
 * software to the public domain. We make this dedication for the benefit
 * of the public at large and to the detriment of our heirs and
 * successors. We intend this dedication to be an overt act of
 * relinquishment in perpetuity of all present and future rights to this
 * software under copyright law.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * For more information, please refer to <http://unlicense.org/>
 */

package net.adamcin.httpsig.testutil;

import net.adamcin.commons.testing.junit.FailUtil;
import org.apache.commons.io.IOUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMDecryptorProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.KeyAgreement;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.MessageDigest;
import java.security.PublicKey;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.DSAPrivateKeySpec;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Properties;

/**
 *
 */
public class KeyTestUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(KeyTestUtil.class);
    private static final String BOUNCY_CASTLE = "BC";

    public static final String P_TYPE = "type";
    public static final String TYPE_RSA = "ssh-rsa";
    public static final String TYPE_DSA = "ssh-dss";

    public static final String DSA_P = "p";
    public static final String DSA_Q = "q";
    public static final String DSA_G = "g";
    public static final String DSA_Y = "y";
    public static final String DSA_X = "x";

    public static final String RSA_N = "n";
    public static final String RSA_E = "e";
    public static final String RSA_D = "d";
    public static final String RSA_P = "p";
    public static final String RSA_Q = "q";
    public static final String RSA_PE = "pe";
    public static final String RSA_QE = "qe";
    public static final String RSA_U = "u";

    static {
        try {
            if (java.security.Security.getProvider(BOUNCY_CASTLE) == null) {
                LOGGER.info("Trying to register BouncyCastle as a JCE provider");
                java.security.Security.addProvider(new BouncyCastleProvider());
                MessageDigest.getInstance("MD5", BOUNCY_CASTLE);
                KeyAgreement.getInstance("DH", BOUNCY_CASTLE);
                LOGGER.info("Registration succeeded");
            } else {
                LOGGER.info("BouncyCastle already registered ");
            }
        } catch (Exception e) {
            LOGGER.error("Failed to register bouncycastle provider", e);
        }
    }

    private static final File TEST_TEMP = new File("target/test-temp");
    static {
        TEST_TEMP.mkdirs();
        new File(TEST_TEMP, "b1024").mkdirs();
        new File(TEST_TEMP, "b2048").mkdirs();
        new File(TEST_TEMP, "b4096").mkdirs();
        new File(TEST_TEMP, "withpass").mkdirs();
    }

    final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();

    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        int v;
        for (int j = 0; j < bytes.length; j++) {
            v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    public static InputStream getAuthorizedKeysStream() {
        return KeyTestUtil.class.getResourceAsStream("/authorized_keys");
    }

    public static File getAuthorizedKeysFile() {
        return getResourceAsFile("/authorized_keys");
    }

    public static File getPrivateKeyAsFile(String parentName, String keyName) {
        return getResourceAsFile("/" + parentName + "/" + keyName);
    }

    public static byte[] dumpKeyBlob(PublicKey publicKey) {
        ByteArrayOutputStream byteOs = new ByteArrayOutputStream();

        try {
            if (publicKey instanceof RSAPublicKey) {
                RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
                DataOutputStream dos = new DataOutputStream(byteOs);
                dos.writeInt("ssh-rsa".getBytes().length);
                dos.write("ssh-rsa".getBytes());
                dos.writeInt(rsaPublicKey.getPublicExponent().toByteArray().length);
                dos.write(rsaPublicKey.getPublicExponent().toByteArray());
                dos.writeInt(rsaPublicKey.getModulus().toByteArray().length);
                dos.write(rsaPublicKey.getModulus().toByteArray());
            } else if (publicKey instanceof DSAPublicKey) {
                DSAPublicKey dsaPublicKey = (DSAPublicKey) publicKey;
                DSAParams dsaParams = dsaPublicKey.getParams();

                DataOutputStream dos = new DataOutputStream(byteOs);
                dos.writeInt("ssh-dss".getBytes().length);
                dos.write("ssh-dss".getBytes());
                dos.writeInt(dsaParams.getP().toByteArray().length);
                dos.write(dsaParams.getP().toByteArray());
                dos.writeInt(dsaParams.getQ().toByteArray().length);
                dos.write(dsaParams.getQ().toByteArray());
                dos.writeInt(dsaParams.getG().toByteArray().length);
                dos.write(dsaParams.getG().toByteArray());
                dos.writeInt(dsaPublicKey.getY().toByteArray().length);
                dos.write(dsaPublicKey.getY().toByteArray());
            } else {
                throw new IllegalArgumentException("Not a supported public key: " + publicKey);
            }
        } catch (IOException e) {
            // shouldn't happen
            LOGGER.error("failed to dump public key blob", e);
        }
        return byteOs.toByteArray();
    }

    public static KeyPair getKeyPairFromProperties(String parentName, String keyName) {
        InputStream is = null;
        try {
            is = KeyTestUtil.class.getResourceAsStream("/" + parentName + "/" + keyName + ".properties");
            Properties props = new Properties();
            props.load(is);
            if (TYPE_RSA.equals(props.getProperty(P_TYPE))) {
                RSAPrivateKeySpec privSpec = null;
                if (props.getProperty(RSA_P) != null && props.getProperty(RSA_Q) != null
                        && props.getProperty(RSA_U) != null) {
                    privSpec = new RSAPrivateCrtKeySpec(new BigInteger(props.getProperty(RSA_N)),
                            new BigInteger(props.getProperty(RSA_E)), new BigInteger(props.getProperty(RSA_D)),
                            new BigInteger(props.getProperty(RSA_P)), new BigInteger(props.getProperty(RSA_Q)),
                            new BigInteger(props.getProperty(RSA_PE)), new BigInteger(props.getProperty(RSA_QE)),
                            new BigInteger(props.getProperty(RSA_U)));
                } else {
                    privSpec = new RSAPrivateKeySpec(new BigInteger(props.getProperty(RSA_N)),
                            new BigInteger(props.getProperty(RSA_D)));
                }
                RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(new BigInteger(props.getProperty(RSA_N)),
                        new BigInteger(props.getProperty(RSA_E)));

                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                return new KeyPair(keyFactory.generatePublic(pubSpec), keyFactory.generatePrivate(privSpec));
            } else if (TYPE_DSA.equals(props.getProperty(P_TYPE))) {
                DSAPrivateKeySpec privSpec = new DSAPrivateKeySpec(new BigInteger(props.getProperty(DSA_X)),
                        new BigInteger(props.getProperty(DSA_P)), new BigInteger(props.getProperty(DSA_Q)),
                        new BigInteger(props.getProperty(DSA_G)));
                DSAPublicKeySpec pubSpec = new DSAPublicKeySpec(new BigInteger(props.getProperty(DSA_Y)),
                        new BigInteger(props.getProperty(DSA_P)), new BigInteger(props.getProperty(DSA_Q)),
                        new BigInteger(props.getProperty(DSA_G)));
                KeyFactory keyFactory = KeyFactory.getInstance("DSA");
                return new KeyPair(keyFactory.generatePublic(pubSpec), keyFactory.generatePrivate(privSpec));
            }
        } catch (Exception e) {
            LOGGER.error("Failed to read properties", e);
        } finally {
            IOUtils.closeQuietly(is);
        }

        return null;
    }

    public static KeyPair getPrivateKeyAsKeyPair(String parentName, String keyName, final String passphrase) {
        JcaPEMKeyConverter converter = new JcaPEMKeyConverter();

        File privateKeyFile = getPrivateKeyAsFile(parentName, keyName);
        InputStream is = null;
        PEMParser parser = null;
        try {
            is = new FileInputStream(privateKeyFile);
            parser = new PEMParser(new InputStreamReader(is));

            Object o = parser.readObject();
            if (o instanceof PEMEncryptedKeyPair) {
                PEMEncryptedKeyPair _encPair = (PEMEncryptedKeyPair) o;
                PEMDecryptorProvider decryptionProv = new JcePEMDecryptorProviderBuilder()
                        .build(passphrase.toCharArray());
                return converter.getKeyPair(_encPair.decryptKeyPair(decryptionProv));
            } else if (o instanceof PEMKeyPair) {
                return converter.getKeyPair((PEMKeyPair) o);
            }
        } catch (Exception e) {
            LOGGER.error("failed to parse private key file: parent=" + parentName + " keyName=" + keyName, e);
        } finally {
            IOUtils.closeQuietly(is);
            IOUtils.closeQuietly(parser);
        }

        return null;
    }

    public static File getPublicKeyAsFile(String parentName, String keyName) {
        return getResourceAsFile("/" + parentName + "/" + keyName + ".pub");
    }

    private static File getResourceAsFile(String name) {
        File temp = new File(TEST_TEMP, name.substring(1));
        if (temp.exists()) {
            return temp;
        }
        InputStream is = null;
        OutputStream os = null;
        try {
            is = KeyTestUtil.class.getResourceAsStream(name);
            os = new FileOutputStream(temp);
            IOUtils.copy(is, os);
            return temp;
        } catch (IOException e) {
            FailUtil.sprintFail(e);
        } finally {
            IOUtils.closeQuietly(is);
            IOUtils.closeQuietly(os);
        }
        return null;
    }
}