iOS 中 Base64 编解码分类实现

iOS 中 Base64 编解码分类实现

太阳火神的美丽人生 (http://blog.csdn.net/opengl_es)

本文遵循“署名-非商业用途-保持一致”创作公用协议

转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS、Android、Html5、Arduino、pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作。

再补充:由此可见,当一个人极力地想要说明自已,表述清楚自已的想法的时侯,最后会被自已搞得更加不清楚了,从而给别人看到的是,你很混乱。即然我们是生活在人所组成的社会中,那么更多的应该考虑人的思维,而不应该过份地关注事物本身的真伪。无论你说的是对的或是错的,但只要你能针对你的观众,按他(她)们的心理需要来说明白就可以了,更确切地说,不是把真象告诉他们,而是把他们心中所知道的和能接受的事情,再重复说给他们听一遍就可以了,就这么简单。因为你是生活和生存在人的世界中,而非真理的世界中,过份强调真理,只能是违背人的内心需求,即使是真理,也会变成谬论,更何况,真理本身是没办法真正表达清楚的。

从另一个角度去看,当你看到一个人在努力地表达一些事情的时侯,本来已经有点靠谱了,但越说越不靠谱了,这其实并不能说明他混乱,而是他进入一种我们无法进入的境界了。不是我们进入不了,而是我们没有专注而已。

专注该专注的,但从长久来看,就是失去本真初,妄心肆意,耐表真心,不可如来,如初生之时。

唉,别说了,再说下去,我也要入境了,哈哈哈,那可不好玩啊......

----------

补充:我还是转一下 base64 的维基解释和用途吧,免得被我个人的理解误导了,我的理解足够我理解和使用,但并不代表我表述的确实是我的想法,也或者说,并不代表我能很好地表述我的想法。

这同样是一个世界性的难题,一个人想到的本身就有偏差,说出来的往往与想到的偏差更大,所以这个世界上并没有真理存在,真正的真理是无法被表达出来的!(大概意思是这样子的,忘了是哪个名人说的至理明言了,以前觉得他好像是疯了,不过这几年来看,有些理解了,所以也明白了高数中的极限的概念,只能是趋近而已)

------

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6个位元为一个单元,对应某个可打印字符。三个字节有24个位元,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。它可用来作为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一些如uuencode的其他编码方法,和之后binhex的版本使用不同的64字符集来代表6个二进制数字,但是它们不叫Base64。

Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据。包括MIME的email,email via MIME,在XML中存储复杂数据.

目录

  [隐藏

我们知道,可识别的文本及各种结构,最终都能转换成二进制来表示,而二进制无非就是它们的内存存储结构的字节排布。

那么,在 iOS  中文本及相关结构有 NSString 等;二进制则使用 NSData 来管理和表示。

而 NSData 可以和这些文本及相关结构进行转换,所以我们只要能对 NSData 进行相应的 Base64 编码,那么就可以对其它能转换成 NSData 的文本及相关结构进行编码:

其实 Base64 编码出来的也是文本,但这种文本串有个特点,就是它使用的都是最基本的字符,不会因7位编码和8位编码等一系列问题,而在某些原始的网络设备中(比如某国外的一台路由器,有这个可能会路由到那里去)无法处理。

并且在一些如 XML 和 JSON 这样的数据承载结构中,只支持明文字符,如果用二进制,则会使其所基于的底层结构混乱,而破坏其自身的可用性。

可以这样来表示这个过程:

Others => 二进制 => Base64编码串

NSString => NSData => Base64

同样的道理,从 Base64 串解码出原始内容,也需要先将 Base64 串转换成 NSData 二进制内容,然后再进行各自的转换。

这样一来,我们就只需要完成 NSData 与 Base64 串的互转,这个问题,会让我们想起在 iOS 中使用分类来扩展 NSData 的功能是最好的办法,且无需额外的管理。

下面就贴一下曾经使用过的一套分类扩展,忘记是从哪里下载到的了,权当是自已的发个原创吧。不过这里的 C 编解码 base64 的方式和当年我学习 C 语言写网页(这个确实是可以的,而且作为 CGI 处理少量请求,效率很高,但写起来拼输出串很费事)时按 base64 原理 和 URL编解码原理写的方式不同,当时的硬件配置,算法精练精高效,而现在的查表方式更轻松易懂一些。

废话不多说,上代码:

Objective-C 类声明:

#import <Foundation/Foundation.h>

void *NewBase64Decode(const char *inputBuffer, size_t length, size_t *outputLength);
char *NewBase64Encode(const void *inputBuffer, size_t length, bool separateLines, size_t *outputLength);

@interface NSData (Base64)

+ (NSData *)dataFromBase64String:(NSString *)aString;
- (NSString *)base64EncodedString;

@end

Objective-C 类实现:

#import "NSData+Base64.h"

//
// Mapping from 6 bit pattern to ASCII character.
//
static unsigned char base64EncodeLookup[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

//
// Definition for "masked-out" areas of the base64DecodeLookup mapping
//
#define xx 65

//
// Mapping from ASCII character to 6 bit pattern.
//
static unsigned char base64DecodeLookup[256] =
{
    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 62, xx, xx, xx, 63,
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, xx, xx, xx, xx, xx, xx,
    xx,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, xx, xx, xx, xx, xx,
    xx, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, xx, xx, xx, xx, xx,
    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
};

//
// Fundamental sizes of the binary and base64 encode/decode units in bytes
//
#define BINARY_UNIT_SIZE 3
#define BASE64_UNIT_SIZE 4

//
// NewBase64Decode
//
// Decodes the base64 ASCII string in the inputBuffer to a newly malloced
// output buffer.
//
//  inputBuffer - the source ASCII string for the decode
//	length - the length of the string or -1 (to specify strlen should be used)
//	outputLength - if not-NULL, on output will contain the decoded length
//
// returns the decoded buffer. Must be free'd by caller. Length is given by
//	outputLength.
//
void *NewBase64Decode(const char *inputBuffer, size_t length, size_t *outputLength)
{
	if (length == -1)
	{
		length = strlen(inputBuffer);
	}

	size_t outputBufferSize = (length / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE;
	unsigned char *outputBuffer = (unsigned char *)malloc(outputBufferSize);

	size_t i = 0;
	size_t j = 0;
	while (i < length)
	{
		//
		// Accumulate 4 valid characters (ignore everything else)
		//
		unsigned char accumulated[BASE64_UNIT_SIZE];
		size_t accumulateIndex = 0;
		while (i < length)
		{
			unsigned char decode = base64DecodeLookup[inputBuffer[i++]];
			if (decode != xx)
			{
				accumulated[accumulateIndex] = decode;
				accumulateIndex++;

				if (accumulateIndex == BASE64_UNIT_SIZE)
				{
					break;
				}
			}
		}

		//
		// Store the 6 bits from each of the 4 characters as 3 bytes
		//
		outputBuffer[j] = (accumulated[0] << 2) | (accumulated[1] >> 4);
		outputBuffer[j + 1] = (accumulated[1] << 4) | (accumulated[2] >> 2);
		outputBuffer[j + 2] = (accumulated[2] << 6) | accumulated[3];
		j += accumulateIndex - 1;
	}

	if (outputLength)
	{
		*outputLength = j;
	}
	return outputBuffer;
}

//
// NewBase64Decode
//
// Encodes the arbitrary data in the inputBuffer as base64 into a newly malloced
// output buffer.
//
//  inputBuffer - the source data for the encode
//	length - the length of the input in bytes
//  separateLines - if zero, no CR/LF characters will be added. Otherwise
//		a CR/LF pair will be added every 64 encoded chars.
//	outputLength - if not-NULL, on output will contain the encoded length
//		(not including terminating 0 char)
//
// returns the encoded buffer. Must be free'd by caller. Length is given by
//	outputLength.
//
char *NewBase64Encode(
	const void *buffer,
	size_t length,
	bool separateLines,
	size_t *outputLength)
{
	const unsigned char *inputBuffer = (const unsigned char *)buffer;

	#define MAX_NUM_PADDING_CHARS 2
	#define OUTPUT_LINE_LENGTH 64
	#define INPUT_LINE_LENGTH ((OUTPUT_LINE_LENGTH / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE)
	#define CR_LF_SIZE 2

	//
	// Byte accurate calculation of final buffer size
	//
	size_t outputBufferSize =
			((length / BINARY_UNIT_SIZE)
				+ ((length % BINARY_UNIT_SIZE) ? 1 : 0))
					* BASE64_UNIT_SIZE;
	if (separateLines)
	{
		outputBufferSize +=
			(outputBufferSize / OUTPUT_LINE_LENGTH) * CR_LF_SIZE;
	}

	//
	// Include space for a terminating zero
	//
	outputBufferSize += 1;

	//
	// Allocate the output buffer
	//
	char *outputBuffer = (char *)malloc(outputBufferSize);
	if (!outputBuffer)
	{
		return NULL;
	}

	size_t i = 0;
	size_t j = 0;
	const size_t lineLength = separateLines ? INPUT_LINE_LENGTH : length;
	size_t lineEnd = lineLength;

	while (true)
	{
		if (lineEnd > length)
		{
			lineEnd = length;
		}

		for (; i + BINARY_UNIT_SIZE - 1 < lineEnd; i += BINARY_UNIT_SIZE)
		{
			//
			// Inner loop: turn 48 bytes into 64 base64 characters
			//
			outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2];
			outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4)
				| ((inputBuffer[i + 1] & 0xF0) >> 4)];
			outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i + 1] & 0x0F) << 2)
				| ((inputBuffer[i + 2] & 0xC0) >> 6)];
			outputBuffer[j++] = base64EncodeLookup[inputBuffer[i + 2] & 0x3F];
		}

		if (lineEnd == length)
		{
			break;
		}

		//
		// Add the newline
		//
		outputBuffer[j++] = '\r';
		outputBuffer[j++] = '\n';
		lineEnd += lineLength;
	}

	if (i + 1 < length)
	{
		//
		// Handle the single '=' case
		//
		outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2];
		outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4)
			| ((inputBuffer[i + 1] & 0xF0) >> 4)];
		outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i + 1] & 0x0F) << 2];
		outputBuffer[j++] =	'=';
	}
	else if (i < length)
	{
		//
		// Handle the double '=' case
		//
		outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2];
		outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0x03) << 4];
		outputBuffer[j++] = '=';
		outputBuffer[j++] = '=';
	}
	outputBuffer[j] = 0;

	//
	// Set the output length and return the buffer
	//
	if (outputLength)
	{
		*outputLength = j;
	}
	return outputBuffer;
}

@implementation NSData (Base64)

//
// dataFromBase64String:
//
// Creates an NSData object containing the base64 decoded representation of
// the base64 string 'aString'
//
// Parameters:
//    aString - the base64 string to decode
//
// returns the autoreleased NSData representation of the base64 string
//
+ (NSData *)dataFromBase64String:(NSString *)aString {

	NSData *data = [aString dataUsingEncoding:NSASCIIStringEncoding];
	size_t outputLength;
	void *outputBuffer = NewBase64Decode([data bytes], [data length], &outputLength);
	NSData *result = [NSData dataWithBytes:outputBuffer length:outputLength];
	free(outputBuffer);
	return result;
}

//
// base64EncodedString
//
// Creates an NSString object that contains the base 64 encoding of the
// receiver's data. Lines are broken at 64 characters long.
//
// returns an autoreleased NSString being the base 64 representation of the
//	receiver.
//
- (NSString *)base64EncodedString {

	size_t outputLength;
	char *outputBuffer =
		NewBase64Encode([self bytes], [self length], true, &outputLength);

	NSString *result =
		[[[NSString alloc]
			initWithBytes:outputBuffer
			length:outputLength
			encoding:NSASCIIStringEncoding]
		autorelease];
	free(outputBuffer);
	return result;
}

@end

或许这段的逻辑更精炼一些,但确实需要你头脑清醒些,才能挼清每一小步的逻辑,这就是早些年中国式编程的一个误区,也是印度当时能成为世界软件外包大国的原因(避勉这种无意义的抽象和极致,更多精力花费在业务逻辑上,以满足客户要求):

BOOL encodeBase64(const unsigned char *src, NSInteger srcLength, char *dest, NSUInteger *pDestLength) {

	static char base64Char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	NSUInteger shouldLength = (srcLength + 2) / 3 * 3;
	NSUInteger base64Length = shouldLength / 3 * 4;
	if (NULL == pDestLength || *pDestLength < base64Length) {
		return NO;
	}
	*pDestLength = base64Length;
	char *data = malloc(shouldLength);
	memcpy(data, src, srcLength);
	for (NSUInteger i = srcLength; i < shouldLength; i++) {
		data[i] = 0;
	}
	for (NSUInteger i = 0; i < shouldLength; i += 3) {
		NSUInteger idx = i / 3 * 4;
		dest[idx] = base64Char[(data[i] & 0xfc) >> 2];
		dest[idx + 1] = base64Char[((data[i] & 0x03) << 4 ) + ((data[i + 1] & 0xf0) >> 4)];
		dest[idx + 2] = base64Char[((data[i + 1] & 0x0f) << 2) + ((data[i + 2] & 0xc0) >> 6)];
		dest[idx + 3] = base64Char[data[i + 2] & 0x3f];
	}
	free( data );
	for (NSUInteger i = 1; i <= shouldLength - srcLength; i++) {
		dest[base64Length - i] = '=';
	}
	return YES;
}

好了,Base64 编解码完成,其实叫它编解码是正确的,不过它同时有加密的功能,至少用肉眼无法误别内容,就像二维码一样,也是一种编解码,同时具有加密功能,加密的对象是肉眼!

后续还有MD5、DES、AES等等对称加密、非对称加密,这些不光有编解码的功效,同时更主要是加解密,加密对象是任何未知密钥或源内容的人或机器。

编码的意义并不一定在于要加密,而加密本身就是一种编码的方式!

不过,MD5已经被中国科学家破解,详见报道  山东大学王小云教授成功破解MD5 。

但,这只说明 MD5 并不是不可逆(无法反算出原始内容)的加密方式,而并不表示我们也很容易地能做到。

一种常规的 MD5 破解方式是跑字典,而跑字典也是很多破解的常用方式。

时间: 2024-12-01 13:36:54

iOS 中 Base64 编解码分类实现的相关文章

Delphi 自带的 Base64 编解码函数

今天帮别人解决一个关于 Base64 编解码的问题,竟然发现 Delphi 自带了 Base64 编解码的单元,叫 EncdDecd,这名字很拗口而且不直观,估计这是一直很少人关注和知道的原因. 这个单元提供两套四个公开函数: 对流的编解码: procedure EncodeStream(Input, Output: TStream); // 编码 procedure DecodeStream(Input, Output: TStream); // 解码 // 对字符串的编解码: functio

Skia深入分析6——skia中图像编解码代码概述

1.API和自注册机制 Skia中编码解码图片都只需要一行代码: SkBitmap bitmap; SkImageDecoder::DecodeFile("test.xxx", &bitmap);//由文件名解码,自动推断图片类型 //或者由流解码 SkFILEStream stream("test.xxx"); SkImageDecoder::DecodeStream(stream, &bitmap);//由输入流解码,自动推断图片类型 //编码

C语言实现Base64编解码

in_str是输入缓冲区的地址 in_len 要编码的数据的长度 out_str 输出的地址 需要在外面分配内存 unsigned char *out_str = (unsigned char *) malloc (in_len * 4 / 3 + 1); 然后再调用函数编码. void Base64Encode(const unsigned char *in_str, int in_len, unsigned char *out_str) { static unsigned char base

使用python3的base64编解码实现字符串的简易加密解密

import base64 copyright = 'Copyright (c) 2012 Doucube Inc. All rights reserved.' def main(): #转成bytes string bytesString = copyright.encode(encoding="utf-8") print(bytesString) #base64 编码 encodestr = base64.b64encode(bytesString) print(encodestr

c++base64编解码使用示例_C 语言

复制代码 代码如下: #include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>static const char b64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";static const char reverse_table[128

PHP也能干大事之PHP中的编码解码详解

PHP也能干大事之PHP中的编码解码详解        这篇文章主要介绍了PHP也能干大事之PHP中的编码解码详解,本文讲解了ASCII编解码.URL编解码.Base64编解码.HTML实体编解码.二进制.八进制.十进制.十六进制相互转换等内容,需要的朋友可以参考下 写在前面 PHP也能干大事是我总结的PHP语法特性及相关函数类库的经典用法,并不一定是真正能实现四两拨千斤的功效,但是掌握这些方法,可以在你的工作和学习上有一些帮助,希望大家能集思广益,将<PHP也能干大事>丰富得更精彩!转载请注

MaxCompute SQL引用第三方Base64JAR实现编解码

BASE64和其他相似的编码算法通常用于转换二进制数据为文本数据,其目的是为了简化存储或传输.更具体地说,BASE64算法主要用于转换二进制数据为ASCII字符串格式. 下面我们通过阿里云MaxCompute 和大数据开发套件,引用第三方的Base64 JAR,来实现字符串的编码.解码: 效果如下: ---base64编码 select id,encode_base64('liuxiaowen1234') from alian.user_info limit 1; bGl1eGlhb3dlbjE

解密-关于C语言的base64字符串解码

问题描述 关于C语言的base64字符串解码 各位大神,我现在急需将一段字符串解码的方法(C语言实现),希望各位出手援助一下. 我需要解码的字符串是: vU3xynE6ee6KymPB1cpwVGwZMrS/GZdXYBXiPNWfWktX6uq0gdIKB6yWG8dq49ywRKjCljpVipbTWyHIOEhS0jpSVuB/y4q3rWI3bvMGCWK9/rHLkUrdi4NIQLKj+hFEZbvgmWfdAyc0mvdIcjQOtRKVTFzQUekoJ5RvMAAqNt+usa

node.js学习之base64编码解码_node.js

一. Base64编码由来 为什么会有Base64编码呢?因为有些网络传送渠道并不支持所有的字节,例如传统的邮件只支持可见字符的传送,像ASCII码的控制字符就 不能通过邮件传送.这样用途就受到了很大的限制,比如图片二进制流的每个字节不可能全部是可见字符,所以就传送不了.最好的方法就是在不改变传统协议的情 况下,做一种扩展方案来支持二进制文件的传送.把不可打印的字符也能用可打印字符来表示,问题就解决了.Base64编码应运而生,Base64就是一种 基于64个可打印字符来表示二进制数据的表示方法