blob: 524f8398681b9e23a123110a49905d2c9cf4b929 [file] [log] [blame]
/*
* 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
*
* http://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.nifi.security.util.crypto;
import static org.bouncycastle.openpgp.PGPUtil.getDecoderStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import org.apache.nifi.processor.exception.ProcessException;
import org.apache.nifi.processor.io.StreamCallback;
import org.apache.nifi.processors.standard.EncryptContent.Encryptor;
import org.bouncycastle.openpgp.PGPCompressedData;
import org.bouncycastle.openpgp.PGPEncryptedDataList;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPPBEEncryptedData;
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.bouncycastle.openpgp.operator.PBEDataDecryptorFactory;
import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
import org.bouncycastle.openpgp.operator.PGPKeyEncryptionMethodGenerator;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OpenPGPPasswordBasedEncryptor implements Encryptor {
private static final Logger logger = LoggerFactory.getLogger(OpenPGPPasswordBasedEncryptor.class);
private String algorithm;
private String provider;
private char[] password;
private String filename;
private Integer cipher;
public OpenPGPPasswordBasedEncryptor(final String algorithm, final Integer cipher, final String provider, final char[] passphrase, final String filename) {
this.algorithm = algorithm;
this.provider = provider;
this.password = passphrase;
this.filename = filename;
this.cipher = cipher;
}
@Override
public StreamCallback getEncryptionCallback() throws Exception {
return new OpenPGPEncryptCallback(algorithm, cipher, provider, password, filename);
}
@Override
public StreamCallback getDecryptionCallback() throws Exception {
return new OpenPGPDecryptCallback(provider, password);
}
@Override
public void updateAttributes(Map<String, String> attributes) throws ProcessException {
// TODO: Implement
}
private static class OpenPGPDecryptCallback implements StreamCallback {
private String provider;
private char[] password;
OpenPGPDecryptCallback(final String provider, final char[] password) {
this.provider = provider;
this.password = password;
}
@Override
public void process(InputStream in, OutputStream out) throws IOException {
InputStream pgpin = getDecoderStream(in);
JcaPGPObjectFactory pgpFactory = new JcaPGPObjectFactory(pgpin);
Object obj = pgpFactory.nextObject();
if (!(obj instanceof PGPEncryptedDataList)) {
obj = pgpFactory.nextObject();
if (!(obj instanceof PGPEncryptedDataList)) {
throw new ProcessException("Invalid OpenPGP data");
}
}
PGPEncryptedDataList encList = (PGPEncryptedDataList) obj;
obj = encList.get(0);
if (!(obj instanceof PGPPBEEncryptedData)) {
throw new ProcessException("Invalid OpenPGP data");
}
PGPPBEEncryptedData encryptedData = (PGPPBEEncryptedData) obj;
try {
final PGPDigestCalculatorProvider digestCalculatorProvider = new JcaPGPDigestCalculatorProviderBuilder().setProvider(provider).build();
final PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder(digestCalculatorProvider).setProvider(provider).build(password);
InputStream clear = encryptedData.getDataStream(decryptorFactory);
JcaPGPObjectFactory pgpObjectFactory = new JcaPGPObjectFactory(clear);
obj = pgpObjectFactory.nextObject();
if (obj instanceof PGPCompressedData) {
PGPCompressedData compressedData = (PGPCompressedData) obj;
pgpObjectFactory = new JcaPGPObjectFactory(compressedData.getDataStream());
obj = pgpObjectFactory.nextObject();
}
PGPLiteralData literalData = (PGPLiteralData) obj;
InputStream plainIn = literalData.getInputStream();
final byte[] buffer = new byte[org.apache.nifi.processors.standard.util.PGPUtil.BLOCK_SIZE];
int len;
while ((len = plainIn.read(buffer)) >= 0) {
out.write(buffer, 0, len);
}
if (encryptedData.isIntegrityProtected()) {
if (!encryptedData.verify()) {
throw new PGPException("Integrity check failed");
}
} else {
logger.warn("No message integrity check");
}
} catch (Exception e) {
throw new ProcessException(e.getMessage());
}
}
}
private static class OpenPGPEncryptCallback implements StreamCallback {
private String algorithm;
private String provider;
private char[] password;
private String filename;
private Integer cipher;
OpenPGPEncryptCallback(final String algorithm, final Integer cipher, final String provider, final char[] password, final String filename) {
this.algorithm = algorithm;
this.provider = provider;
this.password = password;
this.filename = filename;
this.cipher = cipher;
}
@Override
public void process(InputStream in, OutputStream out) throws IOException {
try {
PGPKeyEncryptionMethodGenerator encryptionMethodGenerator = new JcePBEKeyEncryptionMethodGenerator(password).setProvider(provider);
org.apache.nifi.processors.standard.util.PGPUtil.encrypt(in, out, algorithm, provider, cipher, filename, encryptionMethodGenerator);
} catch (Exception e) {
throw new ProcessException(e.getMessage());
}
}
}
}