JavaでRSAの公開鍵を読み込んだらInvalidKeySpecException: unknown object in factory: org.bouncycastle.asn1.DERInteger

AndroidでRSA鍵を扱おうと思い、以下のようなコードを書きました。

/**
* ファイルの中身を全部取得する
*/
public static byte[] readFile(String filename) {
    try {
        FileInputStream is = new FileInputStream(filename);
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();

        byte[] buf = new byte[256];
        int size = 0;

        while ((size = is.read(buf)) != -1) {
            bytes.write(buf, 0, size);
        }

        return bytes.toByteArray();
    } catch (Exception e) {
        //TODO
    }
    return null;
}

/**
* PEMの最初と最後の行を取り除き、データ部分だけ抜き出し、Base64デコードする
* 手抜き実装
* Base64はこちらを利用: http://iharder.net/base64
*/
public static byte[] decodePem(String pem) {
    String BORDER = "-----";
    try {
        if (pem.indexOf(BORDER) != -1) {
            int s1 = pem.indexOf(BORDER); // BEGINの左側
            int s2 = pem.indexOf(BORDER, s1 + 1); // BEGINの右側
            int s3 = pem.indexOf(BORDER, s2 + 1); // ENDの左側
            int s4 = pem.indexOf(BORDER, s3 + 1); // ENDの右側
            if (s1 != -1 && s2 != -1 && s3 != -1 && s4 != -1) {
                String body = pem.substring(s2 + BORDER.length(), s3);
                return Base64.decode(body);
            }
        }
    } catch (Exception e) {
       //TODO
    }
   return null;
}

/**
* DER形式のバイナリを読み込む
*/
public static PublicKey decodePublicKey(byte[] data) {
    try {
        X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
        return KeyFactory.getInstance(ALGORITHM).generatePublic(spec);
    } catch (Exception e) {
        //TODO
    }
    return null;
}

これでPEMファイルを読ませたところ、以下のようなエラーが発生。

java.security.spec.InvalidKeySpecException: java.lang.IllegalArgumentException: unknown object in factory: org.bouncycastle.asn1.DERInteger

エラーメッセージは少し意味不明ですが、鍵の形式がおかしかったようです。

この鍵は、Rubyで

require 'openssl'
rsa = OpenSSL::PKey::RSA.new(2048)
rsa.to_s # > private.pem
rsa.public_key.to_s # => public.pem

として出力したものです。
秘密鍵のほうは問題なく読めたのですが、公開鍵はX.509になっていないので、それが原因で上記エラーが発生してしまったようです。

そんなわけで、公開鍵を作り直しました。Rubyでやっても良いのですが、コマンドのほうが簡単です。

openssl rsa -in private.pem -pubout -out public2.pem

こちらのpublic2.pemなら、Javaから正常に読み込めました。

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

baba

ゆとりプログラマー。 高校時代から趣味でプログラミングを初め、そのままコードを書き続けて現在に至る。慶應義塾大学環境情報学部(SFC)卒業。BPS設立初期に在学中から参加している最古参メンバーの一人。Ruby on Rails、PHP、Androidアプリ、Windows/Macアプリ、超縦書の開発などを気まぐれにやる。軽度の資格マニアで、情報処理技術者試験(15区分 + 情報処理安全確保支援士試験)、技術士(情報工学部門)、CITP、Ruby Programmer Goldなどを保有。

babaの書いた記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