OAEPを使用しないRSA暗号化

OAEPを使用しないRSA暗号化

説明

RSA暗号化には安全なパディングが必要です。NoPadding は決定的で、暗号文の改ざんに弱い方式です。PKCS#1 v1.5パディング(PKCS1Padding)では、復号エラーや処理時間からパディングの有効性を区別できると、Bleichenbacher攻撃などのパディングオラクル攻撃を受けるおそれがあります。攻撃者は応答の違いを利用し、暗号文を段階的に復号できます。

想定される影響

  • 平文の漏えい: パディングオラクルを通じて、暗号化されたトークン、セッション鍵、個人情報などが読み取られるおそれがあります。
  • 認証情報やトークンの窃取: ログイントークンやAPIキーの漏えいが、アカウントの侵害につながるおそれがあります。
  • 完全性の損失: パディングのないRSAや脆弱なパディングにより、意味のある暗号文の改ざんが可能になる場合があります。
  • 暗号保護の低下: OAEPの代わりに古いパディングを許可すると、システムの保護が弱まり、他の攻撃と組み合わされるおそれがあります。

対処方法

  • OAEPパディングを使用してください: Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding")。
  • 可能な場合は OAEPParameterSpec でSHA-256、MGF1のSHA-256、PSource.PSpecified.DEFAULT を明示してください。
  • RSA暗号化コードの "RSA"、"RSA/ECB/PKCS1Padding"、"RSA/ECB/NoPadding" をOAEPに置き換えてください。暗号化側と復号側のパラメーター、およびプロバイダーの対応を確認してください。
  • 復号失敗の処理を統一し、エラーの違いがオラクルにならないようにしてください。
  • 実際のサービスでは、データをAES-GCMで暗号化し、ランダムなセッション鍵をRSA-OAEPでラップするハイブリッド暗号化を使用してください。
  • RSA鍵は2048ビット以上とし、JCA/JCEプロバイダーを適切に更新してください。

例

変更前

java
import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.PublicKey;

public class InsecureRSAExample {
    // 취약: PKCS#1 v1.5 패딩 사용
    public static byte[] encryptPassword(String password, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // BAD
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(password.getBytes(StandardCharsets.UTF_8));
    }
}

変更後

java
import javax.crypto.Cipher;
import javax.crypto.spec.OAEPParameterSpec;
import java.security.spec.MGF1ParameterSpec;
import javax.crypto.spec.PSource;
import java.nio.charset.StandardCharsets;
import java.security.PublicKey;

public class SecureRSAExample {
    // 안전: OAEP(SHA-256, MGF1) 사용
    public static byte[] encryptPassword(String password, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
        OAEPParameterSpec oaep = new OAEPParameterSpec(
                "SHA-256",
                "MGF1",
                MGF1ParameterSpec.SHA256,
                PSource.PSpecified.DEFAULT
        );
        cipher.init(Cipher.ENCRYPT_MODE, publicKey, oaep);
        return cipher.doFinal(password.getBytes(StandardCharsets.UTF_8));
    }
}

解説:

  • 変更前: 復号側がパディングエラーを区別できる場合、PKCS#1 v1.5暗号化はパディングオラクル攻撃に利用されるおそれがあります。NoPadding も決定的で改ざんに弱いため、代替手段にしないでください。
  • 変更後: OAEPのハッシュとMGF1のハッシュにSHA-256を明示しています。この例は暗号化のみを示すため、復号失敗の統一したエラー処理は別途実装してください。

参考資料