Preview:
public static String generateXMLSignature(String docBodyString){
	// 1. Apply the Transforms, as determined by the application, to the data object.
	// (no transforms are done, since the body should be delivered in canonicalized form (Force.com offers no canonicalization algorithm))
	
	// 2. Calculate the digest value over the resulting data object. 
	
	Blob bodyDigest = Crypto.generateDigest('SHA1',Blob.valueOf(docBodyString));
	
	// 3. Create a Reference element, including the (optional) identification of the data object, any (optional) transform elements, the digest algorithm and the DigestValue.
	// (Note, it is the canonical form of these references that are signed and validated in next steps.)

	String referenceString = '';
	referenceString += '';
	referenceString += '<ds:Reference URI="#msgBody">';
	referenceString += '<ds:Transforms>';
	referenceString += '<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>';
	referenceString += '<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:Transform>';
	referenceString += '</ds:Transforms>';
	referenceString += '<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>';
	referenceString += '<ds:DigestValue>'+EncodingUtil.base64Encode(bodyDigest)+'</ds:DigestValue>';
	referenceString += '</ds:Reference>';		 
	
	// 4. Create SignedInfo element with SignatureMethod, CanonicalizationMethod and Reference(s).
	String signedInfoString = '';
	signedInfoString += '<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">';
	signedInfoString += '<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:CanonicalizationMethod>';
	signedInfoString += '<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>';
	signedInfoString += referenceString;
	signedInfoString += '</ds:SignedInfo>';
	
	// 5. Canonicalize and then calculate the SignatureValue over SignedInfo based on algorithms specified in SignedInfo.
	// (no canonicalization is done, since the signedinfo element should be delivered in canonicalized form (Force.com offers no canonicalization algorithm))

	String algorithmName = 'RSA-SHA1';
	// decrypted private key pkcs8 format from certificate
	String key = '[decryptedPrivateKeypkcs8formatfromcertificate]';
	Blob privateKey = EncodingUtil.base64Decode(key);
	
	Blob siBlob = Blob.valueOf(signedInfoString);
	
	Blob signatureValue = Crypto.sign(algorithmName, siBlob, privateKey);
	String signatureValueString = EncodingUtil.base64Encode(signatureValue);

	// 6. Construct the Signature element that includes SignedInfo, Object(s) (if desired, encoding may be different than that used for signing), KeyInfo (if required), and SignatureValue. 
	String signatureString = '';
	
	signatureString += '<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">';
	signatureString += signedInfoString; 
	signatureString += '<ds:SignatureValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">'+signatureValueString+'</ds:SignatureValue>';
	signatureString += '<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">';
	signatureString += '<ds:X509Data xmlns:ds="http://www.w3.org/2000/09/xmldsig#">';
	signatureString += '<ds:X509Certificate xmlns:ds="http://www.w3.org/2000/09/xmldsig#">[the certificate used for signing]</ds:X509Certificate>';
	signatureString += '</ds:X509Data>';
	signatureString += '</ds:KeyInfo>';
	signatureString += '</ds:Signature>';
	
	return signatureString;
}	
downloadDownload PNG downloadDownload JPEG downloadDownload SVG

Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!

Click to optimize width for Twitter