Encryption

AES-GCM加解密疑惑

  • March 21, 2019

我在我的項目中使用 AES-GCM 模式,我有一些疑問。

public String encrypt(String plainText, String authenticationTag) throws GeneralSecurityException, IOException {
       Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
       final int blockSize = cipher.getBlockSize();
       SecretKey secretKey = readKeyFile(...);
       byte[] plainTextByte = plainText.trim().getBytes(Charset.forName("UTF-8"));
       byte[] ivBytes = generateIV();
       cipher.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(GCM_TAG_LENGTH, ivBytes));
       cipher.updateAAD(authenticationTag.getBytes(Charset.forName("UTF-8")));
       byte[] encryptedMessage = cipher.doFinal(plainTextByte);
       byte iv_and_encryptedMessage[] = concatIvAndCipher(ivBytes, encryptedMessage, blockSize);
       Base64.Encoder encoder = Base64.getEncoder().withoutPadding();
       String iv_and_encryptedText = encoder.encodeToString(iv_and_encryptedMessage);
       return iv_and_encryptedText;
   }

   public String decrypt(String iv_and_encryptedTextBase64, String authenticationTag)
           throws GeneralSecurityException, IOException {
       Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
       final int blockSize = cipher.getBlockSize();
       Base64.Decoder decoder = Base64.getDecoder();
       byte[] iv_and_encryptedMessage = decoder.decode(iv_and_encryptedTextBase64.trim());
       byte[] ivBytes = extractIvFrom(iv_and_encryptedMessage, blockSize);
       byte[] encryptedTextBytes = extractEncryptedMessageFrom(iv_and_encryptedMessage, blockSize);
       SecretKey secretKey = readKeyFile(...);
       cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(GCM_TAG_LENGTH, ivBytes));
       cipher.updateAAD(authenticationTag.getBytes(Charset.forName("UTF-8")));
       byte[] decryptedByte = cipher.doFinal(encryptedTextBytes);
       String decryptedMessage = new String(decryptedByte, Charset.forName("UTF-8"));
       return decryptedMessage;
   }

問題:

  1. 我使用 GUID 作為身份驗證標籤,它綁定到敏感資訊所屬的使用者。加密文本和標籤儲存在不同位置的不同數據庫中。這個可以嗎?
  2. 從我讀過的內容來看,AES-GCM 接受(純文字、IV、密鑰、關聯數據)和輸出(密文、身份驗證標籤)。關聯的數據和身份驗證標籤是否相同,因為當我傳遞相同的值時,我的加密和解密實現工作cipher.updateAAD(...)?加密後如何獲取認證標籤?
  3. 我應該使用 Bouncy Castle 而不是使用預設的 Java 實現嗎?
  4. 如果要加密的數據是 16 字節,我應該什麼時候為 enc/dec 生成一個新的 DEK?
  5. 所有 DEK 的一個主 KEK?對於加密 DEK,我應該使用相同的 AES 實現嗎?如果沒有,那用什麼?
  1. 我使用 GUID 作為身份驗證標籤,它綁定到敏感資訊所屬的使用者。加密文本和標籤儲存在不同位置的不同數據庫中。這個可以嗎?

沒有將 GUID 用作身份驗證標籤,而是將其用作附加的經過身份驗證的數據,這沒關係,尤其是因為您已經共享了一個密鑰。身份驗證標籤 - 當使用有點被破解的 Java API 時 - 輸出在密文的末尾。

2)從我讀過的內容來看,AES-GCM 接收(純文字、IV、密鑰、相關數據)和輸出(密文、身份驗證標籤)。關聯的數據和身份驗證標籤是否相同,因為當我在 cipher.updateAAD(…) 中傳遞相同的值時,我的加密和解密實現工作?加密後如何獲取認證標籤?

不,見上文。如果您想獲取身份驗證標籤,您可能希望將其從密文的末尾剝離。

  1. 我應該使用 BouncyCastle 而不是使用預設的 Java 實現。

除非您想放棄 AES-NI 和 GCM 優化,否則不會。對於 OpenJDK / Oracle 執行時提供的 API 中已經存在的實現,我會遠離 Bouncy Castle。

  1. 如果要加密的數據是 16 字節,我應該什麼時候為 enc/dec 生成一個新的 DEK。

請參閱 NIST GCM 規範;一般來說,它取決於身份驗證標籤的大小,因此可能有多個答案。

常量值GCM_TAG_LENGTH不會顯示在問題的程式碼中,因此在您的特定情況下不清楚身份驗證標籤大小是多少。

在評論中提到了 128 位的身份驗證標籤大小。NIST GCM 規範對此並不完全清楚,所以我詢問了這個問題中的尺寸,這個問題後來得到了很多回答。

  1. 一個主 KEK 用於所有 DEK?對於加密 DEK,我應該使用相同的 AES 實現嗎?如果沒有,那用什麼?

這取決於協議,最終取決於案例和威脅模型。但總的來說,我會使用諸如 HKDF 之類的 KDF 來派生密鑰,而不是包裝(加密)它們。現在*,*您可能想要使用 Bouncy Castle,因為 Java 本身沒有任何好的 KDF 實現。

引用自:https://crypto.stackexchange.com/questions/40414