예제 #1
0
  /**
   * Extract a PGPPrivate key from the SecretKey's encrypted contents.
   *
   * @param decryptorFactory factory to use to generate a decryptor for the passed in secretKey.
   * @return PGPPrivateKey the unencrypted private key.
   * @throws PGPException on failure.
   */
  public PGPPrivateKey extractPrivateKey(PBESecretKeyDecryptor decryptorFactory)
      throws PGPException {
    if (isPrivateKeyEmpty()) {
      return null;
    }

    PublicKeyPacket pubPk = secret.getPublicKeyPacket();

    try {
      byte[] data = extractKeyData(decryptorFactory);
      BCPGInputStream in = new BCPGInputStream(new ByteArrayInputStream(data));

      switch (pubPk.getAlgorithm()) {
        case PGPPublicKey.RSA_ENCRYPT:
        case PGPPublicKey.RSA_GENERAL:
        case PGPPublicKey.RSA_SIGN:
          RSASecretBCPGKey rsaPriv = new RSASecretBCPGKey(in);

          return new PGPPrivateKey(this.getKeyID(), pubPk, rsaPriv);
        case PGPPublicKey.DSA:
          DSASecretBCPGKey dsaPriv = new DSASecretBCPGKey(in);

          return new PGPPrivateKey(this.getKeyID(), pubPk, dsaPriv);
        case PGPPublicKey.ELGAMAL_ENCRYPT:
        case PGPPublicKey.ELGAMAL_GENERAL:
          ElGamalSecretBCPGKey elPriv = new ElGamalSecretBCPGKey(in);

          return new PGPPrivateKey(this.getKeyID(), pubPk, elPriv);
        default:
          throw new PGPException("unknown public key algorithm encountered");
      }
    } catch (PGPException e) {
      throw e;
    } catch (Exception e) {
      throw new PGPException("Exception constructing key", e);
    }
  }
예제 #2
0
  private byte[] extractKeyData(PBESecretKeyDecryptor decryptorFactory) throws PGPException {
    byte[] encData = secret.getSecretKeyData();
    byte[] data = null;

    if (secret.getEncAlgorithm() != SymmetricKeyAlgorithmTags.NULL) {
      try {
        if (secret.getPublicKeyPacket().getVersion() == 4) {
          byte[] key =
              decryptorFactory.makeKeyFromPassPhrase(secret.getEncAlgorithm(), secret.getS2K());

          data =
              decryptorFactory.recoverKeyData(
                  secret.getEncAlgorithm(), key, secret.getIV(), encData, 0, encData.length);

          boolean useSHA1 = secret.getS2KUsage() == SecretKeyPacket.USAGE_SHA1;
          byte[] check =
              checksum(
                  useSHA1 ? decryptorFactory.getChecksumCalculator(HashAlgorithmTags.SHA1) : null,
                  data,
                  (useSHA1) ? data.length - 20 : data.length - 2);

          for (int i = 0; i != check.length; i++) {
            if (check[i] != data[data.length - check.length + i]) {
              throw new PGPException("checksum mismatch at " + i + " of " + check.length);
            }
          }
        } else // version 2 or 3, RSA only.
        {
          byte[] key =
              decryptorFactory.makeKeyFromPassPhrase(secret.getEncAlgorithm(), secret.getS2K());

          data = new byte[encData.length];

          byte[] iv = new byte[secret.getIV().length];

          System.arraycopy(secret.getIV(), 0, iv, 0, iv.length);

          //
          // read in the four numbers
          //
          int pos = 0;

          for (int i = 0; i != 4; i++) {
            int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8;

            data[pos] = encData[pos];
            data[pos + 1] = encData[pos + 1];

            byte[] tmp =
                decryptorFactory.recoverKeyData(
                    secret.getEncAlgorithm(), key, iv, encData, pos + 2, encLen);
            System.arraycopy(tmp, 0, data, pos + 2, tmp.length);
            pos += 2 + encLen;

            if (i != 3) {
              System.arraycopy(encData, pos - iv.length, iv, 0, iv.length);
            }
          }

          //
          // verify and copy checksum
          //

          data[pos] = encData[pos];
          data[pos + 1] = encData[pos + 1];

          int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff);
          int calcCs = 0;
          for (int j = 0; j < data.length - 2; j++) {
            calcCs += data[j] & 0xff;
          }

          calcCs &= 0xffff;
          if (calcCs != cs) {
            throw new PGPException(
                "checksum mismatch: passphrase wrong, expected "
                    + Integer.toHexString(cs)
                    + " found "
                    + Integer.toHexString(calcCs));
          }
        }
      } catch (PGPException e) {
        throw e;
      } catch (Exception e) {
        throw new PGPException("Exception decrypting key", e);
      }
    } else {
      data = encData;
    }

    return data;
  }