web-dev-qa-db-ja.com

.NETでのRSA暗号化/復号化の問題

RSAを使用したC#の暗号化と復号化に問題があります。私は機密性の高い財務情報と取引を送信するWebサービスを開発しました。私ができるようにしたいのは、クライアント側で、クライアントのRSA秘密鍵を使用して特定のフィールドを暗号化することです。サービスに到達すると、クライアントの公開鍵で復号化されます。

現時点では、「復号化されるデータが、このモジュラスの最大値である128バイトを超えています」というメッセージが表示され続けます。例外。私はC#RSA暗号化をあまり扱っていないので、助けていただければ幸いです。

これは私がキーを生成するために使用している方法です

private void buttonGenerate_Click(object sender, EventArgs e)
{
    string secretKey = RandomString(12, true);

    CspParameters param = new CspParameters();
    param.Flags = CspProviderFlags.UseMachineKeyStore;

    SecureString secureString = new SecureString();
    byte[] stringBytes = Encoding.ASCII.GetBytes(secretKey);
    for (int i = 0; i < stringBytes.Length; i++)
    {
        secureString.AppendChar((char)stringBytes[i]);
    }
    secureString.MakeReadOnly();
    param.KeyPassword = secureString;

    RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(param);
    rsaProvider = (RSACryptoServiceProvider)RSACryptoServiceProvider.Create();
    rsaProvider.KeySize = 1024;


    string publicKey = rsaProvider.ToXmlString(false);
    string privateKey = rsaProvider.ToXmlString(true);

    Repository.RSA_XML_PRIVATE_KEY = privateKey;
    Repository.RSA_XML_PUBLIC_KEY = publicKey;

    textBoxRsaPrivate.Text = Repository.RSA_XML_PRIVATE_KEY;
    textBoxRsaPublic.Text = Repository.RSA_XML_PUBLIC_KEY;

    MessageBox.Show("Please note, when generating keys you must sign on to the gateway\n" +
        " to exhange keys otherwise transactions will fail", "Key Exchange", MessageBoxButtons.OK, MessageBoxIcon.Information);

}

キーを生成したら、公開キーをWebサービスに送信します。WebサービスはそれをXMLファイルとして保存します。

今私はこれをテストすることに決めたので、これが文字列を暗号化する私の方法です

public static string RsaEncrypt(string dataToEncrypt)
{
    string rsaPrivate = RSA_XML_PRIVATE_KEY;
    CspParameters csp = new CspParameters();
    csp.Flags = CspProviderFlags.UseMachineKeyStore;

    RSACryptoServiceProvider provider = new RSACryptoServiceProvider(csp);

    provider.FromXmlString(rsaPrivate);

    ASCIIEncoding enc = new ASCIIEncoding();
    int numOfChars = enc.GetByteCount(dataToEncrypt);
    byte[] tempArray = enc.GetBytes(dataToEncrypt);
    byte[] result = provider.Encrypt(tempArray, true);
    string resultString = Convert.ToBase64String(result);
    Console.WriteLine("Encrypted : " + resultString);
    return resultString;
}

暗号化された値のように見えます。私が作成したテスト暗号化Webメソッドでは、この暗号化されたデータを取得し、クライアントの公開鍵を使用してデータを復号化して、これを平文で送り返します。しかし、これは例外がスローされる場所です。これが私の方法です。

public string DecryptRSA(string data, string merchantId)
{
    string clearData = null;
    try
    {
        CspParameters param = new CspParameters();
        param.Flags = CspProviderFlags.UseMachineKeyStore;
        RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(param);

        string merchantRsaPublic = GetXmlRsaKey(merchantId);
        rsaProvider.FromXmlString(merchantRsaPublic);
        byte[] asciiString = Encoding.ASCII.GetBytes(data);

        byte[] decryptedData = rsaProvider.Decrypt(asciiString, false);

        clearData = Convert.ToString(decryptedData);
    }
    catch (CryptographicException ex)
    {
        Log.Error("A cryptographic error occured trying to decrypt a value for " + merchantId, ex);

    }
    return clearData;
}

誰かが私を助けてくれるなら、それは素晴らしいことです。私が言ったように、私はC#RSA暗号化/復号化をあまり行っていません。

17
Brendon Randall

少し用語を教えてください。 非対称暗号化デジタル署名があります。

  • 非対称暗号化とは、機密性を維持することです。一部の機密データは、復号化キーを知っているエンティティを除いて、読み取り不可能なものに変換されます。復号化キーは必然的にprivateキーです。復号化キーが公開キーの場合、誰でもデータを復号化でき(公開キーは公開です)、機密性はなくなります。非対称暗号化では、公開鍵で暗号化し、対応する秘密鍵で復号化します。

  • デジタル署名は、整合性を証明することを目的としています。チェックサムとデータの間のリンクを後で検証できるように、誰かがデータに対して一種のキー付きチェックサムを計算します。これが「署名」であるのは、そのチェックサムを計算する能力が公開されていない何かの知識を必要とするためです。簡単に言えば、署名はprivateキーを使用します。ただし、検証は誰でも実行できる必要があるため、公開鍵を使用します。

「the」RSAアルゴリズムは実際には数学演算であり、非対称暗号化システムとデジタル署名システムの両方に分類できるという事実から、かなりの混乱が生じています。混乱は、RSA標準(別名 PKCS#1 )によってさらに強化されます。これは、RSAデジタル署名が最初に記述された方法、つまり「逆暗号化」(「署名者がデータを暗号化する」)に暗黙的に依存します。秘密鍵」)。これは、「sha1WithRSAEncryption」と呼ばれるRSA署名のようなものにつながります。これは非常に残念です。

したがって、最初に機密性と署名のどちらが必要かを決定する必要があります。機密保持のため、送信されるデータの場合fromクライアントtoサーバーの場合、サーバーは秘密鍵を所有し、クライアントはtheサーバーの公開鍵を使用します。データを暗号化します。署名の場合、各クライアントは独自の秘密鍵を持ち、それを使用してデータに署名し、サーバーが署名を検証します。あなたの説明から、私が上でほのめかした混乱のおかげで、あなたが本当に何を求めているのかわかりません。

また、authenticationと呼ばれるものがあります。これはデジタル署名のように見えるかもしれませんが、より弱いものです。署名のポイントは誰でも署名を検証できるということです。特に、署名は裁判官に提示することができ、したがって法的武器として機能することができますに対して署名者(署名は法的拘束力があります-少なくともあなたが正しく行う場合、そして現在の規制の状態では電子署名では、これは簡単ではありません)。ほとんどの場合、必要なのはより弱くて単純なものだけです。サーバーは適切なクライアントと通信していると確信していますが、その後、このクライアントが実際に存在していることを他の人に納得させることはできません。ユーザーパスワードを持つWebサイトは、このような認証を使用しています。

そうは言っても...

  • RSA非対称暗号化は、ショートメッセージのみを対象としています。 1024ビットRSAキー(つまり、最も重要な部分である「RSAモジュラス」が2 ^ 1023〜2 ^ 1024の値の大きな数値であり、暗号化されたメッセージの長さが128バイトであるキー)の場合、暗号化されたメッセージの最大サイズは117バイトです(これがエラーメッセージの実際のソースです)。より長いメッセージを送信する場合は、ハイブリッドシステムを使用します。このシステムでは、ランダムビットの小さな束(たとえば128ビット)のみを暗号化し、その束を対称暗号化システムのキーとして使用します(例:AES)これははるかに長いメッセージを処理できます(そしてはるかに高速です)。

  • 同様に、RSA署名はショートメッセージでのみ計算できるため、PKCS#1標準では、署名は実際にはハッシュ値に対して計算されることが義務付けられています。ハッシュ値は、特定のハッシュ関数の出力であり、署名するメッセージに対して計算されます。ハッシュ関数の出力は固定サイズ(SHA-256の場合は256ビットなど)ですが、(ほぼ)任意の長さの入力メッセージを受け入れます。ハッシュ関数は公開されており(キーはありません)、適切なセキュリティのために、いくつかの特別なプロパティが必要です。 SHA-256は、現時点では悪い選択ではありません。 SHA-1(SHA-256の前身)にはいくつかの弱点があることが証明されているため、回避する必要があります。 MD5には(SHA-1の一種の叔父)より大きな弱点があるため、使用しないでください。

  • 特にハイブリッド方式での非対称暗号化とデジタル署名の適切な使用は、上記のテキストが示唆するものよりも注意が必要です。ある時点で間違いを犯すのは非常に簡単です。目に見えない、つまり、コードは機能しているように見えますが、攻撃者にとって有用なデータが漏洩します。非対称暗号化またはデジタル署名を使用するrightの方法は、既存のよく考えられたプロトコルに依存することです。プロトコルは、暗号化要素をコヒーレントシステムに組み立てたものであり、リークが処理されます。代表的な例は、SSLとも呼ばれるTLSです。これは、整合性と認証(場合によっては相互認証)を使用して、機密データの送信を保証するプロトコルです。 HTTPSプロトコルは、HTTPとSSLを組み合わせたものです。明るい面は、HTTPSには、特にC#で既存の実装があることです。実装とデバッグが最も簡単なコードは、すでに実装とデバッグが行われているコードです。したがって、HTTPSを使用すると、長生きして幸せになります。

34
Thomas Pornin

なぜあなたが質問をしているのか理解しています。問題は、RSAが、一度に8バイトを1日中暗号化する一般的なブロック暗号(AESや3DESなど)のように使用されないことです。 RSAは、除算の余り(モジュラス)を返す数学演算です。小学校に戻って、筆算を学んだとき、余りが除数より大きくなることは決してないことを覚えておいてください。20を7で割る場合、余りは6です。7で割った整数に関係なく、余りは大きくなりません。 6より。

RSA数学も同じ方法です。たとえば、1024ビットのRSA公開鍵を使用している場合、余りは2 ^ 1024(128バイトのみ)を超えることはできません。したがって、このキーで一度に暗号化できるのは128バイトのみです。 (これが、RSAキーのサイズをビット数で測定する理由の1つです。)

技術的には、このRSAキーをループで使用して、一度に128バイトのデータチャンクを暗号化できます。実際には、RSAの計算は大きくて遅いため、これを行うことはほとんどありません。代わりに、いわゆる「2フェーズ」暗号化を使用します。 RSAを使用して短い「セッションキー」のみを暗号化し、次にそのセッションキーを高速対称キーブロック暗号(AESなど)で使用して実際のデータを暗号化します。

プロトコル全体は次のとおりです。

  1. 宛先のRSA公開鍵を取得します。多くの場合、これは証明書に埋め込まれて配信されます。そうである場合は、証明書を検証して、キーが本物であることを確認してください。 RSAキーの長さが2048ビットであるとしましょう。
  2. ブロック暗号のキーとして使用する暗号的に強力な疑似乱数を生成します(たとえば、AES-256のキーとして256ビットが必要です)。256<2048、RSA-2048が一度に暗号化できる最大値に注意してください。 。この乱数を「セッションキー」と呼びます。
  3. RSA2048ビット公開鍵を使用してセッション鍵を暗号化します。それはあなたに2048ビットの暗号化されたセッションキーを与えるでしょう。この操作は非常に遅いことに注意してください。
  4. セッションキーを使用して、AES-256を使用してすべての秘密データを暗号化します。これはステップ3よりもはるかに高速であることに注意してください。
  5. 証明書の公開鍵ID、RSA暗号化セッション鍵、およびAES暗号化データをバンドルします。また、フォーマット識別子とバージョン番号でタグ付けするので、どのフォーマットであるか、どのように復号化するかがわかります。
  6. バンドルを宛先に送信します。

  7. 宛先では、フォーマット識別子とバージョンを使用してバンドルを分解します。

  8. IDが公開鍵IDフィールドにある秘密鍵を取得します。
  9. RSAでこの秘密鍵を使用して、セッション鍵を復号化します。
  10. AESのセッションキーを使用してデータを復号化します。

これを行う場合は、それがまさにCMS(PKCS#7)形式の目的であることを知っておく必要があります。独自のフォーマットを考案するのではなく、標準について学び、それを採用することをお勧めします。 MicrosoftのCSPはそれをサポートしているので、簡単なはずです。

標準に従わない場合は、「RSA暗号化プロセスでAESキービットをどの形式にする必要があるか」などについて独自の決定を行う必要があります。多くの場合、セキュリティ上の間違いを犯し、システムを弱体化させるでしょう。さらに、標準に従わないと、CSPなどのツールの操作が非常に困難になることがわかります。

14
John Deters

DecryptRSAでは、「データベース」base 64はエンコードされていますか?そうである場合は、最初にそれを元に戻す必要があります。

正直なところ、暗号化の経験が豊富でない限り、「機密性の高い財務情報」を保護するために、このルーチンを自分で実装するべきではないと思います。エラーを起こす方法は多すぎます。 SSLと証明書、またはPGPまたはGnuPGだけの、すぐに使えるソリューションを使用する方がよいでしょうか。

3
stmax

RSAは、データ自体を暗号化するのではなく、主にデータの安全なハッシュを検証するために使用されます。したがって、データの大きなブロブが与えられた場合、SHA512を使用してそのデータのハッシュを作成してから、RSAを使用してそのハッシュをsignにすることができます。

AESや3DESなどの大きなデータブロックには対称暗号化アルゴリズムを使用することをお勧めします。

安全なトランザクションの管理は簡単ではなく、昼夜を問わずそれについて考える人に任せるべきです。サービスをWeb経由で公開している場合は、データをすでに暗号化して保護しているSSLを使用するだけです。

3
Paul Alexander

まず、何から保護しようとしているのかを判断します。秘密鍵を使用して何かを「暗号化」する場合、公開鍵は-まあ-publicであるため、誰でも公開鍵で「復号化」できます。

実際に署名したい場合は、(Paul Alexanderが説明しているように)秘密鍵を使用してハッシュに署名する必要があります。秘密鍵はサーバーで検証できます。

RSAを使用してデータをencryptするには、最初にランダム対称鍵(f.x. AES)を生成し、public鍵を使用して鍵を暗号化し、対称鍵を使用してデータを暗号化する必要があります。次に、暗号化されたキーを暗号化されたデータと一緒にprivateキーの所有者に送信できます。所有者は、最初に暗号化されたキーを秘密キーで復号化し、次に対称キーでデータを復号化します。

SSLの使用を検討することもできますが、認証を慎重に検討することを忘れないでください。おそらくクライアント認証が必要であり、信頼する証明書を決定する必要があります(Verisignによって発行された証明書を盲目的に受け入れるべきではありません)。

2
Rasmus Faber