One IT Thing

IT業界で飯を食う為の学習系雑記

java

JavaでRSA暗号を使う際にCRYPTREC暗号リストに足元をすくわれる可能性を回避する

投稿日:2019年6月27日 更新日:

標準的な暗号しか使わないケースでもJavaでRSAを使う時はBouncyCastleを入れておいた方が無難、という話です。

“ECB”という文字列がプログラム中にあると監査に引っかかって時間を割かなければいけなくなるかも知れません。

CRYPTREC暗号リストとは

電子政府推奨暗号リスト。総務省と経済産業省が取り決めている「使ってもいい暗号方式」の一覧表です。

上記サイト冒頭の「電子政府における調達のために参照すべき暗号のリスト(CRYPTREC暗号リスト)」リンクで開くPDFに、政府が使用を推奨している暗号化方式リストが掲載されています。

この中のどれかで暗号化されていれば概ねセキュリティが担保されると監査側は認識していることが多いと思います。

逆にこのリストに載っていない方式がプログラム内に出てくると、納品時にセキュリティ監査による静的コードチェックに引っかかるかも知れません。

JavaコアAPIのみでRSA暗号、復号するコードの問題点

RSA暗号されたsourceを復号するコードです。6行目の
Cipher.getInstance(“RSA/ECB/PKCS1PADDING”);
が受け入れの際の単純チェックに引っかかる可能性が有ります。

    public byte[] decrypt(byte[] source) throws Exception {
        byte[] keyData = readKeyFile(PRIVATE_KEY_FILE);
        KeySpec keyspec = new PKCS8EncodedKeySpec(keyData);
        KeyFactory keyfactory = KeyFactory.getInstance("RSA");
        Key privateKey = keyfactory.generatePrivate(keyspec);
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(source);
    }

暗号処理する為のCipherインスタンスを作る為に”アルゴリズム/暗号化モード/パディング”を指定します。この際JavaコアAPIのみだとRSAを指定した場合のモードは「ECB」しか指定出来ません。それ以外を指定すると例外が発生します。

java.security.NoSuchAlgorithmException: Cannot find any provider supporting RSA/None/PKCS1PADDING
					at javax.crypto.Cipher.getInstance(Cipher.java:539)

ECBはCRYPTREC暗号リストには乗っておらず、初期化ベクトル仕様が無く毎回暗号化結果が同じになる為、世の中的にも非推奨です。

ただこのブロックモード指定が使われるのはAESやDESのような共通鍵暗号の場合で、RSAのような鍵ペアを使った公開鍵暗号方式では使用されません。

RSAではパディングの結果毎回暗号化結果が異なるので本来ECBやCBCのようなブロックモードは意識しなくても良いのですが、開発者側はJavaでRSAする際に取りあえずECBを指定しておくしかない現状があり、監査する側もリストからその意図が読み取れず、非推奨のブロックモードを指定していると判断してしまい、余計な誤解を招いてしまう可能性があります。

対処

“RSA/ECB/PKCS1PADDING”以外の指定が出来るように暗号化ライブラリ「BouncyCastle」を追加します。以下Mavenのpom.xml。

	<dependencies>
		<!-- 追加 -->
		<dependency>
			<groupId>org.bouncycastle</groupId>
			<artifactId>bcprov-jdk15on</artifactId>
			<version>1.62</version>
		</dependency>
	</dependencies>

JVM内の暗号化プロバイダに、先ほど追加したBouncyCastleProvicderを認識させることで”RSA/None/PKCS1PADDING”を指定出来るようにします。

// 追加
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.Security;

        // アプリ初期化時にでも追加
		Security.addProvider(new BouncyCastleProvider());

    public byte[] decrypt(byte[] source) throws Exception {
        byte[] keyData = readKeyFile(PRIVATE_KEY_FILE);
        KeySpec keyspec = new PKCS8EncodedKeySpec(keyData);
        KeyFactory keyfactory = KeyFactory.getInstance("RSA");
        Key privateKey = keyfactory.generatePrivate(keyspec);

        // BouncyCastleProviderのRSA/None/PKCS1PADDINGを使用する
        Cipher cipher = Cipher.getInstance("RSA/None/PKCS1PADDING", "BC");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(source);
    }

“ECB”という文字列はプログラム中から無くなりました。

鬼の首を取ったようにセキュリティ監査部門から糾弾され、弁明する時間を無駄にすることはもうありません。火の無いところに煙は立てたくないところです。

JavaでRSAを使う時はBouncyCastleは必須ですね。

-java
-,

執筆者:

関連記事

StripeとJavaで単発Web決済を一通り流してみる

会社仕事でも個人ビジネスでも、商品やサービスの対価として利用者に課金方法を提供したい時があるかと思います。 最もメジャーな決済方法であるクレジットカードで課金してもらう仕組みを導入したいところですが、 …

Spring&JSPの検証環境を速攻で作る

2019年現在、オワコン風潮の強いJSPですが使っているプロジェクトもまだまだあり、枯れた技術を好む官公庁系のプロジェクトでは根強いシェアを誇っています。実装検証をする為に環境を作る機会があったりする …

Stripe + Javaでオーソリ(与信の確保)を実装する

Stripeでチャリンチャリン、サービスを開発するエンジニアにとっては夢がありますよね。 例え自分で個人的に売るものが無かったとしても、Web決済システムを構築できるノウハウを持っておけば、公的な仕事 …

IPAmj明朝のttfファイルをJVMに読み込ませてSwingで表示(要Java11)

目次1 はじめに2 Java11でSwingがIVSを認識するようになった3 Java Swingソース4 動作確認4.1 Java 8(1.8.0_202)で実行4.2 Java 11(11.0.2 …

CentOS7にOpenJDK11をインストール、alternatives後の再ログインでJAVA_HOMEも自動変更

OpenJDKはCentOS-Baseリポジトリのupdatesに登録されているので新規yumリポジトリ追加は不要です。 [root@spock tmp]# yumdb search from_rep …

 

shingo.7k24
 

東京在勤、職歴20年越え中年ITエンジニアです。まだ開発現場で頑張っています。

19歳(1996年)から書き始めた個人日記が5,000日を超え、残りの人生は発信をして行きたいと思い、令和元日からこのサイトを開始しました。勉強と試行錯誤をしながら、自分が経験したIT関連情報を投稿しています。

私と同じく、今後IT業界で生計を立てて行きたいと考えている方や、技術共有したいけどフリーランスで孤独、といった方と一緒に成長、知識共有して行けたら楽しいな、と思っています。