使用 OpenSAML 在 Java 中使用 SAML 2.0 解密加密断言

Posted

技术标签:

【中文标题】使用 OpenSAML 在 Java 中使用 SAML 2.0 解密加密断言【英文标题】:Decrypting encrypted assertion using SAML 2.0 in java using OpenSAML 【发布时间】:2012-03-14 10:03:07 【问题描述】:

我在尝试使用 SAML 2.0 解密加密断言时遇到问题。我使用的库是 OpenSAML Java 库 2.5.2。

加密的断言如下所示:

<EncryptedAssertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
<enc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" 
    xmlns:enc="http://www.w3.org/2001/04/xmlenc#">
  <enc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" />
  <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
    <e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#">
      <e:EncryptionMethod 
       Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
      </e:EncryptionMethod>
      <KeyInfo>
        <o:SecurityTokenReference 
           xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-
                    1.0.xsd">
          <o:KeyIdentifier 
            ValueType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-
                      1.1#ThumbprintSHA1"
            EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-
                      message-security-1.0#Base64Binary">
          1H3mV/pJAlVZAst/Dt0rqbBd67g=
          </o:KeyIdentifier>
        </o:SecurityTokenReference>
      </KeyInfo>
      <e:CipherData>
        <e:CipherValue>
   ... ENCRYPTED KEY HERE ...
        </e:CipherValue>
      </e:CipherData>
    </e:EncryptedKey>
  </KeyInfo>
  <enc:CipherData>
    <enc:CipherValue>
    ... ENCRYPTED ASSERTIONS HERE ...
    </enc:CipherValue>
  </enc:CipherData>
</enc:EncryptedData>
</EncryptedAssertion>

我确实使用以下 openssl 命令将我的 PEM 格式的私钥转换为 pkcs8 格式:

openssl pkcs8 -topk8 -nocrypt -inform PEM -in rsa_private_key.key -outform DER -out rsa_private_key.pk8

然后我准备尝试解密加密的断言。这是我的 Java 代码:

...
// Load the XML file and parse it.
File xmlFile = new File("data\\token.xml");
InputStream inputStream = new FileInputStream(xmlFile);
Document document = parserPoolManager.parse(inputStream);
Element metadataRoot = document.getDocumentElement();

// Unmarshall
UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(metadataRoot);
EncryptedAssertion encryptedAssertion = (EncryptedAssertion)unmarshaller.unmarshall(metadataRoot);

// Load the private key file.
File privateKeyFile = new File("data\\rsa_private_key.pk8");
FileInputStream inputStreamPrivateKey = new FileInputStream(privateKeyFile);
byte[] encodedPrivateKey = new byte[(int)privateKeyFile.length()];
inputStreamPrivateKey.read(encodedPrivateKey);
inputStreamPrivateKey.close();

// Create the private key.
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
RSAPrivateKey privateKey = (RSAPrivateKey)KeyFactory.getInstance("RSA").generatePrivate(privateKeySpec);

// Create the credentials.
BasicX509Credential decryptionCredential = new BasicX509Credential();
decryptionCredential.setPrivateKey(privateKey);

// Create a decrypter.
Decrypter decrypter = new Decrypter(null, new StaticKeyInfoCredentialResolver(decryptionCredential), new InlineEncryptedKeyResolver());

// Decrypt the assertion.
Assertion decryptedAssertion;

try

    decryptedAssertion = decrypter.decrypt(encryptedAssertion);

...

运行此代码始终导致无法解密断言。我确实收到以下错误:

5473 [main] ERROR org.opensaml.xml.encryption.Decrypter - Error decrypting encrypted key
org.apache.xml.security.encryption.XMLEncryptionException: Key is too long for unwrapping
Original Exception was java.security.InvalidKeyException: Key is too long for unwrapping
    at org.apache.xml.security.encryption.XMLCipher.decryptKey(Unknown Source)
    at org.opensaml.xml.encryption.Decrypter.decryptKey(Decrypter.java:681)
    at org.opensaml.xml.encryption.Decrypter.decryptKey(Decrypter.java:612)
    at org.opensaml.xml.encryption.Decrypter.decryptUsingResolvedEncryptedKey(Decrypter.java:762)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:513)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToList(Decrypter.java:440)
    at org.opensaml.xml.encryption.Decrypter.decryptData(Decrypter.java:401)
    at org.opensaml.saml2.encryption.Decrypter.decryptData(Decrypter.java:141)
    at org.opensaml.saml2.encryption.Decrypter.decrypt(Decrypter.java:69)
    at DecrypterTool.main(DecrypterTool.java:121)
java.security.InvalidKeyException: Key is too long for unwrapping
    at com.sun.crypto.provider.RSACipher.engineUnwrap(DashoA13*..)
    at javax.crypto.Cipher.unwrap(DashoA13*..)
    at org.apache.xml.security.encryption.XMLCipher.decryptKey(Unknown Source)
    at org.opensaml.xml.encryption.Decrypter.decryptKey(Decrypter.java:681)
    at org.opensaml.xml.encryption.Decrypter.decryptKey(Decrypter.java:612)
    at org.opensaml.xml.encryption.Decrypter.decryptUsingResolvedEncryptedKey(Decrypter.java:762)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:513)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToList(Decrypter.java:440)
    at org.opensaml.xml.encryption.Decrypter.decryptData(Decrypter.java:401)
    at org.opensaml.saml2.encryption.Decrypter.decryptData(Decrypter.java:141)
    at org.opensaml.saml2.encryption.Decrypter.decrypt(Decrypter.java:69)
    at DecrypterTool.main(DecrypterTool.java:121)
5477 [main] ERROR org.opensaml.xml.encryption.Decrypter - Failed to decrypt EncryptedKey, valid decryption key could not be resolved
5477 [main] ERROR org.opensaml.xml.encryption.Decrypter - Failed to decrypt EncryptedData using either EncryptedData KeyInfoCredentialResolver or EncryptedKeyResolver + EncryptedKey KeyInfoCredentialResolver
5478 [main] ERROR org.opensaml.saml2.encryption.Decrypter - SAML Decrypter encountered an error decrypting element content
org.opensaml.xml.encryption.DecryptionException: Failed to decrypt EncryptedData
    at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:524)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToList(Decrypter.java:440)
    at org.opensaml.xml.encryption.Decrypter.decryptData(Decrypter.java:401)
    at org.opensaml.saml2.encryption.Decrypter.decryptData(Decrypter.java:141)
    at org.opensaml.saml2.encryption.Decrypter.decrypt(Decrypter.java:69)
    at DecrypterTool.main(DecrypterTool.java:121)

我真的不知道在这种情况下我做错了什么。我将我的私钥转换为 pkcs8,我加载了我的 SAML XML 数据并将其解组为有效类型 (EncryptedAssertion),然后我根据我的私钥创建了一个解密。

是否可能与 RSA 的 oaep 格式有关?我正在使用默认的 java 加密库。

谢谢!

【问题讨论】:

我不知道你的确切问题,但我在处理saml 时撞到了头,我发现使用apache camel 很容易。 @Shahzeb 我很想使用其他东西,但我的客户正在使用 saml,我无法真正改变它。 :( 【参考方案1】:

同意@thwalrusnp。只是想添加可以下载策略 jar 的确切位置。

在answer 到Error while decrypting assertion sent from IDP 上找到它

这是由于默认密码强度的限制而发生的 Java 运行时环境的分布。

    下载 Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files (for Java 7) (for Java 8)

    提取 zip 存档并在其中找到 local_policy.jarUS_export_policy.jar

    将 $JAVA_HOME/jreversion_number/lib/security/ 下这些文件的 JRE 版本替换为下载的文件。

    重新启动 JRE 进程(如果有任何正在运行)。现在您可以使用更长的键了。

【讨论】:

除此之外,Java 9 似乎默认提供了无限强度策略文件。 @user+ 9 up 和 8u161 up 都有内置的无限策略。看到这个更好的预言页面:oracle.com/java/technologies/javase-jce-all-downloads.html.【参考方案2】:

对于遇到此问题的人来说,这与未安装 Java 加密扩展 (JCE) 无限强度管辖策略文件这一事实有关,并且它没有让我使用比 AES-128 更好的加密。用 JCE 策略文件替换策略文件,我能够成功解密我的加密断言。

【讨论】:

介意分享一下您是如何得出这一发现的吗?

以上是关于使用 OpenSAML 在 Java 中使用 SAML 2.0 解密加密断言的主要内容,如果未能解决你的问题,请参考以下文章

OpenSAML 使用引导 IV: 安全特性

OpenSAML / Spring 安全设置,因此在 Tomcat 上重新部署有效

如何使用 opensaml v3?几乎没有文档,并且 v2 已停产

创建 QName 异常时,Opensaml unmarshallMessage 给出的 opensaml 本地部分不能为“null”

org.opensaml.common.SAMLRuntimeException:无法获取 SP 签名密钥

SAML EncryptedAssertion解密失败