How to sign signature data using bouncy castle? - java

**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.

Related

How to add digital signature to Excel and JPG files?

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);
}
}
}

Encrypt a XML file with XmlCipher (RSA)

I just need to encrypt some XML elements with a public key. I successfully can use this code with a simetric algorithm (XMLCipher.AES_128), but failed when try use XMLCipher.RSA_v1dot5.
That is the code:
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.apache.xml.security.encryption.XMLCipher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class XmlEncryption {
private static final String MENSAGEM_ENTIDADE_1 = "mensagem1";
private static final String MENSAGEM_ENTIDADE_2 = "mensagem2";
public static void main(String[] args) throws Exception {
/*
* Encrypt a file with 2 diferent assimetric keys
*/
// parse file into document
// Document document = EncryptToolExtended.parseFile("teste.xml");
Document document = EncryptToolExtended.parseFile("teste.xml");
// generate the keys
KeyPair entity1KeyPair = EncryptToolExtended.GenerateAssymmetricKey();
//KeyPair entity2KeyPair = EncryptToolExtended.GenerateAssymmetricKey();
// specify the element to encrypt
Element rootElement = document.getDocumentElement();
Element mensagem1ToEncrypt = rootElement;
Element mensagem2ToEncrypt = rootElement;
mensagem1ToEncrypt = (Element) rootElement.getElementsByTagName(
MENSAGEM_ENTIDADE_1).item(0);
mensagem2ToEncrypt = (Element) rootElement.getElementsByTagName(
MENSAGEM_ENTIDADE_2).item(0);
if (mensagem1ToEncrypt == null || mensagem2ToEncrypt == null) {
System.err.println("Unable to find element: " + MENSAGEM_ENTIDADE_1
+ " or " + MENSAGEM_ENTIDADE_2);
System.exit(1);
}
// initialize cipher
Security.addProvider(new BouncyCastleProvider());
XMLCipher xmlCipher = XMLCipher.getInstance(XMLCipher.RSA_v1dot5);
xmlCipher.init(XMLCipher.ENCRYPT_MODE, entity1KeyPair.getPublic());
// add key info to encrypted data element
// EncryptedData encryptedDataElement = xmlCipher.getEncryptedData();
// KeyInfo keyInfo = new KeyInfo(document);
// keyInfo.add(entity1KeyPair.getPublic());
// encryptedDataElement.setKeyInfo(keyInfo);
// do the actual encryption
boolean encryptContentsOnly = true;
xmlCipher.doFinal(document, mensagem1ToEncrypt);
xmlCipher.doFinal(document, mensagem1ToEncrypt, encryptContentsOnly);
// write the results to a file
// EncryptToolExtended.writeEncryptedDocToFile(document, "encc.xml");
}
public static Document parseFile(String fileName) throws Exception {
javax.xml.parsers.DocumentBuilderFactory dbf = javax.xml.parsers.DocumentBuilderFactory
.newInstance();
dbf.setNamespaceAware(true);
javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(fileName);
return document;
}
public static KeyPair GenerateAssymmetricKey() throws Exception {
Security.addProvider(new BouncyCastleProvider());
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
return keyGen.genKeyPair();
}
}
Exception:
java.lang.IllegalArgumentException: unknown parameter type.
at org.bouncycastle.jce.provider.JCERSACipher.engineInit(Unknown Source)
at javax.crypto.Cipher.init(Cipher.java:1346)
at javax.crypto.Cipher.init(Cipher.java:1282)
at org.apache.xml.security.encryption.XMLCipher.encryptData(XMLCipher.java:1184)
at org.apache.xml.security.encryption.XMLCipher.encryptData(XMLCipher.java:1136)
at org.apache.xml.security.encryption.XMLCipher.encryptElement(XMLCipher.java:869)
at org.apache.xml.security.encryption.XMLCipher.doFinal(XMLCipher.java:987)
at XmlEncryption.main(XmlEncryption.java:84)
Any tips?
Thanks

Correct way to sign and verify signature using bouncycastle

I am using bcmail-jdk16-1.46.jar and bcprov-jdk16-1.46.jar (Bouncycastle libraries) to sign a string and then verify the signature.
This is my code to sign a string:
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);
BASE64Encoder encoder = new BASE64Encoder();
String signedContent = encoder.encode((byte[]) sigData.getSignedContent().getContent());
System.out.println("Signed content: " + signedContent + "\n");
String envelopedData = encoder.encode(sigData.getEncoded());
System.out.println("Enveloped data: " + envelopedData);
}
}
Now, the EnvelopedData output will be used in the process to verify the signature:
package my.package;
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 {
String envelopedData = "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIAwggLQMIIC" +
"OQIEQ479uzANBgkqhkiG9w0BAQUFADCBrjEmMCQGCSqGSIb3DQEJARYXcm9zZXR0YW5ldEBtZW5k" +
"ZWxzb24uZGUxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIEwZCZXJsaW4xDzANBgNVBAcTBkJlcmxpbjEi" +
"MCAGA1UEChMZbWVuZGVsc29uLWUtY29tbWVyY2UgR21iSDEiMCAGA1UECxMZbWVuZGVsc29uLWUt" +
"Y29tbWVyY2UgR21iSDENMAsGA1UEAxMEbWVuZDAeFw0wNTEyMDExMzQyMTlaFw0xOTA4MTAxMzQy" +
"MTlaMIGuMSYwJAYJKoZIhvcNAQkBFhdyb3NldHRhbmV0QG1lbmRlbHNvbi5kZTELMAkGA1UEBhMC" +
"REUxDzANBgNVBAgTBkJlcmxpbjEPMA0GA1UEBxMGQmVybGluMSIwIAYDVQQKExltZW5kZWxzb24t" +
"ZS1jb21tZXJjZSBHbWJIMSIwIAYDVQQLExltZW5kZWxzb24tZS1jb21tZXJjZSBHbWJIMQ0wCwYD" +
"VQQDEwRtZW5kMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+X1g6JvbdwJI6mQMNT41GcycH" +
"UbwCFWKJ4qHDaHffz3n4h+uQJJoQvc8yLTCfnl109GB0yL2Y5YQtTohOS9IwyyMWBhh77WJtCN8r" +
"dOfD2DW17877te+NlpugRvg6eOH6np9Vn3RZODVxxTyyJ8pI8VMnn13YeyMMw7VVaEO5hQIDAQAB" +
"MA0GCSqGSIb3DQEBBQUAA4GBALwOIc/rWMAANdEh/GgO/DSkVMwxM5UBr3TkYbLU/5jg0Lwj3Y++" +
"KhumYSrxnYewSLqK+JXA4Os9NJ+b3eZRZnnYQ9eKeUZgdE/QP9XE04y8WL6ZHLB4sDnmsgVaTU+p" +
"0lFyH0Te9NyPBG0J88109CXKdXCTSN5gq0S1CfYn0staAAAxggG9MIIBuQIBATCBtzCBrjEmMCQG" +
"CSqGSIb3DQEJARYXcm9zZXR0YW5ldEBtZW5kZWxzb24uZGUxCzAJBgNVBAYTAkRFMQ8wDQYDVQQI" +
"EwZCZXJsaW4xDzANBgNVBAcTBkJlcmxpbjEiMCAGA1UEChMZbWVuZGVsc29uLWUtY29tbWVyY2Ug" +
"R21iSDEiMCAGA1UECxMZbWVuZGVsc29uLWUtY29tbWVyY2UgR21iSDENMAsGA1UEAxMEbWVuZAIE" +
"Q479uzAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUx" +
"DxcNMTMwNTIxMDE1MDUzWjAjBgkqhkiG9w0BCQQxFgQU8mE6gw6iudxLUc9379lWK0lUSWcwDQYJ" +
"KoZIhvcNAQEBBQAEgYB5mVhqJu1iX9nUqfqk7hTYJb1lR/hQiCaxruEuInkuVTglYuyzivZjAR54" +
"zx7Cfm5lkcRyyxQ35ztqoq/V5JzBa+dYkisKcHGptJX3CbmmDIa1s65mEye4eLS4MTBvXCNCUTb9" +
"STYSWvr4VPenN80mbpqSS6JpVxjM0gF3QTAhHwAAAAAAAA==";
Security.addProvider(new BouncyCastleProvider());
CMSSignedData cms = new CMSSignedData(Base64.decode(envelopedData.getBytes()));
Store store = cms.getCertificates();
SignerInformationStore signers = cms.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 cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder);
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))) {
System.out.println("verified");
}
}
}
}
Everything works fine 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)
Can someone please give me a hint of what could be happening?
PS. If someone wants to test above code you will need the test certificate file that I am using to replicate this, just download it from here:
https://www.dropbox.com/s/zs4jo1a86v8qamw/certificates.p12?dl=0
The
gen.generate(msg, false)
means the signed data is not encapsulated in the signature. This is fine if you want to create a detached signature, but it does mean that when you go to verify the SignedData you have to use the CMSSignedData constructor that takes a copy of the data as well - in this case the code is using the single argument constructor which has to assume the signed data was encapsulated (so for this case will be empty), with the result that the attempt at verification is failing.
There are two kinds of CMSSignedData object generated using CMSSignedDataGenerator They are generated by the following way:
The one below generates a CMSSignedData object carrying a detached CMS signature
gen.generate(cmsdata);
The code below creates a CMSSignedData carrying a detached CMS signature, having the data encapsulated
gen.generate(cmsdata, true);
So verifying them requires 2 approaches
Approach No.1 to verify detached signature with encapsulated data
//sig is the Signature object
CMSSignedData signedData = new CMSSignedData(Base64.decode(sig.getBytes()));
Approach No.2 to verify detached signature without encapsulated data, just the detached signature
//Create a CMSProcessable object, specify any encoding, I have used mine
CMSProcessable signedContent = new CMSProcessableByteArray(content.getBytes("ISO-8859-1"));
//Create a InputStream object
InputStream is = new ByteArrayInputStream(Base64.decode(sig.getBytes()));
//Pass them both to CMSSignedData constructor
CMSSignedData signedData = new CMSSignedData(signedContent, is);
Rest of the code for verification remains the same
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 cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder);
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))) {
ret = true;
}
}
If we use signature.sign() as in the OP's answer, we won't be able to retrieve the original message, because its only the signature.
You should just input the original text bytes rather than the signed content. Basically, ignore this part:
//Sign
PrivateKey privKey = (PrivateKey) key;
Signature signature = Signature.getInstance("SHA1WithRSA", "BC");
signature.initSign(privKey);
signature.update(text.getBytes());
and just input as:
CMSTypedData msg = new CMSProcessableByteArray(text.getBytes());
You can find answer at this link here You need to just add some headers to message or just add one blank line before message then sign the message then it will work fine.
Got it working for detached signature :D
package signature;
import java.security.Provider;
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.CMSProcessable;
import org.bouncycastle.cms.CMSProcessableByteArray;
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 {
static final String DIGEST_SHA1 = "SHA1withRSA";
static final String BC_PROVIDER = "BC";
public static void main(String[] args) throws Exception {
String envelopedData = "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIAwggLQMIIC" +
"OQIEQ479uzANBgkqhkiG9w0BAQUFADCBrjEmMCQGCSqGSIb3DQEJARYXcm9zZXR0YW5ldEBtZW5k" +
"ZWxzb24uZGUxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIEwZCZXJsaW4xDzANBgNVBAcTBkJlcmxpbjEi" +
"MCAGA1UEChMZbWVuZGVsc29uLWUtY29tbWVyY2UgR21iSDEiMCAGA1UECxMZbWVuZGVsc29uLWUt" +
"Y29tbWVyY2UgR21iSDENMAsGA1UEAxMEbWVuZDAeFw0wNTEyMDExMzQyMTlaFw0xOTA4MTAxMzQy" +
"MTlaMIGuMSYwJAYJKoZIhvcNAQkBFhdyb3NldHRhbmV0QG1lbmRlbHNvbi5kZTELMAkGA1UEBhMC" +
"REUxDzANBgNVBAgTBkJlcmxpbjEPMA0GA1UEBxMGQmVybGluMSIwIAYDVQQKExltZW5kZWxzb24t" +
"ZS1jb21tZXJjZSBHbWJIMSIwIAYDVQQLExltZW5kZWxzb24tZS1jb21tZXJjZSBHbWJIMQ0wCwYD" +
"VQQDEwRtZW5kMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+X1g6JvbdwJI6mQMNT41GcycH" +
"UbwCFWKJ4qHDaHffz3n4h+uQJJoQvc8yLTCfnl109GB0yL2Y5YQtTohOS9IwyyMWBhh77WJtCN8r" +
"dOfD2DW17877te+NlpugRvg6eOH6np9Vn3RZODVxxTyyJ8pI8VMnn13YeyMMw7VVaEO5hQIDAQAB" +
"MA0GCSqGSIb3DQEBBQUAA4GBALwOIc/rWMAANdEh/GgO/DSkVMwxM5UBr3TkYbLU/5jg0Lwj3Y++" +
"KhumYSrxnYewSLqK+JXA4Os9NJ+b3eZRZnnYQ9eKeUZgdE/QP9XE04y8WL6ZHLB4sDnmsgVaTU+p" +
"0lFyH0Te9NyPBG0J88109CXKdXCTSN5gq0S1CfYn0staAAAxggG9MIIBuQIBATCBtzCBrjEmMCQG" +
"CSqGSIb3DQEJARYXcm9zZXR0YW5ldEBtZW5kZWxzb24uZGUxCzAJBgNVBAYTAkRFMQ8wDQYDVQQI" +
"EwZCZXJsaW4xDzANBgNVBAcTBkJlcmxpbjEiMCAGA1UEChMZbWVuZGVsc29uLWUtY29tbWVyY2Ug" +
"R21iSDEiMCAGA1UECxMZbWVuZGVsc29uLWUtY29tbWVyY2UgR21iSDENMAsGA1UEAxMEbWVuZAIE" +
"Q479uzAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUx" +
"DxcNMTMwNTIxMDE1MDUzWjAjBgkqhkiG9w0BCQQxFgQU8mE6gw6iudxLUc9379lWK0lUSWcwDQYJ" +
"KoZIhvcNAQEBBQAEgYB5mVhqJu1iX9nUqfqk7hTYJb1lR/hQiCaxruEuInkuVTglYuyzivZjAR54" +
"zx7Cfm5lkcRyyxQ35ztqoq/V5JzBa+dYkisKcHGptJX3CbmmDIa1s65mEye4eLS4MTBvXCNCUTb9" +
"STYSWvr4VPenN80mbpqSS6JpVxjM0gF3QTAhHwAAAAAAAA==";
String Sig_Bytes ="YduK22AlMLSXV3ajX5r/pX5OQ0xjj58uhGT9I9MvOrz912xNHo+9OiOKeMOD+Ys2/LUW3XaN6T+/"+
"tuRM5bi4RK7yjaqaJCZWtr/O4I968BQGgt0cyNvK8u0Jagbr9MYk6G7nnejbRXYHyAOaunqD05lW"+
"U/+g92i18dl0OMc50m4=";
Provider provider = new BouncyCastleProvider();
Security.addProvider(provider);
CMSSignedData signedData = new CMSSignedData(Base64.decode(envelopedData.getBytes()));
CMSProcessable cmsProcesableContent = new CMSProcessableByteArray(Base64.decode(Sig_Bytes.getBytes()));
signedData = new CMSSignedData(cmsProcesableContent, Base64.decode(envelopedData.getBytes()));
// Verify signature
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");
}
}
}
}

Java AES 256 CBC mode not working propery

Here's a ruby code to do AES in ECB and CBC:
require 'openssl'
require 'base64'
def encrypt(data, key, cipher_type)
aes = OpenSSL::Cipher::Cipher.new(cipher_type)
key = key.ljust(32, "\0")
aes.encrypt
aes.key = key
Base64.encode64(aes.update(data) + aes.final).tr("\n","")
end
puts encrypt("XJ5QJSVMKZGBOQO7HMSIJO5BERW2OYWDVNPM3BH32NLSWUCNJ4FIP3BML7EKUBNO", "000000", 'AES-256-ECB')
puts encrypt("XJ5QJSVMKZGBOQO7HMSIJO5BERW2OYWDVNPM3BH32NLSWUCNJ4FIP3BML7EKUBNO", "000000", 'AES-256-CBC')
And here's the Java Equivalent:
import org.apache.commons.codec.binary.Base64;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class AESTest
{
public static void main(String [] args)
{
System.out.println(AESEncryptToBase64("AES/ECB/PKCS5padding", "000000", "XJ5QJSVMKZGBOQO7HMSIJO5BERW2OYWDVNPM3BH32NLSWUCNJ4FIP3BML7EKUBNO"));
System.out.println(AESEncryptToBase64("AES/CBC/PKCS5padding", "000000", "XJ5QJSVMKZGBOQO7HMSIJO5BERW2OYWDVNPM3BH32NLSWUCNJ4FIP3BML7EKUBNO"));
}
/**
*
* #param secret
* #param cleartext
* #return encrypted b64 string
*/
public static String AESEncryptToBase64(String cypher, String secret, String clearText) {
byte[] rawKey = new byte[32];
java.util.Arrays.fill(rawKey, (byte) 0);
byte[] secretBytes = secret.getBytes();
for(int i = 0; i &lt secretBytes.length; i++){
rawKey[i] = secretBytes[i];
}
SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
try{
Cipher cipher = Cipher.getInstance(cypher);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encryptedData = cipher.doFinal(clearText.getBytes());
if(encryptedData == null) return null;
// return "l";
return Base64.encodeBase64String(encryptedData);
} catch (Exception e){
e.printStackTrace();
}
return null;
}
}
COMPILE: commons jar: http://apache.mirrors.pair.com//commons/codec/binaries/commons-codec-1.7-bin.zip
$ javac -cp .:commons-codec-1.7.jar AESTest.java
RUN
$ ruby aestest.rb
hYnClaUD9brJfNpEp4YDH0l1Y/QBlGkclnVN8MObNZFsvykd2da8iT2pcwLftNfox1HK/KFWrdfXt0qhP0Aq/fudP1FPIhF3vUTOEDzJbiY=
hYnClaUD9brJfNpEp4YDH5xcdKI4W5soPmWMpU+NikmAEKGSZkDP3KaJVSqRyOHt3JlcoyQzPbuoHxPV6kw6GH/4atDrcmCwV5LacTp+mBg=
$ java -cp .:commons-codec-1.7.jar AESTest
hYnClaUD9brJfNpEp4YDH0l1Y/QBlGkclnVN8MObNZFsvykd2da8iT2pcwLftNfox1HK/KFWrdfXt0qhP0Aq/fudP1FPIhF3vUTOEDzJbiY=
kZZNkbxis/W9UtEgRkxakGH28QetvK4lbf/SxBLrNDYPkGnf3w4MwonOCsoi9FjLAQ34aElOJ3KUjm62fiYLWxwNiE/wls7AcQnXLD19ano=
Notice that ECB mode works exactly on both. But CBC mode is different. I ran this also on C and it turns out that Ruby is correct, Java is not.
What am I doing wrong in Java?
For CBC you need to provide an initialization vector, for example:
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
have an if statement in your code and two different inits. The one for ECB is fine, and this one won't work with ECB.

