├── README.md ├── GTMBase64.h ├── GTMDefines.h └── GTMBase64.m /README.md: -------------------------------------------------------------------------------- 1 | GTMBase64 2 | ========= 3 | 4 | Base64加解密 5 | 6 | 使用方法: 7 | 1)丢入ios项目。 8 | 【注意】开启ARC的同学注意 9 | 解决方法:-fno-objc-arc 10 | 11 | 2)在要使用GTMBase64的地方#import "GTMBase64.h"引入头文件 12 | 13 | 3)下面详细说明: 14 | 15 | 常用的方法,有下面几个: 16 | + (NSString*)md5_base64: (NSString *) inPutText; 17 | + (NSString*)encodeBase64String:(NSString *)input; 18 | + (NSString*)decodeBase64String:(NSString *)input; 19 | + (NSString*)encodeBase64Data:(NSData *)data; 20 | + (NSString*)decodeBase64Data:(NSData *)data; 21 | -------------------------------------------------------------------------------- /GTMBase64.h: -------------------------------------------------------------------------------- 1 | // 2 | // GTMBase64.h 3 | // 4 | // Copyright 2006-2008 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 7 | // use this file except in compliance with the License. You may obtain a copy 8 | // of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 | // License for the specific language governing permissions and limitations under 16 | // the License. 17 | // 18 | 19 | #import 20 | #import "GTMDefines.h" 21 | 22 | // GTMBase64 23 | // 24 | /// Helper for handling Base64 and WebSafeBase64 encodings 25 | // 26 | /// The webSafe methods use different character set and also the results aren't 27 | /// always padded to a multiple of 4 characters. This is done so the resulting 28 | /// data can be used in urls and url query arguments without needing any 29 | /// encoding. You must use the webSafe* methods together, the data does not 30 | /// interop with the RFC methods. 31 | // 32 | @interface GTMBase64 : NSObject 33 | 34 | // 35 | // Standard Base64 (RFC) handling 36 | // 37 | 38 | // encodeData: 39 | // 40 | /// Base64 encodes contents of the NSData object. 41 | // 42 | /// Returns: 43 | /// A new autoreleased NSData with the encoded payload. nil for any error. 44 | // 45 | +(NSData *)encodeData:(NSData *)data; 46 | 47 | // decodeData: 48 | // 49 | /// Base64 decodes contents of the NSData object. 50 | // 51 | /// Returns: 52 | /// A new autoreleased NSData with the decoded payload. nil for any error. 53 | // 54 | +(NSData *)decodeData:(NSData *)data; 55 | 56 | // encodeBytes:length: 57 | // 58 | /// Base64 encodes the data pointed at by |bytes|. 59 | // 60 | /// Returns: 61 | /// A new autoreleased NSData with the encoded payload. nil for any error. 62 | // 63 | +(NSData *)encodeBytes:(const void *)bytes length:(NSUInteger)length; 64 | 65 | // decodeBytes:length: 66 | // 67 | /// Base64 decodes the data pointed at by |bytes|. 68 | // 69 | /// Returns: 70 | /// A new autoreleased NSData with the encoded payload. nil for any error. 71 | // 72 | +(NSData *)decodeBytes:(const void *)bytes length:(NSUInteger)length; 73 | 74 | // stringByEncodingData: 75 | // 76 | /// Base64 encodes contents of the NSData object. 77 | // 78 | /// Returns: 79 | /// A new autoreleased NSString with the encoded payload. nil for any error. 80 | // 81 | +(NSString *)stringByEncodingData:(NSData *)data; 82 | 83 | // stringByEncodingBytes:length: 84 | // 85 | /// Base64 encodes the data pointed at by |bytes|. 86 | // 87 | /// Returns: 88 | /// A new autoreleased NSString with the encoded payload. nil for any error. 89 | // 90 | +(NSString *)stringByEncodingBytes:(const void *)bytes length:(NSUInteger)length; 91 | 92 | // decodeString: 93 | // 94 | /// Base64 decodes contents of the NSString. 95 | // 96 | /// Returns: 97 | /// A new autoreleased NSData with the decoded payload. nil for any error. 98 | // 99 | +(NSData *)decodeString:(NSString *)string; 100 | 101 | // 102 | // Modified Base64 encoding so the results can go onto urls. 103 | // 104 | // The changes are in the characters generated and also allows the result to 105 | // not be padded to a multiple of 4. 106 | // Must use the matching call to encode/decode, won't interop with the 107 | // RFC versions. 108 | // 109 | 110 | // webSafeEncodeData:padded: 111 | // 112 | /// WebSafe Base64 encodes contents of the NSData object. If |padded| is YES 113 | /// then padding characters are added so the result length is a multiple of 4. 114 | // 115 | /// Returns: 116 | /// A new autoreleased NSData with the encoded payload. nil for any error. 117 | // 118 | +(NSData *)webSafeEncodeData:(NSData *)data 119 | padded:(BOOL)padded; 120 | 121 | // webSafeDecodeData: 122 | // 123 | /// WebSafe Base64 decodes contents of the NSData object. 124 | // 125 | /// Returns: 126 | /// A new autoreleased NSData with the decoded payload. nil for any error. 127 | // 128 | +(NSData *)webSafeDecodeData:(NSData *)data; 129 | 130 | // webSafeEncodeBytes:length:padded: 131 | // 132 | /// WebSafe Base64 encodes the data pointed at by |bytes|. If |padded| is YES 133 | /// then padding characters are added so the result length is a multiple of 4. 134 | // 135 | /// Returns: 136 | /// A new autoreleased NSData with the encoded payload. nil for any error. 137 | // 138 | +(NSData *)webSafeEncodeBytes:(const void *)bytes 139 | length:(NSUInteger)length 140 | padded:(BOOL)padded; 141 | 142 | // webSafeDecodeBytes:length: 143 | // 144 | /// WebSafe Base64 decodes the data pointed at by |bytes|. 145 | // 146 | /// Returns: 147 | /// A new autoreleased NSData with the encoded payload. nil for any error. 148 | // 149 | +(NSData *)webSafeDecodeBytes:(const void *)bytes length:(NSUInteger)length; 150 | 151 | // stringByWebSafeEncodingData:padded: 152 | // 153 | /// WebSafe Base64 encodes contents of the NSData object. If |padded| is YES 154 | /// then padding characters are added so the result length is a multiple of 4. 155 | // 156 | /// Returns: 157 | /// A new autoreleased NSString with the encoded payload. nil for any error. 158 | // 159 | +(NSString *)stringByWebSafeEncodingData:(NSData *)data 160 | padded:(BOOL)padded; 161 | 162 | // stringByWebSafeEncodingBytes:length:padded: 163 | // 164 | /// WebSafe Base64 encodes the data pointed at by |bytes|. If |padded| is YES 165 | /// then padding characters are added so the result length is a multiple of 4. 166 | // 167 | /// Returns: 168 | /// A new autoreleased NSString with the encoded payload. nil for any error. 169 | // 170 | +(NSString *)stringByWebSafeEncodingBytes:(const void *)bytes 171 | length:(NSUInteger)length 172 | padded:(BOOL)padded; 173 | 174 | // webSafeDecodeString: 175 | // 176 | /// WebSafe Base64 decodes contents of the NSString. 177 | // 178 | /// Returns: 179 | /// A new autoreleased NSData with the decoded payload. nil for any error. 180 | // 181 | +(NSData *)webSafeDecodeString:(NSString *)string; 182 | 183 | 184 | 185 | #pragma mark - base64 186 | + (NSString*)md5_base64: (NSString *) inPutText; 187 | + (NSString*)encodeBase64String:(NSString *)input; 188 | + (NSString*)decodeBase64String:(NSString *)input; 189 | + (NSString*)encodeBase64Data:(NSData *)data; 190 | + (NSString*)decodeBase64Data:(NSData *)data; 191 | 192 | @end 193 | -------------------------------------------------------------------------------- /GTMDefines.h: -------------------------------------------------------------------------------- 1 | // 2 | // GTMDefines.h 3 | // 4 | // Copyright 2008 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 7 | // use this file except in compliance with the License. You may obtain a copy 8 | // of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 | // License for the specific language governing permissions and limitations under 16 | // the License. 17 | // 18 | 19 | // ============================================================================ 20 | 21 | #include 22 | 23 | // Not all MAC_OS_X_VERSION_10_X macros defined in past SDKs 24 | #ifndef MAC_OS_X_VERSION_10_5 25 | #define MAC_OS_X_VERSION_10_5 1050 26 | #endif 27 | #ifndef MAC_OS_X_VERSION_10_6 28 | #define MAC_OS_X_VERSION_10_6 1060 29 | #endif 30 | 31 | // ---------------------------------------------------------------------------- 32 | // CPP symbols that can be overridden in a prefix to control how the toolbox 33 | // is compiled. 34 | // ---------------------------------------------------------------------------- 35 | 36 | 37 | // GTMHTTPFetcher will support logging by default but only hook its input 38 | // stream support for logging when requested. You can control the inclusion of 39 | // the code by providing your own definitions for these w/in a prefix header. 40 | // 41 | #ifndef GTM_HTTPFETCHER_ENABLE_LOGGING 42 | #define GTM_HTTPFETCHER_ENABLE_LOGGING 1 43 | #endif // GTM_HTTPFETCHER_ENABLE_LOGGING 44 | #ifndef GTM_HTTPFETCHER_ENABLE_INPUTSTREAM_LOGGING 45 | #define GTM_HTTPFETCHER_ENABLE_INPUTSTREAM_LOGGING 0 46 | #endif // GTM_HTTPFETCHER_ENABLE_INPUTSTREAM_LOGGING 47 | 48 | // By setting the GTM_CONTAINERS_VALIDATION_FAILED_LOG and 49 | // GTM_CONTAINERS_VALIDATION_FAILED_ASSERT macros you can control what happens 50 | // when a validation fails. If you implement your own validators, you may want 51 | // to control their internals using the same macros for consistency. 52 | #ifndef GTM_CONTAINERS_VALIDATION_FAILED_ASSERT 53 | #define GTM_CONTAINERS_VALIDATION_FAILED_ASSERT 0 54 | #endif 55 | 56 | // Give ourselves a consistent way to do inlines. Apple's macros even use 57 | // a few different actual definitions, so we're based off of the foundation 58 | // one. 59 | #if !defined(GTM_INLINE) 60 | #if defined (__GNUC__) && (__GNUC__ == 4) 61 | #define GTM_INLINE static __inline__ __attribute__((always_inline)) 62 | #else 63 | #define GTM_INLINE static __inline__ 64 | #endif 65 | #endif 66 | 67 | // Give ourselves a consistent way of doing externs that links up nicely 68 | // when mixing objc and objc++ 69 | #if !defined (GTM_EXTERN) 70 | #if defined __cplusplus 71 | #define GTM_EXTERN extern "C" 72 | #else 73 | #define GTM_EXTERN extern 74 | #endif 75 | #endif 76 | 77 | // Give ourselves a consistent way of exporting things if we have visibility 78 | // set to hidden. 79 | #if !defined (GTM_EXPORT) 80 | #define GTM_EXPORT __attribute__((visibility("default"))) 81 | #endif 82 | 83 | // _GTMDevLog & _GTMDevAssert 84 | // 85 | // _GTMDevLog & _GTMDevAssert are meant to be a very lightweight shell for 86 | // developer level errors. This implementation simply macros to NSLog/NSAssert. 87 | // It is not intended to be a general logging/reporting system. 88 | // 89 | // Please see http://code.google.com/p/google-toolbox-for-mac/wiki/DevLogNAssert 90 | // for a little more background on the usage of these macros. 91 | // 92 | // _GTMDevLog log some error/problem in debug builds 93 | // _GTMDevAssert assert if conditon isn't met w/in a method/function 94 | // in all builds. 95 | // 96 | // To replace this system, just provide different macro definitions in your 97 | // prefix header. Remember, any implementation you provide *must* be thread 98 | // safe since this could be called by anything in what ever situtation it has 99 | // been placed in. 100 | // 101 | 102 | // We only define the simple macros if nothing else has defined this. 103 | #ifndef _GTMDevLog 104 | 105 | #ifdef DEBUG 106 | #define _GTMDevLog(...) NSLog(__VA_ARGS__) 107 | #else 108 | #define _GTMDevLog(...) do { } while (0) 109 | #endif 110 | 111 | #endif // _GTMDevLog 112 | 113 | // Declared here so that it can easily be used for logging tracking if 114 | // necessary. See GTMUnitTestDevLog.h for details. 115 | @class NSString; 116 | GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...); 117 | 118 | #ifndef _GTMDevAssert 119 | // we directly invoke the NSAssert handler so we can pass on the varargs 120 | // (NSAssert doesn't have a macro we can use that takes varargs) 121 | #if !defined(NS_BLOCK_ASSERTIONS) 122 | #define _GTMDevAssert(condition, ...) \ 123 | do { \ 124 | if (!(condition)) { \ 125 | [[NSAssertionHandler currentHandler] \ 126 | handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] \ 127 | file:[NSString stringWithUTF8String:__FILE__] \ 128 | lineNumber:__LINE__ \ 129 | description:__VA_ARGS__]; \ 130 | } \ 131 | } while(0) 132 | #else // !defined(NS_BLOCK_ASSERTIONS) 133 | #define _GTMDevAssert(condition, ...) do { } while (0) 134 | #endif // !defined(NS_BLOCK_ASSERTIONS) 135 | 136 | #endif // _GTMDevAssert 137 | 138 | // _GTMCompileAssert 139 | // _GTMCompileAssert is an assert that is meant to fire at compile time if you 140 | // want to check things at compile instead of runtime. For example if you 141 | // want to check that a wchar is 4 bytes instead of 2 you would use 142 | // _GTMCompileAssert(sizeof(wchar_t) == 4, wchar_t_is_4_bytes_on_OS_X) 143 | // Note that the second "arg" is not in quotes, and must be a valid processor 144 | // symbol in it's own right (no spaces, punctuation etc). 145 | 146 | // Wrapping this in an #ifndef allows external groups to define their own 147 | // compile time assert scheme. 148 | #ifndef _GTMCompileAssert 149 | // We got this technique from here: 150 | // http://unixjunkie.blogspot.com/2007/10/better-compile-time-asserts_29.html 151 | 152 | #define _GTMCompileAssertSymbolInner(line, msg) _GTMCOMPILEASSERT ## line ## __ ## msg 153 | #define _GTMCompileAssertSymbol(line, msg) _GTMCompileAssertSymbolInner(line, msg) 154 | #define _GTMCompileAssert(test, msg) \ 155 | typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ] 156 | #endif // _GTMCompileAssert 157 | 158 | // Macro to allow fast enumeration when building for 10.5 or later, and 159 | // reliance on NSEnumerator for 10.4. Remember, NSDictionary w/ FastEnumeration 160 | // does keys, so pick the right thing, nothing is done on the FastEnumeration 161 | // side to be sure you're getting what you wanted. 162 | #ifndef GTM_FOREACH_OBJECT 163 | #if defined(TARGET_OS_IPHONE) || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) 164 | #define GTM_FOREACH_OBJECT(element, collection) \ 165 | for (element in collection) 166 | #define GTM_FOREACH_KEY(element, collection) \ 167 | for (element in collection) 168 | #else 169 | #define GTM_FOREACH_OBJECT(element, collection) \ 170 | for (NSEnumerator * _ ## element ## _enum = [collection objectEnumerator]; \ 171 | (element = [_ ## element ## _enum nextObject]) != nil; ) 172 | #define GTM_FOREACH_KEY(element, collection) \ 173 | for (NSEnumerator * _ ## element ## _enum = [collection keyEnumerator]; \ 174 | (element = [_ ## element ## _enum nextObject]) != nil; ) 175 | #endif 176 | #endif 177 | 178 | // ============================================================================ 179 | 180 | // ---------------------------------------------------------------------------- 181 | // CPP symbols defined based on the project settings so the GTM code has 182 | // simple things to test against w/o scattering the knowledge of project 183 | // setting through all the code. 184 | // ---------------------------------------------------------------------------- 185 | 186 | // Provide a single constant CPP symbol that all of GTM uses for ifdefing 187 | // iPhone code. 188 | #include 189 | #if TARGET_OS_IPHONE // iPhone SDK 190 | // For iPhone specific stuff 191 | #define GTM_IPHONE_SDK 1 192 | #if TARGET_IPHONE_SIMULATOR 193 | #define GTM_IPHONE_SIMULATOR 1 194 | #else 195 | #define GTM_IPHONE_DEVICE 1 196 | #endif // TARGET_IPHONE_SIMULATOR 197 | #else 198 | // For MacOS specific stuff 199 | #define GTM_MACOS_SDK 1 200 | #endif 201 | 202 | // Provide a symbol to include/exclude extra code for GC support. (This mainly 203 | // just controls the inclusion of finalize methods). 204 | #ifndef GTM_SUPPORT_GC 205 | #if GTM_IPHONE_SDK 206 | // iPhone never needs GC 207 | #define GTM_SUPPORT_GC 0 208 | #else 209 | // We can't find a symbol to tell if GC is supported/required, so best we 210 | // do on Mac targets is include it if we're on 10.5 or later. 211 | #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 212 | #define GTM_SUPPORT_GC 0 213 | #else 214 | #define GTM_SUPPORT_GC 1 215 | #endif 216 | #endif 217 | #endif 218 | 219 | // To simplify support for 64bit (and Leopard in general), we provide the type 220 | // defines for non Leopard SDKs 221 | #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 222 | // NSInteger/NSUInteger and Max/Mins 223 | #ifndef NSINTEGER_DEFINED 224 | #if __LP64__ || NS_BUILD_32_LIKE_64 225 | typedef long NSInteger; 226 | typedef unsigned long NSUInteger; 227 | #else 228 | typedef int NSInteger; 229 | typedef unsigned int NSUInteger; 230 | #endif 231 | #define NSIntegerMax LONG_MAX 232 | #define NSIntegerMin LONG_MIN 233 | #define NSUIntegerMax ULONG_MAX 234 | #define NSINTEGER_DEFINED 1 235 | #endif // NSINTEGER_DEFINED 236 | // CGFloat 237 | #ifndef CGFLOAT_DEFINED 238 | #if defined(__LP64__) && __LP64__ 239 | // This really is an untested path (64bit on Tiger?) 240 | typedef double CGFloat; 241 | #define CGFLOAT_MIN DBL_MIN 242 | #define CGFLOAT_MAX DBL_MAX 243 | #define CGFLOAT_IS_DOUBLE 1 244 | #else /* !defined(__LP64__) || !__LP64__ */ 245 | typedef float CGFloat; 246 | #define CGFLOAT_MIN FLT_MIN 247 | #define CGFLOAT_MAX FLT_MAX 248 | #define CGFLOAT_IS_DOUBLE 0 249 | #endif /* !defined(__LP64__) || !__LP64__ */ 250 | #define CGFLOAT_DEFINED 1 251 | #endif // CGFLOAT_DEFINED 252 | #endif // MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 253 | -------------------------------------------------------------------------------- /GTMBase64.m: -------------------------------------------------------------------------------- 1 | // 2 | // GTMBase64.m 3 | // 4 | // Copyright 2006-2008 Google Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 7 | // use this file except in compliance with the License. You may obtain a copy 8 | // of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 | // License for the specific language governing permissions and limitations under 16 | // the License. 17 | // 18 | 19 | #import "GTMBase64.h" 20 | #import "GTMDefines.h" 21 | #import "commoncrypto/commondigest.h" 22 | static const char *kBase64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 23 | static const char *kWebSafeBase64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; 24 | static const char kBase64PaddingChar = '='; 25 | static const char kBase64InvalidChar = 99; 26 | 27 | static const char kBase64DecodeChars[] = { 28 | // This array was generated by the following code: 29 | // #include 30 | // #include 31 | // #include 32 | // main() 33 | // { 34 | // static const char Base64[] = 35 | // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 36 | // char *pos; 37 | // int idx, i, j; 38 | // printf(" "); 39 | // for (i = 0; i < 255; i += 8) { 40 | // for (j = i; j < i + 8; j++) { 41 | // pos = strchr(Base64, j); 42 | // if ((pos == NULL) || (j == 0)) 43 | // idx = 99; 44 | // else 45 | // idx = pos - Base64; 46 | // if (idx == 99) 47 | // printf(" %2d, ", idx); 48 | // else 49 | // printf(" %2d/*%c*/,", idx, j); 50 | // } 51 | // printf("\n "); 52 | // } 53 | // } 54 | 99, 99, 99, 99, 99, 99, 99, 99, 55 | 99, 99, 99, 99, 99, 99, 99, 99, 56 | 99, 99, 99, 99, 99, 99, 99, 99, 57 | 99, 99, 99, 99, 99, 99, 99, 99, 58 | 99, 99, 99, 99, 99, 99, 99, 99, 59 | 99, 99, 99, 62/*+*/, 99, 99, 99, 63/*/ */, 60 | 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, 61 | 60/*8*/, 61/*9*/, 99, 99, 99, 99, 99, 99, 62 | 99, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, 63 | 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, 64 | 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, 65 | 23/*X*/, 24/*Y*/, 25/*Z*/, 99, 99, 99, 99, 99, 66 | 99, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, 67 | 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, 68 | 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, 69 | 49/*x*/, 50/*y*/, 51/*z*/, 99, 99, 99, 99, 99, 70 | 99, 99, 99, 99, 99, 99, 99, 99, 71 | 99, 99, 99, 99, 99, 99, 99, 99, 72 | 99, 99, 99, 99, 99, 99, 99, 99, 73 | 99, 99, 99, 99, 99, 99, 99, 99, 74 | 99, 99, 99, 99, 99, 99, 99, 99, 75 | 99, 99, 99, 99, 99, 99, 99, 99, 76 | 99, 99, 99, 99, 99, 99, 99, 99, 77 | 99, 99, 99, 99, 99, 99, 99, 99, 78 | 99, 99, 99, 99, 99, 99, 99, 99, 79 | 99, 99, 99, 99, 99, 99, 99, 99, 80 | 99, 99, 99, 99, 99, 99, 99, 99, 81 | 99, 99, 99, 99, 99, 99, 99, 99, 82 | 99, 99, 99, 99, 99, 99, 99, 99, 83 | 99, 99, 99, 99, 99, 99, 99, 99, 84 | 99, 99, 99, 99, 99, 99, 99, 99, 85 | 99, 99, 99, 99, 99, 99, 99, 99 86 | }; 87 | 88 | static const char kWebSafeBase64DecodeChars[] = { 89 | // This array was generated by the following code: 90 | // #include 91 | // #include 92 | // #include 93 | // main() 94 | // { 95 | // static const char Base64[] = 96 | // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; 97 | // char *pos; 98 | // int idx, i, j; 99 | // printf(" "); 100 | // for (i = 0; i < 255; i += 8) { 101 | // for (j = i; j < i + 8; j++) { 102 | // pos = strchr(Base64, j); 103 | // if ((pos == NULL) || (j == 0)) 104 | // idx = 99; 105 | // else 106 | // idx = pos - Base64; 107 | // if (idx == 99) 108 | // printf(" %2d, ", idx); 109 | // else 110 | // printf(" %2d/*%c*/,", idx, j); 111 | // } 112 | // printf("\n "); 113 | // } 114 | // } 115 | 99, 99, 99, 99, 99, 99, 99, 99, 116 | 99, 99, 99, 99, 99, 99, 99, 99, 117 | 99, 99, 99, 99, 99, 99, 99, 99, 118 | 99, 99, 99, 99, 99, 99, 99, 99, 119 | 99, 99, 99, 99, 99, 99, 99, 99, 120 | 99, 99, 99, 99, 99, 62/*-*/, 99, 99, 121 | 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, 122 | 60/*8*/, 61/*9*/, 99, 99, 99, 99, 99, 99, 123 | 99, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, 124 | 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, 125 | 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, 126 | 23/*X*/, 24/*Y*/, 25/*Z*/, 99, 99, 99, 99, 63/*_*/, 127 | 99, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, 128 | 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, 129 | 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, 130 | 49/*x*/, 50/*y*/, 51/*z*/, 99, 99, 99, 99, 99, 131 | 99, 99, 99, 99, 99, 99, 99, 99, 132 | 99, 99, 99, 99, 99, 99, 99, 99, 133 | 99, 99, 99, 99, 99, 99, 99, 99, 134 | 99, 99, 99, 99, 99, 99, 99, 99, 135 | 99, 99, 99, 99, 99, 99, 99, 99, 136 | 99, 99, 99, 99, 99, 99, 99, 99, 137 | 99, 99, 99, 99, 99, 99, 99, 99, 138 | 99, 99, 99, 99, 99, 99, 99, 99, 139 | 99, 99, 99, 99, 99, 99, 99, 99, 140 | 99, 99, 99, 99, 99, 99, 99, 99, 141 | 99, 99, 99, 99, 99, 99, 99, 99, 142 | 99, 99, 99, 99, 99, 99, 99, 99, 143 | 99, 99, 99, 99, 99, 99, 99, 99, 144 | 99, 99, 99, 99, 99, 99, 99, 99, 145 | 99, 99, 99, 99, 99, 99, 99, 99, 146 | 99, 99, 99, 99, 99, 99, 99, 99 147 | }; 148 | 149 | 150 | // Tests a character to see if it's a whitespace character. 151 | // 152 | // Returns: 153 | // YES if the character is a whitespace character. 154 | // NO if the character is not a whitespace character. 155 | // 156 | GTM_INLINE BOOL IsSpace(unsigned char c) { 157 | // we use our own mapping here because we don't want anything w/ locale 158 | // support. 159 | static BOOL kSpaces[256] = { 160 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // 0-9 161 | 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 10-19 162 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20-29 163 | 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 30-39 164 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40-49 165 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 50-59 166 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60-69 167 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 70-79 168 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80-89 169 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90-99 170 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 100-109 171 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 110-119 172 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 120-129 173 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 130-139 174 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 140-149 175 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 150-159 176 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160-169 177 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 170-179 178 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 180-189 179 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 190-199 180 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 200-209 181 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 210-219 182 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 220-229 183 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 230-239 184 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240-249 185 | 0, 0, 0, 0, 0, 1, // 250-255 186 | }; 187 | return kSpaces[c]; 188 | } 189 | 190 | // Calculate how long the data will be once it's base64 encoded. 191 | // 192 | // Returns: 193 | // The guessed encoded length for a source length 194 | // 195 | GTM_INLINE NSUInteger CalcEncodedLength(NSUInteger srcLen, BOOL padded) { 196 | NSUInteger intermediate_result = 8 * srcLen + 5; 197 | NSUInteger len = intermediate_result / 6; 198 | if (padded) { 199 | len = ((len + 3) / 4) * 4; 200 | } 201 | return len; 202 | } 203 | 204 | // Tries to calculate how long the data will be once it's base64 decoded. 205 | // Unlike the above, this is always an upperbound, since the source data 206 | // could have spaces and might end with the padding characters on them. 207 | // 208 | // Returns: 209 | // The guessed decoded length for a source length 210 | // 211 | GTM_INLINE NSUInteger GuessDecodedLength(NSUInteger srcLen) { 212 | return (srcLen + 3) / 4 * 3; 213 | } 214 | 215 | 216 | @interface GTMBase64 (PrivateMethods) 217 | 218 | +(NSData *)baseEncode:(const void *)bytes 219 | length:(NSUInteger)length 220 | charset:(const char *)charset 221 | padded:(BOOL)padded; 222 | 223 | +(NSData *)baseDecode:(const void *)bytes 224 | length:(NSUInteger)length 225 | charset:(const char*)charset 226 | requirePadding:(BOOL)requirePadding; 227 | 228 | +(NSUInteger)baseEncode:(const char *)srcBytes 229 | srcLen:(NSUInteger)srcLen 230 | destBytes:(char *)destBytes 231 | destLen:(NSUInteger)destLen 232 | charset:(const char *)charset 233 | padded:(BOOL)padded; 234 | 235 | +(NSUInteger)baseDecode:(const char *)srcBytes 236 | srcLen:(NSUInteger)srcLen 237 | destBytes:(char *)destBytes 238 | destLen:(NSUInteger)destLen 239 | charset:(const char *)charset 240 | requirePadding:(BOOL)requirePadding; 241 | 242 | 243 | @end 244 | 245 | 246 | @implementation GTMBase64 247 | 248 | // 249 | // Standard Base64 (RFC) handling 250 | // 251 | 252 | +(NSData *)encodeData:(NSData *)data { 253 | return [self baseEncode:[data bytes] 254 | length:[data length] 255 | charset:kBase64EncodeChars 256 | padded:YES]; 257 | } 258 | 259 | +(NSData *)decodeData:(NSData *)data { 260 | return [self baseDecode:[data bytes] 261 | length:[data length] 262 | charset:kBase64DecodeChars 263 | requirePadding:YES]; 264 | } 265 | 266 | +(NSData *)encodeBytes:(const void *)bytes length:(NSUInteger)length { 267 | return [self baseEncode:bytes 268 | length:length 269 | charset:kBase64EncodeChars 270 | padded:YES]; 271 | } 272 | 273 | +(NSData *)decodeBytes:(const void *)bytes length:(NSUInteger)length { 274 | return [self baseDecode:bytes 275 | length:length 276 | charset:kBase64DecodeChars 277 | requirePadding:YES]; 278 | } 279 | 280 | +(NSString *)stringByEncodingData:(NSData *)data { 281 | NSString *result = nil; 282 | NSData *converted = [self baseEncode:[data bytes] 283 | length:[data length] 284 | charset:kBase64EncodeChars 285 | padded:YES]; 286 | if (converted) { 287 | result = [[[NSString alloc] initWithData:converted 288 | encoding:NSASCIIStringEncoding] autorelease]; 289 | } 290 | return result; 291 | } 292 | 293 | +(NSString *)stringByEncodingBytes:(const void *)bytes length:(NSUInteger)length { 294 | NSString *result = nil; 295 | NSData *converted = [self baseEncode:bytes 296 | length:length 297 | charset:kBase64EncodeChars 298 | padded:YES]; 299 | if (converted) { 300 | result = [[[NSString alloc] initWithData:converted 301 | encoding:NSASCIIStringEncoding] autorelease]; 302 | } 303 | return result; 304 | } 305 | 306 | +(NSData *)decodeString:(NSString *)string { 307 | NSData *result = nil; 308 | NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding]; 309 | if (data) { 310 | result = [self baseDecode:[data bytes] 311 | length:[data length] 312 | charset:kBase64DecodeChars 313 | requirePadding:YES]; 314 | } 315 | return result; 316 | } 317 | 318 | // 319 | // Modified Base64 encoding so the results can go onto urls. 320 | // 321 | // The changes are in the characters generated and also the result isn't 322 | // padded to a multiple of 4. 323 | // Must use the matching call to encode/decode, won't interop with the 324 | // RFC versions. 325 | // 326 | 327 | +(NSData *)webSafeEncodeData:(NSData *)data 328 | padded:(BOOL)padded { 329 | return [self baseEncode:[data bytes] 330 | length:[data length] 331 | charset:kWebSafeBase64EncodeChars 332 | padded:padded]; 333 | } 334 | 335 | +(NSData *)webSafeDecodeData:(NSData *)data { 336 | return [self baseDecode:[data bytes] 337 | length:[data length] 338 | charset:kWebSafeBase64DecodeChars 339 | requirePadding:NO]; 340 | } 341 | 342 | +(NSData *)webSafeEncodeBytes:(const void *)bytes 343 | length:(NSUInteger)length 344 | padded:(BOOL)padded { 345 | return [self baseEncode:bytes 346 | length:length 347 | charset:kWebSafeBase64EncodeChars 348 | padded:padded]; 349 | } 350 | 351 | +(NSData *)webSafeDecodeBytes:(const void *)bytes length:(NSUInteger)length { 352 | return [self baseDecode:bytes 353 | length:length 354 | charset:kWebSafeBase64DecodeChars 355 | requirePadding:NO]; 356 | } 357 | 358 | +(NSString *)stringByWebSafeEncodingData:(NSData *)data 359 | padded:(BOOL)padded { 360 | NSString *result = nil; 361 | NSData *converted = [self baseEncode:[data bytes] 362 | length:[data length] 363 | charset:kWebSafeBase64EncodeChars 364 | padded:padded]; 365 | if (converted) { 366 | result = [[[NSString alloc] initWithData:converted 367 | encoding:NSASCIIStringEncoding] autorelease]; 368 | } 369 | return result; 370 | } 371 | 372 | +(NSString *)stringByWebSafeEncodingBytes:(const void *)bytes 373 | length:(NSUInteger)length 374 | padded:(BOOL)padded { 375 | NSString *result = nil; 376 | NSData *converted = [self baseEncode:bytes 377 | length:length 378 | charset:kWebSafeBase64EncodeChars 379 | padded:padded]; 380 | if (converted) { 381 | result = [[[NSString alloc] initWithData:converted 382 | encoding:NSASCIIStringEncoding] autorelease]; 383 | } 384 | return result; 385 | } 386 | 387 | +(NSData *)webSafeDecodeString:(NSString *)string { 388 | NSData *result = nil; 389 | NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding]; 390 | if (data) { 391 | result = [self baseDecode:[data bytes] 392 | length:[data length] 393 | charset:kWebSafeBase64DecodeChars 394 | requirePadding:NO]; 395 | } 396 | return result; 397 | } 398 | 399 | #pragma mark - base64 400 | + (NSString *) md5_base64: (NSString *) inPutText 401 | { 402 | const char *cStr = [inPutText UTF8String]; 403 | unsigned char digest[16]; 404 | CC_MD5( cStr, strlen(cStr), digest ); 405 | 406 | NSData * base64 = [[NSData alloc]initWithBytes:digest length:16]; 407 | base64 = [GTMBase64 encodeData:base64]; 408 | 409 | NSString * output = [[NSString alloc] initWithData:base64 encoding:NSUTF8StringEncoding]; 410 | return output; 411 | } 412 | + (NSString*)encodeBase64String:(NSString * )input { 413 | NSData *data = [input dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; 414 | data = [GTMBase64 encodeData:data]; 415 | NSString *base64String = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; 416 | return base64String; 417 | } 418 | 419 | + (NSString*)decodeBase64String:(NSString * )input { 420 | NSData *data = [input dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; 421 | data = [GTMBase64 decodeData:data]; 422 | NSString *base64String = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; 423 | return base64String; 424 | } 425 | 426 | + (NSString*)encodeBase64Data:(NSData *)data { 427 | data = [GTMBase64 encodeData:data]; 428 | NSString *base64String = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; 429 | return base64String; 430 | } 431 | 432 | + (NSString*)decodeBase64Data:(NSData *)data { 433 | data = [GTMBase64 decodeData:data]; 434 | NSString *base64String = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; 435 | return base64String; 436 | } 437 | 438 | @end 439 | 440 | @implementation GTMBase64 (PrivateMethods) 441 | 442 | // 443 | // baseEncode:length:charset:padded: 444 | // 445 | // Does the common lifting of creating the dest NSData. it creates & sizes the 446 | // data for the results. |charset| is the characters to use for the encoding 447 | // of the data. |padding| controls if the encoded data should be padded to a 448 | // multiple of 4. 449 | // 450 | // Returns: 451 | // an autorelease NSData with the encoded data, nil if any error. 452 | // 453 | +(NSData *)baseEncode:(const void *)bytes 454 | length:(NSUInteger)length 455 | charset:(const char *)charset 456 | padded:(BOOL)padded { 457 | // how big could it be? 458 | NSUInteger maxLength = CalcEncodedLength(length, padded); 459 | // make space 460 | NSMutableData *result = [NSMutableData data]; 461 | [result setLength:maxLength]; 462 | // do it 463 | NSUInteger finalLength = [self baseEncode:bytes 464 | srcLen:length 465 | destBytes:[result mutableBytes] 466 | destLen:[result length] 467 | charset:charset 468 | padded:padded]; 469 | if (finalLength) { 470 | _GTMDevAssert(finalLength == maxLength, @"how did we calc the length wrong?"); 471 | } else { 472 | // shouldn't happen, this means we ran out of space 473 | result = nil; 474 | } 475 | return result; 476 | } 477 | 478 | // 479 | // baseDecode:length:charset:requirePadding: 480 | // 481 | // Does the common lifting of creating the dest NSData. it creates & sizes the 482 | // data for the results. |charset| is the characters to use for the decoding 483 | // of the data. 484 | // 485 | // Returns: 486 | // an autorelease NSData with the decoded data, nil if any error. 487 | // 488 | // 489 | +(NSData *)baseDecode:(const void *)bytes 490 | length:(NSUInteger)length 491 | charset:(const char *)charset 492 | requirePadding:(BOOL)requirePadding { 493 | // could try to calculate what it will end up as 494 | NSUInteger maxLength = GuessDecodedLength(length); 495 | // make space 496 | NSMutableData *result = [NSMutableData data]; 497 | [result setLength:maxLength]; 498 | // do it 499 | NSUInteger finalLength = [self baseDecode:bytes 500 | srcLen:length 501 | destBytes:[result mutableBytes] 502 | destLen:[result length] 503 | charset:charset 504 | requirePadding:requirePadding]; 505 | if (finalLength) { 506 | if (finalLength != maxLength) { 507 | // resize down to how big it was 508 | [result setLength:finalLength]; 509 | } 510 | } else { 511 | // either an error in the args, or we ran out of space 512 | result = nil; 513 | } 514 | return result; 515 | } 516 | 517 | // 518 | // baseEncode:srcLen:destBytes:destLen:charset:padded: 519 | // 520 | // Encodes the buffer into the larger. returns the length of the encoded 521 | // data, or zero for an error. 522 | // |charset| is the characters to use for the encoding 523 | // |padded| tells if the result should be padded to a multiple of 4. 524 | // 525 | // Returns: 526 | // the length of the encoded data. zero if any error. 527 | // 528 | +(NSUInteger)baseEncode:(const char *)srcBytes 529 | srcLen:(NSUInteger)srcLen 530 | destBytes:(char *)destBytes 531 | destLen:(NSUInteger)destLen 532 | charset:(const char *)charset 533 | padded:(BOOL)padded { 534 | if (!srcLen || !destLen || !srcBytes || !destBytes) { 535 | return 0; 536 | } 537 | 538 | char *curDest = destBytes; 539 | const unsigned char *curSrc = (const unsigned char *)(srcBytes); 540 | 541 | // Three bytes of data encodes to four characters of cyphertext. 542 | // So we can pump through three-byte chunks atomically. 543 | while (srcLen > 2) { 544 | // space? 545 | _GTMDevAssert(destLen >= 4, @"our calc for encoded length was wrong"); 546 | curDest[0] = charset[curSrc[0] >> 2]; 547 | curDest[1] = charset[((curSrc[0] & 0x03) << 4) + (curSrc[1] >> 4)]; 548 | curDest[2] = charset[((curSrc[1] & 0x0f) << 2) + (curSrc[2] >> 6)]; 549 | curDest[3] = charset[curSrc[2] & 0x3f]; 550 | 551 | curDest += 4; 552 | curSrc += 3; 553 | srcLen -= 3; 554 | destLen -= 4; 555 | } 556 | 557 | // now deal with the tail (<=2 bytes) 558 | switch (srcLen) { 559 | case 0: 560 | // Nothing left; nothing more to do. 561 | break; 562 | case 1: 563 | // One byte left: this encodes to two characters, and (optionally) 564 | // two pad characters to round out the four-character cypherblock. 565 | _GTMDevAssert(destLen >= 2, @"our calc for encoded length was wrong"); 566 | curDest[0] = charset[curSrc[0] >> 2]; 567 | curDest[1] = charset[(curSrc[0] & 0x03) << 4]; 568 | curDest += 2; 569 | destLen -= 2; 570 | if (padded) { 571 | _GTMDevAssert(destLen >= 2, @"our calc for encoded length was wrong"); 572 | curDest[0] = kBase64PaddingChar; 573 | curDest[1] = kBase64PaddingChar; 574 | curDest += 2; 575 | } 576 | break; 577 | case 2: 578 | // Two bytes left: this encodes to three characters, and (optionally) 579 | // one pad character to round out the four-character cypherblock. 580 | _GTMDevAssert(destLen >= 3, @"our calc for encoded length was wrong"); 581 | curDest[0] = charset[curSrc[0] >> 2]; 582 | curDest[1] = charset[((curSrc[0] & 0x03) << 4) + (curSrc[1] >> 4)]; 583 | curDest[2] = charset[(curSrc[1] & 0x0f) << 2]; 584 | curDest += 3; 585 | destLen -= 3; 586 | if (padded) { 587 | _GTMDevAssert(destLen >= 1, @"our calc for encoded length was wrong"); 588 | curDest[0] = kBase64PaddingChar; 589 | curDest += 1; 590 | } 591 | break; 592 | } 593 | // return the length 594 | return (curDest - destBytes); 595 | } 596 | 597 | // 598 | // baseDecode:srcLen:destBytes:destLen:charset:requirePadding: 599 | // 600 | // Decodes the buffer into the larger. returns the length of the decoded 601 | // data, or zero for an error. 602 | // |charset| is the character decoding buffer to use 603 | // 604 | // Returns: 605 | // the length of the encoded data. zero if any error. 606 | // 607 | +(NSUInteger)baseDecode:(const char *)srcBytes 608 | srcLen:(NSUInteger)srcLen 609 | destBytes:(char *)destBytes 610 | destLen:(NSUInteger)destLen 611 | charset:(const char *)charset 612 | requirePadding:(BOOL)requirePadding { 613 | if (!srcLen || !destLen || !srcBytes || !destBytes) { 614 | return 0; 615 | } 616 | 617 | int decode; 618 | NSUInteger destIndex = 0; 619 | int state = 0; 620 | char ch = 0; 621 | while (srcLen-- && (ch = *srcBytes++) != 0) { 622 | if (IsSpace(ch)) // Skip whitespace 623 | continue; 624 | 625 | if (ch == kBase64PaddingChar) 626 | break; 627 | 628 | decode = charset[(unsigned int)ch]; 629 | if (decode == kBase64InvalidChar) 630 | return 0; 631 | 632 | // Four cyphertext characters decode to three bytes. 633 | // Therefore we can be in one of four states. 634 | switch (state) { 635 | case 0: 636 | // We're at the beginning of a four-character cyphertext block. 637 | // This sets the high six bits of the first byte of the 638 | // plaintext block. 639 | _GTMDevAssert(destIndex < destLen, @"our calc for decoded length was wrong"); 640 | destBytes[destIndex] = decode << 2; 641 | state = 1; 642 | break; 643 | case 1: 644 | // We're one character into a four-character cyphertext block. 645 | // This sets the low two bits of the first plaintext byte, 646 | // and the high four bits of the second plaintext byte. 647 | _GTMDevAssert((destIndex+1) < destLen, @"our calc for decoded length was wrong"); 648 | destBytes[destIndex] |= decode >> 4; 649 | destBytes[destIndex+1] = (decode & 0x0f) << 4; 650 | destIndex++; 651 | state = 2; 652 | break; 653 | case 2: 654 | // We're two characters into a four-character cyphertext block. 655 | // This sets the low four bits of the second plaintext 656 | // byte, and the high two bits of the third plaintext byte. 657 | // However, if this is the end of data, and those two 658 | // bits are zero, it could be that those two bits are 659 | // leftovers from the encoding of data that had a length 660 | // of two mod three. 661 | _GTMDevAssert((destIndex+1) < destLen, @"our calc for decoded length was wrong"); 662 | destBytes[destIndex] |= decode >> 2; 663 | destBytes[destIndex+1] = (decode & 0x03) << 6; 664 | destIndex++; 665 | state = 3; 666 | break; 667 | case 3: 668 | // We're at the last character of a four-character cyphertext block. 669 | // This sets the low six bits of the third plaintext byte. 670 | _GTMDevAssert(destIndex < destLen, @"our calc for decoded length was wrong"); 671 | destBytes[destIndex] |= decode; 672 | destIndex++; 673 | state = 0; 674 | break; 675 | } 676 | } 677 | 678 | // We are done decoding Base-64 chars. Let's see if we ended 679 | // on a byte boundary, and/or with erroneous trailing characters. 680 | if (ch == kBase64PaddingChar) { // We got a pad char 681 | if ((state == 0) || (state == 1)) { 682 | return 0; // Invalid '=' in first or second position 683 | } 684 | if (srcLen == 0) { 685 | if (state == 2) { // We run out of input but we still need another '=' 686 | return 0; 687 | } 688 | // Otherwise, we are in state 3 and only need this '=' 689 | } else { 690 | if (state == 2) { // need another '=' 691 | while ((ch = *srcBytes++) && (srcLen-- > 0)) { 692 | if (!IsSpace(ch)) 693 | break; 694 | } 695 | if (ch != kBase64PaddingChar) { 696 | return 0; 697 | } 698 | } 699 | // state = 1 or 2, check if all remain padding is space 700 | while ((ch = *srcBytes++) && (srcLen-- > 0)) { 701 | if (!IsSpace(ch)) { 702 | return 0; 703 | } 704 | } 705 | } 706 | } else { 707 | // We ended by seeing the end of the string. 708 | 709 | if (requirePadding) { 710 | // If we require padding, then anything but state 0 is an error. 711 | if (state != 0) { 712 | return 0; 713 | } 714 | } else { 715 | // Make sure we have no partial bytes lying around. Note that we do not 716 | // require trailing '=', so states 2 and 3 are okay too. 717 | if (state == 1) { 718 | return 0; 719 | } 720 | } 721 | } 722 | 723 | // If then next piece of output was valid and got written to it means we got a 724 | // very carefully crafted input that appeared valid but contains some trailing 725 | // bits past the real length, so just toss the thing. 726 | if ((destIndex < destLen) && 727 | (destBytes[destIndex] != 0)) { 728 | return 0; 729 | } 730 | 731 | return destIndex; 732 | } 733 | 734 | 735 | @end 736 | --------------------------------------------------------------------------------