1 votes

Comment inverser le processus de cette méthode C# Decode pour créer une méthode Encode ?

J'aimerais savoir comment inverser le processus du DecodeBinaryBase64 ci-dessous afin d'avoir une méthode Encode correspondante. En bref, un code C# qui, si on lui donne la sortie de cette méthode, renverrait la même chaîne que celle qu'il a prise en entrée.

private static string DecodeBinaryBase64(string stringToDecode)
{
    StringBuilder builder = new StringBuilder();
    foreach (var b in Convert.FromBase64String(stringToDecode))
        builder.Append(string.Format("{0:X2}", b));
    return builder.ToString();
}

Voici un exemple de chaîne codée et de son équivalent décodé. Le résultat est un hachage SHA1 pour un fichier. La méthode ci-dessus permet de comprendre comment le décodage fonctionne pour obtenir la bonne chaîne.

ENCODED

/KUGOuoESMWYuDb+BTMK1LaGe7k=

DECODED

FCA5063AEA0448C598B836FE05330AD4B6867BB9

ou

0xFCA5063AEA0448C598B836FE05330AD4B6867BB9

Mise à jour pour refléter la valeur SHA1 correcte grâce à Porges et un correctif pour un bug hexagonal trouvé par Dean 'codeka' Hardin.

Solution mise en œuvre

Voici l'implémentation que j'ai maintenant, elle est tirée de l'article de Porges distillé en deux méthodes.

private static string EncodeFileDigestBase64(string digest)
{
    byte[] result = new byte[digest.Length / 2];

    for (int i = 0; i < digest.Length; i += 2)
        result[i / 2] = byte.Parse(digest.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);

    if (result.Length != 20)
        throw new ArgumentException("Not a valid SHA1 filedigest.");

    return Convert.ToBase64String(result);
}

private static string DecodeFileDigestBase64(string encodedDigest)
{
    byte[] base64bytes = Convert.FromBase64String(encodedDigest);
    return string.Join(string.Empty, base64bytes.Select(x => x.ToString("X2")));
}

3voto

Dean Harding Points 40164

Je ne crois pas que ce soit physiquement possible. Le problème est que string.Format("{0:X}", b) renverra 1 ou 2 caractères selon que l'octet d'entrée est < 16 ou non. Et vous n'avez aucun moyen de le savoir une fois que la chaîne a été assemblée.

Si vous pouvez modifier le DecodeBinaryBase64 afin qu'elle ajoute toujours deux caractères pour chaque octet, c'est-à-dire en utilisant la méthode string.Format("{0:X2}", b) il sera possible de le faire en prenant la chaîne d'entrée deux caractères à la fois.

Si vous avez apporté cette modification à votre DecodeBinaryBase64 Vous pouvez alors utiliser la méthode suivante pour effectuer une nouvelle conversion :

private static string DecodeBinaryBase64(string stringToDecode)
{
    StringBuilder builder = new StringBuilder();
    foreach (var b in Convert.FromBase64String(stringToDecode))
        builder.Append(string.Format("{0:X2}", b));
    return "0x" + builder.ToString();
}

private static string EncodeBinaryBase64(string stringToEncode)
{
    var binary = new List<byte>();
    for(int i = 2; i < stringToEncode.Length; i += 2)
    {
        string s = new string(new [] {stringToEncode[i], stringToEncode[i+1]});
        binary.Add(byte.Parse(s, NumberStyles.HexNumber));
    }
    return Convert.ToBase64String(binary.ToArray());
}

(La vérification des erreurs et autres n'existe pas, cependant)

0voto

Robert Seder Points 808

Vous passez de la base 64 à une chaîne ASCII/UTF-8, puis vous restituez chaque caractère sous la forme d'une valeur hexadécimale à deux chiffres.

Je ne connais aucun moyen de le récupérer automatiquement. Vous devrez peut-être extraire deux caractères à la fois, les convertir en "char", et utiliser string.format() pour les retransformer en caractères, peut-être ?

Je n'ai jamais vu le besoin de prendre une sortie hexagonale comme celle-là, et de la transformer en une vraie chaîne de caractères. J'espère que cela vous aidera.

0voto

Porges Points 17745

J'ai donc élargi un peu ma réponse :

/** Here are the methods in question: **/
string Encode(string input)
{
    return SHA1ToBase64String(StringToBytes(input));
}

string Decode(string input)
{
    return BytesToString(Base64StringToSHA1(input));
}
/****/

string BytesToString(byte[] bytes)
{
    return string.Join("",bytes.Select(x => x.ToString("X2")));
}

byte[] StringToBytes(string input)
{
    var result = new byte[input.Length/2];

    for (var i = 0; i < input.Length; i+=2)
        result[i/2] = byte.Parse(input.Substring(i,2), System.Globalization.NumberStyles.HexNumber);

    return result;
}

string SHA1ToBase64String(byte[] hash)
{
    if (hash.Length != 20)
        throw new Exception("Not an SHA-1 hash.");

    return Convert.ToBase64String(hash);
}

byte[] Base64StringToSHA1(string input)
{
    return Convert.FromBase64String(input);
}

void Main() {

    var encoded = "/KUGOuoESMWYuDb+BTMK1LaGe7k=";

    var decoded = Decode(encoded);
    var reencoded = Encode(decoded);

    Console.WriteLine(encoded == reencoded); //True
    Console.WriteLine(decoded);
    // FCA5063AEA0448C598B836FE05330AD4B6867BB9
}

Je pense que la confusion dans les autres commentaires portait sur la question de savoir si l'on voulait fournir un inverse gauche ou un inverse droit.

En d'autres termes, voulez-vous une fonction " f "qui le fait :

f(Decode(x)) == x // "left inverse"

ou :

Decode(f(x)) == x // "right inverse"

J'ai supposé que c'était le cas, parce que vous avez dit (1er commentaire sur l'autre réponse) que vous vouliez être en mesure de reproduire l'encodage de Microsoft. (Et ce que Dean a noté - votre fonction ne fournissait pas de sortie réversible.) :)

Dans les deux cas, la fonction ci-dessus réimplémente votre version pour une sortie correcte, les deux fonctions sont donc inversées l'une par rapport à l'autre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X