1

Contents of NSString+sha1.h:

#include <CommonCrypto/CommonDigest.h>
#include <Foundation/Foundation.h>

@interface NSString (sha1)

- (NSString *) sha1;

@end

Contents of NSString+sha1.m:

#include "NSString+sha1.h"

@implementation NSString (sha1)

- (NSString *) sha1 {
    const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
    NSData *data = [NSData dataWithBytes:cstr length:input.length];

    uint8_t digest[CC_SHA1_DIGEST_LENGTH];

    CC_SHA1(data.bytes, data.length, digest);

    NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];

    for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
        [output appendFormat:@"%02x", digest[i]];

    return [NSString stringWithString:output];
}

@end

Contents of UIImage+RenderBatteryImage.m:

#include "UIImage+RenderBatteryImage.h"
#include "NSString+sha1.h"
[...]
[@"A string (but not this one)" sha1]

When the code from the third file runs, I get this error:

-[__NSCFString sha1]: unrecognized selector sent to instance 0x12ee1caf0

What is causing this? I can confirm that I have no instances of uppercase SHA1 in any of my source files.

Nikita Leonov
  • 5,684
  • 31
  • 37
Carlos Liam
  • 305
  • 2
  • 10
  • 1
    So, where does the exception traceback say this reference is occurring??? – Hot Licks Jun 29 '15 at 21:35
  • possible duplicate of [How can I debug 'unrecognized selector sent to instance' error](http://stackoverflow.com/questions/25853947/how-can-i-debug-unrecognized-selector-sent-to-instance-error) – Hot Licks Jun 29 '15 at 21:36
  • (You are passing an NSString to some interface that expects an object that has a `SHA1` method. Pass it the correct object.) – Hot Licks Jun 29 '15 at 21:38
  • That should be caught by the compiler. Try cleaning and building or analyzing to see if it finds anything. – EmilioPelaez Jun 29 '15 at 21:41
  • Crash log: https://ghostbin.com/paste/49osr. Syslog: https://ghostbin.com/paste/nw9gy. – Carlos Liam Jun 29 '15 at 21:48
  • As far as I'm aware, I'm not using anything that would expect a SHA1 method. – Carlos Liam Jun 29 '15 at 21:50
  • Just to note that in the syslog the method is lowercase `sha1`... – Alladinian Jun 29 '15 at 21:59
  • Fair enough, I confused some different logs. In that case the problem is different, but there's still a problem. – Carlos Liam Jun 29 '15 at 22:01
  • I believe the issue relates to compiler optimization of constants strings. The compiler may well be collecting all constant strings to create a single copy of each identical string. Here it does not know about your category. Using -all_load linker flag seems a suggestion here: http://stackoverflow.com/questions/12358610/ios-5-make-nsstring-category-include-nscfconstantstring – Rory McKinnel Jun 29 '15 at 22:08
  • Your code works fine on a fresh project (apart from `input.length` which is undefined in the `sha1` method)... – Alladinian Jun 29 '15 at 22:08
  • @CarlosLiam I posted an answer, which is actually the same as RorryMcKinnel mentioned later. Could you check it? Thanks. – Nikita Leonov Jun 29 '15 at 22:29
  • @CarlosLiam Your answer only refers to avoiding using static strings which is not the same as my comment. I am suggesting fixing the issue by trying the compiler -all_load flag which you do not mention, so not the same IMHO. – Rory McKinnel Jun 29 '15 at 22:40
  • The string on which I am calling `sha1` is not a literal, that was only there for purposes of illustration. Calling it on an object created by `[NSString stringWithString:]` resulted in the same error. Regarding the linker flag, I have no easy way to add this flag with Theos' makefile system. – Carlos Liam Jun 29 '15 at 23:11
  • @Alladinian mentioned your code worked fine on a fresh project, which I imagine was done in xcode (Alladinian?). This might point to a problem with your build settings now you have mentioned you build it using your own make system. – Rory McKinnel Jun 29 '15 at 23:31
  • @RoryMcKinnel Correct. Done on Xcode on a fresh project. – Alladinian Jun 30 '15 at 08:44
  • Make things simpler, don't use a Category on NSString, either use a function, a method in a class, probably static. Also do not use SHA1 in new work, it is no longer considered secure. Better methods would be SHA256 or SHA512. – zaph Jun 30 '15 at 12:09

2 Answers2

0

I have an assumption that require validation. In syslog you have following error:

-[__NSCFString sha1]: unrecognized selector sent to instance 0x12ee1caf0

Looks like your method sha1 is not found and it cause a crash. How it may happen? Compiler replace an object of @"A string (but not this one)" with some internal object that represents constant string and you do not have a category method defined for this particular constant string type.

Here is workflow that I suggest to apply to validate and fix assumption:

  1. Comment out string where you do sha1 call and check that error is not happening
  2. Replace literal with an actual object [NSString withString: @"your string"] to oversmart compiler

Here is actually some proof that my assumption right regarding compile-time replacement of a string by constant representation — What is the different between NSCFString and NSConstantString?

Community
  • 1
  • 1
Nikita Leonov
  • 5,684
  • 31
  • 37
0

Sample code, a simple self-contained method, just add it to your class:

// Add Security.framework to the project.
#include <CommonCrypto/CommonDigest.h>

+ (NSString *) sha1:(NSString *)string {
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    NSMutableData *hash = [NSMutableData dataWithLength:CC_SHA1_DIGEST_LENGTH];
    CC_SHA1(data.bytes, (CC_LONG)data.length, hash.mutableBytes);

    NSMutableString *hexAscii = [NSMutableString new];
    for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
        [hexAscii appendFormat:@"%02x", ((uint8_t *)hash.mutableBytes)[i]];

    return [hexAscii copy]; // Make immutable
}

Test (assuming that the method is in the class Test.

NSString *hashHexASCII = [Test sha1:@"test String"];
NSLog(@"hashHexASCII: %@", hashHexASCII);

Output:

hashHexASCII: 9269ca2a6a1695eff8d5acd47b57c045698e3ce1

zaph
  • 111,848
  • 21
  • 189
  • 228