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