I’ve been googled for few days and struggling on “How to decrypt cipher text in iOS”, unfortunately there is no solution were found.

Then I decided to do it with C language rather than Objective-C, and I found a library for openssl that could be included to Xcode.

Step 1: Install the library

Download the library, unzip it then drag the lib and include folders to your xcode project. Make sure the Build Settings -> Header Search Paths you have set properly (i.e. “${SRCROOT}/Libraries/openssl/include”)

Step 2: Add private key

Just drag your private key in pem format to xcode project.

If your private key is in binary form, you may refer here.

Step 3: Create a custom class

Create a new class (subclass of NSObject), just named it Crypto

Crypto.h

1
2
3
4
5
6
7
#import <Foundation/Foundation.h>

@interface Crypto : NSObject

- (NSString *)decryptFromCipherText:(NSString *)cipherText;

@end

Crypto.m

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>

#import "Crypto.h"

@interface Crypto ()

@property (nonatomic, strong) NSString *privateKeyPath;

@end

@implementation Crypto

@synthesize privateKeyPath = _privateKeyPath;

- (id)init
{
if ((self = [super init])) {
// assume the file name is private_key.pem
self.privateKeyPath = [[NSBundle mainBundle] pathForResource:@"private_key"
ofType:@"pem"];
}
return self;
}

- (NSString *)decryptFromCipherText:(NSString *)cipherText
{
RSA *rsa_privateKey = NULL;
FILE *fp_privateKey;
int rsa_private_len;

// read the private key file
if ((fp_privateKey = fopen([self.privateKeyPath UTF8String], "r")) == NULL) {
NSLog(@"Could not open %@", self.privateKeyPath);
return nil;
}

if ((rsa_privateKey = PEM_read_RSAPrivateKey(fp_privateKey, NULL, NULL, NULL)) == NULL)
{
NSLog(@"Error loading RSA Private Key File.");
return nil;
}
fclose(fp_privateKey);

rsa_private_len = RSA_size(rsa_privateKey);

// make sure you decode the base64 string
NSData *decodedData = [Crypto base64DataFromString:cipherText];

// plain text will be stored in this variable
char *decrypted = (unsigned char *)malloc(rsa_private_len - 1);
char *err = NULL;
if (RSA_private_decrypt([decodedData length], [decodedData bytes], decrypted, rsa_privateKey, RSA_PKCS1_PADDING) == -1) {

ERR_load_CRYPTO_strings();
fprintf(stderr, "Error %s\n", ERR_error_string(ERR_get_error(), err));
fprintf(stderr, "Error %s\n", err);
return nil;
}
RSA_free(rsa_privateKey);

// convert the char* to NSString
return [NSString stringWithUTF8String:(char *)decrypted];
}

// decode the base64 string
+ (NSData *)base64DataFromString: (NSString *)string
{
unsigned long ixtext, lentext;
unsigned char ch, inbuf[4], outbuf[3];
short i, ixinbuf;
Boolean flignore, flendtext = false;
const unsigned char *tempcstring;
NSMutableData *theData;

if (string == nil)
{
return [NSData data];
}

ixtext = 0;

tempcstring = (const unsigned char *)[string UTF8String];

lentext = [string length];

theData = [NSMutableData dataWithCapacity: lentext];

ixinbuf = 0;

while (true)
{
if (ixtext >= lentext)
{
break;
}

ch = tempcstring [ixtext++];

flignore = false;

if ((ch >= 'A') && (ch <= 'Z'))
{
ch = ch - 'A';
}
else if ((ch >= 'a') && (ch <= 'z'))
{
ch = ch - 'a' + 26;
}
else if ((ch >= '0') && (ch <= '9'))
{
ch = ch - '0' + 52;
}
else if (ch == '+')
{
ch = 62;
}
else if (ch == '=')
{
flendtext = true;
}
else if (ch == '/')
{
ch = 63;
}
else
{
flignore = true;
}

if (!flignore)
{
short ctcharsinbuf = 3;
Boolean flbreak = false;

if (flendtext)
{
if (ixinbuf == 0)
{
break;
}

if ((ixinbuf == 1) || (ixinbuf == 2))
{
ctcharsinbuf = 1;
}
else
{
ctcharsinbuf = 2;
}

ixinbuf = 3;

flbreak = true;
}

inbuf [ixinbuf++] = ch;

if (ixinbuf == 4)
{
ixinbuf = 0;

outbuf[0] = (inbuf[0] << 2) | ((inbuf[1] & 0x30) >> 4);
outbuf[1] = ((inbuf[1] & 0x0F) << 4) | ((inbuf[2] & 0x3C) >> 2);
outbuf[2] = ((inbuf[2] & 0x03) << 6) | (inbuf[3] & 0x3F);

for (i = 0; i < ctcharsinbuf; i++)
{
[theData appendBytes: &outbuf[i] length: 1];
}
}

if (flbreak)
{
break;
}
}
}

return theData;
}
@end

Step 4: Usage

Refer to my previous blog, encrypt it and get the cipher text, so that you can test here.

1
2
Crypto *crypto = [[Crypto alloc] init];
NSString *plainText = [crypto decryptFromCipherText:@"Your base64 encoded cipher text here"];

Update Dec 24, 2014

You can use my library RSA-objc, and the instructions is inside.