content: /*
   *  Licensed to the Apache Software Foundation (ASF) under one or more
   *  contributor license agreements.  See the NOTICE file distributed with
   *  this work for additional information regarding copyright ownership.
   *  The ASF licenses this file to You under the Apache License, Version 2.0
   *  (the "License"); you may not use this file except in compliance with
   *  the License.  You may obtain a copy of the License at
   *
   *      https://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   */
  package org.apache.ivy.plugins.signer.bouncycastle;
  
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.security.Security;
  import java.util.Iterator;
  
  import org.apache.ivy.plugins.signer.SignatureGenerator;
  import org.bouncycastle.bcpg.ArmoredOutputStream;
  import org.bouncycastle.bcpg.BCPGOutputStream;
  import org.bouncycastle.jce.provider.BouncyCastleProvider;
  import org.bouncycastle.openpgp.PGPException;
  import org.bouncycastle.openpgp.PGPPrivateKey;
  import org.bouncycastle.openpgp.PGPSecretKey;
  import org.bouncycastle.openpgp.PGPSecretKeyRing;
  import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
  import org.bouncycastle.openpgp.PGPSignature;
  import org.bouncycastle.openpgp.PGPSignatureGenerator;
  import org.bouncycastle.openpgp.PGPUtil;
  import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
  import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
  import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
  import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
  import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
  
  public class OpenPGPSignatureGenerator implements SignatureGenerator {
  
      private static final long MASK = 0xFFFFFFFFL;
  
      static {
          Security.addProvider(new BouncyCastleProvider());
      }
  
      private String name;
  
      private String secring;
  
      private String password;
  
      private String keyId;
  
      private PGPSecretKey pgpSec;
  
      public String getName() {
          return name;
      }
  
      public void setName(String name) {
          this.name = name;
      }
  
      public String getExtension() {
          return "asc";
      }
  
      public void setPassword(String password) {
          this.password = password;
      }
  
      public void setSecring(String secring) {
          this.secring = secring;
      }
  
      public void setKeyId(String keyId) {
          if (!"auto".equals(keyId)) {
              this.keyId = keyId;
          }
      }
  
      public void sign(File src, File dest) throws IOException {
          OutputStream out = null;
          InputStream in = null;
          InputStream keyIn = null;
  
          try {
              if (secring == null) {
                  secring = System.getProperty("user.home") + "/.gnupg/secring.gpg";
              }
  
              if (pgpSec == null) {
                  keyIn = new FileInputStream(secring);
                  pgpSec = readSecretKey(keyIn);
              }
  
              PBESecretKeyDecryptor decryptor = new BcPBESecretKeyDecryptorBuilder(
                      new BcPGPDigestCalculatorProvider()).build(password.toCharArray());
              PGPPrivateKey pgpPrivKey = pgpSec.extractPrivateKey(decryptor);
              PGPSignatureGenerator sGen = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(
                      pgpSec.getPublicKey().getAlgorithm(), PGPUtil.SHA1));
              sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey);
  
              in = new FileInputStream(src);
              out = new BCPGOutputStream(new ArmoredOutputStream(new FileOutputStream(dest)));
  
              int ch = 0;
              while ((ch = in.read()) >= 0) {
                  sGen.update((byte) ch);
              }
  
              sGen.generate().encode(out);
          } catch (PGPException e) {
              throw new IOException(e);
          } finally {
              if (out != null) {
                  try {
                      out.close();
                  } catch (IOException e) {
                  }
              }
              if (in != null) {
                  try {
                      in.close();
                  } catch (IOException e) {
                  }
              }
              if (keyIn != null) {
                  try {
                      keyIn.close();
                  } catch (IOException e) {
                  }
              }
          }
      }
  
      private PGPSecretKey readSecretKey(InputStream in) throws IOException, PGPException {
          in = PGPUtil.getDecoderStream(in);
          PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(in,
                  new BcKeyFingerprintCalculator());
  
          PGPSecretKey key = null;
          Iterator<PGPSecretKeyRing> it = pgpSec.getKeyRings();
          while (key == null && it.hasNext()) {
              PGPSecretKeyRing kRing = it.next();
  
              Iterator<PGPSecretKey> it2 = kRing.getSecretKeys();
              while (key == null && it2.hasNext()) {
                  PGPSecretKey k = it2.next();
                  if (keyId == null && k.isSigningKey()) {
                      key = k;
                  }
                  if (keyId != null && Long.valueOf(keyId, 16) == (k.getKeyID() & MASK)) {
                      key = k;
                  }
              }
          }
  
          if (key == null) {
              throw new IllegalArgumentException("Can't find encryption key"
                      + (keyId != null ? " '" + keyId + "' " : " ") + "in key ring.");
          }
  
          return key;
      }
  
  }
  