12
votes

Utilisation d'une clé publique RSA pour déchiffrer une chaîne cryptée à l'aide de la clé privée RSA

Je connais la réponse principale que je suis susceptible d'obtenir c'est pourquoi diable voudriez-vous faire ça ?!

Malheureusement malgré mes manifestations, je dois le faire, même si je sais que cela a peu de sens. P>

J'ai des fonctions écrites dans .NET à Decrypt en utilisant une clé privée, chiffrer à l'aide d'une clé publique. Je signe également RSA et vérifie et j'ai une compréhension raisonnable de la façon dont tout ce travail que je pense. P>

Je suis maintenant envoyé une valeur RSA cryptée à l'aide d'une clé privée que je suis censé dériver une valeur utilisable. En décryptant en utilisant la clé publique. P>

Je n'arrive pas à comprendre comment faire cela. Suis-je un idiot? Est-ce une chose normale à faire? P>

On me dit que la personne m'envoyait la valeur que ce n'est pas un problème dans PHP. Je ne sais pas et je n'ai pas encore utilisé php. Je ne trouve pas une bibliothèque pour le faire dans l'une des langues principales que je connais I.e. C ++, Java, C #. Le serveur que je travaille sur utilise .NET. P>

J'espère que quelqu'un pourrait peut-être m'aider. p>

Ce serait formidable s'il ya une sorte de solution raisonnable en plus de les supplier de changer ce qu'ils font. P>

C'est ma méthode (mise à jour de mon précédent mauvais omes par Iridium) mais lorsque j'essaie de déchiffrer la valeur, une erreur d'exception p>

"s'est produite lors du décodage du remplissage OAEP." p>

Si j'utilise rsa.decrypt (octets, false) i Obtenez une mauvaise exception de clé. P>

