in src/main/java/org/apache/xml/security/stax/impl/processor/input/AbstractDecryptInputProcessor.java [812:894]
public void run() {
try {
final OutputStream outputStream; //NOPMD
final Cipher cipher = getSymmetricCipher();
if (cipher.getAlgorithm().toUpperCase().contains("GCM")) {
//we have to buffer the whole data until they are authenticated.
//In GCM mode the authentication tag is appended after the last cipher block...
outputStream = new FullyBufferedOutputStream(pipedOutputStream);
} else {
outputStream = pipedOutputStream;
}
final CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cipher) { //NOPMD
//override close() to workaround a bug in oracle-jdk:
//authentication failures when using AEAD ciphers are silently ignored...
@Override
public void close() throws IOException {
super.flush();
try {
byte[] bytes = cipher.doFinal();
outputStream.write(bytes);
outputStream.close();
} catch (IllegalBlockSizeException | BadPaddingException e) {
throw new IOException(e);
}
}
};
IVSplittingOutputStream ivSplittingOutputStream = new IVSplittingOutputStream( //NOPMD
cipherOutputStream,
cipher, getSecretKey(), getIvLength());
//buffering seems not to help
//bufferedOutputStream = new BufferedOutputStream(new Base64OutputStream(ivSplittingOutputStream, false), 8192 * 5);
ReplaceableOuputStream replaceableOuputStream = new ReplaceableOuputStream(ivSplittingOutputStream); //NOPMD
OutputStream base64OutputStream = new Base64OutputStream(replaceableOuputStream, false); //NOPMD
ivSplittingOutputStream.setParentOutputStream(replaceableOuputStream);
OutputStreamWriter outputStreamWriter = //NOPMD
new OutputStreamWriter(base64OutputStream,
Charset.forName(inputProcessorChain.getDocumentContext().getEncoding()));
//read the encrypted data from the stream until an end-element occurs and write then
//to the decrypter-stream
XMLSecEvent xmlSecEvent = firstEvent;
// End element must be the CipherValue EndElement.
while (xmlSecEvent.getEventType() != XMLStreamConstants.END_ELEMENT) {
if (xmlSecEvent.getEventType() == XMLStreamConstants.CHARACTERS) {
final char[] data = xmlSecEvent.asCharacters().getText();
outputStreamWriter.write(data);
} else {
throw new XMLSecurityException(
"stax.unexpectedXMLEvent",
new Object[] {XMLSecurityUtils.getXMLEventAsString(xmlSecEvent)}
);
}
xmlSecEvent = processNextEvent();
}
//close to get Cipher.doFinal() called
outputStreamWriter.close();
// Clean the secret key from memory now that we're done with it
if (secretKey instanceof Destroyable) {
try {
((Destroyable)secretKey).destroy();
} catch (DestroyFailedException e) {
LOG.log(Level.DEBUG, "Error destroying key: {0}", e.getMessage());
}
}
LOG.log(Level.DEBUG, "Decryption thread finished");
} catch (Exception e) {
try {
//we have to close the pipe when an exception occurs. Otherwise we can run into a deadlock when an exception occurs
//before we have written any byte to the pipe.
this.pipedOutputStream.close();
} catch (IOException e1) { //NOPMD
//ignore since we will throw the original exception below
}
throw new UncheckedXMLSecurityException(e);
}
}