2011-07-07 20 views
6

He estado golpeando mi cabeza contra la pared ahora por un par de semanas tratando de descubrir por qué nuestro banco no puede descifrar un mensaje que ha sido firmado y encriptado usando BouncyCastle PGP. El banco está utilizando McAfee E-Business Server 8.6 para descifrado.BouncyCastle PGP y McAfee eBusiness Server 8.6 Incompatibilidad

Los datos se encriptan con la clave pública del banco y se firman con nuestra clave privada.

Al utilizar nuestra propia clave pública para el cifrado, puedo descifrar y verificar con éxito la firma en un archivo generado con el siguiente código. Gnupg puede descifrar y verificar el archivo muy bien.

Sin embargo, el banco no puede descifrar el archivo. Intenté apagar la compresión primero y luego desactivar la armadura ASCII. Ninguna de las opciones parece funcionar, y siempre recibe el mismo mensaje de error, no importa qué opciones Trato:

event 1: initial 
event 13: BeginLex 
event 8: Analyze 
File is encrypted. event 9: Recipients 
Secret key is required to read it. 
Key for user ID "XXXXXXXXX <[email protected]>" 
event 6: Passphrase 
event 23: Decryption 

symmetric cipher used: CAST5 
event 3: error -11391 

event 2: final 

Error decrypting file '/somepath/FILENAME'. 
Corrupt data. 
Bad packet 

exitcode = 32 

Aquí está el código que estoy utilizando para hacer el signo de un solo paso y cifrar:

public class PGPService { 

    private static final Logger log = Logger.getLogger(PGPService.class); 


    static { 
     Security.addProvider(new BouncyCastleProvider()); 
    } 


    /** 
    * A simple routine that opens a key ring file and loads the first available key 
    * suitable for signature generation. 
    * 
    * @param input stream to read the secret key ring collection from. 
    * @return a secret key. 
    * @throws IOException on a problem with using the input stream. 
    * @throws PGPException if there is an issue parsing the input stream. 
    */ 
    @SuppressWarnings("rawtypes") 
    private static PGPSecretKey readSecretKey(InputStream input) throws IOException, PGPException { 
     PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
     PGPUtil.getDecoderStream(input)); 

     // We just loop through the collection till we find a key suitable for encryption, in the real 
     // world you would probably want to be a bit smarter about this. 

     Iterator keyRingIter = pgpSec.getKeyRings(); 
     while (keyRingIter.hasNext()) { 
      PGPSecretKeyRing keyRing = (PGPSecretKeyRing)keyRingIter.next(); 
      Iterator keyIter = keyRing.getSecretKeys(); 
      while (keyIter.hasNext()) { 
       PGPSecretKey key = (PGPSecretKey)keyIter.next(); 
       if (key.isSigningKey()) { 
        return key; 
       } 
      } 
     } 

     throw new IllegalArgumentException("Can't find signing key in key ring."); 
    } 

    /** 
    * Single pass signs and encrypts the given file to the given output file using the provided keys. 
    * 
    * @param fileNameIn - The name and location of the source input file. 
    * @param fileNameOut - The name and location of the destination output file. 
    * @param privateKeyIn - The input stream for the private key file. 
    * @param privateKeyPassword - The password for the private key file. 
    * @param publicEncryptionKey - The public encryption key. 
    * @param armoredOutput - Whether or not to ASCII armor the output. 
    */ 
    @SuppressWarnings("rawtypes") 
    public static void signAndEncrypt(String fileNameIn, String fileNameOut, InputStream privateKeyIn, String privateKeyPassword, PGPPublicKey publicEncryptionKey, boolean armoredOutput, boolean compress) { 

     int bufferSize = 1<<16; 
     InputStream input = null; 
     OutputStream finalOut = null; 
     OutputStream encOut = null; 
     OutputStream compressedOut = null; 
     OutputStream literalOut = null; 
     PGPEncryptedDataGenerator encryptedDataGenerator = null; 
     PGPCompressedDataGenerator compressedDataGenerator = null; 
     PGPSignatureGenerator signatureGenerator = null; 
     PGPLiteralDataGenerator literalDataGenerator = null; 

     try { 

      File output = new File(fileNameOut); 
      OutputStream out = new FileOutputStream(output); 
      if (armoredOutput) out = new ArmoredOutputStream(out); 

      // ? Use BCPGOutputStreams ? 

      // Init encrypted data generator 
      encryptedDataGenerator = new PGPEncryptedDataGenerator(PGPEncryptedDataGenerator.CAST5, true, new SecureRandom(), "BC"); 
      encryptedDataGenerator.addMethod(publicEncryptionKey); 
      finalOut = new BufferedOutputStream(out, bufferSize); 
      encOut = encryptedDataGenerator.open(finalOut, new byte[bufferSize]); 

      // Init compression 
      if (compress) { 
       compressedDataGenerator = new PGPCompressedDataGenerator(PGPCompressedData.ZLIB); 
       compressedOut = new BufferedOutputStream(compressedDataGenerator.open(encOut)); 
      } 

      // Init signature 
      PGPSecretKey pgpSec = readSecretKey(privateKeyIn); 
      PGPPrivateKey pgpPrivKey = pgpSec.extractPrivateKey(privateKeyPassword.toCharArray(), "BC");   
      signatureGenerator = new PGPSignatureGenerator(pgpSec.getPublicKey().getAlgorithm(), PGPUtil.SHA1, "BC"); 
      signatureGenerator.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT, pgpPrivKey); 
      Iterator it = pgpSec.getPublicKey().getUserIDs(); 
      if (it.hasNext()) { 
       PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); 
       spGen.setSignerUserID(false, (String)it.next()); 
       signatureGenerator.setHashedSubpackets(spGen.generate()); 
      } 
      PGPOnePassSignature onePassSignature = signatureGenerator.generateOnePassVersion(false); 
      if (compress) onePassSignature.encode(compressedOut); 
      else onePassSignature.encode(encOut); 

      // Create the Literal Data generator Output stream which writes to the compression stream 
      literalDataGenerator = new PGPLiteralDataGenerator(true); 
      if (compress) literalOut = literalDataGenerator.open(compressedOut, PGPLiteralData.BINARY, output.getName(), new Date(), new byte[bufferSize]); 
      else literalOut = literalDataGenerator.open(encOut, PGPLiteralData.TEXT, fileNameIn, new Date(), new byte[bufferSize]); 

      // Update sign and encrypt 
      byte[] buffer = new byte[bufferSize]; 

      int bytesRead = 0; 
      input = new FileInputStream(fileNameIn); 
      while((bytesRead = input.read(buffer)) != -1) { 
       literalOut.write(buffer,0,bytesRead); 
       signatureGenerator.update(buffer,0,bytesRead); 
       literalOut.flush(); 
      } 

      // Close Literal data stream and add signature 
      literalOut.close(); 
      literalDataGenerator.close(); 
      if (compress) signatureGenerator.generate().encode(compressedOut); 
      else signatureGenerator.generate().encode(encOut); 

     } catch (Exception e) { 
      log.error(e); 
      throw new RuntimeException(e); 
     } finally { 
      // Close all streams 
      if (literalOut != null) try { literalOut.close(); } catch (IOException e) {} 
      if (literalDataGenerator != null) try { literalDataGenerator.close(); } catch (IOException e) {} 
      if (compressedOut != null) try { compressedOut.close(); } catch (IOException e) {} 
      if (compressedDataGenerator != null) try { compressedDataGenerator.close(); } catch (IOException e) {} 
      if (encOut != null) try { encOut.close(); } catch (IOException e) {} 
      if (encryptedDataGenerator != null) try { encryptedDataGenerator.close(); } catch (IOException e) {} 
      if (finalOut != null) try { finalOut.close(); } catch (IOException e) {} 
      if (input != null) try { input.close(); } catch (IOException e) {} 
     } 
    } 

    @SuppressWarnings("rawtypes") 
    private static PGPPublicKey readPublicKeyFromCol(InputStream in) throws Exception { 
     PGPPublicKeyRing pkRing = null; 
     PGPPublicKeyRingCollection pkCol = new PGPPublicKeyRingCollection(in); 
     log.info("Key ring size = " + pkCol.size()); 
     Iterator it = pkCol.getKeyRings(); 
     while (it.hasNext()) { 
      pkRing = (PGPPublicKeyRing) it.next(); 
      Iterator pkIt = pkRing.getPublicKeys(); 
      while (pkIt.hasNext()) { 
       PGPPublicKey key = (PGPPublicKey) pkIt.next(); 
       log.info("Encryption key = " + key.isEncryptionKey() + ", Master key = " + 
       key.isMasterKey()); 
       if (key.isEncryptionKey()) { 
        // Find out a little about the keys in the public key ring. 
        log.info("Key Strength = " + key.getBitStrength()); 
        log.info("Algorithm = " + key.getAlgorithm()); 
        log.info("Bit strength = " + key.getBitStrength()); 
        log.info("Version = " + key.getVersion()); 
        return key; 
       } 
      } 
     } 
     return null; 
    } 

    private static PGPPrivateKey findSecretKey(InputStream keyIn, long keyID, char[] pass) 
      throws IOException, PGPException, NoSuchProviderException { 
     PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn)); 
     PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID); 
     if (pgpSecKey == null) { 
      return null; 
     } 
     return pgpSecKey.extractPrivateKey(pass, "BC"); 
    } 
} 

¿Alguna idea de qué podría estar causando esto? He encontrado numerosos informes usando Google, pero no hay resoluciones ni seguimientos.

+0

Intente utilizar una versión de prueba de PGP reciente y vea si obtiene el mismo error. La clave para descubrir esto por su cuenta es averiguar qué significa el error -11391. Si tuviera que adivinar, supongo que necesita utilizar un algoritmo de cadena a clave (s2k) más antiguo para trabajar con esta versión anterior de PGP. –

+0

@GregS, ¿Qué versión anterior de PGP está hablando? Este problema está relacionado con dos sistemas actuales de PGP. Bouncy Castle y el servidor de McAfee eBusiness. – Nobody

+0

Pensé que el producto McAfee era viejo. –

Respuesta

6

Estoy respondiendo mi propia pregunta con la esperanza de que ayude a alguien más en la línea, ya que la respuesta a esta pregunta fue MUY difícil de encontrar en línea.

Las versiones de McAfee E-Business Server anteriores a la 8.6 tenían un problema de compatibilidad con BouncyCastle PGP, y parece que la mayoría de las personas no pudieron hacerlo funcionar. Entonces, si su proveedor/cliente/banco está utilizando una versión de E-Business Server anterior a la 8.6, es muy posible que usted sea SOL y necesite encontrar un paquete de cifrado diferente.

Fuente: https://kc.mcafee.com/corporate/index?page=content&id=KB60816&cat=CORP_EBUSINESS_SERVER&actp=LIST

"Descifrar un archivo que se cifró con el castillo hinchable v1.37 puede resultar en un error Violación de acceso (o SIGSEG en plataformas UNIX) Este tema ha sido dirigida en . este lanzamiento ".

Afortunadamente, nuestro banco está utilizando McAfee E-Business Server 8.6. Sin embargo, esto es solo una parte de la ecuación. Para resolver el problema de incompatibilidad, tuvimos que desactivar AMBAS compresiones y armaduras ASCII antes de que pudieran descifrar y verificar nuestro archivo. Así, utilizando el código original que he publicado, esta es la forma en que lo llamaría para los clientes utilizando E-Business Server 8.6:

PGPService.signAndEncrypt(clearTextFileName, secureFileName, privKeyIn, privateKeyFilePassword, pubKeyIn, true, false, false); 

Por supuesto, esto significa que no puede utilizar blindaje ASCII que puede o no puede ser un problema con usted . Si es así, David en la lista de correo de dev BouncyCastle, sugirió que utilice BouncyCastle en modo no paquete. IE: No pase un búfer de bytes a los comandos abiertos en la secuencia. O bien, firme y encripte el archivo en dos pasos.

Tal como llamando a:

public static void signFile(String fileNameIn, String fileNameOut, InputStream privKeyIn, String password, boolean armoredOutput) { 

     OutputStream out = null; 
     BCPGOutputStream bOut = null; 
     OutputStream lOut = null; 
     InputStream fIn = null; 

     try { 
      out = new FileOutputStream(fileNameOut); 
      if (armoredOutput) { 
       out = new ArmoredOutputStream(out); 
      } 
      PGPSecretKey pgpSec = readSecretKey(privKeyIn); 
      PGPPrivateKey pgpPrivKey = pgpSec.extractPrivateKey(password.toCharArray(), "BC");   
      PGPSignatureGenerator sGen = new PGPSignatureGenerator(pgpSec.getPublicKey().getAlgorithm(), PGPUtil.SHA1, "BC"); 

      sGen.initSign(PGPSignature.BINARY_DOCUMENT, pgpPrivKey); 

      Iterator it = pgpSec.getPublicKey().getUserIDs(); 
      if (it.hasNext()) { 
       PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); 
       spGen.setSignerUserID(false, (String)it.next()); 
       sGen.setHashedSubpackets(spGen.generate()); 
      } 

      PGPCompressedDataGenerator cGen = new PGPCompressedDataGenerator(PGPCompressedData.ZLIB); 
      bOut = new BCPGOutputStream(cGen.open(out)); 

      sGen.generateOnePassVersion(false).encode(bOut); 

      File file = new File(fileNameIn); 
      PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); 
      lOut = lGen.open(bOut, PGPLiteralData.BINARY, file); 
      fIn = new FileInputStream(file); 
      int ch = 0; 

      while ((ch = fIn.read()) >= 0) { 
       lOut.write(ch); 
       sGen.update((byte) ch); 
      } 

      lGen.close(); 
      sGen.generate().encode(bOut); 
      cGen.close(); 

     } catch (Exception e) { 
      log.error(e); 
      throw new RuntimeException(e); 
     } finally { 
      if (lOut != null) try { lOut.close(); } catch (IOException e) {} 
      if (bOut != null) try { bOut.close(); } catch (IOException e) {} 
      if (out != null) try { out.close(); } catch (IOException e) {} 
      if (fIn != null) try { fIn.close(); } catch (IOException e) {} 
     } 
    } 

Seguido de llamar:

public static byte[] encrypt(byte[] data, InputStream pubKeyIn, boolean isPublicKeyArmored) { 

     FileOutputStream fos = null; 
     BufferedReader isr = null; 

     try { 
      if (isPublicKeyArmored) pubKeyIn = new ArmoredInputStream(pubKeyIn); 
      PGPPublicKey key = readPublicKeyFromCol(pubKeyIn); 
      log.info("Creating a temp file..."); 
      // Create a file and write the string to it. 
      File tempfile = File.createTempFile("pgp", null); 
      fos = new FileOutputStream(tempfile); 
      fos.write(data); 
      fos.close(); 
      log.info("Temp file created at: " + tempfile.getAbsolutePath()); 
      log.info("Reading the temp file to make sure that the bits were written...\n"); 
      isr = new BufferedReader(new FileReader(tempfile)); 
      String line = ""; 
      while ((line = isr.readLine()) != null) { 
       log.info(line + "\n"); 
      } 
      int count = 0; 
      for (java.util.Iterator iterator = key.getUserIDs(); iterator.hasNext();) { 
       count++; 
       log.info(iterator.next()); 
      } 
      log.info("Key Count = " + count); 
      // Encrypt the data. 
      ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
      _encrypt(tempfile.getAbsolutePath(), baos, key); 
      log.info("Encrypted text length = " + baos.size());   
      tempfile.delete(); 
      return baos.toByteArray(); 
     } catch (PGPException e) { 
      log.error(e); 
      throw new RuntimeException(e); 
     } catch (Exception e) { 
      log.error(e); 
      throw new RuntimeException(e); 
     } finally { 
      if (fos != null) try { fos.close(); } catch (IOException e) {} 
      if (isr != null) try { isr.close(); } catch (IOException e) {} 
     } 
    } 

caveat.emptor, ya que no era capaz de probar este método para ver si esto incluso resolver el problema de incompatibilidad. Pero es una ruta que puede probar si no tiene opciones y debe usar blindaje ASCII para un destino de servidor de E-Business.

Puede encontrar más información en el archivo de la lista de correo de BouncyCastle dev que puede ayudar si decide seguir este camino. Específicamente este hilo: http://www.bouncycastle.org/devmailarchive/msg12080.html

+0

BouncyCastle 1.49 mcafee ebusiness-server 8.6, funciona bien girando armore y copression, pero falla en modo no paquete ....... – Hippoom

+0

¡Muy útil e increíble para ir más allá con la implementación alternativa! – user919426

Cuestiones relacionadas