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

net.named_data.jndn.security.tpm.TpmPrivateKey Maven / Gradle / Ivy

/**
 * Copyright (C) 2017-2018 Regents of the University of California.
 * @author: Jeff Thompson 
 * @author: From https://github.com/named-data/ndn-cxx/blob/master/src/security/transform/private-key.cpp
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 * A copy of the GNU Lesser General Public License is in the file COPYING.
 */

package net.named_data.jndn.security.tpm;

import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import net.named_data.jndn.encoding.OID;
import net.named_data.jndn.encoding.der.DerDecodingException;
import net.named_data.jndn.encoding.der.DerEncodingException;
import net.named_data.jndn.encoding.der.DerNode;
import net.named_data.jndn.encoding.der.DerNode.DerSequence;
import net.named_data.jndn.encrypt.algo.EncryptAlgorithmType;
import net.named_data.jndn.security.DigestAlgorithm;
import net.named_data.jndn.security.EcKeyParams;
import net.named_data.jndn.security.KeyParams;
import net.named_data.jndn.security.KeyType;
import net.named_data.jndn.security.RsaKeyParams;
import net.named_data.jndn.util.Blob;
import net.named_data.jndn.util.Common;

/**
 * A TpmPrivateKey holds an in-memory private key and provides cryptographic
 * operations such as for signing by the in-memory TPM.
 */
public class TpmPrivateKey {
  /**
   * A TpmPrivateKey.Error extends Exception and represents an error in private
   * key processing.
   * Note that even though this is called "Error" to be consistent with the
   * other libraries, it extends the Java Exception class, not Error.
   */
  public static class Error extends Exception {
    public Error(String message)
    {
      super(message);
    }
  }

  /**
   * Create an uninitialized TpmPrivateKey. You must call a load method to
   * initialize it, such as loadPkcs1.
   */
  public TpmPrivateKey() {}

  /**
   * Load the unencrypted private key from a buffer with the PKCS #1 encoding.
   * This replaces any existing private key in this object.
   * @param encoding The byte buffer with the private key encoding.
   * @param keyType The KeyType, such as KeyType.RSA. If null, then partially
   * decode the private key to determine the key type.
   * @throws TpmPrivateKey.Error for errors decoding the key.
   */
  public final void
  loadPkcs1(ByteBuffer encoding, KeyType keyType) throws TpmPrivateKey.Error
  {
    if (keyType == null) {
      // Try to determine the key type.
      try {
        DerNode parsedNode = DerNode.parse(encoding);
        List children = parsedNode.getChildren();

        // An RsaPrivateKey has integer version 0 and 8 integers.
        if (children.size() == 9 &&
            children.get(0) instanceof DerNode.DerInteger &&
            ((int)((DerNode.DerInteger)children.get(0)).toVal()) == 0 &&
            children.get(1) instanceof DerNode.DerInteger &&
            children.get(2) instanceof DerNode.DerInteger &&
            children.get(3) instanceof DerNode.DerInteger &&
            children.get(4) instanceof DerNode.DerInteger &&
            children.get(5) instanceof DerNode.DerInteger &&
            children.get(6) instanceof DerNode.DerInteger &&
            children.get(7) instanceof DerNode.DerInteger &&
            children.get(8) instanceof DerNode.DerInteger)
          keyType = KeyType.RSA;
        else
          // Assume it is an EC key. Try decoding it below.
          keyType = KeyType.EC;
      } catch (DerDecodingException ex) {
        // Assume it is an EC key. Try decoding it below.
        keyType = KeyType.EC;
      }
    }

    // Java can't decode a PKCS #1 private key, so make a PKCS #8 private key
    // and decode that.
    Blob pkcs8;
    if (keyType == KeyType.EC) {
      throw new TpmPrivateKey.Error("TODO: loadPkcs1 for EC is not implemented");
    }
    else if (keyType == KeyType.RSA)
      pkcs8 = encodePkcs8PrivateKey
        (encoding, new OID(RSA_ENCRYPTION_OID), new DerNode.DerNull());
    else
      throw new TpmPrivateKey.Error("loadPkcs1: Unrecognized keyType: " + keyType);

    loadPkcs8(pkcs8.buf(), keyType);
  }

