У меня есть следующий код песочницы в Swift, который пытается создать правильный URL-адрес Amazon S3 с подходящей подписью для защищенного контента, и я пытаюсь «преобразовать» его из моего рабочего PHP кода. Однако я получаю страшную
Рассчитанная нами подпись запроса не соответствует предоставленной вами подписи. Проверьте ваш ключ и метод подписи.
сообщение при попытке URL. Одна вещь, которую я заметил, состоит в том, что подпись, генерируемая из PHP, имеет длину 30 символов, но та, которая генерируется в Swift, намного длиннее. Вот два примера:
PHP: Signature=jCpLoXYohCo%2BIkOS%2BjaObehyIng%3D
Swift: Signature=YmRhYWI2ZjkwY2VjZmY4YTNlZDhhYWI4ZTA2ZGI1ZDZjYjI3ZmEwZg==
Поскольку мне ничего не нужно из Amazon SDK, я решил не включать его в этот проект , В PHP функция, которая успешно генерировала правильную подпись в течение многих лет, выглядит так:
{
return base64_encode(extension_loaded('hash') ?
hash_hmac('sha1', $string, self::$__secretKey, true) : pack('H*', sha1(
(str_pad(self::$__secretKey, 64, chr(0x00)) ^ (str_repeat(chr(0x5c), 64))) .
pack('H*', sha1((str_pad(self::$__secretKey, 64, chr(0x00)) ^
(str_repeat(chr(0x36), 64))) . $string)))));
}
Я доказал, что extension_loaded ('ha sh') возвращает true в приведенном выше коде.
В Swift я попробовал некоторый код, который я нашел здесь, в Переполнении стека, который генерирует эту более длинную подпись. Генерируемый ha sh имеет длину 40 символов, который я затем пытаюсь кодировать в Base64:
enum CryptoAlgorithm {
case MD5, SHA1, SHA224, SHA256, SHA384, SHA512
var HMACAlgorithm: CCHmacAlgorithm {
var result: Int = 0
switch self {
case .MD5: result = kCCHmacAlgMD5
case .SHA1: result = kCCHmacAlgSHA1
case .SHA224: result = kCCHmacAlgSHA224
case .SHA256: result = kCCHmacAlgSHA256
case .SHA384: result = kCCHmacAlgSHA384
case .SHA512: result = kCCHmacAlgSHA512
}
return CCHmacAlgorithm(result)
}
var digestLength: Int {
var result: Int32 = 0
switch self {
case .MD5: result = CC_MD5_DIGEST_LENGTH
case .SHA1: result = CC_SHA1_DIGEST_LENGTH
case .SHA224: result = CC_SHA224_DIGEST_LENGTH
case .SHA256: result = CC_SHA256_DIGEST_LENGTH
case .SHA384: result = CC_SHA384_DIGEST_LENGTH
case .SHA512: result = CC_SHA512_DIGEST_LENGTH
}
return Int(result)
}
}
extension String {
func hmac(algorithm: CryptoAlgorithm, key: String) -> String {
let str = self.cString(using: String.Encoding.utf8)
let strLen = Int(self.lengthOfBytes(using: String.Encoding.utf8))
let digestLen = algorithm.digestLength
let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
let keyStr = key.cString(using: String.Encoding.utf8)
let keyLen = Int(key.lengthOfBytes(using: String.Encoding.utf8))
CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result)
let digest = stringFromResult(result: result, length: digestLen)
result.deallocate()
return digest.toBase64()
}
private func stringFromResult(result: UnsafeMutablePointer<CUnsignedChar>, length: Int) -> String {
var hash = NSMutableString()
for i in 0..<length {
hash.appendFormat("%02x", result[i])
}
return String(hash)
}
}
extension String {
func fromBase64() -> String? {
guard let data = Data(base64Encoded: self) else {
return nil
}
return String(data: data, encoding: .utf8)
}
func toBase64() -> String {
return Data(self.utf8).base64EncodedString()
}
}
Кто-нибудь может помочь мне понять, почему это не генерирует правильную подпись? Если версия PHP генерирует 30-символьную подпись, мое первое предположение состоит в том, что версия Swift должна быть такой же, но я не обязательно приклеен к этому как факт.