1. Aperçu
1.Qu'est-ce que Base64 :
Base64 est l'une des méthodes de codage les plus courantes pour transmettre des codes d'octets de 8 bits sur Internet. Vous pouvez consulter RFC2045~RFC2049, qui contient des spécifications détaillées pour MIME. Le codage Base64 peut être utilisé pour transmettre des informations d'identification plus longues dans un environnement HTTP. Par exemple, dans le système Java Persistence Hibernate, Base64 est utilisé pour coder un long identifiant unique (généralement un UUID de 128 bits) dans une chaîne, qui est utilisée comme paramètres dans les formulaires HTTP et les URL HTTP GET. Dans d'autres applications, il est souvent nécessaire d'encoder les données binaires sous une forme adaptée au placement dans une URL (y compris les champs de formulaire masqués). À l’heure actuelle, l’utilisation du codage Base64 est non seulement plus courte, mais également illisible, c’est-à-dire que les données codées ne seront pas directement visibles à l’œil nu.
2. Introduction :
Le standard Base64 ne convient pas à la transmission directement dans l'URL, car l'encodeur d'URL modifiera les caractères "/" et "+" du standard Base64 sous la forme de "%XX", et ces caractères "%" existent lors de la saisie dans la base de données. , une conversion supplémentaire est requise car le signe « % » a été utilisé comme caractère générique dans ANSI SQL.
Pour résoudre ce problème, un codage Base64 amélioré pour les URL peut être utilisé, qui ne complète pas le signe « = » à la fin et modifie le « + » et « / » dans la base 64 standard en « * » et « - » respectivement. , Cela élimine le besoin de conversion lors du codage, du décodage et du stockage de la base de données de l'URL, évite l'augmentation de la longueur des informations codées au cours du processus et unifie le format des identifiants d'objet dans les bases de données, les formulaires, etc.
Il existe également une variante Base64 améliorée pour les expressions régulières, qui remplace "+" et "/" par "!" et "-" car "+", "*" et " Les deux [" et "]" peuvent avoir des significations particulières dans expressions régulières.
Il existe également des variantes qui remplacent "+/" par "_-" ou "._" (utilisés comme noms d'identifiant dans les langages de programmation) ou ".-" (utilisé pour les Nmtokens en XML) ou même "_ :" (pour Name en XML).
Base64 nécessite de convertir tous les trois octets de 8 bits en quatre octets de 6 bits (3*8 = 4*6 = 24), puis d'ajouter deux 0 de poids fort au 6 bits pour former quatre octets de 8 bits, c'est-à-dire que la chaîne convertie sera théoriquement 1/3 plus long que celui d'origine.
3. Règles :
Règles concernant cet encodage :
①.Convertissez 3 caractères en 4 caractères.
②.Ajoutez un caractère de nouvelle ligne tous les 76 caractères.
③.Le terminateur final doit également être traité.
N'est-ce pas trop abstrait ? Ne vous inquiétez pas, regardons un exemple :
Avant conversion : aaaaaabb ccccdddd eeffffff
Après conversion : 00aaaaaa 00bbcccc 00ddddee 00ffffff
Cela devrait être clair, non ? Les trois octets supérieurs sont le texte original et les quatre octets inférieurs sont le codage Base64 converti, les deux premiers bits étant 0.
Après la conversion, nous utilisons une table de codes pour obtenir la chaîne souhaitée (c'est-à-dire l'encodage Base64 final)
2. Exemple de code d'implémentation Java :
public final class Base64 { static private final int BASELENGTH = 255; static private final int LOOKUPLENGTH = 64; static private final int TWENTYFOURBITGROUP = 24; = 6 ; final privé statique int FOURBYTE = 4 ; int SIGN = -128 ; caractère final privé statique PAD = '=' ; ]; statique { pour (int i = 0; i < BASELENGTH; i++) { base64Alphabet[i] = -1; } pour (int i = 'Z'; i >= 'A'; i--) { base64Alphabet[i] = (octet) (i - 'A' } pour (int); je = 'z'; je >= 'a'; i--) { base64Alphabet[i] = (octet) (i - 'a' + 26 } pour (int i = '9'; je); >= '0'; i--) { base64Alphabet[i] = (octet) (i - '0' + 52); base64Alphabet['+'] = 62; base64Alphabet['/'] = 63; int i = 0; i <= 25; i++) lookUpBase64Alphabet[i] = (char) ('A' + i); 26, j = 0 ; i <= 51 ; i++, j++) lookUpBase64Alphabet[i] = (char) ('a' + j); pour (int i = 52, j = 0 ; i <= 61 ; i++, j++) ) lookUpBase64Alphabet[i] = (caractère) ('0' + j); lookUpBase64Alphabet[62] = (caractère) '+'; lookUpBase64Alphabet[63] = (char) '/'; } protected static boolean isWhiteSpace(char octect) { return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9 } protected); static boolean isPad(char octect) { return (octect == PAD); } protected static boolean isData(char octect) { return (base64Alphabet[octect] != -1); } protected static boolean isBase64(char octect) { return (isWhiteSpace(octect) || isPad(octect) || isData(octect) ); } /** * Encode les octets hexadécimaux en Base64 * * @param BinaryData * Tableau contenant binaireData * @return Tableau encodé en Base64 */ public static String encode(byte[] binaireData) { if (binaryData == null) return null; int lengthDataBits = binaireData.length * EIGHTBIT; ; } int moinsThan24bits = longueurDataBits % VINGTQUATREBITGROUP; int nombreTriplets = longueurDataBits / TWENTYFOURBITGROUP; int numberQuartet = moins de 24 bits ! = 0 ? numberTriplets + 1 : numberTriplets ; int numberQuartet = (numberQuartet - 1) / 19 + 1 ; char encodedData [] = null ; = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; int encodedIndex = 0; int dataIndex = 0; int i = 0; if (fDebug) { System.out.println("nombre de triplets = " + numberTriplets } for (int line =); 0; ligne < nombreLignes - 1; ligne++) { for (int quatuor = 0; quatuor < 19; quatuor++) { b1 = données binaires[dataIndex++]; b2 = données binaires[dataIndex++]; b3 = données binaires[dataIndex++]; + b3); } l = (octet) (b2 & 0x0f); k = (octet) (b1 & 0x03); ((b1 & SIGN) == 0) ? (octet) (b1 >> 2) : (octet) ((b1) >> 2 ^ 0xc0); octet val2 = ((b2 & SIGN) == 0) ? octet) (b2 >> 4) : (octet) ((b2) >> 4 ^ 0xf0); octet val3 = ((b3 & SIGN) == 0) ? (octet) (b3 >> 6) : (octet) ((b3) >> 6 ^ 0xfc); if (fDebug) { System.out.println("val2 = " + val2); println("k4 = " + (k << 4)); System.out.println("vak = " + (val2 | (k << 4))); encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | lookUpBase64Alphabet[b3 & 0x3f]; } encodedData[encodedIndex++] = 0xa; } for (; i < numberTriplets; i++) { b1 = binaireData[dataIndex++]; (fDebug) { System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3); } l = (octet) (b2 & 0x0f); k = (octet) (b1 & 0x03); = 0) ? (octet) (b1 >> 2) : (octet) ((b1) >> 2 ^ 0xc0); ((b2 & SIGN) == 0) ? (octet) (b2 >> 4) : (octet) ((b2) >> 4 ^ 0xf0); octet val3 = ((b3 & SIGN) == 0) ? octet) (b3 >> 6) : (octet) ((b3) >> 6 ^ 0xfc) if (fDebug) { System.out.println("val2 = " + val2); System.out.println("k4 = " + (k << 4)); System.out.println("vak = " + (val2 | (k < < 4))); } encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; lookUpBase64Alphabet[val2 | (k << 4)]; encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f] } // forme un nombre entier de 6- groupes de bits si (moins de 24 bits == EIGHTBIT) { b1 = binaireData[dataIndex]; k = (octet) (b1 & 0x03); if (fDebug) { System.out.println("b1=" + b1); " + (b1 >> 2)); } octet val1 = ((b1 & SIGN) == 0) ? (octet) (b1 >> 2) : (octet) ((b1) >> 2 ^ 0xc0); encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4]; si (moins de 24 bits == SIXTEENBIT) { b1 = données binaires[dataIndex]; b2 = données binaires[dataIndex + 1]; l = (octet) (b2 & 0x0f); == 0) ? (octet) (b1 >> 2) : (octet) ((b1) >> 2 ^ 0xc0); octet val2 = ((b2 & SIGN) == 0) ? (octet) (b2 >> 4) : (octet) ((b2) >> 4 ^ 0xf0 encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]); ; encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | 4)]; encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; encodedData[encodedIndex++] = PAD; } encodedData[encodedIndex] = 0xa; return new String(encodedData } /** * Décode les données Base64 en octets * * @param binaireData * Tableau d'octets contenant des données Base64 * @return Array containind données décodées. */ public static byte[] decode(String encoded) { if (encoded == null) return null; char[] base64Data = encoded.toCharArray(); ); if (len % FOURBYTE != 0) { return null;// doit être divisible par quatre } int numberQuadruple = (len / FOURBYTE); if (numberQuadruple == 0) renvoie un nouvel octet[0] ; octet decodedData[] = null ; octet b1 = 0, b3 = 0, b4 = 0, marqueur1 = 0 ; d1 = 0, d2 = 0, d3 = 0, d4 = 0 ; int i = 0 ; = 0; int dataIndex = 0; decodedData = nouvel octet[(numberQuadruple) * 3]; for (; i < numberQuadruple - 1; i++) { if (!isData((d1 = base64Data[dataIndex++])) || !isData ((d2 = base64Data[dataIndex++])) || !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++]))) return null;// si "aucune donnée" est trouvée, retournez simplement null b1 = base64Alphabet[d1] b2 = base64Alphabet[d2]; = base64Alphabet[d3]; b4 = base64Alphabet[d4]; = (octet) (b1 << 2 | b2 >> 4); decodedData[encodedIndex++] = (octet) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); encodedIndex++] = (octet) (b3 << 6 | b4 } if (!isData((d1 =) base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) { return null;// si trouvé "aucune donnée", renvoie simplement null } b1 = base64Alphabet[d1]; ; d3 = base64Data[dataIndex++]; d4 = base64Data[dataIndex++]; (!isData((d3)) || !isData((d4))) {// Vérifiez s'il s'agit de caractères PAD if (isPad(d3) && isPad(d4)) { // Deux PAD, par exemple 3c[Pad][ Pad] if ((b2 & 0xf) != 0)// les 4 derniers bits doivent être nuls return byte[] tmp = new byte[i * 3 + 1]; System.arraycopy(decodedData, 0, tmp, 0, i * 3); tmp[encodedIndex] = (octet) (b1 << 2 | b2 >> 4); d3) && isPad(d4)) { // Un PAD par exemple 3cQ[Pad] b3 = base64Alphabet[d3]; if ((b3 & 0x3) != 0)// les 2 derniers bits doivent être nuls return null; byte[] tmp = new byte[i * 3 + 2]; tmp, 0, i * 3); tmp[encodedIndex++] = (octet) (b1 << 2 | b2 >> 4); tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); return tmp; else { return null;// une erreur comme " 3c[Pad]r", "3cdX", "3cXd", "3cXX" // où X n'est pas une donnée } } else { // Pas de PAD par exemple 3cQl b3 = base64Alphabet[d3]; b4 = base64Alphabet[d4]; decodedData[encodedIndex++] = (octet) (b1 << 2 | b2 >> 4); decodedData[encodedIndex++] = (octet) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); return decodedData; } /** * supprime WhiteSpace du MIME contenant les données codées en Base64 * le tableau d'octets de données base64 (avec WS. ) * @renvoie la nouvelle longueur */ protected static int removeWhiteSpace(char[] data) { if (data == null) return 0 ; // compte les caractères qui ne le sont pas ; espace blanc int newSize = 0; int len = data.length; for (int i = 0; i < len; i++) { if (!isWhiteSpace(data[i])) data[newSize++] = data[i]; } return newSize; } public static void main(String[] args) { System.out.println(encode("République populaire de Chine".getBytes()));