如何手动解密EncryptedAssertion?OpenSaml Decrypter解密失败求助
Hey there, let's tackle this decryption headache step by step—I've wrestled with similar OpenSAML issues before, so let's break down what might be going wrong with both your out-of-the-box Decrypter attempt and your manual workaround.
First: Troubleshooting the OpenSAML Decrypter Failure
The "Failed to decrypt EncryptedData" error usually boils down to a handful of common misconfigurations. Let's rule these out first:
- Key loading mistakes: Double-check that you're using the correct private key (not a public key) and that your key store (PKCS#12/JKS) is loaded with the right password. It's easy to mix up key aliases or forget that some key stores require separate passwords for the store and the key itself.
- Algorithm mismatches: Inspect the
EncryptionMethodURI in your SAML response'sEncryptedDataelement. For example, if it's set tohttp://www.w3.org/2001/04/xmlenc#aes256-cbc, your Decrypter must be configured to use the matching Java algorithm (AES/CBC/PKCS5Padding)—using AES-GCM instead will fail immediately. - Missing KeyInfo resolution: If your SAML response includes a
KeyInfoelement with metadata about the encryption key, you need to configure aKeyInfoCredentialResolverfor OpenSAML to pick it up. Without this, the Decrypter can't map the encrypted key to your private key. - JCE policy restrictions: If you're using AES-256 encryption, older Java versions (pre-8u151) require the unlimited strength jurisdiction policy files. Even newer versions might need you to enable this via security properties.
Here's a quick corrected Decrypter setup to test:
// Load your private key credential (implement this method to fetch from your key store) Credential decryptionCred = getDecryptionPrivateKeyCredential(); // Configure KeyInfo resolver to use your credential BasicInlineKeyInfoCredentialResolver keyInfoResolver = new BasicInlineKeyInfoCredentialResolver(Collections.singletonList(decryptionCred)); // Initialize Decrypter with proper resolvers Decrypter decrypter = new Decrypter(null, keyInfoResolver, new InlineEncryptedKeyResolver()); decrypter.setRootInNewDocument(true); try { Assertion decryptedAssertion = decrypter.decrypt((EncryptedAssertion) samlResponse.getEncryptedAssertions().get(0)); } catch (DecryptionException e) { // Dig into the root cause—print the full stack trace, not just the top-level error e.printStackTrace(); // Check if e.getCause() is a NoSuchAlgorithmException or InvalidKeyException }
Second: Fixing Your Manual Decryption Attempt
Since you're using hybrid encryption (asymmetric key encrypts the symmetric data key), your manual workflow should follow this exact order. If your decrypted symmetric key is unreadable, you're likely skipping a step or using the wrong algorithm:
Extract the EncryptedKey and EncryptedData:
First, pull the two core elements from yourEncryptedAssertion—the encrypted symmetric key lives inEncryptedKey, and the encrypted assertion data is inEncryptedData.Decrypt the symmetric key correctly:
TheCipherValueinEncryptedKeyis Base64-encoded, so you need to decode it first. Then, use your private key with the exact algorithm specified in theEncryptedKey'sEncryptionMethodURI. For example:- If the URI is
http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p, useRSA/ECB/OAEPWithSHA-1AndMGF1Paddingin Java. - If it's
http://www.w3.org/2009/xmlenc11#rsa-oaep, useRSA/ECB/OAEPWithSHA-256AndMGF1Padding.
The decrypted result is a binary symmetric key—don't try to convert it to a string; keep it as a byte array for the next step.
- If the URI is
Decrypt the assertion data:
Now use the binary symmetric key to decrypt theEncryptedData'sCipherValue. Don't forget to extract the initialization vector (IV) if you're using a block cipher like AES-CBC—this is usually stored in theEncryptionMethod's parameters.
Here's a simplified code snippet for this flow:
// Parse your EncryptedAssertion from the SAML response EncryptedAssertion encryptedAssertion = ...; // Get EncryptedKey and EncryptedData EncryptedKey encryptedSymKey = encryptedAssertion.getEncryptedKeys().get(0); EncryptedData encryptedAssertionData = encryptedAssertion.getEncryptedData(); // Step 1: Decrypt the symmetric key byte[] encryptedSymKeyBytes = Base64.decodeBase64(encryptedSymKey.getCipherData().getCipherValue().getValue()); Cipher keyCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); // Match EncryptedKey's algorithm keyCipher.init(Cipher.DECRYPT_MODE, yourPrivateKey); byte[] symmetricKey = keyCipher.doFinal(encryptedSymKeyBytes); // Step 2: Decrypt the assertion data byte[] encryptedDataBytes = Base64.decodeBase64(encryptedAssertionData.getCipherData().getCipherValue().getValue()); // Extract IV (adjust parsing based on your XML structure) EncryptionMethod method = encryptedAssertionData.getEncryptionMethod(); String ivBase64 = method.getParameters().getDOM().getTextContent(); byte[] iv = Base64.decodeBase64(ivBase64); Cipher dataCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // Match EncryptedData's algorithm dataCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(symmetricKey, "AES"), new IvParameterSpec(iv)); byte[] decryptedAssertionBytes = dataCipher.doFinal(encryptedDataBytes); // Convert to readable XML String assertionXml = new String(decryptedAssertionBytes, StandardCharsets.UTF_8);
Quick Checks for Your Unreadable decryptedValue:
- Did you decode the Base64
CipherValuebefore decrypting? Skipping this will give garbage data. - Are you using the exact algorithm URI specified in the SAML response? Even a minor mismatch (SHA-1 vs SHA-256) will break decryption.
- Is your private key the correct one for the public key used to encrypt the symmetric key? Double-check key pairs—this is a super common mistake.
内容的提问来源于stack exchange,提问作者user1544460

