0

当社のお客様は、公開 RSA キーを証明書に保存しています。

クライアント側で暗号化できるように、WinRT アプリでこのキーをハードコーディングする必要があります。ただし、キーを CryptographicKey クラスのインスタンスにインポートする際に問題が発生しています。

RSAProvider で ImportPublicKey を使用しています。

rsaProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
key = rsaProvider.ImportPublicKey(publicKeyBuffer);

いくつかのものを publicKeyBuffer にロードしようとしました: 証明書、証明書からいくつかの形式でエクスポートされた公開鍵。

公開鍵をどのようにロードしますか?

4

3 に答える 3

1

MSDN フォーラムのこの記事は非常に役に立ちました。Carlos Lopez は、Base64 でエンコードされた証明書から公開鍵を取得するコードを投稿しました。

http://social.msdn.microsoft.com/Forums/en-US/17e1467a-2de7-47d2-8d8c-130518eaac68/how-to-use-a-x509-certificate-not-a-pfx-to-verify-サイン

ここにコード:

public static CryptographicKey GetCryptographicPublicKeyFromCert(string strCert)
    {
        int length;
        CryptographicKey CryptKey = null;

        byte[] bCert = Convert.FromBase64String(strCert);

        // Assume Cert contains RSA public key 
        // Find matching OID in the certificate and return public key
        byte[] rsaOID = EncodeOID("1.2.840.113549.1.1.1");
        int index = FindX509PubKeyIndex(bCert, rsaOID, out length);

        // Found X509PublicKey in certificate so copy it.
        if (index > -1)
        {
            byte[] X509PublicKey = new byte[length];
            Array.Copy(bCert, index, X509PublicKey, 0, length);

            AsymmetricKeyAlgorithmProvider AlgProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
            CryptKey = AlgProvider.ImportPublicKey(CryptographicBuffer.CreateFromByteArray(X509PublicKey));
        }

        return CryptKey;
    }

    static int FindX509PubKeyIndex(byte[] Reference, byte[] value, out int length)
    {
        int index = -1;
        bool found;
        length = 0;

        for (int n = 0; n < Reference.Length; n++)
        {
            if ((Reference[n] == value[0]) && (n + value.Length < Reference.Length))
            {
                index = n;
                found = true;

                for (int m = 1; m < value.Length; m++)
                {
                    if (Reference[n + m] != value[m])
                    {
                        found = false;
                        break;
                    }
                }

                if (found) break;
                else index = -1;
            }
        }

        if (index > -1)
        {
            // Find outer Sequence
            while (index > 0 && Reference[index] != 0x30) index--;
            index--;
            while (index > 0 && Reference[index] != 0x30) index--;
        }

        if (index > -1)
        {
            // Find the length of encoded Public Key
            if ((Reference[index + 1] & 0x80) == 0x80)
            {
                int numBytes = Reference[index + 1] & 0x7F;
                for (int m = 0; m < numBytes; m++)
                {
                    length += (Reference[index + 2 + m] << ((numBytes - 1 - m) * 8));
                }

                length += 4;
            }
            else
            {
                length = Reference[index + 1] + 2;
            }
        }

        return index;
    }

    static public byte[] EncodeOID(string szOID)
    {
        int[] OIDNums;
        byte[] pbEncodedTemp = new byte[64];
        byte[] pbEncoded = null;
        int n, index, num, count;

        OIDNums = ParseOID(szOID);

        pbEncodedTemp[0] = 6;

        pbEncodedTemp[2] = Convert.ToByte(OIDNums[0] * 40 + OIDNums[1]);
        count = 1;

        for (n = 2, index = 3; n < OIDNums.Length; n++)
        {
            num = OIDNums[n];

            if (num >= 16384)
            {
                pbEncodedTemp[index++] = Convert.ToByte(num / 16384 | 0x80);
                num = num % 16384;

                count++;
            }

            if (num >= 128)
            {
                pbEncodedTemp[index++] = Convert.ToByte(num / 128 | 0x80);
                num = num % 128;

                count++;
            }


            pbEncodedTemp[index++] = Convert.ToByte(num);
            count++;
        }

        pbEncodedTemp[1] = Convert.ToByte(count);

        pbEncoded = new byte[count + 2];
        Array.Copy(pbEncodedTemp, 0, pbEncoded, 0, count + 2);

        return pbEncoded;
    }

    static public int[] ParseOID(string szOID)
    {
        int nlast, n = 0;
        bool fFinished = false;
        int count = 0;
        int[] dwNums = null;

        do
        {
            nlast = n;
            n = szOID.IndexOf(".", nlast);
            if (n == -1) fFinished = true;
            count++;
            n++;
        } while (fFinished == false);

        dwNums = new int[count];

        count = 0;
        fFinished = false;

        do
        {
            nlast = n;
            n = szOID.IndexOf(".", nlast);
            if (n != -1)
            {
                dwNums[count] = Convert.ToInt32(szOID.Substring(nlast, n - nlast), 10);
            }
            else
            {
                fFinished = true;
                dwNums[count] = Convert.ToInt32(szOID.Substring(nlast, szOID.Length - nlast), 10);
            }

            n++;
            count++;
        } while (fFinished == false);

        return dwNums;
    }
于 2014-05-14T09:34:33.157 に答える
0

2つのこと:

  1. ImportPublicKey キーへの引数は IBuffer です。これを取得する最も簡単な方法は、byte[] に ToBuffer 拡張メソッドを使用することです。
  2. IBuffer とCryptographicPublicKeyBlobTypeの両方を受け取る ImportPublicKeyのオーバーライド、具体的には CryptographicPublicKeyBlobType.X509SubjectPublicKeyInfo を使用します。証明書からサブジェクトの公開鍵情報フィールドを渡します。
于 2012-09-17T13:11:39.690 に答える
0

証明書に格納された公開キーを WinRT アプリで使用する方法について頭を悩ませている方のために、痛みを和らげさせてください。少なくとも直接はできません。

このAsymmetricKeyAlgorithmProvider.ImportPublicKey関数は、IBuffer と CryptographicPublicKeyBlobType、keyBlob (IBuffer) パラメーターを受け取ります。これは証明書の公開鍵であり、完全な証明書ではなく、その公開鍵のみです。

ただし、最初に解析しないと証明書の公開キーを取得できません。ここに問題があり、WinRT で証明書を解析する方法はありません。このタスクで最も使用されるクラスである X509Certificate がまた、その名前空間もありません。証明書の機能は、Web サービス接続でのみ使用されます。

これを回避する唯一の方法は、証明書パーサーを実装するか、 Bouncy Castleなどのオープン ソース プロジェクトからそのような機能を移植することです。なので、ご存知の方はコメントに残してください。

ところで、WinRT アプリで使用できる形式で (プレーンな .NET で) 証明書から公開キーをエクスポートするには、次のようにします。

X509Certificate2 Certificate;
....
byte[] CertificatePublicKey = Certificate.PublicKey.EncodedKeyValue.RawData;

次に、WinRT アプリでこれを使用します。

AsymmetricKeyAlgorithmProvider algorithm = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaSignPkcs1Sha1);
IBuffer KeyBuffer = CryptographicBuffer.DecodeFromBase64String(CertificatePublicKeyContent);
CryptographicKey key = algorithm.ImportPublicKey(KeyBuffer, CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey);

最初に base 64 で公開鍵をエンコードしましたが、代わりに未加工のバイナリ データを使用することもできます (CryptographicBuffer クラスには、この目的のためのメソッドが他にもあります)。

于 2012-12-11T19:31:45.827 に答える