public static string DecryptUsingPublic(string dataEncrypted, string publicKey)
    {
        if (dataEncrypted == null) throw new ArgumentNullException("dataEncrypted");
        if (publicKey == null) throw new ArgumentNullException("publicKey");
        try
        {
            RSAParameters _publicKey = LoadRsaPublicKey(publicKey, false);
            RSACryptoServiceProvider rsa = InitRSAProvider(_publicKey);

            byte[] bytes = Convert.FromBase64String(dataEncrypted);
            byte[] decryptedBytes = rsa.Decrypt(bytes, true);

            ArrayList arrayList = new ArrayList();
            arrayList.AddRange(decryptedBytes);

           return Encoding.UTF8.GetString(decryptedBytes);
        }
        catch
        {
            return null;
        }
    }

    private static RSAParameters LoadRsaPublicKey(String publicKeyFilePath, Boolean isFile)
    {
        RSAParameters RSAKeyInfo = new RSAParameters();
        byte[] pubkey = ReadFileKey(publicKeyFilePath, "PUBLIC KEY", isFile);
        byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
        byte[] seq = new byte[15];
        // ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------
        MemoryStream mem = new MemoryStream(pubkey);
        BinaryReader binr = new BinaryReader(mem);    //wrap Memory Stream with BinaryReader for easy reading
        byte bt = 0;
        ushort twobytes = 0;

        try
        {

            twobytes = binr.ReadUInt16();
            if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                binr.ReadByte();    //advance 1 byte
            else if (twobytes == 0x8230)
                binr.ReadInt16();   //advance 2 bytes
            else
                return RSAKeyInfo;

            seq = binr.ReadBytes(15);       //read the Sequence OID
            if (!CompareBytearrays(seq, SeqOID))    //make sure Sequence for OID is correct
                return RSAKeyInfo;

            twobytes = binr.ReadUInt16();
            if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)
                binr.ReadByte();    //advance 1 byte
            else if (twobytes == 0x8203)
                binr.ReadInt16();   //advance 2 bytes
            else
                return RSAKeyInfo;

            bt = binr.ReadByte();
            if (bt != 0x00)     //expect null byte next
                return RSAKeyInfo;

            twobytes = binr.ReadUInt16();
            if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                binr.ReadByte();    //advance 1 byte
            else if (twobytes == 0x8230)
                binr.ReadInt16();   //advance 2 bytes
            else
                return RSAKeyInfo;

            twobytes = binr.ReadUInt16();
            byte lowbyte = 0x00;
            byte highbyte = 0x00;

            if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81)
                lowbyte = binr.ReadByte();  // read next bytes which is bytes in modulus
            else if (twobytes == 0x8202)
            {
                highbyte = binr.ReadByte(); //advance 2 bytes
                lowbyte = binr.ReadByte();
            }
            else
                return RSAKeyInfo;
            byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };   //reverse byte order since asn.1 key uses big endian order
            int modsize = BitConverter.ToInt32(modint, 0);

            byte firstbyte = binr.ReadByte();
            binr.BaseStream.Seek(-1, SeekOrigin.Current);

            if (firstbyte == 0x00)
            {   //if first byte (highest order) of modulus is zero, don't include it
                binr.ReadByte();    //skip this null byte
                modsize -= 1;   //reduce modulus buffer size by 1
            }

            byte[] modulus = binr.ReadBytes(modsize);   //read the modulus bytes

            if (binr.ReadByte() != 0x02)            //expect an Integer for the exponent data
                return RSAKeyInfo;
            int expbytes = (int)binr.ReadByte();        // should only need one byte for actual exponent data (for all useful values)
            byte[] exponent = binr.ReadBytes(expbytes);


            RSAKeyInfo.Modulus = modulus;
            RSAKeyInfo.Exponent = exponent;

            return RSAKeyInfo;
        }
        catch (Exception)
        {
            return RSAKeyInfo;
        }

        finally { binr.Close(); }
        //return RSAparams;

    }

 private static RSACryptoServiceProvider InitRSAProvider(RSAParameters rsaParam)
    {
        //
        // Initailize the CSP
        //   Supresses creation of a new key
        //
        CspParameters csp = new CspParameters();
        //csp.KeyContainerName = "RSA Test (OK to Delete)";

        const int PROV_RSA_FULL = 1;
        csp.ProviderType = PROV_RSA_FULL;

        const int AT_KEYEXCHANGE = 1;
        // const int AT_SIGNATURE = 2;
        csp.KeyNumber = AT_KEYEXCHANGE;
        //
        // Initialize the Provider
        //
        RSACryptoServiceProvider rsa =
          new RSACryptoServiceProvider(csp);
        rsa.PersistKeyInCsp = false;

        //
        // The moment of truth...
        //
        rsa.ImportParameters(rsaParam);
        return rsa;
    }

    private static int GetIntegerSize(BinaryReader binr)
    {
        byte bt = 0;
        byte lowbyte = 0x00;
        byte highbyte = 0x00;
        int count = 0;
        bt = binr.ReadByte();
        if (bt != 0x02)     //expect integer
            return 0;
        bt = binr.ReadByte();

        if (bt == 0x81)
            count = binr.ReadByte();    // data size in next byte
        else
            if (bt == 0x82)
            {
                highbyte = binr.ReadByte(); // data size in next 2 bytes
                lowbyte = binr.ReadByte();
                byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
                count = BitConverter.ToInt32(modint, 0);
            }
            else
            {
                count = bt;     // we already have the data size
            }

        while (binr.ReadByte() == 0x00)
        {   //remove high order zeros in data
            count -= 1;
        }
        binr.BaseStream.Seek(-1, SeekOrigin.Current);       //last ReadByte wasn't a removed zero, so back up a byte
        return count;
    }

    private static bool CompareBytearrays(byte[] a, byte[] b)
    {
        if (a.Length != b.Length)
            return false;
        int i = 0;
        foreach (byte c in a)
        {
            if (c != b[i])
                return false;
            i++;
        }
        return true;
    }


10 commentaires

Tu peux répéter s'il te plait? C'est exactement ce que l'algorithme est censé faire. Décrypte en utilisant une clé privée Qu'est-ce qui a été crypté à l'aide de la clé publique correspondante. Soit tu es confus gros fois ou je suis! C # favorise parfaitement RSA :)


Désolé. Édité ma question. Je l'ai écrit complètement mal. Le cerveau commence à brouiller un peu le vendredi.


Qu'est-ce que tu ne peux pas comprendre? Vous dites que vous avez déjà des fonctions pour déchiffrer avec une clé publique.


D'accord, désolé. J'aurais dû lire ma question correctement. Fait un gâchis total de celui-ci. J'ai le déchiffrement standard avec une clé privée et non publique. Si j'essaie de déchiffrer la valeur cryptée à l'aide de la clé privée avec la clé publique, je reçois une exception - les données à déchiffrer dépassent le maximum de ce module de 128 octets. J'ai cherché à essayer beaucoup de choses, mais je continue à obtenir des exceptions.


Que font LoadrsapublicKey et InitirsAprovider? Pouvez-vous aussi fournir le code de ces méthodes aussi?


Bien sûr, le code est assez long mais je vais l'ajouter. Les clés sont des clés PEM issues d'une base de données comme chaînes.


Hey, j'ai le même problème essayé votre code, mais il n'existe toujours pas que la clé n'existe pas, quelle est exactement Listerfilekey Looke, quel est le format de votre clé?


Désolé Oscar Cabrero. C'était un moment de retour et je ne me souviens pas des détails précis. Je sais que le code dans ma question est faux et n'a pas fonctionné. Je l'ai éventuellement résolu à l'aide de ce tutoriel: codeproject.com/kb/security/privatecryption.aspx et les détails de la réponse acceptée. Je regrette maintenant de ne pas poster toute ma solution. Je n'ai plus le code et je n'ai certainement pas de mémoire assez bon pour la reproduire correctement sans prendre un peu de temps. Quant à la clé, je lis cela comme une chaîne d'une base de données. J'ai reçu les clés que les fichiers PEM, copié les valeurs à la base de données et lisez à partir de là.


Que référencez-vous pour "Readfilekey" ??


AVERTISSEMENT: Cryptage avec une clé privée et un déchiffrement avec une clé publique est intrinsèquement dangereux et n'est pas identique à la génération / vérification de la signature. Ok, vous avez été averti, vous pouvez continuer à vous tirer au pied maintenant.


3 Réponses :


15
votes

RSA est intégrée dans .NET:. System.Security.Cryptography.RSA

Encrypting en utilisant la clé publique et avec la clé de décryptage privée est l'une des choses les plus communes que les gens font avec des algorithmes asymétriques, il permet à chacun de vous envoyer quelque chose en toute sécurité.

Si vous le faites dans l'autre sens: Crypter avec la clé privée, et décrypter avec la clé publique alors il prouve le message a été envoyé par le titulaire de la clé privée. Mais parce que tout le monde peut sans doute mettre la main sur la clé publique, les gens ont tendance à ne pas chiffrer le message entier, ils signent plutôt juste un hachage des données à l'aide de la clé privée. Par conséquent RSACryptoServiceProvider a __ Connexion et Vérifier __ pour le faire.

Pourtant, il y a Crypter / Décrypter si votre partenaire insiste sur le fait.

Dire que j'ai trouvé les cours de Microsoft Crypto un peu difficile à traiter et manque dans certains domaines et beaucoup préfèrent la Bouncy bibliothèques Château .


5 commentaires

Désolé je suis un idiot. J'ai eu ma question complètement en arrière. Je l'ai édité pour montrer ce que je voulais dire.


Je pensais alors! Mise à jour de la réponse.


Merci beaucoup pour votre réponse. Je ne peux pas sembler obtenir la méthode Decrypt pour travailler dans ce cas. J'ai mis à jour ma question à montrer où cela va mal. Je fais probablement quelque chose de stupide et marquera cela comme la réponse dès que je trouve ce que c'est.


Ajout d'une suggestion d'essayer les bibliothèques du château gonflable - ils ont tendance à inter-opérer avec le monde non MS un peu mieux.


Va regarder dans le château de Bouncy. Merci pour votre suggestion.



12
votes

Après avoir examiné certaines des informations sur les modes de cryptage RSA, il semblerait que PKCS # 1 v1.5 (que vous utilisez, parce que vous appelez Décrypter (..., false) code>)

"... peut fonctionner sur des messages de longueur jusqu'à k - 11 octets em> strong> (k est la longueur d'octet du module RSA)" p> Blockquote>

(RFC 3447, Souligné par l'auteur) p>

D'après le message d'erreur, ce qui indique que la clé est de 128 octets, cela signifie que vous ne pouvez pas effectuer RSA (en |. De ) Cryption utilisant PKCS # 1 v1.5 sur un message avec plus de 128 -. 11 = 117 octets p>

au lieu de chiffrer votre message directement en utilisant RSA, vous devez utiliser un algorithme symétrique pour chiffrer le corps le message et chiffrent uniquement la clé de chiffrement symétrique en utilisant RSA. Seulement si votre message est raisonnablement court (par exemple ci-dessous 117 octets pour votre taille de la clé) devrait vous envisager de chiffrer le message directement avec RSA. P>

J'ai ajouté ce qui suit, en supposant que votre entrée est codé en Base64 que vous indiquez dans votre commentaire ci-dessous: p>

public string DecryptUsingPublic(string dataEncryptedBase64, string publicKey)
    {
        if (dataEncryptedBase64 == null) throw new ArgumentNullException("dataEncryptedBase64");
        if (publicKey == null) throw new ArgumentNullException("publicKey");
        try
        {
            RSAParameters _publicKey = LoadRsaPublicKey(publicKey, false);
            RSACryptoServiceProvider rsa = InitRSAProvider(_publicKey);

            byte[] bytes = Convert.FromBase64String(dataEncryptedBase64);
            byte[] decryptedBytes = rsa.Decrypt(bytes, false);

            // I assume here that the decrypted data is intended to be a
            // human-readable string, and that it was UTF8 encoded.
            return Encoding.UTF8.GetString(decryptedBytes);
        }
        catch
        {
            return null;
        }
    }


5 commentaires

Merci pour votre réponse. J'ai lu RFC 3447 toute la journée en essayant de trouver une solution. Le principal problème est que je n'ai aucun contrôle sur la manière dont la valeur est cryptée. Fondamentalement, je reçois une valeur i.e. valeur = base64 [rsa_private_encrypt (quelque_text)] Il m'a été laissé à comprendre comment décrypter et utiliser cette valeur. J'ai essayé beaucoup de choses mais pas de joie. J'ai demandé un exemple de travail pour le déchiffrement de la personne qui m'envoie la valeur. Si je l'obtiens, je le posterai ici.


Ce n'est pas ce que votre code de code suggère, car vous n'avez pas de décodage de base64. (Vous ne devriez pas utiliser Encoding.Actentii à cet effet soit, car il est seulement 7 bits). Si votre entrée est base64, vous devez utiliser Convert.frombase64String (datacrypted) pour obtenir un tableau d'octets à utiliser avec les fonctions RSA.


Bien que ma réponse d'origine s'applique toujours, j'ai ajouté du code à ma réponse qui peut corriger votre problème, en fonction de l'hypothèse que l'entrée est en fait de base64 codée comme indiqué dans votre commentaire ci-dessus.


Merci. Vous avez raison. J'étais censé utiliser la base64. C'était une erreur stupide commise comme j'essayais d'inverser la méthode de chiffrement. J'ai mis à jour ma question.


Enfin, utilisez-le en utilisant votre conseil et votre code source d'ici codeProject.com/kb/security/ PrivéCollection.aspx



6
votes

RSA est non destiné à chiffrer des données arbitraires, encore moins de longueur de données arbitraire (comme @iridium vous a déjà dit). La limite dépend du rembourrage utilisé et de l'utilisation du rembourrage est très important (suffisant que MS ne vous laisse pas appeler chiffrervalue et déchiffsvalue directement) .

Le moyen droit pour le faire consiste à chiffrer votre chaîne à l'aide d'un chiffre symétrique (comme AES), puis chiffrez la clé secrète à l'aide de la clé publique RSA.

L'autre partie sera en mesure de déchiffrer la clé Secret (AES) à l'aide de la clé privée RSA. Ensuite, utilisez la touche décrypte votre chaîne.

J'ai un vieux (mais toujours à jour) Entrée de blog sur Le sujet qui comprend code source (C #).


4 commentaires

Merci pour votre réponse. Je suis complètement d'accord avec toi. Le problème est que je ne chiffre pas la valeur. J'ai une clé privée et une clé publique. Je suis envoyé une valeur qui a été cryptée à l'aide de la clé privée et je dois maintenant comprendre comment la déchiffrer. Cela peut ne pas avoir de sens et il peut ne pas y avoir une solution simple, mais je ne suis pas très expérimenté avec cela, donc j'apprécie tous les commentaires et suggestions.


Si vous êtes coincé sur la touche Diffrigation , vous n'avez pas de choix (sûr ou non) que de faire les opérations inverse pour récupérer les données. J'espère que cela ne vous obligera pas à utiliser déchiffsvalue (il ne doit pas si l'autre, crypter, utilisation de la partie .NET), mais même alors il y a des solutions pour cela :) Faites-nous savoir!


Je ne comprends pas cela de votre blog il a également un sens "Security wise" car une clé symétrique de 128 bits est plus sécurisée qu'un clavier asymétrique de 1024 bits (au moins pour RSA) . Pourriez-vous expliquer plus sur la manière dont AES est plus sécurisé que RSA?


Il ne s'agit pas de AES ou de RSA eux-mêmes (trop différent), il s'agit de la longueur de la clé utilisée pour les deux (c'est-à-dire que c'est difficile de les casser). Je dois être plus facile à casser RSA 1024 que l'AES 128. Suggéré a suggéré de lire Security.stackexchange.com/questions/38015/...