I need to generate a CMS with SHA1+RSA detached signature in PEM format over a xml file input. I need to make this from Java code in runtime. I need to avoid the use of an external tool like OpenSSL. This is because we need invoke some services with the generated signature from Java and manage error properly if an exception ocurred in the signature process (the input xml changes every day).
The file I have to sign looks like this:
<header>
<generationTime>2017-04-17T00:00:01-03:00</generationTime>
<expirationTime>2017-04-17T23:59:59-03:00</expirationTime>
</header>
Using OpenSSL, with a private key and a certificate, the signature is generated executing this command:
openssl cms -sign -in tra.xml -inkey MyPrivateKey -signer myCertificate.pem -out tra.xml.cms -outform PEM -nodetach
The generated PEM signature in that case is:
-----BEGIN CMS-----
MIIGdAYJKoZIhvcNAQcCoIIGZTCCBmECAQExDTALBglghkgBZQMEAgEwgaIGCSqG
SIb3DQEHAaCBlASBkTxoZWFkZXI+ICAgIA0KPGdlbmVyYXRpb25UaW1lPjIwMTct
MDQtMTdUMDA6MDA6MDEtMDM6MDA8L2dlbmVyYXRpb25UaW1lPg0KPGV4cGlyYXRp
b25UaW1lPjIwMTctMDQtMTdUMjM6NTk6NTktMDM6MDA8L2V4cGlyYXRpb25UaW1l
Pg0KPC9oZWFkZXI+DQqgggNOMIIDSjCCAjKgAwIBAgIII0Or3JGYSY4wDQYJKoZI
hvcNAQENBQAwODEaMBgGA1UEAwwRQ29tcHV0YWRvcmVzIFRlc3QxDTALBgNVBAoM
BEFGSVAxCzAJBgNVBAYTAkFSMB4XDTE3MDEyNjE2MDIwNFoXDTE5MDEyNjE2MDIw
NFowMDETMBEGA1UEAwwKYWNjZXNvQUZJUDEZMBcGA1UEBRMQQ1VJVCAyMDI5OTUw
Mzk2OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPhtRXT8FQPvcFvQ
CUSZaHTtcc864DsvP3zedpcr1gDLyJRMMlKnV0mZVJXEeC6eo6AV71kv2QpFUUp3
OGUAS/zJGXByCJ2trV/pXrvppmJvAJARlfw6KoqQBY+YYoIinIzCbUHdvoPwub2K
o7081VlmLxUffiDElbAi3gi41z/W6pD57i3U1uPjS45HRvIn7Vcv4epcH3x9+IDC
DEbZ0hsKIiuJrH4RO1k50gSSaXjvAQSG8kbEXMQ89AxAeynI8jk964JpHc0qLj6y
1sfvAyCSPq8ZFURribdboZi8G6oAccIM1pyMKA13+AcPkOFy0SyotjnFgrK2MMVZ
+vEgNwECAwEAAaNgMF4wDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBSzstP//em6
3t6NrxEhnNYgffJPbzAdBgNVHQ4EFgQUEuAlczdaDyI7hGuwyqR6ipLvTikwDgYD
VR0PAQH/BAQDAgXgMA0GCSqGSIb3DQEBDQUAA4IBAQA+Pg0RQ7J5qiViZMk94tgD
WAgTT0iIoVm65Xn2/czlBgefhxY6l4SKqQCONJpAMCUI2mEG6qgOg/u+GbN3pR+p
1FSC2yDETRIpf9nekooTEot6A9r2Huykd4Sp3QHZEly9Sx3+3ek+w7Mg0k/+AtgT
JodP0ArzCQyvBJCR8ZTTHjUazf2/9o0iEqQIKyp1vn2vv3JlMONBb7+ALqzCXgCb
FVjFpF8PpZyWM/+J6WVrU19hB3wsdyhLh0M5CiBQ19aGC8R/0bWm2w2P3awOn8r4
r/duYqdGzK/7zTpjtvk0VKax6/Pe5WIFLKXTP9LGpxbCQjxKpbVxMbzx1pDPGBjF
MYICVDCCAlACAQEwRDA4MRowGAYDVQQDDBFDb21wdXRhZG9yZXMgVGVzdDENMAsG
A1UECgwEQUZJUDELMAkGA1UEBhMCQVICCCNDq9yRmEmOMAsGCWCGSAFlAwQCAaCB
5DAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xNzA0
MTcxMzM3MDVaMC8GCSqGSIb3DQEJBDEiBCBL5i3jl4+rfSfo/Pcu/CbI6JHGj0jg
UGI/EucH7LBM6jB5BgkqhkiG9w0BCQ8xbDBqMAsGCWCGSAFlAwQBKjALBglghkgB
ZQMEARYwCwYJYIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqGSIb3DQMCAgIAgDAN
BggqhkiG9w0DAgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIBKDANBgkqhkiG9w0B
AQEFAASCAQAMNHskWrhZCu/DmFQLCrAweTEacCwTJdYOx+704PS6DkflXQLpD9q4
B0Psxx6gmN7HkHkrY4bD250TefZpKyD7IfJjdNQEz4SzgmtgMTl2a0JvlgpWSNjq
au0WMkFXnoSo0oJ3s4FSHWAe15DlNFQn9HbKfjI/sIHpkhgA0u/Kr6ZHUSIEnfxS
KVNxQ224uvFPGCggHnPIdtBRFgGn44J1hRyiYm0BLqJO5sAwV23gWB8OztsuBHqj
imi4WWXnCVPk7/6BMGNuLpUH3bH6nfIPDfSL7bb7vXRhcQrjTU8o38/C3gDsJr2A
4JNHkIjPMoo4l+wlS66MJQpOXadjYaFi
-----END CMS-----
Thats is what I need generate over Java 7.
I already read and make many test with Bouncy Castle and java.security.cert standard API, but I can't generate the same signature result. I checked internal representation from Bouncy Castle and the API is using DER format to hold the signature. And in the examples are always showing how to verify a signature, but no how to generate one and save it in a file or print it in PEM form.
Here is an example of how I generate a BC signature, but the result is pretty different from what I need:
public static String encryptSHA1RSA(String xmlPayload) throws Exception {
List certList = new ArrayList();
CMSTypedData msg = new CMSProcessableByteArray(xmlPayload.getBytes());
certList.add(CMSEncryptor.getSingCert());
Store certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(CMSEncryptor.getPrivateKey());
gen.addSignerInfoGenerator( new JcaSignerInfoGeneratorBuilder(
new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())
.build(sha1Signer, CMSEncryptor.getSingCert()));
gen.addCertificates(certs);
CMSSignedData sigData = gen.generate(msg, true);
ASN1InputStream asn1 = new ASN1InputStream(sigData.getEncoded());
FileOutputStream fos = new FileOutputStream(getSecurityFolderPath() + "/tra.test.cms");
DEROutputStream dos = new DEROutputStream(fos);
dos.writeObject(asn1.readObject());
dos.flush();
dos.close();
asn1.close();
return Base64Util.encodeBase64(new String(sigData.getEncoded()));
}
Is different also if I encode the result with base64:
return Base64Util.encodeBase64(new String(sigData.getEncoded()));
Any tips will be very apreciated
I've made a test using BouncyCastle (bcprov-jdk15on) 1.56 and Java 1.7
To convert your signature to PEM format, you can use BouncyCastle's JcaPEMWriter (or just PEMWriter for older versions), like this:
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
// ... used the same code you posted above ...
// *** NOTE: if you want a detached signature, change the second parameter to false ***
CMSSignedData sigData = gen.generate(msg, false);
// write sigData to output.pem file, using a pem writer
ContentInfo ci = ContentInfo.getInstance(ASN1Sequence.fromByteArray(sigData.getEncoded()));
JcaPEMWriter writer = new JcaPEMWriter(new FileWriter("output.pem"));
writer.writeObject(ci);
writer.close();
The result is slightly different, because BouncyCastle generates a file with BEGIN PKCS7 and END PKCS7 headers (instead of BEGIN CMS and END CMS):
-----BEGIN PKCS7-----
MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAaCA
JIAEgYg8aGVhZGVyPgo8Z2VuZXJhdGlvblRpbWU+MjAxNy0wNC0xN1QwMDowMDow
... lots of base64 lines ...
WHkpUQDxQj+v/SbMGa5+U7VC8+HNOfgFOba+U56QLhbhDEeaaozwATXveRkqhsdn
AAAAAAAA
-----END PKCS7-----
But the output file is a valid digital signature anyway. And both (PKCS7 and CMS headers) can be read by OpenSSL and BouncyCastle. So, unless you need exactly BEGIN CMS header, I believe this will be enough.
If you don't want to write to a file and get a String instead, you can use java.io.StringWriter combined with JcaPEMWriter:
StringWriter sw = new StringWriter();
JcaPEMWriter writer = new JcaPEMWriter(sw);
writer.writeObject(ci);
writer.close();
String pemString = sw.toString(); // pemString will be the PEM formatted string (with BEGIN PKCS7 header)
Related
So I have an X509Certificate that I encode like this
String base64 = Base64.getEncoder().encodeToString(certificate.getEncoded());
But this returns a string that looks like this (MII....)
Hence why I believe that when I run this part
PEMParser reader= new PEMParser (new StringReader(new String(Base64.getDecoder().decode(base64))));
PemObject object = reader.readPemObject();
The object is equal to null.
I believe that this is because the base64 encoded string is missing the header/footer -----BEGIN CERTIFCATE----- and -----END CERTIFICATE-----.
any idea how I can fix this?
The PEM encoding is derived from the DER encoding by first Base64 encoding the DER data with a line break after every 64 characters and adding a specific header and footer line.
Although this can be easily implemented, BouncyCastle provides convenient support for converting DER to PEM and vice versa. For writing PEM data JcaPEMWriter is used, for parsing PEM data PEMParser.
This applies not only to certificates, but also to public and private keys of various formats (PKCS#8, X.509/SPKI, PKCS#1).
The current question is about the conversion of a certificate. In this case the header line is -----BEGIN CERTIFICATE----- and the footer line is -----END CERTIFICATE-----. The following example shows the use of both classes for the conversion PEM to DER and DER to PEM:
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Base64;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemObjectGenerator;
...
// PEM encoded certificate
String cert = "-----BEGIN CERTIFICATE-----\r\n"
+ "MIIFlTCCA32gAwIBAgIJAO4YFLMMLNM2MA0GCSqGSIb3DQEBCwUAMGExCzAJBgNV\r\n"
...
+ "nZSJxV3jloZP3NJDIQOZ8zXBqzVfba9fOOZF1ghIa0wFuvH1Ip1vL1sdBdo4PFsY\r\n"
+ "BQfFgCihe1CeDfY3gNQVQSS/dQ5139+kBQBsYnEeWoz0CLQWhGp3B/8=\r\n"
+ "-----END CERTIFICATE-----";
// Convert PEM to DER
PEMParser pemParser = new PEMParser(new StringReader(cert));
PemObject pemObject = pemParser.readPemObject();
byte[] derCertificate = pemObject.getContent(); // the DER encoded certificate
System.out.println(Base64.getEncoder().encodeToString(derCertificate));
// Convert DER to PEM
StringWriter stringWriter = new StringWriter();
JcaPEMWriter jcaPEMWriter = new JcaPEMWriter(stringWriter);
jcaPEMWriter.writeObject((PemObjectGenerator)new PemObject("CERTIFICATE", pemObject.getContent()));
jcaPEMWriter.close();
String pemCertificate = stringWriter.toString(); // the PEM encoded certificate
System.out.println(pemCertificate);
The code requires the bcprov and bcpkix jar files.
Similarly, private and public keys can be converted, with only the CERTIFICATE string in the PemObject constructor needing to be adjusted:
format string
---------------------------------------
PKCS#8 PRIVATE KEY
X.509/SPKI PUBLIC KEY
PKCS#1, private RSA PRIVATE KEY
PKCS#1, public RSA PUBLIC KEY
I create a certificate with keytool:
keytool -genkeypair -alias sara -keyalg RSA -keysize 2048 -keypass
password -keystore "\Sviluppo\JavaKeyStore\keystore.jks" -storepass
12345678 -validity 360 -dname "cn=Sara, ou=***, o=***, l=Padova,
s=Italia, c=IT"
Then i want to sign a pdf with this certificate, i use Itextpdf to sign a pdf.
First I load private key and certificate from keystore:
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
File fileKeyStore = new File(pathKeyStore);
FileInputStream fis = new FileInputStream(fileKeyStore);
keyStore.load(fis, "12345678".toCharArray());
final PrivateKey privateKey = (PrivateKey) keyStore.getKey("sara", "password".toCharArray());
final Certificate certificate = keyStore.getCertificate(certID);
then I open document for calculate hash to sign:
PdfReader reader = new PdfReader(new RandomAccessFileOrArray(pdfInputPath), null);
OutputStream pdfOutputStream = new FileOutputStream(pdfOutputPath);
PdfStamper stp = PdfStamper.createSignature(reader, pdfOutputStream, '\0', tempPathFile, true)
PdfSignatureAppearance sap = stp.getSignatureAppearance();
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
dic.setDate(dateNow);
sap.setCryptoDictionary(dic);
sap.setCrypto(privateKey, keyStore.getCertificateChain("sara"), null, PdfSignatureAppearance.SELF_SIGNED);
HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
exc.put(PdfName.CONTENTS, (int) (6144 * 2 + 2));
sap.preClose(exc);
then calculate hash of sap.getRangeStream(), load certificate from keystore:
BufferedInputStream bis = new BufferedInputStream(sap.getRangeStream());
MessageDigest digest = MessageDigest.getInstance("SHA-256");
DigestInputStream dis = new DigestInputStream(bis, digest);
byte[] buff = new byte[512];
while (dis.read(buff) != -1) {
;
}
dis.close();
dis = null;
byte[] hashToSign= digest.digest();
bis.close();
I sign with certificate from keystore:
java.security.Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(hashToSign);
byte[] hashSigned = signature.sign();
at the end close pdf:
byte[] paddedSig = new byte[6144];
System.arraycopy(hashSigned, 0, paddedSig, 0, hashSigned.length);
PdfDictionary pdfDictionary = new PdfDictionary();
pdfDictionary.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
sap.close(pdfDictionary);
But the pdf signed is invalid: "There are errors in the formatting or information contained in this signature"
What's the problem, the certificare or signature?
Thanks for help
Sara
The cause for the "There are errors in the formatting or information contained in this signature" validation failure message is that your code puts a naked PKCS1 signature value where a full-fledged CMS signature container is expected:
You on the one hand use SELF_SIGNED in your sap.setCrypto which indicates that you want to create an adbe.x509.rsa_sha1 SubFilter signature, and on the other hand set the SubFilter to adbe.pkcs7.detached in your PdfSignature constructor.
This does not match at all, adbe.x509.rsa_sha1 uses naked PKCS1 signature values while adbe.pkcs7.detached uses CMS signature containers.
This should answer your question "What's the problem, the certificare or signature?"...
According to a comment you meanwhile found a solution in a copy of iText in Action, 2nd Edition.
Please be aware, though, that the iText signing API meanwhile has been substantially extended. If you are working with iText 5.5.x, you should download and read Digital Signatures for PDF Documents, a white paper by Bruno Lowagie (iText Software).
While the code from iText in Action, 2nd Edition, still focused on signatures according to ISO 32000-1:2008 (SOTA at the time of its publishing but not anymore), Digital Signatures for PDF Documents focuses on signatures according to PAdES which meanwhile have been included in ISO 32000-2:2017.
I'm trying to write matching code in Java, for this openssl operation:
openssl rsautl -sign
So far, I tried this:
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(privateKey, SecureRandom.getInstanceStrong());
ByteArrayInputStream bais = new ByteArrayInputStream(inputData);
byte[] sBuffer = new byte[1024];
int sBufferLen;
while ((sBufferLen = bais.read(sBuffer)) >= 0) {
sig.update(sBuffer, 0, sBufferLen);
}
bais.close();
byte[] signature = sig.sign();
Looks like the Java code calculates the SHA-256 hash for the inputData, then signs the hash and returns the signature only.
openssl, on the other hand seems to return the inputData along with the signature.
I am inferring this using the openssl rsautl -verify operation. Running this operation on the Java signed data returns the ASN1 encoded data with a sha256 object in it. Running this operation on the openssl signed data returns the actual input data.
Is there any way to mimic what openssl is doing - including the original data with the signature (detached signature?) using Java APIs?
According to the answer here, while signing:
Java does:
[hash data -> ASN.1 encode -> Pad -> modexp]
openssl only does:
[Pad -> modexp]
So I had to skip the first two steps in Java, so that it matches openssl rsautl -sign
To do that I looked at the code in the RSASignature class.
byte[] toBePadded = inputData.getBytes();
RSAPadding padding = RSAPadding.getInstance(1, 512, SecureRandom.getInstanceStrong());
byte[] toBeSigned = padding.pad(toBePadded);
byte[] opensslSignature = RSACore.rsa(toBeSigned, (RSAPrivateKey) privateKey, true);
Edit: Easier to just use "NONEwithRSA" signature type:
Signature sig = Signature.getInstance("NONEwithRSA");
I am new to Cryptography and so please excuse me if you think this is a basic question
I have a .p7b file which I need to read and extract the individual public certificates i.e the .cer files and store it in the key store. I need not worry about persisting in the key store as there is already a service which takes in the .cer file as byte[] and saves that.
What i want to know is , how do i read the .p7b and extract the individual .cer file? I know that can be done via the openSSL commands, but i need to do the same in java. I need to also read the Issued By name as that will be used as a unique key to persist the certificate.
Thanks in advance
You can get the certificates from a PKCS#7 object with BouncyCastle. Here is a quick code sample:
public Collection<X59Certificate> getCertificates(String path) throws Exception
{
Security.addProvider(new BouncyCastleProvider());
CMSSignedData sd = new CMSSignedData(new FileInputStream(path));
X509Store store = sd.getCertificates("Collection", "BC");
Collection<X509Certificate> certificates = store.getMatches(X509CertStoreSelector.getInstance(new X509CertSelector()));
return certificates;
}
Note that a PKCS#7 may contain more than one certificate. Most of the time it includes intermediate certification authority certificates required to build the certificate chain between the end-user certificate and the root CA.
I was successfully able to read the individual .X509 certificates from the p7b files. Here are the steps
First step includes, getting a byte[] from the java.io.File. The steps include to remove the -----BEGIN PKCS7----- and -----END PKCS7----- from the file, and decode the remaining base64 encoded String.
BufferedReader reader = new BufferedReader(new FileReader(file));
StringBuilder cerfile = new StringBuilder();
String line = null;
while(( line = reader.readLine())!=null){
if(!line.contains("PKCS7")){
cerfile.append(line);
}
}
byte[] fileBytes = Base64.decode(cerfile.toString().getBytes());
The next step is to use the BouncyCastle api to parse the file
CMSSignedData dataParser = new CMSSignedData(trustBundleByte);
ContentInfo contentInfo = dataParser.getContentInfo();
SignedData signedData = SignedData.getInstance(contentInfo.getContent());
CMSSignedData encapInfoBundle = new CMSSignedData(new CMSProcessableByteArray(signedData.getEncapContentInfo().getContent().getDERObject().getEncoded()),contentInfo);
SignedData encapMetaData = SignedData.getInstance(encapInfoBundle.getContentInfo().getContent());
CMSProcessableByteArray cin = new CMSProcessableByteArray(((ASN1OctetString)encapMetaData.getEncapContentInfo().getContent()).getOctets());
CertificateFactory ucf = CertificateFactory.getInstance("X.509");
CMSSignedData unsignedParser = new CMSSignedData(cin.getInputStream());
ContentInfo unsginedEncapInfo = unsignedParser.getContentInfo();
SignedData metaData = SignedData.getInstance(unsginedEncapInfo.getContent());
Enumeration certificates = metaData.getCertificates().getObjects();
// Build certificate path
while (certificates.hasMoreElements()) {
DERObject certObj = (DERObject) certificates.nextElement();
InputStream bin = new ByteArrayInputStream(certObj.getDEREncoded());
X509Certificate cert = (X509Certificate) ucf.generateCertificate(bin);
X500Name x500name = new JcaX509CertificateHolder(cert).getSubject();
RDN cn = x500name.getRDNs(BCStyle.CN)[0];
}
The above steps are working fine, but i am sure there are other solutions with less lines of code to achieve this. I am using bcjdk16 jars.
OK, this is another of those "I have no real idea where to start" questions, so hopefully the answer is simple. However, I don't really know what to search for, and my attempts so far haven't turned up much of use.
I want to read a private key from a (currently on-disk) file. Ultimately the key will reside in a database, but this will be good enough for the moment and that difference should have no real bearing on parsing the key material. I have been able to create a Credential instance that holds the public part of the key (confirmed by debugger), but I can't seem to figure out how to read the private part. The key pair was generated as:
openssl genrsa 512 > d:\host.key
openssl req -new -x509 -nodes -sha1 -days 365 -key d:\host.key > d:\host.cert
(Yes, I know that 512 bit RSA keys were broken long ago. However, for trying to get the API to work, I see no reason to exhaust the system entropy supply needlessly.)
The code thus far is:
import org.opensaml.xml.security.credential.Credential;
import org.opensaml.xml.security.x509.BasicX509Credential;
private Credential getSigningCredential()
throws java.security.cert.CertificateException, IOException {
BasicX509Credential credential = new BasicX509Credential();
credential.setUsageType(UsageType.SIGNING);
// read public key
InputStream inStream = new FileInputStream("d:\\host.cert");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);
inStream.close();
credential.setEntityCertificate(cert);
// TODO: read private key
// done.
return credential;
}
But how do I read the file host.key into the private key portion of credential, so I can use the generated Credential instance to sign data?
BasicX509Credential is not part from standard Java; I suppose you are talking about org.opensaml.xml.security.x509.BasicX509Credential from OpenSAML.
You want a PrivateKey which you will set with credential.setPrivateKey(). To get a PrivateKey, you must first convert the private key into a format that Java can read, namely PKCS#8:
openssl pkcs8 -topk8 -nocrypt -outform DER < D:\host.key > D:\host.pk8
Then, from Java:
RandomAccessFile raf = new RandomAccessFile("d:\\host.pk8", "r");
byte[] buf = new byte[(int)raf.length()];
raf.readFully(buf);
raf.close();
PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(buf);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privKey = kf.generatePrivate(kspec);
and voilĂ ! you have your PrivateKey.
By default, openssl writes key in its own format (for RSA keys, PKCS#8 happens to be a wrapper around that format), and it encodes them in PEM, which Base64 with a header and a footer. Both characteristics are unsupported by plain Java, hence the conversion to PKCS#8. The -nocrypt option is because PKCS#8 supports optional password-based encryption of private key.
Warning: you really really want to use a longer RSA key. 512 bits are weak; a 512-bit RSA key was broken in 1999 with a few hundred computers. In 2011, with 12 years of technological advances, one should assume that a 512-bit RSA key can be broken by almost anybody. Therefore, use 1024-bit RSA keys at least (preferably, 2048-bit; the computational overhead when using the key is not that bad, you will still be able to perform hundred of signatures per second).
This question is related to SAML and is also relevant for someone who wants to retrieve a private key for signing an XMLObject. The answer above works great and it also possible to retrieve a private key from a keystore as well:
Properties sigProperties = new Properties();
sigProperties.put("org.apache.ws.security.crypto.provider","org.apache.ws.security.components.crypto.Merlin");
sigProperties.put("org.apache.ws.security.crypto.merlin.keystore.type","jks");
sigProperties.put("org.apache.ws.security.crypto.merlin.keystore.password","keypass");
sigProperties.put("org.apache.ws.security.crypto.merlin.keystore.alias","keyalias");
sigProperties.put("org.apache.ws.security.crypto.merlin.keystore.file","keystore.jks");
Crypto issuerCrypto = CryptoFactory.getInstance(sigProperties);
String issuerKeyName = (String) sigProperties.get("org.apache.ws.security.crypto.merlin.keystore.alias");
//See http://ws.apache.org/wss4j/xref/org/apache/ws/security/saml/ext/AssertionWrapper.html 'signAssertion' method
// prepare to sign the SAML token
CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
cryptoType.setAlias(issuerKeyName);
X509Certificate[] issuerCerts = issuerCrypto.getX509Certificates(cryptoType);
if (issuerCerts == null) {
throw new WSSecurityException(
"No issuer certs were found to sign the SAML Assertion using issuer name: "
+ issuerKeyName);
}
String password = ADSUnitTestUtils.getPrivateKeyPasswordFromAlias(issuerKeyName);
PrivateKey privateKey = null;
try {
privateKey = issuerCrypto.getPrivateKey(issuerKeyName, password);
} catch (Exception ex) {
throw new WSSecurityException(ex.getMessage(), ex);
}
BasicX509Credential signingCredential = new BasicX509Credential();
signingCredential.setEntityCertificate(issuerCerts[0]);
signingCredential.setPrivateKey(privateKey);
signature.setSigningCredential(signingCredential);
This is more code than the original query requested, but it looks they are trying to get at a BasicX509Credential.
Thanks,
Yogesh