Make use of class extensions.

This commit is contained in:
Jonathan Schleifer 2011-03-21 18:05:35 +01:00
parent 88b1e827a8
commit b836831b03
3 changed files with 343 additions and 320 deletions

View file

@ -103,10 +103,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4BC5599B1337A65400E345C7 /* Supporting Files */, 4BC5599B1337A65400E345C7 /* Supporting Files */,
4BC559FD1337AC1800E345C7 /* XMPPSCRAMAuth.m */,
4BC559FE1337AC1800E345C7 /* XMPPStanza.h */,
4BC559FF1337AC1800E345C7 /* XMPPStanza.m */,
4BC559D91337AC0900E345C7 /* arc4random_uniform.m */,
4BC559DA1337AC0900E345C7 /* XMPPAuthenticator.h */, 4BC559DA1337AC0900E345C7 /* XMPPAuthenticator.h */,
4BC559DB1337AC0900E345C7 /* XMPPAuthenticator.m */, 4BC559DB1337AC0900E345C7 /* XMPPAuthenticator.m */,
4BC559DC1337AC0900E345C7 /* XMPPConnection.h */, 4BC559DC1337AC0900E345C7 /* XMPPConnection.h */,
@ -124,6 +120,10 @@
4BC559E81337AC0900E345C7 /* XMPPPresence.h */, 4BC559E81337AC0900E345C7 /* XMPPPresence.h */,
4BC559E91337AC0900E345C7 /* XMPPPresence.m */, 4BC559E91337AC0900E345C7 /* XMPPPresence.m */,
4BC559EA1337AC0900E345C7 /* XMPPSCRAMAuth.h */, 4BC559EA1337AC0900E345C7 /* XMPPSCRAMAuth.h */,
4BC559FD1337AC1800E345C7 /* XMPPSCRAMAuth.m */,
4BC559FE1337AC1800E345C7 /* XMPPStanza.h */,
4BC559FF1337AC1800E345C7 /* XMPPStanza.m */,
4BC559D91337AC0900E345C7 /* arc4random_uniform.m */,
); );
path = ObjXMPP; path = ObjXMPP;
sourceTree = "<group>"; sourceTree = "<group>";

View file

@ -45,6 +45,19 @@
#define NS_SESSION @"urn:ietf:params:xml:ns:xmpp-session" #define NS_SESSION @"urn:ietf:params:xml:ns:xmpp-session"
#define NS_STREAM @"http://etherx.jabber.org/streams" #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 @implementation XMPPConnection
@synthesize username, password, server, resource, JID, port, useTLS, delegate; @synthesize username, password, server, resource, JID, port, useTLS, delegate;
@ -165,21 +178,13 @@
[old release]; [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 - (void)connect
{ {
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
[sock connectToHost: server [sock connectToHost: server
onPort: port]; onPort: port];
[self _startStream]; [self XMPP_startStream];
[pool release]; [pool release];
} }
@ -230,162 +235,6 @@
parser.delegate = elementBuilder; 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 - (void)elementBuilder: (OFXMLElementBuilder*)b
didBuildElement: (OFXMLElement*)elem didBuildElement: (OFXMLElement*)elem
{ {
@ -397,18 +246,18 @@
if ([elem.namespace isEqual: NS_CLIENT]) { if ([elem.namespace isEqual: NS_CLIENT]) {
if ([elem.name isEqual: @"iq"]) { if ([elem.name isEqual: @"iq"]) {
[self _handleIQ: [XMPPIQ stanzaWithElement: elem]]; [self XMPP_handleIQ: [XMPPIQ stanzaWithElement: elem]];
return; return;
} }
if ([elem.name isEqual: @"message"]) { if ([elem.name isEqual: @"message"]) {
[self _handleMessage: [self XMPP_handleMessage:
[XMPPMessage stanzaWithElement: elem]]; [XMPPMessage stanzaWithElement: elem]];
return; return;
} }
if ([elem.name isEqual: @"presence"]) { if ([elem.name isEqual: @"presence"]) {
[self _handlePresence: [self XMPP_handlePresence:
[XMPPPresence stanzaWithElement: elem]]; [XMPPPresence stanzaWithElement: elem]];
return; return;
} }
@ -418,7 +267,7 @@
if ([elem.namespace isEqual: NS_STREAM]) { if ([elem.namespace isEqual: NS_STREAM]) {
if ([elem.name isEqual: @"features"]) { if ([elem.name isEqual: @"features"]) {
[self _handleFeatures: elem]; [self XMPP_handleFeatures: elem];
return; return;
} }
@ -432,7 +281,7 @@
/* Stream restart */ /* Stream restart */
parser.delegate = self; parser.delegate = self;
[self _startStream]; [self XMPP_startStream];
return; return;
} }
@ -474,7 +323,7 @@
/* Stream restart */ /* Stream restart */
parser.delegate = self; parser.delegate = self;
[self _startStream]; [self XMPP_startStream];
return; return;
} }
@ -500,4 +349,168 @@
{ {
// TODO // 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 @end

View file

@ -33,6 +33,15 @@
extern uint32_t arc4random_uniform(uint32_t); extern uint32_t arc4random_uniform(uint32_t);
#endif #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 @implementation XMPPSCRAMAuth
+ SCRAMAuthWithAuthcid: (OFString*)authcid + SCRAMAuthWithAuthcid: (OFString*)authcid
password: (OFString*)password password: (OFString*)password
@ -122,135 +131,6 @@ extern uint32_t arc4random_uniform(uint32_t);
[old release]; [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*)clientFirstMessage
{ {
OFDataArray *ret = [OFDataArray dataArrayWithItemSize: 1]; OFDataArray *ret = [OFDataArray dataArrayWithItemSize: 1];
@ -259,19 +139,20 @@ extern uint32_t arc4random_uniform(uint32_t);
GS2Header = nil; GS2Header = nil;
if (authzid) if (authzid)
GS2Header = [[OFString alloc] GS2Header = [[OFString alloc] initWithFormat: @"n,a=%@,",
initWithFormat: @"n,a=%@,", authzid]; authzid];
else else
GS2Header = @"n,,"; GS2Header = @"n,,";
[cNonce release]; [cNonce release];
cNonce = nil; cNonce = nil;
cNonce = [[self _genNonce] retain]; cNonce = [[self XMPP_genNonce] retain];
[clientFirstMessageBare release]; [clientFirstMessageBare release];
clientFirstMessageBare = nil; clientFirstMessageBare = nil;
clientFirstMessageBare = [[OFString alloc] clientFirstMessageBare = [[OFString alloc] initWithFormat: @"n=%@,r=%@",
initWithFormat: @"n=%@,r=%@", authcid, cNonce]; authcid,
cNonce];
[ret addNItems: [GS2Header cStringLength] [ret addNItems: [GS2Header cStringLength]
fromCArray: [GS2Header cString]]; fromCArray: [GS2Header cString]];
@ -345,9 +226,9 @@ extern uint32_t arc4random_uniform(uint32_t);
* IETF RFC 5802: * IETF RFC 5802:
* SaltedPassword := Hi(Normalize(password), salt, i) * SaltedPassword := Hi(Normalize(password), salt, i)
*/ */
saltedPassword = [self _hiWithData: tmpArray saltedPassword = [self XMPP_hiWithData: tmpArray
salt: salt salt: salt
iterationCount: iterCount]; iterationCount: iterCount];
/* /*
* IETF RFC 5802: * IETF RFC 5802:
@ -371,8 +252,8 @@ extern uint32_t arc4random_uniform(uint32_t);
tmpArray = [OFDataArray dataArrayWithItemSize: 1]; tmpArray = [OFDataArray dataArrayWithItemSize: 1];
[tmpArray addNItems: 10 [tmpArray addNItems: 10
fromCArray: "Client Key"]; fromCArray: "Client Key"];
clientKey = [self _HMACWithKey: saltedPassword clientKey = [self XMPP_HMACWithKey: saltedPassword
data: tmpArray]; data: tmpArray];
/* /*
* IETF RFC 5802: * IETF RFC 5802:
@ -388,8 +269,8 @@ extern uint32_t arc4random_uniform(uint32_t);
* IETF RFC 5802: * IETF RFC 5802:
* ClientSignature := HMAC(StoredKey, AuthMessage) * ClientSignature := HMAC(StoredKey, AuthMessage)
*/ */
clientSignature = [self _HMACWithKey: tmpArray clientSignature = [self XMPP_HMACWithKey: tmpArray
data: authMessage]; data: authMessage];
/* /*
* IETF RFC 5802: * IETF RFC 5802:
@ -398,8 +279,8 @@ extern uint32_t arc4random_uniform(uint32_t);
tmpArray = [OFDataArray dataArrayWithItemSize: 1]; tmpArray = [OFDataArray dataArrayWithItemSize: 1];
[tmpArray addNItems: 10 [tmpArray addNItems: 10
fromCArray: "Server Key"]; fromCArray: "Server Key"];
serverKey = [self _HMACWithKey: saltedPassword serverKey = [self XMPP_HMACWithKey: saltedPassword
data: tmpArray]; data: tmpArray];
/* /*
* IETF RFC 5802: * IETF RFC 5802:
@ -410,8 +291,8 @@ extern uint32_t arc4random_uniform(uint32_t);
fromCArray: serverKey]; fromCArray: serverKey];
serverSignature = [[OFDataArray alloc] initWithItemSize: 1]; serverSignature = [[OFDataArray alloc] initWithItemSize: 1];
[serverSignature addNItems: [hashType digestSize] [serverSignature addNItems: [hashType digestSize]
fromCArray: [self _HMACWithKey: tmpArray fromCArray: [self XMPP_HMACWithKey: tmpArray
data: authMessage]]; data: authMessage]];
/* /*
* IETF RFC 5802: * IETF RFC 5802:
@ -459,4 +340,133 @@ extern uint32_t arc4random_uniform(uint32_t);
[pool release]; [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 @end