Kafka Twitter streaming TwitterException error - twitter

I am trying the sample code on Kafka Twitter streaming from the following tutorial.
https://www.tutorialspoint.com/apache_kafka/apache_kafka_real_time_application.htm
Here is my code:
import java.util.Arrays;
import java.util.Properties;
import java.util.concurrent.LinkedBlockingQueue;
import twitter4j.*;
import twitter4j.conf.*;
import twitter4j.StatusListener;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
public class KafkaTwitterProducer {
public static void main(String[] args) throws Exception {
LinkedBlockingQueue<Status> queue = new LinkedBlockingQueue<Status>(1000);
String consumerKey = “XXXXXXXXXXXXXXXXX”; //args[0].toString();
String consumerSecret = "XXXXXXXXXXXXXXXXX"; //args[1].toString();
String accessToken = "XXXXXXXXXXXXXXXXX" ; //args[2].toString();
String accessTokenSecret = "XXXXXXXXXXXXXXXXX" ; //args[3].toString();
String topicName = "twittertest" ; //args[4].toString();
//String[] arguments = args.clone();
String[] keyWords = {“Hello”,”Hi”,”Welcome”}; //Arrays.copyOfRange(arguments, 5, arguments.length);
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true)
.setOAuthConsumerKey(consumerKey)
.setOAuthConsumerSecret(consumerSecret)
.setOAuthAccessToken(accessToken)
.setOAuthAccessTokenSecret(accessTokenSecret);
TwitterStream twitterStream = new TwitterStreamFactory(cb.build()).getInstance();
StatusListener listener = new StatusListener() {
#Override
public void onStatus(Status status) {
queue.offer(status);
System.out.println("#" + status.getUser().getScreenName()
+ " - " + status.getText());
// System.out.println("#" + status.getUser().getScreen-Name());
/*for(URLEntity urle : status.getURLEntities()) {
System.out.println(urle.getDisplayURL());
}*/
/*for(HashtagEntity hashtage : status.getHashtagEntities()) {
System.out.println(hashtage.getText());
}*/
}
#Override
public void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {
System.out.println("Got a status deletion notice id:"
+ statusDeletionNotice.getStatusId());
}
#Override
public void onTrackLimitationNotice(int numberOfLimitedStatuses) {
System.out.println("Got track limitation notice:" +
numberOfLimitedStatuses);
}
#Override
public void onScrubGeo(long userId, long upToStatusId) {
System.out.println("Got scrub_geo event userId:" + userId +
"upToStatusId:" + upToStatusId);
}
#Override
public void onStallWarning(StallWarning warning) {
// System.out.println("Got stall warning:" + warning);
}
#Override
public void onException(Exception ex) {
ex.printStackTrace();
}
};
twitterStream.addListener(listener);
FilterQuery query = new FilterQuery().track(keyWords);
twitterStream.filter(query);
Thread.sleep(5000);
//Add Kafka producer config settings
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("client.id", "SampleProducer");
props.put("auto.commit.interval.ms", "1000");
props.put("session.timeout.ms", "30000");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
//props.put("key.serializer",
// "org.apache.kafka.common.serialization.StringSerializer");
//props.put("value.serializer",
// "org.apache.kafka.common.serialization.StringSerializer");
Producer<String, String> producer = new KafkaProducer<String, String>(props);
int i = 0;
int j = 0;
while(i < 10) {
Status ret = queue.poll();
if (ret == null) {
Thread.sleep(100);
i++;
}else {
for(HashtagEntity hashtage : ret.getHashtagEntities()) {
System.out.println("Hashtag: " + hashtage.getText());
producer.send(new ProducerRecord<String, String>(
topicName, Integer.toString(j++), hashtage.getText()));
}
}
}
producer.close();
Thread.sleep(5000);
twitterStream.shutdown();
}
}
When I run this as Java application, I am getting the following error: (this is not compile/build error)
Read timed out
Relevant discussions can be found on the Internet at:
http://www.google.co.jp/search?q=1169356e or
http://www.google.co.jp/search?q=c04b39f0
TwitterException{exceptionCode=[1169356e-c04b39f0 c2863472-491bffd7], statusCode=-1, message=null, code=-1, retryAfter=-1, rateLimitStatus=null, version=4.0.4}
at twitter4j.HttpClientImpl.handleRequest(HttpClientImpl.java:179)
at twitter4j.HttpClientBase.request(HttpClientBase.java:57)
at twitter4j.HttpClientBase.post(HttpClientBase.java:86)
at twitter4j.TwitterStreamImpl.getFilterStream(TwitterStreamImpl.java:346)
at twitter4j.TwitterStreamImpl$8.getStream(TwitterStreamImpl.java:322)
at twitter4j.TwitterStreamImpl$TwitterStreamConsumer.run(TwitterStreamImpl.java:552)
Caused by: java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:170)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
at sun.security.ssl.InputRecord.read(InputRecord.java:503)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:930)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:105)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:704)
at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:647)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1536)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:338)
at twitter4j.HttpResponseImpl.<init>(HttpResponseImpl.java:35)
at twitter4j.HttpClientImpl.handleRequest(HttpClientImpl.java:143)
... 5 more
I am not sure what is the problem here. Could someone suggest me the solution or fix please?
Ok Update here: It is working now if key words are generic like String[] keyWords = {"USA","Basketball","Sports};
If I change this to my requirement with specific keywords like my company name, product name etc., for ex: String[] keyWords = {"XXX","YYY","ZZZ"}; then the java application is getting terminated. What could be the reason? How to fix it in this code? Please advise?

The Twitter4J source code shows that this exception is thrown because of Http connection time out.
I get similar exception by setting a low value for connection timeout.
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true)
.setOAuthConsumerKey(consumerKey)
.setOAuthConsumerSecret(consumerSecret)
.setOAuthAccessToken(accessToken)
.setOAuthAccessTokenSecret(accessTokenSecret)
.setHttpStreamingReadTimeout(10);
This is the stack trace I get.
TwitterException{exceptionCode=[1169356e-c3c3770e 1169356e-c3c376e4], statusCode=-1, message=null, code=-1, retryAfter=-1, rateLimitStatus=null, version=4.0.6}
at twitter4j.HttpClientImpl.handleRequest(HttpClientImpl.java:179)
at twitter4j.HttpClientBase.request(HttpClientBase.java:57)
at twitter4j.HttpClientBase.post(HttpClientBase.java:86)
at twitter4j.TwitterStreamImpl.getFilterStream(TwitterStreamImpl.java:347)
at twitter4j.TwitterStreamImpl$8.getStream(TwitterStreamImpl.java:323)
at twitter4j.TwitterStreamImpl$TwitterStreamConsumer.run(TwitterStreamImpl.java:554)
Caused by: java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
at sun.security.ssl.InputRecord.read(InputRecord.java:503)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:983)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1316)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1291)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
at twitter4j.HttpClientImpl.handleRequest(HttpClientImpl.java:137)
... 5 more
For your example, please try setting a higher value for HttpStreamingReadTimeout. The default value in the code is 40 seconds. Try setting it to 120,000 (milliseconds) or higher. That should work.