java.lang.NoClassDefFoundError when adding a classpath

Code:
import org.apache.commons.codec.binary.Base64;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class AESTest
{
public static void main(String [] args)
{
String enc = AESEncryptToBase64("000000", "XJ5QJSVMKZGBOQO7HMSIJO5BERW2OYWDVNPM3BH32NLSWUCNJ4FIP3BML7EKUBNO");
System.out.println(enc);
}
/**
*
* #param secret
* #param cleartext
* #return encrypted b64 string
*/
public static String AESEncryptToBase64(String secret, String clearText) {
byte[] rawKey = new byte[32];
java.util.Arrays.fill(rawKey, (byte) 0);
byte[] secretBytes = secret.getBytes();
for(int i = 0; i &lt secretBytes.length; i++){
rawKey[i] = secretBytes[i];
}
SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
try{
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encryptedData = cipher.doFinal(clearText.getBytes());
if(encryptedData == null) return null;
// return "l";
return Base64.encodeBase64String(encryptedData);
} catch (Exception e){
e.printStackTrace();
}
return null;
}
}
Compile And run:
$ javac -cp "commons-codec-1.7.jar" AESTest.java
$ java -cp "commons-codec-1.7.jar" AESTest
Exception in thread "main" java.lang.NoClassDefFoundError: AESTest
Caused by: java.lang.ClassNotFoundException: AESTest
Here's the apache-commons-codec:
http://apache.mirrors.pair.com//commons/codec/binaries/commons-codec-1.7-bin.zip
Include . into your classpath: java -cp ".:commons-codec-1.7.jar" AESTest
This will tell JVM to include classes from current folder to classpath

Categories

Resources