加密算法的分類
-
Hash哈希散列函數(shù)
:嚴(yán)格意義上來說不屬于加密算法,常見的散列函數(shù)有MD5、SHA1/256/512秽梅;
-
對稱加密算法
:DES抹蚀、3DES、AES(高級密碼標(biāo)準(zhǔn)企垦,Mac電腦的鑰匙串就是用AES實現(xiàn)的)环壤;
-
非對稱加密算法
:RSA;
Hash哈希散列函數(shù)
- Hash:即哈希散列函數(shù)钞诡,就是
將任意長度的輸入通過散列算法變換成固定長度的輸出
郑现,該輸出就是散列值
,這種轉(zhuǎn)換是一種壓縮映射荧降,也就是接箫,散列值的空間通常遠(yuǎn)小于輸入的空間,不同的輸入可能會散列成相同的輸出朵诫,所以不可能從散列值來確定唯一的輸入值辛友,簡單的說就是一種將任意長度的消息壓縮到某一固定長度的消息摘要函數(shù)
;
- 哈希算法拗窃,即散列函數(shù),是一種
單向密碼機制
泌辫,即從明文到密文的不可逆的映射
随夸,只有加密過程,沒有解密過程震放;
Hash的特點
- 算法是公開的宾毒;
- 對相同的數(shù)據(jù)進(jìn)行哈希運算,得到的結(jié)果是相同的殿遂;
- 對不同的數(shù)據(jù)進(jìn)行哈希運算诈铛,得到的結(jié)果是定長的;
- 不可逆運算墨礁,只有加密過程幢竹,沒有解密過程,即無法從密文去逆運算稱明文恩静;
- 是信息摘要焕毫、信息“指紋”,是用來做數(shù)據(jù)識別的驶乾、完整性檢查的邑飒;
Hash的應(yīng)用場景
- 用戶密碼的加密;
- 搜索引擎级乐;
- 版權(quán)疙咸;
- 數(shù)字簽名;
常見的哈希散列函數(shù)
- MD5风科;
- SHA-1撒轮;
- SHA-256乞旦;
- SHA-512;
- HMAC腔召;
哈希散列函數(shù)的源碼實現(xiàn)
- 首先我們需要知道
密碼在網(wǎng)絡(luò)上傳輸
必須遵循兩個原則:
- 網(wǎng)絡(luò)上不允許明文傳遞用戶的隱私信息杆查;
- 本地不允許明文保存用戶隱私信息;
- 可使用哈希散列函數(shù)臀蛛,對用戶的隱私信息進(jìn)行哈希計算亲桦,得到密文哈希值,然后再在網(wǎng)絡(luò)上傳輸浊仆,有關(guān)哈希散列函數(shù)的源碼如下:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface YYHash : NSString
///MD5哈希散列函數(shù)
+ (NSString *)md5:(NSString *)str;
///MD5哈希散列函數(shù) + 加鹽
+ (NSString *)md5:(NSString *)str salt:(NSString *)salt;
///SHA散列函數(shù)
+ (NSString *)sha1:(NSString *)str;
+ (NSString *)sha256:(NSString *)str;
+ (NSString *)sha512:(NSString *)str;
///HMAC散列函數(shù)
+ (NSString *)hmacMD5Str:(NSString *)str key:(NSString *)key;
+ (NSString *)hmacSHA1Str:(NSString *)str key:(NSString *)key;
+ (NSString *)hmacSHA256Str:(NSString *)str key:(NSString *)key;
+ (NSString *)hmacSHA512Str:(NSString *)str key:(NSString *)key;
///文件散列函數(shù)
+ (NSString *)fileMD5HashPath:(NSString *)path;
+ (NSString *)fileSHA1HashPath:(NSString *)path;
+ (NSString *)fileSHA256HashPath:(NSString *)path;
+ (NSString *)fileSHA512HashPath:(NSString *)path;
@end
NS_ASSUME_NONNULL_END
#import "YYHash.h"
#import <CommonCrypto/CommonCrypto.h>
@implementation YYHash
#pragma mark MD5
+ (NSString *)md5:(NSString *)str {
const char *string = str.UTF8String;
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
CC_MD5(string, (CC_LONG)strlen(string), buffer);
return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
+ (NSString *)md5:(NSString *)str salt:(NSString *)salt {
NSString *string = [NSString stringWithFormat:@"%@%@",str,salt];
return [self md5:string];
}
#pragma mark SHA
+ (NSString *)sha1:(NSString *)str {
const char *string = str.UTF8String;
uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(string, (CC_LONG)strlen(string), buffer);
return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
+ (NSString *)sha256:(NSString *)str {
const char *string = str.UTF8String;
uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(string, (CC_LONG)strlen(string), buffer);
return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
+ (NSString *)sha512:(NSString *)str {
const char *string = str.UTF8String;
uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
CC_SHA512(string, (CC_LONG)strlen(string), buffer);
return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
#pragma mark HMAC
+ (NSString *)hmacMD5Str:(NSString *)str key:(NSString *)key {
const char *keyData = key.UTF8String;
const char *strData = str.UTF8String;
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer);
return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
+ (NSString *)hmacSHA1Str:(NSString *)str key:(NSString *)key {
const char *keyData = key.UTF8String;
const char *strData = str.UTF8String;
uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA1, keyData, strlen(keyData), strData, strlen(strData), buffer);
return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
+ (NSString *)hmacSHA256Str:(NSString *)str key:(NSString *)key {
const char *keyData = key.UTF8String;
const char *strData = str.UTF8String;
uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, keyData, strlen(keyData), strData, strlen(strData), buffer);
return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
+ (NSString *)hmacSHA512Str:(NSString *)str key:(NSString *)key {
const char *keyData = key.UTF8String;
const char *strData = str.UTF8String;
uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA512, keyData, strlen(keyData), strData, strlen(strData), buffer);
return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
#pragma mark 文件散列函數(shù)
#define FileHashDefaultChunkSizeForReadingData 4096
+ (NSString *)fileMD5HashPath:(NSString *)path {
NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:path];
if (fp == nil) {
return nil;
}
CC_MD5_CTX hashCtx;
CC_MD5_Init(&hashCtx);
while (YES) {
@autoreleasepool {
NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
CC_MD5_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
if (data.length == 0) {
break;
}
}
}
[fp closeFile];
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
CC_MD5_Final(buffer, &hashCtx);
return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
+ (NSString *)fileSHA1HashPath:(NSString *)path {
NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:path];
if (fp == nil) {
return nil;
}
CC_SHA1_CTX hashCtx;
CC_SHA1_Init(&hashCtx);
while (YES) {
@autoreleasepool {
NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
CC_SHA1_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
if (data.length == 0) {
break;
}
}
}
[fp closeFile];
uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
CC_SHA1_Final(buffer, &hashCtx);
return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
+ (NSString *)fileSHA256HashPath:(NSString *)path {
NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:path];
if (fp == nil) {
return nil;
}
CC_SHA256_CTX hashCtx;
CC_SHA256_Init(&hashCtx);
while (YES) {
@autoreleasepool {
NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
CC_SHA256_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
if (data.length == 0) {
break;
}
}
}
[fp closeFile];
uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
CC_SHA256_Final(buffer, &hashCtx);
return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
+ (NSString *)fileSHA512HashPath:(NSString *)path {
NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:path];
if (fp == nil) {
return nil;
}
CC_SHA512_CTX hashCtx;
CC_SHA512_Init(&hashCtx);
while (YES) {
@autoreleasepool {
NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
CC_SHA512_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
if (data.length == 0) {
break;
}
}
}
[fp closeFile];
uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
CC_SHA512_Final(buffer, &hashCtx);
return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
+ (NSString *)stringFromBytes:(uint8_t *)bytes length:(int)length {
NSMutableString *strM = [NSMutableString string];
for (int i = 0; i < length; i++) {
[strM appendFormat:@"%02x", bytes[i]];
}
return [strM copy];
}
@end
- 可通過Mac終端命令行客峭,對以上哈希散列函數(shù)進(jìn)行驗證;
- 針對
MD5
哈希散列函數(shù)驗證抡柿,終端輸入:
md5 -s "123456"
-
md5 -s "123456LKSJDFLKJ"
舔琅,其中LKSJDFLKJ是鹽
;
- 針對
SHA
哈希散列函數(shù)驗證洲劣,終端輸入:
echo -n "123456" | openssl sha1
echo -n "123456" | openssl sha256
echo -n "123456" | openssl sha512
- 針對
HMAC加密
备蚓,其原理就是判斷是否有key,這個key是由服務(wù)器動態(tài)提供的
囱稽,保存在手機側(cè)郊尝,簡單來說,就相當(dāng)于現(xiàn)在的授權(quán)設(shè)備战惊,
HMAC主要就是檢測你的設(shè)備是否有授權(quán)`流昏;
- 終端輸入:
echo -n "123456" | openssl dgst -md5 -hmac "yanzi"
echo -n "123456" | openssl sha1 -hmac "yanzi"
echo -n "123456" | openssl sha256 -hmac "yanzi"
echo -n "123456" | openssl sha512 -hmac "yanzi"
- 其中
123456
是明文密碼,yanzi
是key值吞获;
- 可在
HMAC散列函數(shù)的基礎(chǔ)
上况凉,加上時間戳的認(rèn)證
,邏輯如下:
- 客戶端:對
密碼使用HMAC加密
各拷,得到一個hash值A(chǔ)
刁绒,再將hashA值帶上服務(wù)器給的時間戳
,求得另一個hash值B
烤黍;
- 將客戶端得到的
Hash值A(chǔ)膛锭、Hash值B
發(fā)送到服務(wù)器進(jìn)行驗證;
- 服務(wù)器:將傳過來的Hash值A(chǔ)蚊荣,帶上服務(wù)器的時間戳初狰,得到一個
Hash值C
,判斷Hash值C是否等于傳過來的Hash值B互例,如果不等于奢入,則表示不通過,在時間范圍內(nèi),再繼續(xù)驗證上一分鐘
腥光;
對稱加密
- 對稱加密方式:
明文
通過密鑰加密
得到密文
关顷,密文
通過密鑰解密
得到明文
;
- 對稱加密算法的特征:
- 加密方和解密方使用同一個密鑰武福;
- 加密解密的速度比較快议双,適合數(shù)據(jù)比較長時的使用;
- 密鑰傳輸?shù)倪^程不安全捉片,且容易被破解平痰,密鑰管理也比較麻煩;
- 加密與解密互為逆運算伍纫;
- 常見的對稱加密的算法:
-
DES
:數(shù)據(jù)加密標(biāo)準(zhǔn)宗雇,速度較快,適用于加密大量數(shù)據(jù)的場合(用得少莹规,因為強度不夠)赔蒲;
-
3DES
:是基于DES,對一塊數(shù)據(jù)用3個不同的密鑰進(jìn)行3次加密良漱,強度更高舞虱;
-
AES
:高級加密標(biāo)準(zhǔn),是下一代的加密算法標(biāo)準(zhǔn)母市,速度快矾兜,安全級別高,支持128窒篱、192焕刮、256舶沿、512位密鑰的加密墙杯;
- 對稱加密算法的應(yīng)用模式:
-
ECB (Electronic Code Book)
:電子密碼本模式,每一塊數(shù)據(jù)括荡,獨立加密高镐,最基本的加密模式,也就是通常理解的加密畸冲,相同的明文將永遠(yuǎn)加密成相同的密文嫉髓,無初始向量,容易受到密碼本重放攻擊邑闲,一般情況下很少用算行;
-
CBC (Cipher Block Chaining)
:密碼分組鏈接模式,使用一個密鑰
和一個初始化向量iv
對數(shù)據(jù)執(zhí)行加密苫耸,明文被加密前要與前面的密文進(jìn)行異或運算后再加密州邢,因此只要選擇不同的初始向量,相同的密文加密后會形成不同的密文褪子,這是目前應(yīng)用最廣泛的模式量淌;
-
AES
的加密實現(xiàn)源碼YYAES.h/m文件
如下所示:
#import <Foundation/Foundation.h>
@interface YYAES : NSString
//aes128 模式:ecb 補碼方式:pkcs7padding
+ (NSString *)AES128Encrypt:(NSString *)plainText key:(NSString *)key; //加密后base64
+ (NSString *)AES128Decrypt:(NSString *)encryptText key:(NSString *)key; //先base64解密后aes128
//aes256 模式:ecb 補碼方式:pkcs7padding
+ (NSString *)AES256EncryptWithKey:(NSString *)plainText key:(NSString *)key; //加密后base64
+ (NSString *)AES256DecryptWithKey:(NSString *)encryptText key:(NSString *)key; //先base64解密后aes256
#pragma mark 上面方法采用ecb模式有漏洞骗村,采用下面cbc模式替換,iv是偏移向量
//aes128 模式:cbc 補碼方式:pkcs7padding
+ (NSString *)AES128Encrypt:(NSString *)plainText key:(NSString *)key iv:(NSString *)iv; //加密后base64
+ (NSString *)AES128Decrypt:(NSString *)encryptText key:(NSString *)key iv:(NSString *)iv; //先base64解密后aes128
//aes256 模式:cbc 補碼方式:pkcs7padding
+ (NSString *)AES256EncryptWithKey:(NSString *)encryptText key:(NSString *)key iv:(NSString *)iv;//加密后base64
+ (NSString *)AES256DecryptWithKey:(NSString *)encryptText key:(NSString *)key iv:(NSString *)iv; //先base64解密后aes256
@end
#import "YYAES.h"
#import <CommonCrypto/CommonCryptor.h>
#import "GTMBase64.h"
static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@implementation YYAES
+ (NSString *)AES128Encrypt:(NSString *)plainText key:(NSString *)key {
char keyPtr[kCCKeySizeAES128+1];
memset(keyPtr, 0, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSData* data = [plainText dataUsingEncoding:NSUTF8StringEncoding];
NSUInteger dataLength = [data length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionECBMode | kCCOptionPKCS7Padding,
keyPtr,
kCCBlockSizeAES128,
NULL,
[data bytes],
dataLength,
buffer,
bufferSize,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
return [GTMBase64 stringByEncodingData:resultData];
}
free(buffer);
return nil;
}
+ (NSString *)AES128Decrypt:(NSString *)encryptText key:(NSString *)key {
char keyPtr[kCCKeySizeAES128 + 1];
memset(keyPtr, 0, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSData *data = [GTMBase64 decodeData:[encryptText dataUsingEncoding:NSUTF8StringEncoding]];
NSUInteger dataLength = [data length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesCrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmAES128,
kCCOptionECBMode | kCCOptionPKCS7Padding,
keyPtr,
kCCBlockSizeAES128,
NULL,
[data bytes],
dataLength,
buffer,
bufferSize,
&numBytesCrypted);
if (cryptStatus == kCCSuccess) {
NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
return [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
}
free(buffer);
return nil;
}
+ (NSString *)AES256EncryptWithKey:(NSString *)plainText key:(NSString *)key {
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSData* data = [plainText dataUsingEncoding:NSUTF8StringEncoding];
NSUInteger dataLength = [data length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[data bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
return [GTMBase64 stringByEncodingData:resultData];
}
free(buffer); //free the buffer;
return nil;
}
+ (NSString *)AES256DecryptWithKey:(NSString *)encryptText key:(NSString *)key {
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSData *data = [GTMBase64 decodeData:[encryptText dataUsingEncoding:NSUTF8StringEncoding]];
NSUInteger dataLength = [data length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[data bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
return [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
}
free(buffer); //free the buffer;
return nil;
}
@end
-
AES
加密算法呀枢,依賴于Base64編解碼
胚股;
- 加密過程:
先加密
,再Base64編碼
裙秋;
- 解密過程:
先Base64解碼
琅拌,再解密
;
- Base64編解碼的源碼實現(xiàn)如下:
#include <AvailabilityMacros.h>
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE
#include <Availability.h>
#endif // TARGET_OS_IPHONE
// Not all MAC_OS_X_VERSION_10_X macros defined in past SDKs
#ifndef MAC_OS_X_VERSION_10_5
#define MAC_OS_X_VERSION_10_5 1050
#endif
#ifndef MAC_OS_X_VERSION_10_6
#define MAC_OS_X_VERSION_10_6 1060
#endif
// Not all __IPHONE_X macros defined in past SDKs
#ifndef __IPHONE_2_1
#define __IPHONE_2_1 20100
#endif
#ifndef __IPHONE_2_2
#define __IPHONE_2_2 20200
#endif
#ifndef __IPHONE_3_0
#define __IPHONE_3_0 30000
#endif
#ifndef __IPHONE_3_1
#define __IPHONE_3_1 30100
#endif
#ifndef __IPHONE_3_2
#define __IPHONE_3_2 30200
#endif
#ifndef __IPHONE_4_0
#define __IPHONE_4_0 40000
#endif
#ifndef GTM_CONTAINERS_VALIDATION_FAILED_ASSERT
#define GTM_CONTAINERS_VALIDATION_FAILED_ASSERT 0
#endif
#if !defined(GTM_INLINE)
#if defined (__GNUC__) && (__GNUC__ == 4)
#define GTM_INLINE static __inline__ __attribute__((always_inline))
#else
#define GTM_INLINE static __inline__
#endif
#endif
#if !defined (GTM_EXTERN)
#if defined __cplusplus
#define GTM_EXTERN extern "C"
#define GTM_EXTERN_C_BEGIN extern "C" {
#define GTM_EXTERN_C_END }
#else
#define GTM_EXTERN extern
#define GTM_EXTERN_C_BEGIN
#define GTM_EXTERN_C_END
#endif
#endif
#if !defined (GTM_EXPORT)
#define GTM_EXPORT __attribute__((visibility("default")))
#endif
#if !defined (GTM_UNUSED)
#define GTM_UNUSED(x) ((void)(x))
#endif
#ifndef _GTMDevLog
#ifdef DEBUG
#define _GTMDevLog(...) NSLog(__VA_ARGS__)
#else
#define _GTMDevLog(...) do { } while (0)
#endif
#endif // _GTMDevLog
#ifndef _GTMDevAssert
#if !defined(NS_BLOCK_ASSERTIONS)
#define _GTMDevAssert(condition, ...) \
do { \
if (!(condition)) { \
[[NSAssertionHandler currentHandler] \
handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] \
file:[NSString stringWithUTF8String:__FILE__] \
lineNumber:__LINE__ \
description:__VA_ARGS__]; \
} \
} while(0)
#else // !defined(NS_BLOCK_ASSERTIONS)
#define _GTMDevAssert(condition, ...) do { } while (0)
#endif // !defined(NS_BLOCK_ASSERTIONS)
#endif // _GTMDevAssert
#ifndef _GTMCompileAssert
#define _GTMCompileAssertSymbolInner(line, msg) _GTMCOMPILEASSERT ## line ## __ ## msg
#define _GTMCompileAssertSymbol(line, msg) _GTMCompileAssertSymbolInner(line, msg)
#define _GTMCompileAssert(test, msg) \
typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ]
#endif // _GTMCompileAssert
#if TARGET_OS_IPHONE // iPhone SDK
// For iPhone specific stuff
#define GTM_IPHONE_SDK 1
#if TARGET_IPHONE_SIMULATOR
#define GTM_IPHONE_SIMULATOR 1
#else
#define GTM_IPHONE_DEVICE 1
#endif // TARGET_IPHONE_SIMULATOR
#else
// For MacOS specific stuff
#define GTM_MACOS_SDK 1
#endif
// Some of our own availability macros
#if GTM_MACOS_SDK
#define GTM_AVAILABLE_ONLY_ON_IPHONE UNAVAILABLE_ATTRIBUTE
#define GTM_AVAILABLE_ONLY_ON_MACOS
#else
#define GTM_AVAILABLE_ONLY_ON_IPHONE
#define GTM_AVAILABLE_ONLY_ON_MACOS UNAVAILABLE_ATTRIBUTE
#endif
// Provide a symbol to include/exclude extra code for GC support. (This mainly
// just controls the inclusion of finalize methods).
#ifndef GTM_SUPPORT_GC
#if GTM_IPHONE_SDK
// iPhone never needs GC
#define GTM_SUPPORT_GC 0
#else
// We can't find a symbol to tell if GC is supported/required, so best we
// do on Mac targets is include it if we're on 10.5 or later.
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
#define GTM_SUPPORT_GC 0
#else
#define GTM_SUPPORT_GC 1
#endif
#endif
#endif
// To simplify support for 64bit (and Leopard in general), we provide the type
// defines for non Leopard SDKs
#if !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
// NSInteger/NSUInteger and Max/Mins
#ifndef NSINTEGER_DEFINED
#if __LP64__ || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
#define NSIntegerMax LONG_MAX
#define NSIntegerMin LONG_MIN
#define NSUIntegerMax ULONG_MAX
#define NSINTEGER_DEFINED 1
#endif // NSINTEGER_DEFINED
// CGFloat
#ifndef CGFLOAT_DEFINED
#if defined(__LP64__) && __LP64__
// This really is an untested path (64bit on Tiger?)
typedef double CGFloat;
#define CGFLOAT_MIN DBL_MIN
#define CGFLOAT_MAX DBL_MAX
#define CGFLOAT_IS_DOUBLE 1
#else /* !defined(__LP64__) || !__LP64__ */
typedef float CGFloat;
#define CGFLOAT_MIN FLT_MIN
#define CGFLOAT_MAX FLT_MAX
#define CGFLOAT_IS_DOUBLE 0
#endif /* !defined(__LP64__) || !__LP64__ */
#define CGFLOAT_DEFINED 1
#endif // CGFLOAT_DEFINED
#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
// Some support for advanced clang static analysis functionality
// See http://clang-analyzer.llvm.org/annotations.html
#ifndef __has_feature // Optional.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#ifndef NS_RETURNS_RETAINED
#if __has_feature(attribute_ns_returns_retained)
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
#else
#define NS_RETURNS_RETAINED
#endif
#endif
#ifndef NS_RETURNS_NOT_RETAINED
#if __has_feature(attribute_ns_returns_not_retained)
#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
#else
#define NS_RETURNS_NOT_RETAINED
#endif
#endif
#ifndef CF_RETURNS_RETAINED
#if __has_feature(attribute_cf_returns_retained)
#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
#else
#define CF_RETURNS_RETAINED
#endif
#endif
#ifndef CF_RETURNS_NOT_RETAINED
#if __has_feature(attribute_cf_returns_not_retained)
#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
#else
#define CF_RETURNS_NOT_RETAINED
#endif
#endif
// Defined on 10.6 and above.
#ifndef NS_FORMAT_ARGUMENT
#define NS_FORMAT_ARGUMENT(A)
#endif
// Defined on 10.6 and above.
#ifndef NS_FORMAT_FUNCTION
#define NS_FORMAT_FUNCTION(F,A)
#endif
// Defined on 10.6 and above.
#ifndef CF_FORMAT_ARGUMENT
#define CF_FORMAT_ARGUMENT(A)
#endif
// Defined on 10.6 and above.
#ifndef CF_FORMAT_FUNCTION
#define CF_FORMAT_FUNCTION(F,A)
#endif
#ifndef GTM_NONNULL
#define GTM_NONNULL(x) __attribute__((nonnull(x)))
#endif
#ifdef __OBJC__
// Declared here so that it can easily be used for logging tracking if
// necessary. See GTMUnitTestDevLog.h for details.
@class NSString;
GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
#if !defined (GTM_NSSTRINGIFY)
#define GTM_NSSTRINGIFY_INNER(x) @#x
#define GTM_NSSTRINGIFY(x) GTM_NSSTRINGIFY_INNER(x)
#endif
#ifndef GTM_FOREACH_OBJECT
#if TARGET_OS_IPHONE || !(MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
#define GTM_FOREACH_ENUMEREE(element, enumeration) \
for (element in enumeration)
#define GTM_FOREACH_OBJECT(element, collection) \
for (element in collection)
#define GTM_FOREACH_KEY(element, collection) \
for (element in collection)
#else
#define GTM_FOREACH_ENUMEREE(element, enumeration) \
for (NSEnumerator *_ ## element ## _enum = enumeration; \
(element = [_ ## element ## _enum nextObject]) != nil; )
#define GTM_FOREACH_OBJECT(element, collection) \
GTM_FOREACH_ENUMEREE(element, [collection objectEnumerator])
#define GTM_FOREACH_KEY(element, collection) \
GTM_FOREACH_ENUMEREE(element, [collection keyEnumerator])
#endif
#endif
#if !defined(GTM_10_6_PROTOCOLS_DEFINED) && !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
#define GTM_10_6_PROTOCOLS_DEFINED 1
@protocol NSConnectionDelegate
@end
@protocol NSAnimationDelegate
@end
@protocol NSImageDelegate
@end
@protocol NSTabViewDelegate
@end
#endif // !defined(GTM_10_6_PROTOCOLS_DEFINED) && !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
#ifndef GTM_SEL_STRING
#ifdef DEBUG
#define GTM_SEL_STRING(selName) NSStringFromSelector(@selector(selName))
#else
#define GTM_SEL_STRING(selName) @#selName
#endif // DEBUG
#endif // GTM_SEL_STRING
#endif // __OBJC__
#import <Foundation/Foundation.h>
#import "GTMDefines.h"
@interface GTMBase64 : NSObject
+(NSData *)encodeData:(NSData *)data;
+(NSData *)decodeData:(NSData *)data;
+(NSData *)encodeBytes:(const void *)bytes length:(NSUInteger)length;
+(NSData *)decodeBytes:(const void *)bytes length:(NSUInteger)length;
+(NSString *)stringByEncodingData:(NSData *)data;
+(NSString *)stringByEncodingBytes:(const void *)bytes length:(NSUInteger)length;
+(NSData *)decodeString:(NSString *)string;
+(NSData *)webSafeEncodeData:(NSData *)data
padded:(BOOL)padded;
+(NSData *)webSafeDecodeData:(NSData *)data;
+(NSData *)webSafeEncodeBytes:(const void *)bytes
length:(NSUInteger)length
padded:(BOOL)padded;
+(NSData *)webSafeDecodeBytes:(const void *)bytes length:(NSUInteger)length;
+(NSString *)stringByWebSafeEncodingData:(NSData *)data
padded:(BOOL)padded;
+(NSString *)stringByWebSafeEncodingBytes:(const void *)bytes
length:(NSUInteger)length
padded:(BOOL)padded;
+(NSData *)webSafeDecodeString:(NSString *)string;
@end
#import "GTMBase64.h"
#import "GTMDefines.h"
static const char *kBase64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char *kWebSafeBase64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
static const char kBase64PaddingChar = '=';
static const char kBase64InvalidChar = 99;
static const char kBase64DecodeChars[] = {
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 62/*+*/, 99, 99, 99, 63/*/ */,
52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
60/*8*/, 61/*9*/, 99, 99, 99, 99, 99, 99,
99, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
23/*X*/, 24/*Y*/, 25/*Z*/, 99, 99, 99, 99, 99,
99, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
49/*x*/, 50/*y*/, 51/*z*/, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
};
static const char kWebSafeBase64DecodeChars[] = {
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 62/*-*/, 99, 99,
52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
60/*8*/, 61/*9*/, 99, 99, 99, 99, 99, 99,
99, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
23/*X*/, 24/*Y*/, 25/*Z*/, 99, 99, 99, 99, 63/*_*/,
99, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
49/*x*/, 50/*y*/, 51/*z*/, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
};
GTM_INLINE BOOL IsSpace(unsigned char c) {
static BOOL kSpaces[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // 0-9
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 10-19
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20-29
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 30-39
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40-49
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 50-59
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60-69
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 70-79
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80-89
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90-99
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 100-109
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 110-119
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 120-129
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 130-139
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 140-149
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 150-159
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160-169
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 170-179
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 180-189
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 190-199
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 200-209
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 210-219
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 220-229
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 230-239
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240-249
0, 0, 0, 0, 0, 1, // 250-255
};
return kSpaces[c];
}
GTM_INLINE NSUInteger CalcEncodedLength(NSUInteger srcLen, BOOL padded) {
NSUInteger intermediate_result = 8 * srcLen + 5;
NSUInteger len = intermediate_result / 6;
if (padded) {
len = ((len + 3) / 4) * 4;
}
return len;
}
GTM_INLINE NSUInteger GuessDecodedLength(NSUInteger srcLen) {
return (srcLen + 3) / 4 * 3;
}
@interface GTMBase64 (PrivateMethods)
+(NSData *)baseEncode:(const void *)bytes
length:(NSUInteger)length
charset:(const char *)charset
padded:(BOOL)padded;
+(NSData *)baseDecode:(const void *)bytes
length:(NSUInteger)length
charset:(const char*)charset
requirePadding:(BOOL)requirePadding;
+(NSUInteger)baseEncode:(const char *)srcBytes
srcLen:(NSUInteger)srcLen
destBytes:(char *)destBytes
destLen:(NSUInteger)destLen
charset:(const char *)charset
padded:(BOOL)padded;
+(NSUInteger)baseDecode:(const char *)srcBytes
srcLen:(NSUInteger)srcLen
destBytes:(char *)destBytes
destLen:(NSUInteger)destLen
charset:(const char *)charset
requirePadding:(BOOL)requirePadding;
@end
@implementation GTMBase64
+(NSData *)encodeData:(NSData *)data {
return [self baseEncode:[data bytes]
length:[data length]
charset:kBase64EncodeChars
padded:YES];
}
+(NSData *)decodeData:(NSData *)data {
return [self baseDecode:[data bytes]
length:[data length]
charset:kBase64DecodeChars
requirePadding:YES];
}
+(NSData *)encodeBytes:(const void *)bytes length:(NSUInteger)length {
return [self baseEncode:bytes
length:length
charset:kBase64EncodeChars
padded:YES];
}
+(NSData *)decodeBytes:(const void *)bytes length:(NSUInteger)length {
return [self baseDecode:bytes
length:length
charset:kBase64DecodeChars
requirePadding:YES];
}
+(NSString *)stringByEncodingData:(NSData *)data {
NSString *result = nil;
NSData *converted = [self baseEncode:[data bytes]
length:[data length]
charset:kBase64EncodeChars
padded:YES];
if (converted) {
result = [[NSString alloc] initWithData:converted
encoding:NSASCIIStringEncoding];
}
return result;
}
+(NSString *)stringByEncodingBytes:(const void *)bytes length:(NSUInteger)length {
NSString *result = nil;
NSData *converted = [self baseEncode:bytes
length:length
charset:kBase64EncodeChars
padded:YES];
if (converted) {
result = [[NSString alloc] initWithData:converted
encoding:NSASCIIStringEncoding];
}
return result;
}
+(NSData *)decodeString:(NSString *)string {
NSData *result = nil;
NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding];
if (data) {
result = [self baseDecode:[data bytes]
length:[data length]
charset:kBase64DecodeChars
requirePadding:YES];
}
return result;
}
+(NSData *)webSafeEncodeData:(NSData *)data
padded:(BOOL)padded {
return [self baseEncode:[data bytes]
length:[data length]
charset:kWebSafeBase64EncodeChars
padded:padded];
}
+(NSData *)webSafeDecodeData:(NSData *)data {
return [self baseDecode:[data bytes]
length:[data length]
charset:kWebSafeBase64DecodeChars
requirePadding:NO];
}
+(NSData *)webSafeEncodeBytes:(const void *)bytes
length:(NSUInteger)length
padded:(BOOL)padded {
return [self baseEncode:bytes
length:length
charset:kWebSafeBase64EncodeChars
padded:padded];
}
+(NSData *)webSafeDecodeBytes:(const void *)bytes length:(NSUInteger)length {
return [self baseDecode:bytes
length:length
charset:kWebSafeBase64DecodeChars
requirePadding:NO];
}
+(NSString *)stringByWebSafeEncodingData:(NSData *)data
padded:(BOOL)padded {
NSString *result = nil;
NSData *converted = [self baseEncode:[data bytes]
length:[data length]
charset:kWebSafeBase64EncodeChars
padded:padded];
if (converted) {
result = [[NSString alloc] initWithData:converted
encoding:NSASCIIStringEncoding];
}
return result;
}
+(NSString *)stringByWebSafeEncodingBytes:(const void *)bytes
length:(NSUInteger)length
padded:(BOOL)padded {
NSString *result = nil;
NSData *converted = [self baseEncode:bytes
length:length
charset:kWebSafeBase64EncodeChars
padded:padded];
if (converted) {
result = [[NSString alloc] initWithData:converted
encoding:NSASCIIStringEncoding];
}
return result;
}
+(NSData *)webSafeDecodeString:(NSString *)string {
NSData *result = nil;
NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding];
if (data) {
result = [self baseDecode:[data bytes]
length:[data length]
charset:kWebSafeBase64DecodeChars
requirePadding:NO];
}
return result;
}
@end
@implementation GTMBase64 (PrivateMethods)
+(NSData *)baseEncode:(const void *)bytes
length:(NSUInteger)length
charset:(const char *)charset
padded:(BOOL)padded {
// how big could it be?
NSUInteger maxLength = CalcEncodedLength(length, padded);
// make space
NSMutableData *result = [NSMutableData data];
[result setLength:maxLength];
// do it
NSUInteger finalLength = [self baseEncode:bytes
srcLen:length
destBytes:[result mutableBytes]
destLen:[result length]
charset:charset
padded:padded];
if (finalLength) {
_GTMDevAssert(finalLength == maxLength, @"how did we calc the length wrong?");
} else {
// shouldn't happen, this means we ran out of space
result = nil;
}
return result;
}
+(NSData *)baseDecode:(const void *)bytes
length:(NSUInteger)length
charset:(const char *)charset
requirePadding:(BOOL)requirePadding {
// could try to calculate what it will end up as
NSUInteger maxLength = GuessDecodedLength(length);
// make space
NSMutableData *result = [NSMutableData data];
[result setLength:maxLength];
// do it
NSUInteger finalLength = [self baseDecode:bytes
srcLen:length
destBytes:[result mutableBytes]
destLen:[result length]
charset:charset
requirePadding:requirePadding];
if (finalLength) {
if (finalLength != maxLength) {
// resize down to how big it was
[result setLength:finalLength];
}
} else {
// either an error in the args, or we ran out of space
result = nil;
}
return result;
}
+(NSUInteger)baseEncode:(const char *)srcBytes
srcLen:(NSUInteger)srcLen
destBytes:(char *)destBytes
destLen:(NSUInteger)destLen
charset:(const char *)charset
padded:(BOOL)padded {
if (!srcLen || !destLen || !srcBytes || !destBytes) {
return 0;
}
char *curDest = destBytes;
const unsigned char *curSrc = (const unsigned char *)(srcBytes);
while (srcLen > 2) {
// space?
_GTMDevAssert(destLen >= 4, @"our calc for encoded length was wrong");
curDest[0] = charset[curSrc[0] >> 2];
curDest[1] = charset[((curSrc[0] & 0x03) << 4) + (curSrc[1] >> 4)];
curDest[2] = charset[((curSrc[1] & 0x0f) << 2) + (curSrc[2] >> 6)];
curDest[3] = charset[curSrc[2] & 0x3f];
curDest += 4;
curSrc += 3;
srcLen -= 3;
destLen -= 4;
}
switch (srcLen) {
case 0:
break;
case 1:
_GTMDevAssert(destLen >= 2, @"our calc for encoded length was wrong");
curDest[0] = charset[curSrc[0] >> 2];
curDest[1] = charset[(curSrc[0] & 0x03) << 4];
curDest += 2;
destLen -= 2;
if (padded) {
_GTMDevAssert(destLen >= 2, @"our calc for encoded length was wrong");
curDest[0] = kBase64PaddingChar;
curDest[1] = kBase64PaddingChar;
curDest += 2;
}
break;
case 2:
_GTMDevAssert(destLen >= 3, @"our calc for encoded length was wrong");
curDest[0] = charset[curSrc[0] >> 2];
curDest[1] = charset[((curSrc[0] & 0x03) << 4) + (curSrc[1] >> 4)];
curDest[2] = charset[(curSrc[1] & 0x0f) << 2];
curDest += 3;
destLen -= 3;
if (padded) {
_GTMDevAssert(destLen >= 1, @"our calc for encoded length was wrong");
curDest[0] = kBase64PaddingChar;
curDest += 1;
}
break;
}
return (curDest - destBytes);
}
+(NSUInteger)baseDecode:(const char *)srcBytes
srcLen:(NSUInteger)srcLen
destBytes:(char *)destBytes
destLen:(NSUInteger)destLen
charset:(const char *)charset
requirePadding:(BOOL)requirePadding {
if (!srcLen || !destLen || !srcBytes || !destBytes) {
return 0;
}
int decode;
NSUInteger destIndex = 0;
int state = 0;
char ch = 0;
while (srcLen-- && (ch = *srcBytes++) != 0) {
if (IsSpace(ch)) // Skip whitespace
continue;
if (ch == kBase64PaddingChar)
break;
decode = charset[(unsigned int)ch];
if (decode == kBase64InvalidChar)
return 0;
switch (state) {
case 0:
_GTMDevAssert(destIndex < destLen, @"our calc for decoded length was wrong");
destBytes[destIndex] = decode << 2;
state = 1;
break;
case 1:
// We're one character into a four-character cyphertext block.
// This sets the low two bits of the first plaintext byte,
// and the high four bits of the second plaintext byte.
_GTMDevAssert((destIndex+1) < destLen, @"our calc for decoded length was wrong");
destBytes[destIndex] |= decode >> 4;
destBytes[destIndex+1] = (decode & 0x0f) << 4;
destIndex++;
state = 2;
break;
case 2:
_GTMDevAssert((destIndex+1) < destLen, @"our calc for decoded length was wrong");
destBytes[destIndex] |= decode >> 2;
destBytes[destIndex+1] = (decode & 0x03) << 6;
destIndex++;
state = 3;
break;
case 3:
_GTMDevAssert(destIndex < destLen, @"our calc for decoded length was wrong");
destBytes[destIndex] |= decode;
destIndex++;
state = 0;
break;
}
}
if (ch == kBase64PaddingChar) {
if ((state == 0) || (state == 1)) {
return 0; // Invalid '=' in first or second position
}
if (srcLen == 0) {
if (state == 2) { // We run out of input but we still need another '='
return 0;
}
// Otherwise, we are in state 3 and only need this '='
} else {
if (state == 2) { // need another '='
while ((ch = *srcBytes++) && (srcLen-- > 0)) {
if (!IsSpace(ch))
break;
}
if (ch != kBase64PaddingChar) {
return 0;
}
}
// state = 1 or 2, check if all remain padding is space
while ((ch = *srcBytes++) && (srcLen-- > 0)) {
if (!IsSpace(ch)) {
return 0;
}
}
}
} else {
if (requirePadding) {
// If we require padding, then anything but state 0 is an error.
if (state != 0) {
return 0;
}
} else {
// Make sure we have no partial bytes lying around. Note that we do not
// require trailing '=', so states 2 and 3 are okay too.
if (state == 1) {
return 0;
}
}
}
if ((destIndex < destLen) &&
(destBytes[destIndex] != 0)) {
return 0;
}
return destIndex;
}
@end
參考文章
iOS逆向 07:Hash算法
iOS開發(fā)中DES的加密和解密
iOS逆向之RSA加密