2010-11-23 49 views
1

我有包含Java JCA密碼和消息摘要對象的實例不可變加密器輔助對象池:這個加密代碼線程安全嗎?

AlgorithmInstance(Cipher encCipher, Cipher decCipher, MessageDigest digest) { ... } 
private BlockingQueue<AlgorithmInstance> pool = new ArrayBlockingQueue<AlgorithmInstance>(poolSize); 

不同的線程在我的應用程序,需要加密或解密,通過訪問池爭AlgorithmInstance對象。每個線程使用它們進行加密或解密,然後在完成後將它們返回給池。線程不會在任何JCA對象上同步,因爲沒有併發訪問。解密工作方式大致相同。

public byte[] encryptMessage(byte data[]) { ... 
try { 
    AlgorithmInstance inst = pool.take(); 

    inst.digest.reset(); 
    byte[] digest = inst.digest.digest(message); 

    inst.encryptCipher.init(Cipher.ENCRYPT_MODE, m_currentKey, ivParams); 
    inst.encryptCipher.doFinal(messageBuffer); 
} 
finally { 
    pool.put(inst) 
} 
} 

這項工程99.99%的時間;和100%的時間在單元測試。然而,一旦進入藍色月亮,我會收到一條消息,其計算的摘要不正確 - 通常這表示消息篡改或網絡錯誤;但是發送者和接收者在同一臺機器上(在不同的進程中)。

問:是否有一個密碼或文摘一些內部狀態,這可以從內存一致性效應的影響 - 我在一個2核心的Windows中,所以我看不出我甚至可以從內存中遭受的一致性效果。我重新初始化密碼並消化每個呼叫,所以它應該沒有關係。

問:有沒有什麼辦法可以結束與填充模式,有時根據消息長度失敗?解密器和加密器使用完全相同的算法(AES/CBC/Pkcs5Padding + SHA-256,密鑰大小爲128)。

+1

答案1:不是我能看到的。答案2:No. – 2010-11-24 00:50:05

+0

我的感覺是它在GC或者密碼/摘要中的一些共享緩衝區有一些副作用;或者@Rook表示我錯誤地使用了它。它再次發生,文摘完全不同,不僅僅是幾個不同點。絕對不知道。 – Justin 2010-11-24 01:30:12

+0

你有沒有理由把它們放在一起?它是否真的提供性能優勢?我會猜想創建cyper對象不會很昂貴。 – CodesInChaos 2011-01-11 20:58:17

回答

0

我改變了代碼,這樣我就AlgorithmInstance同步,而我使用它的任何包含的對象。自那以後我沒有看到這個問題;然而它不清楚爲什麼;由於queue.put()queue.take()操作應形成完全一樣之前發生由監視器解鎖形成關係:

synchronized (inst) { 
... 
// do crypto opperations 
} 

唯一的其他可能性我可以想出的是,IVParamSpec在Cipher.init期間修改()計算,然後在最後恢復。由於ivParams被假定爲只讀且在池中的所有對象之間共享,因此如果爲true,則可能會導致非同步訪問並可能導致MCE。

0

encryptMessage()功能自身是線程安全的,因爲其不使用存儲器2個線程共享。但是,使用此函數的代碼可能不是線程安全的。如果要同時對池或隊列中的數據進行加密/解密,則可能「當前工作索引」不是以線程安全的方式遞增或遞減。線程之間共享的全局索引可以通過讓互斥鎖保護全局整數來創建。在讀取此值並更改之前,線程必須請求對此變量進行鎖定。

3

你的應用有很多線程嗎?因爲不是擁有一個池,您可以將您的AlgorithmInstances放入ThreadLocal對象中,從而確保每個AlgorithmInstance始終只由同一個線程使用,所以問題應該消失,您不需要在AlgorithmInstance上同步(所以你會得到更好的表現)。