1

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

标准是:

  1. OAuth 应该RSA-SHA1用于生成签名。
  2. 请求方法应该是PUT
  3. 由于请求有正文,因此需要包含正文哈希。

我们拥有的是一个 ConsumerKey 和 PrivetKey 的 .p12 文件。我尝试了许多库,例如RestKit, ASIHTTPRequest,OAuthConsumer等。

最后我得到了这段代码:

#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 中的任何开源库吗?

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

4

1 回答 1

0

尝试使用chilkatsoft 或仅使用本机CommonCrypto(Apple 框架)

于 2013-06-07T10:12:32.413 回答