  /**
   * Load the unencrypted private key from a buffer with the PKCS #1 encoding.
   * This replaces any existing private key in this object. This partially
   * decodes the private key to determine the key type.
   * @param encoding The byte buffer with the private key encoding.
   * @throws TpmPrivateKey.Error for errors decoding the key.
   */
  public final void
  loadPkcs1(ByteBuffer encoding) throws TpmPrivateKey.Error
  {
    loadPkcs1(encoding, null);
  }

  /**
   * Load the unencrypted private key from a buffer with the PKCS #8 encoding.
   * This replaces any existing private key in this object.
   * @param encoding The byte buffer with the private key encoding.
   * @param keyType The KeyType, such as KeyType.RSA. If null, then partially
   * decode the private key to determine the key type.
   * @throws TpmPrivateKey.Error for errors decoding the key.
   */
  public final void
  loadPkcs8(ByteBuffer encoding, KeyType keyType) throws TpmPrivateKey.Error
  {
    if (keyType == null) {
      // Decode the PKCS #8 DER to find the algorithm OID.
      String oidString = null;
      try {
        DerNode parsedNode = DerNode.parse(encoding, 0);
        List pkcs8Children = parsedNode.getChildren();
        List algorithmIdChildren = DerNode.getSequence
          (pkcs8Children, 1).getChildren();
        oidString = "" + ((DerNode.DerOid)algorithmIdChildren.get(0)).toVal();
      }
      catch (DerDecodingException ex) {
        throw new TpmPrivateKey.Error
          ("Cannot decode the PKCS #8 private key: " + ex);
      }

      if (oidString.equals(EC_ENCRYPTION_OID))
        keyType = KeyType.EC;
      else if (oidString.equals(RSA_ENCRYPTION_OID))
        keyType = KeyType.RSA;
      else
        throw new TpmPrivateKey.Error
          ("loadPkcs8: Unrecognized private key OID: " + oidString);
    }

    // Use a Blob to get the byte array.
    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec
      (new Blob(encoding, false).getImmutableArray());
    if (keyType == KeyType.EC) {
      try {
        KeyFactory kf = KeyFactory.getInstance("EC");
        privateKey_ = kf.generatePrivate(spec);
        keyType_ = KeyType.EC;
      }
      catch (InvalidKeySpecException ex) {
        // Don't expect this to happen.
        throw new TpmPrivateKey.Error("loadPkcs8: EC is not supported: " + ex);
      }
      catch (NoSuchAlgorithmException ex) {
        // Don't expect this to happen.
        throw new TpmPrivateKey.Error
          ("loadPkcs8: PKCS8EncodedKeySpec is not supported for EC: " + ex);
      }
    }
    else if (keyType == KeyType.RSA) {
      try {
        KeyFactory kf = KeyFactory.getInstance("RSA");
        privateKey_ = kf.generatePrivate(spec);
        keyType_ = KeyType.RSA;
      }
      catch (InvalidKeySpecException ex) {
        // Don't expect this to happen.
        throw new TpmPrivateKey.Error("loadPkcs8: RSA is not supported: " + ex);
      }
      catch (NoSuchAlgorithmException ex) {
        // Don't expect this to happen.
        throw new TpmPrivateKey.Error
          ("loadPkcs8: PKCS8EncodedKeySpec is not supported for RSA: " + ex);
      }
    }
    else
      throw new TpmPrivateKey.Error
        ("loadPkcs8: Unrecognized keyType: " + keyType);
  }

  /**
   * Load the unencrypted private key from a buffer with the PKCS #8 encoding.
   * This replaces any existing private key in this object. This partially
   * decodes the private key to determine the key type.
   * @param encoding The byte buffer with the private key encoding.
   * @throws TpmPrivateKey.Error for errors decoding the key.
   */
  public final void
  loadPkcs8(ByteBuffer encoding) throws TpmPrivateKey.Error
  {
    loadPkcs8(encoding, null);
  }

