I am using below code to generate and add digital signatures to the Excel file:
SignedObject signedHashObject =null;
signatureConfig.setKey((PrivateKey) privateKey);signatureConfig.setSigningCertificateChain(Collections.singletonList(Util.getX509Certificate(certificateAlias)));
OPCPackage pkg = OPCPackage.open(selectedFileName, PackageAccess.READ_WRITE);
signatureConfig.setOpcPackage(pkg);
SignatureInfo si = new SignatureInfo();
si.setSignatureConfig(signatureConfig);
si.confirmSignature();
pkg.close();
Here the private key is java.security.mscapi.rsaprivatekey.
After fixing all the version compatibility issues, I am stuck with the below error,
The specified key of type sun.security.mscapi.RSAPrivateKey is not an RSAPrivateKey
I've fixed this now via #62159.
Make sure to set -Dorg.apache.xml.security.ignoreLineBreaks=true in the JVM properties.
Complete example, i.e. my test code:
import java.awt.geom.Rectangle2D;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.TimeZone;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.poifs.crypt.dsig.SignatureConfig;
import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFTextBox;
public class CertTest {
static PrivateKey winKey;
static List<X509Certificate> winChain;
public static void main(String[] args) throws Exception {
System.setProperty("org.apache.xml.security.ignoreLineBreaks", "true");
HashAlgorithm hashes[] = { HashAlgorithm.sha1, HashAlgorithm.sha256, HashAlgorithm.sha384, HashAlgorithm.sha512 };
loadWinKey();
SignatureConfig signatureConfig = new SignatureConfig();
Calendar cal = Calendar.getInstance();
cal.clear();
cal.set(2018, 1, 18, 12, 0, 0);
signatureConfig.setExecutionTime(cal.getTime());
for (final HashAlgorithm ha : hashes) {
try (final OPCPackage pkg = loadOPC("test-" + ha + ".pptx")) {
signatureConfig.setDigestAlgo(ha);
signatureConfig.setKey(winKey);
signatureConfig.setSigningCertificateChain(winChain);
signatureConfig.setOpcPackage(pkg);
SignatureInfo si = new SignatureInfo();
si.setSignatureConfig(signatureConfig);
si.confirmSignature();
}
}
}
static void loadWinKey() throws Exception {
String alias = "poitest";
KeyStore keystore = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
keystore.load(null, null);
winKey = (PrivateKey) keystore.getKey(alias, null);
winChain = Collections.singletonList((X509Certificate) keystore.getCertificate(alias));
}
static OPCPackage loadOPC(String fileName) throws Exception {
try (final XMLSlideShow ppt = new XMLSlideShow()) {
try (final FileOutputStream fos = new FileOutputStream(fileName)) {
XSLFTextBox tb = ppt.createSlide().createTextBox();
tb.setText("test");
tb.setAnchor(new Rectangle2D.Double(100, 100, 100, 100));
ppt.write(fos);
}
return OPCPackage.open(fileName, PackageAccess.READ_WRITE);
}
}
}
Related
I'm currently using the below method to take screenshots and store them in a folder called 'Screenshots'. But what i want is, to take these screenshots and paste them in a word document according to the test cases to which they belong.
Is it possible? If so could somebody please guide me?
public String FailureScreenshotAndroid(String name) {
try {
Date d = new Date();
String date = d.toString().replace(":", "_").replace(" ", "_");
TakesScreenshot t = (TakesScreenshot)driver;
File f1 = t.getScreenshotAs(OutputType.FILE);//Temporary Location
String permanentLocation =System.getProperty("user.dir")+ "\\Screenshots\\"+name+date+".png";
File f2 = new File(permanentLocation);
FileUtils.copyFile(f1, f2);
return permanentLocation;
}catch (Exception e) {
String msg = e.getMessage();
return msg;
}
}
Try below:
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFRun;
public class TakeScreenshots {
public static void main(String[] args) {
try {
XWPFDocument docx = new XWPFDocument();
XWPFRun run = docx.createParagraph().createRun();
FileOutputStream out = new FileOutputStream("d:/xyz/doc1.docx");
for (int counter = 1; counter <= 5; counter++) {
captureScreenShot(docx, run, out);
TimeUnit.SECONDS.sleep(1);
}
docx.write(out);
out.flush();
out.close();
docx.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void captureScreenShot(XWPFDocument docx, XWPFRun run, FileOutputStream out) throws Exception {
String screenshot_name = System.currentTimeMillis() + ".png";
BufferedImage image = new Robot()
.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
File file = new File("d:/xyz/" + screenshot_name);
ImageIO.write(image, "png", file);
InputStream pic = new FileInputStream("d:/xyz/" + screenshot_name);
run.addBreak();
run.addPicture(pic, XWPFDocument.PICTURE_TYPE_PNG, screenshot_name, Units.toEMU(350), Units.toEMU(350));
pic.close();
file.delete();
}
}
how can we unprotect the word document using java apache poi? I have protected the document as read-only using password pro-grammatically.Now I want to unprotect it. How can we do ? Is there any method to unprotect the document. I have used removePasswordProtection() but that document is not editable even after using that method.
The sample code that I have used for protection is
XWPFDocument document=new XWPFDocument();
document.enforceReadonlyProtection(strPassword,HashAlgorithm.sha1);
The document is getting protected successfully.
But when I am unprotecting document using the below code snippet it is not working.
if(document.isEnforcedReadonlyProtection())
{
if(document.validateProtectionPassword(strPassword))
{
document.removeProtectionEnforcement();
}
}
Can anyone help me what method that I can use to unprotect the document?
Cannot reproducing.
Following code produces two Word documents. One, WordProtected.docx, which is protected and one, WordUnprotected.docx in which protection is removed.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.poifs.crypt.HashAlgorithm;
class XWPFReadOnlyProtection {
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument();
String strPassword = "password";
document.enforceReadonlyProtection(strPassword, HashAlgorithm.sha1);
FileOutputStream fileout = new FileOutputStream("WordProtected.docx");
document.write(fileout);
fileout.close();
document.close();
document = new XWPFDocument(new FileInputStream("WordProtected.docx"));
document.removeProtectionEnforcement();
fileout = new FileOutputStream("WordUnprotected.docx");
document.write(fileout);
fileout.close();
document.close();
}
}
use this code for Word to Protect
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
public class WordTest {
public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream("D:\\govind.doc");
BufferedInputStream bin = new BufferedInputStream(in);
POIFSFileSystem poiFileSystem = new POIFSFileSystem(bin);
Biff8EncryptionKey.setCurrentUserPassword("P#ssw0rd");
HWPFDocument doc = new HWPFDocument(poiFileSystem);
Range range = doc.getRange();
FileOutputStream out = new FileOutputStream("D:\\govind.doc");
doc.write(out);
out.close();
}
}
this is use for protected word File unportected
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
public class wordFileTest {
public static void main(String[] args) throws IOException {
geenrateUnprotectedFile("D:\\","govind","1234");
}
public static void geenrateUnprotectedFile(String filePath,String fileName,String pwdtxt) {
try {
FileInputStream in = new FileInputStream(filePath+fileName+".doc");
BufferedInputStream bin = new BufferedInputStream(in);
POIFSFileSystem poiFileSystem = new POIFSFileSystem(bin);
Biff8EncryptionKey.setCurrentUserPassword(pwdtxt);
HWPFDocument doc = new HWPFDocument(poiFileSystem);
String docType=doc.getDocumentText();
FileOutputStream out = new FileOutputStream(filePath+fileName+"12.doc");
out.write(docType.getBytes());
System.out.println("don");
}catch (Exception e) {
e.printStackTrace();
}
}
}
I am getting below exception while running.Need to protect xls file which is already exists.
java.io.FileNotFoundException: no such entry: "EncryptionInfo", had:
[] at
org.apache.poi.poifs.filesystem.DirectoryNode.getEntry(DirectoryNode.java:399)
at
org.apache.poi.poifs.filesystem.DirectoryNode.createDocumentInputStream(DirectoryNode.java:188)
at
org.apache.poi.poifs.crypt.EncryptionInfo.(EncryptionInfo.java:94)
at
org.apache.poi.poifs.crypt.EncryptionInfo.(EncryptionInfo.java:76)
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.poifs.crypt.EncryptionInfo;
import org.apache.poi.poifs.crypt.EncryptionMode;
import org.apache.poi.poifs.crypt.Encryptor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
public class xlsProtect {
public static void main(String[] args) {
try {
POIFSFileSystem fs = new POIFSFileSystem();
EncryptionInfo info = new EncryptionInfo(fs);
Encryptor enc = info.getEncryptor();
enc.confirmPassword("test"); // s3cr3t is your password to open sheet.
OPCPackage opc = OPCPackage.open(new File("C:/Users/test/Desktop/pdf/1.xls"), PackageAccess.READ_WRITE);
OutputStream os = enc.getDataStream(fs);
opc.save(os);
opc.close();
FileOutputStream fos = new FileOutputStream("C:/Users/test/Desktop/pdf/1.xls");
fs.writeFilesystem(fos);
fos.close();
fs.writeFilesystem(fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
The Biff8EncryptionKey.setCurrentUserPassword() method has to be called after you've opened a .xls. See the following for encrypting both formats.
I've tested the .xls with Excel 2016 and Libre Office 6.0 - Libre Office currently can't open CryptoAPI encrypted files - if this is an issue for you, I think the example can be adapted to fallback to Binary RC4 encryption.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.poifs.crypt.EncryptionInfo;
import org.apache.poi.poifs.crypt.EncryptionMode;
import org.apache.poi.poifs.crypt.Encryptor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class EncryptTest {
public static void main(String[] args) throws Exception {
encryptHSSF();
encryptXSSF();
for (final String file : new String[] {"test.xls","test.xlsx"}) {
try (Workbook wb = WorkbookFactory.create(new File(file), "pass")) {
System.out.println(wb.getSheetAt(0).getRow(0).getCell(0).getStringCellValue());
}
}
}
public static void encryptHSSF() throws IOException, EncryptedDocumentException, InvalidFormatException {
generateFile("test.xls");
try (HSSFWorkbook hwb = (HSSFWorkbook)WorkbookFactory.create(new File("test.xls"))) {
Biff8EncryptionKey.setCurrentUserPassword("pass");
hwb.write();
}
}
public static void encryptXSSF() throws IOException, GeneralSecurityException {
generateFile("test.xlsx");
try (POIFSFileSystem fs = new POIFSFileSystem()) {
EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
Encryptor enc = info.getEncryptor();
enc.confirmPassword("pass");
try (OutputStream os = enc.getDataStream(fs)) {
try (InputStream is = new FileInputStream("test.xlsx")) {
IOUtils.copy(is, os);
}
}
try (FileOutputStream fos = new FileOutputStream("test.xlsx")) {
fs.writeFilesystem(fos);
}
}
}
public static void generateFile(final String filename) throws IOException {
try (Workbook wb = filename.endsWith("x") ? new XSSFWorkbook() : new HSSFWorkbook()) {
wb.createSheet("test").createRow(0).createCell(0).setCellValue("Test");
try (FileOutputStream fos = new FileOutputStream(filename)) {
wb.write(fos);
}
}
}
}
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import org.apache.sanselan.*;
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.ImageWriteException;
import org.apache.sanselan.common.IImageMetadata;
import org.apache.sanselan.common.ImageMetadata;
import org.apache.sanselan.common.RationalNumber;
import org.apache.sanselan.formats.jpeg.JpegImageMetadata;
import org.apache.sanselan.formats.jpeg.exifRewrite.ExifRewriter;
import org.apache.sanselan.formats.tiff.TiffImageMetadata;
import org.apache.sanselan.formats.tiff.constants.ExifTagConstants;
import org.apache.sanselan.formats.tiff.constants.TiffConstants;
import org.apache.sanselan.formats.tiff.constants.TiffFieldTypeConstants;
import org.apache.sanselan.formats.tiff.constants.TiffTagConstants;
import org.apache.sanselan.formats.tiff.write.TiffOutputDirectory;
import org.apache.sanselan.formats.tiff.write.TiffOutputField;
import org.apache.sanselan.formats.tiff.write.TiffOutputSet;
import org.apache.sanselan.formats.tiff.fieldtypes.FieldType;
import org.apache.sanselan.formats.tiff.fieldtypes.FieldTypeASCII;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
public class extraction {
public static void main(String[] args) throws ImageReadException, ImageWriteException, IOException {
extraction obj = new extraction();
File jpeg = new File("/Users/prijunankar/Desktop/G0015444.jpg");
File jpeg2 = new File("/Users/prijunankar/Desktop/G0015444a.jpg");
obj.editAnnotation(jpeg, jpeg2, "2016:07:04 00:00:00");
}
public void editAnnotation(final File jpeg, final File dest, final String tag) throws ImageReadException, IOException, ImageWriteException {
OutputStream os = null;
TiffOutputSet outputSet = null;
final IImageMetadata md = Sanselan.getMetadata(jpeg);
final JpegImageMetadata jpegmd = (JpegImageMetadata) md;
TiffOutputDirectory exifDir = null;
if(null != jpegmd) {
final TiffImageMetadata exif = jpegmd.getExif();
if (null != exif) {
outputSet = exif.getOutputSet();
exifDir = outputSet.getExifDirectory();
//System.out.println(exifDir.getFields().toString());
System.out.println("exif exists");
}
}
else if (null == outputSet) {
outputSet = new TiffOutputSet();
System.out.println("no exif");
exifDir = outputSet.getOrCreateExifDirectory();
}
//final FieldType field = new FieldType(TiffFieldTypeConstants.FIELD_TYPE_ASCII, 1, "Test");
Date newDate = new Date();
newDate.setDate(1);
newDate.setMonth(2);
newDate.setYear(2016);
String date = newDate.toString();
byte[] b = date.getBytes();
final TiffOutputField output = new TiffOutputField(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL, FieldType.FIELD_TYPE_BYTE, b.length, b);
//final TiffOutputField output2 = TiffOutputField.
//final TiffOutputDirectory exifDir = outputSet.getExifDirectory();
//System.out.println(exifDir.toString());
//System.out.println(exifDir.getRawTiffImageData().toString());
exifDir.removeField(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL);
exifDir.add(output);
double longitude = -74.0; // 74 degrees W (in Degrees East)
double latitude = 40 + 43 / 60.0; // 40 degrees N (in Degrees
// North)
outputSet.setGPSInDegrees(longitude, latitude);
os = new FileOutputStream(dest);
os = new BufferedOutputStream(os);
new ExifRewriter().updateExifMetadataLossless(jpeg, os, outputSet);
os.close();
os = null;
}
}
This is the code I am using to try to update the Original_Date_Time tag. However when checking the new exif data after running this code it outputs:
file: \Users\prijunankar\Desktop\G0015444a.jpg
XResolution: 72
Date Time: '2016:07:03 17:46:24'
Date Time Original: 87, 101, 100, 32, 77, 97, 114, 32, 48, 49, 32, 49, 52, 58, 50, 53, 58, 48, 52, 32, 69, 83, 84, 32, 51, 57, 49, 54
ISO: 100
Shutter Speed Value: -11468/-1000 (11.468)
Aperture Value: 280/100 (2.8)
Brightness Value: Not Found.
The date time original tag does not save as a string (used to be in the same format Date Time) but instead saves as a byte array. Can someone please help explain why/what is going wrong?
Here's some code I wrote, borrowing heavily from various examples:
package com.sengsational.jdf;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.apache.commons.imaging.ImageReadException;
import org.apache.commons.imaging.ImageWriteException;
import org.apache.commons.imaging.Imaging;
import org.apache.commons.imaging.common.ImageMetadata;
import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;
import org.apache.commons.imaging.formats.jpeg.exif.ExifRewriter;
import org.apache.commons.imaging.formats.tiff.TiffField;
import org.apache.commons.imaging.formats.tiff.TiffImageMetadata;
import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants;
import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
import org.apache.commons.imaging.formats.tiff.fieldtypes.FieldType;
import org.apache.commons.imaging.formats.tiff.taginfos.TagInfo;
import org.apache.commons.imaging.formats.tiff.write.TiffOutputDirectory;
import org.apache.commons.imaging.formats.tiff.write.TiffOutputField;
import org.apache.commons.imaging.formats.tiff.write.TiffOutputSet;
/*
* Created on Aug 26, 2021
*
*/
public class JpgDateFixer {
public static final int DATE_TIME_ORIGINAL = 0x9003;
public static void updateHourOnFile(String inputFileName, String outputFileName, int hourChange) throws ImageReadException, IOException, ParseException, ImageWriteException {
File inputFile = new File(inputFileName);
final ImageMetadata metadata = Imaging.getMetadata(inputFile);
if (metadata!=null && metadata instanceof JpegImageMetadata) {
final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
System.out.println("we have metadata");
final TiffField dateTimeField = jpegMetadata.findEXIFValueWithExactMatch(TiffTagConstants.TIFF_TAG_DATE_TIME);
SimpleDateFormat SDF = new SimpleDateFormat("yyyy:MM:dd kk:mm:ss");
Date pictureDate = SDF.parse((String)dateTimeField.getValue());
System.out.println("date: " + pictureDate);
Calendar cal = Calendar.getInstance();
cal.clear();
cal.setTime(pictureDate);
cal.add(Calendar.HOUR, hourChange);
System.out.println("new date time: " + cal.getTime());
TiffOutputSet outputSet = null;
try (FileOutputStream fos = new FileOutputStream(new File(outputFileName)); OutputStream os = new BufferedOutputStream(fos)) {
final TiffImageMetadata exif = jpegMetadata.getExif();
outputSet = exif.getOutputSet();
if (outputSet != null) {
final TiffOutputDirectory exifDirectory = outputSet.getOrCreateExifDirectory();
FieldType originalFieldType = null;
TagInfo originalTagInfo = null;
TiffOutputField dateTimeFieldOriginal = exifDirectory.findField(DATE_TIME_ORIGINAL); // DateTimeOriginal
if (dateTimeFieldOriginal != null) {
originalFieldType = dateTimeFieldOriginal.fieldType;
originalTagInfo = dateTimeFieldOriginal.tagInfo;
}
exifDirectory.removeField(DATE_TIME_ORIGINAL);
String updatedDateString = SDF.format(cal.getTime());
final TiffOutputField dateTimeOutputField = new TiffOutputField(originalTagInfo, originalFieldType, updatedDateString.length(), updatedDateString.getBytes());
exifDirectory.add(dateTimeOutputField);
new ExifRewriter().updateExifMetadataLossless(inputFile, os, outputSet);
} else {
System.out.println("no cigar on output set from file " + inputFileName);
}
}
} else {
System.out.println("no cigar on file " + inputFileName);
}
}
public static void main(String[] args) throws ImageWriteException, ImageReadException, IOException, ParseException {
String inputFileName = "C:\\Users\\Owner\\Pictures\\2021\\08 10 Florida and Puerto Rico\\LumixCamera\\P1000032.JPG";
String outputFileName = "C:\\Users\\Owner\\Pictures\\2021\\08 10 Florida and Puerto Rico\\LumixCamera\\P1000032_.JPG";
int hoursChange = -6;
updateHourOnFile(inputFileName, outputFileName, hoursChange);
}
}
**This is my code to sign a String.</br>**
package my.package;
import java.io.FileInputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.Signature;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.Store;
import sun.misc.BASE64Encoder;
public class SignMessage {
static final String KEYSTORE_FILE = "keys/certificates.p12";
static final String KEYSTORE_INSTANCE = "PKCS12";
static final String KEYSTORE_PWD = "test";
static final String KEYSTORE_ALIAS = "Key1";
public static void main(String[] args) throws Exception {
String text = "This is a message";
Security.addProvider(new BouncyCastleProvider());
KeyStore ks = KeyStore.getInstance(KEYSTORE_INSTANCE);
ks.load(new FileInputStream(KEYSTORE_FILE), KEYSTORE_PWD.toCharArray());
Key key = ks.getKey(KEYSTORE_ALIAS, KEYSTORE_PWD.toCharArray());
//Sign
PrivateKey privKey = (PrivateKey) key;
Signature signature = Signature.getInstance("SHA1WithRSA", "BC");
signature.initSign(privKey);
signature.update(text.getBytes());
//Build CMS
X509Certificate cert = (X509Certificate) ks.getCertificate(KEYSTORE_ALIAS);
List certList = new ArrayList();
CMSTypedData msg = new CMSProcessableByteArray(signature.sign());
certList.add(cert);
Store certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(privKey);
gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(sha1Signer, cert));
gen.addCertificates(certs);
CMSSignedData sigData = gen.generate(msg, false);
FileOutputStream sigfos = new FileOutputStream("D:\\SBI-DATA\\file\\signature_1.txt");
sigfos.write(Base64.encodeBase64(sp.getEncoded()));
sigfos.close();
}
}
Now, the EnvelopedData output will be used in the process to verify the signature by this way:
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Iterator;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Store;
import org.bouncycastle.util.encoders.Base64;
public class VerifySignature {
public static void main(String[] args) throws Exception {
File p7s = new File("D:\\SBI-DATA\\file\\signature_2.txt") ;
int size = ((int) p7s.length());
byte[] sig = new byte[size];
File f = new File("D:\\SBI-DATA\\file\\plain.txt") ;
int sizecontent = ((int) f.length());
byte[] Data_Bytes = new byte[sizecontent];
Security.addProvider(new BouncyCastleProvider());
CMSSignedData signedData = new CMSSignedData(new CMSProcessableByteArray(Data_Bytes), sig);
Store store = signedData.getCertificates();
SignerInformationStore signers = signedData.getSignerInfos();
Collection c = signers.getSigners();
Iterator it = c.iterator();
while (it.hasNext()) {
SignerInformation signer = (SignerInformation) it.next();
Collection certCollection = store.getMatches(signer.getSID());
Iterator certIt = certCollection.iterator();
X509CertificateHolder certHolder = (X509CertificateHolder) certIt.next();
X509Certificate certFromSignedData = new JcaX509CertificateConverter().setProvider(BC_PROVIDER).getCertificate(certHolder);
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC_PROVIDER).build(certFromSignedData))) {
System.out.println("Signature verified");
} else {
System.out.println("Signature verification failed");
}
}
}
}
Everything works good until signer.verify(..) due to the following Exception:
Exception in thread "main" org.bouncycastle.cms.CMSSignerDigestMismatchException: message-digest attribute value does not match calculated value
at org.bouncycastle.cms.SignerInformation.doVerify(Unknown Source)
at org.bouncycastle.cms.SignerInformation.verify(Unknown Source)
at my.package.VerifySignature.main(VerifySignature.java:64)
And I really don't know what I am doing wrong. Can someone please give me a hint of what is happening?
I think you are signing it twice, once directly using Signature and the other one using ContentSigner. You need only to sign the data, not the signature.
So the solution should be to replace signature.sign() with text.getBytes(), or text.getBytes(StandardCharsets.UTF_8) if you want to explicitly define a character set for text instead of using some system default.