Skip to content

Commit

Permalink
Merge new API by Danny Greg, other fixes
Browse files Browse the repository at this point in the history
Add GITIGNORE for AppCode and internal Xcode project files
Add CFobError class, use standard Cocoa error handling pattern
Update copyright years, Twitter handle
Use BSD license
Support GC
Fix OpenSSL initialisation conflicts
  • Loading branch information
glebd committed Oct 31, 2011
2 parents af9546c + 6848b58 commit f959604
Show file tree
Hide file tree
Showing 13 changed files with 576 additions and 274 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
build
*.mode2v3
*.mode*
*.pbxuser
*.perspectivev3
.idea
20 changes: 20 additions & 0 deletions objc/CFobError.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// CFobError.h
// cocoafob
//
// Created by Danny Greg on 24/08/2010.
// Copyright 2010 Realmac Software. All rights reserved.
// Licensed under CC Attribution Licence 3.0 <http://creativecommons.org/licenses/by/3.0/>
//

#import <Foundation/Foundation.h>

enum _CFobErrorCode {
CFobErrorCodeInvalidKey = -1,
CFobErrorCodeCouldNotDecode = -2,
CFobErrorCodeSigningFailed = -3,
CFobErrorCodeCouldNotEncode = -4,
CFobErrorCodeNoName = -5,
};

void CFobAssignErrorWithDescriptionAndCode(NSError **err, NSString *description, NSInteger code);
18 changes: 18 additions & 0 deletions objc/CFobError.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// CFobError.h
// cocoafob
//
// Created by Danny Greg on 24/08/2010.
// Copyright 2010 Realmac Software. All rights reserved.
// Licensed under CC Attribution Licence 3.0 <http://creativecommons.org/licenses/by/3.0/>
//

#import "CFobError.h"

#import "CFobLicVerifier.h"

void CFobAssignErrorWithDescriptionAndCode(NSError **err, NSString *description, NSInteger code)
{
if (err != NULL)
*err = [NSError errorWithDomain:[[NSBundle bundleForClass:[CFobLicVerifier class]] bundleIdentifier] code:code userInfo:[NSDictionary dictionaryWithObject:NSLocalizedStringFromTableInBundle(description, nil, [NSBundle bundleForClass:[CFobLicVerifier class]], nil) forKey:NSLocalizedDescriptionKey]];
}
40 changes: 8 additions & 32 deletions objc/CFobLicGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
// CocoaFob
//
// Created by Gleb Dolgich on 09/02/2009.
// Follow me on Twitter @gbd.
// Copyright (C) 2009 PixelEspresso. All rights reserved.
// Licensed under CC Attribution License 3.0 <http://creativecommons.org/licenses/by/3.0/>
// Follow me on Twitter @glebd.
// Copyright (C) 2009-2011 PixelEspresso. All rights reserved.
// BSD License
//

#import <Foundation/Foundation.h>
Expand All @@ -18,49 +18,25 @@
@discussion Given user name and DSA private key, generates a human-readable registration code.
*/
@interface CFobLicGenerator : NSObject {
DSA *dsa;
NSString *regName;
NSString *regCode;
NSString *lastError;
DSA *_dsa;
}

@property (nonatomic, copy) NSString *regName;
@property (nonatomic, copy) NSString *regCode;
@property (nonatomic, copy) NSString *lastError;

/*!
@method generatorWithPrivateKey:
@abstract Creates a new registration code generator given DSA private key.
@discussion Use this class method to create an autoreleased registration code generator.
@param privKey PEM-encoded non-encrypted DSA private key.
@result A new autoreleased registration code generator object.
*/
+ (id)generatorWithPrivateKey:(NSString *)privKey;

/*!
@method initWithPrivateKey:
@abstract Designated initializer that takes a DSA private key.
@discussion Initializes registration code generator using a DSA private key.
@param privKey PEM-encoded non-encrypted DSA private key.
@result An initialized registration code generator object.
*/
- (id)initWithPrivateKey:(NSString *)privKey;

/*!
@method setPrivateKey:
@abstract Sets a new DSA private key.
@discussion Sets a new DSA private key to be used for subsequent generated registration codes.
@param privKey PEM-encoded non-encrypted DSA private key.
@result YES on success, NO on error.
*/
- (BOOL)setPrivateKey:(NSString *)privKey;
- (BOOL)setPrivateKey:(NSString *)privKey error:(NSError **)err;

/*!
@method generate
@abstract Generates a registration code from regName property.
@discussion Takes regName property and DSA private key and generates a new registration code that is placed in regCode property.
@result YES on success, NO on error.
@param The name or registration string to generate a serial number for.
@result The serial number as a string, nil on failure.
*/
- (BOOL)generate;
- (NSString *)generateRegCodeForName:(NSString *)name error:(NSError **)err;

@end
119 changes: 71 additions & 48 deletions objc/CFobLicGenerator.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,133 +3,156 @@
// CocoaFob
//
// Created by Gleb Dolgich on 09/02/2009.
// Follow me on Twitter @gbd.
// Copyright (C) 2009 PixelEspresso. All rights reserved.
// Licensed under CC Attribution Licence 3.0 <http://creativecommons.org/licenses/by/3.0/>
// Follow me on Twitter @glebd.
// Copyright (C) 2009-2011 PixelEspresso. All rights reserved.
// BSD License
//

#import "CFobLicGenerator.h"

#import "CFobError.h"

#import "NSData+PECrypt.h"
#import "NSString+PECrypt.h"
#import "CFobLicGenerator.h"

#import <openssl/evp.h>
#import <openssl/err.h>
#import <openssl/pem.h>

//***************************************************************************

@interface CFobLicGenerator ()

@property (nonatomic, assign) DSA *dsa;

- (void)initOpenSSL;
- (void)shutdownOpenSSL;

@end


@implementation CFobLicGenerator

@synthesize regName;
@synthesize regCode;
@synthesize lastError;

#pragma mark -
#pragma mark Class methods

+ (id)generatorWithPrivateKey:(NSString *)privKey {
return [[[CFobLicGenerator alloc] initWithPrivateKey:privKey] autorelease];
}
@synthesize dsa = _dsa;

#pragma mark -
#pragma mark Lifecycle

- (id)init {
return [self initWithPrivateKey:nil];
}

- (id)initWithPrivateKey:(NSString *)privKey {
if (![super init])
- (id)init
{
if ([super init] == nil)
return nil;

[self initOpenSSL];
[self setPrivateKey:privKey];

return self;
}

- (void)dealloc {
if (dsa)
DSA_free(dsa);
self.regCode = nil;
self.regName = nil;
self.lastError = nil;
- (void)finalize
{
if (self.dsa)
DSA_free(self.dsa);

[self shutdownOpenSSL];
[super finalize];
}

- (void)dealloc
{
if (self.dsa)
DSA_free(self.dsa);

[self shutdownOpenSSL];
[super dealloc];
}

#pragma mark -
#pragma mark API

- (BOOL)setPrivateKey:(NSString *)privKey {
- (BOOL)setPrivateKey:(NSString *)privKey error:(NSError **)err
{
// Validate the argument.
if (!privKey || ![privKey length]) {
self.lastError = @"Invalid key";
if (privKey == nil || [privKey length] < 1) {
CFobAssignErrorWithDescriptionAndCode(err, @"Invalid private key.", CFobErrorCodeInvalidKey);
return NO;
}
if (dsa)
DSA_free(dsa);
dsa = DSA_new();

if (self.dsa)
DSA_free(self.dsa);
self.dsa = DSA_new();
// Prepare BIO to read PEM-encoded private key from memory.
// Prepare buffer given NSString.
const char *privkeyCString = [privKey UTF8String];
BIO *bio = BIO_new_mem_buf((void *)privkeyCString, -1);
PEM_read_bio_DSAPrivateKey(bio, &dsa, NULL, NULL);
PEM_read_bio_DSAPrivateKey(bio, &_dsa, NULL, NULL);
BOOL result = YES;
if (!dsa->priv_key) {
self.lastError = @"Unable to decode key";
if (!self.dsa->priv_key) {
CFobAssignErrorWithDescriptionAndCode(err, @"Unable to decode key.", CFobErrorCodeCouldNotDecode);
result = NO;
}
// Cleanup BIO
BIO_vfree(bio);
return result;
}

- (BOOL)generate {
if (![regName length] || !dsa || !dsa->priv_key)
return NO;
NSData *digest = [regName sha1];
- (NSString *)generateRegCodeForName:(NSString *)name error:(NSError **)err
{
if (name == nil || [name length] < 1) {
CFobAssignErrorWithDescriptionAndCode(err, @"No name provided.", CFobErrorCodeNoName);
return nil;
}

if (!self.dsa || !self.dsa->priv_key) {
CFobAssignErrorWithDescriptionAndCode(err, @"Invalid private key.", CFobErrorCodeInvalidKey);
return nil;
}

NSData *digest = [name sha1];
unsigned int siglen;
unsigned char sig[100];
int check = DSA_sign(NID_sha1, [digest bytes], [digest length], sig, &siglen, dsa);
int check = DSA_sign(NID_sha1, [digest bytes], [digest length], sig, &siglen, self.dsa);
if (!check) {
self.lastError = @"Signing failed";
CFobAssignErrorWithDescriptionAndCode(err, @"Signing failed.", CFobErrorCodeSigningFailed);
return NO;
}

// Encode signature in Base32
NSData *signature = [NSData dataWithBytes:sig length:siglen];
NSString *b32Orig = [signature base32];
if (!b32Orig || ![b32Orig length]) {
self.lastError = @"Unable to encode in base32";
CFobAssignErrorWithDescriptionAndCode(err, @"Unable to encode in base32", CFobErrorCodeCouldNotEncode);
return NO;
}

// Replace Os with 8s and Is with 9s
NSString *replacedOWith8 = [b32Orig stringByReplacingOccurrencesOfString:@"O" withString:@"8"];
NSString *b32 = [replacedOWith8 stringByReplacingOccurrencesOfString:@"I" withString:@"9"];

// Cut off the padding.
NSString *regKeyNoPadding = [b32 stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]];
NSString *regKeyNoPadding = [b32 stringByReplacingOccurrencesOfString:@"=" withString:@""];

// Add dashes every 5 characters.
NSMutableString *serial = [NSMutableString stringWithString:regKeyNoPadding];
NSUInteger index = 5;
while (index < [serial length]) {
[serial insertString:@"-" atIndex:index];
index += 6;
}
self.regCode = serial;
return YES;

return serial;
}

#pragma mark -
#pragma mark OpenSSL Lifecycle

- (void)initOpenSSL {
- (void)initOpenSSL
{
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
}

- (void)shutdownOpenSSL {
- (void)shutdownOpenSSL
{
EVP_cleanup();
ERR_free_strings();
}
Expand Down
Loading

0 comments on commit f959604

Please sign in to comment.