  /**
   * Load the encrypted private key from a buffer with the PKCS #8 encoding of
   * the EncryptedPrivateKeyInfo.
   * This replaces any existing private key in this object. This partially
   * decodes the private key to determine the key type.
   * @param encoding The byte buffer with the private key encoding.
   * @param password The password for decrypting the private key.
   * @throws TpmPrivateKey.Error for errors decoding or decrypting the key.
   */
  public final void
  loadEncryptedPkcs8(ByteBuffer encoding, ByteBuffer password)
    throws TpmPrivateKey.Error
  {
    // Decode the PKCS #8 EncryptedPrivateKeyInfo.
    // See https://tools.ietf.org/html/rfc5208.
    String oidString;
    Object parameters;
    Blob encryptedKey;
    try {
      DerNode parsedNode = DerNode.parse(encoding, 0);
      List encryptedPkcs8Children = parsedNode.getChildren();
      List algorithmIdChildren = DerNode.getSequence
        (encryptedPkcs8Children, 0).getChildren();
      oidString = "" + ((DerNode.DerOid)algorithmIdChildren.get(0)).toVal();
      parameters = algorithmIdChildren.get(1);

      encryptedKey = 
        (Blob)((DerNode.DerOctetString)encryptedPkcs8Children.get(1)).toVal();
    }
    catch (Throwable ex) {
      throw new TpmPrivateKey.Error
        ("Cannot decode the PKCS #8 EncryptedPrivateKeyInfo: " + ex);
    }

    // Use the password to get the unencrypted pkcs8Encoding.
    byte[] pkcs8Encoding;
    if (oidString.equals(PBES2_OID)) {
      // Decode the PBES2 parameters. See https://www.ietf.org/rfc/rfc2898.txt .
      String keyDerivationOidString;
      Object keyDerivationParameters;
      String encryptionSchemeOidString;
      Object encryptionSchemeParameters;
      try {
        List parametersChildren = ((DerNode.DerSequence)parameters).getChildren();

        List keyDerivationAlgorithmIdChildren = DerNode.getSequence
          (parametersChildren, 0).getChildren();
        keyDerivationOidString = "" +
          ((DerNode.DerOid)keyDerivationAlgorithmIdChildren.get(0)).toVal();
        keyDerivationParameters = keyDerivationAlgorithmIdChildren.get(1);

        List encryptionSchemeAlgorithmIdChildren = DerNode.getSequence
          (parametersChildren, 1).getChildren();
        encryptionSchemeOidString = "" +
          ((DerNode.DerOid)encryptionSchemeAlgorithmIdChildren.get(0)).toVal();
        encryptionSchemeParameters = encryptionSchemeAlgorithmIdChildren.get(1);
      }
      catch (Throwable ex) {
        throw new TpmPrivateKey.Error
          ("Cannot decode the PBES2 parameters: " + ex);
      }

      // Get the derived key from the password.
      byte[] derivedKey = null;
      if (keyDerivationOidString.equals(PBKDF2_OID)) {
        // Decode the PBKDF2 parameters.
        Blob salt;
        int nIterations;
        try {
          List pbkdf2ParametersChildren =
            ((DerNode.DerSequence)keyDerivationParameters).getChildren();
          salt = (Blob)
            ((DerNode.DerOctetString)pbkdf2ParametersChildren.get(0)).toVal();
          nIterations = (int)
            ((DerNode.DerInteger)pbkdf2ParametersChildren.get(1)).toVal();
        }
        catch (Throwable ex) {
          throw new TpmPrivateKey.Error
            ("Cannot decode the PBES2 parameters: " + ex);
        }

        // Check the encryption scheme here to get the needed result length.
        int resultLength;
        if (encryptionSchemeOidString.equals(DES_EDE3_CBC_OID))
          resultLength = DES_EDE3_KEY_LENGTH;
        else
          throw new TpmPrivateKey.Error
            ("Unrecognized PBES2 encryption scheme OID: " +
             encryptionSchemeOidString);

        try {
          derivedKey = Common.computePbkdf2WithHmacSha1
            (new Blob(password, false).getImmutableArray(),
             salt.getImmutableArray(), nIterations, resultLength);
        }
        catch (Throwable ex) {
          throw new TpmPrivateKey.Error
            ("Error computing the derived key using PBKDF2 with HMAC SHA1: " + ex);
        }
      }
      else
        throw new TpmPrivateKey.Error
          ("Unrecognized PBES2 key derivation OID: " + keyDerivationOidString);

      // Use the derived key to get the unencrypted pkcs8Encoding.
      if (encryptionSchemeOidString.equals(DES_EDE3_CBC_OID)) {
        // Decode the DES-EDE3-CBC parameters.
        Blob initialVector;
        try {
          initialVector = (Blob)
            ((DerNode.DerOctetString)encryptionSchemeParameters).toVal();
        }
        catch (Throwable ex) {
          throw new TpmPrivateKey.Error
            ("Cannot decode the DES-EDE3-CBC parameters: " + ex);
        }

        try {
          Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
          cipher.init
            (Cipher.DECRYPT_MODE,
             new SecretKeySpec(derivedKey, "DESede"),
             new IvParameterSpec(initialVector.getImmutableArray()));
          pkcs8Encoding = cipher.doFinal(encryptedKey.getImmutableArray());
        }
        catch (Throwable ex) {
          throw new TpmPrivateKey.Error
            ("Error decrypting PKCS #8 key with DES-EDE3-CBC: " + ex);
        }
      }
      else
        throw new TpmPrivateKey.Error
          ("Unrecognized PBES2 encryption scheme OID: " +
           encryptionSchemeOidString);
    }
    else
      throw new TpmPrivateKey.Error
        ("Unrecognized PKCS #8 EncryptedPrivateKeyInfo OID: " + oidString);

    loadPkcs8(ByteBuffer.wrap(pkcs8Encoding));
  }

