Skip to content

Instantly share code, notes, and snippets.

@eliburke
Created May 1, 2015 17:55
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eliburke/1a55ed616bb15a7f908b to your computer and use it in GitHub Desktop.
Save eliburke/1a55ed616bb15a7f908b to your computer and use it in GitHub Desktop.
iOS NSUUID category for calculating an RFC4122 compliant uuid5. Tested / compatible with python's uuid.uuid5
//
// NSUUID+uuid5.h
//
// MIT License (aka, do with it what you want)
//
// Copyright (c) 2015 Eli Burke eburke@pobox.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//
// With thanks to
// https://gist.github.com/datalogics-robl/6215182
// and
// https://gist.github.com/superduper/177aab4b9700e41103e3
// both are flawed but pointed me in the right direction
//
// output can be tested in a python interpreter
// > python
// >>> import uuid
// >>> uuid.uuid5(uuid.NAMESPACE_URL,"input string")
// UUID('4552de95-510d-5ab2-85a0-6f42ceacdb7e')
// >>> uuid.uuid5(uuid.NAMESPACE_URL,"input string").hex
// '4552de95510d5ab285a06f42ceacdb7e'
//
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
@interface NSUUID (uuid5)
+ (NSUUID*)uuid5:(NSUUID*)namespace input:(NSString*)input;
+ (NSUUID *)NAMESPACE_DNS;
+ (NSUUID *)NAMESPACE_URL;
+ (NSUUID *)NAMESPACE_OID;
+ (NSUUID *)NAMESPACE_X500;
@end
@implementation NSUUID (uuid5)
+ (NSUUID*)uuid5:(NSUUID*)namespace input:(NSString*)input {
// convert the namespace UUID to bytes
uuid_t namespaceUUID, resultUUID;
[namespace getUUIDBytes:namespaceUUID];
// convert the input string to bytes
NSData * inputData = [input dataUsingEncoding:NSUTF8StringEncoding];
// combine the two sets of bytes
NSMutableData *hashData = [NSMutableData dataWithBytes:namespaceUUID length:sizeof(uuid_t)];
[hashData appendBytes:inputData.bytes length:inputData.length];
// hash with SHA1
NSMutableData * digestData = [NSMutableData dataWithLength:CC_SHA1_DIGEST_LENGTH];
CC_SHA1(hashData.bytes, hashData.length, [digestData mutableBytes]);
// convert back to uuid_t so we can tweak bytes
[digestData getBytes:resultUUID length:sizeof(resultUUID)];
// this is uuid5, so always set the version to 5
resultUUID[6] = ((resultUUID[6] & 0x0F) | (0x50));
// https://www.ietf.org/rfc/rfc4122.txt
// we want a RFC4122 hash, so the leftmost bits should be 10xxxxxx
// to achieve that, first AND with 00111111, then OR with 10000000
resultUUID[8] = ((resultUUID[8] & 0x3F) | 0x80 );
return [[NSUUID alloc] initWithUUIDBytes:resultUUID];
}
+ (NSUUID *)NAMESPACE_DNS {
static NSUUID * uuid;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
uuid = [[NSUUID alloc] initWithUUIDString:@"6ba7b810-9dad-11d1-80b4-00c04fd430c8"];
});
return uuid;
}
+ (NSUUID *)NAMESPACE_URL {
static NSUUID * uuid;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
uuid = [[NSUUID alloc] initWithUUIDString:@"6ba7b811-9dad-11d1-80b4-00c04fd430c8"];
});
return uuid;
}
+ (NSUUID *)NAMESPACE_OID {
static NSUUID * uuid;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
uuid = [[NSUUID alloc] initWithUUIDString:@"6ba7b812-9dad-11d1-80b4-00c04fd430c8"];
});
return uuid;
}
+ (NSUUID *)NAMESPACE_X500 {
static NSUUID * uuid;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
uuid = [[NSUUID alloc] initWithUUIDString:@"6ba7b814-9dad-11d1-80b4-00c04fd430c8"];
});
return uuid;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment