Base64常用于字符的编码,将原始数据加密为不可读的字符,因其编码方式是完全公开的,所以称作“编码”更为贴切。
详细的介绍可以参见:https://zh.wikipedia.org/wiki/Base64
原理
"3*8 = 4*6 "
这是百度百科上的一句精简概括。具体可以理解为将数据每3个字符分为一组,转为二进制,每个字符为8bit。编码过程中,将二进制数据每6bit分割为一条,最后一条不足6bit时在低位补齐0,每4条为1组。
通常情况下一个字节为8bit,所以分好组后还需要在每个字节的高位补齐0。当一组不够4个字符时,用“=”代替缺失的字符,最后再将转换后的二进制数据根据Base64对照表翻译成编码后的数据。
所以,Base64加密后的数据比加密前的数据长了约4/3。
Base64编码对照表如下:
数值 | 字符 | 数值 | 字符 | 数值 | 字符 | 数值 | 字符 |
---|---|---|---|---|---|---|---|
0 | A | 16 | Q | 32 | g | 48 | w |
1 | B | 17 | R | 33 | h | 49 | x |
2 | C | 18 | S | 34 | i | 50 | y |
3 | D | 19 | T | 35 | j | 51 | z |
4 | E | 20 | U | 36 | k | 52 | 0 |
5 | F | 21 | V | 37 | l | 53 | 1 |
6 | G | 22 | W | 38 | m | 54 | 2 |
7 | H | 23 | X | 39 | n | 55 | 3 |
8 | I | 24 | Y | 40 | o | 56 | 4 |
9 | J | 25 | Z | 41 | p | 57 | 5 |
10 | K | 26 | a | 42 | q | 58 | 6 |
11 | L | 27 | b | 43 | r | 59 | 7 |
12 | M | 28 | c | 44 | s | 60 | 8 |
13 | N | 29 | d | 45 | t | 61 | 9 |
14 | O | 30 | e | 46 | u | 62 | + |
15 | P | 31 | f | 47 | v | 63 | / |
示例1 - 【编码】
原始字符:
Abc123*
1.根据ascii码表翻译:
65 98 99 49 50 51 42
2.转换为二进制:
01000001 01100010 01100011 00110001 00110010 00110011 00101010
3.将数据以每6位分割为一项,不足6位的低位用0补齐,每四项为一组
1 | 2 | 3 | 4 |
---|---|---|---|
010000 | 010110 | 001001 | 100011 |
001100 | 010011 | 001000 | 110011 |
001010 | 100000 |
4.每项数据高位用“0”补齐至8位
1 | 2 | 3 | 4 |
---|---|---|---|
00010000 | 00010110 | 00001001 | 00100011 |
00001100 | 00010011 | 00001000 | 00110011 |
00001010 | 00100000 |
5.根据Base64码表将新的二进制翻译成数据,并将不足四项的组用‘=’补齐,得到加密后的数据
1 | 2 | 3 | 4 |
---|---|---|---|
Q | W | J | j |
M | T | I | z |
K | g | = | = |
加密后的数据: QWJjMTIzKg==
示例2 - 【解码】
熟悉了编码过程,想要得到原始数据只需逆向执行就好
待解密数据:
QWJjMTIzKg==
1.将待解密的数字分组并根据Base64码表翻译成原始数据的二进制,并去掉补位用的"="以及高位补位所加上的0
1 | 2 | 3 | 4 |
---|---|---|---|
010000 | 010110 | 001001 | 100011 |
001100 | 010011 | 001000 | 110011 |
001010 | 100000 |
2.将数据每8位分割为一条,若有剩下不够分的部分直接舍弃掉,这是加密过程中为了补位所添加的
01000001 01100010 01100011
00110001 00110010 00110011
00101010 0000
3.将解密出来的二进制根据Ascii码表翻译出来就得到了原始数据
65 98 99 49 50 51 42
根据Ascii码表翻译为:
Abc123*
Tips:
1、Base64的加密方式简易透明,容易被破解。在数据敏感时,通常会在加密前后添加各种处理,稍稍加大逆向解码的难度(毕竟不能指望仅仅依靠Base64来保证数据的安全)。
2、为了适应多种环境,Base64编码也有多种版本(UTF-7, IRCu, URL)。
iOS中的应用
iOS中提供了系统方法予以支持,使用方式十分简便:
编码
NSString * string = @"Abc123*";
NSData * data = [string dataUsingEncoding:NSUTF8StringEncoding];
NSString * encodeString = [data base64EncodedStringWithOptions:0];
NSLog(@"%@", encodeString);
//输出: QWJjMTIzKg==
解码
NSData * decodeData = [[NSData alloc] initWithBase64EncodedString:encodeString
options:0];
NSString * decodeString = [[NSString alloc] initWithData:decodeData
encoding:NSUTF8StringEncoding];
NSLog(@"%@", decodeString);
//输出: Abc123*
自己实现一个Base64编码器
以下代码比较粗糙,仅供参考
// NSString+Base64.h
@interface NSString (Base64)
- (NSString *)encodeWithBase64;
- (NSString *)decodeWithBase64;
@end
// NSString+Base64.m
@implementation NSString (Base64)
- (NSString *)encodeWithBase64 {
//转换成二进制串
const char * cString = [self cStringUsingEncoding:NSASCIIStringEncoding];
char * tempData = malloc(sizeof(cString) * 9 * sizeof(char *));
for (int index = 0; index < strlen(cString); index += 1) {
int asciiCode = cString[index] ;
char * binaryCode = [self convertBinaryCodeWithValue:asciiCode];
strcat(tempData, binaryCode);
free(binaryCode);
}
//按照 "6 * 3 = 8 * 4"的规则进行划分
char * tempBuff = malloc(self.length * sizeof(char *));;
int lenth = (int)strlen(tempData);
for (int index = 0; index < lenth; index += 6) {
char temp6[7];
strncpy(temp6, tempData+index, 6);
temp6[6] = '\0';
char * temp8 = malloc(9 * sizeof(char *));
temp8[0] = '0';
temp8[1] = '0';
temp8[2] = '\0';
strcat(temp8, temp6);
int lenth = (int)strlen(temp8);
//不足8位补齐
if (lenth < 8) {
char * blank = "00000000";
char * blankBuff = malloc(9 * sizeof(char *));
strncpy(blankBuff, blank+lenth, 8 - lenth);
strcat(temp8, blankBuff);
free(blankBuff);
}
//对照Base64编码表转码
tempBuff[index / 6] = [self transformBase64CodeWithValue:temp8];
if (index + 6 > lenth) {
tempBuff[index / 6 + 1] = '\0';
}
free(temp8);
}
NSString * base64String = [NSString stringWithCString:tempBuff encoding:NSUTF8StringEncoding];
int equlNum = base64String.length % 4;
if (equlNum != 0) {
NSString * equlString = equlNum == 1 ? @"=" : (equlNum == 2 ? @"==" : @"===");
return [base64String stringByAppendingString:equlString];
}
return base64String;
}
- (NSString *)decodeWithBase64 {
//转换成二进制串
NSString * string = [self stringByReplacingOccurrencesOfString:@"=" withString:@""];
const char * cString = [string cStringUsingEncoding:NSASCIIStringEncoding];
char * tempData = malloc(sizeof(cString) * 6 * sizeof(char *));
for (int index = 0; index < strlen(cString); index += 1) {
//根据base64编码表查询出对应的编号
char base64Character = [self getNumWithBase64Character:cString[index]];
//获取编号的二进制
char * binaryCode = [self convertBinaryCodeWithValue:base64Character];
//去掉编码时补位的0
char * code = &binaryCode[2];
strcat(tempData, code);
free(binaryCode);
}
//获取原始数据的二进制并转换出原始字符
char * tempBuff = malloc(self.length * sizeof(char *));
for (int index = 0; index < strlen(tempData); index += 8) {
char * tureBinaryCode = malloc(8 * sizeof(char *));
strncpy(tureBinaryCode, tempData+index, 8);
int asciiCode = [self convertValueWithBinaryCode:tureBinaryCode];
char asciiCharacter = (char)asciiCode;
tempBuff[index / 8] = asciiCharacter;
if (index + 8 > strlen(tempData)) {
tempBuff[index + 1] = '\0';
}
}
NSString * resourceString = [NSString stringWithCString:tempBuff encoding:NSUTF8StringEncoding];
return resourceString;
}
- (char)transformBase64CodeWithValue:(char *)value {
int num = [self convertValueWithBinaryCode:value];
char data = [self getBase64CodeWithNum:num];
return data;
}
///////////////////////////////////////////////////////////
//Tools
//base64码表
- (char)getBase64CodeWithNum:(int)num {
char * codes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmoopqrstuvwxyz+/";
return codes[num];
}
- (int)getNumWithBase64Character:(char)character {
char * codes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmoopqrstuvwxyz+/";
int index = -1;
int lenth = (int)strlen(codes);
while(index < lenth) {
char value = codes[index];
if (value == character) {
return index;
}
index += 1;
}
return index;
}
//十进制转换为二进制
- (char *)convertBinaryCodeWithValue:(int)value {
char * tempCode = malloc(9 * sizeof(char *));
int tempValue = value;
int index = 0;
while (index <= 7) {
if (tempValue != 0) {
char value = tempValue % 2 + '0';
tempCode[7 - index] = value;
tempValue = tempValue / 2;
} else {
tempCode[7 - index] = '0';
}
index += 1;
}
tempCode[index] = '\0';
return tempCode;
}
//将二进制转换为十进制
- (int)convertValueWithBinaryCode:(char *)value {
int lenth = (int)strlen(value);
int tempValue = 0;
for (int index = 1; index <= lenth; index += 1) {
char numChar = value[index];
int num = atoi(&numChar);
if (num == 1) {
tempValue += pow(2, lenth - index - 1);
}
}
return tempValue;
}
@end
都看到这里了,觉得还行的话就点个赞吧 : )
网友评论