I am doing a project where i need to sign a pdf using a usb based digital signature. I have tried the following code locally and able to sign the pdf. my problem is weather the following code will work in a client server based senerio.
My code is:
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfSignatureAppearance;
import com.lowagie.text.pdf.PdfStamper;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CRL;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import javax.servlet.RequestDispatcher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.security.mscapi.SunMSCAPI;
public class Testing {
private static boolean resFlag;
public static void main (String args[])
{
try {
BouncyCastleProvider providerBC = new BouncyCastleProvider();
Security.addProvider(providerBC);
SunMSCAPI providerMSCAPI = new SunMSCAPI();
Security.addProvider(providerMSCAPI);
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null);
String alias = (String)ks.aliases().nextElement();
PrivateKey pk = (PrivateKey)ks.getKey(alias, null);
Certificate[] chain = ks.getCertificateChain(alias);
// //String e = request.getParameter("digiFile");
// KeyStore ks = KeyStore.getInstance("pkcs12");
// String f10 = CommonUtil.getRealPath();
// String str8 = f10 + "/DigiFiles/";
// //System.out.println("str8-->>>>>>>>" + str8 + e);
// ks.load(new FileInputStream("F:/DigiFiles/Anurag Goel.pfx"), "123".toCharArray());
//
//
// System.out.println("The actual path is " + str8);
// String alias = (String)ks.aliases().nextElement();
// PrivateKey key = (PrivateKey)ks.getKey(alias, "123".toCharArray());
// Certificate[] chain = ks.getCertificateChain(alias);
PdfReader reader = new PdfReader("F:/test.pdf");
FileOutputStream os = new FileOutputStream("F:/SampleOutPut61.pdf");
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0',null,true);
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setCrypto(pk, chain, (CRL[])null, PdfSignatureAppearance.VERISIGN_SIGNED);
appearance.setReason("elicense project");
appearance.setLocation("Assam");
appearance.setVisibleSignature("hi");
stamper.close();
} catch (KeyStoreException var27) {
var27.printStackTrace();
resFlag = false;
} catch (NoSuchAlgorithmException var28) {
var28.printStackTrace();
resFlag = false;
} catch (CertificateException var29) {
var29.printStackTrace();
resFlag = false;
} catch (FileNotFoundException var30) {
var30.printStackTrace();
resFlag = false;
} catch (IOException var31) {
var31.printStackTrace();
resFlag = false;
} catch (UnrecoverableKeyException var32) {
var32.printStackTrace();
resFlag = false;
} catch (DocumentException var33) {
var33.printStackTrace();
resFlag = false;
} catch (Exception var34) {
var34.printStackTrace();
resFlag = false;
} finally {
RequestDispatcher rd;
}
}
}
Please give me suggestion . thanks all
You are using the wrong iText version, hence you are creating signatures that are not future proof (please read this book to find out what's wrong with your code).
You are depending on the fact that the operating system is Windows. Is your server also a Windows server? Your code won't work if it's a Linux server. Check with your hosting provider and also ask your hosting provider if it is allowed for you to have a USB token on that server (if it's not a dedicated server, chances are they are going to refuse that).
You are using Windows-MY which means that you delegate the authentication to the operating system. If the USB needs a passphrase (they usually do), Windows will open up a dialog box for you to fill out that passphrase. If you deploy this on a server: will you have somebody sitting next to that server to fill out that password every time somebody requests a signature?
USB tokens are designed for people to sign a document manually. They usually have specific limitations. For instance: normally, you can not apply more than 1 signature per second. This is usually insufficient in a web context. In a web context, you are expected to use install a Hardware Security Module (HSM) on your server.
While your code may work on a server in theory, I see a lot of reasons why it's not a wise decision to use the code that works on a standalone machine in a client/server environment. There are too many practical issues (such as authentication, speed, wrong version of iText,...) that can make your project go wrong. I would answer "no" to your question whether that code will work in a client/server scenario.
Update:
In your comments to my answer, you indicate that your server is a Linux server. It should be obvious that using "Windows-MY" will never work on a Linux server. You'll have to use PKCS#11 instead of Windows-MY to talk to the hardware device on which your token is stored. This is a code sample that works on a Luna SA from SafeNet. As you can see, it uses PKCS#11:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.security.pkcs11.SunPKCS11;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.log.LoggerFactory;
import com.itextpdf.text.log.SysoLogger;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.CertificateUtil;
import com.itextpdf.text.pdf.security.CrlClient;
import com.itextpdf.text.pdf.security.CrlClientOnline;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.OcspClient;
import com.itextpdf.text.pdf.security.OcspClientBouncyCastle;
import com.itextpdf.text.pdf.security.PrivateKeySignature;
import com.itextpdf.text.pdf.security.TSAClient;
import com.itextpdf.text.pdf.security.TSAClientBouncyCastle;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
public class C4_01_SignWithPKCS11HSM {
public static final String SRC = "/home/itext/hello.pdf";
public static final String PROPS = "/home/itext/key.properties";
public static final String DEST = "/home/itext/hello_hsm.pdf";
public void sign(String src, String dest,
Certificate[] chain, PrivateKey pk,
String digestAlgorithm, String provider, CryptoStandard subfilter,
String reason, String location,
Collection<CrlClient> crlList,
OcspClient ocspClient,
TSAClient tsaClient,
int estimatedSize)
throws GeneralSecurityException, IOException, DocumentException {
// Creating the reader and the stamper
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
// Creating the appearance
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
// Creating the signature
ExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
ExternalDigest digest = new BouncyCastleDigest();
MakeSignature.signDetached(appearance, digest, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
}
public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
LoggerFactory.getInstance().setLogger(new SysoLogger());
Properties properties = new Properties();
properties.load(new FileInputStream(PROPS));
char[] pass = properties.getProperty("PASSWORD").toCharArray();
String pkcs11cfg = properties.getProperty("PKCS11CFG");
BouncyCastleProvider providerBC = new BouncyCastleProvider();
Security.addProvider(providerBC);
FileInputStream fis = new FileInputStream(pkcs11cfg);
Provider providerPKCS11 = new SunPKCS11(fis);
Security.addProvider(providerPKCS11);
KeyStore ks = KeyStore.getInstance("PKCS11");
ks.load(null, pass);
String alias = (String)ks.aliases().nextElement();
PrivateKey pk = (PrivateKey)ks.getKey(alias, pass);
Certificate[] chain = ks.getCertificateChain(alias);
OcspClient ocspClient = new OcspClientBouncyCastle();
TSAClient tsaClient = null;
for (int i = 0; i < chain.length; i++) {
X509Certificate cert = (X509Certificate)chain[i];
String tsaUrl = CertificateUtil.getTSAURL(cert);
if (tsaUrl != null) {
tsaClient = new TSAClientBouncyCastle(tsaUrl);
break;
}
}
List<CrlClient> crlList = new ArrayList<CrlClient>();
crlList.add(new CrlClientOnline(chain));
C4_01_SignWithPKCS11HSM app = new C4_01_SignWithPKCS11HSM();
app.sign(SRC, DEST, chain, pk, DigestAlgorithms.SHA256, providerPKCS11.getName(), CryptoStandard.CMS,
"HSM test", "Ghent", crlList, ocspClient, tsaClient, 0);
}
}
The content of the config file that is used looks like this:
Name = Luna
library = /usr/lunasa/lib/libCryptoki2_64.so
slot = 1
Note that the so may be in another directory in your case, and your certificate may be in another slot. I also use a properties file to store the password for the certificate. Obviously I won't share my password ;-)
This example was tested on a server owned by GlobalSign using a GlobalSign certificate.
Related
I've used the Apache Directory API to load in user data from an Active Directory. It's similar to the example code by 'oers' found in this stackoverflow question: Apache Directory LDAP - Paged searches
Some differences I have are:
I'm coding it with in Nashorn (Javascript running in Java)
I'm using the PagedResultsImpl class instead of PagedResultsDecorator
I'm saving the cookie as a string between calls by using a Base64 encoding of the byte[] cookie.
I'm using Apache Directory API with the following maven import:
<dependency>
<groupId>org.apache.directory.api</groupId>
<artifactId>api-all</artifactId>
<version>1.0.3</version>
</dependency>
Here's some of the important bits:
...
var pageCursor = ""; /** or some Base64 encoded byte[] cookie if I'm trying to start from where i left off last time. */
...
pagedSearchControl = new PagedResultsImpl();
pagedSearchControl.setSize(pageSize);
pagedSearchControl.setCookie(Base64.getEncoder().encodeToString(pageCursor.getBytes()));
...
var searchRequest = new SearchRequestImpl();
...
searchRequest.addControl(pagedSearchControl);
...
var cursor = new EntryCursorImpl(connection.search(searchRequest));
...
pagingResults = cursor.getSearchResultDone().getControl(PagedResults.OID);
if (pagingResults != null){
nextPageCursor = Base64.getEncoder().encodeToString(pagingResults.getCookie());
}
When run against Active Directory I can page all the users just fine. When I change my connection to point to an OpenLDAP directory I am able to search for users just fine, EXCEPT for when I set the page control cookie using a non-null value for pageCursor (one I got from base 64 encoding a previous call's cookie). Basically, I can't get the paged results from OpenLDAP. I get no results and there are no exceptions.
What is needed in order to get OpenLDAP to page properly?
Am I missing something with setting up page control in Apache Directory?
Is paging a setting in OpenLDAP I need to turn on?
[UPDATE] I Ported my code outside of Nashorn to just Java and now I can see it is because the paging cookie appears to be only valid within the same connection for OpenLDAP, but for Active Directory it can be different connections. You can see yourself with the code below.:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Base64;
import java.util.Iterator;
import java.util.Properties;
import java.util.StringJoiner;
import javax.naming.ConfigurationException;
//imports for json
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
//imports for LDAP
import org.apache.directory.api.ldap.model.cursor.EntryCursor;
import org.apache.directory.api.ldap.model.entry.Attribute;
import org.apache.directory.api.ldap.model.entry.DefaultEntry;
import org.apache.directory.api.ldap.model.entry.Entry;
import org.apache.directory.api.ldap.model.entry.Value;
import org.apache.directory.api.ldap.model.exception.LdapException;
import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
import org.apache.directory.api.ldap.model.message.Control;
import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
import org.apache.directory.api.ldap.model.message.SearchRequest;
import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
import org.apache.directory.api.ldap.model.message.SearchResultDone;
import org.apache.directory.api.ldap.model.message.SearchScope;
import org.apache.directory.api.ldap.model.message.controls.AbstractControl;
import org.apache.directory.api.ldap.model.message.controls.PagedResults;
import org.apache.directory.api.ldap.model.message.controls.PagedResultsImpl;
import org.apache.directory.api.ldap.model.name.Dn;
import org.apache.directory.ldap.client.api.EntryCursorImpl;
import org.apache.directory.ldap.client.api.LdapConnection;
import org.apache.directory.ldap.client.api.LdapNetworkConnection;
//Nashorn
import delight.nashornsandbox.NashornSandbox;
import delight.nashornsandbox.NashornSandboxes;
public class Executor
{
public static void main( String[] args )
{
pagingTest();
}
private static void pagingTest(){
//ENTER YOUR CREDENTIALS
String server = "";
int port = 0;
String loginId = "";
String loginPassword = "";
String usersBaseDN = "";
String userObjectClass = "";
String base64cookie = null;
LdapNetworkConnection connection = new LdapNetworkConnection(server, port, true );
try{
connection.setTimeOut( 300 );
connection.bind(loginId,loginPassword);
/*First Pass*/
PagedResultsImpl pagedSearchControl = new PagedResultsImpl();
pagedSearchControl.setSize(5);
pagedSearchControl.setCookie(Base64.getDecoder().decode(""));
SearchRequestImpl searchRequest = new SearchRequestImpl();
searchRequest.setBase(new Dn(usersBaseDN));
searchRequest.setFilter("(objectClass=" + userObjectClass +")");
searchRequest.setScope(SearchScope.SUBTREE);
searchRequest.addAttributes("*");
searchRequest.addControl(pagedSearchControl);
EntryCursorImpl cursor = new EntryCursorImpl(connection.search(searchRequest));
while (cursor.next()) {
System.out.println("First Pass User: " + cursor.get().getDn());
}
PagedResults pagingResults = (PagedResults)cursor.getSearchResultDone().getControl(PagedResults.OID);
if (pagingResults != null){
byte[] cookie = pagingResults.getCookie();
if (cookie != null && cookie.length > 0) {
base64cookie = Base64.getEncoder().encodeToString(cookie);
System.out.println("First Pass Cookie: " + cookie);
}
}
cursor.close();
}catch(Exception e){
System.out.println(e);
}
finally {
//COMMENT THIS CODE BLOCK TO SEE IT WORKING (IT WILL USE THE SAME CONNECTION)
try {
connection.unBind();
connection.close();
} catch (Exception e) {
System.out.println(e);
}
connection = new LdapNetworkConnection( server, port, true );
}
try{
connection.setTimeOut( 300 );
connection.bind(loginId,loginPassword);
/*Second Pass*/
PagedResultsImpl secondPagedSearchControl = new PagedResultsImpl();
secondPagedSearchControl.setSize(5);
secondPagedSearchControl.setCookie(Base64.getDecoder().decode(base64cookie));
SearchRequestImpl secondSearchRequest = new SearchRequestImpl();
secondSearchRequest.setBase(new Dn(usersBaseDN));
secondSearchRequest.setFilter("(objectClass=" + userObjectClass +")");
secondSearchRequest.setScope(SearchScope.SUBTREE);
secondSearchRequest.addAttributes("*");
secondSearchRequest.addControl(secondPagedSearchControl);
EntryCursorImpl secondCursor = new EntryCursorImpl(connection.search(secondSearchRequest));
while (secondCursor.next()) {
System.out.println("Second Pass User: " + secondCursor.get().getDn());
}
secondCursor.close();
}catch(Exception e){
System.out.println(e);
}
finally {
try {
connection.unBind();
connection.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
}
So I guess my new question is:
Is anybody aware of a workaround to allow OpenLDAP to accept
pagination cookies from previous connections?
I have been using the rally javatoolkit for a while to add testcases, test results etc without any error. But all of a sudden it started throwing error as
" javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated" . I have referred the pages "rally rest api java toolkit sslpeerunverifiedexception : peer not authenticated" , rally rest api java toolkit sslpeerunverifiedexception : peer not authenticated but they didn't help me. Can someone help me with what I am doing wrong. Also If i need to download a certificate please help me for windows system. Thanks in advance. my code is as below:
import com.rallydev.rest.RallyRestApi;
import com.rallydev.rest.client.HttpClient;
import com.rallydev.rest.request.GetRequest;
import com.rallydev.rest.response.GetResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.scheme.Scheme;
public class ConnnectionTestWithHTTPClient {
public static void main(String[] args) throws URISyntaxException, IOException {
String host = "https://rally1.rallydev.com";
String apiKey = "_abc123";
String applicationName = "Connnection Test With HTTPClient";
RallyRestApi restApi = new RallyRestApi(new URI(host),apiKey);
restApi.setApplicationName(applicationName);
//restApi.setProxy(new URI("http://myproxy.mycompany.com"), "MyProxyUsername", "MyProxyPassword"); //SET PROXY SETTINS HERE
HttpClient client = restApi.getClient();
try {
SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy() {
public boolean isTrusted(X509Certificate[] certificate, String authType)
throws CertificateException {
//trust all certs
return true;
}
}, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
client.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, sf));
String workspaceRef = "/workspace/12345"; //USE VALID WORKSPACE OID
GetRequest getRequest = new GetRequest(workspaceRef);
GetResponse getResponse = restApi.get(getRequest);
System.out.println(getResponse.getObject());
} catch (Exception e) {
System.out.println(e);
} finally {
restApi.close();
}
}
}
Also adding to the issue, i found a different error when I changed the port from 443 to 8443. i get "java.io.IOException: HTTP/1.1 522 Origin Connection Time-out" when i use 8443.
For some reason when I uncomment the line //restApi.setProxy(new URI("http://myproxy.mycompany.com"), "MyProxyUsername", "MyProxyPassword"); with correct inputs, the error goes off.
For all those who need the inputs, please put in the following:
restApi.setProxy(new URI("http://rally1.rallydev.com"), "xyz#abc.com", "rallypassword");
so the working code is as below:
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import com.rallydev.rest.RallyRestApi;
import com.rallydev.rest.client.HttpClient;
import com.rallydev.rest.request.GetRequest;
import com.rallydev.rest.response.GetResponse;
public class ConnnectionTestWithHTTPClient {
public static void main(String[] args) throws URISyntaxException, IOException {
String host = "https://rally1.rallydev.com";
String apiKey = "_apikey";
String applicationName = "Connnection Test With HTTPClient";
RallyRestApi restApi = new RallyRestApi(new URI(host),apiKey);
restApi.setApplicationName(applicationName);
restApi.setProxy(new URI("http://rally1.rallydev.com"), "abc#abc.com", "rallypassword"); //YOUR PROXY SETTINGS HERE
HttpClient client = restApi.getClient();
try {
SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy() {
public boolean isTrusted(X509Certificate[] certificate, String authType)
throws CertificateException {
//trust all certs
return true;
}
}, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
client.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, sf));
String workspaceRef = "/workspace/1234";
GetRequest getRequest = new GetRequest(workspaceRef);
GetResponse getResponse = restApi.get(getRequest);
System.out.println(getResponse.getObject());
} catch (Exception e) {
System.out.println(e);
} finally {
restApi.close();
}
}
}
I had written a java program which uses client id and client secret for authentication. When i run my program it gives an url and when i go to that url it gives me access token. How can i programatically get the access token without using a browser?
My code:
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.admin.directory.Directory;
import com.google.api.services.admin.directory.DirectoryScopes;
import com.google.api.services.admin.directory.model.User;
import com.google.api.services.admin.directory.model.Users;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
public class DirectoryCommandLine {
private static String CLIENT_ID = "YOUR_CLIENT_ID";
private static String CLIENT_SECRET = "YOUR_CLIENT_SECRET";
private static String REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";
public static void main(String[] args) throws IOException {
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET, Arrays.asList(DirectoryScopes.ADMIN_DIRECTORY_USER))
.setAccessType("online")
.setApprovalPrompt("auto").build();
String url = flow.newAuthorizationUrl().setRedirectUri(REDIRECT_URI).build();
System.out.println("Please open the following URL in your browser then type the authorization code:");
System.out.println(" " + url);
System.out.println("Enter authorization code:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String code = br.readLine();
GoogleTokenResponse response = flow.newTokenRequest(code).setRedirectUri(REDIRECT_URI).execute();
GoogleCredential credential = new GoogleCredential().setFromTokenResponse(response);
// Create a new authorized API client
Directory service = new Directory.Builder(httpTransport, jsonFactory, credential)
.setApplicationName("DirectoryCommandLine")
.build();
List<User> allUsers = new ArrayList<User>();
Directory.Users.List request = service.users().list().setCustomer("my_customer");
// Get all users
do {
try {
Users currentPage = request.execute();
allUsers.addAll(currentPage.getUsers());
request.setPageToken(currentPage.getNextPageToken());
} catch (IOException e) {
System.out.println("An error occurred: " + e);
request.setPageToken(null);
}
} while (request.getPageToken() != null &&
request.getPageToken().length() > 0 );
// Print all users
for (User currentUser : allUsers) {
System.out.println(currentUser.getPrimaryEmail());
}
}
}
You do need to use a browser to get user's authorization, but you only have to do it exactly once if you store your refresh token securely.
What's your scenario? You can use embedded browser in mobile, and get the authorization code automatically.
When I am adding digital signature to the encrypted(password protected) PDF using PDF BOX am getting the following exceptions,
Exception in thread "main" java.lang.NullPointerException
at org.apache.pdfbox.pdmodel.encryption.StandardSecurityHandler.computeRevisionNumber(StandardSecurityHandler.java:128)
at org.apache.pdfbox.pdmodel.encryption.StandardSecurityHandler.prepareDocumentForEncryption(StandardSecurityHandler.java:299)
at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1457)
at org.apache.pdfbox.pdmodel.PDDocument.saveIncremental(PDDocument.java:1396)
at com.seind.pdf.digitalsignature.CreateVisibleSignature.signPDF(CreateVisibleSignature.java:187)
at com.seind.pdf.digitalsignature.CreateVisibleSignature.main(CreateVisibleSignature.java:305)
But when I am using owner password to decrypt the PDF, its not working. its correct a password which I was used to encrypt... I hope you all understand the problem and here is my sample code:
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertStore;
import java.security.cert.Certificate;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.List;
import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.encryption.StandardDecryptionMaterial;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigProperties;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSSignedGenerator;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* This is an example for visual signing a pdf with bouncy castle.
* {#see CreateSignature}
* #author Vakhtang Koroghlishvili
*/
public class CreateVisibleSignature implements SignatureInterface
{
public static final String RESOURCE ="stock1.jpg";//"Paul_Cézanne_222.jpg";//"signature-stamp.jpg";//"SJG_Signature.png";//"amber-signature.png";// "Man-Utd-v-Bayern-Munich-018.jpg";//"check_256.png";//"signature-stamp.jpg";
private static BouncyCastleProvider provider = new BouncyCastleProvider();
private PrivateKey privKey;
private Certificate[] cert;
private SignatureOptions options;
public CreateVisibleSignature()
{
}
/**
* Initialize the signature creator with a keystore (pkcs12) and pin that
* should be used for the signature.
*
* #param keystore is a pkcs12 keystore.
* #param pin is the pin for the keystore / private key
*/
public CreateVisibleSignature(KeyStore keystore, char[] pin)
{
try
{
// grabs the first alias from the keystore and get the private key. An
// alternative method or constructor could be used for setting a specific
// alias that should be used.
Enumeration<String> aliases = keystore.aliases();
String alias = null;
while (aliases.hasMoreElements())
{
alias = aliases.nextElement();
System.out.println(" alias name "+alias);
}
privKey = (PrivateKey) keystore.getKey(alias, pin);
cert = keystore.getCertificateChain(alias);
}
catch (KeyStoreException e)
{
e.printStackTrace();
}
catch (UnrecoverableKeyException e)
{
System.err.println("Could not extract private key.");
e.printStackTrace();
}
catch (NoSuchAlgorithmException e)
{
System.err.println("Unknown algorithm.");
e.printStackTrace();
}
}
/**
* Signs the given pdf file.
*
* #param document is the pdf document
* #param signatureProperties
* #return the signed pdf document
* #throws Exception
*/
public File signPDF(File document, PDVisibleSigProperties signatureProperties) throws Exception
{
PDDocument doc = openPDFDoc(document);
byte[] buffer = new byte[8 * 1024];
if (document == null || !document.exists())
{
new RuntimeException("Document for signing does not exist");
}
// creating output document and prepare the IO streams.
String name = document.getName();
String substring = name.substring(0, name.lastIndexOf("."));
File outputDocument = new File(document.getParent(), substring + "_signed.pdf");
FileInputStream fis = new FileInputStream(document);
FileOutputStream fos = new FileOutputStream(outputDocument);
int c;
while ((c = fis.read(buffer)) != -1)
{
fos.write(buffer, 0, c);
}
fis.close();
fis = new FileInputStream(outputDocument);
// load document
// PDDocument doc = PDDocument.load(document);
// create signature dictionary
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); // default filter
// subfilter for basic and PAdES Part 2 signatures
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setName(signatureProperties.getSignerName());
signature.setLocation("chennai");
//signature.setReason("reason for signature");
// the signing date, needed for valid signature
signature.setSignDate(Calendar.getInstance());
// register signature dictionary and sign interface
options = new SignatureOptions();
options.setVisualSignature(signatureProperties);
// options.setPage(signatureProperties.getPage());
//options.setPreferedSignatureSize(signatureProperties.getPreferredSize());
doc.addSignature(signature, this, options);
doc.saveIncremental(fis, fos);
return outputDocument;
}
PDDocument openPDFDoc(File pdfFile) throws Exception
{
File originalPDF = pdfFile;
PDFParser parser = new PDFParser(new BufferedInputStream(new FileInputStream(originalPDF)));
parser.parse();
PDDocument originialPdfDoc = parser.getPDDocument();
boolean isOriginalDocEncrypted = originialPdfDoc.isEncrypted();
if (isOriginalDocEncrypted)
{
originialPdfDoc.openProtection(new StandardDecryptionMaterial("123456"));
}
return originialPdfDoc;
}
/**
* SignatureInterface implementation.
*
* This method will be called from inside of the pdfbox and create the pkcs7 signature.
* The given InputStream contains the bytes that are given by the byte range.
*
* This method is for internal use only. <-- TODO this method should be private
*
* Use your favorite cryptographic library to implement pkcs7 signature creation.
*/
#SuppressWarnings("deprecation")
#Override
public byte[] sign(InputStream content) throws IOException
{
CMSProcessableInputStream input = new CMSProcessableInputStream(content);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
// CertificateChain
List<Certificate> certList = Arrays.asList(cert);
CertStore certStore = null;
try
{
certStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList), provider);
gen.addSigner(privKey, (X509Certificate) certList.get(0), CMSSignedGenerator.DIGEST_SHA256);
gen.addCertificatesAndCRLs(certStore);
CMSSignedData signedData = gen.generate(input, false, provider);
return signedData.getEncoded();
}
catch (Exception e)
{
// should be handled
System.err.println("Error while creating pkcs7 signature.");
e.printStackTrace();
}
throw new RuntimeException("Problem while preparing signature");
}
public static void main(String[] args) throws Exception
{
//String pdfPath="E:\\outputs1\\iText in Action.pdf";
String pdfPath="E:\\outputs1\\CNB_20131029_AAPL034_0490301_NSEFO_ECN_iPass.pdf";
// new PdfOptimize().reducePdfSize(pdfPath);
File ksFile = new File("E:/sol.p12");
KeyStore keystore = KeyStore.getInstance("PKCS12", provider);
char[] pin = "xxxxxxx".toCharArray();
keystore.load(new FileInputStream(ksFile), pin);
//String pdfPath="E:\\temp\\pdf\\security\\password\\hello_iText.pdf";
File document = new File(pdfPath);
CreateVisibleSignature signing = new CreateVisibleSignature(keystore, pin.clone());
FileInputStream image = new FileInputStream(RESOURCE);
PDVisibleSignDesigner visibleSig = new PDVisibleSignDesigner(pdfPath, image, 1);
visibleSig.xAxis(660).yAxis(480).zoom(-50).signatureFieldName("signature");
visibleSig.height(37);
visibleSig.width(70);
//visibleSig.imageSizeInPercents(50);
PDVisibleSigProperties signatureProperties = new PDVisibleSigProperties();
signatureProperties.signerName("XXXXXXX").signerLocation("chennai").signatureReason("Security").preferredSize(0)
.page(1).visualSignEnabled(true).setPdVisibleSignature(visibleSig).buildSignature();
signatureProperties.setPdVisibleSignature(visibleSig);
signing.signPDF(document, signatureProperties);
}
}
And most of the methods are deprecated which are used to verify the owner password ,user password and etc.
Even the password you used is a correct one , when the PDF is Password protected it has some securities added to it. So you need to remove those securites.
In your openPDFDoc(File pdfFile) method
Add these lines to your method
if (isOriginalDocEncrypted)
{
originialPdfDoc.openProtection(new StandardDecryptionMaterial("123456"));
**originialPdfDoc.setAllSecurityToBeRemoved(true);**
}
This will remove the securities set to the PDF
Now you can do the job.
I want to encrypt decrypt data using PKCS #7.
While exploring i found a book Beginning Cryptography With Java
In ch 9 of the book is having a example code is below
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.*;
import java.util.Arrays;
import org.bouncycastle.cms.CMSProcessable;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
/**
* Example of generating a detached signature.
*/
public class SignedDataExample
extends SignedDataProcessor
{
public static void main(String[] args) throws Exception
{
KeyStore credentials = Utils.createCredentials();
PrivateKey key = (PrivateKey)credentials.getKey(
Utils.END_ENTITY_ALIAS, Utils.KEY_PASSWD);
Certificate[] chain = credentials.getCertificateChain(
Utils.END_ENTITY_ALIAS);
CertStore certsAndCRLs = CertStore.getInstance(
"Collection", new CollectionCertStoreParameters(
Arrays.asList(chain)), "BC");
X509Certificate cert = (X509Certificate)chain[0];
// set up the generator
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addSigner(key, cert, CMSSignedDataGenerator.DIGEST_SHA224);
gen.addCertificatesAndCRLs(certsAndCRLs);
// create the signed-data object
CMSProcessable data = new CMSProcessableByteArray(
"Hello World!".getBytes());
CMSSignedData signed = gen.generate(data, "BC");
// re-create
signed = new CMSSignedData(data, signed.getEncoded());
// verification step
X509Certificate rootCert = (X509Certificate)credentials.getCertificate(
Utils.ROOT_ALIAS);
if (isValid(signed, rootCert))
{
System.out.println("verification succeeded");
}
else
{
System.out.println("verification failed");
}
}
}
I have couple of question
Where is encrypted data and how do i write it to file
How do i recover back original data from encrypted data
Do i need to send key store to the person who is decrypting the encrypted data.
In what format should i send encrypted data
Thanks A Lot