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

org.cryptacular.util.KeyPairUtil Maven / Gradle / Ivy

There is a newer version: 6.2.20
Show newest version
/* See LICENSE for licensing and NOTICE for copyright. */
package org.cryptacular.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.signers.DSASigner;
import org.bouncycastle.crypto.signers.ECDSASigner;
import org.bouncycastle.crypto.signers.RSADigestSigner;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.cryptacular.EncodingException;
import org.cryptacular.StreamException;
import org.cryptacular.adapter.Converter;
import org.cryptacular.asn.OpenSSLPrivateKeyDecoder;
import org.cryptacular.asn.PKCS8PrivateKeyDecoder;
import org.cryptacular.asn.PublicKeyDecoder;

/**
 * Utility methods for public/private key pairs used for asymmetric encryption.
 *
 * @author  Middleware Services
 */
public final class KeyPairUtil
{

  /** Data used to verify key pairs. */
  private static final byte[] SIGN_BYTES = ByteUtil.toBytes("Mr. Watson--come here--I want to see you.");


  /** Private constructor of utility class. */
  private KeyPairUtil() {}


  /**
   * Gets the length in bits of a public key where key size is dependent on the particulars of the algorithm.
   *
   * 
    *
  • DSA - length of p
  • *
  • EC - length of p for prime fields, m for binary fields
  • *
  • RSA - length of modulus
  • *
* * @param pubKey Public key. * * @return Size of the key in bits. */ public static int length(final PublicKey pubKey) { final int size; if (pubKey instanceof DSAPublicKey) { size = ((DSAPublicKey) pubKey).getParams().getP().bitLength(); } else if (pubKey instanceof RSAPublicKey) { size = ((RSAPublicKey) pubKey).getModulus().bitLength(); } else if (pubKey instanceof ECPublicKey) { size = ((ECPublicKey) pubKey).getParams().getCurve().getField().getFieldSize(); } else { throw new IllegalArgumentException(pubKey + " not supported."); } return size; } /** * Gets the length in bits of a private key where key size is dependent on the particulars of the algorithm. * *
    *
  • DSA - length of q in bits
  • *
  • EC - length of p for prime fields, m for binary fields
  • *
  • RSA - modulus length in bits
  • *
* * @param privKey Private key. * * @return Size of the key in bits. */ public static int length(final PrivateKey privKey) { final int size; if (privKey instanceof DSAPrivateKey) { size = ((DSAPrivateKey) privKey).getParams().getQ().bitLength(); } else if (privKey instanceof RSAPrivateKey) { size = ((RSAPrivateKey) privKey).getModulus().bitLength(); } else if (privKey instanceof ECPrivateKey) { size = ((ECPrivateKey) privKey).getParams().getCurve().getField().getFieldSize(); } else { throw new IllegalArgumentException(privKey + " not supported."); } return size; } /** * Determines whether the given public and private keys form a proper key pair by computing and verifying a digital * signature with the keys. * * @param pubKey DSA, RSA or EC public key. * @param privKey DSA, RSA, or EC private key. * * @return True if the keys form a functioning keypair, false otherwise. Errors during signature verification are * treated as false. * * @throws org.cryptacular.CryptoException on key validation errors. */ public static boolean isKeyPair(final PublicKey pubKey, final PrivateKey privKey) throws org.cryptacular.CryptoException { final String alg = pubKey.getAlgorithm(); if (!alg.equals(privKey.getAlgorithm())) { return false; } // Dispatch onto the algorithm-specific method final boolean result; switch (alg) { case "DSA": result = isKeyPair((DSAPublicKey) pubKey, (DSAPrivateKey) privKey); break; case "RSA": result = isKeyPair((RSAPublicKey) pubKey, (RSAPrivateKey) privKey); break; case "EC": result = isKeyPair((ECPublicKey) pubKey, (ECPrivateKey) privKey); break; default: throw new IllegalArgumentException(alg + " not supported."); } return result; } /** * Determines whether the given DSA public and private keys form a proper key pair by computing and verifying a * digital signature with the keys. * * @param pubKey DSA public key. * @param privKey DSA private key. * * @return True if the keys form a functioning keypair, false otherwise. Errors during signature verification are * treated as false. * * @throws org.cryptacular.CryptoException on key validation errors. */ public static boolean isKeyPair(final DSAPublicKey pubKey, final DSAPrivateKey privKey) throws org.cryptacular.CryptoException { final DSASigner signer = new DSASigner(); final DSAParameters params = new DSAParameters( privKey.getParams().getP(), privKey.getParams().getQ(), privKey.getParams().getG()); try { signer.init(true, new DSAPrivateKeyParameters(privKey.getX(), params)); final BigInteger[] sig = signer.generateSignature(SIGN_BYTES); signer.init(false, new DSAPublicKeyParameters(pubKey.getY(), params)); return signer.verifySignature(SIGN_BYTES, sig[0], sig[1]); } catch (RuntimeException e) { throw new org.cryptacular.CryptoException("Signature computation error", e); } } /** * Determines whether the given RSA public and private keys form a proper key pair by computing and verifying a * digital signature with the keys. * * @param pubKey RSA public key. * @param privKey RSA private key. * * @return True if the keys form a functioning keypair, false otherwise. Errors during signature verification are * treated as false. * * @throws org.cryptacular.CryptoException on key validation errors. */ public static boolean isKeyPair(final RSAPublicKey pubKey, final RSAPrivateKey privKey) throws org.cryptacular.CryptoException { final RSADigestSigner signer = new RSADigestSigner(new SHA256Digest()); try { signer.init(true, new RSAKeyParameters(true, privKey.getModulus(), privKey.getPrivateExponent())); signer.update(SIGN_BYTES, 0, SIGN_BYTES.length); final byte[] sig = signer.generateSignature(); signer.init(false, new RSAKeyParameters(false, pubKey.getModulus(), pubKey.getPublicExponent())); signer.update(SIGN_BYTES, 0, SIGN_BYTES.length); return signer.verifySignature(sig); } catch (Exception e) { throw new org.cryptacular.CryptoException("Signature computation error", e); } } /** * Determines whether the given EC public and private keys form a proper key pair by computing and verifying a digital * signature with the keys. * * @param pubKey EC public key. * @param privKey EC private key. * * @return True if the keys form a functioning keypair, false otherwise. Errors during signature verification are * treated as false. * * @throws org.cryptacular.CryptoException on key validation errors. */ public static boolean isKeyPair(final ECPublicKey pubKey, final ECPrivateKey privKey) throws org.cryptacular.CryptoException { final ECDSASigner signer = new ECDSASigner(); try { signer.init(true, ECUtil.generatePrivateKeyParameter(privKey)); final BigInteger[] sig = signer.generateSignature(SIGN_BYTES); signer.init(false, ECUtil.generatePublicKeyParameter(pubKey)); return signer.verifySignature(SIGN_BYTES, sig[0], sig[1]); } catch (Exception e) { throw new org.cryptacular.CryptoException("Signature computation error", e); } } /** * Reads an encoded private key from a file at the given path. Both PKCS#8 and OpenSSL "traditional" formats are * supported in DER or PEM encoding. See {@link #decodePrivateKey(byte[])} for supported asymmetric algorithms. * * @param path Path to private key file. * * @return Private key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors reading data from file. */ public static PrivateKey readPrivateKey(final String path) throws EncodingException, StreamException { return readPrivateKey(new File(path)); } /** * Reads an encoded private key from a file. Both PKCS#8 and OpenSSL "traditional" formats are supported in DER or PEM * encoding. See {@link #decodePrivateKey(byte[])} for supported asymmetric algorithms. * * @param file Private key file. * * @return Private key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors reading data from file. */ public static PrivateKey readPrivateKey(final File file) throws EncodingException, StreamException { try { return readPrivateKey(new FileInputStream(file)); } catch (FileNotFoundException e) { throw new StreamException("File not found: " + file); } } /** * Reads an encoded private key from an input stream. Both PKCS#8 and OpenSSL "traditional" formats are supported in * DER or PEM encoding. See {@link #decodePrivateKey(byte[])} for supported asymmetric algorithms. The {@link * InputStream} parameter is closed by this method. * * @param in Input stream containing private key data. * * @return Private key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors reading data from file. */ public static PrivateKey readPrivateKey(final InputStream in) throws EncodingException, StreamException { return decodePrivateKey(StreamUtil.readAll(in)); } /** * Reads an encrypted private key from a file at the given path. Both PKCS#8 and OpenSSL "traditional" formats are * supported in DER or PEM encoding. See {@link #decodePrivateKey(byte[])} for supported asymmetric algorithms. * * @param path Path to private key file. * @param password Password used to encrypt private key. * * @return Private key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors. */ public static PrivateKey readPrivateKey(final String path, final char[] password) throws EncodingException, StreamException { return readPrivateKey(new File(path), password); } /** * Reads an encrypted private key from a file. Both PKCS#8 and OpenSSL "traditional" formats are supported in DER or * PEM encoding. See {@link #decodePrivateKey(byte[])} for supported asymmetric algorithms. * * @param file Private key file. * @param password Password used to encrypt private key. * * @return Private key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors. */ public static PrivateKey readPrivateKey(final File file, final char[] password) throws EncodingException, StreamException { try { return readPrivateKey(new FileInputStream(file), password); } catch (FileNotFoundException e) { throw new StreamException("File not found: " + file); } } /** * Reads an encrypted private key from an input stream. Both PKCS#8 and OpenSSL "traditional" formats are supported in * DER or PEM encoding. See {@link #decodePrivateKey(byte[])} for supported asymmetric algorithms. The {@link * InputStream} parameter is closed by this method. * * @param in Input stream containing private key data. * @param password Password used to encrypt private key. * * @return Private key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors. */ public static PrivateKey readPrivateKey(final InputStream in, final char[] password) throws EncodingException, StreamException { return decodePrivateKey(StreamUtil.readAll(in), password); } /** * Decodes an encoded private key in either PKCS#8 or OpenSSL "traditional" format in either DER or PEM encoding. Keys * from the following asymmetric algorithms are supported: * *
    *
  • DSA
  • *
  • RSA
  • *
  • Elliptic curve
  • *
* * @param encodedKey Encoded private key data. * * @return Private key. * * @throws EncodingException on key encoding errors. */ public static PrivateKey decodePrivateKey(final byte[] encodedKey) throws EncodingException { return decodePrivateKey(encodedKey, null); } /** * Decodes an encrypted private key. The following formats are supported: * *
    *
  • DER or PEM encoded PKCS#8 format
  • *
  • PEM encoded OpenSSL "traditional" format
  • *
* *

Keys from the following asymmetric algorithms are supported:

* *
    *
  • DSA
  • *
  • RSA
  • *
  • Elliptic curve
  • *
* * @param encryptedKey Encrypted private key data. * @param password Password used to encrypt private key. * * @return Private key. * * @throws EncodingException on key encoding errors. */ public static PrivateKey decodePrivateKey(final byte[] encryptedKey, final char[] password) throws EncodingException { AsymmetricKeyParameter key; try { final PKCS8PrivateKeyDecoder decoder = new PKCS8PrivateKeyDecoder(); key = decoder.decode(encryptedKey, password); } catch (RuntimeException e) { final OpenSSLPrivateKeyDecoder decoder = new OpenSSLPrivateKeyDecoder(); key = decoder.decode(encryptedKey, password); } return Converter.convertPrivateKey(key); } /** * Reads a DER or PEM-encoded public key from a file. * * @param path Path to DER or PEM-encoded public key file. * * @return Public key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors. */ public static PublicKey readPublicKey(final String path) throws EncodingException, StreamException { return readPublicKey(new File(path)); } /** * Reads a DER or PEM-encoded public key from a file. * * @param file DER or PEM-encoded public key file. * * @return Public key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors. */ public static PublicKey readPublicKey(final File file) throws EncodingException, StreamException { try { return readPublicKey(new FileInputStream(file)); } catch (FileNotFoundException e) { throw new StreamException("File not found: " + file); } } /** * Reads a DER or PEM-encoded public key from data in the given stream. The {@link InputStream} parameter is closed by * this method. * * @param in Input stream containing an encoded key. * * @return Public key. * * @throws EncodingException on key encoding errors. * @throws StreamException on IO errors. */ public static PublicKey readPublicKey(final InputStream in) throws EncodingException, StreamException { return decodePublicKey(StreamUtil.readAll(in)); } /** * Decodes public keys formatted in an X.509 SubjectPublicKeyInfo structure in either PEM or DER encoding. * * @param encoded Encoded public key bytes. * * @return Public key. * * @throws EncodingException on key encoding errors. */ public static PublicKey decodePublicKey(final byte[] encoded) throws EncodingException { return Converter.convertPublicKey(new PublicKeyDecoder().decode(encoded)); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy