Comment vérifier une chaîne codée Base64 valide

Y a-t-il un moyen dans C # de voir si une chaîne est codée en Base 64, à part essayer de la convertir et voir s’il y a une erreur? J’ai un code comme celui-ci:

// Convert base64-encoded hash value into a byte array. byte[] HashBytes = Convert.FromBase64Ssortingng(Value); 

Je veux éviter l’exception “caractère non valide dans une chaîne de base 64” qui se produit si la valeur n’est pas une chaîne de base 64 valide. Je veux juste vérifier et renvoyer false au lieu de gérer une exception parce que je m’attends parfois à ce que cette valeur ne soit pas une chaîne de base 64. Y a-t-il un moyen de vérifier avant d’utiliser la fonction Convert.FromBase64Ssortingng?

Merci!

Mettre à jour:
Merci pour toutes vos réponses. Voici une méthode d’extension que vous pouvez utiliser jusqu’à présent, il semble que votre chaîne transmette Convert.FromBase64Ssortingng sans exception. .NET semble ignorer tous les espaces de fin et de fin lors de la conversion en base 64 pour que “1234” soit valide, de même que “1234”

 public static bool IsBase64Ssortingng(this ssortingng s) { s = s.Trim(); return (s.Length % 4 == 0) && Regex.IsMatch(s, @"^[a-zA-Z0-9\+/]*={0,3}$", RegexOptions.None); } 

Pour ceux qui s’interrogent sur les performances des tests par rapport à l’attrapage et aux exceptions, dans la plupart des cas pour cette base, il est plus rapide de vérifier que d’attraper l’exception jusqu’à ce que vous atteigniez une certaine longueur. Plus la longueur est petite, plus c’est rapide

Dans mon test très peu scientifique: Pour 10000 itérations de 100 000 à 110000 caractères, le test était 2,7 fois plus rapide.

Pour 1000 itérations pour des caractères de 1 à 16 caractères pour un total de 16 000 tests, il était 10,9 fois plus rapide.

Je suis sûr qu’il y a un point où il est préférable de tester avec la méthode basée sur les exceptions. Je ne sais tout simplement pas à quel point c’est.

Il est assez facile de reconnaître une chaîne Base64, car elle ne sera composée que des caractères 'A'..'Z', 'a'..'z', '0'..'9', '+', '/' et il est souvent complété à la fin avec jusqu’à deux’ = ‘, pour que la longueur soit un multiple de 4. Mais au lieu de les comparer, il serait préférable d’ignorer l’exception, si elle se produit.

Je sais que tu as dit que tu ne voulais pas attraper une exception. Mais, comme il est plus fiable de capturer une exception, je vais aller de l’avant et poster cette réponse.

 public static bool IsBase64(this ssortingng base64Ssortingng) { // Credit: oybek https://stackoverflow.com/users/794764/oybek if (base64Ssortingng== null || base64Ssortingng.Length == 0 || base64Ssortingng.Length % 4 != 0 || base64Ssortingng.Contains(" ") || base64Ssortingng.Contains("\t") || base64Ssortingng.Contains("\r") || base64Ssortingng.Contains("\n")) return false; try{ Convert.FromBase64Ssortingng(base64Ssortingng); return true; } catch(Exception exception){ // Handle the exception } return false; } 

Mise à jour: J’ai mis à jour la condition grâce à oybek pour améliorer encore la fiabilité.

Je crois que le regex devrait être:

  Regex.IsMatch(s, @"^[a-zA-Z0-9\+/]*={0,2}$") 

Ne correspond qu’à un ou deux signes “=”, pas trois.

s devrait être la chaîne qui sera vérifiée. Regex fait partie de l’espace de noms System.Text.RegularExpressions .

Pourquoi ne pas simplement saisir l’exception et renvoyer False?

Cela évite des frais généraux supplémentaires dans le cas commun.

Par souci d’exhaustivité, je souhaite apporter une certaine implémentation. De manière générale, Regex est une approche coûteuse, surtout si la chaîne est volumineuse (ce qui arrive lors du transfert de fichiers volumineux). L’approche suivante essaie d’abord les moyens de détection les plus rapides.

 public static class HelperExtensions { // Characters that are used in base64 ssortingngs. private static Char[] Base64Chars = new[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; ///  /// Extension method to test whether the value is a base64 ssortingng ///  /// Value to test /// Boolean value, true if the ssortingng is base64, otherwise false public static Boolean IsBase64Ssortingng(this Ssortingng value) { // The quickest test. If the value is null or is equal to 0 it is not base64 // Base64 ssortingng's length is always divisible by four, ie 8, 16, 20 etc. // If it is not you can return false. Quite effective // Further, if it meets the above criterias, then test for spaces. // If it contains spaces, it is not base64 if (value == null || value.Length == 0 || value.Length % 4 != 0 || value.Contains(' ') || value.Contains('\t') || value.Contains('\r') || value.Contains('\n')) return false; // 98% of all non base64 values are invalidated by this time. var index = value.Length - 1; // if there is padding step back if (value[index] == '=') index--; // if there are two padding chars step back a second time if (value[index] == '=') index--; // Now traverse over characters // You should note that I'm not creating any copy of the existing ssortingngs, // assuming that they may be quite large for (var i = 0; i <= index; i++) // If any of the character is not from the allowed list if (!Base64Chars.Contains(value[i])) // return false return false; // If we got here, then the value is a valid base64 string return true; } } 

MODIFIER

Comme suggéré par Sam , vous pouvez également modifier légèrement le code source. Il fournit une approche plus performante pour la dernière étape des tests. La routine

  private static Boolean IsInvalid(char value) { var intValue = (Int32)value; // 1 - 9 if (intValue >= 48 && intValue <= 57) return false; // A - Z if (intValue >= 65 && intValue <= 90) return false; // a - z if (intValue >= 97 && intValue <= 122) return false; // + or / return intValue != 43 && intValue != 47; } 

peut être utilisé pour remplacer if (!Base64Chars.Contains(value[i])) line with if (IsInvalid(value[i]))

Le code source complet avec les améliorations de Sam ressemblera à ceci (commentaires supprimés pour plus de clarté)

 public static class HelperExtensions { public static Boolean IsBase64Ssortingng(this Ssortingng value) { if (value == null || value.Length == 0 || value.Length % 4 != 0 || value.Contains(' ') || value.Contains('\t') || value.Contains('\r') || value.Contains('\n')) return false; var index = value.Length - 1; if (value[index] == '=') index--; if (value[index] == '=') index--; for (var i = 0; i <= index; i++) if (IsInvalid(value[i])) return false; return true; } // Make it private as there is the name makes no sense for an outside caller private static Boolean IsInvalid(char value) { var intValue = (Int32)value; if (intValue >= 48 && intValue <= 57) return false; if (intValue >= 65 && intValue <= 90) return false; if (intValue >= 97 && intValue <= 122) return false; return intValue != 43 && intValue != 47; } } 

La réponse doit dépendre de l’utilisation de la chaîne. Il existe de nombreuses chaînes qui peuvent être “base64 valide” selon la syntaxe suggérée par plusieurs affiches, mais qui peuvent “correctement” décoder, sans exception, les fichiers indésirables. Exemple: la chaîne 8char Portland est valide Base64. Quel est l’intérêt de déclarer qu’il s’agit d’une base64 valide? Je suppose qu’à un moment donné, vous voudriez savoir que cette chaîne doit ou non être décodée en Base64.

Dans mon cas, j’ai des chaînes de connexion Oracle qui peuvent être en texte brut comme:

 Data source=mydb/DBNAME;User Id=Roland;Password=.....` 

ou en base64 comme

 VXNlciBJZD1sa.....................................== 

Je dois juste vérifier la présence d’un point-virgule, car cela prouve que ce n’est PAS une base64, ce qui est bien sûr plus rapide que toute méthode ci-dessus.

Knibb High règles de football!

Cela devrait être relativement rapide et précis, mais j’avoue que je ne l’ai pas soumis à un test approfondi, juste quelques-uns.

Il évite les exceptions coûteuses, regex, et évite également de boucler un jeu de caractères, en utilisant plutôt des plages ascii pour la validation.

 public static bool IsBase64Ssortingng(ssortingng s) { s = s.Trim(); int mod4 = s.Length % 4; if(mod4!=0){ return false; } int i=0; bool checkPadding = false; int paddingCount = 1;//only applies when the first is encountered. for(i=0;i 3) { return false; } continue; } if(c>='A' && c<='z' || c>='0' && c<='9'){ continue; } switch(c){ case '+': case '/': continue; case '=': checkPadding = true; continue; } return false; } //if here //, length was correct //, there were no invalid characters //, padding was correct return true; } 
 public static bool IsBase64Ssortingng1(ssortingng value) { if (ssortingng.IsNullOrEmpty(value)) { return false; } try { Convert.FromBase64Ssortingng(value); if (value.EndsWith("=")) { value = value.Trim(); int mod4 = value.Length % 4; if (mod4 != 0) { return false; } return true; } else { return false; } } catch (FormatException) { return false; } } 

Je vais utiliser comme ça pour que je n’ai pas besoin d’appeler à nouveau la méthode de conversion

  public static bool IsBase64(this ssortingng base64Ssortingng,out byte[] bytes) { bytes = null; // Credit: oybek http://stackoverflow.com/users/794764/oybek if (ssortingng.IsNullOrEmpty(base64Ssortingng) || base64Ssortingng.Length % 4 != 0 || base64Ssortingng.Contains(" ") || base64Ssortingng.Contains("\t") || base64Ssortingng.Contains("\r") || base64Ssortingng.Contains("\n")) return false; try { bytes=Convert.FromBase64Ssortingng(base64Ssortingng); return true; } catch (Exception) { // Handle the exception } return false; } 

Sûr. Assurez-vous que chaque caractère est compris entre az , AZ , 0-9 , / ou + et que la chaîne se termine par == . (Au moins, c’est l’implémentation la plus courante de Base64. Vous pouvez trouver des implémentations qui utilisent des caractères différents de / ou + pour les deux derniers caractères.)

Oui, puisque Base64 code les données binarys en chaînes ASCII en utilisant un ensemble limité de caractères, vous pouvez simplement le vérifier avec cette expression régulière:

/ ^ [A-Za-z0-9 \ = \ + \ / \ s \ n] + $ / s

qui assurera que la chaîne ne contient que AZ, az, 0-9, ‘+’, ‘/’, ‘=’ et les espaces.

Je suggère de créer une regex pour faire le travail. Vous devrez vérifier quelque chose comme ceci: [a-zA-Z0-9 + / =] Vous devrez également vérifier la longueur de la chaîne. Je ne suis pas sûr sur celui-ci, mais je suis sûr que si quelque chose est coupé (autre que le remplissage “=”), il pourrait exploser.

Ou mieux encore, consultez cette question de stackoverflow

J’aime l’idée d’une vérification d’expression régulière. Les expressions régulières peuvent être rapides et enregistrer la surcharge de codage par moments. l’enquête originale, avait une mise à jour qui a fait exactement cela. Je trouve cependant que je ne peux jamais supposer que les chaînes ne seraient pas nulles. J’élargirais la fonction d’extension pour vérifier la chaîne source pour les caractères nuls ou blancs uniquement.

  public static bool IsBase64Ssortingng(this ssortingng s) { if (ssortingng.IsNullOrWhiteSpace(s)) return false; s = s.Trim(); return (s.Length % 4 == 0) && Regex.IsMatch(s, @"^[a-zA-Z0-9\+/]*={0,3}$", RegexOptions.None); } 

Je viens d’avoir une exigence très similaire où je laisse l’utilisateur faire une manipulation d’image dans un élément et ensuite envoyer l’image résultante récupérée avec .toDataURL() au backend. Je voulais faire une validation du serveur avant de sauvegarder l’image et j’ai implémenté un ValidationAtsortingbute utilisant une partie du code provenant d’autres réponses:

 [AtsortingbuteUsage(AtsortingbuteTargets.Property, AllowMultiple = false, Inherited = false)] public class Bae64PngImageAtsortingbute : ValidationAtsortingbute { public override bool IsValid(object value) { if (value == null || ssortingng.IsNullOrWhiteSpace(value as ssortingng)) return true; // not concerned with whether or not this field is required var base64ssortingng = (value as ssortingng).Trim(); // we are expecting a URL type ssortingng if (!base64ssortingng.StartsWith("data:image/png;base64,")) return false; base64ssortingng = base64ssortingng.Subssortingng("data:image/png;base64,".Length); // match length and regular expression if (base64ssortingng.Length % 4 != 0 || !Regex.IsMatch(base64ssortingng, @"^[a-zA-Z0-9\+/]*={0,3}$", RegexOptions.None)) return false; // finally, try to convert it to a byte array and catch exceptions try { byte[] converted = Convert.FromBase64Ssortingng(base64ssortingng); return true; } catch(Exception) { return false; } } } 

Comme vous pouvez le constater, j’attends une chaîne de type image / png, qui est la valeur par défaut renvoyée par lors de l’utilisation de .toDataURL() .

Imho c’est pas vraiment possible. Toutes les solutions affichées échouent pour des chaînes telles que “test” , etc. S’ils peuvent être divisés en 4, ne sont pas nuls ou vides, et s’ils sont un caractère de base64 valide, ils réussiront tous les tests. Cela peut être plusieurs chaînes …

Il n’y a donc pas de solution réelle autre que de savoir qu’il s’agit d’une chaîne codée en base 64 . Ce que je suis venu avec c’est ceci:

 if (base64DecodedSsortingng.StartsWith("") { // This was really a base64 encoded ssortingng I was expecting. Yippie! } else { // This is gibberish. } 

Je m’attends à ce que la chaîne décodée commence par une certaine structure, alors je vérifie cela.