Related

401:Authentication credentials were invalid - Invalid or expired token. code - 89

This is the code and I am recieving the error 401: Authentication Error
public class Server {
// initialize socket and input stream
private Socket socket = null;
private ServerSocket server = null;
private DataInputStream in = null;
public void tweet() throws TwitterException {
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDaemonEnabled(true).setOAuthConsumerKey("......")
.setOAuthConsumerSecret("......")
.setOAuthAccessToken("......")
.setOAuthAccessTokenSecret(".....");
TwitterFactory tf = new TwitterFactory();
twitter4j.Twitter twitter = tf.getInstance();
List status = twitter.getHomeTimeline();
for (Status st : status) {
System.out.println(st.getUser().getName() + "---- Tweets----" + st.getText());
}
}
// constructor with port
public Server(int port) throws TwitterException {
// starts server and waits for a connection
try {
server = new ServerSocket(port);
System.out.println("Server started");
System.out.println("Waiting for a client ...");
socket = server.accept();
System.out.println("Client accepted");
// takes input from the client socket
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
String line = "";
// reads message from client until "Over" is sent
while (!line.equals("Over")) {
try {
line = in.readUTF();
System.out.println(line);
if (line.equalsIgnoreCase("Data")) {
tweet();
}
} catch (IOException i) {
System.out.println(i);
}
}
System.out.println("Closing connection");
// close connection
socket.close();
in.close();
} catch (IOException i) {
System.out.println(i);
}
}
public static void main(String args[]) throws TwitterException {
Server server = new Server(5000);
}
}
Please make sure that the tokens are valid.
Then, you could try enabling system proxies like so:
System.setProperty("java.net.useSystemProxies", "true");

Connection error while connecting wamp server with netbeans8.1

I can't get any output from this program. Do you know why? I am using NetBeans 8.1 and wamp server. I design database named assignments online. Can you also suggest if I am using true drivers?
package managmentSystem;
import javax.swing.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.SQLException;
/**
*
* #author DiyaBangesh
*/
public class ManagmentSystem {
//PreparedStatement pst = null;
//Statement st= null;
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
try{
ResultSet rs;
Connection conn;
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost/assignment","root","");
JOptionPane.showMessageDialog(null,"Connection to database is established");
//return conn;
Statement st = conn.createStatement();
String sql ="SELECT * FROM userdetails";
rs = st.executeQuery(sql);
while(rs.next()){
String nam = rs.getString("name");
String uid = rs.getString("user_id");
String pwd = rs.getString("password");
String eid = rs.getString("email_id");
String con = rs.getString("contact");
String ut = rs.getString("usertype");
System.out.println(nam + " " + uid + " " + pwd + " "+ eid + " " + con + " " + ut );
}
conn.close();
}
catch (Exception sqlEx){
System.out.println(sqlEx);
}
}
}
mysql-connector-java-bin.jar is the one needeed and you have already used it. Make sure that you used correct database name & correct password. Replace 'yourpassword' with your database password. And make sure that server is running.
Follow as below.
public class ManagmentSystem {
Connection con;
Statement s;
PreparedStatement ps;
ResultSet rs;
ManagmentSystem()
{
try
{ Class.forName("com.mysql.jdbc.Driver");
con=DriverManager.getConnection("jdbc:mysql://localhost/assignment?user=root&password=yourpassword");
}
catch(SQLException s)
{
System.out.println("Error in DB Connection");
s.printStackTrace();
}
catch(ClassNotFoundException c)
{
System.out.println("Driver not Found");
}
}
}

Smack 4.1 connection to gtalk

