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;
|
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>";
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue