4

因此,我一直在與Bouncycastle庫一起嘗試連接遠程服務器。這個過程從一開始就存在問題,現在我已經接近讓所有的工作都能正常工作,但一些奇怪的事情正在發生。Java中的Bouncycastle奇數加密和解密結果

當我第一次開始構建加密過程時,我被告知使用帶有PKCS7Padding的AES 256。經過一番嘮叨,我得到了一個C++的服務器代碼例子。事實證明,IV是256位,所以我不得不使用RijndaelEngine。此外爲了這個工作正常,我必須使用ZeroBytePadding。

這裏是我的代碼:

socket = new Socket(remoteIP, port); 

outputStream = new PrintWriter(socket.getOutputStream()); 
inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream())); 

byte[] base_64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/".getBytes("UTF-8"); 

Security.addProvider(new BouncyCastleProvider()); 

public String AESEncrypt(String out) throws IOException, DataLengthException, IllegalStateException, InvalidCipherTextException { 
    byte[] EncKey = key; 
    byte randKey; 
    Random randNumber = new Random(); 

    randKey = base_64[randNumber.nextInt(base_64.length)]; 
    EncKey[randKey&0x1f] = randKey; 

    RijndaelEngine rijndaelEngine = new RijndaelEngine(256); 
    PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(rijndaelEngine), new ZeroBytePadding()); 
    ParametersWithIV keyParameter = new ParametersWithIV(new KeyParameter(EncKey), iv); 
    cipher.init(true, keyParameter); 

    byte[] txt = out.getBytes(); 
    byte[] encoded = new byte[cipher.getOutputSize(txt.length)]; 
    int len = cipher.processBytes(txt, 0, txt.length, encoded, 0); 

    cipher.doFinal(encoded, len); 

    char keyChar = (char) randKey; 
    String encString = new String(Base64.encode(encoded)); 
    encString = encString.substring(0, encString.length()-1) + randKey; 

    return encString; 
} 

public void AESDecrypt(String in) throws DataLengthException, IllegalStateException, IOException, InvalidCipherTextException { 
    byte[] decKey = key; 
    byte[] msg = in.getBytes(); 
    byte randKey = msg[msg.length-1]; 
    decKey[randKey&0x1f] = randKey; 

    byte[] trimMsg = new byte[msg.length-1]; 
    System.arraycopy(msg, 0, trimMsg, 0, trimMsg.length); 

    in = new String(trimMsg); 

    RijndaelEngine rijndaelEngine = new RijndaelEngine(256); 
    PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(rijndaelEngine), new ZeroBytePadding()); 
    ParametersWithIV keyParameter = new ParametersWithIV(new KeyParameter(decKey), iv); 
    cipher.init(false, keyParameter); 

    byte[] encoded = Base64.decode(in.trim()); 
    byte[] decoded = new byte[cipher.getOutputSize(encoded.length)]; 
    int len = cipher.processBytes(encoded, 0, encoded.length, decoded, 0); 
    cipher.doFinal(decoded, len); 

    String decString = new String(decoded); 
} 

這裏是我使用的發送和接收消息的測試功能:

public void serverTest() throws DataLengthException, IllegalStateException, InvalidCipherTextException, IOException { 

    //out = AESEncrypt(out); 

    outputStream.write(out + "\n"); 
    outputStream.flush(); 

    String msg = ""; 

    while ((msg = inputStream.readLine()) != null) { 
     AESDecrypt(msg); 
    } 
} 

密鑰和IV不符合的異常改變密鑰中的最後一個字節。如果我正在加密,我會得到一個隨機的base64字符並將最後一個字節更改爲該字符。如果解密,我從消息中得到最後一個字節,並將密鑰的最後一個值設置爲解密。

在C++示例中,存在未加密的消息和兩條加密的消息。我可以處理那些罰款。

這是問題所在,當我將消息發送到遠程服務器「加密」時,應用程序會等待響應,直到連接超時但從未獲得響應。如果我發送郵件的未加密的,我得到或者7層的反應,我可以成功解密,最後

org.bouncycastle.util.encoders.DecoderException: unable to decode base64 string: 
String index out of range: -4 at org.bouncycastle.util.encoders.Base64.decode(Unknown Source) 

或我的錯誤之前最後一行看起來像這樣:

?"??n?i???el????s???!_S=??ah????CR??l6??]?{?l??Y?????Gn???+?????9!'??gU&4>??{X????G?.$c=??0?5??GP???_Q5????8??Z\?~???<Kr?????[2\ ???a$?C??z%?W???{?.?????eR?j????~?B"$??"z??W;???<?Yu??Y*???Z?K?e!?????f?;O(?Zw0B??g<???????????,)?L>???A"?????<[email protected]\???f%??j ?EhY/?? [email protected]?1??I??????M 

如果我設置的加密/解密使用PKCS7Padding我沒有得到任何迴應時,我的消息仍然是加密,但是從我2至6響應之間獲得服務器解密,然後

org.bouncycastle.crypto.InvalidCipherTextException: pad block corrupted 

我很茫然機智這個。我不知道我可能做錯了什麼,所以我來到了這裏。我希望這樣的社區能指出我的錯誤,並指導我走向正確的方向。

我有一點更新,我發現我的加密錯誤。我沒有正確地將隨機base64值放在加密字符串的末尾,所以現在我正在這樣做。

encString += (char)randKey; 

我現在可以從服務器得到響應。現在的問題是我有時會得到一兩個可讀的行,但其餘的都是垃圾。我問誰運行服務器關於它的人,他們在他們引用一些C#代碼表示,有

return UTF8Encoding.UTF8.GetString(resultArray); 

和多數民衆贊成所有我必須走下車的。我已經嘗試過使用UTF-8編碼的地方,我在那裏做了getBytes或新的String,並且我試圖製作BurrferReader流UTF-8,但它仍然是垃圾。

+0

聽起來像你只是想直到有工作隨意的事情。爲什麼不從服務器的運營商那裏獲得真正的規範? –

+0

「隨機」是一個安全的PRNG嗎?標準的Random類不安全,不應該用在加密代碼中。 – CodesInChaos

+0

@GregS問題之一是來自服務器運營商的規範。他們一直告訴我必須使用256位AES,但初始化向量是256位。 AES的塊大小不會允許。當我提到這一點時,我不得不使用Rijndael或使用提供的IV。另外,我被告知使用的填充從不用於解密。 – hswets

回答

1

你有沒有種下BCgit?這有bouncycastle代碼和例子。我在這個倉庫中使用Csharp版本。https://github.com/bcgit/bc-java

所有加密的原始實例都存儲在這裏:https://github.com/bcgit/bc-java/tree/master/core/src/test/java/org/bouncycastle/crypto/test

嘗試此代碼測試AES-CBC

private void testNullCBC() 
    throws InvalidCipherTextException 
{ 
    BufferedBlockCipher b = new BufferedBlockCipher(new CBCBlockCipher(new AESEngine())); 
    KeyParameter kp = new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")); 

    b.init(true, new ParametersWithIV(kp, new byte[16])); 

    byte[] out = new byte[b.getOutputSize(tData.length)]; 

    int len = b.processBytes(tData, 0, tData.length, out, 0); 

    len += b.doFinal(out, len); 

    if (!areEqual(outCBC1, out)) 
    { 
     fail("no match on first nullCBC check"); 
    } 

    b.init(true, new ParametersWithIV(null, Hex.decode("000102030405060708090a0b0c0d0e0f"))); 

    len = b.processBytes(tData, 0, tData.length, out, 0); 

    len += b.doFinal(out, len); 

    if (!areEqual(outCBC2, out)) 
    { 
     fail("no match on second nullCBC check"); 
    } 
}