是否有任何双腿OAuth库支持iOS的RSA-SHA1签名?

时间:2013-05-28 09:40:06

标签: ios objective-c oauth

我试图在iOS中实现MasterCard MoneySend API。 API需要两条腿的oauth来授权请求​​。

标准是:

  1. OAuth应使用RSA-SHA1生成签名。
  2. 请求方法应为PUT
  3. 由于请求有一个body,需要包含body hash。
  4. 我们拥有的是PrivetKey的ConsumerKey和.p12文件。我尝试了很多库,例如RestKitASIHTTPRequestOAuthConsumer等。

    最后我最终得到了这段代码:

    #import "NSStringAdditions.h"
    #import "ASIHTTPRequest.h"
    #import "sha.h"
    #import "rsa.h"
    #import "pem.h"
    #import "objects.h"
    
    #define SANDBOX_CONSUMER_KEY @""
    #define PRIVETKEY @""
    
    @interface MC_TestApi ()
    <NSURLConnectionDelegate>
    {
        NSMutableData *responseData;
        NSURLConnection *urlConnection;
    }
    @end
    
    @implementation MC_TestApi
    
    - (NSString*)oAuthBodyHash:(NSData*)body
    {
        unsigned char digest[SHA_DIGEST_LENGTH];
    
        SHA1([body bytes], [body length], (unsigned char*)&digest);
    
        unsigned c = SHA_DIGEST_LENGTH;
        uint8_t *bytes = malloc(sizeof(*bytes) * c);
    
        unsigned i;
        for (i = 0; i < c; i++)
        {
            int byte = (unsigned int)digest[i];
            bytes[i] = (uint8_t)byte;
        }
        NSData *strData = [NSData dataWithBytesNoCopy:bytes length:c freeWhenDone:YES];
    
        return [NSString base64StringFromData:strData length:strData.length ];
    }
    
    - (NSString *)sha1RsaText: (NSString *)text
    {
        NSString *path = [[NSBundle mainBundle] pathForResource: @"MCOpenAPI" ofType: @"pem"];
        FILE *secretFile = fopen([path cStringUsingEncoding: NSUTF8StringEncoding], "r");
        if (secretFile==NULL){
            printf("ERROR opening RSA Keys failed test.pem\n");
            return nil;
        }
    
    
        NSData *clearTextData = [text dataUsingEncoding: NSUTF8StringEncoding];
        unsigned char encryptedData[40];
        RSA *rsa = (RSA *)PEM_read_RSAPrivateKey(secretFile, &rsa, NULL, NULL);
    
        unsigned int encryptionLength = 40; //RSA_size(rsa);
    
        RSA_sign(NID_sha1, [clearTextData bytes], [clearTextData length], encryptedData, &encryptionLength, rsa);
    
        unsigned c = 20;
        uint8_t *bytes = malloc(sizeof(*bytes) * c);
    
        unsigned i;
        for (i = 0; i < c; i++)
        {
            int byte = (unsigned int)encryptedData[i];
            bytes[i] = (uint8_t)byte;
        }
        NSData *strData = [NSData dataWithBytesNoCopy:bytes length:c freeWhenDone:YES];
    
        return [NSString base64StringFromData:strData length:strData.length ];
    }
    
    - (NSString *)urlEncodeValue:(NSString *)str
    {
        NSString *result = (NSString *) CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
                                                                                                  (CFStringRef)str,
                                                                                                  NULL,
                                                                                                  CFSTR(":/?#[]@!$&'()*+,;="),
                                                                                                  kCFStringEncodingUTF8));
        return result;
    }
    
    -(void)requestWithOAuth {
    
        NSUInteger time = [[NSDate date] timeIntervalSince1970];
    
        NSString *timestamp = [NSString stringWithFormat: @"%d", time];
        NSString *urlString = @"https://sandbox.api.mastercard.com/moneysend/eligibility/v1/pan";
        NSString *nonce = @"1234567890";
        NSString *consumerKey = SANDBOX_CONSUMER_KEY;
    
        NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@?Format=XML",urlString]];
        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
        [request setHTTPMethod:@"PUT"];
        [request setValue:@"application/xml" forHTTPHeaderField:@"content-type"];
    
        NSString *bodyString = @"<?xml version=\"1.0\" encoding=\"UTF-8\" ?> <PanEligibilityRequest> <SendingAccountNumber>5555555555559999</SendingAccountNumber> </PanEligibilityRequest>";
    
        NSData *body = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
        NSString *bodyLength = [NSString stringWithFormat:@"%d",[body length]];
        [request setValue:bodyLength forHTTPHeaderField:@"content-length"];
    
        NSString *oAuthBodyHash = [self oAuthBodyHash:body];
    
        NSString *header = [NSString stringWithFormat:@"oauth_timestamp=\"%@\",oauth_nonce=\"%@\",oauth_version=\"1.0\",oauth_body_hash=\"%@\",oauth_consumer_key=\"%@\",oauth_signature_method=\"RSA-SHA1\"",timestamp,nonce,oAuthBodyHash,SANDBOX_CONSUMER_KEY];
    
        NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                           consumerKey,@"oauth_consumer_key",
                                           nonce,@"oauth_nonce",
                                           @"RSA-SHA1",@"oauth_signature_method",
                                           timestamp,@"oauth_timestamp",
                                           @"1.0",@"oauth_version",
                                           oAuthBodyHash,@"oauth_body_hash",
                                           @"XML",@"Format",
                                           nil];
        NSArray *keys = [parameters allKeys];
    
        NSSortDescriptor* sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES selector:@selector(localizedCompare:)];
        keys = [keys sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
        NSString *test = @"";
        for (NSUInteger i = 0; i<[keys count]; i++) {
            NSString *key = [keys objectAtIndex:i];
            NSString *str = [NSString stringWithFormat:@"%@=%@",key,[parameters objectForKey:key]];
            if (i!=([parameters count]-1))
                str = [str stringByAppendingString:@","];
            test = [test stringByAppendingString:str];
        }
    
        NSString *signatureString = [NSString stringWithFormat: @"PUT&%@%%26%@",
                                     [self urlEncodeValue: urlString],
                                     [self urlEncodeValue: [test stringByReplacingOccurrencesOfString: @"," withString: @"&"]]];
    
        NSString *signature = [self sha1RsaText: signatureString];
        NSString *finalAuthHeader = [NSString stringWithFormat: @"OAuth %@,oauth_signature=\"%@\"", header, signature];
        [request setValue:finalAuthHeader forHTTPHeaderField:@"Authorization"];
    
        [request setHTTPBody:body];
    
        urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
        [urlConnection start];
    }
    
    #pragma mark - NSURLConnectionDelegate
    
    - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
    {
        NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
        int code = [httpResponse statusCode];
        NSLog(@"in didReceiveResponse %i %@",code,[NSHTTPURLResponse localizedStringForStatusCode:code]);
    
        responseData = nil;
        responseData = [[NSMutableData alloc] init];
        [responseData setLength:0];
    }
    
    - (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
        NSLog(@"in didReceiveData ");
        [responseData appendData:data];
    }
    
    - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
    {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        NSLog(@"\n\n ERORR \n\n%@",[NSString stringWithFormat:@"Connection failed: %@", [error description]]);
    }
    
    - (void) connectionDidFinishLoading:(NSURLConnection *)connection
    {
        if (responseData) {
            NSString *newStr = [NSString stringWithUTF8String:[responseData bytes]];
            NSLog(@"XML: %@",newStr);
    
        }
        responseData = nil;
    }
    
    @end
    

    我的问题是:

    • 我在这里做错了什么?

    • iOS中是否有可以使用的开源库?

    伙计们请帮助我...谢谢和问候

1 个答案:

答案 0 :(得分:0)

尝试使用chilkatsoft 或者只是原生CommonCrypto (an Apple framework)