I've been working on settting passwords on PDFs to prevent copy/paste and allow printing, add watermarks and set an owner password to prevent further changes.
Everything works well as expected, no issue there.
Then I downloaded this free for 15 days pdf removal tool, a-pdf. In a blink it removes all protection, no matter the complexity of the password (tried with 50 char length will all kind of chars).
I see there are other methods in itextPDF to encrypt a document. I used the following:
File f = new File("C:/TEMP/zip/waterMarked.pdf");
String hardPassword = "D 5BaIZQ# CqAk+NQCW)7Dkgb#i&02ifu!2TMX*d 0TGK(j(Kq";
byte[] hardPasswordByte = hardPassword.getBytes();
PdfReader reader = new PdfReader("C:/TEMP/zip/Original_document-9.pdf");
FileOutputStream out = new FileOutputStream(f);
PdfStamper stamp = new PdfStamper(reader, out);
//first argument is the user password. If set to something it asks for password when opening file, not wanted.
stamp.setEncryption(null, hardPasswordByte, PdfWriter.ALLOW_PRINTING, true);
//do stuff on the stamper, save file.
Does anyone knows a better way to protect PDF documents from Java code ?
PDF files support 2 passwords: user password and owner password. A user can view the PDF file if he knows any of these passwords. If the file has a user password, when the file is opened with a PDF viewer, the viewer asks the user to enter a password and either the user or owner passwords will work. If the file has only an owner password, the document is displayed automatically and the password is required when trying to change the file's access rights. This is the flow of operations suggested by PDF specification, but in reality it works like this: if the file is protected with a user password, brute force approach is required for password cracking, the longer the password is the longer it takes to crack. Problem is your real users need the password to open the file. If the file is protected only with an owner password, there is a default decryption key (remember, any viewer can display the PDF file without requesting a password) and the application that processes the PDF file decides whether to respect or not the document access rights. Once the file has been decrypted, it is saved without encryption and the output file has no longer a password. Since your documents have only the owner password, the tool removes it without problems using the default decryption key.
There are a few solutions (more or less related to iText) depending on your audience:
simple PDF encryption (with the problems above) if your audience is widespread, for example you publish papers on a website; 3rd party DRM solution, more complex and requires various plugins installed on your users' computers; certificate encryption (no sure if iText supports it), again complex, requires each user to have a digital certificate and documents access is defined for each user. Last 2 options work in a controlled enterprise environment.
Related
My web server generates a pdf, signs it, and give it to the client. The client sign it multiple times (with different tokens using Adobe Pro) and then upload it back to the server.
I want the server to verify if it is the pdf that was previously generated by the server. I read that the hash is changed when multiple signatures are applied. How can do this verification easily with iText ?
Multiple integrated signatures in the same PDF are applied by means of incremental updates if done properly, cf. this answer on Information Security Stack Exchange:
Thus, while in a way it is true what you read
I read that the hash is changed when multiple signatures are applied.
(indeed, the hash of the whole file changes unless you have an extremely unlikely collision), the hash of the bytes your initial signature applies to remains and can be retrieved from the document.
So depending on what you want to check and what information you still have, there are these obvious options:
Comparing the initial revision
My web server generates a pdf, signs it, and give it to the client
If you still have that initial signed PDF stored somewhere (e.g. in a database) and you want to check whether the PDF the client uploaded back to you is based on that very PDF, all you need to do is check whether the client's PDF byte stream starts with the bytes of the PDF you stored.
This does not require any extra use of cryptographic functions or PDF specific APIs, merely a comparison of bytes or blocks of them.
Checking the signature
My web server generates a pdf, signs it, and give it to the client
If you don't have that initial signed PDF stored anywhere or you only want to check whether the PDF the client uploaded back to you is based on one of many possible base PDFs signed by you, direct revision comparison is impossible or very resource intensive.
In this case you should check whether the initial signature of the document
is valid and
has been created by your server.
Checking the signature validity
There are many examples on how to check the integrity of signatures in a PDF, e.g.
public PdfPKCS7 verifySignature(AcroFields fields, String name) throws GeneralSecurityException, IOException {
System.out.println("Signature covers whole document: " + fields.signatureCoversWholeDocument(name));
System.out.println("Document revision: " + fields.getRevision(name) + " of " + fields.getTotalRevisions());
PdfPKCS7 pkcs7 = fields.verifySignature(name);
System.out.println("Integrity check OK? " + pkcs7.verify());
return pkcs7;
}
public void verifySignatures(String path) throws IOException, GeneralSecurityException {
System.out.println(path);
PdfReader reader = new PdfReader(path);
AcroFields fields = reader.getAcroFields();
ArrayList<String> names = fields.getSignatureNames();
for (String name : names) {
System.out.println("===== " + name + " =====");
verifySignature(fields, name);
}
System.out.println();
}
(C5_01_SignatureIntegrity.java from the iText digital signatures white paper)
For your task you actually can simply restrict yourself to checking the first signature only but checking the other ones, too, might also be a good idea.
Checking the signature certificate
To check whether the initial signature has been created by your server, let's assume your web server signs these PDFs using a X509 certificate dedicated to this task (or a known set of such certificates).
You can retrieve the certificate using which the initial signature was created with the method getSigningCertificate of the PdfPKCS7 object you retrieve from the verifySignature call for the first signature. All you have to do is check whether the certificate is the one certificate (or one of the set of certificates) you dedicated for this task.
i am working on a project that requires a password to access every downloaded PDF file. The password is to be fetched from a database (I am using MySQL).
I have searched for a java code that would relate to this type of task but I have barely got any. Most answers are inclined to form filling after the document is already downloaded.
I have thought about making the PDF files templates that would only display information if the password field that would be auto-filled (In case i am forced to use this option) but i am afraid that would take a lot of doing.
i have read on the context of iTEXT by Bruno Lowagie directed by a question on Stackoverflow but the closest i got was this snippet that answers a question by "affan" on how to fill a PDF automatically using external data from a database.
I recon that this snippet is to be used to fill in an already open PDF document.
This is the snippet:
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
AcroFields form = stamper.getAcroFields();
form.setField(key, value);
stamper.setFormFlattening(true);
stamper.close();
reader.close();
Someone please help out with how i could automatically fill the password field of a PDF that requires a password for access.
It seems that you are mixing two different things:
Form fields, in which you have a text field for which a specific field flag is set so that the text that is added is obfuscated (e.g. "Password" is shown as "********"). Reading your requirement, this is not what you want. Also: I see that you set the form flattening to true and that removes all the field information, including the field flag that changes a text field into a password field.
Encryption, in which you protect a document with one or two passwords.
I assume that you want to protect a document, but I have to admit that my assumption could be wrong. I have no idea why you are mentioning form field in your question.
If you protect a document with an owner password only, everyone has access to that document, but you can put in place some permissions. This is not a secure solution, because many viewers ignore the owner password; moreover, it is very easy to remove the owner password.
If you protect a document with an owner and a user password, only people who know either the owner password or the user password can view the document. All the content of the document is encrypted (except for the Metadata if you want the metadata to be accessible).
Please read the answer to the following questions:
How to protect a PDF with a username and password?
How to protect an already existing PDF with a password?
iText setEncryption error
BadPasswordException: Bad user password (this is probably the most interesting one)
For a more elaborate answer, please consult the FAQ on the official web site.
for iText 5: How to decrypt a PDF document with the owner password?
for iText 7: How to decrypt a PDF document with the owner password?
Form fields (even when using the password flag on a text field) and using encryption to protect a document, are two completely separate topics in the PDF specification (ISO-32000). You can't "automatically fill a password field" in a PDF form, and hope that you can use the value of that field to open a protected document.
Hello fellow stack overflow users.
I have a problem that I have no idea how to face... I want to incorporate a login screen into one of my Netbeans projects that requires a user to either create a user name and password or login using a existing password and username. When the user logs into their personal account it must display which their personal high-scores. All the information has to be read and written to a already created text file in the project file.
My login screen
Any suggestions to help improve the concept or where I can read up more on Text file databases would also be much appreciated.
Thanks from:
Noobie Coder
EDIT:
This is part of an school I.T assignment, we had a choice to make a functioning login system using either a textfile or a MySQL database. It does not need to be a secure login system with layers of encryption or extra security measures.
What I am struggling with:
Honestly I just don't know how to begin. I don't have the faintest clue of I/O and have no clue how to incorporate it into my project.
A way to encrypt your text file would be to use a Cipher.
https://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html
There are also tutorials for reading/writing an encrypted file with Java:
https://www.flexiprovider.de/examples/ExampleCrypt.html
Edit to match your edited question again:
You can set the encryption key to the password a user has to enter. You could create a .txt, encrypted with the password of the user, containing the users scores. To read the encrypted file line by line, use a BufferedReader (in the example they write the input to another file). To use the code from the example:
String cleartextAgainFile = "cleartextAgainSymm.txt";
cipher.init(Cipher.DECRYPT_MODE, secKey);
fis = new FileInputStream(ciphertextFile);
CipherInputStream cis = new CipherInputStream(fis, cipher);
BufferedReader read = new BufferedReader(new InputStreamReader(cis));
String str;
while((str=read.readLine())!=null){
//do sth with the read line
}
read.close();
We need to embed a file into a pdf with java, and we need to have it crypted with certificate
I've found something using (if I'm not worng) itext some months ago, but I cannot find it anymore
The certs are on a smart card
Encrypting a PDF is done with a public certificate. Once a PDF is encrypted, only the person with the corresponding private certificate can open the PDF. In your scenario, this would mean that only the person who owns the smart card can open the document.
First you need to extract the public certificate from the smart card. The main question here is: do you want to do this in Java? If so, do you want to do this using PKCS#11? Using MSCAPI? Using a smart card API? I honestly don't think that's what you want to do. I think you want the owners of the smart card to extract their public certificate manually and to send it to you. If this assumption is wrong, you need to post another question: how to get a public certificate from a smart card.
Once you have this certificate, you can encrypt the PDF like this:
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
Certificate cert = getPublicCertificate("resources/encryption/public.cer");
stamper.setEncryption(new Certificate[]{cert},
new int[]{PdfWriter.ALLOW_PRINTING}, PdfWriter.ENCRYPTION_AES_128);
stamper.close();
reader.close();
The public certificate is stored in the file public.cer. That's the file your end user extracted from the smart card.
If you want to encrypt attachments separately, you'll have to do this at the level of those files. It isn't clear if you're talking about PDFs or about another type of document.
I have copy pasted the source code snippet from my book.
I have a properties file in java, in which I store all information of my app, like logo image filename, database name, database user and database password.
I can store the password encrypted on the properties file. But, the key or passphrase can be read out of the jar using a decompiler.
Is there a way to store the db pass in a properties file securely?
There are multiple ways to manage this. If you can figure out a way to have a user provide a password for a keystore when the application starts up the most appropriate way would be to encrypt all the values using a key, and store this key in the keystore. The command line interface to the keystore is by using keytool. However JSE has APIs to programmatically access the keystore as well.
If you do not have an ability to have a user manually provide a password to the keystore on startup (say for a web application), one way to do it is to write an exceptionally complex obfuscation routine which can obfuscate the key and store it in a property file as well. Important things to remember is that the obfuscation and deobfuscation logic should be multi layered (could involve scrambling, encoding, introduction of spurious characters etc. etc.) and should itself have at least one key which could be hidden away in other classes in the application using non intuitive names. This is not a fully safe mechanism since someone with a decompiler and a fair amount of time and intelligence can still work around it but is the only one I know of which does not require you to break into native (ie. non easily decompilable) code.
You store a SHA1 hash of the password in your properties file. Then when you validate a users password, you hash their login attempt and make sure that the two hashes match.
This is the code that will hash some bytes for you. You can easily ger bytes from a String using the getBytes() method.
/**
* Returns the hash value of the given chars
*
* Uses the default hash algorithm described above
*
* #param in
* the byte[] to hash
* #return a byte[] of hashed values
*/
public static byte[] getHashedBytes(byte[] in)
{
MessageDigest msg;
try
{
msg = MessageDigest.getInstance(hashingAlgorithmUsed);
}
catch (NoSuchAlgorithmException e)
{
throw new AssertionError("Someone chose to use a hashing algorithm that doesn't exist. Epic fail, go change it in the Util file. SHA(1) or MD5");
}
msg.update(in);
return msg.digest();
}
No there is not. Even if you encrypt it, somebody will decompile the code that decrypts it.
You could make a separate properties file (outside the jar) for passwords (either direct DB password or or key passphrase) and not include that properties file with the distribution. Or you might be able to make the server only accept that login from a specific machine so that spoofing would be required.
In addition to encrypting the passwords as described above put any passwords in separate properties file and on deployment try to give this file the most locked down permissions possible.
For example, if your Application Server runs on Linux/Unix as root then make the password properties file owned by root with 400/-r-------- permissions.
Couldn't you have the app contact a server over https and download the password, after authenticating in some way of course?