2016-03-04 99 views
3

SAML XML響應由我們的Gluu/Shibboleth服務器通過我的公共證書加密。我已閱讀規範,並在Stackoverflow的幫助下實施了該解決方案。但是,解密後,我會在最後得到隨機字符。SAML RSA和AES解密 - 結尾的隨機垃圾字節

SAML響應使用RSA-ECB/MGF1編碼的AES-128-CBC密鑰。所以首先我必須解碼AES密鑰(字節),然後使用該AES密鑰來解密XML響應。

這裏是我的代碼:

public static void main(String[] args) throws Exception { 
    Path p = Paths.get("C:\\Users\\jj\\Desktop\\myPrivateKey.key"); 
    String encryptedAESKey = "FUZLPtkLSUgOo0bETQ5hwP1OWNggGlWhG+Z......wF1G6twRjg=="; // from XML 
    byte[] aesKey = decryptWithPem("RSA/ECB/OAEPwithSHA1andMGF1Padding", "RSA", Util.base64DecodeAsBytes(encryptedAESKey), p); 
    String encryptedXML = "YfJu7h4Id09hpuoqthl3Ks/JqhIXm.....amb24JZu7cJZT3cEO2a2U6qi0VCyoXQ="; 
    byte[] decryptedData = decrypt("AES/CBC/NoPadding", "AES", Util.base64DecodeAsBytes(encryptedXML), aesKey); 
    for(int i = decryptedData.length - 20; i < decryptedData.length; i++) { 
     System.out.println("i: " + i + " -> " + decryptedData[i]); // print last 20 bytes 
    } 
    System.out.println(new String(decryptedData)); // prints <saml2:Assertion xmlns:saml2="urn:oasis:names:........</saml2:Assertion>�G{A 

} 

注意在打印語句隨機字節!最後一行打印:

<saml2:Assertion xmlns:saml2="urn:oasis:names:........</saml2:Assertion>�G{A

我意識到,在該消息中的前16個字節是IV,所以從消息(從消息的開始擺脫垃圾)去掉它們。但是現在我在消息結尾處隨機獲得5個字節。這些字節是:

i: 1931 -> -120 
i: 1932 -> 71 
i: 1933 -> 123 
i: 1934 -> 65 
i: 1935 -> 5 

其它功能:

public static byte[] decryptWithPem(String alg, String pemAlg, byte[] encryptedData, Path pemPath) { 
    try { 
     Cipher cipher = Cipher.getInstance(alg, "BC"); 
     cipher.init(Cipher.DECRYPT_MODE, loadPrivateKey(pemPath, pemAlg)); 
     return cipher.doFinal(encryptedData); 
    } catch (Exception e) { 
     throw new RuntimeException(e); 
    } 
} 

private static PrivateKey loadPrivateKey(Path keyPath, String alg) { 
    try { 
     byte[] keyData = Util.base64DecodeAsBytes(IOUtil.fileToString(keyPath).replaceAll("\\s", "")); 
     KeyFactory keyFactory = KeyFactory.getInstance(alg); 
     EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(keyData); 
     return keyFactory.generatePrivate(privateKeySpec); 
    } catch(NoSuchAlgorithmException | InvalidKeySpecException e) { 
     throw new RuntimeException(e); 
    } 
} 

private static SecretKeySpec getSecretKeySpec(String alg, byte[] key) { 
    return new SecretKeySpec(key, alg); 
} 

public static byte[] decrypt(String alg, String keyAlg, byte[] dataToDecrypt, byte[] key) { 
    try { 
     Cipher cipher = Cipher.getInstance(alg, "BC"); 
     cipher.init(Cipher.DECRYPT_MODE, getSecretKeySpec(keyAlg, key), new IvParameterSpec(dataToDecrypt, 0, 16)); 
     return cipher.doFinal(Arrays.copyOfRange(dataToDecrypt, 16, dataToDecrypt.length)); 
    } catch (Exception e) { 
     throw new RuntimeException(e); 
    } 
} 

我使用充氣城堡。 如果我使用PKCS7填充,我得到一個關於錯誤填充的錯誤。

AES密鑰的加密方式:http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p,http://www.w3.org/2000/09/xmldsig#sha1。 XML數據加密的方式:http://www.w3.org/2001/04/xmlenc#aes128-cbc

是否有可能消息是隨機填充的?

------編輯------

看來,規範使用ISO 10126的填充,可以使用 「AES/CBC/ISO10126Padding」,而不是 「AES/CBC/NoPadding」 的。

回答

3

消息是否可以隨機填充?

是,如在Padding section詳述它通過說問號可以是任何使用隨機填充,但最後一個字節表示填充的長度。他們的例子:0x2122232425262728??????????????08

這實際上是ISO 10126 padding,你可以很容易地通過看最後一個字節刪除:

byte[] pp = cipher.doFinal(Arrays.copyOfRange(dataToDecrypt, 16, dataToDecrypt.length)); 
return Arrays.copyOf(pp, pp.length - pp[pp.length-1]); 

請注意,如果你自己處理填充,你必須在alg使用NoPadding。

+1

非常感謝!我會使用「AES/CBC/ISO10126Padding」這似乎工作,只要你有BouncyCastle。 – jn1kk