I updated to smack 4.1, but now cannot connect to gtalk. This is my code I am using:
XMPPTCPConnectionConfiguration.Builder configBuilder = XMPPTCPConnectionConfiguration.builder();
configBuilder.setHost("talk.google.com");
configBuilder.setPort(5222);
configBuilder.setServiceName("gmail.com");
configBuilder.setSecurityMode(SecurityMode.required);
configBuilder.setDebuggerEnabled(true);
configBuilder.setSendPresence(true);
configBuilder.setUsernameAndPassword(pref.getString(Constants.KEY_USER, ""), pref.getString(Constants.KEY_TOKEN, ""));
SASLAuthentication.blacklistSASLMechanism(SASLMechanism.PLAIN);
AbstractXMPPConnection connection = new XMPPTCPConnection(configBuilder.build());
try
{
connection.connect();
connection.login();//.login(pref.getString(Constants.KEY_USER, ""), pref.getString(Constants.KEY_TOKEN, ""));
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
This is the error i get:
D/SMACK(12807): SENT (3): <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='X-OAUTH2'>REMOVED_THIS=</auth>
D/SMACK(12807): RECV (3): <failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><incorrect-encoding/></failure>
The problem is the line in SASLXOauth2Mechanism:
Base64.encode(toBytes('\u0000' + authenticationId + '\u0000' + password));
As a quick test replace in your code
AbstractXMPPConnection connection = new XMPPTCPConnection(configBuilder.build());
with this
AbstractXMPPConnection connection = new XMPPTCPConnection(configBuilder.build())
{
#Override
public void send(PlainStreamElement auth) throws NotConnectedException
{
if(auth instanceof AuthMechanism)
{
final XmlStringBuilder xml = new XmlStringBuilder();
xml.halfOpenElement(AuthMechanism.ELEMENT)
.xmlnsAttribute(SaslStreamElements.NAMESPACE)
.attribute("mechanism", "X-OAUTH2")
.attribute("auth:service", "oauth2")
.attribute("xmlns:auth", "http://www.google.com/talk/protocol/auth")
.rightAngleBracket()
.optAppend(Base64.encodeToString(StringUtils.toBytes("\0" + authenticationId + "\0" + password)))
.closeElement(AuthMechanism.ELEMENT);
super.send(new PlainStreamElement()
{
#Override
public String toXML()
{
return xml.toString();
}
});
}
else super.send(auth);
}
};
I didn't test it, but I hope it works. authenticationId and token are your credentials.

javacv error (Has setFormat() been called?)_

hi i'm making program that record video with audio by javacv but i got some error. any suggestion?
lib version : jdk 1.8 javacv 0.8 opencv 2.4.9
Exception in thread "main" org.bytedeco.javacv.FrameGrabber$Exception: avformat_open_input() error -2: Could not open input "output.mp4". (Has setFormat() been called?)
at org.bytedeco.javacv.FFmpegFrameGrabber.startUnsafe(FFmpegFrameGrabber.java:362)
at org.bytedeco.javacv.FFmpegFrameGrabber.start(FFmpegFrameGrabber.java:312)
at com.unomic.securobot.javacv.main(javacv.java:14)
my code
FFmpegFrameGrabber grabber1 = new FFmpegFrameGrabber("output.mp4");
FFmpegFrameGrabber grabber2 = new FFmpegFrameGrabber("test.mp3");
grabber1.setFormat("mp4");
grabber1.start();
grabber2.start();
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder("outputFinal.mp4",
grabber1.getImageWidth(), grabber1.getImageHeight(),
grabber2.getAudioChannels());
recorder.setFrameRate(grabber1.getFrameRate());
recorder.setSampleFormat(grabber2.getSampleFormat());
recorder.setSampleRate(grabber2.getSampleRate());
recorder.start();
Frame frame1;
Frame frame2 = null;
while ((frame1 = grabber1.grabFrame()) != null ||
(frame2 = grabber2.grabFrame()) != null) {
recorder.record(frame1);
recorder.record(frame2);
}
recorder.stop();
grabber1.stop();
grabber2.stop();
}
I was trying to get thumbnails from a videos using the framegrabber. I was getting the same error but then I just tried giving the full path of the files and voila it worked. Previously, I was using a relative path which was not working. When I gave the full path it started working.
package com.tape.controller;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.imageio.ImageIO;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.OpenCVFrameGrabber;
public class VideoThumbTaker {
protected String ffmpegApp;
public VideoThumbTaker(String ffmpegApp)
{
this.ffmpegApp = ffmpegApp;
}
public void getThumb(String videoFilename, String thumbFilename, int width, int height,int hour, int min, float sec)
throws IOException, InterruptedException
{
ProcessBuilder processBuilder = new ProcessBuilder(ffmpegApp, "-y", "-i", videoFilename, "-vframes", "1",
"-ss", hour + ":" + min + ":" + sec, "-f", "mjpeg", "-s", width + "*" + height, "-an", thumbFilename);
Process process = processBuilder.start();
InputStream stderr = process.getErrorStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null);
process.waitFor();
}
public static void main(String[] args) throws Exception, IOException
{
//Both case work
FFmpegFrameGrabber g = new FFmpegFrameGrabber("C:\\JavaEE\\New Project\\tape\\src\\main\\webapp\\web-resources\\videos\\vid.mp4");
g.setFormat("mp4");
g.start();
for (int i = 0 ; i < 50 ; i++) {
ImageIO.write(g.grab().getBufferedImage(), "png", new File("C:\\JavaEE\\New Project\\tape\\src\\main\\webapp\\web-resources\\thumbnails\\video-frame-" + System.currentTimeMillis() + ".png"));
}
g.stop();
}
}

BouncyCastle PGP Encryption / Decryption: Caused by: java.io.EOFException: premature end of stream in PartialInputStream

When attempting to encrypt then decrypt a file I run into the following exception:
com.example.common.crypto.CipherException: org.bouncycastle.openpgp.PGPException: Exception starting decryption
at com.example.common.crypto.PGPFileCipher.decrypt(PGPFileCipher.java:151)
at com.example.common.crypto.PGPFileCipherTest.testEncryptDecryptFile(PGPFileCipherTest.java:41)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:43)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:345)
at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1009)
Caused by: org.bouncycastle.openpgp.PGPException: Exception starting decryption
at org.bouncycastle.openpgp.PGPPublicKeyEncryptedData.getDataStream(Unknown Source)
at org.bouncycastle.openpgp.PGPPublicKeyEncryptedData.getDataStream(Unknown Source)
at com.example.common.crypto.PGPFileCipher.decrypt(PGPFileCipher.java:128)
... 28 more
Caused by: java.io.EOFException: premature end of stream in PartialInputStream
at org.bouncycastle.bcpg.BCPGInputStream$PartialInputStream.read(Unknown Source)
at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
at java.io.InputStream.read(InputStream.java:82)
at javax.crypto.CipherInputStream.a(DashoA13*..)
at javax.crypto.CipherInputStream.read(DashoA13*..)
at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
... 31 more
My PGPFileCipher class is:
package com.example.common.crypto;
public class PGPFileCipher implements FileCipher {
private static final Logger logger = LoggerFactory.getLogger(PGPFileCipher.class);
public File encryptFile(File inputFile, String encryptedFilePath, String publicKeyPath) throws CipherException {
FileInputStream publicKeyStream = null;
FileOutputStream encryptedFileOutputStream = null;
try {
publicKeyStream = new FileInputStream(new File(publicKeyPath));
File encryptedFile = new File(encryptedFilePath);
encryptedFileOutputStream = new FileOutputStream(encryptedFile);
encryptedFileOutputStream.write(encrypt(getBytesFromFile(inputFile), publicKeyStream, ""));
encryptedFileOutputStream.flush();
return encryptedFile;
} catch (Exception e) {
throw new CipherException(e);
} finally {
IOUtils.closeQuietly(encryptedFileOutputStream);
IOUtils.closeQuietly(publicKeyStream);
}
}
private PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection pgpSec, long keyID, char[] pass) throws CipherException {
try {
PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
if (pgpSecKey == null) {
return null;
}
return pgpSecKey.extractPrivateKey(pass, new BouncyCastleProvider());
} catch (Exception e) {
throw new CipherException(e);
}
}
/**
* decrypt the passed in message stream
*
* #param encrypted
* The message to be decrypted.
* #param keyIn
* InputStream of the key
*
* #return Clear text as a byte array. I18N considerations are not handled
* by this routine
* #exception CipherException
*/
public byte[] decrypt(byte[] encrypted, InputStream keyIn, char[] password) throws CipherException {
ByteArrayOutputStream out = null;
InputStream clear = null;
InputStream in = null;
InputStream unc = null;
try {
in = new ByteArrayInputStream(encrypted);
in = PGPUtil.getDecoderStream(in);
PGPObjectFactory pgpF = new PGPObjectFactory(in);
PGPEncryptedDataList enc = null;
Object o = pgpF.nextObject();
//
// the first object might be a PGP marker packet.
//
if (o instanceof PGPEncryptedDataList) {
enc = (PGPEncryptedDataList) o;
} else {
enc = (PGPEncryptedDataList) pgpF.nextObject();
}
//
// find the secret key
//
Iterator it = enc.getEncryptedDataObjects();
PGPPrivateKey sKey = null;
PGPPublicKeyEncryptedData pbe = null;
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(keyIn));
while (sKey == null && it.hasNext()) {
pbe = (PGPPublicKeyEncryptedData) it.next();
sKey = findSecretKey(pgpSec, pbe.getKeyID(), password);
}
if (sKey == null) {
throw new IllegalArgumentException(
"secret key for message not found.");
}
clear = pbe.getDataStream(sKey, new BouncyCastleProvider());
PGPObjectFactory pgpFact = new PGPObjectFactory(clear);
PGPCompressedData cData = (PGPCompressedData) pgpFact.nextObject();
pgpFact = new PGPObjectFactory(cData.getDataStream());
PGPLiteralData ld = (PGPLiteralData) pgpFact.nextObject();
unc = ld.getInputStream();
out = new ByteArrayOutputStream();
int ch;
while ((ch = unc.read()) >= 0) {
out.write(ch);
}
out.flush();
byte[] returnBytes = out.toByteArray();
return returnBytes;
} catch (Exception e) {
e.printStackTrace();
throw new CipherException(e);
} finally {
IOUtils.closeQuietly(out);
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(clear);
IOUtils.closeQuietly(unc);
}
}
/**
* Simple PGP encryptor between byte[].
*
* #param clearData
* The test to be encrypted
* #param keyInputStream
* Input stream of the key
* #param fileName
* File name. This is used in the Literal Data Packet (tag 11)
* which is really inly important if the data is to be related to
* a file to be recovered later. Because this routine does not
* know the source of the information, the caller can set
* something here for file name use that will be carried. If this
* routine is being used to encrypt SOAP MIME bodies, for
* example, use the file name from the MIME type, if applicable.
* Or anything else appropriate.
*
* #return encrypted data.
* #exception CipherException
*/
public byte[] encrypt(byte[] clearData, InputStream keyInputStream, String fileName)
throws CipherException {
OutputStream out = null;
OutputStream cOut = null;
PGPCompressedDataGenerator comData = null;
PGPLiteralDataGenerator lData = null;
ByteArrayOutputStream encOut = null;
ByteArrayOutputStream bOut = null;
OutputStream cos = null;
OutputStream pOut = null;
try {
PGPPublicKey encKey = readPublicKey(keyInputStream);
if (fileName == null || fileName.trim().length() < 1) {
fileName = PGPLiteralData.CONSOLE;
}
encOut = new ByteArrayOutputStream();
out = encOut;
bOut = new ByteArrayOutputStream();
comData = new PGPCompressedDataGenerator(
PGPCompressedDataGenerator.ZIP);
cos = comData.open(bOut); // open it with the final
// destination
lData = new PGPLiteralDataGenerator();
// we want to generate compressed data. This might be a user option
// later,
// in which case we would pass in bOut.
pOut = lData.open(cos, // the compressed output stream
PGPLiteralData.BINARY, fileName, // "filename" to store
clearData.length, // length of clear data
new Date() // current time
);
pOut.write(clearData);
pOut.flush();
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(
PGPEncryptedData.CAST5, false, new SecureRandom(),
new BouncyCastleProvider());
cPk.addMethod(encKey);
byte[] bytes = bOut.toByteArray();
cOut = cPk.open(out, bytes.length);
cOut.write(bytes); // obtain the actual bytes from the compressed stream
cOut.flush();
encOut.flush();
return encOut.toByteArray();
} catch (Exception e) {
throw new CipherException(e);
} finally {
IOUtils.closeQuietly(out);
IOUtils.closeQuietly(cOut);
IOUtils.closeQuietly(encOut);
IOUtils.closeQuietly(bOut);
IOUtils.closeQuietly(cos);
IOUtils.closeQuietly(pOut);
try {
if (lData != null) {
lData.close();
}
if (comData != null) {
comData.close();
}
} catch (IOException ignored) {}
}
}
private PGPPublicKey readPublicKey(InputStream in)
throws CipherException {
try {
in = PGPUtil.getDecoderStream(in);
PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(in);
//
// 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.
//
//
// iterate through the key rings.
//
Iterator rIt = pgpPub.getKeyRings();
while (rIt.hasNext()) {
PGPPublicKeyRing kRing = (PGPPublicKeyRing) rIt.next();
Iterator kIt = kRing.getPublicKeys();
while (kIt.hasNext()) {
PGPPublicKey k = (PGPPublicKey) kIt.next();
if (k.isEncryptionKey()) {
return k;
}
}
}
throw new IllegalArgumentException("Can't find encryption key in key ring.");
} catch (Exception e) {
throw new CipherException(e);
}
}
private byte[] getBytesFromFile(File file) throws CipherException {
InputStream is = null;
try {
is = new FileInputStream(file);
// Get the size of the file
long length = file.length();
if (length > Integer.MAX_VALUE) {
throw new CipherException("File is too large: " + file.getName());
}
return IOUtils.toByteArray(is);
} catch (IOException e) {
throw new CipherException(e);
} finally {
IOUtils.closeQuietly(is);
}
}
}
And the test I'm attempting to run is:
package com.example.common.crypto;
public class PGPFileCipherTest {
private static final Logger logger = LoggerFactory.getLogger(PGPFileCipherTest.class);
#Rule
public TemporaryFolder folder = new TemporaryFolder();
#Test
public void testEncryptDecryptFile() throws IOException, CipherException {
FileOutputStream decryptedFileOutputStream = null;
InputStream privateKeyStream = null;
try {
PGPFileCipher fileCipher = new PGPFileCipher();
Resource inputFile = new ClassPathResource("testInputFile.txt");
Resource publicKey = new ClassPathResource("PUBLIC.asc");
Resource privateKey = new ClassPathResource("PRIVATE.asc");
// Encrypt file
File encryptedFile = fileCipher.encryptFile(inputFile.getFile(), folder.newFile("testInputFile_enc.txt").getPath(), publicKey.getFile().getPath());
// Now decrypt the file
File decryptedFile = folder.newFile("testInputFile_dec.txt");
decryptedFileOutputStream = new FileOutputStream(decryptedFile);
privateKeyStream = new FileInputStream(privateKey.getFile());
decryptedFileOutputStream.write(fileCipher.decrypt(FileUtils.readFileToByteArray(encryptedFile), privateKeyStream, "".toCharArray()));
decryptedFileOutputStream.flush();
} finally {
IOUtils.closeQuietly(decryptedFileOutputStream);
IOUtils.closeQuietly(privateKeyStream);
}
}
}
Unfortunately I'm not all that familiar with the BouncyCastle and it would seem as if a stream is not properly being closed / flushed but I can't seem to track it down. This is a modified version of one of the BouncyCastle examples FYI. Thanks in advance for your help.
check the jdk version.. we were facing issue running encryption and both in jdk1.5. but jdk 1.6 it work fine. and yes the bc pro jars "bcpg-jdk16" and" bcprov-ext-jdk16" verison should be 1.46
Be careful when using new BouncyCastleProvider() as it will result in the provider being registered in JceSecurity each time you instantiate it. This will cause a memory leak.
Consider doing something like this instead
private Provider getProvider() {
Provider provider = Security.getProvider("BC");
if (provider==null){
provider = new BouncyCastleProvider();
Security.addProvider(provider);
}
return provider;
}

Resources