LoginSignup
1
1

iOS APIでは RSA/ECB/OAEPwithSHA-256andMGF1Padding の暗号化・復号ができない

Last updated at Posted at 2022-01-08

iOS の標準APIでは、Java の RSA-OAEP の "RSA/ECB/OAEPwithSHA-256andMGF1Padding" の暗号化・復号ができません。SHA-512も同様。

iOS API と Java の OAEP の違い

OAEP は RSA で使われる平文パディングの手法で、アルゴリズムとしては2つのダイジェスト(ハッシュ)アルゴリズムを使います。

  • メッセージダイジェスト
  • MGF(Mask Generation Function) ダイジェスト

iOS の標準API と Java API では OAEP の仕様が微妙に違います。

  • Java の RSA/ECB/OAEPwithSHA-256andMGF1Padding: メッセージダイジェスト=SHA-256, MGF1ダイジェスト=SHA-1
  • iOS の SecurityAlgorithm.rsaEncryptionOAEPSHA256: メッセージダイジェスト=SHA-256, MGF1ダイジェスト=SHA-256

メッセージダイジェストは同じなのですが、MGF1ダイジェストが違うため、互換性がありません。
MGF1ダイジェストのほうは普通 SHA-1 で十分なはずなのですが、iOS ではなぜかメッセージダイジェストに合わせて変わってしまう様子。

このため、iOS 標準API では、Java の "RSA/ECB/OAEPwithSHA-256andMGF1Padding" に対応することは不可能です。

対策1) Java 側を iOS に合わせる

Java 側を iOS の仕様に合わせる方法です。

Java 側では、メインダイジェストと MGF1 ダイジェストを個別に指定することができるので、容易に iOS 側に合わせることができます。

Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
cipher.init(Cipher.DECRYPT_MODE, privKey, 
    new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));

対策2) 自前で OAEP を実装する

iOS 側で自前で OAEP を実装する方法です。こちらはちょっと面倒。

iOS 側では、OAEP Padding のみを実装し、あとは rsaEncryptionRaw で RSA 暗号化・復号を実行する、ということで MGF1 ダイジェストをあわせることができます。
OAEP の実装自体はそれほど難しくありません。OAEP を実装したものを RsaOaepPadding.swift として公開しています。

これを使うと、RSA/ECB/OAEPwithSHA-256andMGF1Padding 相当の暗号化は以下のように実装できます。

let plainData = "TEST TEXT".data(using: .utf8)!

// main digest SHA256, MGF1 digest SHA1 で RsaOAEPPadding クラスを生成
let padding = RsaOAEPPadding(mainDigest: OAEPDigest.SHA256, mgf1Digest: OAEPDigest.SHA1)

// OAEP Padding を計算 (RSA鍵長は 2048bit = 256byte前提)
let padded = try! padding.pad(plain: plainData, blockSize: 256);

// raw で暗号化
guard let cipherData = SecKeyCreateEncryptedData(publicKey, SecKeyAlgorithm.rsaEncryptionRaw, padded as CFData, &error) else {
    // Error処理
}

復号は以下のようになります。

guard let decryptedBlock = SecKeyCreateDecryptedData(privKey, SecKeyAlgorithm.rsaEncryptionRaw, cipherData as CFData, &error) else {
    // Error 処理
}

// OAEP Padding 解除
let decrypted = try! padding.unpad(padded: decryptedBlock as Data)

let decryptedString = String(data: decrypted, encoding: .utf8)!

検証用テストプログラム

検証用のプログラムおよびライブラリを https://github.com/tmurakam/rsa-oaep においておきます。

Apple に言いたいこと

SecKeyAlgorithm の説明、不足しすぎじゃね?

参考文献・サイトなど

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1