在 iOS SDK 中创建密码摘要
Create password digest in iOS SDK
我正在将 DigestPassword Web 服务集成到我的 iPhone 应用程序中。为此,我需要生成 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];
}
有人可以检查我创建随机数和密码摘要的代码,让我知道我犯了什么错误,因为我无法用它访问 Web 服务吗?我总是收到 Message Expired 错误。
错误:
<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>
我认为您需要将 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 随机数,但在文档中的公式是:
Password_Digest = Base64 ( SHA-1 ( nonce + created + password ) )
所以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:
This specification defines and illustrates time references in terms of
the xsd:dateTime type defined in XML Schema. It is RECOMMENDED that
all time references use this type. All references MUST be in UTC
time. Implementations MUST NOT generate time instants that specify
leap seconds. If, however, other time types are used, then the
ValueType attribute (described below) MUST be specified to indicate
the data type of the time format. Requestors and receivers SHOULD NOT
rely on other applications supporting time resolution finer than
milliseconds.
使用 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]];
我正在将 DigestPassword Web 服务集成到我的 iPhone 应用程序中。为此,我需要生成 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];
}
有人可以检查我创建随机数和密码摘要的代码,让我知道我犯了什么错误,因为我无法用它访问 Web 服务吗?我总是收到 Message Expired 错误。 错误:
<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>
我认为您需要将 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 随机数,但在文档中的公式是:
Password_Digest = Base64 ( SHA-1 ( nonce + created + password ) )
所以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:
This specification defines and illustrates time references in terms of the xsd:dateTime type defined in XML Schema. It is RECOMMENDED that all time references use this type. All references MUST be in UTC time. Implementations MUST NOT generate time instants that specify leap seconds. If, however, other time types are used, then the ValueType attribute (described below) MUST be specified to indicate the data type of the time format. Requestors and receivers SHOULD NOT rely on other applications supporting time resolution finer than milliseconds.
使用 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]];