  /**
   * Get the encoded public key for this private key.
   * @return The public key encoding Blob.
   * @throws TpmPrivateKey.Error if no private key is loaded, or error
   * converting to a public key.
   */
  public final Blob
  derivePublicKey() throws TpmPrivateKey.Error
  {
    if (keyType_ == KeyType.EC) {
      throw new TpmPrivateKey.Error
        ("TODO: derivePublicKey for EC is not implemented");
    }
    else if (keyType_ == KeyType.RSA) {
      // Decode the PKCS #1 RSAPrivateKey. (We don't use RSAPrivateCrtKey because
      // the Android library doesn't have an easy way to decode into it.)
      List rsaPrivateKeyChildren;
      try {
        DerNode parsedNode = DerNode.parse(toPkcs1().buf(), 0);
        rsaPrivateKeyChildren = parsedNode.getChildren();
      } catch (DerDecodingException ex) {
        throw new TpmPrivateKey.Error
          ("Error parsing RSA PKCS #1 key: " + ex);
      }
      Blob modulus = ((DerNode)rsaPrivateKeyChildren.get(1)).getPayload();
      Blob publicExponent = ((DerNode)rsaPrivateKeyChildren.get(2)).getPayload();

      try {
        java.security.PublicKey publicKey =
          KeyFactory.getInstance("RSA").generatePublic
            (new RSAPublicKeySpec
             (new BigInteger(modulus.getImmutableArray()),
              new BigInteger(publicExponent.getImmutableArray())));
        return new Blob(publicKey.getEncoded(), false);
      } catch (Exception ex) {
        throw new TpmPrivateKey.Error("Error making RSA public key: " + ex);
      }
    }
    else
      throw new TpmPrivateKey.Error
        ("derivePublicKey: The private key is not loaded");
  }

  /**
   * Decrypt the cipherText using this private key according the encryption
   * algorithmType. Only RSA encryption is supported for now.
   * @param cipherText The cipher text byte buffer.
   * @param algorithmType This decrypts according to algorithmType.
   * @return The decrypted data.
   * @throws TpmPrivateKey.Error if the private key is not loaded, if
   * decryption is not supported for this key type, or for error decrypting.
   */
  public final Blob
  decrypt(ByteBuffer cipherText, EncryptAlgorithmType algorithmType)
    throws TpmPrivateKey.Error
  {
    if (keyType_ == null)
      throw new TpmPrivateKey.Error("decrypt: The private key is not loaded");

    String transformation;
    if (algorithmType == EncryptAlgorithmType.RsaPkcs)
      transformation = "RSA/ECB/PKCS1Padding";
    else if (algorithmType == EncryptAlgorithmType.RsaOaep)
      transformation = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
    else
      throw new TpmPrivateKey.Error("unsupported padding scheme");

    try {
      Cipher cipher = Cipher.getInstance(transformation);
      cipher.init(Cipher.DECRYPT_MODE, privateKey_);
      // Use Blob to get the byte array.
      byte[] cipherByteArray = new Blob(cipherText, false).getImmutableArray();
      return new Blob(cipher.doFinal(cipherByteArray), false);
    } catch (Exception ex) {
      throw new TpmPrivateKey.Error
        ("Error decrypting with private key: " + ex.getMessage());
    }
  }

  /**
   * Call the main decrypt where algorithmType is RsaOaep.
   */
  public final Blob
  decrypt(ByteBuffer cipherText) throws TpmPrivateKey.Error
  {
    return decrypt(cipherText, EncryptAlgorithmType.RsaOaep);
  }

  /**
   * Sign the data with this private key, returning a signature Blob.
   * @param data The input byte buffer.
   * @param digestAlgorithm the digest algorithm.
   * @return The signature Blob, or an isNull Blob if this private key is not
   * initialized.
   * @throws TpmPrivateKey.Error for unrecognized digestAlgorithm or an error
   * in signing.
   */
  public final Blob
  sign(ByteBuffer data, DigestAlgorithm digestAlgorithm)
    throws TpmPrivateKey.Error
  {
    if (digestAlgorithm != DigestAlgorithm.SHA256)
      throw new TpmPrivateKey.Error
        ("TpmPrivateKey.sign: Unsupported digest algorithm");

    java.security.Signature signature = null;
    if (keyType_ == KeyType.EC) {
      try {
        signature = java.security.Signature.getInstance("SHA256withECDSA");
      }
      catch (NoSuchAlgorithmException e) {
        // Don't expect this to happen.
        throw new TpmPrivateKey.Error
          ("SHA256withECDSA algorithm is not supported");
      }
    }
    else if (keyType_ == KeyType.RSA) {
      try {
        signature = java.security.Signature.getInstance("SHA256withRSA");
      }
      catch (NoSuchAlgorithmException e) {
        // Don't expect this to happen.
        throw new TpmPrivateKey.Error("SHA256withRSA algorithm is not supported");
      }
    }
    else
      return new Blob();

    try {
      signature.initSign(privateKey_);
    }
    catch (InvalidKeyException exception) {
      throw new TpmPrivateKey.Error
        ("InvalidKeyException: " + exception.getMessage());
    }
    try {
      signature.update(data);
      return new Blob(signature.sign(), false);
    }
    catch (SignatureException exception) {
      throw new TpmPrivateKey.Error
        ("SignatureException: " + exception.getMessage());
    }
  }

  /**
   * Get the encoded unencrypted private key in PKCS #1.
   * @return The private key encoding Blob.
   * @throws TpmPrivateKey.Error if no private key is loaded, or error encoding.
   */
  public final Blob
  toPkcs1() throws TpmPrivateKey.Error
  {
    if (keyType_ == null)
      throw new TpmPrivateKey.Error("toPkcs1: The private key is not loaded");

    // Decode the PKCS #8 private key.
    DerNode parsedNode;
    try {
      parsedNode = DerNode.parse(toPkcs8().buf(), 0);
      List pkcs8Children = parsedNode.getChildren();
      return ((DerNode)pkcs8Children.get(2)).getPayload();
    } catch (DerDecodingException ex) {
      throw new TpmPrivateKey.Error("Error decoding PKCS #8 private key: " + ex);
    }
  }

  /**
   * Get the encoded unencrypted private key in PKCS #8.
   * @return The private key encoding Blob.
   * @throws TpmPrivateKey.Error if no private key is loaded, or error encoding.
   */
  public final Blob
  toPkcs8() throws TpmPrivateKey.Error
  {
    if (keyType_ == null)
      throw new TpmPrivateKey.Error("toPkcs8: The private key is not loaded");

    return new Blob(privateKey_.getEncoded());
  }

  /**
   * Get the encoded encrypted private key in PKCS #8.
   * @param password The password for encrypting the private key.
   * @return The encoding Blob of the EncryptedPrivateKeyInfo.
   * @throws TpmPrivateKey.Error if no private key is loaded, or error encoding.
   */
  public final Blob
  toEncryptedPkcs8(ByteBuffer password) throws TpmPrivateKey.Error
  {
    if (keyType_ == null)
      throw new TpmPrivateKey.Error
        ("toEncryptedPkcs8: The private key is not loaded");

    // Create the derivedKey from the password.
    final int nIterations = 2048;
    byte[] salt = new byte[8];
    Common.getRandom().nextBytes(salt);
    byte[] derivedKey;
    try {
      derivedKey = Common.computePbkdf2WithHmacSha1
        (new Blob(password, false).getImmutableArray(),
         salt, nIterations, DES_EDE3_KEY_LENGTH);
    }
    catch (Throwable ex) {
      // We don't expect this to happen.
      throw new TpmPrivateKey.Error
        ("Error computing the derived key using PBKDF2 with HMAC SHA1: " + ex);
    }

    // Use the derived key to get the encrypted pkcs8Encoding.
    byte[] encryptedEncoding;
    byte[] initialVector = new byte[8];
    Common.getRandom().nextBytes(initialVector);
    try {
      Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
      cipher.init
        (Cipher.ENCRYPT_MODE,
         new SecretKeySpec(derivedKey, "DESede"),
         new IvParameterSpec(initialVector));
      encryptedEncoding = cipher.doFinal(privateKey_.getEncoded());
    }
    catch (Throwable ex) {
      throw new TpmPrivateKey.Error
        ("Error encrypting PKCS #8 key with DES-EDE3-CBC: " + ex);
    }

    try {
      // Encode the PBES2 parameters. See https://www.ietf.org/rfc/rfc2898.txt .
      DerSequence keyDerivationParameters = new DerSequence();
      keyDerivationParameters.addChild(new DerNode.DerOctetString
        (ByteBuffer.wrap(salt)));
      keyDerivationParameters.addChild(new DerNode.DerInteger(nIterations));
      DerSequence keyDerivationAlgorithmIdentifier = new DerSequence();
      keyDerivationAlgorithmIdentifier.addChild(new DerNode.DerOid
        (PBKDF2_OID));
      keyDerivationAlgorithmIdentifier.addChild(keyDerivationParameters);

      DerSequence encryptionSchemeAlgorithmIdentifier = new DerSequence();
      encryptionSchemeAlgorithmIdentifier.addChild(new DerNode.DerOid
        (DES_EDE3_CBC_OID));
      encryptionSchemeAlgorithmIdentifier.addChild(new DerNode.DerOctetString
        (ByteBuffer.wrap(initialVector)));

      DerSequence encryptedKeyParameters = new DerSequence();
      encryptedKeyParameters.addChild(keyDerivationAlgorithmIdentifier);
      encryptedKeyParameters.addChild(encryptionSchemeAlgorithmIdentifier);
      DerSequence encryptedKeyAlgorithmIdentifier = new DerSequence();
      encryptedKeyAlgorithmIdentifier.addChild(new DerNode.DerOid(PBES2_OID));
      encryptedKeyAlgorithmIdentifier.addChild(encryptedKeyParameters);

      // Encode the PKCS #8 EncryptedPrivateKeyInfo.
      // See https://tools.ietf.org/html/rfc5208.
      DerSequence encryptedKey = new DerSequence();
      encryptedKey.addChild(encryptedKeyAlgorithmIdentifier);
      encryptedKey.addChild(new DerNode.DerOctetString
        (ByteBuffer.wrap(encryptedEncoding)));

      return encryptedKey.encode();
    } catch (DerEncodingException ex) {
      throw new TpmPrivateKey.Error
        ("Error encoding the encryped PKCS #8 private key: " + ex);
    }
  }

