2017-02-01 43 views
3

我不明白爲什麼我的密碼是不是基於以下矢量預期的輸出更長。我不會解釋代碼,因爲我認爲它非常簡潔明瞭。這個AES 128加密有什麼問題?

package mundo; 
import javax.crypto.Cipher; 
import javax.crypto.spec.SecretKeySpec; 
import javax.xml.bind.DatatypeConverter; 

class AESTest { 
    public static void main(String[] args) throws Exception { 
    //each array is a vector case {key, plainText, expectedCipher} 
    String[][] cases = new String[][]{{"00000000000000000000000000000000", "f34481ec3cc627bacd5dc3fb08f273e6","0336763e966d92595a567cc9ce537f5e"}, 
             {"00000000000000000000000000000000", "9798c4640bad75c7c3227db910174e72", "a9a1631bf4996954ebc093957b234589"}, 
             {"2b7e151628aed2a6abf7158809cf4f3c", "6bc1bee22e409f96e93d7e117393172a", "3ad77bb40d7a3660a89ecaf32466ef97"}, 
             {"2b7e151628aed2a6abf7158809cf4f3c", "ae2d8a571e03ac9c9eb76fac45af8e51", "f5d3d58503b9699de785895a96fdbaaf"}}; 
    for(String[] kase : cases) 
    { 
     byte[] theKey = byte2hex(kase[0]); 
     byte[] theMsg = byte2hex(kase[1]); 
     byte[] theExp = byte2hex(kase[2]); 
     Cipher cipher = Cipher.getInstance("AES"); 
     SecretKeySpec keySpec = new SecretKeySpec(theKey, "AES"); 
     cipher.init(Cipher.ENCRYPT_MODE, keySpec); 
     byte[] cryptMsg = cipher.doFinal(theMsg); 
     System.out.println("Key  : "+hex2byte(theKey)); 
     System.out.println("Message : "+hex2byte(theMsg)); 
     System.out.println("Cipher : "+hex2byte(cryptMsg)); 
     System.out.println("Expected: "+hex2byte(theExp) + "\n"); 
    } 
    } 
    public static String hex2byte(byte[] array) { 
     return DatatypeConverter.printHexBinary(array); 
    } 
    public static byte[] byte2hex(String s) { 
     return DatatypeConverter.parseHexBinary(s); 
    } 
} 

這是輸出:

Key  : 00000000000000000000000000000000 
Message : F34481EC3CC627BACD5DC3FB08F273E6 
Cipher : 0336763E966D92595A567CC9CE537F5E0143DB63EE66B0CDFF9F69917680151E 
Expected: 0336763E966D92595A567CC9CE537F5E 

Key  : 00000000000000000000000000000000 
Message : 9798C4640BAD75C7C3227DB910174E72 
Cipher : A9A1631BF4996954EBC093957B2345890143DB63EE66B0CDFF9F69917680151E 
Expected: A9A1631BF4996954EBC093957B234589 

Key  : 2B7E151628AED2A6ABF7158809CF4F3C 
Message : 6BC1BEE22E409F96E93D7E117393172A 
Cipher : 3AD77BB40D7A3660A89ECAF32466EF97A254BE88E037DDD9D79FB6411C3F9DF8 
Expected: 3AD77BB40D7A3660A89ECAF32466EF97 

Key  : 2B7E151628AED2A6ABF7158809CF4F3C 
Message : AE2D8A571E03AC9C9EB76FAC45AF8E51 
Cipher : F5D3D58503B9699DE785895A96FDBAAFA254BE88E037DDD9D79FB6411C3F9DF8 
Expected: F5D3D58503B9699DE785895A96FDBAAF 

爲什麼密碼比預期更長。這是從參考書中獲得的可信的128位AES矢量。

編輯添加到代碼:

cipher.init(Cipher.DECRYPT_MODE, keySpec); 
byte[] dcrypMsg = cipher.doFinal(cryptMsg); 
System.out.println("Decrypted: " + byte2hex(dcrypMsg) + "\n"); 

解密是正確的,但我仍然無法理解......

Key  : 2B7E151628AED2A6ABF7158809CF4F3C 
Message : AE2D8A571E03AC9C9EB76FAC45AF8E51 
Cipher : F5D3D58503B9699DE785895A96FDBAAFA254BE88E037DDD9D79FB6411C3F9DF8 
Expected: F5D3D58503B9699DE785895A96FDBAAF 
Decrypted: AE2D8A571E03AC9C9EB76FAC45AF8E51 

回答

4

請使用Cipher.getInstance("AES/ECB/NoPadding"); 確保,您輸入的內容沒有得到填充。 然後我得到所有測試用例的預期輸出。

根據https://docs.oracle.com/javase/8/docs/api/javax/crypto/Cipher.html

的變換的形式是:

「算法/模式/填充」或「算法」(在後一種情況下, 特定於提供商的默認值模式和填充方案使用 )。

你不知道,如果你沒有指定它,使用什麼樣的填充。我想你的輸入數據被填補,這意味着什麼被添加到您的輸入填滿它,這樣你有一套你的密碼的塊大小的全塊。您的輸入長度是由塊大小已經整除,所以完整的塊被添加,導致消息,具有兩倍預期長度。

2

如果不指定密文分組鏈接模式和填充算法,那麼JDK將採取默認值。密碼規範建議不要指定它們:

建議使用完全指定 算法,模式和填充的轉換。如果不這樣做,提供商將使用默認值 。例如,的了SunJCE和SunPKCS11提供商使用ECB作爲 默認模式,並且PKCS5Padding作爲許多 對稱密碼的默認填充。 http://docs.oracle.com/javase/7/docs/technotes/guides/security/crypto/CryptoSpec.html#trans

爲了讓您所需的輸出,你需要使用電子菜譜模式(ECB) - 所以沒有塊鏈接 - 並沒有填充:

Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");