-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
XMPPDigestAuthentication.m
182 lines (145 loc) · 4.91 KB
/
XMPPDigestAuthentication.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
//
// XMPPDigestAuthentication.m
// iPhoneXMPP
//
// Created by Eric Chamberlain on 10/1/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "XMPPDigestAuthentication.h"
#import "NSData+XMPP.h"
#import "XMPPLogging.h"
#import "XMPPStream.h"
// Log levels: off, error, warn, info, verbose
#if DEBUG
static const int xmppLogLevel = XMPP_LOG_LEVEL_INFO | XMPP_LOG_FLAG_SEND_RECV; // | XMPP_LOG_FLAG_TRACE;
#else
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
#endif
@implementation XMPPDigestAuthentication
- (id)initWithChallenge:(NSXMLElement *)challenge
{
if((self = [super init]))
{
// Convert the base 64 encoded data into a string
NSData *base64Data = [[challenge stringValue] dataUsingEncoding:NSASCIIStringEncoding];
NSData *decodedData = [base64Data base64Decoded];
NSString *authStr = [[[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding] autorelease];
XMPPLogVerbose(@"%@: Decoded challenge: %@", THIS_FILE, authStr);
// Extract all the key=value pairs, and put them in a dictionary for easy lookup
NSMutableDictionary *auth = [NSMutableDictionary dictionaryWithCapacity:5];
NSArray *components = [authStr componentsSeparatedByString:@","];
int i;
for(i = 0; i < [components count]; i++)
{
NSString *component = [components objectAtIndex:i];
NSRange separator = [component rangeOfString:@"="];
if(separator.location != NSNotFound)
{
NSMutableString *key = [[component substringToIndex:separator.location] mutableCopy];
NSMutableString *value = [[component substringFromIndex:separator.location+1] mutableCopy];
if(key) CFStringTrimWhitespace((CFMutableStringRef)key);
if(value) CFStringTrimWhitespace((CFMutableStringRef)value);
if([value hasPrefix:@"\""] && [value hasSuffix:@"\""] && [value length] > 2)
{
// Strip quotes from value
[value deleteCharactersInRange:NSMakeRange(0, 1)];
[value deleteCharactersInRange:NSMakeRange([value length]-1, 1)];
}
[auth setObject:value forKey:key];
[value release];
[key release];
}
}
// Extract and retain the elements we need
rspauth = [[auth objectForKey:@"rspauth"] copy];
realm = [[auth objectForKey:@"realm"] copy];
nonce = [[auth objectForKey:@"nonce"] copy];
qop = [[auth objectForKey:@"qop"] copy];
// Generate cnonce
cnonce = [[XMPPStream generateUUID] retain];
}
return self;
}
- (void)dealloc
{
[rspauth release];
[realm release];
[nonce release];
[qop release];
[username release];
[password release];
[cnonce release];
[nc release];
[digestURI release];
[super dealloc];
}
- (NSString *)rspauth
{
return [[rspauth copy] autorelease];
}
- (NSString *)realm
{
return [[realm copy] autorelease];
}
- (void)setRealm:(NSString *)newRealm
{
if(![realm isEqual:newRealm])
{
[realm release];
realm = [newRealm copy];
}
}
- (void)setDigestURI:(NSString *)newDigestURI
{
if(![digestURI isEqual:newDigestURI])
{
[digestURI release];
digestURI = [newDigestURI copy];
}
}
- (void)setUsername:(NSString *)newUsername password:(NSString *)newPassword
{
if(![username isEqual:newUsername])
{
[username release];
username = [newUsername copy];
}
if(![password isEqual:newPassword])
{
[password release];
password = [newPassword copy];
}
}
- (NSString *)response
{
NSString *HA1str = [NSString stringWithFormat:@"%@:%@:%@", username, realm, password];
NSString *HA2str = [NSString stringWithFormat:@"AUTHENTICATE:%@", digestURI];
NSData *HA1dataA = [[HA1str dataUsingEncoding:NSUTF8StringEncoding] md5Digest];
NSData *HA1dataB = [[NSString stringWithFormat:@":%@:%@", nonce, cnonce] dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *HA1data = [NSMutableData dataWithCapacity:([HA1dataA length] + [HA1dataB length])];
[HA1data appendData:HA1dataA];
[HA1data appendData:HA1dataB];
NSString *HA1 = [[HA1data md5Digest] hexStringValue];
NSString *HA2 = [[[HA2str dataUsingEncoding:NSUTF8StringEncoding] md5Digest] hexStringValue];
NSString *responseStr = [NSString stringWithFormat:@"%@:%@:00000001:%@:auth:%@",
HA1, nonce, cnonce, HA2];
NSString *response = [[[responseStr dataUsingEncoding:NSUTF8StringEncoding] md5Digest] hexStringValue];
return response;
}
- (NSString *)base64EncodedFullResponse
{
NSMutableString *buffer = [NSMutableString stringWithCapacity:100];
[buffer appendFormat:@"username=\"%@\",", username];
[buffer appendFormat:@"realm=\"%@\",", realm];
[buffer appendFormat:@"nonce=\"%@\",", nonce];
[buffer appendFormat:@"cnonce=\"%@\",", cnonce];
[buffer appendFormat:@"nc=00000001,"];
[buffer appendFormat:@"qop=auth,"];
[buffer appendFormat:@"digest-uri=\"%@\",", digestURI];
[buffer appendFormat:@"response=%@,", [self response]];
[buffer appendFormat:@"charset=utf-8"];
XMPPLogSend(@"decoded response: %@", buffer);
NSData *utf8data = [buffer dataUsingEncoding:NSUTF8StringEncoding];
return [utf8data base64Encoded];
}
@end