  /**
   * Generate a key pair according to keyParams and return a new TpmPrivateKey
   * with the private key. You can get the public key with derivePublicKey.
   * @param keyParams The parameters of the key.
   * @return A new TpmPrivateKey.
   * @throws IllegalArgumentException if the key type is not supported.
   * @throws TpmPrivateKey.Error for an invalid key size, or an error generating.
   */
  public static TpmPrivateKey
  generatePrivateKey(KeyParams keyParams)
    throws IllegalArgumentException, TpmPrivateKey.Error
  {
    String keyAlgorithm;
    int keySize;
    if (keyParams.getKeyType() == KeyType.RSA) {
      keyAlgorithm = "RSA";
      keySize = ((RsaKeyParams)keyParams).getKeySize();
    }
    else if (keyParams.getKeyType() == KeyType.EC) {
      keyAlgorithm = "EC";
      keySize = ((EcKeyParams)keyParams).getKeySize();
    }
    else
      throw new IllegalArgumentException
        ("Cannot generate a key pair of type " + keyParams.getKeyType());

    KeyPairGenerator generator = null;
    try{
      generator = KeyPairGenerator.getInstance(keyAlgorithm);
    }
    catch(NoSuchAlgorithmException e){
      throw new TpmPrivateKey.Error
        ("TpmPrivateKey: Could not create the key generator: " + e.getMessage());
    }

    generator.initialize(keySize);
    KeyPair pair = generator.generateKeyPair();

    TpmPrivateKey result = new TpmPrivateKey();
    result.keyType_ = keyParams.getKeyType();
    result.privateKey_ = pair.getPrivate();

    return result;
  }

  /**
   * Encode the private key to a PKCS #8 private key. We do this explicitly here
   * to avoid linking to extra OpenSSL libraries.
   * @param privateKeyDer The input private key DER.
   * @param oid The OID of the privateKey.
   * @param parameters The DerNode of the parameters for the OID.
   * @return The PKCS #8 private key DER.
   */
  private static Blob
  encodePkcs8PrivateKey(ByteBuffer privateKeyDer, OID oid, DerNode parameters)
    throws TpmPrivateKey.Error
  {
    try {
      DerSequence algorithmIdentifier = new DerSequence();
      algorithmIdentifier.addChild(new DerNode.DerOid(oid));
      algorithmIdentifier.addChild(parameters);

      DerSequence result = new DerSequence();
      result.addChild(new DerNode.DerInteger(0));
      result.addChild(algorithmIdentifier);
      result.addChild(new DerNode.DerOctetString(privateKeyDer));

      return result.encode();
    } catch (DerEncodingException ex) {
      throw new TpmPrivateKey.Error("Error encoding PKCS #8 private key: " + ex);
    }
  }

  private static final String RSA_ENCRYPTION_OID = "1.2.840.113549.1.1.1";
  private static final String EC_ENCRYPTION_OID = "1.2.840.10045.2.1";
  private static final String PBES2_OID = "1.2.840.113549.1.5.13";
  private static final String PBKDF2_OID = "1.2.840.113549.1.5.12";
  private static final String DES_EDE3_CBC_OID = "1.2.840.113549.3.7";
  private static final int DES_EDE3_KEY_LENGTH = 24;

  private KeyType keyType_ = null;
  private java.security.PrivateKey privateKey_;
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy