├── .gitignore ├── Base64.h ├── Base64.m ├── CryptoUtil.h ├── CryptoUtil.m ├── KeychainUtil.h ├── KeychainUtil.m ├── RSADemo.xcodeproj └── project.pbxproj └── RSADemo ├── Default-568h@2x.png ├── Default.png ├── Default@2x.png ├── GLAppDelegate.h ├── GLAppDelegate.m ├── GLViewController.h ├── GLViewController.m ├── RSADemo-Info.plist ├── RSADemo-Prefix.pch ├── en.lproj ├── InfoPlist.strings └── MainStoryboard.storyboard ├── key.txt └── main.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | build/* 3 | *.pbxuser 4 | !default.pbxuser 5 | *.mode1v3 6 | !default.mode1v3 7 | *.mode2v3 8 | !default.mode2v3 9 | *.perspectivev3 10 | !default.perspectivev3 11 | *.xcworkspace 12 | !default.xcworkspace 13 | xcuserdata 14 | profile 15 | *.moved-aside 16 | DerivedData -------------------------------------------------------------------------------- /Base64.h: -------------------------------------------------------------------------------- 1 | // 2 | // Base64.h 3 | // 4 | // Version 1.1 5 | // 6 | // Created by Nick Lockwood on 12/01/2012. 7 | // Copyright (C) 2012 Charcoal Design 8 | // 9 | // Distributed under the permissive zlib License 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/nicklockwood/Base64 13 | // 14 | // This software is provided 'as-is', without any express or implied 15 | // warranty. In no event will the authors be held liable for any damages 16 | // arising from the use of this software. 17 | // 18 | // Permission is granted to anyone to use this software for any purpose, 19 | // including commercial applications, and to alter it and redistribute it 20 | // freely, subject to the following restrictions: 21 | // 22 | // 1. The origin of this software must not be misrepresented; you must not 23 | // claim that you wrote the original software. If you use this software 24 | // in a product, an acknowledgment in the product documentation would be 25 | // appreciated but is not required. 26 | // 27 | // 2. Altered source versions must be plainly marked as such, and must not be 28 | // misrepresented as being the original software. 29 | // 30 | // 3. This notice may not be removed or altered from any source distribution. 31 | // 32 | 33 | #import 34 | 35 | 36 | @interface NSData (Base64) 37 | 38 | + (NSData *)dataWithBase64EncodedString:(NSString *)string; 39 | - (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth; 40 | - (NSString *)base64EncodedString; 41 | 42 | @end 43 | 44 | 45 | @interface NSString (Base64) 46 | 47 | + (NSString *)stringWithBase64EncodedString:(NSString *)string; 48 | - (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth; 49 | - (NSString *)base64EncodedString; 50 | - (NSString *)base64DecodedString; 51 | - (NSData *)base64DecodedData; 52 | 53 | @end -------------------------------------------------------------------------------- /Base64.m: -------------------------------------------------------------------------------- 1 | // 2 | // Base64.m 3 | // 4 | // Version 1.1 5 | // 6 | // Created by Nick Lockwood on 12/01/2012. 7 | // Copyright (C) 2012 Charcoal Design 8 | // 9 | // Distributed under the permissive zlib License 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/nicklockwood/Base64 13 | // 14 | // This software is provided 'as-is', without any express or implied 15 | // warranty. In no event will the authors be held liable for any damages 16 | // arising from the use of this software. 17 | // 18 | // Permission is granted to anyone to use this software for any purpose, 19 | // including commercial applications, and to alter it and redistribute it 20 | // freely, subject to the following restrictions: 21 | // 22 | // 1. The origin of this software must not be misrepresented; you must not 23 | // claim that you wrote the original software. If you use this software 24 | // in a product, an acknowledgment in the product documentation would be 25 | // appreciated but is not required. 26 | // 27 | // 2. Altered source versions must be plainly marked as such, and must not be 28 | // misrepresented as being the original software. 29 | // 30 | // 3. This notice may not be removed or altered from any source distribution. 31 | // 32 | 33 | #import "Base64.h" 34 | 35 | 36 | #import 37 | #if !__has_feature(objc_arc) 38 | #error This library requires automatic reference counting 39 | #endif 40 | 41 | 42 | @implementation NSData (Base64) 43 | 44 | + (NSData *)dataWithBase64EncodedString:(NSString *)string 45 | { 46 | const char lookup[] = 47 | { 48 | 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 49 | 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 50 | 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 62, 99, 99, 99, 63, 51 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 99, 99, 99, 99, 99, 99, 52 | 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 53 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 99, 99, 99, 99, 99, 54 | 99, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 55 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 99, 99, 99, 99, 99 56 | }; 57 | 58 | NSData *inputData = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; 59 | long long inputLength = [inputData length]; 60 | const unsigned char *inputBytes = [inputData bytes]; 61 | 62 | long long maxOutputLength = (inputLength / 4 + 1) * 3; 63 | NSMutableData *outputData = [NSMutableData dataWithLength:maxOutputLength]; 64 | unsigned char *outputBytes = (unsigned char *)[outputData mutableBytes]; 65 | 66 | int accumulator = 0; 67 | long long outputLength = 0; 68 | unsigned char accumulated[] = {0, 0, 0, 0}; 69 | for (long long i = 0; i < inputLength; i++) 70 | { 71 | unsigned char decoded = lookup[inputBytes[i] & 0x7F]; 72 | if (decoded != 99) 73 | { 74 | accumulated[accumulator] = decoded; 75 | if (accumulator == 3) 76 | { 77 | outputBytes[outputLength++] = (accumulated[0] << 2) | (accumulated[1] >> 4); 78 | outputBytes[outputLength++] = (accumulated[1] << 4) | (accumulated[2] >> 2); 79 | outputBytes[outputLength++] = (accumulated[2] << 6) | accumulated[3]; 80 | } 81 | accumulator = (accumulator + 1) % 4; 82 | } 83 | } 84 | 85 | //handle left-over data 86 | if (accumulator > 0) outputBytes[outputLength] = (accumulated[0] << 2) | (accumulated[1] >> 4); 87 | if (accumulator > 1) outputBytes[++outputLength] = (accumulated[1] << 4) | (accumulated[2] >> 2); 88 | if (accumulator > 2) outputLength++; 89 | 90 | //truncate data to match actual output length 91 | outputData.length = outputLength; 92 | return outputLength? outputData: nil; 93 | } 94 | 95 | - (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth 96 | { 97 | //ensure wrapWidth is a multiple of 4 98 | wrapWidth = (wrapWidth / 4) * 4; 99 | 100 | const char lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 101 | 102 | long long inputLength = [self length]; 103 | const unsigned char *inputBytes = [self bytes]; 104 | 105 | long long maxOutputLength = (inputLength / 3 + 1) * 4; 106 | maxOutputLength += wrapWidth? (maxOutputLength / wrapWidth) * 2: 0; 107 | unsigned char *outputBytes = (unsigned char *)malloc(maxOutputLength); 108 | 109 | long long i; 110 | long long outputLength = 0; 111 | for (i = 0; i < inputLength - 2; i += 3) 112 | { 113 | outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2]; 114 | outputBytes[outputLength++] = lookup[((inputBytes[i] & 0x03) << 4) | ((inputBytes[i + 1] & 0xF0) >> 4)]; 115 | outputBytes[outputLength++] = lookup[((inputBytes[i + 1] & 0x0F) << 2) | ((inputBytes[i + 2] & 0xC0) >> 6)]; 116 | outputBytes[outputLength++] = lookup[inputBytes[i + 2] & 0x3F]; 117 | 118 | //add line break 119 | if (wrapWidth && (outputLength + 2) % (wrapWidth + 2) == 0) 120 | { 121 | outputBytes[outputLength++] = '\r'; 122 | outputBytes[outputLength++] = '\n'; 123 | } 124 | } 125 | 126 | //handle left-over data 127 | if (i == inputLength - 2) 128 | { 129 | // = terminator 130 | outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2]; 131 | outputBytes[outputLength++] = lookup[((inputBytes[i] & 0x03) << 4) | ((inputBytes[i + 1] & 0xF0) >> 4)]; 132 | outputBytes[outputLength++] = lookup[(inputBytes[i + 1] & 0x0F) << 2]; 133 | outputBytes[outputLength++] = '='; 134 | } 135 | else if (i == inputLength - 1) 136 | { 137 | // == terminator 138 | outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2]; 139 | outputBytes[outputLength++] = lookup[(inputBytes[i] & 0x03) << 4]; 140 | outputBytes[outputLength++] = '='; 141 | outputBytes[outputLength++] = '='; 142 | } 143 | 144 | if (outputLength >= 4) 145 | { 146 | //truncate data to match actual output length 147 | outputBytes = realloc(outputBytes, outputLength); 148 | return [[NSString alloc] initWithBytesNoCopy:outputBytes 149 | length:outputLength 150 | encoding:NSASCIIStringEncoding 151 | freeWhenDone:YES]; 152 | } 153 | else if (outputBytes) 154 | { 155 | free(outputBytes); 156 | } 157 | return nil; 158 | } 159 | 160 | - (NSString *)base64EncodedString 161 | { 162 | return [self base64EncodedStringWithWrapWidth:0]; 163 | } 164 | 165 | @end 166 | 167 | 168 | @implementation NSString (Base64) 169 | 170 | + (NSString *)stringWithBase64EncodedString:(NSString *)string 171 | { 172 | NSData *data = [NSData dataWithBase64EncodedString:string]; 173 | if (data) 174 | { 175 | return [[self alloc] initWithData:data encoding:NSUTF8StringEncoding]; 176 | } 177 | return nil; 178 | } 179 | 180 | - (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth 181 | { 182 | NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; 183 | return [data base64EncodedStringWithWrapWidth:wrapWidth]; 184 | } 185 | 186 | - (NSString *)base64EncodedString 187 | { 188 | NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; 189 | return [data base64EncodedString]; 190 | } 191 | 192 | - (NSString *)base64DecodedString 193 | { 194 | return [NSString stringWithBase64EncodedString:self]; 195 | } 196 | 197 | - (NSData *)base64DecodedData 198 | { 199 | return [NSData dataWithBase64EncodedString:self]; 200 | } 201 | 202 | @end 203 | -------------------------------------------------------------------------------- /CryptoUtil.h: -------------------------------------------------------------------------------- 1 | // 2 | // CryptoUtil.h 3 | // iPhoneLib, 4 | // Helper Functions and Classes for Ordinary Application Development on iPhone 5 | // 6 | // Created by meinside on 10. 01. 16. 7 | // 8 | // last update: 10.07.21. 9 | // 10 | 11 | #pragma once 12 | #import 13 | 14 | //needs: Security.framework 15 | 16 | 17 | @interface CryptoUtil : NSObject { 18 | 19 | } 20 | 21 | + (BOOL)generateRSAKeyWithKeySizeInBits:(int)keyBits publicKeyTag:(NSString*)publicTag privateKeyTag:(NSString*)privateTag; 22 | 23 | /* 24 | * generate a public key in ASN.1 format from given modulus and exponent 25 | * 26 | * reference: https://devforums.apple.com/message/21365 27 | 28 | resulting byte array for example: 29 | 30 | //64 bytes 31 | { 32 | 0x30, //SEQUENCE tag: fixed element 33 | 0x47, //total length 34 | 35 | 0x02, //INTEGER tag: fixed element 36 | 0x40, //modulus length 37 | 38 | //modulus array starts here 39 | 0x78, 0x74, 0xE4, 0xD6, 0xF2, 0x99, 0xDD, 0x4C, 40 | 0x3B, 0xFB, 0xE1, 0x15, 0x92, 0x5A, 0x65, 0x40, 41 | 0xF3, 0x3F, 0xAB, 0xEF, 0x78, 0x4B, 0xF5, 0xCA, 42 | 0x97, 0x69, 0xAF, 0xB5, 0xFF, 0xC1, 0x0C, 0xE0, 43 | 0x39, 0x69, 0x68, 0x01, 0x32, 0x3A, 0xF6, 0xB8, 44 | 0xCA, 0xC4, 0xC6, 0x7F, 0xA2, 0x4A, 0x21, 0xB2, 45 | 0xC1, 0xE7, 0x8C, 0x7B, 0x3B, 0x64, 0x77, 0x0D, 46 | 0xF6, 0xE1, 0x93, 0x04, 0xC0, 0xB9, 0x5D, 0x83, 47 | //modulus array ends here 48 | 49 | 0x02, //INTEGER tag: fixed element 50 | 0x03, //exponent length 51 | 52 | 0x01, 0x00, 0x01, //exponent array 53 | }; 54 | //128 bytes 55 | { 56 | 0x30, //SEQUENCE tag: fixed element 57 | 0x81, 137, //total length (if length >= 0x80, it should be represented as 'positive' by appending 0x81 ahead of it) 58 | 59 | 0x02, //INTEGER tag: fixed element 60 | 0x81, 129, //modulus length (same as above) 61 | 62 | //modulus array starts here 63 | 0x00, //if first byte of modulus array >= 0x80, it should be represented as 'positive' by inserting 0x00 here) 64 | 0x9F, 0x8C, 0x20, 0x2F, 0xDB, 0xF9, 0xE8, 0x02, 65 | 0x59, 0x0B, 0xC6, 0x36, 0x56, 0x34, 0x7C, 0x4F, 66 | 0x4F, 0x03, 0x7C, 0x2F, 0x06, 0x0B, 0x3D, 0xC5, 67 | 0x53, 0x7C, 0x92, 0xD7, 0x2B, 0xF9, 0xCB, 0xBF, 68 | 0xB2, 0x17, 0xEE, 0x1C, 0xA1, 0x19, 0x0D, 0xC6, 69 | 0xC9, 0xF7, 0xF5, 0x85, 0xC7, 0xB3, 0xBE, 0x8D, 70 | 0x28, 0x2E, 0x8E, 0xC9, 0x80, 0x39, 0x60, 0x3B, 71 | 0x31, 0xFE, 0x1D, 0xAB, 0x28, 0x55, 0x01, 0x0B, 72 | 0x43, 0xD6, 0x55, 0xAE, 0xB1, 0x32, 0xB1, 0xE3, 73 | 0x1A, 0x8A, 0xD1, 0xC5, 0x4A, 0x17, 0x42, 0xC3, 74 | 0x07, 0x16, 0xF1, 0x00, 0xB1, 0x10, 0x00, 0x3C, 75 | 0x6D, 0x68, 0xCB, 0x95, 0x3E, 0x94, 0x12, 0xBD, 76 | 0x41, 0x03, 0xDA, 0x11, 0x1B, 0xE6, 0xD5, 0x0A, 77 | 0xF3, 0x6D, 0xA8, 0x0D, 0xAF, 0x69, 0xB4, 0xC6, 78 | 0x07, 0x0C, 0xC6, 0x62, 0x1C, 0x87, 0xB0, 0x05, 79 | 0x60, 0xFD, 0xDA, 0x6D, 0xD2, 0x43, 0x6F, 0x41, 80 | //modulus array ends here 81 | 82 | 0x02, //INTEGER tag: fixed element 83 | 0x03, //exponent length 84 | 85 | 0x01, 0x00, 0x01, //exponent array 86 | }; 87 | //256 bytes 88 | { 89 | 0x30, //SEQUENCE tag: fixed element 90 | 0x82, 0x01, 0x0A, //total length (if length >= 0x0100, it should be represented as 'positive' by appending 0x82 ahead of it) 91 | 92 | 0x02, //INTEGER tag: fixed element 93 | 0x82, 0x01, 0x01, //modulus length (same as above) 94 | 95 | //modulus array starts here 96 | 0x00, //if first byte of modulus array >= 0x80, it should be represented as 'positive' by inserting 0x00 here) 97 | 0xA3, 0xDD, 0x97, 0xC9, 0x15, 0x3B, 0xF9, 0xE4, 98 | 0xE7, 0x1C, 0xE2, 0x82, 0x10, 0xD8, 0x81, 0xD5, 99 | 0x7F, 0x04, 0x2B, 0xE4, 0xE3, 0x2B, 0xF3, 0x71, 100 | 0x67, 0x1F, 0xC9, 0xC8, 0x55, 0x43, 0xCF, 0x32, 101 | 0x66, 0x81, 0x45, 0xF1, 0xBC, 0xCE, 0x90, 0x54, 102 | 0x8D, 0xD9, 0x79, 0xD6, 0xB1, 0x45, 0xF7, 0xD5, 103 | 0xE5, 0xA3, 0x21, 0xAC, 0xCC, 0x14, 0xE0, 0x54, 104 | 0xB3, 0x89, 0xE5, 0x6D, 0xBD, 0x4F, 0x30, 0xDB, 105 | 0xE2, 0x0D, 0x6E, 0x97, 0x64, 0x33, 0x60, 0x63, 106 | 0x81, 0x7E, 0x36, 0xFC, 0x3A, 0x85, 0xD2, 0xAF, 107 | 0xD5, 0x3A, 0xA8, 0xE0, 0x36, 0x27, 0xFA, 0x4C, 108 | 0x75, 0xEF, 0xC0, 0xC2, 0x47, 0xA6, 0xC9, 0xD9, 109 | 0x8C, 0xCB, 0x92, 0x70, 0xEA, 0xF5, 0xB7, 0x68, 110 | 0x4B, 0xF5, 0x33, 0xC2, 0xDB, 0x8E, 0x2F, 0xDE, 111 | 0x91, 0xCC, 0x75, 0x30, 0x7C, 0x75, 0x08, 0x76, 112 | 0x4D, 0xE8, 0x98, 0x6F, 0x4A, 0x61, 0x66, 0x29, 113 | 0x19, 0x38, 0x8D, 0x32, 0xC2, 0x5E, 0x6E, 0xB8, 114 | 0xE1, 0xD0, 0xE8, 0xBD, 0x39, 0xEF, 0x02, 0x76, 115 | 0x48, 0x09, 0xE1, 0xCC, 0xD6, 0xA9, 0x4A, 0x33, 116 | 0xAF, 0xC2, 0x53, 0x7C, 0x16, 0xF1, 0xC5, 0x96, 117 | 0x1B, 0xB9, 0x9B, 0x23, 0x86, 0x78, 0xC3, 0x5D, 118 | 0x2A, 0x43, 0xFF, 0x57, 0x64, 0x55, 0x05, 0xC9, 119 | 0x2C, 0x21, 0xEF, 0x99, 0x74, 0x4F, 0x6B, 0x8D, 120 | 0x13, 0x65, 0xD3, 0x1B, 0x63, 0x24, 0xA7, 0x84, 121 | 0x0F, 0xCA, 0x59, 0x06, 0xE4, 0x37, 0x28, 0x1B, 122 | 0xA1, 0xA9, 0xC4, 0x25, 0x69, 0x03, 0x48, 0x8B, 123 | 0x2B, 0x78, 0x4E, 0x6A, 0xB3, 0xE1, 0x4A, 0xC4, 124 | 0x64, 0xF6, 0x2C, 0x2D, 0x5D, 0x0D, 0x6C, 0x46, 125 | 0xC8, 0xC3, 0x4D, 0x68, 0x03, 0x7A, 0x67, 0xFC, 126 | 0xBE, 0x0F, 0xBB, 0x3C, 0x06, 0x20, 0xE3, 0xC4, 127 | 0x90, 0x62, 0x9F, 0x22, 0xF2, 0xD4, 0x7F, 0xE3, 128 | 0x6A, 0x38, 0x7B, 0x6E, 0xF7, 0x58, 0x80, 0xAF, 129 | //modulus array ends here 130 | 131 | 0x02, //INTEGER tag: fixed element 132 | 0x03, //exponent length 133 | 134 | 0x01, 0x00, 0x01, //exponent array 135 | }; 136 | */ 137 | + (NSData*)generateRSAPublicKeyWithModulus:(NSData*)modulus exponent:(NSData*)exponent; 138 | 139 | + (BOOL)saveRSAPublicKey:(NSData*)publicKey appTag:(NSString*)appTag overwrite:(BOOL)overwrite; 140 | 141 | + (BOOL)updateRSAPublicKey:(NSData*)publicKey appTag:(NSString*)appTag; 142 | 143 | + (SecKeyRef)loadRSAPublicKeyRefWithAppTag:(NSString*)appTag; 144 | 145 | + (NSData*)encryptString:(NSString*)original RSAPublicKey:(SecKeyRef)publicKey padding:(SecPadding)padding; 146 | 147 | + (BOOL)deleteRSAPublicKeyWithAppTag:(NSString*)appTag; 148 | 149 | + (SecKeyRef)RSAPublicKeyRefFromBase64String:(NSString *)key withTag:(NSString *)tag; 150 | 151 | 152 | @end 153 | -------------------------------------------------------------------------------- /CryptoUtil.m: -------------------------------------------------------------------------------- 1 | // 2 | // CryptoUtil.m 3 | // iPhoneLib, 4 | // Helper Functions and Classes for Ordinary Application Development on iPhone 5 | // 6 | // Created by meinside on 10. 01. 16. 7 | // 8 | // last update: 12.07.16. 9 | // 10 | 11 | #import "CryptoUtil.h" 12 | 13 | #import "KeychainUtil.h" 14 | 15 | #import "Base64.h" 16 | 17 | @implementation CryptoUtil 18 | 19 | #pragma mark - 20 | #pragma mark RSA key-related functions 21 | 22 | + (BOOL)generateRSAKeyWithKeySizeInBits:(int)keyBits publicKeyTag:(NSString*)publicTag privateKeyTag:(NSString*)privateTag 23 | { 24 | NSMutableDictionary* privateKeyAttr = [[NSMutableDictionary alloc] init]; 25 | NSMutableDictionary* publicKeyAttr = [[NSMutableDictionary alloc] init]; 26 | NSMutableDictionary* keyPairAttr = [[NSMutableDictionary alloc] init]; 27 | 28 | NSData* publicTagData = [publicTag dataUsingEncoding:NSUTF8StringEncoding]; 29 | NSData* privateTagData = [privateTag dataUsingEncoding:NSUTF8StringEncoding]; 30 | 31 | SecKeyRef publicKey = NULL; 32 | SecKeyRef privateKey = NULL; 33 | 34 | [keyPairAttr setObject:(id)kSecAttrKeyTypeRSA 35 | forKey:(id)kSecAttrKeyType]; 36 | [keyPairAttr setObject:[NSNumber numberWithInt:keyBits] 37 | forKey:(id)kSecAttrKeySizeInBits]; 38 | 39 | [privateKeyAttr setObject:[NSNumber numberWithBool:YES] 40 | forKey:(id)kSecAttrIsPermanent]; 41 | [privateKeyAttr setObject:privateTagData 42 | forKey:(id)kSecAttrApplicationTag]; 43 | 44 | [publicKeyAttr setObject:[NSNumber numberWithBool:YES] 45 | forKey:(id)kSecAttrIsPermanent]; 46 | [publicKeyAttr setObject:publicTagData 47 | forKey:(id)kSecAttrApplicationTag]; 48 | 49 | [keyPairAttr setObject:privateKeyAttr 50 | forKey:(id)kSecPrivateKeyAttrs]; 51 | [keyPairAttr setObject:publicKeyAttr 52 | forKey:(id)kSecPublicKeyAttrs]; 53 | 54 | OSStatus status = SecKeyGeneratePair((CFDictionaryRef)keyPairAttr, &publicKey, &privateKey); 55 | 56 | NSLog(@"result = %@", [KeychainUtil fetchStatus:status]); 57 | 58 | if(privateKeyAttr) [privateKeyAttr release]; 59 | if(publicKeyAttr) [publicKeyAttr release]; 60 | if(keyPairAttr) [keyPairAttr release]; 61 | if(publicKey) CFRelease(publicKey); 62 | if(privateKey) CFRelease(privateKey); 63 | 64 | return status == noErr; 65 | } 66 | 67 | + (NSData*)generateRSAPublicKeyWithModulus:(NSData*)modulus exponent:(NSData*)exponent 68 | { 69 | const uint8_t DEFAULT_EXPONENT[] = {0x01, 0x00, 0x01,}; //default: 65537 70 | const uint8_t UNSIGNED_FLAG_FOR_BYTE = 0x81; 71 | const uint8_t UNSIGNED_FLAG_FOR_BYTE2 = 0x82; 72 | const uint8_t UNSIGNED_FLAG_FOR_BIGNUM = 0x00; 73 | const uint8_t SEQUENCE_TAG = 0x30; 74 | const uint8_t INTEGER_TAG = 0x02; 75 | 76 | uint8_t* modulusBytes = (uint8_t*)[modulus bytes]; 77 | uint8_t* exponentBytes = (uint8_t*)(exponent == nil ? DEFAULT_EXPONENT : [exponent bytes]); 78 | 79 | //(1) calculate lengths 80 | //- length of modulus 81 | int lenMod = [modulus length]; 82 | if(modulusBytes[0] >= 0x80) 83 | lenMod ++; //place for UNSIGNED_FLAG_FOR_BIGNUM 84 | int lenModHeader = 2 + (lenMod >= 0x80 ? 1 : 0) + (lenMod >= 0x0100 ? 1 : 0); 85 | //- length of exponent 86 | int lenExp = exponent == nil ? sizeof(DEFAULT_EXPONENT) : [exponent length]; 87 | int lenExpHeader = 2; 88 | //- length of body 89 | int lenBody = lenModHeader + lenMod + lenExpHeader + lenExp; 90 | //- length of total 91 | int lenTotal = 2 + (lenBody >= 0x80 ? 1 : 0) + (lenBody >= 0x0100 ? 1 : 0) + lenBody; 92 | 93 | int index = 0; 94 | uint8_t* byteBuffer = malloc(sizeof(uint8_t) * lenTotal); 95 | memset(byteBuffer, 0x00, sizeof(uint8_t) * lenTotal); 96 | 97 | //(2) fill up byte buffer 98 | //- sequence tag 99 | byteBuffer[index ++] = SEQUENCE_TAG; 100 | //- total length 101 | if(lenBody >= 0x80) 102 | byteBuffer[index ++] = (lenBody >= 0x0100 ? UNSIGNED_FLAG_FOR_BYTE2 : UNSIGNED_FLAG_FOR_BYTE); 103 | if(lenBody >= 0x0100) 104 | { 105 | byteBuffer[index ++] = (uint8_t)(lenBody / 0x0100); 106 | byteBuffer[index ++] = lenBody % 0x0100; 107 | } 108 | else 109 | byteBuffer[index ++] = lenBody; 110 | //- integer tag 111 | byteBuffer[index ++] = INTEGER_TAG; 112 | //- modulus length 113 | if(lenMod >= 0x80) 114 | byteBuffer[index ++] = (lenMod >= 0x0100 ? UNSIGNED_FLAG_FOR_BYTE2 : UNSIGNED_FLAG_FOR_BYTE); 115 | if(lenMod >= 0x0100) 116 | { 117 | byteBuffer[index ++] = (int)(lenMod / 0x0100); 118 | byteBuffer[index ++] = lenMod % 0x0100; 119 | } 120 | else 121 | byteBuffer[index ++] = lenMod; 122 | //- modulus value 123 | if(modulusBytes[0] >= 0x80) 124 | byteBuffer[index ++] = UNSIGNED_FLAG_FOR_BIGNUM; 125 | memcpy(byteBuffer + index, modulusBytes, sizeof(uint8_t) * [modulus length]); 126 | index += [modulus length]; 127 | //- exponent length 128 | byteBuffer[index ++] = INTEGER_TAG; 129 | byteBuffer[index ++] = lenExp; 130 | //- exponent value 131 | memcpy(byteBuffer + index, exponentBytes, sizeof(uint8_t) * lenExp); 132 | index += lenExp; 133 | 134 | if(index != lenTotal) 135 | NSLog(@"lengths mismatch: index = %d, lenTotal = %d", index, lenTotal); 136 | 137 | NSMutableData* buffer = [NSMutableData dataWithBytes:byteBuffer length:lenTotal]; 138 | free(byteBuffer); 139 | 140 | return buffer; 141 | } 142 | 143 | + (BOOL)saveRSAPublicKey:(NSData*)publicKey appTag:(NSString*)appTag overwrite:(BOOL)overwrite 144 | { 145 | CFDataRef ref; 146 | OSStatus status = SecItemAdd((CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys: 147 | (id)kSecClassKey, kSecClass, 148 | (id)kSecAttrKeyTypeRSA, kSecAttrKeyType, 149 | (id)kSecAttrKeyClassPublic, kSecAttrKeyClass, 150 | kCFBooleanTrue, kSecAttrIsPermanent, 151 | [appTag dataUsingEncoding:NSUTF8StringEncoding], kSecAttrApplicationTag, 152 | publicKey, kSecValueData, 153 | kCFBooleanTrue, kSecReturnPersistentRef, 154 | nil], 155 | (CFTypeRef *)&ref); 156 | 157 | NSLog(@"result = %@", [KeychainUtil fetchStatus:status]); 158 | 159 | if(status == noErr) 160 | return YES; 161 | else if(status == errSecDuplicateItem && overwrite == YES) 162 | return [CryptoUtil updateRSAPublicKey:publicKey appTag:appTag]; 163 | 164 | return NO; 165 | } 166 | 167 | + (BOOL)updateRSAPublicKey:(NSData*)publicKey appTag:(NSString*)appTag 168 | { 169 | OSStatus status = SecItemCopyMatching((CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys: 170 | (id)kSecClassKey, kSecClass, 171 | kSecAttrKeyTypeRSA, kSecAttrKeyType, 172 | kSecAttrKeyClassPublic, kSecAttrKeyClass, 173 | [appTag dataUsingEncoding:NSUTF8StringEncoding], kSecAttrApplicationTag, 174 | nil], 175 | NULL); //don't need public key ref 176 | 177 | NSLog(@"result = %@", [KeychainUtil fetchStatus:status]); 178 | 179 | if(status == noErr) 180 | { 181 | status = SecItemUpdate((CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys: 182 | (id)kSecClassKey, kSecClass, 183 | kSecAttrKeyTypeRSA, kSecAttrKeyType, 184 | kSecAttrKeyClassPublic, kSecAttrKeyClass, 185 | [appTag dataUsingEncoding:NSUTF8StringEncoding], kSecAttrApplicationTag, 186 | nil], 187 | (CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys: 188 | publicKey, kSecValueData, 189 | nil]); 190 | 191 | NSLog(@"result = %@", [KeychainUtil fetchStatus:status]); 192 | 193 | return status == noErr; 194 | } 195 | return NO; 196 | } 197 | 198 | + (BOOL)deleteRSAPublicKeyWithAppTag:(NSString*)appTag 199 | { 200 | OSStatus status = SecItemDelete((CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys: 201 | (id)kSecClassKey, kSecClass, 202 | kSecAttrKeyTypeRSA, kSecAttrKeyType, 203 | kSecAttrKeyClassPublic, kSecAttrKeyClass, 204 | [appTag dataUsingEncoding:NSUTF8StringEncoding], kSecAttrApplicationTag, 205 | nil]); 206 | 207 | NSLog(@"result = %@", [KeychainUtil fetchStatus:status]); 208 | 209 | return status == noErr; 210 | } 211 | 212 | /* 213 | * returned value(SecKeyRef) should be released with CFRelease() function after use. 214 | * 215 | */ 216 | + (SecKeyRef)loadRSAPublicKeyRefWithAppTag:(NSString*)appTag 217 | { 218 | SecKeyRef publicKeyRef; 219 | OSStatus status = SecItemCopyMatching((CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys: 220 | (id)kSecClassKey, kSecClass, 221 | kSecAttrKeyTypeRSA, kSecAttrKeyType, 222 | kSecAttrKeyClassPublic, kSecAttrKeyClass, 223 | [appTag dataUsingEncoding:NSUTF8StringEncoding], kSecAttrApplicationTag, 224 | kCFBooleanTrue, kSecReturnRef, 225 | nil], 226 | (CFTypeRef*)&publicKeyRef); 227 | 228 | NSLog(@"result = %@", [KeychainUtil fetchStatus:status]); 229 | 230 | if(status == noErr) 231 | return publicKeyRef; 232 | else 233 | return NULL; 234 | } 235 | 236 | /** 237 | * encrypt with RSA public key 238 | * 239 | * padding = kSecPaddingPKCS1 / kSecPaddingNone 240 | * 241 | */ 242 | + (NSData*)encryptString:(NSString*)original RSAPublicKey:(SecKeyRef)publicKey padding:(SecPadding)padding 243 | { 244 | @try 245 | { 246 | size_t encryptedLength = SecKeyGetBlockSize(publicKey); 247 | uint8_t encrypted[encryptedLength]; 248 | 249 | const char* cStringValue = [original UTF8String]; 250 | OSStatus status = SecKeyEncrypt(publicKey, 251 | padding, 252 | (const uint8_t*)cStringValue, 253 | strlen(cStringValue), 254 | encrypted, 255 | &encryptedLength); 256 | if(status == noErr) 257 | { 258 | NSData* encryptedData = [[NSData alloc] initWithBytes:(const void*)encrypted length:encryptedLength]; 259 | return [encryptedData autorelease]; 260 | } 261 | else 262 | return nil; 263 | } 264 | @catch (NSException * e) 265 | { 266 | //do nothing 267 | NSLog(@"exception: %@", [e reason]); 268 | } 269 | return nil; 270 | } 271 | 272 | + (NSData *)stripPublicKeyHeader:(NSData *)d_key 273 | { 274 | // Skip ASN.1 public key header 275 | if (d_key == nil) return(nil); 276 | 277 | unsigned int len = [d_key length]; 278 | if (!len) return(nil); 279 | 280 | unsigned char *c_key = (unsigned char *)[d_key bytes]; 281 | unsigned int idx = 0; 282 | 283 | if (c_key[idx++] != 0x30) return(nil); 284 | 285 | if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; 286 | else idx++; 287 | 288 | // PKCS #1 rsaEncryption szOID_RSA_RSA 289 | static unsigned char seqiod[] = 290 | { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 291 | 0x01, 0x05, 0x00 }; 292 | if (memcmp(&c_key[idx], seqiod, 15)) return(nil); 293 | 294 | idx += 15; 295 | 296 | if (c_key[idx++] != 0x03) return(nil); 297 | 298 | if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; 299 | else idx++; 300 | 301 | if (c_key[idx++] != '\0') return(nil); 302 | 303 | // Now make a new NSData from this buffer 304 | return([NSData dataWithBytes:&c_key[idx] length:len - idx]); 305 | } 306 | 307 | + (SecKeyRef)RSAPublicKeyRefFromBase64String:(NSString *)key withTag:(NSString *)tag 308 | { 309 | NSString *s_key = [NSString string]; 310 | NSArray *a_key = [key componentsSeparatedByString:@"\n"]; 311 | BOOL f_key = FALSE; 312 | 313 | for (NSString *a_line in a_key) { 314 | if ([a_line isEqualToString:@"-----BEGIN PUBLIC KEY-----"]) { 315 | f_key = TRUE; 316 | } 317 | else if ([a_line isEqualToString:@"-----END PUBLIC KEY-----"]) { 318 | f_key = FALSE; 319 | } 320 | else if (f_key) { 321 | s_key = [s_key stringByAppendingString:a_line]; 322 | } 323 | } 324 | if (s_key.length == 0) return(FALSE); 325 | 326 | // This will be base64 encoded, decode it. 327 | NSData *d_key = [NSData dataWithBase64EncodedString:s_key]; 328 | d_key = [self stripPublicKeyHeader:d_key]; 329 | if (d_key == nil) return(FALSE); 330 | 331 | 332 | NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]]; 333 | 334 | // Delete any old lingering key with the same tag 335 | NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init]; 336 | [publicKey setObject:(id) kSecClassKey forKey:(id)kSecClass]; 337 | [publicKey setObject:(id) kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType]; 338 | [publicKey setObject:d_tag forKey:(id)kSecAttrApplicationTag]; 339 | SecItemDelete((CFDictionaryRef)publicKey); 340 | 341 | CFTypeRef persistKey = nil; 342 | 343 | // Add persistent version of the key to system keychain 344 | [publicKey setObject:d_key forKey:(id)kSecValueData]; 345 | [publicKey setObject:(id) kSecAttrKeyClassPublic forKey:(id) 346 | kSecAttrKeyClass]; 347 | [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(id) 348 | kSecReturnPersistentRef]; 349 | 350 | OSStatus secStatus = SecItemAdd((CFDictionaryRef)publicKey, &persistKey); 351 | if (persistKey != nil) CFRelease(persistKey); 352 | 353 | if ((secStatus != noErr) && (secStatus != errSecDuplicateItem)) { 354 | [publicKey release]; 355 | return(FALSE); 356 | } 357 | 358 | // Now fetch the SecKeyRef version of the key 359 | SecKeyRef keyRef = nil; 360 | 361 | [publicKey removeObjectForKey:(id)kSecValueData]; 362 | [publicKey removeObjectForKey:(id)kSecReturnPersistentRef]; 363 | [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef 364 | ]; 365 | [publicKey setObject:(id) kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType]; 366 | secStatus = SecItemCopyMatching((CFDictionaryRef)publicKey, 367 | (CFTypeRef *)&keyRef); 368 | 369 | [publicKey release]; 370 | 371 | if (keyRef == nil) 372 | return(FALSE); 373 | else 374 | return keyRef; 375 | } 376 | 377 | 378 | 379 | @end -------------------------------------------------------------------------------- /KeychainUtil.h: -------------------------------------------------------------------------------- 1 | // 2 | // KeychainUtil.h 3 | // iPhoneLib, 4 | // Helper Functions and Classes for Ordinary Application Development on iPhone 5 | // 6 | // Created by meinside on 09. 07. 19. 7 | // 8 | // last update: 13.04.02. 9 | // 10 | 11 | #pragma once 12 | #import 13 | 14 | //needs: Security.framework 15 | 16 | @interface KeychainUtil : NSObject { 17 | 18 | } 19 | 20 | + (BOOL)saveGenericPasswd:(NSData*)data 21 | forAccount:(NSString*)account 22 | service:(NSString*)service 23 | passwdKey:(NSString*)key 24 | accessGroup:(NSString*)group 25 | overwrite:(BOOL)overwrite; 26 | + (BOOL)saveGenericPasswd:(NSData*)data 27 | forAccount:(NSString*)account 28 | service:(NSString*)service 29 | passwdKey:(NSString*)key 30 | overwrite:(BOOL)overwrite; 31 | 32 | + (BOOL)updateGenericPasswd:(NSData*)data 33 | forAccount:(NSString*)account 34 | service:(NSString*)service 35 | passwdKey:(NSString*)key 36 | accessGroup:(NSString*)group; 37 | + (BOOL)updateGenericPasswd:(NSData*)data 38 | forAccount:(NSString*)account 39 | service:(NSString*)service 40 | passwdKey:(NSString*)key; 41 | 42 | + (NSString*)loadPasswdStringForAccount:(NSString*)account 43 | service:(NSString*)service 44 | passwdKey:(NSString*)key 45 | accessGroup:(NSString*)group; 46 | + (NSString*)loadPasswdStringForAccount:(NSString*)account 47 | service:(NSString*)service 48 | passwdKey:(NSString*)key; 49 | 50 | + (NSData*)loadPasswdDataForAccount:(NSString*)account 51 | service:(NSString*)service 52 | passwdKey:(NSString*)key 53 | accessGroup:(NSString*)group; 54 | + (NSData*)loadPasswdDataForAccount:(NSString*)account 55 | service:(NSString*)service 56 | passwdKey:(NSString*)key; 57 | 58 | + (BOOL)deleteGenericPasswdForAccount:(NSString*)account 59 | service:(NSString*)service 60 | passwdKey:(NSString*)key 61 | accessGroup:(NSString*)group; 62 | + (BOOL)deleteGenericPasswdForAccount:(NSString*)account 63 | service:(NSString*)service 64 | passwdKey:(NSString*)key; 65 | 66 | + (BOOL)genericPasswdExistsForAccount:(NSString*)account 67 | service:(NSString*)service 68 | passwdKey:(NSString*)key 69 | accessGroup:(NSString*)group; 70 | + (BOOL)genericPasswdExistsForAccount:(NSString*)account 71 | service:(NSString*)service 72 | passwdKey:(NSString*)key; 73 | 74 | 75 | + (NSData*)dataFromDictionary:(NSMutableDictionary*)dic; 76 | 77 | + (NSMutableDictionary*)dictionaryFromData:(NSData*)data; 78 | 79 | 80 | + (NSString*)fetchStatus:(OSStatus)status; 81 | 82 | 83 | + (void)resetCredentials; 84 | 85 | + (void)dumpCredentials; 86 | 87 | @end 88 | -------------------------------------------------------------------------------- /KeychainUtil.m: -------------------------------------------------------------------------------- 1 | // 2 | // KeychainUtil.m 3 | // iPhoneLib, 4 | // Helper Functions and Classes for Ordinary Application Development on iPhone 5 | // 6 | // Created by meinside on 09. 07. 19. 7 | // 8 | // last update: 13.04.02. 9 | // 10 | 11 | #import "KeychainUtil.h" 12 | 13 | 14 | 15 | @implementation KeychainUtil 16 | 17 | #pragma mark - 18 | #pragma mark factory functions 19 | 20 | + (NSMutableDictionary*)dictionaryOfGenericPasswdForAccount:(NSString*)account 21 | service:(NSString*)service 22 | passwdKey:(NSString*)key 23 | accessGroup:(NSString*)group 24 | { 25 | NSMutableDictionary* dic = [[NSMutableDictionary alloc] init]; 26 | 27 | NSData* identifier = [key dataUsingEncoding:NSUTF8StringEncoding]; 28 | [dic setObject:identifier 29 | forKey:(id)kSecAttrGeneric]; 30 | [dic setObject:account 31 | forKey:(id)kSecAttrAccount]; 32 | [dic setObject:service 33 | forKey:(id)kSecAttrService]; 34 | [dic setObject:(id)kSecClassGenericPassword 35 | forKey:(id)kSecClass]; 36 | if(group) 37 | [dic setObject:group 38 | forKey:(id)kSecAttrAccessGroup]; 39 | 40 | return [dic autorelease]; 41 | } 42 | 43 | + (NSMutableDictionary*)dictionaryOfGenericPasswdForAccount:(NSString*)account 44 | service:(NSString*)service 45 | passwdKey:(NSString*)key 46 | { 47 | return [KeychainUtil dictionaryOfGenericPasswdForAccount:account 48 | service:service 49 | passwdKey:key 50 | accessGroup:nil]; 51 | } 52 | 53 | #pragma mark - 54 | #pragma mark C/R/U/D functions 55 | 56 | + (NSMutableDictionary*)searchDictionaryOfGenericPasswdForAccount:(NSString*)account 57 | service:(NSString*)service 58 | passwdKey:(NSString*)key 59 | accessGroup:(NSString*)group 60 | { 61 | NSMutableDictionary* dic = [KeychainUtil dictionaryOfGenericPasswdForAccount:account 62 | service:service 63 | passwdKey:key 64 | accessGroup:group]; 65 | [dic setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit]; 66 | [dic setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes]; 67 | [dic setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; 68 | return dic; 69 | } 70 | 71 | + (BOOL)saveGenericPasswd:(NSData*)data 72 | forAccount:(NSString*)account 73 | service:(NSString*)service 74 | passwdKey:(NSString*)key 75 | accessGroup:(NSString*)group 76 | overwrite:(BOOL)overwrite 77 | { 78 | NSMutableDictionary* dic = [KeychainUtil dictionaryOfGenericPasswdForAccount:account 79 | service:service 80 | passwdKey:key 81 | accessGroup:group]; 82 | [dic setObject:data forKey:(id)kSecValueData]; 83 | 84 | OSStatus status = SecItemAdd((CFDictionaryRef)dic, NULL); 85 | if(status == noErr) 86 | { 87 | return YES; 88 | } 89 | else if(status == errSecDuplicateItem && overwrite == YES) 90 | { 91 | return [KeychainUtil updateGenericPasswd:data 92 | forAccount:account 93 | service:service 94 | passwdKey:key 95 | accessGroup:group]; 96 | } 97 | return NO; 98 | } 99 | 100 | + (BOOL)saveGenericPasswd:(NSData*)data 101 | forAccount:(NSString*)account 102 | service:(NSString*)service 103 | passwdKey:(NSString*)key 104 | overwrite:(BOOL)overwrite 105 | { 106 | return [KeychainUtil saveGenericPasswd:data 107 | forAccount:account 108 | service:service 109 | passwdKey:key 110 | accessGroup:nil 111 | overwrite:overwrite]; 112 | } 113 | 114 | + (BOOL)updateGenericPasswd:(NSData*)data 115 | forAccount:(NSString*)account 116 | service:(NSString*)service 117 | passwdKey:(NSString*)key 118 | accessGroup:(NSString*)group 119 | { 120 | NSMutableDictionary* dic = [KeychainUtil dictionaryOfGenericPasswdForAccount:account 121 | service:service 122 | passwdKey:key 123 | accessGroup:group]; 124 | NSMutableDictionary* updateDic = [NSMutableDictionary dictionary]; 125 | [updateDic setObject:data forKey:(id)kSecValueData]; 126 | 127 | OSStatus status = SecItemUpdate((CFDictionaryRef)dic, (CFDictionaryRef)updateDic); 128 | if(status == noErr) 129 | return YES; 130 | else 131 | return NO; 132 | } 133 | 134 | + (BOOL)updateGenericPasswd:(NSData*)data 135 | forAccount:(NSString*)account 136 | service:(NSString*)service 137 | passwdKey:(NSString*)key 138 | { 139 | return [KeychainUtil updateGenericPasswd:data 140 | forAccount:account 141 | service:service 142 | passwdKey:key 143 | accessGroup:nil]; 144 | } 145 | 146 | + (NSMutableDictionary*)loadDictionaryOfGenericPasswdForAccount:(NSString*)account 147 | service:(NSString*)service 148 | passwdKey:(NSString*)key 149 | accessGroup:(NSString*)group 150 | { 151 | NSMutableDictionary* searchDic = [KeychainUtil searchDictionaryOfGenericPasswdForAccount:account 152 | service:service 153 | passwdKey:key 154 | accessGroup:group]; 155 | NSMutableDictionary* dic = nil; 156 | 157 | OSStatus status = SecItemCopyMatching((CFDictionaryRef)searchDic, (CFTypeRef*)&dic); 158 | if(status == noErr) 159 | return [dic autorelease]; 160 | else 161 | return nil; 162 | } 163 | 164 | + (NSData*)loadGenericPasswdForAccount:(NSString*)account 165 | service:(NSString*)service 166 | passwdKey:(NSString*)key 167 | accessGroup:(NSString*)group 168 | { 169 | NSMutableDictionary* dic = [KeychainUtil loadDictionaryOfGenericPasswdForAccount:account 170 | service:service 171 | passwdKey:key 172 | accessGroup:group]; 173 | if(dic) 174 | return [KeychainUtil dataFromDictionary:dic]; 175 | else 176 | return nil; 177 | } 178 | 179 | + (NSString*)loadPasswdStringForAccount:(NSString*)account 180 | service:(NSString*)service 181 | passwdKey:(NSString*)key 182 | accessGroup:(NSString*)group 183 | { 184 | NSMutableDictionary* dic = [KeychainUtil loadDictionaryOfGenericPasswdForAccount:account 185 | service:service 186 | passwdKey:key 187 | accessGroup:group]; 188 | if(dic) 189 | { 190 | NSString* resultString = [[NSString alloc] initWithData:[dic objectForKey:(id)kSecValueData] encoding:NSUTF8StringEncoding]; 191 | return [resultString autorelease]; 192 | } 193 | else 194 | return nil; 195 | } 196 | 197 | + (NSString*)loadPasswdStringForAccount:(NSString*)account 198 | service:(NSString*)service 199 | passwdKey:(NSString*)key 200 | { 201 | return [KeychainUtil loadPasswdStringForAccount:account 202 | service:service 203 | passwdKey:key 204 | accessGroup:nil]; 205 | } 206 | 207 | + (NSData*)loadPasswdDataForAccount:(NSString*)account 208 | service:(NSString*)service 209 | passwdKey:(NSString*)key 210 | accessGroup:(NSString*)group 211 | { 212 | NSMutableDictionary* dic = [KeychainUtil loadDictionaryOfGenericPasswdForAccount:account 213 | service:service 214 | passwdKey:key 215 | accessGroup:group]; 216 | if(dic) 217 | return [dic objectForKey:(id)kSecValueData]; 218 | else 219 | return nil; 220 | } 221 | 222 | + (NSData*)loadPasswdDataForAccount:(NSString*)account 223 | service:(NSString*)service 224 | passwdKey:(NSString*)key 225 | { 226 | return [KeychainUtil loadPasswdDataForAccount:account 227 | service:service 228 | passwdKey:key 229 | accessGroup:nil]; 230 | } 231 | 232 | + (BOOL)deleteGenericPasswdForAccount:(NSString*)account 233 | service:(NSString*)service 234 | passwdKey:(NSString*)key 235 | accessGroup:(NSString*)group 236 | { 237 | NSMutableDictionary* dic = [KeychainUtil dictionaryOfGenericPasswdForAccount:account 238 | service:service 239 | passwdKey:key 240 | accessGroup:group]; 241 | 242 | OSStatus status = SecItemDelete((CFDictionaryRef)dic); 243 | if(status == noErr) 244 | return YES; 245 | else 246 | return NO; 247 | } 248 | 249 | + (BOOL)deleteGenericPasswdForAccount:(NSString*)account 250 | service:(NSString*)service 251 | passwdKey:(NSString*)key 252 | { 253 | return [KeychainUtil deleteGenericPasswdForAccount:account 254 | service:service 255 | passwdKey:key 256 | accessGroup:nil]; 257 | } 258 | 259 | + (BOOL)genericPasswdExistsForAccount:(NSString*)account 260 | service:(NSString*)service 261 | passwdKey:(NSString*)key 262 | accessGroup:(NSString*)group 263 | { 264 | NSMutableDictionary* searchDic = [KeychainUtil searchDictionaryOfGenericPasswdForAccount:account 265 | service:service 266 | passwdKey:key 267 | accessGroup:group]; 268 | NSMutableDictionary* dic = nil; 269 | 270 | OSStatus status = SecItemCopyMatching((CFDictionaryRef)searchDic, (CFTypeRef*)&dic); 271 | [dic release]; 272 | if(status == noErr) 273 | return YES; 274 | else if(status == errSecItemNotFound) 275 | return NO; 276 | else 277 | return NO; 278 | } 279 | 280 | + (BOOL)genericPasswdExistsForAccount:(NSString*)account 281 | service:(NSString*)service 282 | passwdKey:(NSString*)key 283 | { 284 | return [KeychainUtil genericPasswdExistsForAccount:account 285 | service:service 286 | passwdKey:key 287 | accessGroup:nil]; 288 | } 289 | 290 | #pragma mark - 291 | #pragma mark helper functions 292 | 293 | + (NSData*)dataFromDictionary:(NSMutableDictionary*)dic 294 | { 295 | if(dic == nil) 296 | return nil; 297 | 298 | NSString* errorString; 299 | NSData* data = [NSPropertyListSerialization dataFromPropertyList:dic 300 | format:NSPropertyListBinaryFormat_v1_0 301 | errorDescription:&errorString]; 302 | return data; 303 | } 304 | 305 | + (NSMutableDictionary*)dictionaryFromData:(NSData*)data 306 | { 307 | if(data == nil) 308 | return nil; 309 | 310 | NSString* errorString; 311 | NSMutableDictionary* dic = [NSPropertyListSerialization propertyListFromData:data 312 | mutabilityOption:NSPropertyListMutableContainersAndLeaves 313 | format:NULL 314 | errorDescription:&errorString]; 315 | return dic; 316 | } 317 | 318 | + (NSString*)fetchStatus:(OSStatus)status 319 | { 320 | if(status == 0) 321 | return @"success"; 322 | else if(status == errSecNotAvailable) 323 | return @"no trust results available"; 324 | else if(status == errSecItemNotFound) 325 | return @"the item cannot be found"; 326 | else if(status == errSecParam) 327 | return @"parameter error"; 328 | else if(status == errSecAllocate) 329 | return @"memory allocation error"; 330 | else if(status == errSecInteractionNotAllowed) 331 | return @"user interaction not allowd"; 332 | else if(status == errSecUnimplemented) 333 | return @"not implemented"; 334 | else if(status == errSecDuplicateItem) 335 | return @"item already exists"; 336 | else if(status == errSecDecode) 337 | return @"unable to decode data"; 338 | else 339 | return [NSString stringWithFormat:@"%ld", status]; 340 | } 341 | 342 | #pragma mark - 343 | #pragma mark functions for debug purpose 344 | //from: https://devforums.apple.com/message/123846#123846 345 | 346 | + (void)resetCredentials 347 | { 348 | OSStatus err; 349 | err = SecItemDelete((CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys: 350 | (id)kSecClassIdentity, kSecClass, 351 | nil]); 352 | assert(err == noErr); 353 | 354 | err = SecItemDelete((CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys: 355 | (id)kSecClassCertificate, kSecClass, 356 | nil]); 357 | assert(err == noErr); 358 | 359 | err = SecItemDelete((CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys: 360 | (id)kSecClassKey, kSecClass, 361 | nil]); 362 | assert(err == noErr); 363 | 364 | err = SecItemDelete((CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys: 365 | (id)kSecClassGenericPassword, kSecClass, 366 | nil]); 367 | assert(err == noErr); 368 | 369 | err = SecItemDelete((CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys: 370 | (id)kSecClassInternetPassword, kSecClass, 371 | nil]); 372 | assert(err == noErr); 373 | } 374 | 375 | + (void)_printCertificate:(SecCertificateRef)certificate attributes:(NSDictionary *)attrs indent:(int)indent 376 | { 377 | CFStringRef summary; 378 | NSString* label; 379 | NSData* hash; 380 | 381 | summary = SecCertificateCopySubjectSummary(certificate); 382 | assert(summary != NULL); 383 | 384 | label = [attrs objectForKey:(id)kSecAttrLabel]; 385 | if (label != nil) 386 | { 387 | fprintf(stderr, "%*slabel = '%s'\n", indent, "", [label UTF8String]); 388 | } 389 | 390 | fprintf(stderr, "%*ssummary = '%s'\n", indent, "", [(NSString *)summary UTF8String]); 391 | 392 | hash = [attrs objectForKey:(id)kSecAttrPublicKeyHash]; 393 | if (hash != nil) 394 | { 395 | fprintf(stderr, "%*shash = %s\n", indent, "", [[hash description] UTF8String]); 396 | } 397 | 398 | CFRelease(summary); 399 | } 400 | 401 | + (void)_printKey:(SecKeyRef)key 402 | attributes:(NSDictionary *)attrs 403 | indent:(int)indent 404 | { 405 | #pragma unused(key) 406 | NSString* label; 407 | CFTypeRef keyClass; 408 | 409 | label = [attrs objectForKey:(id)kSecAttrLabel]; 410 | if (label != nil) 411 | { 412 | fprintf(stderr, "%*slabel = '%s'\n", indent, "", [label UTF8String]); 413 | } 414 | 415 | label = [attrs objectForKey:(id)kSecAttrApplicationLabel]; 416 | if (label != nil) 417 | { 418 | fprintf(stderr, "%*sapp label = %s\n", indent, "", [[label description] UTF8String]); 419 | } 420 | 421 | label = [attrs objectForKey:(id)kSecAttrApplicationTag]; 422 | if (label != nil) 423 | { 424 | fprintf(stderr, "%*sapp tag = %s\n", indent, "", [[label description] UTF8String]); 425 | } 426 | 427 | //test 428 | // NSArray* keys = [attrs allKeys]; 429 | // for(int i=0; i<[keys count]; i++) 430 | // { 431 | // NSLog(@"key: %@ => value: %@", [keys objectAtIndex:i], [attrs objectForKey:[keys objectAtIndex:i]]); 432 | // } 433 | 434 | keyClass = (CFTypeRef) [attrs objectForKey:(id)kSecAttrKeyClass]; 435 | if (keyClass != nil) 436 | { 437 | const char* keyClassStr; 438 | 439 | // keyClass is a CFNumber whereas kSecAttrKeyClassPublic (and so on) 440 | // are CFStrings. Gosh, that makes things hard . 441 | // So I compare their descriptions. Yuck! 442 | if ([[(id)keyClass description] isEqual:(id)kSecAttrKeyClassPublic]) 443 | { 444 | keyClassStr = "kSecAttrKeyClassPublic"; 445 | } 446 | else if ([[(id)keyClass description] isEqual:(id)kSecAttrKeyClassPrivate]) 447 | { 448 | keyClassStr = "kSecAttrKeyClassPrivate"; 449 | } 450 | else if ([[(id)keyClass description] isEqual:(id)kSecAttrKeyClassSymmetric]) 451 | { 452 | keyClassStr = "kSecAttrKeyClassSymmetric"; 453 | } 454 | else 455 | { 456 | keyClassStr = "?"; 457 | } 458 | fprintf(stderr, "%*skey class = %s\n", indent, "", keyClassStr); 459 | } 460 | } 461 | 462 | + (void)_printIdentity:(SecIdentityRef)identity 463 | attributes:(NSDictionary *)attrs 464 | { 465 | OSStatus err; 466 | SecCertificateRef certificate; 467 | SecKeyRef key; 468 | 469 | err = SecIdentityCopyCertificate(identity, &certificate); 470 | assert(err == noErr); 471 | 472 | err = SecIdentityCopyPrivateKey(identity, &key); 473 | assert(err == noErr); 474 | 475 | fprintf(stderr, " certificate\n"); 476 | [self _printCertificate:certificate 477 | attributes:attrs 478 | indent:6]; 479 | 480 | fprintf(stderr, " key\n"); 481 | [self _printKey:key 482 | attributes:attrs 483 | indent:6]; 484 | 485 | CFRelease(key); 486 | CFRelease(certificate); 487 | } 488 | 489 | + (void)_printPassword:(CFStringRef)password 490 | attributes:(NSDictionary *)attrs 491 | indent:(int)indent 492 | { 493 | NSString* generic; 494 | NSString* account; 495 | NSString* label; 496 | NSString* value; 497 | 498 | generic = [attrs objectForKey:(id)kSecAttrGeneric]; 499 | if (generic != nil) 500 | { 501 | fprintf(stderr, "%*sgeneric = '%s'\n", indent, "", [[generic description] UTF8String]); 502 | } 503 | 504 | account = [attrs objectForKey:(id)kSecAttrAccount]; 505 | if (account != nil) 506 | { 507 | fprintf(stderr, "%*saccount = '%s'\n", indent, "", [account UTF8String]); 508 | } 509 | 510 | label = [attrs objectForKey:(id)kSecAttrLabel]; 511 | if (label != nil) 512 | { 513 | fprintf(stderr, "%*slabel = '%s'\n", indent, "", [label UTF8String]); 514 | } 515 | 516 | value = [attrs objectForKey:(id)kSecValueData]; 517 | if (value != nil) 518 | { 519 | NSString* valueStr = [[NSString alloc] initWithData:(NSData*)value 520 | encoding:NSUTF8StringEncoding]; 521 | fprintf(stderr, "%*svalue = %s\n", indent, "", [value UTF8String]); 522 | [valueStr release]; 523 | } 524 | } 525 | 526 | + (void)_printCertificate:(SecCertificateRef)certificate 527 | attributes:(NSDictionary *)attrs 528 | { 529 | [self _printCertificate:certificate 530 | attributes:attrs 531 | indent:4]; 532 | } 533 | 534 | + (void)_printKey:(SecKeyRef)key 535 | attributes:(NSDictionary *)attrs 536 | { 537 | [self _printKey:key 538 | attributes:attrs 539 | indent:4]; 540 | } 541 | 542 | + (void)_printPassword:(CFStringRef)password 543 | attributes:(NSDictionary *)attrs 544 | { 545 | [self _printPassword:password 546 | attributes:attrs 547 | indent:4]; 548 | } 549 | 550 | + (void)_dumpCredentialsOfSecClass:(CFTypeRef)secClass 551 | printSelector:(SEL)printSelector 552 | { 553 | OSStatus err; 554 | CFArrayRef result; 555 | CFIndex resultCount; 556 | CFIndex resultIndex; 557 | 558 | result = NULL; 559 | err = SecItemCopyMatching((CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys: 560 | (id)secClass, kSecClass, 561 | kSecMatchLimitAll, kSecMatchLimit, 562 | kCFBooleanTrue, kSecReturnRef, 563 | kCFBooleanTrue, kSecReturnAttributes, 564 | nil], 565 | (CFTypeRef *) &result); 566 | if (result != NULL) 567 | { 568 | assert( CFGetTypeID(result) == CFArrayGetTypeID() ); 569 | 570 | resultCount = CFArrayGetCount(result); 571 | for (resultIndex = 0; resultIndex < resultCount; resultIndex++) 572 | { 573 | NSDictionary * thisResult; 574 | 575 | fprintf(stderr, " %zd\n", (ssize_t) resultIndex); 576 | 577 | thisResult = (NSDictionary *) CFArrayGetValueAtIndex(result, resultIndex); 578 | if ((secClass == kSecClassGenericPassword) || (secClass == kSecClassInternetPassword)) 579 | { 580 | [self performSelector:printSelector withObject:[thisResult objectForKey:(NSString *)kSecValueData] withObject:thisResult]; 581 | } 582 | else 583 | { 584 | [self performSelector:printSelector withObject:[thisResult objectForKey:(NSString *)kSecValueRef] withObject:thisResult]; 585 | } 586 | } 587 | 588 | CFRelease(result); 589 | } 590 | } 591 | 592 | + (void)dumpCredentials 593 | { 594 | fprintf(stderr, "identities:\n"); 595 | [self _dumpCredentialsOfSecClass:kSecClassIdentity 596 | printSelector:@selector(_printIdentity:attributes:)]; 597 | 598 | fprintf(stderr, "certificates:\n"); 599 | [self _dumpCredentialsOfSecClass:kSecClassCertificate 600 | printSelector:@selector(_printCertificate:attributes:)]; 601 | 602 | fprintf(stderr, "keys:\n"); 603 | [self _dumpCredentialsOfSecClass:kSecClassKey 604 | printSelector:@selector(_printKey:attributes:)]; 605 | 606 | fprintf(stderr, "generic passwords:\n"); 607 | [self _dumpCredentialsOfSecClass:kSecClassGenericPassword 608 | printSelector:@selector(_printPassword:attributes:)]; 609 | 610 | fprintf(stderr, "internet passwords:\n"); 611 | [self _dumpCredentialsOfSecClass:kSecClassInternetPassword 612 | printSelector:@selector(_printPassword:attributes:)]; 613 | } 614 | 615 | @end 616 | -------------------------------------------------------------------------------- /RSADemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BF2F807A1727AB390067D0DB /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF2F80791727AB390067D0DB /* UIKit.framework */; }; 11 | BF2F807C1727AB390067D0DB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF2F807B1727AB390067D0DB /* Foundation.framework */; }; 12 | BF2F807E1727AB390067D0DB /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF2F807D1727AB390067D0DB /* CoreGraphics.framework */; }; 13 | BF2F80841727AB390067D0DB /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF2F80821727AB390067D0DB /* InfoPlist.strings */; }; 14 | BF2F80861727AB390067D0DB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BF2F80851727AB390067D0DB /* main.m */; }; 15 | BF2F808A1727AB390067D0DB /* GLAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BF2F80891727AB390067D0DB /* GLAppDelegate.m */; }; 16 | BF2F808C1727AB390067D0DB /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = BF2F808B1727AB390067D0DB /* Default.png */; }; 17 | BF2F808E1727AB390067D0DB /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = BF2F808D1727AB390067D0DB /* Default@2x.png */; }; 18 | BF2F80901727AB390067D0DB /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = BF2F808F1727AB390067D0DB /* Default-568h@2x.png */; }; 19 | BF2F80931727AB390067D0DB /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF2F80911727AB390067D0DB /* MainStoryboard.storyboard */; }; 20 | BF2F80961727AB390067D0DB /* GLViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BF2F80951727AB390067D0DB /* GLViewController.m */; }; 21 | BF2F80A41727AB970067D0DB /* Base64.m in Sources */ = {isa = PBXBuildFile; fileRef = BF2F809D1727AB5B0067D0DB /* Base64.m */; }; 22 | BF2F80A51727AB980067D0DB /* CryptoUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = BF2F809F1727AB5B0067D0DB /* CryptoUtil.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 23 | BF2F80A61727AB980067D0DB /* KeychainUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = BF2F80A11727AB5B0067D0DB /* KeychainUtil.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 24 | BF2F80A81727ABB90067D0DB /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF2F80A71727ABB90067D0DB /* Security.framework */; }; 25 | BF2F80AA1727AC960067D0DB /* key.txt in Resources */ = {isa = PBXBuildFile; fileRef = BF2F80A91727AC960067D0DB /* key.txt */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | BF2F80761727AB390067D0DB /* RSADemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RSADemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 30 | BF2F80791727AB390067D0DB /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 31 | BF2F807B1727AB390067D0DB /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 32 | BF2F807D1727AB390067D0DB /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 33 | BF2F80811727AB390067D0DB /* RSADemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RSADemo-Info.plist"; sourceTree = ""; }; 34 | BF2F80831727AB390067D0DB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 35 | BF2F80851727AB390067D0DB /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 36 | BF2F80871727AB390067D0DB /* RSADemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RSADemo-Prefix.pch"; sourceTree = ""; }; 37 | BF2F80881727AB390067D0DB /* GLAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GLAppDelegate.h; sourceTree = ""; }; 38 | BF2F80891727AB390067D0DB /* GLAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GLAppDelegate.m; sourceTree = ""; }; 39 | BF2F808B1727AB390067D0DB /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 40 | BF2F808D1727AB390067D0DB /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 41 | BF2F808F1727AB390067D0DB /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 42 | BF2F80921727AB390067D0DB /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard.storyboard; sourceTree = ""; }; 43 | BF2F80941727AB390067D0DB /* GLViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GLViewController.h; sourceTree = ""; }; 44 | BF2F80951727AB390067D0DB /* GLViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GLViewController.m; sourceTree = ""; }; 45 | BF2F809C1727AB5B0067D0DB /* Base64.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Base64.h; sourceTree = ""; }; 46 | BF2F809D1727AB5B0067D0DB /* Base64.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Base64.m; sourceTree = ""; }; 47 | BF2F809E1727AB5B0067D0DB /* CryptoUtil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CryptoUtil.h; sourceTree = ""; }; 48 | BF2F809F1727AB5B0067D0DB /* CryptoUtil.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CryptoUtil.m; sourceTree = ""; }; 49 | BF2F80A01727AB5B0067D0DB /* KeychainUtil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeychainUtil.h; sourceTree = ""; }; 50 | BF2F80A11727AB5B0067D0DB /* KeychainUtil.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeychainUtil.m; sourceTree = ""; }; 51 | BF2F80A71727ABB90067D0DB /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 52 | BF2F80A91727AC960067D0DB /* key.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = key.txt; sourceTree = ""; }; 53 | /* End PBXFileReference section */ 54 | 55 | /* Begin PBXFrameworksBuildPhase section */ 56 | BF2F80731727AB390067D0DB /* Frameworks */ = { 57 | isa = PBXFrameworksBuildPhase; 58 | buildActionMask = 2147483647; 59 | files = ( 60 | BF2F80A81727ABB90067D0DB /* Security.framework in Frameworks */, 61 | BF2F807A1727AB390067D0DB /* UIKit.framework in Frameworks */, 62 | BF2F807C1727AB390067D0DB /* Foundation.framework in Frameworks */, 63 | BF2F807E1727AB390067D0DB /* CoreGraphics.framework in Frameworks */, 64 | ); 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | /* End PBXFrameworksBuildPhase section */ 68 | 69 | /* Begin PBXGroup section */ 70 | BF2F806D1727AB390067D0DB = { 71 | isa = PBXGroup; 72 | children = ( 73 | BF2F80A71727ABB90067D0DB /* Security.framework */, 74 | BF2F80A31727AB630067D0DB /* Security */, 75 | BF2F807F1727AB390067D0DB /* RSADemo */, 76 | BF2F80781727AB390067D0DB /* Frameworks */, 77 | BF2F80771727AB390067D0DB /* Products */, 78 | ); 79 | sourceTree = ""; 80 | }; 81 | BF2F80771727AB390067D0DB /* Products */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | BF2F80761727AB390067D0DB /* RSADemo.app */, 85 | ); 86 | name = Products; 87 | sourceTree = ""; 88 | }; 89 | BF2F80781727AB390067D0DB /* Frameworks */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | BF2F80791727AB390067D0DB /* UIKit.framework */, 93 | BF2F807B1727AB390067D0DB /* Foundation.framework */, 94 | BF2F807D1727AB390067D0DB /* CoreGraphics.framework */, 95 | ); 96 | name = Frameworks; 97 | sourceTree = ""; 98 | }; 99 | BF2F807F1727AB390067D0DB /* RSADemo */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | BF2F80881727AB390067D0DB /* GLAppDelegate.h */, 103 | BF2F80891727AB390067D0DB /* GLAppDelegate.m */, 104 | BF2F80911727AB390067D0DB /* MainStoryboard.storyboard */, 105 | BF2F80941727AB390067D0DB /* GLViewController.h */, 106 | BF2F80951727AB390067D0DB /* GLViewController.m */, 107 | BF2F80801727AB390067D0DB /* Supporting Files */, 108 | ); 109 | path = RSADemo; 110 | sourceTree = ""; 111 | }; 112 | BF2F80801727AB390067D0DB /* Supporting Files */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | BF2F80A91727AC960067D0DB /* key.txt */, 116 | BF2F80811727AB390067D0DB /* RSADemo-Info.plist */, 117 | BF2F80821727AB390067D0DB /* InfoPlist.strings */, 118 | BF2F80851727AB390067D0DB /* main.m */, 119 | BF2F80871727AB390067D0DB /* RSADemo-Prefix.pch */, 120 | BF2F808B1727AB390067D0DB /* Default.png */, 121 | BF2F808D1727AB390067D0DB /* Default@2x.png */, 122 | BF2F808F1727AB390067D0DB /* Default-568h@2x.png */, 123 | ); 124 | name = "Supporting Files"; 125 | sourceTree = ""; 126 | }; 127 | BF2F80A31727AB630067D0DB /* Security */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | BF2F809C1727AB5B0067D0DB /* Base64.h */, 131 | BF2F809D1727AB5B0067D0DB /* Base64.m */, 132 | BF2F809E1727AB5B0067D0DB /* CryptoUtil.h */, 133 | BF2F809F1727AB5B0067D0DB /* CryptoUtil.m */, 134 | BF2F80A01727AB5B0067D0DB /* KeychainUtil.h */, 135 | BF2F80A11727AB5B0067D0DB /* KeychainUtil.m */, 136 | ); 137 | name = Security; 138 | sourceTree = ""; 139 | }; 140 | /* End PBXGroup section */ 141 | 142 | /* Begin PBXNativeTarget section */ 143 | BF2F80751727AB390067D0DB /* RSADemo */ = { 144 | isa = PBXNativeTarget; 145 | buildConfigurationList = BF2F80991727AB390067D0DB /* Build configuration list for PBXNativeTarget "RSADemo" */; 146 | buildPhases = ( 147 | BF2F80721727AB390067D0DB /* Sources */, 148 | BF2F80731727AB390067D0DB /* Frameworks */, 149 | BF2F80741727AB390067D0DB /* Resources */, 150 | ); 151 | buildRules = ( 152 | ); 153 | dependencies = ( 154 | ); 155 | name = RSADemo; 156 | productName = RSADemo; 157 | productReference = BF2F80761727AB390067D0DB /* RSADemo.app */; 158 | productType = "com.apple.product-type.application"; 159 | }; 160 | /* End PBXNativeTarget section */ 161 | 162 | /* Begin PBXProject section */ 163 | BF2F806E1727AB390067D0DB /* Project object */ = { 164 | isa = PBXProject; 165 | attributes = { 166 | CLASSPREFIX = GL; 167 | LastUpgradeCheck = 0460; 168 | ORGANIZATIONNAME = GraceLancy; 169 | }; 170 | buildConfigurationList = BF2F80711727AB390067D0DB /* Build configuration list for PBXProject "RSADemo" */; 171 | compatibilityVersion = "Xcode 3.2"; 172 | developmentRegion = English; 173 | hasScannedForEncodings = 0; 174 | knownRegions = ( 175 | en, 176 | ); 177 | mainGroup = BF2F806D1727AB390067D0DB; 178 | productRefGroup = BF2F80771727AB390067D0DB /* Products */; 179 | projectDirPath = ""; 180 | projectRoot = ""; 181 | targets = ( 182 | BF2F80751727AB390067D0DB /* RSADemo */, 183 | ); 184 | }; 185 | /* End PBXProject section */ 186 | 187 | /* Begin PBXResourcesBuildPhase section */ 188 | BF2F80741727AB390067D0DB /* Resources */ = { 189 | isa = PBXResourcesBuildPhase; 190 | buildActionMask = 2147483647; 191 | files = ( 192 | BF2F80841727AB390067D0DB /* InfoPlist.strings in Resources */, 193 | BF2F808C1727AB390067D0DB /* Default.png in Resources */, 194 | BF2F808E1727AB390067D0DB /* Default@2x.png in Resources */, 195 | BF2F80901727AB390067D0DB /* Default-568h@2x.png in Resources */, 196 | BF2F80931727AB390067D0DB /* MainStoryboard.storyboard in Resources */, 197 | BF2F80AA1727AC960067D0DB /* key.txt in Resources */, 198 | ); 199 | runOnlyForDeploymentPostprocessing = 0; 200 | }; 201 | /* End PBXResourcesBuildPhase section */ 202 | 203 | /* Begin PBXSourcesBuildPhase section */ 204 | BF2F80721727AB390067D0DB /* Sources */ = { 205 | isa = PBXSourcesBuildPhase; 206 | buildActionMask = 2147483647; 207 | files = ( 208 | BF2F80A41727AB970067D0DB /* Base64.m in Sources */, 209 | BF2F80A51727AB980067D0DB /* CryptoUtil.m in Sources */, 210 | BF2F80A61727AB980067D0DB /* KeychainUtil.m in Sources */, 211 | BF2F80861727AB390067D0DB /* main.m in Sources */, 212 | BF2F808A1727AB390067D0DB /* GLAppDelegate.m in Sources */, 213 | BF2F80961727AB390067D0DB /* GLViewController.m in Sources */, 214 | ); 215 | runOnlyForDeploymentPostprocessing = 0; 216 | }; 217 | /* End PBXSourcesBuildPhase section */ 218 | 219 | /* Begin PBXVariantGroup section */ 220 | BF2F80821727AB390067D0DB /* InfoPlist.strings */ = { 221 | isa = PBXVariantGroup; 222 | children = ( 223 | BF2F80831727AB390067D0DB /* en */, 224 | ); 225 | name = InfoPlist.strings; 226 | sourceTree = ""; 227 | }; 228 | BF2F80911727AB390067D0DB /* MainStoryboard.storyboard */ = { 229 | isa = PBXVariantGroup; 230 | children = ( 231 | BF2F80921727AB390067D0DB /* en */, 232 | ); 233 | name = MainStoryboard.storyboard; 234 | sourceTree = ""; 235 | }; 236 | /* End PBXVariantGroup section */ 237 | 238 | /* Begin XCBuildConfiguration section */ 239 | BF2F80971727AB390067D0DB /* Debug */ = { 240 | isa = XCBuildConfiguration; 241 | buildSettings = { 242 | ALWAYS_SEARCH_USER_PATHS = NO; 243 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 244 | CLANG_CXX_LIBRARY = "libc++"; 245 | CLANG_ENABLE_OBJC_ARC = YES; 246 | CLANG_WARN_CONSTANT_CONVERSION = YES; 247 | CLANG_WARN_EMPTY_BODY = YES; 248 | CLANG_WARN_ENUM_CONVERSION = YES; 249 | CLANG_WARN_INT_CONVERSION = YES; 250 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 251 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 252 | COPY_PHASE_STRIP = NO; 253 | GCC_C_LANGUAGE_STANDARD = gnu99; 254 | GCC_DYNAMIC_NO_PIC = NO; 255 | GCC_OPTIMIZATION_LEVEL = 0; 256 | GCC_PREPROCESSOR_DEFINITIONS = ( 257 | "DEBUG=1", 258 | "$(inherited)", 259 | ); 260 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 261 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 262 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 263 | GCC_WARN_UNUSED_VARIABLE = YES; 264 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 265 | ONLY_ACTIVE_ARCH = YES; 266 | SDKROOT = iphoneos; 267 | }; 268 | name = Debug; 269 | }; 270 | BF2F80981727AB390067D0DB /* Release */ = { 271 | isa = XCBuildConfiguration; 272 | buildSettings = { 273 | ALWAYS_SEARCH_USER_PATHS = NO; 274 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 275 | CLANG_CXX_LIBRARY = "libc++"; 276 | CLANG_ENABLE_OBJC_ARC = YES; 277 | CLANG_WARN_CONSTANT_CONVERSION = YES; 278 | CLANG_WARN_EMPTY_BODY = YES; 279 | CLANG_WARN_ENUM_CONVERSION = YES; 280 | CLANG_WARN_INT_CONVERSION = YES; 281 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 282 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 283 | COPY_PHASE_STRIP = YES; 284 | GCC_C_LANGUAGE_STANDARD = gnu99; 285 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 286 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 287 | GCC_WARN_UNUSED_VARIABLE = YES; 288 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 289 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 290 | SDKROOT = iphoneos; 291 | VALIDATE_PRODUCT = YES; 292 | }; 293 | name = Release; 294 | }; 295 | BF2F809A1727AB390067D0DB /* Debug */ = { 296 | isa = XCBuildConfiguration; 297 | buildSettings = { 298 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 299 | GCC_PREFIX_HEADER = "RSADemo/RSADemo-Prefix.pch"; 300 | INFOPLIST_FILE = "RSADemo/RSADemo-Info.plist"; 301 | PRODUCT_NAME = "$(TARGET_NAME)"; 302 | WRAPPER_EXTENSION = app; 303 | }; 304 | name = Debug; 305 | }; 306 | BF2F809B1727AB390067D0DB /* Release */ = { 307 | isa = XCBuildConfiguration; 308 | buildSettings = { 309 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 310 | GCC_PREFIX_HEADER = "RSADemo/RSADemo-Prefix.pch"; 311 | INFOPLIST_FILE = "RSADemo/RSADemo-Info.plist"; 312 | PRODUCT_NAME = "$(TARGET_NAME)"; 313 | WRAPPER_EXTENSION = app; 314 | }; 315 | name = Release; 316 | }; 317 | /* End XCBuildConfiguration section */ 318 | 319 | /* Begin XCConfigurationList section */ 320 | BF2F80711727AB390067D0DB /* Build configuration list for PBXProject "RSADemo" */ = { 321 | isa = XCConfigurationList; 322 | buildConfigurations = ( 323 | BF2F80971727AB390067D0DB /* Debug */, 324 | BF2F80981727AB390067D0DB /* Release */, 325 | ); 326 | defaultConfigurationIsVisible = 0; 327 | defaultConfigurationName = Release; 328 | }; 329 | BF2F80991727AB390067D0DB /* Build configuration list for PBXNativeTarget "RSADemo" */ = { 330 | isa = XCConfigurationList; 331 | buildConfigurations = ( 332 | BF2F809A1727AB390067D0DB /* Debug */, 333 | BF2F809B1727AB390067D0DB /* Release */, 334 | ); 335 | defaultConfigurationIsVisible = 0; 336 | }; 337 | /* End XCConfigurationList section */ 338 | }; 339 | rootObject = BF2F806E1727AB390067D0DB /* Project object */; 340 | } 341 | -------------------------------------------------------------------------------- /RSADemo/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lancy/RSADemo/7fde4f352e5b0b3c0f3501b2d9d836574b9f9f80/RSADemo/Default-568h@2x.png -------------------------------------------------------------------------------- /RSADemo/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lancy/RSADemo/7fde4f352e5b0b3c0f3501b2d9d836574b9f9f80/RSADemo/Default.png -------------------------------------------------------------------------------- /RSADemo/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lancy/RSADemo/7fde4f352e5b0b3c0f3501b2d9d836574b9f9f80/RSADemo/Default@2x.png -------------------------------------------------------------------------------- /RSADemo/GLAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // GLAppDelegate.h 3 | // RSADemo 4 | // 5 | // Created by Lancy on 24/4/13. 6 | // Copyright (c) 2013 GraceLancy. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface GLAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /RSADemo/GLAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // GLAppDelegate.m 3 | // RSADemo 4 | // 5 | // Created by Lancy on 24/4/13. 6 | // Copyright (c) 2013 GraceLancy. All rights reserved. 7 | // 8 | 9 | #import "GLAppDelegate.h" 10 | 11 | @implementation GLAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | - (void)applicationWillResignActive:(UIApplication *)application 20 | { 21 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 22 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application 26 | { 27 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | - (void)applicationWillEnterForeground:(UIApplication *)application 32 | { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | - (void)applicationDidBecomeActive:(UIApplication *)application 37 | { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application 42 | { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /RSADemo/GLViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // GLViewController.h 3 | // RSADemo 4 | // 5 | // Created by Lancy on 24/4/13. 6 | // Copyright (c) 2013 GraceLancy. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface GLViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /RSADemo/GLViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // GLViewController.m 3 | // RSADemo 4 | // 5 | // Created by Lancy on 24/4/13. 6 | // Copyright (c) 2013 GraceLancy. All rights reserved. 7 | // 8 | 9 | #import "GLViewController.h" 10 | #import "CryptoUtil.h" 11 | #import "Base64.h" 12 | 13 | 14 | @interface GLViewController () 15 | 16 | @end 17 | 18 | @implementation GLViewController 19 | 20 | - (void)viewDidLoad 21 | { 22 | [super viewDidLoad]; 23 | // Do any additional setup after loading the view, typically from a nib. 24 | NSString *path = [[NSBundle mainBundle] pathForResource:@"key" ofType:@"txt"]; 25 | NSString *publicKeyString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; 26 | NSLog(@"%@", publicKeyString); 27 | SecKeyRef publicKey = [CryptoUtil RSAPublicKeyRefFromBase64String:publicKeyString withTag:@"com.gracelancy.tag"]; 28 | NSData *encryptData = [CryptoUtil encryptString:@"hello world" RSAPublicKey:publicKey padding:kSecPaddingNone]; 29 | NSLog(@"%@", [encryptData base64EncodedString]); 30 | 31 | } 32 | 33 | - (void)didReceiveMemoryWarning 34 | { 35 | [super didReceiveMemoryWarning]; 36 | // Dispose of any resources that can be recreated. 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /RSADemo/RSADemo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.gracelancy.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | MainStoryboard 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /RSADemo/RSADemo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'RSADemo' target in the 'RSADemo' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_5_0 8 | #warning "This project uses features only available in iOS SDK 5.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /RSADemo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /RSADemo/en.lproj/MainStoryboard.storyboard: -------------------------------------------------------------------------------- 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 | 26 | -------------------------------------------------------------------------------- /RSADemo/key.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCXG9Edu7/zTaLQFhPks1lm9rsJ 3 | VHuQ6oNKEkf8oYyaidSCfm3mvzYiOgH39aB4vEePGoGTN/aLPioF+wdKhrwg3VlO 4 | 2JGcvi8ssntsVajdkuom2OvLZoo74uZ0twQpJx73mGN8tgvLQfwv2GdkvTBzLiaj 5 | QUMOQTMrWQPr4gtTnwIDAQAB 6 | -----END PUBLIC KEY----- 7 | -------------------------------------------------------------------------------- /RSADemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // RSADemo 4 | // 5 | // Created by Lancy on 24/4/13. 6 | // Copyright (c) 2013 GraceLancy. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "GLAppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([GLAppDelegate class])); 17 | } 18 | } 19 | --------------------------------------------------------------------------------