Make use of class extensions.
This commit is contained in:
parent
88b1e827a8
commit
b836831b03
3 changed files with 343 additions and 320 deletions
|
@ -103,10 +103,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
4BC5599B1337A65400E345C7 /* Supporting Files */,
|
||||
4BC559FD1337AC1800E345C7 /* XMPPSCRAMAuth.m */,
|
||||
4BC559FE1337AC1800E345C7 /* XMPPStanza.h */,
|
||||
4BC559FF1337AC1800E345C7 /* XMPPStanza.m */,
|
||||
4BC559D91337AC0900E345C7 /* arc4random_uniform.m */,
|
||||
4BC559DA1337AC0900E345C7 /* XMPPAuthenticator.h */,
|
||||
4BC559DB1337AC0900E345C7 /* XMPPAuthenticator.m */,
|
||||
4BC559DC1337AC0900E345C7 /* XMPPConnection.h */,
|
||||
|
@ -124,6 +120,10 @@
|
|||
4BC559E81337AC0900E345C7 /* XMPPPresence.h */,
|
||||
4BC559E91337AC0900E345C7 /* XMPPPresence.m */,
|
||||
4BC559EA1337AC0900E345C7 /* XMPPSCRAMAuth.h */,
|
||||
4BC559FD1337AC1800E345C7 /* XMPPSCRAMAuth.m */,
|
||||
4BC559FE1337AC1800E345C7 /* XMPPStanza.h */,
|
||||
4BC559FF1337AC1800E345C7 /* XMPPStanza.m */,
|
||||
4BC559D91337AC0900E345C7 /* arc4random_uniform.m */,
|
||||
);
|
||||
path = ObjXMPP;
|
||||
sourceTree = "<group>";
|
||||
|
|
|
@ -45,6 +45,19 @@
|
|||
#define NS_SESSION @"urn:ietf:params:xml:ns:xmpp-session"
|
||||
#define NS_STREAM @"http://etherx.jabber.org/streams"
|
||||
|
||||
@interface XMPPConnection ()
|
||||
- (void)XMPP_startStream;
|
||||
- (void)XMPP_sendAuth: (OFString*)name;
|
||||
- (void)XMPP_sendResourceBind;
|
||||
- (void)XMPP_sendSession;
|
||||
- (void)XMPP_handleResourceBind: (XMPPIQ*)iq;
|
||||
- (void)XMPP_handleSession;
|
||||
- (void)XMPP_handleFeatures: (OFXMLElement*)elem;
|
||||
- (void)XMPP_handleIQ: (XMPPIQ*)iq;
|
||||
- (void)XMPP_handleMessage: (XMPPMessage*)msg;
|
||||
- (void)XMPP_handlePresence: (XMPPPresence*)pres;
|
||||
@end
|
||||
|
||||
@implementation XMPPConnection
|
||||
@synthesize username, password, server, resource, JID, port, useTLS, delegate;
|
||||
|
||||
|
@ -165,21 +178,13 @@
|
|||
[old release];
|
||||
}
|
||||
|
||||
- (void)_startStream
|
||||
{
|
||||
[sock writeFormat: @"<?xml version='1.0'?>\n"
|
||||
@"<stream:stream to='%@' xmlns='" NS_CLIENT @"' "
|
||||
@"xmlns:stream='" NS_STREAM @"' "
|
||||
@"version='1.0'>", server];
|
||||
}
|
||||
|
||||
- (void)connect
|
||||
{
|
||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||
|
||||
[sock connectToHost: server
|
||||
onPort: port];
|
||||
[self _startStream];
|
||||
[self XMPP_startStream];
|
||||
|
||||
[pool release];
|
||||
}
|
||||
|
@ -230,162 +235,6 @@
|
|||
parser.delegate = elementBuilder;
|
||||
}
|
||||
|
||||
- (void)_sendAuth: (OFString*)name
|
||||
{
|
||||
OFXMLElement *authTag;
|
||||
|
||||
authTag = [OFXMLElement elementWithName: @"auth"
|
||||
namespace: NS_SASL];
|
||||
[authTag addAttributeWithName: @"mechanism"
|
||||
stringValue: name];
|
||||
[authTag addChild: [OFXMLElement elementWithCharacters:
|
||||
[[authModule clientFirstMessage] stringByBase64Encoding]]];
|
||||
|
||||
[self sendStanza: authTag];
|
||||
}
|
||||
|
||||
- (void)_sendResourceBind
|
||||
{
|
||||
XMPPIQ *iq = [XMPPIQ IQWithType: @"set"
|
||||
ID: @"bind0"];
|
||||
OFXMLElement *bind = [OFXMLElement elementWithName: @"bind"
|
||||
namespace: NS_BIND];
|
||||
if (resource)
|
||||
[bind addChild: [OFXMLElement elementWithName: @"resource"
|
||||
stringValue: resource]];
|
||||
[iq addChild: bind];
|
||||
|
||||
[self sendStanza: iq];
|
||||
}
|
||||
|
||||
- (void)_sendSession
|
||||
{
|
||||
XMPPIQ *iq = [XMPPIQ IQWithType: @"set"
|
||||
ID: @"session0"];
|
||||
[iq addChild: [OFXMLElement elementWithName: @"session"
|
||||
namespace: NS_SESSION]];
|
||||
[self sendStanza: iq];
|
||||
}
|
||||
|
||||
- (void)_handleResourceBind: (XMPPIQ*)iq
|
||||
{
|
||||
OFXMLElement *bindElem = iq.children.firstObject;
|
||||
OFXMLElement *jidElem;
|
||||
|
||||
if (![bindElem.name isEqual: @"bind"] ||
|
||||
![bindElem.namespace isEqual: NS_BIND])
|
||||
assert(0);
|
||||
|
||||
jidElem = bindElem.children.firstObject;
|
||||
JID = [[XMPPJID alloc] initWithString:
|
||||
[jidElem.children.firstObject stringValue]];
|
||||
|
||||
if (needsSession) {
|
||||
[self _sendSession];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([delegate respondsToSelector: @selector(connection:wasBoundToJID:)])
|
||||
[delegate connection: self
|
||||
wasBoundToJID: JID];
|
||||
}
|
||||
|
||||
- (void)_handleSession
|
||||
{
|
||||
if ([delegate respondsToSelector: @selector(connection:wasBoundToJID:)])
|
||||
[delegate connection: self
|
||||
wasBoundToJID: JID];
|
||||
}
|
||||
|
||||
- (void)_handleFeatures: (OFXMLElement*)elem
|
||||
{
|
||||
OFXMLElement *starttls = [elem
|
||||
elementsForName: @"starttls"
|
||||
namespace: NS_STARTTLS].firstObject;
|
||||
OFXMLElement *bind = [elem elementsForName: @"bind"
|
||||
namespace: NS_BIND].firstObject;
|
||||
OFXMLElement *session = [elem elementsForName: @"session"
|
||||
namespace: NS_SESSION].firstObject;
|
||||
OFArray *mechs = [elem elementsForName: @"mechanisms"
|
||||
namespace: NS_SASL];
|
||||
OFMutableArray *mechanisms = [OFMutableArray array];
|
||||
|
||||
if (starttls != nil) {
|
||||
[self sendStanza: [OFXMLElement elementWithName: @"starttls"
|
||||
namespace: NS_STARTTLS]];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([mechs count] > 0) {
|
||||
for (OFXMLElement *mech in [mechs.firstObject children])
|
||||
[mechanisms addObject:
|
||||
[mech.children.firstObject stringValue]];
|
||||
|
||||
if ([mechanisms containsObject: @"SCRAM-SHA-1"]) {
|
||||
authModule = [[XMPPSCRAMAuth alloc]
|
||||
initWithAuthcid: username
|
||||
password: password
|
||||
hash: [OFSHA1Hash class]];
|
||||
[self _sendAuth: @"SCRAM-SHA-1"];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([mechanisms containsObject: @"PLAIN"]) {
|
||||
authModule = [[XMPPPLAINAuth alloc]
|
||||
initWithAuthcid: username
|
||||
password: password];
|
||||
[self _sendAuth: @"PLAIN"];
|
||||
return;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (session != nil)
|
||||
needsSession = YES;
|
||||
|
||||
if (bind != nil) {
|
||||
[self _sendResourceBind];
|
||||
return;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
}
|
||||
|
||||
- (void)_handleIQ: (XMPPIQ*)iq
|
||||
{
|
||||
// FIXME: More checking!
|
||||
if ([iq.ID isEqual: @"bind0"] && [iq.type isEqual: @"result"]) {
|
||||
[self _handleResourceBind: iq];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([iq.ID isEqual: @"session0"] && [iq.type isEqual: @"result"]) {
|
||||
[self _handleSession];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([delegate respondsToSelector: @selector(connection:didReceiveIQ:)])
|
||||
[delegate connection: self
|
||||
didReceiveIQ: iq];
|
||||
}
|
||||
|
||||
- (void)_handleMessage: (XMPPMessage*)msg
|
||||
{
|
||||
if ([delegate respondsToSelector:
|
||||
@selector(connection:didReceiveMessage:)])
|
||||
[delegate connection: self
|
||||
didReceiveMessage: msg];
|
||||
}
|
||||
|
||||
- (void)_handlePresence: (XMPPPresence*)pres
|
||||
{
|
||||
if ([delegate respondsToSelector:
|
||||
@selector(connection:didReceivePresence:)])
|
||||
[delegate connection: self
|
||||
didReceivePresence: pres];
|
||||
}
|
||||
|
||||
- (void)elementBuilder: (OFXMLElementBuilder*)b
|
||||
didBuildElement: (OFXMLElement*)elem
|
||||
{
|
||||
|
@ -397,18 +246,18 @@
|
|||
|
||||
if ([elem.namespace isEqual: NS_CLIENT]) {
|
||||
if ([elem.name isEqual: @"iq"]) {
|
||||
[self _handleIQ: [XMPPIQ stanzaWithElement: elem]];
|
||||
[self XMPP_handleIQ: [XMPPIQ stanzaWithElement: elem]];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([elem.name isEqual: @"message"]) {
|
||||
[self _handleMessage:
|
||||
[self XMPP_handleMessage:
|
||||
[XMPPMessage stanzaWithElement: elem]];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([elem.name isEqual: @"presence"]) {
|
||||
[self _handlePresence:
|
||||
[self XMPP_handlePresence:
|
||||
[XMPPPresence stanzaWithElement: elem]];
|
||||
return;
|
||||
}
|
||||
|
@ -418,7 +267,7 @@
|
|||
|
||||
if ([elem.namespace isEqual: NS_STREAM]) {
|
||||
if ([elem.name isEqual: @"features"]) {
|
||||
[self _handleFeatures: elem];
|
||||
[self XMPP_handleFeatures: elem];
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -432,7 +281,7 @@
|
|||
|
||||
/* Stream restart */
|
||||
parser.delegate = self;
|
||||
[self _startStream];
|
||||
[self XMPP_startStream];
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -474,7 +323,7 @@
|
|||
|
||||
/* Stream restart */
|
||||
parser.delegate = self;
|
||||
[self _startStream];
|
||||
[self XMPP_startStream];
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -500,4 +349,168 @@
|
|||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
- (void)XMPP_startStream
|
||||
{
|
||||
[sock writeFormat: @"<?xml version='1.0'?>\n"
|
||||
@"<stream:stream to='%@' xmlns='" NS_CLIENT @"' "
|
||||
@"xmlns:stream='" NS_STREAM @"' "
|
||||
@"version='1.0'>", server];
|
||||
}
|
||||
|
||||
- (void)XMPP_handleIQ: (XMPPIQ*)iq
|
||||
{
|
||||
// FIXME: More checking!
|
||||
if ([iq.ID isEqual: @"bind0"] && [iq.type isEqual: @"result"]) {
|
||||
[self XMPP_handleResourceBind: iq];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([iq.ID isEqual: @"session0"] && [iq.type isEqual: @"result"]) {
|
||||
[self XMPP_handleSession];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([delegate respondsToSelector: @selector(connection:didReceiveIQ:)])
|
||||
[delegate connection: self
|
||||
didReceiveIQ: iq];
|
||||
}
|
||||
|
||||
- (void)XMPP_handleMessage: (XMPPMessage*)msg
|
||||
{
|
||||
if ([delegate respondsToSelector:
|
||||
@selector(connection:didReceiveMessage:)])
|
||||
[delegate connection: self
|
||||
didReceiveMessage: msg];
|
||||
}
|
||||
|
||||
- (void)XMPP_handlePresence: (XMPPPresence*)pres
|
||||
{
|
||||
if ([delegate respondsToSelector:
|
||||
@selector(connection:didReceivePresence:)])
|
||||
[delegate connection: self
|
||||
didReceivePresence: pres];
|
||||
}
|
||||
|
||||
- (void)XMPP_handleFeatures: (OFXMLElement*)elem
|
||||
{
|
||||
OFXMLElement *starttls =
|
||||
[elem elementsForName: @"starttls"
|
||||
namespace: NS_STARTTLS].firstObject;
|
||||
OFXMLElement *bind = [elem elementsForName: @"bind"
|
||||
namespace: NS_BIND].firstObject;
|
||||
OFXMLElement *session = [elem elementsForName: @"session"
|
||||
namespace: NS_SESSION].firstObject;
|
||||
OFArray *mechs = [elem elementsForName: @"mechanisms"
|
||||
namespace: NS_SASL];
|
||||
OFMutableArray *mechanisms = [OFMutableArray array];
|
||||
|
||||
if (starttls != nil) {
|
||||
[self sendStanza: [OFXMLElement elementWithName: @"starttls"
|
||||
namespace: NS_STARTTLS]];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([mechs count] > 0) {
|
||||
for (OFXMLElement *mech in [mechs.firstObject children])
|
||||
[mechanisms addObject:
|
||||
[mech.children.firstObject stringValue]];
|
||||
|
||||
if ([mechanisms containsObject: @"SCRAM-SHA-1"]) {
|
||||
authModule = [[XMPPSCRAMAuth alloc]
|
||||
initWithAuthcid: username
|
||||
password: password
|
||||
hash: [OFSHA1Hash class]];
|
||||
[self XMPP_sendAuth: @"SCRAM-SHA-1"];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([mechanisms containsObject: @"PLAIN"]) {
|
||||
authModule = [[XMPPPLAINAuth alloc]
|
||||
initWithAuthcid: username
|
||||
password: password];
|
||||
[self XMPP_sendAuth: @"PLAIN"];
|
||||
return;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (session != nil)
|
||||
needsSession = YES;
|
||||
|
||||
if (bind != nil) {
|
||||
[self XMPP_sendResourceBind];
|
||||
return;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
}
|
||||
|
||||
- (void)XMPP_sendAuth: (OFString*)name
|
||||
{
|
||||
OFXMLElement *authTag;
|
||||
|
||||
authTag = [OFXMLElement elementWithName: @"auth"
|
||||
namespace: NS_SASL];
|
||||
[authTag addAttributeWithName: @"mechanism"
|
||||
stringValue: name];
|
||||
[authTag addChild: [OFXMLElement elementWithCharacters:
|
||||
[[authModule clientFirstMessage] stringByBase64Encoding]]];
|
||||
|
||||
[self sendStanza: authTag];
|
||||
}
|
||||
|
||||
- (void)XMPP_sendResourceBind
|
||||
{
|
||||
XMPPIQ *iq = [XMPPIQ IQWithType: @"set"
|
||||
ID: @"bind0"];
|
||||
OFXMLElement *bind = [OFXMLElement elementWithName: @"bind"
|
||||
namespace: NS_BIND];
|
||||
if (resource)
|
||||
[bind addChild: [OFXMLElement elementWithName: @"resource"
|
||||
stringValue: resource]];
|
||||
[iq addChild: bind];
|
||||
|
||||
[self sendStanza: iq];
|
||||
}
|
||||
|
||||
- (void)XMPP_handleResourceBind: (XMPPIQ*)iq
|
||||
{
|
||||
OFXMLElement *bindElem = iq.children.firstObject;
|
||||
OFXMLElement *jidElem;
|
||||
|
||||
if (![bindElem.name isEqual: @"bind"] ||
|
||||
![bindElem.namespace isEqual: NS_BIND])
|
||||
assert(0);
|
||||
|
||||
jidElem = bindElem.children.firstObject;
|
||||
JID = [[XMPPJID alloc] initWithString:
|
||||
[jidElem.children.firstObject stringValue]];
|
||||
|
||||
if (needsSession) {
|
||||
[self XMPP_sendSession];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([delegate respondsToSelector: @selector(connection:wasBoundToJID:)])
|
||||
[delegate connection: self
|
||||
wasBoundToJID: JID];
|
||||
}
|
||||
|
||||
- (void)XMPP_sendSession
|
||||
{
|
||||
XMPPIQ *iq = [XMPPIQ IQWithType: @"set"
|
||||
ID: @"session0"];
|
||||
[iq addChild: [OFXMLElement elementWithName: @"session"
|
||||
namespace: NS_SESSION]];
|
||||
[self sendStanza: iq];
|
||||
}
|
||||
|
||||
- (void)XMPP_handleSession
|
||||
{
|
||||
if ([delegate respondsToSelector: @selector(connection:wasBoundToJID:)])
|
||||
[delegate connection: self
|
||||
wasBoundToJID: JID];
|
||||
}
|
||||
@end
|
||||
|
|
|
@ -33,6 +33,15 @@
|
|||
extern uint32_t arc4random_uniform(uint32_t);
|
||||
#endif
|
||||
|
||||
@interface XMPPSCRAMAuth ()
|
||||
- (OFString*)XMPP_genNonce;
|
||||
- (uint8_t*)XMPP_HMACWithKey: (OFDataArray*)key
|
||||
data: (OFDataArray*)data;
|
||||
- (OFDataArray*)XMPP_hiWithData: (OFDataArray *)str
|
||||
salt: (OFDataArray *)salt_
|
||||
iterationCount: (intmax_t)i;
|
||||
@end
|
||||
|
||||
@implementation XMPPSCRAMAuth
|
||||
+ SCRAMAuthWithAuthcid: (OFString*)authcid
|
||||
password: (OFString*)password
|
||||
|
@ -122,135 +131,6 @@ extern uint32_t arc4random_uniform(uint32_t);
|
|||
[old release];
|
||||
}
|
||||
|
||||
- (OFString*)_genNonce
|
||||
{
|
||||
OFMutableString *nonce = [OFMutableString string];
|
||||
uint32_t res, i;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
while ((res = arc4random_uniform('~' - '!' + 1) + '!') == ',');
|
||||
[nonce appendFormat: @"%c", res];
|
||||
}
|
||||
|
||||
return nonce;
|
||||
}
|
||||
|
||||
- (uint8_t*)_HMACWithKey: (OFDataArray*)key
|
||||
data: (OFDataArray*)data
|
||||
{
|
||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||
OFDataArray *k = [OFDataArray dataArrayWithItemSize: 1];
|
||||
size_t i, kSize, blockSize = [hashType blockSize];
|
||||
uint8_t *kCArray, *kI = NULL, *kO = NULL;
|
||||
OFHash *hash;
|
||||
|
||||
if (key.itemSize * key.count > blockSize) {
|
||||
hash = [[[hashType alloc] init] autorelease];
|
||||
[hash updateWithBuffer: [key cArray]
|
||||
ofSize: key.itemSize * key.count];
|
||||
[k addNItems: [hashType digestSize]
|
||||
fromCArray: [hash digest]];
|
||||
} else
|
||||
[k addNItems: key.itemSize * key.count
|
||||
fromCArray: [key cArray]];
|
||||
|
||||
@try {
|
||||
kI = [self allocMemoryWithSize: blockSize * sizeof(uint8_t)];
|
||||
memset(kI, HMAC_IPAD, blockSize * sizeof(uint8_t));
|
||||
|
||||
kO = [self allocMemoryWithSize: blockSize * sizeof(uint8_t)];
|
||||
memset(kO, HMAC_OPAD, blockSize * sizeof(uint8_t));
|
||||
|
||||
kCArray = [k cArray];
|
||||
kSize = k.count;
|
||||
for (i = 0; i < kSize; i++) {
|
||||
kI[i] ^= kCArray[i];
|
||||
kO[i] ^= kCArray[i];
|
||||
}
|
||||
|
||||
k = [OFDataArray dataArrayWithItemSize: 1];
|
||||
[k addNItems: blockSize
|
||||
fromCArray: kI];
|
||||
[k addNItems: data.itemSize * data.count
|
||||
fromCArray: [data cArray]];
|
||||
|
||||
hash = [[[hashType alloc] init] autorelease];
|
||||
[hash updateWithBuffer: [k cArray]
|
||||
ofSize: k.count];
|
||||
k = [OFDataArray dataArrayWithItemSize: 1];
|
||||
[k addNItems: blockSize
|
||||
fromCArray: kO];
|
||||
[k addNItems: [hashType digestSize]
|
||||
fromCArray: [hash digest]];
|
||||
} @finally {
|
||||
[self freeMemory: kI];
|
||||
[self freeMemory: kO];
|
||||
}
|
||||
|
||||
hash = [[[hashType alloc] init] autorelease];
|
||||
[hash updateWithBuffer: [k cArray]
|
||||
ofSize: k.count];
|
||||
|
||||
[hash retain];
|
||||
[pool release];
|
||||
|
||||
return [hash digest];
|
||||
}
|
||||
|
||||
- (OFDataArray*)_hiWithData: (OFDataArray *)str
|
||||
salt: (OFDataArray *)salt_
|
||||
iterationCount: (intmax_t)i
|
||||
{
|
||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||
size_t digestSize = [hashType digestSize];
|
||||
uint8_t *result = NULL, *u, *uOld;
|
||||
intmax_t j, k;
|
||||
OFDataArray *salty, *tmp, *ret;
|
||||
|
||||
result = [self allocMemoryWithSize: digestSize];
|
||||
|
||||
@try {
|
||||
memset(result, 0, digestSize);
|
||||
|
||||
salty = [[salt_ copy] autorelease];
|
||||
[salty addNItems: 4
|
||||
fromCArray: "\0\0\0\1"];
|
||||
|
||||
uOld = [self _HMACWithKey: str
|
||||
data: salty];
|
||||
|
||||
for (j = 0; j < digestSize; j++)
|
||||
result[j] ^= uOld[j];
|
||||
|
||||
for (j = 0; j < i - 1; j++) {
|
||||
tmp = [OFDataArray dataArrayWithItemSize: 1];
|
||||
[tmp addNItems: digestSize
|
||||
fromCArray: uOld];
|
||||
|
||||
u = [self _HMACWithKey: str
|
||||
data: tmp];
|
||||
|
||||
for (k = 0; k < digestSize; k++)
|
||||
result[k] ^= u[k];
|
||||
|
||||
uOld = u;
|
||||
|
||||
[pool releaseObjects];
|
||||
}
|
||||
|
||||
ret = [OFDataArray dataArrayWithItemSize: 1];
|
||||
[ret addNItems: digestSize
|
||||
fromCArray: result];
|
||||
} @finally {
|
||||
[self freeMemory: result];
|
||||
}
|
||||
|
||||
[ret retain];
|
||||
[pool release];
|
||||
|
||||
return [ret autorelease];
|
||||
}
|
||||
|
||||
- (OFDataArray*)clientFirstMessage
|
||||
{
|
||||
OFDataArray *ret = [OFDataArray dataArrayWithItemSize: 1];
|
||||
|
@ -259,19 +139,20 @@ extern uint32_t arc4random_uniform(uint32_t);
|
|||
GS2Header = nil;
|
||||
|
||||
if (authzid)
|
||||
GS2Header = [[OFString alloc]
|
||||
initWithFormat: @"n,a=%@,", authzid];
|
||||
GS2Header = [[OFString alloc] initWithFormat: @"n,a=%@,",
|
||||
authzid];
|
||||
else
|
||||
GS2Header = @"n,,";
|
||||
|
||||
[cNonce release];
|
||||
cNonce = nil;
|
||||
cNonce = [[self _genNonce] retain];
|
||||
cNonce = [[self XMPP_genNonce] retain];
|
||||
|
||||
[clientFirstMessageBare release];
|
||||
clientFirstMessageBare = nil;
|
||||
clientFirstMessageBare = [[OFString alloc]
|
||||
initWithFormat: @"n=%@,r=%@", authcid, cNonce];
|
||||
clientFirstMessageBare = [[OFString alloc] initWithFormat: @"n=%@,r=%@",
|
||||
authcid,
|
||||
cNonce];
|
||||
|
||||
[ret addNItems: [GS2Header cStringLength]
|
||||
fromCArray: [GS2Header cString]];
|
||||
|
@ -345,7 +226,7 @@ extern uint32_t arc4random_uniform(uint32_t);
|
|||
* IETF RFC 5802:
|
||||
* SaltedPassword := Hi(Normalize(password), salt, i)
|
||||
*/
|
||||
saltedPassword = [self _hiWithData: tmpArray
|
||||
saltedPassword = [self XMPP_hiWithData: tmpArray
|
||||
salt: salt
|
||||
iterationCount: iterCount];
|
||||
|
||||
|
@ -371,7 +252,7 @@ extern uint32_t arc4random_uniform(uint32_t);
|
|||
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
||||
[tmpArray addNItems: 10
|
||||
fromCArray: "Client Key"];
|
||||
clientKey = [self _HMACWithKey: saltedPassword
|
||||
clientKey = [self XMPP_HMACWithKey: saltedPassword
|
||||
data: tmpArray];
|
||||
|
||||
/*
|
||||
|
@ -388,7 +269,7 @@ extern uint32_t arc4random_uniform(uint32_t);
|
|||
* IETF RFC 5802:
|
||||
* ClientSignature := HMAC(StoredKey, AuthMessage)
|
||||
*/
|
||||
clientSignature = [self _HMACWithKey: tmpArray
|
||||
clientSignature = [self XMPP_HMACWithKey: tmpArray
|
||||
data: authMessage];
|
||||
|
||||
/*
|
||||
|
@ -398,7 +279,7 @@ extern uint32_t arc4random_uniform(uint32_t);
|
|||
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
||||
[tmpArray addNItems: 10
|
||||
fromCArray: "Server Key"];
|
||||
serverKey = [self _HMACWithKey: saltedPassword
|
||||
serverKey = [self XMPP_HMACWithKey: saltedPassword
|
||||
data: tmpArray];
|
||||
|
||||
/*
|
||||
|
@ -410,7 +291,7 @@ extern uint32_t arc4random_uniform(uint32_t);
|
|||
fromCArray: serverKey];
|
||||
serverSignature = [[OFDataArray alloc] initWithItemSize: 1];
|
||||
[serverSignature addNItems: [hashType digestSize]
|
||||
fromCArray: [self _HMACWithKey: tmpArray
|
||||
fromCArray: [self XMPP_HMACWithKey: tmpArray
|
||||
data: authMessage]];
|
||||
|
||||
/*
|
||||
|
@ -459,4 +340,133 @@ extern uint32_t arc4random_uniform(uint32_t);
|
|||
|
||||
[pool release];
|
||||
}
|
||||
|
||||
- (OFString*)XMPP_genNonce
|
||||
{
|
||||
OFMutableString *nonce = [OFMutableString string];
|
||||
uint32_t res, i;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
while ((res = arc4random_uniform('~' - '!' + 1) + '!') == ',');
|
||||
[nonce appendFormat: @"%c", res];
|
||||
}
|
||||
|
||||
return nonce;
|
||||
}
|
||||
|
||||
- (uint8_t*)XMPP_HMACWithKey: (OFDataArray*)key
|
||||
data: (OFDataArray*)data
|
||||
{
|
||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||
OFDataArray *k = [OFDataArray dataArrayWithItemSize: 1];
|
||||
size_t i, kSize, blockSize = [hashType blockSize];
|
||||
uint8_t *kCArray, *kI = NULL, *kO = NULL;
|
||||
OFHash *hash;
|
||||
|
||||
if (key.itemSize * key.count > blockSize) {
|
||||
hash = [[[hashType alloc] init] autorelease];
|
||||
[hash updateWithBuffer: [key cArray]
|
||||
ofSize: key.itemSize * key.count];
|
||||
[k addNItems: [hashType digestSize]
|
||||
fromCArray: [hash digest]];
|
||||
} else
|
||||
[k addNItems: key.itemSize * key.count
|
||||
fromCArray: [key cArray]];
|
||||
|
||||
@try {
|
||||
kI = [self allocMemoryWithSize: blockSize * sizeof(uint8_t)];
|
||||
memset(kI, HMAC_IPAD, blockSize * sizeof(uint8_t));
|
||||
|
||||
kO = [self allocMemoryWithSize: blockSize * sizeof(uint8_t)];
|
||||
memset(kO, HMAC_OPAD, blockSize * sizeof(uint8_t));
|
||||
|
||||
kCArray = [k cArray];
|
||||
kSize = k.count;
|
||||
for (i = 0; i < kSize; i++) {
|
||||
kI[i] ^= kCArray[i];
|
||||
kO[i] ^= kCArray[i];
|
||||
}
|
||||
|
||||
k = [OFDataArray dataArrayWithItemSize: 1];
|
||||
[k addNItems: blockSize
|
||||
fromCArray: kI];
|
||||
[k addNItems: data.itemSize * data.count
|
||||
fromCArray: [data cArray]];
|
||||
|
||||
hash = [[[hashType alloc] init] autorelease];
|
||||
[hash updateWithBuffer: [k cArray]
|
||||
ofSize: k.count];
|
||||
k = [OFDataArray dataArrayWithItemSize: 1];
|
||||
[k addNItems: blockSize
|
||||
fromCArray: kO];
|
||||
[k addNItems: [hashType digestSize]
|
||||
fromCArray: [hash digest]];
|
||||
} @finally {
|
||||
[self freeMemory: kI];
|
||||
[self freeMemory: kO];
|
||||
}
|
||||
|
||||
hash = [[[hashType alloc] init] autorelease];
|
||||
[hash updateWithBuffer: [k cArray]
|
||||
ofSize: k.count];
|
||||
|
||||
[hash retain];
|
||||
[pool release];
|
||||
|
||||
return [hash digest];
|
||||
}
|
||||
|
||||
- (OFDataArray*)XMPP_hiWithData: (OFDataArray *)str
|
||||
salt: (OFDataArray *)salt_
|
||||
iterationCount: (intmax_t)i
|
||||
{
|
||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||
size_t digestSize = [hashType digestSize];
|
||||
uint8_t *result = NULL, *u, *uOld;
|
||||
intmax_t j, k;
|
||||
OFDataArray *salty, *tmp, *ret;
|
||||
|
||||
result = [self allocMemoryWithSize: digestSize];
|
||||
|
||||
@try {
|
||||
memset(result, 0, digestSize);
|
||||
|
||||
salty = [[salt_ copy] autorelease];
|
||||
[salty addNItems: 4
|
||||
fromCArray: "\0\0\0\1"];
|
||||
|
||||
uOld = [self XMPP_HMACWithKey: str
|
||||
data: salty];
|
||||
|
||||
for (j = 0; j < digestSize; j++)
|
||||
result[j] ^= uOld[j];
|
||||
|
||||
for (j = 0; j < i - 1; j++) {
|
||||
tmp = [OFDataArray dataArrayWithItemSize: 1];
|
||||
[tmp addNItems: digestSize
|
||||
fromCArray: uOld];
|
||||
|
||||
u = [self XMPP_HMACWithKey: str
|
||||
data: tmp];
|
||||
|
||||
for (k = 0; k < digestSize; k++)
|
||||
result[k] ^= u[k];
|
||||
|
||||
uOld = u;
|
||||
|
||||
[pool releaseObjects];
|
||||
}
|
||||
|
||||
ret = [OFDataArray dataArrayWithItemSize: 1];
|
||||
[ret addNItems: digestSize
|
||||
fromCArray: result];
|
||||
} @finally {
|
||||
[self freeMemory: result];
|
||||
}
|
||||
|
||||
[ret retain];
|
||||
[pool release];
|
||||
|
||||
return [ret autorelease];
|
||||
}
|
||||
@end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue