在iOS SDK中创建密码摘要

时间:2015-08-27 14:43:28

标签: ios objective-c soap ws-security

我正在努力在我的iPhone应用程序中集成DigestPassword Web服务。为此,我需要生成nonce和passwordDigest。我努力了,但在Google搜索中找不到任何有用的例子。

我已按照以下方式完成:更新代码:

NSString *user = @"XXXXXXXXXXXXXXXXXXXXXX";
NSNumber *nonce = @(arc4random());
NSLog(@"nonce %@",[self encodeStringTo64:[nonce stringValue]]);
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
NSString *created = [dateFormatter stringFromDate:[NSDate date]];
NSLog(@"created %@",created);
NSString *digest_concat = [NSString stringWithFormat:@"%@%@%@", nonce, created, @"Pwd@123"];

NSData *digestBytes = [self shaa1:digest_concat];
NSString *digestBase64 = [self base64forData:digestBytes];
NSLog(@"digestBase64 %@",digestBase64);

NSString *strSOAP = [NSString stringWithFormat:@"<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:v1=\"http://sita.aero/iborders/external/ReferralManagementServiceWSDLType/V1\"><soap:Header><wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\"><wsse:UsernameToken wsu:Id=\"UsernameToken-27E173B8CF239BE6F01440582357416191\"><wsse:Username>%@</wsse:Username><wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest\">%@</wsse:Password><wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">%@</wsse:Nonce><wsu:Created>%@</wsu:Created></wsse:UsernameToken></wsse:Security></soap:Header><soap:Body><v1:SearchReferralsRequest><v1:ReferralSearchCriteria><ReferralId>2038100</ReferralId></v1:ReferralSearchCriteria><v1:Paging><FetchNumber>1</FetchNumber><ResultsPerFetch>1</ResultsPerFetch></v1:Paging></v1:SearchReferralsRequest></soap:Body></soap:Envelope>",user,digestBase64,[self encodeStringTo64:[nonce stringValue]],created];

- (NSString*)encodeStringTo64:(NSString*)fromString{
    NSData *plainData = [fromString dataUsingEncoding:NSUTF8StringEncoding];
    NSString *base64String;
    if ([plainData respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
        base64String = [plainData base64EncodedStringWithOptions:kNilOptions];  // iOS 7+
    } else {
        base64String = [plainData base64Encoding];                              // pre iOS7
    }
    return base64String;
}

- (NSData *)shaa1:(NSString *)input {
NSData *data = [input dataUsingEncoding:NSUTF8StringEncoding];
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(data.bytes, (CC_LONG) data.length, digest);
return [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH];

}

有人可以查看我的代码来创建nonce和密码摘要,让我知道我犯了什么错误,因为我无法访问这个网络服务吗?我总是收到消息已过期错误。 错误:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
   <soap:Body>
      <soap:Fault>
         <soap:Code>
            <soap:Value>soap:Sender</soap:Value>
            <soap:Subcode>
               <soap:Value xmlns:ns1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">ns1:MessageExpired</soap:Value>
            </soap:Subcode>
         </soap:Code>
         <soap:Reason>
            <soap:Text xml:lang="en">The message has expired</soap:Text>
         </soap:Reason>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

编辑:我想要的SOAP请求:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:v1="http://xxxxx/xxxx/external/ServiceWSDLType/V1">
 <soap:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
      <wsse:UsernameToken wsu:Id="UsernameToken-XXXXX">
          <wsse:Username>XXXXXXXXXXXXXXXXXXX</wsse:Username>
          <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">iAdbggkXsbNih5wBJ8M2tyyVWiA=</wsse:Password>
          <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">b8SD2g2iiVvihx7ajVwPfw==</wsse:Nonce>
          <wsu:Created>2015-08-28T07:16:04.857Z</wsu:Created>
       </wsse:UsernameToken>
    </wsse:Security>
 </soap:Header>
 <soap:Body>
    <v1:SearchReferralsRequest>
       <v1:ReferralSearchCriteria>
          <ReferralId>213213</ReferralId>
       </v1:ReferralSearchCriteria>
       <v1:Paging>
          <FetchNumber>1</FetchNumber>
          <ResultsPerFetch>1</ResultsPerFetch>
       </v1:Paging>
    </v1:SearchReferralsRequest>
 </soap:Body>
</soap:Envelope>

1 个答案:

答案 0 :(得分:1)

我认为你需要将没有额外编码的SHA1摘要发送到十六进制字符串。

为SHA1尝试此功能:

- (NSData *)sha1:(NSString *)input {
    NSData *data = [input dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1(data.bytes, (CC_LONG) data.length, digest);
    return [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH];
}

同时检查密码摘要中的时间值是否与wsu:Created相同。

更新#1

您也可以在密码摘要中使用base64 nonce,但在文档公式中是:

  

Password_Digest = Base64(SHA-1(nonce + created +密码))

因此,nonce必须是数字,而不是base64编码的数字。试试这个密码摘要代码:

NSNumber *nonce = @(arc4random());

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
NSString *created = [dateFormatter stringFromDate:[NSDate date]];

NSString *digest_concat = [NSString stringWithFormat:@"%@%@%@", nonce, created, password];

更新#2

由于时区,您似乎已过期消息。来自规范 Web服务安全性:SOAP消息安全性1.1.1版

  

本规范定义并说明了时间参考   XML Schema中定义的xsd:dateTime类型。这是推荐的   所有时间参考都使用此类型。所有引用必须是UTC   时间。实现绝不能生成指定的时间瞬间   闰秒。但是,如果使用其他时间类型,那么   必须指定ValueType属性(如下所述)以指示   时间格式的数据类型。请求者和接收者不应该   依赖于支持时间分辨率更精细的其他应用程序   毫秒。

使用UTC时区:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
NSString *created = [dateFormatter stringFromDate:[NSDate date]];