Digital signatures depend upon message and the secret key. Suppose receiver copies the message several times ( the reason for which we unique ids) , why will the signature be different (since the message and secret key are same)?
Bitcoin uses ECDSA, and the reason the signature is different for the same message and key is the random nonce, which is generated each time a signature is created.
An ECDSA signature is a pair (r,s) where r is the X coordinate of kG, and s = (m+r*x)/k (where k=nonce, m=message hash, x=private key, G=curve generator).
See also #3 in https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Signature_generation_algorithm
This answer is just a practical supplement to the theoretical answer provided above. This snippet digitally signs inside the for-loop the same message over and over again using the same private key and each time, it is printing out different digital signatures. Each of these signatures are valid and will verify using the signer's public key.
import java.security.Security;
import java.security.Signature;
import java.security.KeyFactory;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.KeyPairGenerator;
import java.security.KeyPair;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.interfaces.ECPublicKey;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
class liptic
{
static String the_message = "how are you, little tiger?";
public static void main(String args[]) throws Exception
{
Security.addProvider(new BouncyCastleProvider());
SecureRandom random = new SecureRandom();
ECParameterSpec ecSpec
=
ECNamedCurveTable.getParameterSpec("secp256k1");
KeyPairGenerator g =
KeyPairGenerator.getInstance("ECDH", "BC");
g.initialize(ecSpec, random);
KeyPair keyPair = g.generateKeyPair();
byte[] bob_pubkey = Hex.decode( "040581E4AEEEB1CEA57094D1AD97B8C721509B6E5D3690C70BBB8EB2C5FE8040"
+ "FB2C9B0A77EA2AD05C5E8DB499F647BC9A8BE829961950D6F5A45952C097CCB0BC");
Signature signer = Signature.getInstance("SHA256withECDSA", "BC");
ECPublicKeySpec pubkSpec = new ECPublicKeySpec(
ecSpec.getCurve().decodePoint(bob_pubkey), ecSpec);
ECPublicKey publicKey
= (ECPublicKey)KeyFactory.getInstance("ECDSA", "BC")
.generatePublic(pubkSpec);
byte[] signature = null;
byte[] input = the_message.getBytes();
signer.initSign(keyPair.getPrivate());
signer.update(input);
for (int i = 0; i < 5; i++) {
signature = signer.sign();
System.out.println(o(signature));
}
}
public static String o(byte[] bytes)
{
int n = 0;
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b));
n++;
if (n % 128 == 0) {
sb.append("\n");
}
}
return sb.toString();
}
}
Here are the digital signatures:
3046022100889CC42C4BAA07FF33AB34CADD8BCB0A44E77031D4A5F5A9849840DF3AB63FDA0221009CA5C49FC0EBE9F839A0CFAB18CEC91C9169FF439C1E2DFD724D06E2DB9FE258
30460221009D30465EFD3676982CBE12B998D41D012322C255594D5037F156143AEC7E7305022100A77FE7DEB580837A1A5A5D1B74334C56E9F26BA1834EE3AC93ECEB01349A6F1C
3045022100DF4AF153D808A9199C18C97E689F1214E7F59C621D6ECBAADFE206B83707CA2802203E592D0152E79E14084183206F4B6DBC95D68FBA2D23F65884A3B68FA79A4E04
304502202E9FA22709308D08106F76CBB6278B3F485A3C706EDA3FFAF5CE744D4B90E9510221009DD2370863D6C1CE36D828FF9B98347905F2D0856052C4A30B25DD00575B8921
3045022100AA46FEA1A80498E481D46B17EFD7FBE6656641CD719AF1F5DC0C77ADD334729D0220471472117374E0284074EBC81172E6271CA9D86F54AFCE6E6CF6863814EBF824
This is using the Elliptic Curve Digital Signature Algorithm.
Related
We have to build a signature string hashed using SHA-256 with random salt and using 10000 iterations. However, when I run the below code with salt, output hash value is not matching at all for the same input string. If I run the code without the salt, hashed value matches. Can someone point out the right way to add a random salt to the SHA-256 digest and get the firstValue/secondValue same below.
import java.security.MessageDigest;
import java.security.SecureRandom;
import org.springframework.security.crypto.codec.Hex;
public class someTester{
public static void main(String[] args) {
String signatureInput = "someStringWhichisSensitive";
String firstSignValue = getSignature(signatureInput);
String secondSignValue = getSignature(signatureInput);
System.out.println("firstSignValue="+firstSignValue);
System.out.println("secondSignValue="+secondSignValue);
}
private static String getSignature(String signatureInput){
MessageDigest md;
String signatureValue = null;
try {
// Create a random salt
SecureRandom sr = new SecureRandom();
byte[] bSalt = new byte[8];
sr.nextBytes(bSalt);
md = MessageDigest.getInstance("SHA-256");
// digest.update(bSalt);
byte[] bDigest = md.digest(signatureInput.getBytes());
// Iterate through 10000 times
for (int i = 0; i < 10000; i++) {
bDigest = md.digest(bDigest);
}
signatureValue = new String(Hex.encode(bDigest));
} catch (Exception e) {
System.out.println("Exception while calculating SHA-256 digest value"+e);
}
return signatureValue;
}
}
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.
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.
My task is the following:
Retrieve my public and private key from the keystore I created.
Use these keys to encrypt a paragraph using my RSA 2048-bit public key.
Digitally sign the result using the DSA-SHA-1 signature algorithm.
Save the digital signature output on a file called output.dat.
The program below is throwing error : "java.security.InvalidKeyException: No installed provider supports this key: sun.security.provider.DSAPublicKeyImpl".
import java.security.*;
import java.security.KeyStore.*;
import java.io.*;
import java.security.PublicKey;
import java.security.PrivateKey;
import javax.crypto.Cipher;
import java.nio.charset.*;
import sun.security.provider.*;
import javax.crypto.*;
public class Code {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
try {
/* getting data for keystore */
File file = new File(System.getProperty("user.home") + File.separatorChar + ".keystore");
FileInputStream is = new FileInputStream(file);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
/*Information for certificate to be generated */
String password = "abcde";
String alias = "mykeys";
String alias1 = "skeys";
String filepath ="C:\\email.txt";
/* getting the key*/
keystore.load(is, password.toCharArray());
PrivateKey key = (PrivateKey)keystore.getKey(alias, "bemylife".toCharArray());
//PrivateKey key = cert1.getPrivateKey();
//PublicKey key1= (PrivateKey)key;
/* Get certificate of public key */
java.security.cert.Certificate cert = keystore.getCertificate(alias);
/* Here it prints the public key*/
System.out.println("Public Key:");
System.out.println(cert.getPublicKey());
/* Here it prints the private key*/
System.out.println("\nPrivate Key:");
System.out.println(key);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE,cert.getPublicKey());
String cleartextFile = "C:\\email.txt";
String ciphertextFile = "D:\\ciphertextRSA.png";
FileInputStream fis = new FileInputStream(cleartextFile);
FileOutputStream fos = new FileOutputStream(ciphertextFile);
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
byte[] block = new byte[32];
int i;
while ((i = fis.read(block)) != -1) {
cos.write(block, 0, i);
}
cos.close();
/* computing the signature*/
Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");
dsa.initSign(key);
FileInputStream f = new FileInputStream(ciphertextFile);
BufferedInputStream in = new BufferedInputStream(f);
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) >= 0) {
dsa.update(buffer, 0, len);
};
in.close();
/* Here it prints the signature*/
System.out.println("Digital Signature :");
System.out.println( dsa.sign());
/* Now Exporting Certificate */
System.out.println("Exporting Certificate. ");
byte[] buffer_out = cert.getEncoded();
FileOutputStream os = new FileOutputStream(new File("d:\\signedcetificate.cer"));
os.write(buffer_out);
os.close();
/* writing signature to output.dat file */
byte[] buffer_out1 = dsa.sign();
FileOutputStream os1 = new FileOutputStream(new File("d:\\output.dat"));
os1.write(buffer_out1);
os1.close();
} catch (Exception e) {System.out.println(e);}
}
}
You have to read it from the keystore file (which probably ends in .jks) into a java.security.KeyStore object.
/**
* Reads a Java keystore from a file.
*
* #param keystoreFile
* keystore file to read
* #param password
* password for the keystore file
* #param keyStoreType
* type of keystore, e.g., JKS or PKCS12
* #return the keystore object
* #throws KeyStoreException
* if the type of KeyStore could not be created
* #throws IOException
* if the keystore could not be loaded
* #throws NoSuchAlgorithmException
* if the algorithm used to check the integrity of the keystore
* cannot be found
* #throws CertificateException
* if any of the certificates in the keystore could not be loaded
*/
public static KeyStore loadKeyStore(final File keystoreFile,
final String password, final String keyStoreType)
throws KeyStoreException, IOException, NoSuchAlgorithmException,
CertificateException {
if (null == keystoreFile) {
throw new IllegalArgumentException("Keystore url may not be null");
}
LOG.debug("Initializing key store: {}", keystoreFile.getAbsolutePath());
final URI keystoreUri = keystoreFile.toURI();
final URL keystoreUrl = keystoreUri.toURL();
final KeyStore keystore = KeyStore.getInstance(keyStoreType);
InputStream is = null;
try {
is = keystoreUrl.openStream();
keystore.load(is, null == password ? null : password.toCharArray());
LOG.debug("Loaded key store");
} finally {
if (null != is) {
is.close();
}
}
return keystore;
}
Once you have the KeyStore, you can get to the Certificate and the public and private keys.
But using that to sign text and save it in a file is more involved, and easy to do wrong. Take a look at Sign string using given Public Key and replace the getKeyPair method with one that uses the KeyStore. Something along the lines of
public static KeyPair getKeyPair(final KeyStore keystore,
final String alias, final String password) {
final Key key = (PrivateKey) keystore.getKey(alias, password.toCharArray());
final Certificate cert = keystore.getCertificate(alias);
final PublicKey publicKey = cert.getPublicKey();
return KeyPair(publicKey, (PrivateKey) key);
}
(obviously a little rougher, I didn't have a sample handy)
The problem is that a DSA key is unsuitable for RSA encryption. You need an RSA key for encryption, maybe you can switch your signature algorithm to RSA/SHA1 to avoid the need for two keys..
In Spring Boot(my example is using 2.4.x), you can use a bean for your KeyStore, like so:
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
#Configuration
public class KeyStoreConfiguration {
private static final String KEY_STORE = "keystore.p12";
private static final String KEY_STORE_TYPE = "PKCS12";
private static final String KEY_STORE_PASSWORD = "password";
#Bean
public KeyStore keyStore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE);
keyStore.load(new ClassPathResource(KEY_STORE).getInputStream(), KEY_STORE_PASSWORD.toCharArray());
return keyStore;
}
}
and you can then retrieve the public and private key like so:
import java.security.PrivateKey;
import java.security.PublicKey;
PrivateKey privateKey = (PrivateKey) keyStore.getKey("my-alias", "my-password".toCharArray());
PublicKey publicKey = keyStore.getCertificate("my-alias").getPublicKey();
trusted.load(in, ((PBCApplication) context.getApplicationContext()).getBuildSettings().getCertificatePass());
Enumeration enumeration = trusted.aliases();
while (enumeration.hasMoreElements()) {
String alias = (String) enumeration.nextElement();
System.out.println("alias name: " + alias);
Certificate certificate = trusted.getCertificate(alias);
certificate.getPublicKey();
}
I don't have the Java code stored at the top of my brain, but some general sanity checks are:
is the public certificate you want stored where you want it? In particular, my recollection is that the certificate with the public key and the private key are stored together under a single alias, so the two alias setting you have there seems really odd. Try storing both under the same alias and referencing it in both the private and public key calls.
can you get anything else out of the certificate - for example, subject DN or issuer DN are both must-have fields in a certificate. That gives you a good proof that the certificate is being read as expected.
in almost any crypto transaction, be very careful with how you read from files and transfer your encoding methods. If you've created your File IO and pulled from it in a weird way, you can corrupt the encoding of the key material. That's a last thing to check - usually Java and JKS haven't been so bad for this, but it happens. On the same vein, be clear about the format of the file - JKS files are different from PKCS 12 files, for example.
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