A little cleanup work. Still needs a configure script.
This commit is contained in:
parent
ba13fa3e3a
commit
c44fefa67c
5 changed files with 318 additions and 249 deletions
|
@ -1,6 +1,6 @@
|
||||||
all:
|
all:
|
||||||
objfw-compile -Wall --lib 0.0 -o objxmpp *.m \
|
objfw-compile -Wall --lib 0.0 -o objxmpp *.m \
|
||||||
`pkg-config --cflags --libs libidn libbsd`
|
`pkg-config --cflags --libs libidn`
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *.so *.dylib *.dll
|
rm -f *.o *.so *.dylib *.dll
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
password: (OFString*)password
|
password: (OFString*)password
|
||||||
{
|
{
|
||||||
return [[[self alloc] initWithAuthcid: authcid
|
return [[[self alloc] initWithAuthcid: authcid
|
||||||
password: password] autorelease];
|
password: password] autorelease];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ PLAINAuthWithAuthzid: (OFString*)authzid
|
+ PLAINAuthWithAuthzid: (OFString*)authzid
|
||||||
|
@ -36,23 +36,28 @@
|
||||||
password: (OFString*)password
|
password: (OFString*)password
|
||||||
{
|
{
|
||||||
return [[[self alloc] initWithAuthzid: authzid
|
return [[[self alloc] initWithAuthzid: authzid
|
||||||
authcid: authcid
|
authcid: authcid
|
||||||
password: password] autorelease];
|
password: password] autorelease];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (OFDataArray*)clientFirstMessage
|
- (OFDataArray*)clientFirstMessage
|
||||||
{
|
{
|
||||||
OFDataArray *message = [OFDataArray dataArrayWithItemSize: 1];
|
OFDataArray *message = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
|
|
||||||
/* authzid */
|
/* authzid */
|
||||||
if (authzid)
|
if (authzid)
|
||||||
[message addItem: authzid];
|
[message addItem: authzid];
|
||||||
|
|
||||||
/* separator */
|
/* separator */
|
||||||
[message addItem: ""];
|
[message addItem: ""];
|
||||||
|
|
||||||
/* authcid */
|
/* authcid */
|
||||||
[message addNItems: [authcid cStringLength]
|
[message addNItems: [authcid cStringLength]
|
||||||
fromCArray: [authcid cString]];
|
fromCArray: [authcid cString]];
|
||||||
|
|
||||||
/* separator */
|
/* separator */
|
||||||
[message addItem: ""];
|
[message addItem: ""];
|
||||||
|
|
||||||
/* passwd */
|
/* passwd */
|
||||||
[message addNItems: [password cStringLength]
|
[message addNItems: [password cStringLength]
|
||||||
fromCArray: [password cString]];
|
fromCArray: [password cString]];
|
||||||
|
@ -62,10 +67,10 @@
|
||||||
|
|
||||||
- (OFDataArray*)calculateResponseWithChallenge: (OFDataArray*)challenge
|
- (OFDataArray*)calculateResponseWithChallenge: (OFDataArray*)challenge
|
||||||
{
|
{
|
||||||
@throw [XMPPAuthFailedException
|
@throw [XMPPAuthFailedException newWithClass: isa
|
||||||
newWithClass: isa
|
connection: nil
|
||||||
connection: nil
|
reason: @"Received a challenge "
|
||||||
reason: @"Received a challenge during PLAIN auth"];
|
@"during PLAIN auth"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)parseServerFinalMessage: (OFDataArray*)message
|
- (void)parseServerFinalMessage: (OFDataArray*)message
|
||||||
|
|
|
@ -44,8 +44,8 @@
|
||||||
* \return A new autoreleased XMPPSCRAMAuth
|
* \return A new autoreleased XMPPSCRAMAuth
|
||||||
*/
|
*/
|
||||||
+ SCRAMAuthWithAuthcid: (OFString*)authcid
|
+ SCRAMAuthWithAuthcid: (OFString*)authcid
|
||||||
password: (OFString*)password
|
password: (OFString*)password
|
||||||
hash: (Class)hash;
|
hash: (Class)hash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new autoreleased XMPPSCRAMAuth with an authzid,
|
* Creates a new autoreleased XMPPSCRAMAuth with an authzid,
|
||||||
|
@ -58,9 +58,9 @@
|
||||||
* \return A new autoreleased XMPPSCRAMAuth
|
* \return A new autoreleased XMPPSCRAMAuth
|
||||||
*/
|
*/
|
||||||
+ SCRAMAuthWithAuthzid: (OFString*)authzid
|
+ SCRAMAuthWithAuthzid: (OFString*)authzid
|
||||||
authcid: (OFString*)authcid
|
authcid: (OFString*)authcid
|
||||||
password: (OFString*)password
|
password: (OFString*)password
|
||||||
hash: (Class)hash;
|
hash: (Class)hash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes an already allocated XMPPSCRAMAuth with an authcid and password.
|
* Initializes an already allocated XMPPSCRAMAuth with an authcid and password.
|
||||||
|
@ -72,7 +72,7 @@
|
||||||
*/
|
*/
|
||||||
- initWithAuthcid: (OFString*)authcid
|
- initWithAuthcid: (OFString*)authcid
|
||||||
password: (OFString*)password
|
password: (OFString*)password
|
||||||
hash: (Class)hash;
|
hash: (Class)hash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes an already allocated XMPPSCRAMAuth with a authzid,
|
* Initializes an already allocated XMPPSCRAMAuth with a authzid,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, Florian Zeitz <florob@babelmonkeys.de>
|
* Copyright (c) 2011, Florian Zeitz <florob@babelmonkeys.de>
|
||||||
|
* Copyright (c) 2011, Jonathan Schleifer <js@webkeks.org>
|
||||||
*
|
*
|
||||||
* https://webkeks.org/hg/objxmpp/
|
* https://webkeks.org/hg/objxmpp/
|
||||||
*
|
*
|
||||||
|
@ -21,10 +22,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <bsd/stdlib.h>
|
|
||||||
// FIXME: Remove this once libbsd includes arc4random_uniform() in it's headers
|
|
||||||
#define fake_arc4random_uniform(upper) \
|
|
||||||
((uint32_t) (arc4random() / (double) UINT32_MAX * upper))
|
|
||||||
|
|
||||||
#import "XMPPSCRAMAuth.h"
|
#import "XMPPSCRAMAuth.h"
|
||||||
#import "XMPPExceptions.h"
|
#import "XMPPExceptions.h"
|
||||||
|
@ -32,8 +29,11 @@
|
||||||
#define HMAC_IPAD 0x36
|
#define HMAC_IPAD 0x36
|
||||||
#define HMAC_OPAD 0x5c
|
#define HMAC_OPAD 0x5c
|
||||||
|
|
||||||
@implementation XMPPSCRAMAuth
|
#ifndef HAVE_ARC4RANDOM_UNIFORM
|
||||||
|
extern uint32_t arc4random_uniform(uint32_t);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@implementation XMPPSCRAMAuth
|
||||||
+ SCRAMAuthWithAuthcid: (OFString*)authcid
|
+ SCRAMAuthWithAuthcid: (OFString*)authcid
|
||||||
password: (OFString*)password
|
password: (OFString*)password
|
||||||
hash: (Class)hash;
|
hash: (Class)hash;
|
||||||
|
@ -93,14 +93,12 @@
|
||||||
OFString *old = authzid;
|
OFString *old = authzid;
|
||||||
|
|
||||||
if (authzid_) {
|
if (authzid_) {
|
||||||
OFMutableString *new = [[OFMutableString alloc]
|
OFMutableString *new = [[authzid_ mutableCopy] autorelease];
|
||||||
initWithString: authzid_];
|
|
||||||
[new replaceOccurrencesOfString: @"="
|
[new replaceOccurrencesOfString: @"="
|
||||||
withString: @"=3D"];
|
withString: @"=3D"];
|
||||||
[new replaceOccurrencesOfString: @","
|
[new replaceOccurrencesOfString: @","
|
||||||
withString: @"=2C"];
|
withString: @"=2C"];
|
||||||
authzid = [new copy];
|
authzid = [new retain];
|
||||||
[new release];
|
|
||||||
} else
|
} else
|
||||||
authzid = nil;
|
authzid = nil;
|
||||||
|
|
||||||
|
@ -112,54 +110,51 @@
|
||||||
OFString *old = authcid;
|
OFString *old = authcid;
|
||||||
|
|
||||||
if (authcid_) {
|
if (authcid_) {
|
||||||
OFMutableString *new = [[OFMutableString alloc]
|
OFMutableString *new = [[authcid_ mutableCopy] autorelease];
|
||||||
initWithString: authcid_];
|
|
||||||
[new replaceOccurrencesOfString: @"="
|
[new replaceOccurrencesOfString: @"="
|
||||||
withString: @"=3D"];
|
withString: @"=3D"];
|
||||||
[new replaceOccurrencesOfString: @","
|
[new replaceOccurrencesOfString: @","
|
||||||
withString: @"=2C"];
|
withString: @"=2C"];
|
||||||
authcid = [new copy];
|
authcid = [new retain];
|
||||||
[new release];
|
|
||||||
} else
|
} else
|
||||||
authcid = nil;
|
authcid = nil;
|
||||||
|
|
||||||
[old release];
|
[old release];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (OFString *)_genNonce
|
- (OFString*)_genNonce
|
||||||
{
|
{
|
||||||
OFMutableString *nonce = [OFMutableString string];
|
OFMutableString *nonce = [OFMutableString string];
|
||||||
uint32_t res, i;
|
uint32_t res, i;
|
||||||
|
|
||||||
for (i = 0; i < 64; i++) {
|
for (i = 0; i < 64; i++) {
|
||||||
while((res = fake_arc4random_uniform(0x5e) + 0x21) == 0x2C);
|
while ((res = arc4random_uniform('~' - '!' + 1) + '!') == ',');
|
||||||
[nonce appendFormat: @"%c", res];
|
[nonce appendFormat: @"%c", res];
|
||||||
}
|
}
|
||||||
|
|
||||||
return nonce;
|
return nonce;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (uint8_t *)_hmacWithKey: (OFDataArray*)key
|
- (uint8_t*)_HMACWithKey: (OFDataArray*)key
|
||||||
data: (OFDataArray*)data
|
data: (OFDataArray*)data
|
||||||
{
|
{
|
||||||
|
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||||
|
OFDataArray *k = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
size_t i, kSize, blockSize = [hashType blockSize];
|
size_t i, kSize, blockSize = [hashType blockSize];
|
||||||
uint8_t *kCArray = NULL, *kI = NULL, *kO = NULL;
|
uint8_t *kCArray, *kI = NULL, *kO = NULL;
|
||||||
OFAutoreleasePool *pool = nil;
|
OFHash *hash;
|
||||||
OFDataArray *k = nil;
|
|
||||||
OFHash *hash = nil;
|
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 {
|
@try {
|
||||||
pool = [[OFAutoreleasePool alloc] init];
|
|
||||||
k = [OFDataArray dataArrayWithItemSize: 1];
|
|
||||||
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]];
|
|
||||||
|
|
||||||
kI = [self allocMemoryWithSize: blockSize * sizeof(uint8_t)];
|
kI = [self allocMemoryWithSize: blockSize * sizeof(uint8_t)];
|
||||||
memset(kI, HMAC_IPAD, blockSize * sizeof(uint8_t));
|
memset(kI, HMAC_IPAD, blockSize * sizeof(uint8_t));
|
||||||
|
|
||||||
|
@ -177,7 +172,7 @@
|
||||||
[k addNItems: blockSize
|
[k addNItems: blockSize
|
||||||
fromCArray: kI];
|
fromCArray: kI];
|
||||||
[k addNItems: data.itemSize * data.count
|
[k addNItems: data.itemSize * data.count
|
||||||
fromCArray: [data cArray]];
|
fromCArray: [data cArray]];
|
||||||
|
|
||||||
hash = [[[hashType alloc] init] autorelease];
|
hash = [[[hashType alloc] init] autorelease];
|
||||||
[hash updateWithBuffer: [k cArray]
|
[hash updateWithBuffer: [k cArray]
|
||||||
|
@ -187,89 +182,94 @@
|
||||||
fromCArray: kO];
|
fromCArray: kO];
|
||||||
[k addNItems: [hashType digestSize]
|
[k addNItems: [hashType digestSize]
|
||||||
fromCArray: [hash digest]];
|
fromCArray: [hash digest]];
|
||||||
|
|
||||||
hash = [[[hashType alloc] init] autorelease];
|
|
||||||
[hash updateWithBuffer: [k cArray]
|
|
||||||
ofSize: k.count];
|
|
||||||
|
|
||||||
[hash retain];
|
|
||||||
[pool release];
|
|
||||||
pool = nil;
|
|
||||||
[hash autorelease];
|
|
||||||
|
|
||||||
return [hash digest];
|
|
||||||
} @finally {
|
} @finally {
|
||||||
[pool release];
|
|
||||||
[self freeMemory: kI];
|
[self freeMemory: kI];
|
||||||
[self freeMemory: kO];
|
[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
|
- (OFDataArray*)_hiWithData: (OFDataArray *)str
|
||||||
salt: (OFDataArray *)salt_
|
salt: (OFDataArray *)salt_
|
||||||
iterationCount: (unsigned int)i
|
iterationCount: (unsigned int)i
|
||||||
{
|
{
|
||||||
|
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||||
|
size_t digestSize = [hashType digestSize];
|
||||||
uint8_t *result = NULL, *u, *uOld;
|
uint8_t *result = NULL, *u, *uOld;
|
||||||
unsigned int j, k;
|
unsigned int j, k;
|
||||||
size_t digestSize;
|
|
||||||
OFAutoreleasePool *pool = nil;
|
|
||||||
OFDataArray *salty, *tmp, *ret;
|
OFDataArray *salty, *tmp, *ret;
|
||||||
|
|
||||||
|
result = [self allocMemoryWithSize: digestSize];
|
||||||
|
|
||||||
@try {
|
@try {
|
||||||
pool = [[OFAutoreleasePool alloc] init];
|
memset(result, 0, digestSize);
|
||||||
digestSize = [hashType digestSize];
|
|
||||||
result = [self
|
salty = [[salt_ copy] autorelease];
|
||||||
allocMemoryWithSize: digestSize * sizeof(uint8_t)];
|
|
||||||
memset(result, 0, digestSize * sizeof(uint8_t));
|
|
||||||
salty = [salt_ copy];
|
|
||||||
[salty addNItems: 4
|
[salty addNItems: 4
|
||||||
fromCArray: "\0\0\0\1"];
|
fromCArray: "\0\0\0\1"];
|
||||||
|
|
||||||
uOld = [self _hmacWithKey: str
|
uOld = [self _HMACWithKey: str
|
||||||
data: salty];
|
data: salty];
|
||||||
[salty release];
|
|
||||||
for (j = 0; j < digestSize; j++)
|
for (j = 0; j < digestSize; j++)
|
||||||
result[j] ^= uOld[j];
|
result[j] ^= uOld[j];
|
||||||
|
|
||||||
for (j = 0; j < i-1; j++) {
|
for (j = 0; j < i - 1; j++) {
|
||||||
tmp = [OFDataArray dataArrayWithItemSize: 1];
|
tmp = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
[tmp addNItems: digestSize
|
[tmp addNItems: digestSize
|
||||||
fromCArray: uOld];
|
fromCArray: uOld];
|
||||||
u = [self _hmacWithKey: str
|
|
||||||
|
u = [self _HMACWithKey: str
|
||||||
data: tmp];
|
data: tmp];
|
||||||
|
|
||||||
for (k = 0; k < digestSize; k++)
|
for (k = 0; k < digestSize; k++)
|
||||||
result[k] ^= u[k];
|
result[k] ^= u[k];
|
||||||
|
|
||||||
uOld = u;
|
uOld = u;
|
||||||
|
|
||||||
|
[pool releaseObjects];
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = [OFDataArray dataArrayWithItemSize: 1];
|
ret = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
[ret addNItems: digestSize
|
[ret addNItems: digestSize
|
||||||
fromCArray: result];
|
fromCArray: result];
|
||||||
|
|
||||||
[ret retain];
|
|
||||||
[pool release];
|
|
||||||
pool = nil;
|
|
||||||
|
|
||||||
return [ret autorelease];
|
|
||||||
} @finally {
|
} @finally {
|
||||||
[pool release];
|
|
||||||
[self freeMemory: result];
|
[self freeMemory: result];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ret retain];
|
||||||
|
[pool release];
|
||||||
|
|
||||||
|
return [ret autorelease];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (OFDataArray*)clientFirstMessage
|
- (OFDataArray*)clientFirstMessage
|
||||||
{
|
{
|
||||||
OFDataArray *ret = [OFDataArray dataArrayWithItemSize: 1];
|
OFDataArray *ret = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
|
|
||||||
[GS2Header release];
|
[GS2Header release];
|
||||||
|
GS2Header = nil;
|
||||||
|
|
||||||
if (authzid)
|
if (authzid)
|
||||||
GS2Header = [[OFString alloc]
|
GS2Header = [[OFString alloc]
|
||||||
initWithFormat: @"n,a=%@,", authzid];
|
initWithFormat: @"n,a=%@,", authzid];
|
||||||
else
|
else
|
||||||
GS2Header = [[OFString alloc] initWithFormat: @"n,,"];
|
GS2Header = @"n,,";
|
||||||
|
|
||||||
[cNonce release];
|
[cNonce release];
|
||||||
|
cNonce = nil;
|
||||||
cNonce = [[self _genNonce] retain];
|
cNonce = [[self _genNonce] retain];
|
||||||
|
|
||||||
[clientFirstMessageBare release];
|
[clientFirstMessageBare release];
|
||||||
|
clientFirstMessageBare = nil;
|
||||||
clientFirstMessageBare = [[OFString alloc]
|
clientFirstMessageBare = [[OFString alloc]
|
||||||
initWithFormat: @"n=%@,r=%@", authcid, cNonce];
|
initWithFormat: @"n=%@,r=%@", authcid, cNonce];
|
||||||
|
|
||||||
|
@ -292,183 +292,171 @@
|
||||||
OFString *tmpString, *sNonce;
|
OFString *tmpString, *sNonce;
|
||||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||||
|
|
||||||
@try {
|
hash = [[[hashType alloc] init] autorelease];
|
||||||
hash = [[[hashType alloc] init] autorelease];
|
ret = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
ret = [OFDataArray dataArrayWithItemSize: 1];
|
authMessage = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
authMessage = [OFDataArray dataArrayWithItemSize: 1];
|
|
||||||
|
|
||||||
OFString *chal = [OFString
|
OFString *chal = [OFString stringWithCString: [challenge cArray]
|
||||||
stringWithCString: [challenge cArray]
|
length: [challenge count] *
|
||||||
length:
|
[challenge itemSize]];
|
||||||
[challenge count] * [challenge itemSize]];
|
|
||||||
|
|
||||||
for (OFString *comp
|
for (OFString *comp in [chal componentsSeparatedByString: @","]) {
|
||||||
in [chal componentsSeparatedByString: @","]) {
|
OFString *entry = [comp substringFromIndex: 2
|
||||||
OFString *entry = [comp
|
toIndex: [comp length]];
|
||||||
substringFromIndex: 2
|
|
||||||
toIndex: [comp length]];
|
|
||||||
if ([comp hasPrefix: @"r="]) {
|
|
||||||
if (![entry hasPrefix: cNonce])
|
|
||||||
@throw [XMPPAuthFailedException
|
|
||||||
newWithClass: isa
|
|
||||||
connection: nil
|
|
||||||
reason:
|
|
||||||
@"Received wrong nonce"];
|
|
||||||
sNonce = entry;
|
|
||||||
} else if ([comp hasPrefix: @"s="])
|
|
||||||
salt = [OFDataArray
|
|
||||||
dataArrayWithBase64EncodedString: entry];
|
|
||||||
else if ([comp hasPrefix: @"i="])
|
|
||||||
iterCount = [entry decimalValue];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add c=<base64(GS2Header+channelBindingData)>
|
if ([comp hasPrefix: @"r="]) {
|
||||||
// XXX: No channel binding for now
|
if (![entry hasPrefix: cNonce])
|
||||||
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
@throw [XMPPAuthFailedException
|
||||||
[tmpArray addNItems: [GS2Header cStringLength]
|
newWithClass: isa
|
||||||
fromCArray: [GS2Header cString]];
|
connection: nil
|
||||||
tmpString = [tmpArray stringByBase64Encoding];
|
reason: @"Received wrong nonce"];
|
||||||
[ret addNItems: 2
|
|
||||||
fromCArray: "c="];
|
|
||||||
[ret addNItems: [tmpString cStringLength]
|
|
||||||
fromCArray: [tmpString cString]];
|
|
||||||
|
|
||||||
// Add r=<nonce>
|
sNonce = entry;
|
||||||
[ret addItem: ","];
|
} else if ([comp hasPrefix: @"s="])
|
||||||
[ret addNItems: 2
|
salt = [OFDataArray
|
||||||
fromCArray: "r="];
|
dataArrayWithBase64EncodedString: entry];
|
||||||
[ret addNItems: [sNonce cStringLength]
|
else if ([comp hasPrefix: @"i="])
|
||||||
fromCArray: [sNonce cString]];
|
iterCount = [entry decimalValue];
|
||||||
|
|
||||||
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
|
||||||
[tmpArray addNItems: [password cStringLength]
|
|
||||||
fromCArray: [password cString]];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* IETF RFC 5802:
|
|
||||||
* SaltedPassword := Hi(Normalize(password), salt, i)
|
|
||||||
*/
|
|
||||||
saltedPassword = [self _hiWithData: tmpArray
|
|
||||||
salt: salt
|
|
||||||
iterationCount: iterCount];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* IETF RFC 5802:
|
|
||||||
* AuthMessage := client-first-message-bare + "," +
|
|
||||||
* server-first-message + "," +
|
|
||||||
* client-final-message-without-proof
|
|
||||||
*/
|
|
||||||
[authMessage addNItems: [clientFirstMessageBare cStringLength]
|
|
||||||
fromCArray: [clientFirstMessageBare cString]];
|
|
||||||
[authMessage addItem: ","];
|
|
||||||
[authMessage addNItems: [challenge count] * [challenge itemSize]
|
|
||||||
fromCArray: [challenge cArray]];
|
|
||||||
[authMessage addItem: ","];
|
|
||||||
[authMessage addNItems: [ret count]
|
|
||||||
fromCArray: [ret cArray]];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* IETF RFC 5802:
|
|
||||||
* ClientKey := HMAC(SaltedPassword, "Client Key")
|
|
||||||
*/
|
|
||||||
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
|
||||||
[tmpArray addNItems: 10
|
|
||||||
fromCArray: "Client Key"];
|
|
||||||
clientKey = [self _hmacWithKey: saltedPassword
|
|
||||||
data: tmpArray];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* IETF RFC 5802:
|
|
||||||
* StoredKey := H(ClientKey)
|
|
||||||
*/
|
|
||||||
[hash updateWithBuffer: (void*) clientKey
|
|
||||||
ofSize: [hashType digestSize]];
|
|
||||||
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
|
||||||
[tmpArray addNItems: [hashType digestSize]
|
|
||||||
fromCArray: [hash digest]];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* IETF RFC 5802:
|
|
||||||
* ClientSignature := HMAC(StoredKey, AuthMessage)
|
|
||||||
*/
|
|
||||||
clientSignature = [self _hmacWithKey: tmpArray
|
|
||||||
data: authMessage];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* IETF RFC 5802:
|
|
||||||
* ServerKey := HMAC(SaltedPassword, "Server Key")
|
|
||||||
*/
|
|
||||||
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
|
||||||
[tmpArray addNItems: 10
|
|
||||||
fromCArray: "Server Key"];
|
|
||||||
serverKey = [self _hmacWithKey: saltedPassword
|
|
||||||
data: tmpArray];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* IETF RFC 5802:
|
|
||||||
* ServerSignature := HMAC(ServerKey, AuthMessage)
|
|
||||||
*/
|
|
||||||
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
|
||||||
[tmpArray addNItems: [hashType digestSize]
|
|
||||||
fromCArray: serverKey];
|
|
||||||
serverSignature = [[OFDataArray alloc] initWithItemSize: 1];
|
|
||||||
[serverSignature addNItems: [hashType digestSize]
|
|
||||||
fromCArray: [self _hmacWithKey: tmpArray
|
|
||||||
data: authMessage]];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* IETF RFC 5802:
|
|
||||||
* ClientProof := ClientKey XOR ClientSignature
|
|
||||||
*/
|
|
||||||
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
|
||||||
for (i = 0; i < [hashType digestSize]; i++) {
|
|
||||||
uint8_t c = clientKey[i] ^ clientSignature[i];
|
|
||||||
[tmpArray addItem: &c];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add p=<base64(ClientProof)>
|
|
||||||
[ret addItem: ","];
|
|
||||||
[ret addNItems: 2
|
|
||||||
fromCArray: "p="];
|
|
||||||
tmpString = [tmpArray stringByBase64Encoding];
|
|
||||||
[ret addNItems: [tmpString cStringLength]
|
|
||||||
fromCArray: [tmpString cString]];
|
|
||||||
|
|
||||||
[ret retain];
|
|
||||||
[pool release];
|
|
||||||
pool = nil;
|
|
||||||
|
|
||||||
return [ret autorelease];
|
|
||||||
} @finally {
|
|
||||||
[pool release];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add c=<base64(GS2Header+channelBindingData)>
|
||||||
|
// XXX: No channel binding for now
|
||||||
|
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
|
[tmpArray addNItems: [GS2Header cStringLength]
|
||||||
|
fromCArray: [GS2Header cString]];
|
||||||
|
tmpString = [tmpArray stringByBase64Encoding];
|
||||||
|
[ret addNItems: 2
|
||||||
|
fromCArray: "c="];
|
||||||
|
[ret addNItems: [tmpString cStringLength]
|
||||||
|
fromCArray: [tmpString cString]];
|
||||||
|
|
||||||
|
// Add r=<nonce>
|
||||||
|
[ret addItem: ","];
|
||||||
|
[ret addNItems: 2
|
||||||
|
fromCArray: "r="];
|
||||||
|
[ret addNItems: [sNonce cStringLength]
|
||||||
|
fromCArray: [sNonce cString]];
|
||||||
|
|
||||||
|
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
|
[tmpArray addNItems: [password cStringLength]
|
||||||
|
fromCArray: [password cString]];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IETF RFC 5802:
|
||||||
|
* SaltedPassword := Hi(Normalize(password), salt, i)
|
||||||
|
*/
|
||||||
|
saltedPassword = [self _hiWithData: tmpArray
|
||||||
|
salt: salt
|
||||||
|
iterationCount: iterCount];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IETF RFC 5802:
|
||||||
|
* AuthMessage := client-first-message-bare + "," +
|
||||||
|
* server-first-message + "," +
|
||||||
|
* client-final-message-without-proof
|
||||||
|
*/
|
||||||
|
[authMessage addNItems: [clientFirstMessageBare cStringLength]
|
||||||
|
fromCArray: [clientFirstMessageBare cString]];
|
||||||
|
[authMessage addItem: ","];
|
||||||
|
[authMessage addNItems: [challenge count] * [challenge itemSize]
|
||||||
|
fromCArray: [challenge cArray]];
|
||||||
|
[authMessage addItem: ","];
|
||||||
|
[authMessage addNItems: [ret count]
|
||||||
|
fromCArray: [ret cArray]];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IETF RFC 5802:
|
||||||
|
* ClientKey := HMAC(SaltedPassword, "Client Key")
|
||||||
|
*/
|
||||||
|
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
|
[tmpArray addNItems: 10
|
||||||
|
fromCArray: "Client Key"];
|
||||||
|
clientKey = [self _HMACWithKey: saltedPassword
|
||||||
|
data: tmpArray];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IETF RFC 5802:
|
||||||
|
* StoredKey := H(ClientKey)
|
||||||
|
*/
|
||||||
|
[hash updateWithBuffer: (void*) clientKey
|
||||||
|
ofSize: [hashType digestSize]];
|
||||||
|
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
|
[tmpArray addNItems: [hashType digestSize]
|
||||||
|
fromCArray: [hash digest]];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IETF RFC 5802:
|
||||||
|
* ClientSignature := HMAC(StoredKey, AuthMessage)
|
||||||
|
*/
|
||||||
|
clientSignature = [self _HMACWithKey: tmpArray
|
||||||
|
data: authMessage];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IETF RFC 5802:
|
||||||
|
* ServerKey := HMAC(SaltedPassword, "Server Key")
|
||||||
|
*/
|
||||||
|
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
|
[tmpArray addNItems: 10
|
||||||
|
fromCArray: "Server Key"];
|
||||||
|
serverKey = [self _HMACWithKey: saltedPassword
|
||||||
|
data: tmpArray];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IETF RFC 5802:
|
||||||
|
* ServerSignature := HMAC(ServerKey, AuthMessage)
|
||||||
|
*/
|
||||||
|
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
|
[tmpArray addNItems: [hashType digestSize]
|
||||||
|
fromCArray: serverKey];
|
||||||
|
serverSignature = [[OFDataArray alloc] initWithItemSize: 1];
|
||||||
|
[serverSignature addNItems: [hashType digestSize]
|
||||||
|
fromCArray: [self _HMACWithKey: tmpArray
|
||||||
|
data: authMessage]];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IETF RFC 5802:
|
||||||
|
* ClientProof := ClientKey XOR ClientSignature
|
||||||
|
*/
|
||||||
|
tmpArray = [OFDataArray dataArrayWithItemSize: 1];
|
||||||
|
for (i = 0; i < [hashType digestSize]; i++) {
|
||||||
|
uint8_t c = clientKey[i] ^ clientSignature[i];
|
||||||
|
[tmpArray addItem: &c];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add p=<base64(ClientProof)>
|
||||||
|
[ret addItem: ","];
|
||||||
|
[ret addNItems: 2
|
||||||
|
fromCArray: "p="];
|
||||||
|
tmpString = [tmpArray stringByBase64Encoding];
|
||||||
|
[ret addNItems: [tmpString cStringLength]
|
||||||
|
fromCArray: [tmpString cString]];
|
||||||
|
|
||||||
|
[ret retain];
|
||||||
|
[pool release];
|
||||||
|
|
||||||
|
return [ret autorelease];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)parseServerFinalMessage: (OFDataArray*)message
|
- (void)parseServerFinalMessage: (OFDataArray*)message
|
||||||
{
|
{
|
||||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||||
@try {
|
OFString *mess = [OFString stringWithCString: [message cArray]
|
||||||
OFString *mess = [OFString
|
length: [message count] *
|
||||||
stringWithCString: [message cArray]
|
[message itemSize]];
|
||||||
length: [message count] * [message itemSize]];
|
OFString *value = [mess substringFromIndex: 2
|
||||||
|
toIndex: [mess length]];
|
||||||
|
|
||||||
OFString *value = [mess substringFromIndex: 2
|
if ([mess hasPrefix: @"v="]) {
|
||||||
toIndex: [mess length]];
|
if (![value isEqual: [serverSignature stringByBase64Encoding]])
|
||||||
|
@throw [XMPPAuthFailedException
|
||||||
|
newWithClass: isa
|
||||||
|
connection: nil
|
||||||
|
reason: @"Received wrong ServerSignature"];
|
||||||
|
} else
|
||||||
|
@throw [XMPPAuthFailedException newWithClass: isa
|
||||||
|
connection: nil
|
||||||
|
reason: value];
|
||||||
|
|
||||||
if ([mess hasPrefix: @"v="]) {
|
[pool release];
|
||||||
if ([value compare:
|
|
||||||
[serverSignature stringByBase64Encoding]])
|
|
||||||
@throw [XMPPAuthFailedException
|
|
||||||
newWithClass: isa
|
|
||||||
connection: nil
|
|
||||||
reason:
|
|
||||||
@"Received wrong ServerSignature"];
|
|
||||||
} else
|
|
||||||
@throw [XMPPAuthFailedException newWithClass: isa
|
|
||||||
connection: nil
|
|
||||||
reason: value];
|
|
||||||
} @finally {
|
|
||||||
[pool release];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
76
src/arc4random_uniform.m
Normal file
76
src/arc4random_uniform.m
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1996, David Mazieres <dm@uun.org>
|
||||||
|
* Copyright (c) 2008, Damien Miller <djm@openbsd.org>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arc4 random number generator for OpenBSD.
|
||||||
|
*
|
||||||
|
* This code is derived from section 17.1 of Applied Cryptography,
|
||||||
|
* second edition, which describes a stream cipher allegedly
|
||||||
|
* compatible with RSA Labs "RC4" cipher (the actual description of
|
||||||
|
* which is a trade secret). The same algorithm is used as a stream
|
||||||
|
* cipher called "arcfour" in Tatu Ylonen's ssh package.
|
||||||
|
*
|
||||||
|
* RC4 is a registered trademark of RSA Laboratories.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate a uniformly distributed random number less than upper_bound
|
||||||
|
* avoiding "modulo bias".
|
||||||
|
*
|
||||||
|
* Uniformity is achieved by generating new random numbers until the one
|
||||||
|
* returned is outside the range [0, 2**32 % upper_bound). This
|
||||||
|
* guarantees the selected random number will be inside
|
||||||
|
* [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
|
||||||
|
* after reduction modulo upper_bound.
|
||||||
|
*/
|
||||||
|
uint32_t
|
||||||
|
arc4random_uniform(uint32_t upper_bound)
|
||||||
|
{
|
||||||
|
uint32_t r, min;
|
||||||
|
|
||||||
|
if (upper_bound < 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#if (ULONG_MAX > 0xffffffffUL)
|
||||||
|
min = 0x100000000UL % upper_bound;
|
||||||
|
#else
|
||||||
|
/* Calculate (2**32 % upper_bound) avoiding 64-bit math */
|
||||||
|
if (upper_bound > 0x80000000)
|
||||||
|
min = 1 + ~upper_bound; /* 2**32 - upper_bound */
|
||||||
|
else {
|
||||||
|
/* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
|
||||||
|
min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This could theoretically loop forever but each retry has
|
||||||
|
* p > 0.5 (worst case, usually far better) of selecting a
|
||||||
|
* number inside the range we need, so it should rarely need
|
||||||
|
* to re-roll.
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
r = arc4random();
|
||||||
|
if (r >= min)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r % upper_bound;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue